forked from Upstream/CommandPanels
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
690ac0e6bf | ||
|
86aecb856a | ||
|
e58adfa9f5 | ||
|
5473206adf | ||
|
aced7b6243 | ||
|
98a02f2408 | ||
|
5f5db64255 | ||
|
9975b2f76a | ||
|
768b2a6de9 | ||
|
8b518e3cb7 | ||
|
372a9c0e86 | ||
|
3034ecd8f3 | ||
|
15766dca58 | ||
|
42e61009db | ||
|
f068a61596 |
30
.gitea/workflows/build.yml
Normal file
30
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,30 @@
|
||||
name: Build CommandPanels plugin
|
||||
run-name: Build CommandPanels plugin
|
||||
on: [push]
|
||||
jobs:
|
||||
Build-latest-jar:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Build | Prepare packages
|
||||
run: |
|
||||
apt update; apt-get install software-properties-common -y
|
||||
wget -O- https://apt.corretto.aws/corretto.key | apt-key add -
|
||||
add-apt-repository 'deb https://apt.corretto.aws stable main'
|
||||
apt-get update; apt-get install -y maven java-21-amazon-corretto-jdk
|
||||
- name: Setup git
|
||||
run: |
|
||||
git config --global user.name "Radim Lipovčan"
|
||||
git config --global user.email "radim@lipovcan.cz"
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
- name: Build | Maven clean build
|
||||
run: |
|
||||
mvn clean install && ls -lah && ls */ -lah && ls */* -lah&& ls */*/* -lah
|
||||
- name: Push | Create release
|
||||
uses: https://git.lipovcan.cz/Upstream/gitea-release-action.git@v1
|
||||
with:
|
||||
files: |-
|
||||
target/CommandPanels-DEV.jar
|
||||
- name: Push | Old FTP way to gitea.lipovcan.cz:8081
|
||||
run: |
|
||||
curl --insecure --user username:mypass -T ./target/CommandPanels-DEV.jar ftp://192.168.10.133:/
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
# Project exclude paths
|
||||
/out/
|
||||
/target/
|
||||
.idea/
|
||||
.idea/
|
||||
.github
|
@ -6,11 +6,6 @@
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="io.papermc" />
|
||||
<option name="name" value="io.papermc" />
|
||||
<option name="url" value="https://papermc.io/repo/repository/maven-releases/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jitpack.io" />
|
||||
<option name="name" value="jitpack.io" />
|
||||
@ -21,11 +16,21 @@
|
||||
<option name="name" value="jeff-media-public" />
|
||||
<option name="url" value="https://hub.jeff-media.com/nexus/repository/jeff-media-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="io.papermc" />
|
||||
<option name="name" value="io.papermc" />
|
||||
<option name="url" value="https://papermc.io/repo/repository/maven-releases/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="sonatype" />
|
||||
<option name="name" value="sonatype" />
|
||||
<option name="url" value="https://oss.sonatype.org/content/groups/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="io.papermc" />
|
||||
<option name="name" value="io.papermc" />
|
||||
<option name="url" value="https://repo.papermc.io/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="codemc-repo" />
|
||||
<option name="name" value="codemc-repo" />
|
||||
@ -47,15 +52,40 @@
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BenCodez Repo" />
|
||||
<option name="name" value="BenCodez Repo" />
|
||||
<option name="url" value="https://nexus.bencodez.com/repository/maven-public/" />
|
||||
<option name="id" value="oraxen" />
|
||||
<option name="name" value="Oraxen Repository" />
|
||||
<option name="url" value="https://repo.oraxen.com/#/releases" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="phoenix" />
|
||||
<option name="name" value="phoenix" />
|
||||
<option name="url" value="https://nexus.phoenixdevt.fr/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BenCodez Repo" />
|
||||
<option name="name" value="BenCodez Repo" />
|
||||
<option name="url" value="https://nexus.bencodez.com/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="central" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="oraxen" />
|
||||
<option name="name" value="Oraxen Repository" />
|
||||
<option name="url" value="https://repo.oraxen.com/releases" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="github" />
|
||||
<option name="name" value="github" />
|
||||
<option name="url" value="https://maven.pkg.github.com/xap3y/skullcreator" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jitpack-repo" />
|
||||
<option name="name" value="jitpack-repo" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="ess-repo" />
|
||||
<option name="name" value="ess-repo" />
|
||||
@ -66,6 +96,11 @@
|
||||
<option name="name" value="spigot-repo" />
|
||||
<option name="url" value="https://hub.spigotmc.org/nexus/content/repositories/snapshots/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jeff-media-public" />
|
||||
<option name="name" value="jeff-media-public" />
|
||||
<option name="url" value="https://repo.jeff-media.com/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
|
50
pom.xml
50
pom.xml
@ -4,7 +4,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>groupId</groupId>
|
||||
<groupId>me.rockyhawk.commandpanels</groupId>
|
||||
<artifactId>CommandPanels</artifactId>
|
||||
<version>DEV</version>
|
||||
|
||||
@ -71,14 +71,14 @@
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>io.papermc</id>
|
||||
<url>https://papermc.io/repo/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>io.papermc</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>minecraft-repo</id>
|
||||
<url>https://libraries.minecraft.net/</url>
|
||||
@ -89,11 +89,7 @@
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jeff-media-public</id>
|
||||
<url>https://hub.jeff-media.com/nexus/repository/jeff-media-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>BenCodez Repo</id>
|
||||
<url>https://nexus.bencodez.com/repository/maven-public/</url>
|
||||
<url>https://repo.jeff-media.com/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>ess-repo</id>
|
||||
@ -126,7 +122,7 @@
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>2.13.1-SNAPSHOT</version>
|
||||
<version>2.14.1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -162,18 +158,12 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.13.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.bencodez</groupId>
|
||||
<artifactId>votingplugin</artifactId>
|
||||
<version>LATEST</version>
|
||||
<scope>provided</scope>
|
||||
<version>2.14.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.3</version>
|
||||
<version>2.11.6</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -185,25 +175,13 @@
|
||||
<dependency>
|
||||
<groupId>net.Indyuce</groupId>
|
||||
<artifactId>MMOItems-API</artifactId>
|
||||
<version>LATEST</version>
|
||||
<version>6.10-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.lumine</groupId>
|
||||
<artifactId>MythicLib-dist</artifactId>
|
||||
<version>LATEST</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.Realizedd</groupId>
|
||||
<artifactId>TokenManager</artifactId>
|
||||
<version>LATEST</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<version>1.6.2-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -212,6 +190,12 @@
|
||||
<version>1.3.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.LoneDev6</groupId>
|
||||
<artifactId>api-itemsadder</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc</groupId>
|
||||
<artifactId>paperlib</artifactId>
|
||||
|
@ -37,7 +37,7 @@ input:
|
||||
- '&aEnter Input for Command'
|
||||
- '&cType &4%cp-args% &cto Cancel the command'
|
||||
hexcodes:
|
||||
start_tag: '#'
|
||||
start_tag: '&#'
|
||||
end_tag: ''
|
||||
placeholders:
|
||||
primary:
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: 3.21.3.3
|
||||
version: 3.21.4.4
|
||||
main: me.rockyhawk.commandpanels.CommandPanels
|
||||
name: CommandPanels
|
||||
author: RockyHawk
|
||||
|
@ -1,11 +1,11 @@
|
||||
package me.rockyhawk.commandpanels;
|
||||
|
||||
import com.bencodez.votingplugin.VotingPluginHooks;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import me.rockyhawk.commandpanels.api.CommandPanelsAPI;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import me.rockyhawk.commandpanels.classresources.ExecuteOpenVoids;
|
||||
import me.rockyhawk.commandpanels.classresources.MiniMessageUtils;
|
||||
import me.rockyhawk.commandpanels.classresources.customheads.GetCustomHeads;
|
||||
import me.rockyhawk.commandpanels.classresources.HasSections;
|
||||
import me.rockyhawk.commandpanels.classresources.ItemCreation;
|
||||
@ -77,7 +77,6 @@ import java.io.Reader;
|
||||
import java.util.*;
|
||||
|
||||
public class CommandPanels extends JavaPlugin{
|
||||
public VotingPluginHooks votingPlugin;
|
||||
public YamlConfiguration config;
|
||||
public Economy econ = null;
|
||||
public boolean openWithItem = false; //this will be true if there is a panel with open-with-item
|
||||
@ -100,6 +99,8 @@ public class CommandPanels extends JavaPlugin{
|
||||
public CreateText tex = new CreateText(this);
|
||||
public HexColours hex = new HexColours(this);
|
||||
|
||||
public MiniMessageUtils miniMessage = null;
|
||||
|
||||
public ExecuteOpenVoids openVoids = new ExecuteOpenVoids(this);
|
||||
public ItemCreation itemCreate = new ItemCreation(this);
|
||||
public HasSections has = new HasSections(this);
|
||||
@ -119,7 +120,6 @@ public class CommandPanels extends JavaPlugin{
|
||||
public InventorySaver inventorySaver = new InventorySaver(this);
|
||||
public ItemStackSerializer itemSerializer = new ItemStackSerializer(this);
|
||||
public UserInputUtils inputUtils = new UserInputUtils(this);
|
||||
public OpenFloodgateGUI floodgateOpenGUI = new OpenFloodgateGUI(this);
|
||||
|
||||
public File panelsf = new File(this.getDataFolder() + File.separator + "panels");
|
||||
public YamlConfiguration blockConfig; //where panel block locations are stored
|
||||
@ -127,6 +127,9 @@ public class CommandPanels extends JavaPlugin{
|
||||
public void onEnable() {
|
||||
Bukkit.getLogger().info("[CommandPanels] RockyHawk's CommandPanels v" + this.getDescription().getVersion() + " Plugin Loading...");
|
||||
|
||||
//Initialise classes that are not used externally
|
||||
new OpenFloodgateGUI(this);
|
||||
|
||||
//register config files
|
||||
this.blockConfig = YamlConfiguration.loadConfiguration(new File(getDataFolder() + File.separator + "blocks.yml"));
|
||||
panelData.dataConfig = YamlConfiguration.loadConfiguration(new File(getDataFolder() + File.separator + "data.yml"));
|
||||
@ -165,6 +168,7 @@ public class CommandPanels extends JavaPlugin{
|
||||
new Metrics(this, 5097);
|
||||
this.setupEconomy();
|
||||
this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
|
||||
this.getServer().getMessenger().registerOutgoingPluginChannel(this, "my:psb");
|
||||
Objects.requireNonNull(this.getCommand("commandpanel")).setExecutor(new Commandpanel(this));
|
||||
Objects.requireNonNull(this.getCommand("commandpanel")).setTabCompleter(new CpTabComplete(this));
|
||||
|
||||
@ -195,6 +199,17 @@ public class CommandPanels extends JavaPlugin{
|
||||
this.getServer().getPluginManager().registerEvents(new legacyPlayerEvent(this), this);
|
||||
}
|
||||
|
||||
try {
|
||||
// Check all the minimessage classes exist before loading
|
||||
Class.forName("net.kyori.adventure.text.Component");
|
||||
Class.forName("net.kyori.adventure.text.format.TextDecoration");
|
||||
Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
|
||||
Class.forName("net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer");
|
||||
miniMessage = new MiniMessageUtils(this);
|
||||
} catch (ClassNotFoundException ignore) {
|
||||
//do not initialise miniMessage
|
||||
}
|
||||
|
||||
this.getServer().getPluginManager().registerEvents(inputUtils, this);
|
||||
this.getServer().getPluginManager().registerEvents(panelDataPlayers, this);
|
||||
this.getServer().getPluginManager().registerEvents(new UtilsPanelsLoader(this), this);
|
||||
@ -246,10 +261,6 @@ public class CommandPanels extends JavaPlugin{
|
||||
if (!Bukkit.getVersion().contains("1.8")) {
|
||||
this.getServer().getPluginManager().registerEvents(new SwapItemEvent(this), this);
|
||||
}
|
||||
//if VotingPlugin is enabled
|
||||
if (getServer().getPluginManager().isPluginEnabled("VotingPlugin")) {
|
||||
votingPlugin= VotingPluginHooks.getInstance();
|
||||
}
|
||||
//if plugin ChestSort is enabled
|
||||
if(getServer().getPluginManager().isPluginEnabled("ChestSort")){
|
||||
this.getServer().getPluginManager().registerEvents(new UtilsChestSortEvent(this), this);
|
||||
|
@ -87,23 +87,24 @@ public class Utils implements Listener {
|
||||
panel = plugin.openPanels.getOpenPanel(p.getName(),position);
|
||||
|
||||
//this loops through all the items in the panel
|
||||
boolean foundSlot = false;
|
||||
for(String slot : Objects.requireNonNull(panel.getConfig().getConfigurationSection("item")).getKeys(false)){
|
||||
String foundSlot = null;
|
||||
for(String item : Objects.requireNonNull(panel.getConfig().getConfigurationSection("item")).getKeys(false)){
|
||||
String slot = plugin.tex.placeholdersNoColour(panel, position, p, item);
|
||||
if (slot.equals(Integer.toString(clickedSlot))) {
|
||||
foundSlot = true;
|
||||
foundSlot = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!foundSlot){
|
||||
if(foundSlot == null){
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//get the section of the slot that was clicked
|
||||
String section = plugin.has.hasSection(panel,position,panel.getConfig().getConfigurationSection("item." + clickedSlot), p);
|
||||
String section = plugin.has.hasSection(panel,position,panel.getConfig().getConfigurationSection("item." + foundSlot), p);
|
||||
|
||||
if(panel.getConfig().contains("item." + clickedSlot + section + ".itemType")){
|
||||
if(panel.getConfig().getStringList("item." + clickedSlot + section + ".itemType").contains("placeable")){
|
||||
if(panel.getConfig().contains("item." + foundSlot + section + ".itemType")){
|
||||
if(panel.getConfig().getStringList("item." + foundSlot + section + ".itemType").contains("placeable")){
|
||||
//skip if the item is a placeable
|
||||
e.setCancelled(false);
|
||||
return;
|
||||
@ -115,13 +116,13 @@ public class Utils implements Listener {
|
||||
p.updateInventory();
|
||||
|
||||
//if an item has an area for input instead of commands
|
||||
if(panel.getConfig().contains("item." + clickedSlot + section + ".player-input")) {
|
||||
plugin.inputUtils.playerInput.put(p,new PlayerInput(panel,panel.getConfig().getStringList("item." + clickedSlot + section + ".player-input"),e.getClick()));
|
||||
if(panel.getConfig().contains("item." + foundSlot + section + ".player-input")) {
|
||||
plugin.inputUtils.playerInput.put(p,new PlayerInput(panel,panel.getConfig().getStringList("item." + foundSlot + section + ".player-input"),e.getClick()));
|
||||
plugin.inputUtils.sendMessage(panel,position,p);
|
||||
}
|
||||
|
||||
if(panel.getConfig().contains("item." + clickedSlot + section + ".commands")) {
|
||||
List<String> commands = panel.getConfig().getStringList("item." + clickedSlot + section + ".commands");
|
||||
if(panel.getConfig().contains("item." + foundSlot + section + ".commands")) {
|
||||
List<String> commands = panel.getConfig().getStringList("item." + foundSlot + section + ".commands");
|
||||
if (!commands.isEmpty()) {
|
||||
for (int i = 0; commands.size() > i; i++) {
|
||||
try {
|
||||
@ -130,9 +131,9 @@ public class Utils implements Listener {
|
||||
commands.set(i, commands.get(i).replaceAll("%cp-clicked%", "AIR"));
|
||||
}
|
||||
}
|
||||
if (panel.getConfig().contains("item." + clickedSlot + section + ".multi-paywall")) {
|
||||
if (panel.getConfig().contains("item." + foundSlot + section + ".multi-paywall")) {
|
||||
plugin.commandRunner.runMultiPaywall(panel,position,p,
|
||||
panel.getConfig().getStringList("item." + clickedSlot + section + ".multi-paywall"),
|
||||
panel.getConfig().getStringList("item." + foundSlot + section + ".multi-paywall"),
|
||||
commands,e.getClick());
|
||||
} else {
|
||||
plugin.commandRunner.runCommands(panel, position, p, commands, e.getClick());
|
||||
|
@ -9,9 +9,7 @@ import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.*;
|
||||
|
||||
public class HasSections {
|
||||
CommandPanels plugin;
|
||||
@ -20,10 +18,29 @@ public class HasSections {
|
||||
}
|
||||
|
||||
public String hasSection(Panel panel, PanelPosition position, ConfigurationSection cf, Player p) {
|
||||
for (String setName : cf.getKeys(false)) {
|
||||
if (!cf.isConfigurationSection(setName)) continue;
|
||||
// Use a TreeMap to automatically sort the sections by the extracted number.
|
||||
Map<Integer, String> sortedSections = new TreeMap<>();
|
||||
|
||||
ConfigurationSection currentSection = cf.getConfigurationSection(setName);
|
||||
// Loop through the section names and filter for the ones starting with "has".
|
||||
for (String key : cf.getKeys(false)) {
|
||||
if (!cf.isConfigurationSection(key)) continue;
|
||||
|
||||
// Check if the section starts with "has" and is followed by a number.
|
||||
if (key.startsWith("has")) {
|
||||
try {
|
||||
// Extract the number after "has" and put it in the map for sorting.
|
||||
int number = Integer.parseInt(key.substring(3));
|
||||
sortedSections.put(number, key);
|
||||
} catch (NumberFormatException ignore) {
|
||||
// If the section name doesn't have a valid number after "has", skip it.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String hasSection : sortedSections.values()) {
|
||||
if (!cf.isConfigurationSection(hasSection)) continue;
|
||||
|
||||
ConfigurationSection currentSection = cf.getConfigurationSection(hasSection);
|
||||
int numberOfConditions = currentSection.getKeys(false).size();
|
||||
|
||||
Boolean currentBlockResult = null; // This will store the result of the current block (a set of conditions combined by AND or OR).
|
||||
@ -48,7 +65,7 @@ public class HasSections {
|
||||
HashSet<String> values = doOperators(new HashSet<>(Collections.singletonList(value)));
|
||||
boolean localResult = false; // This tracks the result of the current condition.
|
||||
for (String val : values) {
|
||||
if (hasProcess(setName, val, compare, p)) {
|
||||
if (hasProcess(val, compare)) {
|
||||
localResult = true;
|
||||
break;
|
||||
}
|
||||
@ -71,7 +88,7 @@ public class HasSections {
|
||||
|
||||
if (currentBlockResult != null && currentBlockResult) {
|
||||
// If the result of this section is true, check nested sections.
|
||||
return "." + setName + hasSection(panel, position, currentSection, p);
|
||||
return "." + hasSection + hasSection(panel, position, currentSection, p);
|
||||
}
|
||||
// If the result is false, continue to the next 'has' section.
|
||||
}
|
||||
@ -90,7 +107,7 @@ public class HasSections {
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean hasProcess(String setName, String value, String compare,Player p){
|
||||
private boolean hasProcess(String value, String compare){
|
||||
//check to see if the value should be reversed
|
||||
boolean outputValue = true;
|
||||
if(value.startsWith("NOT ")){
|
||||
@ -99,18 +116,16 @@ public class HasSections {
|
||||
}
|
||||
|
||||
//the current has section with all the functions implemented inside it
|
||||
if(setName.startsWith("has")) {
|
||||
if(value.endsWith(" HASPERM")) {
|
||||
String playername = value.substring(0, value.length()-8);
|
||||
Player player = Bukkit.getPlayerExact(playername);
|
||||
if(player != null){
|
||||
return player.hasPermission(compare) == outputValue;
|
||||
}
|
||||
}else if(value.endsWith(" ISGREATER")) {
|
||||
return (new BigDecimal(compare).compareTo(new BigDecimal(value.substring(0, value.length()-10).replace(",",""))) <= 0 == outputValue);
|
||||
}else{
|
||||
return compare.equals(value) == outputValue;
|
||||
if(value.endsWith(" HASPERM")) {
|
||||
String playername = value.substring(0, value.length()-8);
|
||||
Player player = Bukkit.getPlayerExact(playername);
|
||||
if(player != null){
|
||||
return player.hasPermission(compare) == outputValue;
|
||||
}
|
||||
}else if(value.endsWith(" ISGREATER")) {
|
||||
return (new BigDecimal(compare).compareTo(new BigDecimal(value.substring(0, value.length()-10).replace(",",""))) <= 0 == outputValue);
|
||||
}else{
|
||||
return compare.equals(value) == outputValue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package me.rockyhawk.commandpanels.classresources;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import me.arcaniax.hdb.api.HeadDatabaseAPI;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import me.rockyhawk.commandpanels.classresources.customheads.SavedCustomHead;
|
||||
import me.rockyhawk.commandpanels.ioclasses.legacy.MinecraftVersions;
|
||||
import me.rockyhawk.commandpanels.openpanelsmanager.PanelPosition;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
@ -26,6 +28,7 @@ import org.bukkit.inventory.meta.trim.TrimMaterial;
|
||||
import org.bukkit.inventory.meta.trim.TrimPattern;
|
||||
import org.bukkit.potion.PotionType;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -94,6 +97,50 @@ public class ItemCreation {
|
||||
}
|
||||
}
|
||||
|
||||
//Oraxen support, uses itemID (eg, oraxen= coin)
|
||||
if (matraw.split("\\s")[0].equalsIgnoreCase("oraxen=")) {
|
||||
String itemID = matraw.split("\\s")[1];
|
||||
try {
|
||||
// Load the OraxenItems class
|
||||
Class<?> oraxenItemsClass = Class.forName("io.th0rgal.oraxen.api.OraxenItems");
|
||||
|
||||
// Retrieve the 'getItemById' method from the OraxenItems class
|
||||
Method getItemByIdMethod = oraxenItemsClass.getMethod("getItemById", String.class);
|
||||
getItemByIdMethod.setAccessible(true);
|
||||
|
||||
// Invoke the 'getItemById' method with the itemID
|
||||
Object oraxenItem = getItemByIdMethod.invoke(null, itemID); // static method, so pass 'null'
|
||||
|
||||
// Ensure that the method returned a valid Oraxen item
|
||||
if (oraxenItem != null) {
|
||||
// Now we need to invoke 'getReferenceClone' on the OraxenItem object
|
||||
Method getReferenceCloneMethod = oraxenItem.getClass().getMethod("getReferenceClone");
|
||||
getReferenceCloneMethod.setAccessible(true);
|
||||
ItemStack stack = (ItemStack) getReferenceCloneMethod.invoke(oraxenItem);
|
||||
|
||||
// Check if stack is not null
|
||||
if (stack != null) {
|
||||
s = stack;
|
||||
normalCreation = false;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.debug(e, null);
|
||||
// Handle the error or inform the player
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//ItemsAdder support, needs namespaceID (eg, itemsadder= money:coin)
|
||||
if (matraw.split("\\s")[0].equalsIgnoreCase("itemsadder=")) {
|
||||
String namespaceID = matraw.split("\\s")[1];
|
||||
CustomStack stack = CustomStack.getInstance(namespaceID);
|
||||
if(stack != null) {
|
||||
s = stack.getItemStack().clone();
|
||||
normalCreation = false;
|
||||
}
|
||||
}
|
||||
|
||||
//creates custom MMOItems items
|
||||
if(matraw.split("\\s")[0].equalsIgnoreCase("mmo=") && plugin.getServer().getPluginManager().isPluginEnabled("MMOItems")){
|
||||
String itemType = matraw.split("\\s")[1];
|
||||
@ -433,14 +480,7 @@ public class ItemCreation {
|
||||
}
|
||||
if(plugin.getHeads.ifSkullOrHead(cont.getType().toString())){
|
||||
if(!Objects.requireNonNull(file.getString("panels." + panelName + ".item." + i + ".material")).contains("%") && !Objects.requireNonNull(file.getString("panels." + panelName + ".item." + i + ".material")).contains("=")) {
|
||||
SkullMeta meta = (SkullMeta) cont.getItemMeta();
|
||||
if (plugin.customHeads.getHeadBase64(cont) != null) {
|
||||
//inject base64 here, disable for legacy as is not working
|
||||
file.set("panels." + panelName + ".item." + i + ".material", "cps= " + plugin.customHeads.getHeadBase64(cont));
|
||||
} else{
|
||||
//return blank head
|
||||
file.set("panels." + panelName + ".item." + i + ".material", plugin.getHeads.playerHeadString());
|
||||
}
|
||||
file.set("panels." + panelName + ".item." + i + ".material", plugin.getHeads.playerHeadString());
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
@ -0,0 +1,60 @@
|
||||
package me.rockyhawk.commandpanels.classresources;
|
||||
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MiniMessageUtils {
|
||||
|
||||
CommandPanels plugin;
|
||||
public MiniMessageUtils(CommandPanels pl) {
|
||||
this.plugin = pl;
|
||||
}
|
||||
|
||||
/*
|
||||
MiniMessage is used here as an alternative to the standard Minecraft colour codes &
|
||||
As MiniMessage does not accept legacy colour codes at any point, which is
|
||||
a possibility when using Minecraft colour codes, running a try/catch allows for
|
||||
MiniMessage to be used anywhere and ignored when legacy colour codes are found.
|
||||
*/
|
||||
|
||||
public String doMiniMessageLegacy(String string) {
|
||||
MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||
try {
|
||||
Component component = miniMessage.deserialize(string);
|
||||
return LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.hexColors()
|
||||
.build()
|
||||
.serialize(component);
|
||||
}catch (Exception e){
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> doMiniMessageLegacy(List<String> strings) {
|
||||
return strings.stream()
|
||||
.map(this::doMiniMessageLegacy)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Component doMiniMessage(String string) {
|
||||
LegacyComponentSerializer legacyComponentSerializer = LegacyComponentSerializer.builder().hexColors().character('&').build();
|
||||
Component component = legacyComponentSerializer.deserialize(string.replace('§', '&'));
|
||||
|
||||
return MiniMessage.miniMessage().deserialize(MiniMessage.miniMessage().serialize(component.decoration(TextDecoration.ITALIC, false))
|
||||
.replace("\\<", "<").replace("\\", "").replace("\n", "<br>")).decoration(TextDecoration.ITALIC, false);
|
||||
|
||||
}
|
||||
|
||||
public List<Component> doMiniMessage(List<String> strings) {
|
||||
return strings.stream()
|
||||
.map(this::doMiniMessage)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package me.rockyhawk.commandpanels.classresources;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
|
||||
public class SerializerUtils {
|
||||
|
||||
public static Component serializeText(String msg){
|
||||
return MiniMessage.miniMessage().deserialize(msg);
|
||||
}
|
||||
}
|
@ -1,216 +1,34 @@
|
||||
package me.rockyhawk.commandpanels.classresources.customheads;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.mojang.authlib.properties.PropertyMap;
|
||||
import me.arcaniax.hdb.api.HeadDatabaseAPI;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.classresources.customheads.methods.CustomHeadGameProfile;
|
||||
import me.rockyhawk.commandpanels.classresources.customheads.methods.CustomHeadPlayerProfile;
|
||||
import me.rockyhawk.commandpanels.ioclasses.legacy.MinecraftVersions;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class GetCustomHeads {
|
||||
CustomHeadGameProfile gameProfileHeadClass;
|
||||
CustomHeadPlayerProfile playerProfileHeadClass;
|
||||
CommandPanels plugin;
|
||||
|
||||
public GetCustomHeads(CommandPanels pl) {
|
||||
this.plugin = pl;
|
||||
gameProfileHeadClass = new CustomHeadGameProfile(pl);
|
||||
playerProfileHeadClass = new CustomHeadPlayerProfile();
|
||||
}
|
||||
|
||||
public HashMap<String, SavedCustomHead> savedCustomHeads = new HashMap<>();
|
||||
|
||||
public String getHeadBase64(ItemStack head) {
|
||||
if (plugin.getHeads.ifSkullOrHead(head.getType().toString()) && head.hasItemMeta()) {
|
||||
//check if the head is a HeadDatabase head first
|
||||
if(plugin.getServer().getPluginManager().isPluginEnabled("HeadDatabase")) {
|
||||
HeadDatabaseAPI api = new HeadDatabaseAPI();
|
||||
try {
|
||||
String base64 = api.getBase64(head);
|
||||
if(base64 != null){
|
||||
return base64;
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
//try getting Base64 of a custom head
|
||||
if (!(head.getItemMeta() instanceof SkullMeta)) return null;
|
||||
SkullMeta meta = (SkullMeta) head.getItemMeta();
|
||||
if (meta == null) return null;
|
||||
|
||||
try {
|
||||
Field profileField = meta.getClass().getDeclaredField("profile");
|
||||
profileField.setAccessible(true);
|
||||
GameProfile profile = (GameProfile) profileField.get(meta);
|
||||
|
||||
Collection<Property> textures = profile.getProperties().get("textures");
|
||||
if (!textures.isEmpty()) {
|
||||
// Directly accessing fields within the Property object via reflection.
|
||||
Property textureProperty = textures.iterator().next();
|
||||
Field valueField = textureProperty.getClass().getDeclaredField("value");
|
||||
valueField.setAccessible(true);
|
||||
return (String) valueField.get(textureProperty);
|
||||
}
|
||||
|
||||
} catch (Exception error) {
|
||||
plugin.debug(error, null);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//getting the head from a Player Name
|
||||
public ItemStack getPlayerHead(String name) {
|
||||
byte id = 0;
|
||||
if (plugin.legacy.MAJOR_VERSION.lessThanOrEqualTo(MinecraftVersions.v1_15)) {
|
||||
id = 3;
|
||||
}
|
||||
|
||||
//get texture if already cached
|
||||
if (savedCustomHeads.containsKey(name)) {
|
||||
if (!savedCustomHeads.get(name).isValid && (System.currentTimeMillis() - savedCustomHeads.get(name).lastAttempt) < 60000) {
|
||||
// If the last attempt was less than 60 seconds ago and was invalid, return null or a default item
|
||||
return new ItemStack(Material.valueOf(plugin.getHeads.playerHeadString()));
|
||||
}
|
||||
if(savedCustomHeads.get(name).isValid) {
|
||||
return savedCustomHeads.get(name).headItem; // Return cached item if valid
|
||||
}
|
||||
}
|
||||
|
||||
//create ItemStack
|
||||
ItemStack itemStack = new ItemStack(Material.matchMaterial(plugin.getHeads.playerHeadString()), 1, id);
|
||||
|
||||
//Run fallback code, if API call fails, use legacy setOwner
|
||||
SkullMeta meta = (SkullMeta) itemStack.getItemMeta();
|
||||
meta.setOwner(name);
|
||||
itemStack.setItemMeta(meta);
|
||||
|
||||
// Fetch and cache the texture asynchronously
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
try {
|
||||
if(plugin.debug.consoleDebug){
|
||||
plugin.getServer().getConsoleSender().sendMessage(plugin.tex.colour(plugin.tag +
|
||||
ChatColor.WHITE +
|
||||
"Download & Cache Head Texture for " + name));
|
||||
}
|
||||
|
||||
// Fetch the player UUID from the Mojang API
|
||||
URL uuidUrl = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
|
||||
URLConnection uuidConnection = uuidUrl.openConnection();
|
||||
uuidConnection.setConnectTimeout(2000); // Set connection timeout to 2 seconds
|
||||
uuidConnection.setReadTimeout(2000); // Set read timeout to 2 seconds
|
||||
//Json is simple and structured so a hard code solution will avoid the need for a library
|
||||
String uuidReader = new Scanner(uuidConnection.getInputStream(),
|
||||
StandardCharsets.UTF_8.name()).useDelimiter("\\A").next();
|
||||
String uuid = uuidReader.split("\"id\" : \"")[1].split("\"")[0];
|
||||
|
||||
// Fetch the skin texture from the Mojang API using the player UUID
|
||||
URL texturesUrl = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid);
|
||||
URLConnection texturesConnection = texturesUrl.openConnection();
|
||||
texturesConnection.setConnectTimeout(2000); // Set connection timeout to 2 seconds
|
||||
texturesConnection.setReadTimeout(2000); // Set read timeout to 2 seconds
|
||||
//Json is simple and structured so a hard code solution will avoid the need for a library
|
||||
String valueReader = new Scanner(texturesConnection.getInputStream(),
|
||||
StandardCharsets.UTF_8.name()).useDelimiter("\\A").next();
|
||||
String value = valueReader.split("\"value\" : \"")[1].split("\"")[0];
|
||||
|
||||
// Once the API call is finished, update the ItemStack on the main thread
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
itemStack.setItemMeta(getCustomHead(name, value).getItemMeta());
|
||||
savedCustomHeads.put(name, new SavedCustomHead(itemStack, value, true));
|
||||
});
|
||||
} catch (Exception ignore) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
//do not overwrite a valid cached head
|
||||
if(savedCustomHeads.containsKey(name) && savedCustomHeads.get(name).isValid){
|
||||
return;
|
||||
}
|
||||
savedCustomHeads.put(name, new SavedCustomHead(null, null, false)); // Mark as invalid
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
//will also use cached heads feature to get heads if player name is provided
|
||||
public ItemStack getCustomHead(String playerName, String b64stringtexture) {
|
||||
//check for any saved heads
|
||||
if(savedCustomHeads.containsKey(playerName)) {
|
||||
if (savedCustomHeads.get(playerName).base64 != null) {
|
||||
return savedCustomHeads.get(playerName).headItem;
|
||||
}
|
||||
savedCustomHeads.get(playerName).isValid = false;
|
||||
}
|
||||
|
||||
//if saved head is not found from player name, get head manually
|
||||
return getCustomHead(b64stringtexture);
|
||||
}
|
||||
|
||||
//used to get heads from Base64 Textures
|
||||
@SuppressWarnings("deprecation")
|
||||
public ItemStack getCustomHead(String b64stringtexture) {
|
||||
//get head from base64
|
||||
GameProfile profile = new GameProfile(UUID.randomUUID(), "");
|
||||
PropertyMap propertyMap = profile.getProperties();
|
||||
if (propertyMap == null) {
|
||||
throw new IllegalStateException("Profile doesn't contain a property map");
|
||||
} else {
|
||||
propertyMap.put("textures", new Property("textures", b64stringtexture));
|
||||
byte id = 0;
|
||||
if(plugin.legacy.MAJOR_VERSION.lessThanOrEqualTo(MinecraftVersions.v1_15)){
|
||||
id = 3;
|
||||
}
|
||||
ItemStack head = new ItemStack(Material.matchMaterial(plugin.getHeads.playerHeadString()), 1,id);
|
||||
ItemMeta headMeta = head.getItemMeta();
|
||||
assert headMeta != null;
|
||||
|
||||
Field profileField;
|
||||
Method setProfileMethod = null;
|
||||
try {
|
||||
// Attempt to access the 'profile' field directly
|
||||
// Also writes to 'serializedProfile' field as one cannot be null while the other is not
|
||||
// This block is mainly for 1.20.2+ versions
|
||||
profileField = headMeta.getClass().getDeclaredField("profile");
|
||||
Field serializedProfileField = headMeta.getClass().getDeclaredField("serializedProfile");
|
||||
|
||||
profileField.setAccessible(true);
|
||||
serializedProfileField.setAccessible(true);
|
||||
|
||||
profileField.set(headMeta, profile);
|
||||
serializedProfileField.set(headMeta, profile); // Assuming serializedProfile is of the same type
|
||||
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e1) {
|
||||
try {
|
||||
// This block covers versions that have a 'setProfile' method instead of direct field access
|
||||
// Likely for versions prior to 1.20.2
|
||||
setProfileMethod = headMeta.getClass().getDeclaredMethod("setProfile", GameProfile.class);
|
||||
} catch (NoSuchMethodException ignore) {}
|
||||
} catch (SecurityException ignored) {}
|
||||
try {
|
||||
if (setProfileMethod == null) {
|
||||
// Attempt to access the 'profile' field directly
|
||||
// This block is a generic fallback for versions lacking the 'setProfile' method
|
||||
profileField = headMeta.getClass().getDeclaredField("profile");
|
||||
profileField.setAccessible(true);
|
||||
profileField.set(headMeta, profile);
|
||||
} else {
|
||||
// Use the 'setProfile' method if it was found
|
||||
setProfileMethod.setAccessible(true);
|
||||
setProfileMethod.invoke(headMeta, profile);
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
plugin.debug(e1,null);
|
||||
}
|
||||
|
||||
head.setItemMeta(headMeta);
|
||||
return head;
|
||||
public ItemStack getCustomHead(String base64){
|
||||
if(plugin.legacy.MAJOR_VERSION.greaterThanOrEqualTo(MinecraftVersions.v1_18)){
|
||||
return playerProfileHeadClass.getCustomHead(base64);
|
||||
}else{
|
||||
return gameProfileHeadClass.getCustomHead(base64);
|
||||
}
|
||||
}
|
||||
}
|
||||
public ItemStack getPlayerHead(String playerName){
|
||||
if(plugin.legacy.MAJOR_VERSION.greaterThanOrEqualTo(MinecraftVersions.v1_21)){
|
||||
return playerProfileHeadClass.getPlayerHead(playerName);
|
||||
}else{
|
||||
return gameProfileHeadClass.getPlayerHead(playerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,185 @@
|
||||
package me.rockyhawk.commandpanels.classresources.customheads.methods;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.mojang.authlib.properties.PropertyMap;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.classresources.customheads.SavedCustomHead;
|
||||
import me.rockyhawk.commandpanels.ioclasses.legacy.MinecraftVersions;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class CustomHeadGameProfile {
|
||||
CommandPanels plugin;
|
||||
public CustomHeadGameProfile(CommandPanels pl) {
|
||||
this.plugin = pl;
|
||||
}
|
||||
|
||||
public HashMap<String, SavedCustomHead> savedCustomHeads = new HashMap<>();
|
||||
|
||||
//getting the head from a Player Name
|
||||
public ItemStack getPlayerHead(String name) {
|
||||
byte id = 0;
|
||||
if (plugin.legacy.MAJOR_VERSION.lessThanOrEqualTo(MinecraftVersions.v1_15)) {
|
||||
id = 3;
|
||||
}
|
||||
|
||||
//get texture if already cached
|
||||
if (savedCustomHeads.containsKey(name)) {
|
||||
if (!savedCustomHeads.get(name).isValid && (System.currentTimeMillis() - savedCustomHeads.get(name).lastAttempt) < 60000) {
|
||||
// If the last attempt was less than 60 seconds ago and was invalid, return null or a default item
|
||||
return new ItemStack(Material.valueOf(plugin.getHeads.playerHeadString()));
|
||||
}
|
||||
if(savedCustomHeads.get(name).isValid) {
|
||||
return savedCustomHeads.get(name).headItem; // Return cached item if valid
|
||||
}
|
||||
}
|
||||
|
||||
//create ItemStack
|
||||
ItemStack itemStack = new ItemStack(Material.matchMaterial(plugin.getHeads.playerHeadString()), 1, id);
|
||||
|
||||
//Run fallback code, if API call fails, use legacy setOwner
|
||||
SkullMeta meta = (SkullMeta) itemStack.getItemMeta();
|
||||
meta.setOwner(name);
|
||||
itemStack.setItemMeta(meta);
|
||||
|
||||
// Fetch and cache the texture asynchronously
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
try {
|
||||
if(plugin.debug.consoleDebug){
|
||||
plugin.getServer().getConsoleSender().sendMessage(plugin.tex.colour(plugin.tag +
|
||||
ChatColor.WHITE +
|
||||
"Download & Cache Head Texture for " + name));
|
||||
}
|
||||
|
||||
// Fetch the player UUID from the Mojang API
|
||||
URL uuidUrl = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
|
||||
URLConnection uuidConnection = uuidUrl.openConnection();
|
||||
uuidConnection.setConnectTimeout(2000); // Set connection timeout to 2 seconds
|
||||
uuidConnection.setReadTimeout(2000); // Set read timeout to 2 seconds
|
||||
//Json is simple and structured so a hard code solution will avoid the need for a library
|
||||
String uuidReader = new Scanner(uuidConnection.getInputStream(),
|
||||
StandardCharsets.UTF_8.name()).useDelimiter("\\A").next();
|
||||
String uuid = uuidReader.split("\"id\" : \"")[1].split("\"")[0];
|
||||
|
||||
// Fetch the skin texture from the Mojang API using the player UUID
|
||||
URL texturesUrl = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid);
|
||||
URLConnection texturesConnection = texturesUrl.openConnection();
|
||||
texturesConnection.setConnectTimeout(2000); // Set connection timeout to 2 seconds
|
||||
texturesConnection.setReadTimeout(2000); // Set read timeout to 2 seconds
|
||||
//Json is simple and structured so a hard code solution will avoid the need for a library
|
||||
String valueReader = new Scanner(texturesConnection.getInputStream(),
|
||||
StandardCharsets.UTF_8.name()).useDelimiter("\\A").next();
|
||||
String value = valueReader.split("\"value\" : \"")[1].split("\"")[0];
|
||||
|
||||
// Once the API call is finished, update the ItemStack on the main thread
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
itemStack.setItemMeta(getCustomHead(name, value).getItemMeta());
|
||||
savedCustomHeads.put(name, new SavedCustomHead(itemStack, value, true));
|
||||
});
|
||||
} catch (Exception ignore) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
//do not overwrite a valid cached head
|
||||
if(savedCustomHeads.containsKey(name) && savedCustomHeads.get(name).isValid){
|
||||
return;
|
||||
}
|
||||
savedCustomHeads.put(name, new SavedCustomHead(null, null, false)); // Mark as invalid
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
//will also use cached heads feature to get heads if player name is provided
|
||||
public ItemStack getCustomHead(String playerName, String b64stringtexture) {
|
||||
//check for any saved heads
|
||||
if(savedCustomHeads.containsKey(playerName)) {
|
||||
if (savedCustomHeads.get(playerName).base64 != null) {
|
||||
return savedCustomHeads.get(playerName).headItem;
|
||||
}
|
||||
savedCustomHeads.get(playerName).isValid = false;
|
||||
}
|
||||
|
||||
//clear cached textures list until length limit is reached
|
||||
Iterator<Map.Entry<String, SavedCustomHead>> iterator = savedCustomHeads.entrySet().iterator();
|
||||
while (savedCustomHeads.size() > 2000 && iterator.hasNext()) {
|
||||
iterator.next(); // Move to next entry
|
||||
iterator.remove(); // Remove the entry
|
||||
}
|
||||
|
||||
//if saved head is not found from player name, get head manually
|
||||
return getCustomHead(b64stringtexture);
|
||||
}
|
||||
|
||||
//used to get heads from Base64 Textures
|
||||
@SuppressWarnings("deprecation")
|
||||
public ItemStack getCustomHead(String b64stringtexture) {
|
||||
//get head from base64
|
||||
GameProfile profile = new GameProfile(UUID.randomUUID(), "");
|
||||
PropertyMap propertyMap = profile.getProperties();
|
||||
if (propertyMap == null) {
|
||||
throw new IllegalStateException("Profile doesn't contain a property map");
|
||||
} else {
|
||||
propertyMap.put("textures", new Property("textures", b64stringtexture));
|
||||
byte id = 0;
|
||||
if(plugin.legacy.MAJOR_VERSION.lessThanOrEqualTo(MinecraftVersions.v1_15)){
|
||||
id = 3;
|
||||
}
|
||||
ItemStack head = new ItemStack(Material.matchMaterial(plugin.getHeads.playerHeadString()), 1,id);
|
||||
ItemMeta headMeta = head.getItemMeta();
|
||||
assert headMeta != null;
|
||||
|
||||
Field profileField;
|
||||
Method setProfileMethod = null;
|
||||
try {
|
||||
// Attempt to access the 'profile' field directly
|
||||
// Also writes to 'serializedProfile' field as one cannot be null while the other is not
|
||||
// This block is mainly for 1.20.2+ versions
|
||||
profileField = headMeta.getClass().getDeclaredField("profile");
|
||||
Field serializedProfileField = headMeta.getClass().getDeclaredField("serializedProfile");
|
||||
|
||||
profileField.setAccessible(true);
|
||||
serializedProfileField.setAccessible(true);
|
||||
|
||||
profileField.set(headMeta, profile);
|
||||
serializedProfileField.set(headMeta, profile); // Assuming serializedProfile is of the same type
|
||||
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e1) {
|
||||
try {
|
||||
// This block covers versions that have a 'setProfile' method instead of direct field access
|
||||
// Likely for versions prior to 1.20.2
|
||||
setProfileMethod = headMeta.getClass().getDeclaredMethod("setProfile", GameProfile.class);
|
||||
} catch (NoSuchMethodException ignore) {}
|
||||
} catch (SecurityException ignored) {}
|
||||
try {
|
||||
if (setProfileMethod == null) {
|
||||
// Attempt to access the 'profile' field directly
|
||||
// This block is a generic fallback for versions lacking the 'setProfile' method
|
||||
profileField = headMeta.getClass().getDeclaredField("profile");
|
||||
profileField.setAccessible(true);
|
||||
profileField.set(headMeta, profile);
|
||||
} else {
|
||||
// Use the 'setProfile' method if it was found
|
||||
setProfileMethod.setAccessible(true);
|
||||
setProfileMethod.invoke(headMeta, profile);
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
plugin.debug(e1,null);
|
||||
}
|
||||
|
||||
head.setItemMeta(headMeta);
|
||||
return head;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package me.rockyhawk.commandpanels.classresources.customheads.methods;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
import org.bukkit.profile.PlayerTextures;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
public class CustomHeadPlayerProfile {
|
||||
//cached itemstacks stored for access
|
||||
public HashMap<String, ItemStack> savedCustomHeads = new HashMap<>();
|
||||
|
||||
//Using the PlayerProfile API for getting custom heads
|
||||
public ItemStack getCustomHead(String base64Texture) {
|
||||
//check for any saved heads
|
||||
if(savedCustomHeads.containsKey(base64Texture)) {
|
||||
return savedCustomHeads.get(base64Texture);
|
||||
}
|
||||
|
||||
//clear cached textures list until length limit is reached
|
||||
Iterator<Map.Entry<String, ItemStack>> iterator = savedCustomHeads.entrySet().iterator();
|
||||
while (savedCustomHeads.size() > 2000 && iterator.hasNext()) {
|
||||
iterator.next(); // Move to next entry
|
||||
iterator.remove(); // Remove the entry
|
||||
}
|
||||
|
||||
// Create a new player head ItemStack
|
||||
ItemStack skull = new ItemStack(Material.PLAYER_HEAD, 1);
|
||||
SkullMeta skullMeta = (SkullMeta) skull.getItemMeta();
|
||||
|
||||
// Create a new PlayerProfile
|
||||
UUID uuid = UUID.randomUUID(); // Unique ID for the profile
|
||||
PlayerProfile profile = Bukkit.createPlayerProfile(uuid);
|
||||
|
||||
// Decode the base64 texture and extract the texture URL
|
||||
String decodedTexture = extractSkinUrlFromBase64(base64Texture);
|
||||
|
||||
// Set the skin URL using PlayerTextures
|
||||
PlayerTextures textures = profile.getTextures();
|
||||
try {
|
||||
// Using a URL object for the texture
|
||||
textures.setSkin(new URL(decodedTexture));
|
||||
} catch (MalformedURLException ignore) {} // Base64 has no URL, ignore
|
||||
|
||||
// Apply the textures to the profile
|
||||
profile.setTextures(textures);
|
||||
|
||||
// Apply the PlayerProfile to the SkullMeta
|
||||
skullMeta.setOwnerProfile(profile);
|
||||
|
||||
// Set the modified SkullMeta back to the ItemStack
|
||||
skull.setItemMeta(skullMeta);
|
||||
|
||||
savedCustomHeads.put(base64Texture, skull);
|
||||
return skull;
|
||||
}
|
||||
|
||||
// New method to get a player head by player name
|
||||
public ItemStack getPlayerHead(String playerName) {
|
||||
//check for any saved heads
|
||||
if(savedCustomHeads.containsKey(playerName)) {
|
||||
return savedCustomHeads.get(playerName);
|
||||
}
|
||||
|
||||
//clear cached textures list until length limit is reached
|
||||
Iterator<Map.Entry<String, ItemStack>> iterator = savedCustomHeads.entrySet().iterator();
|
||||
while (savedCustomHeads.size() > 2000 && iterator.hasNext()) {
|
||||
iterator.next(); // Move to next entry
|
||||
iterator.remove(); // Remove the entry
|
||||
}
|
||||
|
||||
// Create a new player head ItemStack
|
||||
ItemStack skull = new ItemStack(Material.PLAYER_HEAD, 1);
|
||||
SkullMeta skullMeta = (SkullMeta) skull.getItemMeta();
|
||||
|
||||
// Get the OfflinePlayer object for the provided player name
|
||||
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName);
|
||||
|
||||
// Create a PlayerProfile from the player's UUID
|
||||
UUID playerUUID = offlinePlayer.getUniqueId();
|
||||
PlayerProfile profile = Bukkit.createPlayerProfile(playerUUID);
|
||||
|
||||
// Apply the PlayerProfile to the SkullMeta
|
||||
skullMeta.setOwnerProfile(profile);
|
||||
|
||||
// Set the modified SkullMeta back to the ItemStack
|
||||
skull.setItemMeta(skullMeta);
|
||||
|
||||
savedCustomHeads.put(playerName, skull);
|
||||
return skull;
|
||||
}
|
||||
|
||||
// Helper method to extract the skin URL from the base64 texture
|
||||
private String extractSkinUrlFromBase64(String base64Texture) {
|
||||
// Decode the base64 string
|
||||
byte[] decodedBytes = Base64.getDecoder().decode(base64Texture);
|
||||
String decodedString = new String(decodedBytes);
|
||||
|
||||
// Parse the decoded string as JSON
|
||||
JsonObject jsonObject = JsonParser.parseString(decodedString).getAsJsonObject();
|
||||
|
||||
// Navigate to "textures" -> "SKIN" -> "url"
|
||||
JsonObject textures = jsonObject.getAsJsonObject("textures");
|
||||
JsonObject skin = textures.getAsJsonObject("SKIN");
|
||||
|
||||
// Return the URL if it exists
|
||||
return skin.has("url") ? skin.get("url").getAsString() : null;
|
||||
}
|
||||
|
||||
}
|
@ -86,6 +86,9 @@ public class CreateText {
|
||||
//regular string papi, but only colours so Player doesn't need to be there
|
||||
public String colour(String setpapi) {
|
||||
try {
|
||||
if(plugin.miniMessage != null){
|
||||
setpapi = plugin.miniMessage.doMiniMessageLegacy(setpapi);
|
||||
}
|
||||
setpapi = ChatColor.translateAlternateColorCodes('&', setpapi);
|
||||
setpapi = plugin.hex.translateHexColorCodes(setpapi);
|
||||
return setpapi;
|
||||
@ -108,7 +111,11 @@ public class CreateText {
|
||||
public String placeholders(Panel panel, PanelPosition position, Player p, String setpapi) {
|
||||
try {
|
||||
setpapi = attachPlaceholders(panel,position, p,setpapi);
|
||||
setpapi = plugin.hex.translateHexColorCodes(ChatColor.translateAlternateColorCodes('&', setpapi));
|
||||
if(plugin.miniMessage != null){
|
||||
setpapi = plugin.miniMessage.doMiniMessageLegacy(setpapi);
|
||||
}
|
||||
setpapi = ChatColor.translateAlternateColorCodes('&', setpapi);
|
||||
setpapi = plugin.hex.translateHexColorCodes(setpapi);
|
||||
return setpapi;
|
||||
}catch(NullPointerException e){
|
||||
return setpapi;
|
||||
|
@ -35,7 +35,7 @@ public class HexColours {
|
||||
}
|
||||
|
||||
//automatically format regex to escape special characters
|
||||
public String formatRegex(String path){
|
||||
private String formatRegex(String path){
|
||||
String inputString = plugin.config.getString(path);
|
||||
final String[] metaCharacters = {"\\","^","$","{","}","[","]","(",")",".","*","+","?","|","<",">","-","&","%"};
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
package me.rockyhawk.commandpanels.classresources.placeholders;
|
||||
|
||||
import com.bencodez.votingplugin.VotingPluginHooks;
|
||||
import com.earth2me.essentials.Essentials;
|
||||
import me.realized.tokenmanager.api.TokenManager;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import me.rockyhawk.commandpanels.ioclasses.legacy.MinecraftVersions;
|
||||
@ -211,6 +209,52 @@ public class Placeholders {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
//get name value from slot in current open inventory (panel)
|
||||
if(identifier.startsWith("name-")) {
|
||||
try {
|
||||
String nameNumber = identifier.replace("name-", "");
|
||||
String name;
|
||||
try {
|
||||
ItemStack item = p.getOpenInventory().getTopInventory().getItem((int)Double.parseDouble(nameNumber));
|
||||
name = item.getType().toString().replace("_"," ");
|
||||
if(item.hasItemMeta()){
|
||||
if(item.getItemMeta().hasDisplayName()){
|
||||
name = item.getItemMeta().getDisplayName();
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException er) {
|
||||
name = "";
|
||||
}
|
||||
return name;
|
||||
} catch (Exception ex) {
|
||||
plugin.debug(ex,p);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
//get lore value from slot in current open inventory (panel)
|
||||
if(identifier.startsWith("lore-")) {
|
||||
try {
|
||||
String loreNumber = identifier.replace("lore-", "");
|
||||
String lore = "";
|
||||
try {
|
||||
ItemStack item = p.getOpenInventory().getTopInventory().getItem((int)Double.parseDouble(loreNumber));
|
||||
if(item.hasItemMeta()){
|
||||
if(item.getItemMeta().hasLore()){
|
||||
List<String> ListLore = item.getItemMeta().getLore();
|
||||
for(String list : ListLore){
|
||||
lore = lore + list + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException er) {
|
||||
lore = "";
|
||||
}
|
||||
return lore;
|
||||
} catch (Exception ex) {
|
||||
plugin.debug(ex,p);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
//get stack amount from slot in current open inventory (panel)
|
||||
if(identifier.startsWith("stack-")) {
|
||||
try {
|
||||
@ -417,18 +461,6 @@ public class Placeholders {
|
||||
} catch (Exception place) {
|
||||
//skip
|
||||
}
|
||||
if (plugin.getServer().getPluginManager().isPluginEnabled("TokenManager")) {
|
||||
TokenManager api = (TokenManager) Bukkit.getServer().getPluginManager().getPlugin("TokenManager");
|
||||
assert api != null;
|
||||
if(identifier.equals("tokenmanager-balance")) {
|
||||
return Long.toString(api.getTokens(p).orElse(0));
|
||||
}
|
||||
}
|
||||
if (plugin.getServer().getPluginManager().isPluginEnabled("VotingPlugin")) {
|
||||
if(identifier.equals("votingplugin-points")) {
|
||||
return String.valueOf(VotingPluginHooks.getInstance().getUserManager().getVotingPluginUser(p).getPoints());
|
||||
}
|
||||
}
|
||||
//end nodes with PlaceHolders
|
||||
return "";
|
||||
}
|
||||
|
@ -54,9 +54,6 @@ public class Commandpanelsreload implements CommandExecutor {
|
||||
registerCommands();
|
||||
}
|
||||
|
||||
//pre-cache any player head textures from panels will be reloaded
|
||||
plugin.customHeads.savedCustomHeads.clear();
|
||||
|
||||
sender.sendMessage(plugin.tex.colour(plugin.tag + plugin.config.getString("config.format.reload")));
|
||||
}else{
|
||||
sender.sendMessage(plugin.tex.colour(plugin.tag + plugin.config.getString("config.format.perms")));
|
||||
|
@ -52,11 +52,11 @@ public class CommandRunner {
|
||||
CommandTagEvent tags = new CommandTagEvent(plugin, panel, position, p, commandRAW);
|
||||
Bukkit.getPluginManager().callEvent(tags);
|
||||
if (!tags.commandTagUsed) {
|
||||
Bukkit.dispatchCommand(p, plugin.tex.placeholders(panel, position, p, commandRAW.trim()));
|
||||
Bukkit.dispatchCommand(p, plugin.tex.attachPlaceholders(panel, position, p, commandRAW.trim()));
|
||||
}
|
||||
}
|
||||
|
||||
public void runMultiPaywall(Panel panel, PanelPosition position, Player p, List<String> paywalls, List<String> commands, ClickType click) {
|
||||
public boolean runMultiPaywall(Panel panel, PanelPosition position, Player p, List<String> paywalls, List<String> commands, ClickType click) {
|
||||
boolean allPaywallsValid = true;
|
||||
|
||||
// New list combining paywalls and commands
|
||||
@ -79,6 +79,9 @@ public class CommandRunner {
|
||||
if (allPaywallsValid) {
|
||||
plugin.commandRunner.runCommands(panel, position, p, allCommands, click);
|
||||
}
|
||||
|
||||
// Return output as boolean for usage if applicable
|
||||
return allPaywallsValid;
|
||||
}
|
||||
|
||||
//do this on startup to load listeners
|
||||
|
@ -3,7 +3,6 @@ package me.rockyhawk.commandpanels.commandtags;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import me.rockyhawk.commandpanels.openpanelsmanager.PanelPosition;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
@ -40,8 +39,8 @@ public class CommandTagEvent extends Event {
|
||||
if(doApiPlaceholders) {
|
||||
this.args = plugin.tex.attachPlaceholders(panel1,pos, player, split[1].trim()).split("\\s");
|
||||
}else{
|
||||
this.args = ChatColor.translateAlternateColorCodes('&',plugin.placeholders.setPlaceholders(panel, pos, p,split[1].trim(),false)).split("\\s");
|
||||
this.args = ChatColor.translateAlternateColorCodes('&',plugin.placeholders.setPlaceholders(panel, pos, p,split[1].trim(),true)).split("\\s");
|
||||
this.args = plugin.placeholders.setPlaceholders(panel, pos, p,split[1].trim(),false).split("\\s");
|
||||
this.args = plugin.placeholders.setPlaceholders(panel, pos, p,split[1].trim(),true).split("\\s");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,5 +31,20 @@ public class Hasperm implements Listener {
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Blocked;
|
||||
}
|
||||
}
|
||||
|
||||
if(e.name.equalsIgnoreCase("hasnoperm=")){
|
||||
//if player uses hasnoperm= [perm]
|
||||
if (!e.p.hasPermission(e.args[0])) {
|
||||
if (plugin.config.getBoolean("purchase.permission.enable") && e.doDelete) {
|
||||
plugin.tex.sendString(e.panel, PanelPosition.Top, e.p, Objects.requireNonNull(plugin.config.getString("purchase.permission.success")).replaceAll("%cp-args%", e.args[0]));
|
||||
}
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Passed;
|
||||
} else {
|
||||
if (plugin.config.getBoolean("purchase.currency.enable")) {
|
||||
plugin.tex.sendString(e.panel, PanelPosition.Top, e.p, Objects.requireNonNull(plugin.config.getString("purchase.permission.failure")));
|
||||
}
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Blocked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
package me.rockyhawk.commandpanels.commandtags.paywalls;
|
||||
|
||||
import me.realized.tokenmanager.api.TokenManager;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.commandtags.PaywallEvent;
|
||||
import me.rockyhawk.commandpanels.commandtags.PaywallOutput;
|
||||
@ -10,45 +8,67 @@ import org.bukkit.ChatColor;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
import java.util.OptionalLong;
|
||||
|
||||
public class TokenPaywall implements Listener {
|
||||
CommandPanels plugin;
|
||||
private final CommandPanels plugin;
|
||||
|
||||
public TokenPaywall(CommandPanels pl) {
|
||||
this.plugin = pl;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void commandTag(PaywallEvent e){
|
||||
if(e.name.equalsIgnoreCase("tokenpaywall=")){
|
||||
//if player uses tokenpaywall= [price]
|
||||
public void commandTag(PaywallEvent e) {
|
||||
if (e.name.equalsIgnoreCase("tokenpaywall=")) {
|
||||
// if player uses tokenpaywall= [price]
|
||||
try {
|
||||
if (plugin.getServer().getPluginManager().isPluginEnabled("TokenManager")) {
|
||||
final TokenManager api = (TokenManager) Bukkit.getPluginManager().getPlugin("TokenManager");
|
||||
assert api != null;
|
||||
int balance = Integer.parseInt(Long.toString(api.getTokens(e.p).orElse(0)));
|
||||
if (balance >= Double.parseDouble(e.args[0])) {
|
||||
if (e.doDelete) {
|
||||
api.removeTokens(e.p, Long.parseLong(e.args[0]));
|
||||
}
|
||||
//if the message is empty don't send
|
||||
if (plugin.config.getBoolean("purchase.tokens.enable") && e.doDelete) {
|
||||
plugin.tex.sendString(e.panel, PanelPosition.Top, e.p, Objects.requireNonNull(plugin.config.getString("purchase.tokens.success")).replaceAll("%cp-args%", e.args[0]));
|
||||
// Using reflection in this method as TokenManager has issues with Maven due to the Jitpack dependency
|
||||
Object api = Bukkit.getPluginManager().getPlugin("TokenManager");
|
||||
if (api != null) {
|
||||
// Use reflection to access the getTokens and removeTokens methods
|
||||
Method getTokensMethod = api.getClass().getMethod("getTokens", org.bukkit.entity.Player.class);
|
||||
Method removeTokensMethod = api.getClass().getMethod("removeTokens", org.bukkit.entity.Player.class, long.class);
|
||||
|
||||
// Call getTokens
|
||||
Object result = getTokensMethod.invoke(api, e.p);
|
||||
long balance;
|
||||
|
||||
if (result instanceof OptionalLong) {
|
||||
balance = ((OptionalLong) result).orElse(0L);
|
||||
} else {
|
||||
balance = 0L;
|
||||
}
|
||||
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Passed;
|
||||
} else {
|
||||
if (plugin.config.getBoolean("purchase.tokens.enable")) {
|
||||
plugin.tex.sendString(e.panel, PanelPosition.Top, e.p, Objects.requireNonNull(plugin.config.getString("purchase.tokens.failure")));
|
||||
if (balance >= Double.parseDouble(e.args[0])) {
|
||||
if (e.doDelete) {
|
||||
// Call removeTokens
|
||||
removeTokensMethod.invoke(api, e.p, Long.parseLong(e.args[0]));
|
||||
}
|
||||
// if the message is empty don't send
|
||||
if (plugin.config.getBoolean("purchase.tokens.enable") && e.doDelete) {
|
||||
plugin.tex.sendString(e.panel, PanelPosition.Top, e.p, Objects.requireNonNull(plugin.config.getString("purchase.tokens.success")).replaceAll("%cp-args%", e.args[0]));
|
||||
}
|
||||
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Passed;
|
||||
} else {
|
||||
if (plugin.config.getBoolean("purchase.tokens.enable")) {
|
||||
plugin.tex.sendString(e.panel, PanelPosition.Top, e.p, Objects.requireNonNull(plugin.config.getString("purchase.tokens.failure")));
|
||||
}
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Blocked;
|
||||
}
|
||||
} else {
|
||||
plugin.tex.sendString(e.p, plugin.tag + ChatColor.RED + "Needs TokenManager to work!");
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Blocked;
|
||||
}
|
||||
} else {
|
||||
plugin.tex.sendString(e.p, plugin.tag + ChatColor.RED + "Needs TokenManager to work!");
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Blocked;
|
||||
}
|
||||
} catch (Exception buyc) {
|
||||
plugin.debug(buyc, e.p);
|
||||
} catch (Exception ex) {
|
||||
plugin.debug(ex, e.p);
|
||||
plugin.tex.sendString(e.p, plugin.tag + plugin.config.getString("config.format.error") + " " + "commands: " + e.name);
|
||||
e.PAYWALL_OUTPUT = PaywallOutput.Blocked;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ public class ItemPaywall implements Listener {
|
||||
@EventHandler
|
||||
public void commandTag(PaywallEvent e){
|
||||
if(e.name.equalsIgnoreCase("item-paywall=")){
|
||||
//if player uses item-paywall= [Material] [Amount] <id:#> <IGNORENBT> WILL NOT TAKE CUSTOM ITEMS. IGNORENBT lets nbt items through. Useful for spawner edge cases.
|
||||
//if player uses item-paywall= [Material] [Amount] <IGNORENBT> WILL NOT TAKE CUSTOM ITEMS. IGNORENBT lets nbt items through. Useful for spawner edge cases.
|
||||
//player can use item-paywall= [custom-item] [Amount]
|
||||
try {
|
||||
boolean ignoreNBT = false;
|
||||
|
@ -1,8 +1,10 @@
|
||||
package me.rockyhawk.commandpanels.commandtags.tags.standard;
|
||||
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.api.PanelCommandEvent;
|
||||
import me.rockyhawk.commandpanels.classresources.SerializerUtils;
|
||||
import me.rockyhawk.commandpanels.classresources.MiniMessageUtils;
|
||||
import me.rockyhawk.commandpanels.commandtags.CommandTagEvent;
|
||||
import me.rockyhawk.commandpanels.ioclasses.legacy.MinecraftVersions;
|
||||
import me.rockyhawk.commandpanels.openpanelsmanager.PanelOpenType;
|
||||
@ -69,6 +71,18 @@ public class BasicTags implements Listener {
|
||||
e.p.chat("/" + String.join(" ",e.args));
|
||||
return;
|
||||
}
|
||||
if (e.name.equalsIgnoreCase("bungee=")) {
|
||||
e.commandTagUsed();
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
try {
|
||||
out.writeUTF(e.p.getName());
|
||||
out.writeUTF(String.join(" ",e.args));
|
||||
} catch(Exception ex) {
|
||||
e.p.sendMessage(plugin.tag + ChatColor.translateAlternateColorCodes('&', "&cSomething wrong happened..."));
|
||||
}
|
||||
e.p.sendPluginMessage(plugin, "my:psb", out.toByteArray());
|
||||
return;
|
||||
}
|
||||
if(e.name.equalsIgnoreCase("msg=")) {
|
||||
e.commandTagUsed();
|
||||
plugin.tex.sendString(e.panel,e.pos,e.p,String.join(" ",e.args));
|
||||
@ -140,7 +154,7 @@ public class BasicTags implements Listener {
|
||||
//do mini message if conditions are met
|
||||
if (plugin.legacy.MAJOR_VERSION.greaterThanOrEqualTo(MinecraftVersions.v1_18)) {
|
||||
Audience player = (Audience) e.p; // Needed because the basic Player from the Event can't send Paper's Components
|
||||
Component parsedText = SerializerUtils.serializeText(String.join(" ", e.args));
|
||||
Component parsedText = plugin.miniMessage.doMiniMessage(String.join(" ", e.args));
|
||||
player.sendMessage(parsedText);
|
||||
} else {
|
||||
plugin.tex.sendString(e.p, plugin.tag + ChatColor.RED + "MiniMessage-Feature needs Paper 1.18 or newer to work!");
|
||||
|
@ -3,19 +3,19 @@ package me.rockyhawk.commandpanels.editor;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import net.md_5.bungee.api.chat.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class CommandPanelsEditor implements CommandExecutor {
|
||||
CommandPanels plugin;
|
||||
@ -81,14 +81,11 @@ public class CommandPanelsEditor implements CommandExecutor {
|
||||
}
|
||||
//download the requested panel using an import
|
||||
if (args.length == 3) {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
downloadPanel(sender,args[1],args[0], args[2]);
|
||||
plugin.reloadPanelFiles();
|
||||
plugin.hotbar.reloadHotbarSlots();
|
||||
}
|
||||
}.run();
|
||||
downloadPanel(sender,args[1],args[0], args[2]).thenAccept((ignored) -> {
|
||||
plugin.reloadPanelFiles();
|
||||
plugin.hotbar.reloadHotbarSlots();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
@ -99,12 +96,17 @@ public class CommandPanelsEditor implements CommandExecutor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void downloadPanel(CommandSender sender, String userID, String fileName, String token) {
|
||||
private CompletableFuture<Void> downloadPanel(CommandSender sender, String userID, String fileName, String token) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
|
||||
//get custom editor URL
|
||||
String url = "https://firebasestorage.googleapis.com/v0/b/commandpanels-website.appspot.com/o/pastes%2F" + userID + "%2F" + fileName + "?alt=media&token=" + token;
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
plugin.downloader.downloadPanel(sender, url, fileName);
|
||||
future.complete(null);
|
||||
});
|
||||
|
||||
plugin.downloader.downloadPanel(sender, url, fileName);
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
private String readFileAsString(String filePath) {
|
||||
|
@ -85,7 +85,7 @@ public class OpenFloodgateGUI implements Listener {
|
||||
ConfigurationSection buttonConfig = fgPanel.getConfigurationSection(key + section);
|
||||
if (buttonConfig == null) return null;
|
||||
|
||||
String buttonContent = plugin.tex.placeholders(panel, null, p, buttonConfig.getString("text"));
|
||||
String buttonContent = plugin.tex.placeholders(panel, null, p, buttonConfig.getString("text").replaceAll("\\\\n", "\n"));
|
||||
if (!buttonConfig.contains("icon")) {
|
||||
form.button(buttonContent);
|
||||
} else {
|
||||
@ -116,12 +116,12 @@ public class OpenFloodgateGUI implements Listener {
|
||||
}
|
||||
switch (type) {
|
||||
case "toggle":
|
||||
form.toggle(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("text")),
|
||||
form.toggle(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("text").replaceAll("\\\\n", "\n")),
|
||||
Boolean.parseBoolean(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("default"))));
|
||||
commandsOrder.add(key);
|
||||
break;
|
||||
case "slider":
|
||||
form.slider(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("text")),
|
||||
form.slider(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("text").replaceAll("\\\\n", "\n")),
|
||||
Long.parseLong(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("min"))),
|
||||
Long.parseLong(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("max"))),
|
||||
Long.parseLong(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("step"))),
|
||||
@ -129,13 +129,13 @@ public class OpenFloodgateGUI implements Listener {
|
||||
commandsOrder.add(key);
|
||||
break;
|
||||
case "input":
|
||||
form.input(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("text")),
|
||||
form.input(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("text").replaceAll("\\\\n", "\n")),
|
||||
plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("placeholder")),
|
||||
plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("default")));
|
||||
commandsOrder.add(key);
|
||||
break;
|
||||
case "dropdown":
|
||||
form.dropdown(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("text")),
|
||||
form.dropdown(plugin.tex.placeholders(e.getPanel(), null, e.getPlayer(), fieldConfig.getString("text").replaceAll("\\\\n", "\n")),
|
||||
plugin.tex.placeholdersList(e.getPanel(), null, e.getPlayer(), fieldConfig.getStringList("options"), true));
|
||||
commandsOrder.add(key);
|
||||
break;
|
||||
|
@ -22,6 +22,10 @@ public class Commandpanelrefresher implements Listener {
|
||||
}
|
||||
@EventHandler
|
||||
public void onPanelOpen(PanelOpenedEvent e){ //Handles when Players open inventory
|
||||
if(e.isCancelled()){
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.config.contains("config.refresh-panels")) {
|
||||
if (Objects.requireNonNull(plugin.config.getString("config.refresh-panels")).trim().equalsIgnoreCase("false")) {
|
||||
return;
|
||||
|
@ -9,7 +9,6 @@ import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
@ -50,9 +49,9 @@ public class OpenGUI {
|
||||
Set<String> itemList = pconfig.getConfigurationSection("item").getKeys(false);
|
||||
HashSet<Integer> takenSlots = new HashSet<>();
|
||||
for (String item : itemList) {
|
||||
String section = "";
|
||||
String section;
|
||||
//openType needs to not be 3 so the editor won't include hasperm and hasvalue, etc items
|
||||
section = plugin.has.hasSection(panel,position,pconfig.getConfigurationSection("item." + Integer.parseInt(item)), p);
|
||||
section = plugin.has.hasSection(panel,position,pconfig.getConfigurationSection("item." + item), p);
|
||||
//This section is for animations below here: VISUAL ONLY
|
||||
|
||||
//check for if there is animations inside the items section
|
||||
@ -70,17 +69,16 @@ public class OpenGUI {
|
||||
//this is for contents in the itemType section
|
||||
if (pconfig.getStringList("item." + item + section + ".itemType").contains("placeable") && openType == PanelOpenType.Refresh) {
|
||||
//keep item the same, openType == 0 meaning panel is refreshing
|
||||
setItem(p.getOpenInventory().getItem(Integer.parseInt(item)),Integer.parseInt(item),i,p,position);
|
||||
takenSlots.add(Integer.parseInt(item));
|
||||
setItem(p.getOpenInventory().getItem(Integer.parseInt(plugin.tex.placeholdersNoColour(panel,position,p,item))), item, i, p, position);
|
||||
takenSlots.add(Integer.parseInt(plugin.tex.placeholdersNoColour(panel,position,p,item)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
//place item into the GUI
|
||||
setItem(s,Integer.parseInt(item),i,p,position);
|
||||
takenSlots.add(Integer.parseInt(item));
|
||||
//i.setItem(Integer.parseInt(item), s);
|
||||
setItem(s,item,i,p,position);
|
||||
takenSlots.add(Integer.parseInt(plugin.tex.placeholdersNoColour(panel,position,p,item)));
|
||||
//only place duplicate items in without the editor mode. These are merely visual and will not carry over commands
|
||||
if(pconfig.contains("item." + item + section + ".duplicate")) {
|
||||
try {
|
||||
@ -121,19 +119,20 @@ public class OpenGUI {
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException ignore) {}
|
||||
}
|
||||
if (pconfig.contains("empty") && !Objects.equals(pconfig.getString("empty"), "AIR")) {
|
||||
if (pconfig.contains("empty") && !plugin.tex.placeholdersNoColour(panel,position,p,pconfig.getString("empty")).equals("AIR")) {
|
||||
String emptyValue = plugin.tex.placeholdersNoColour(panel,position,p,pconfig.getString("empty"));
|
||||
ItemStack empty;
|
||||
try {
|
||||
//emptyID for older versions of minecraft (might be deprecated later on)
|
||||
short id = 0;
|
||||
if(pconfig.contains("emptyID")){
|
||||
id = Short.parseShort(pconfig.getString("emptyID"));
|
||||
id = Short.parseShort(plugin.tex.placeholdersNoColour(panel,position,p,pconfig.getString("emptyID")));
|
||||
}
|
||||
//either use custom item or just material type
|
||||
if(pconfig.contains("custom-item." + pconfig.getString("empty"))){
|
||||
empty = plugin.itemCreate.makeItemFromConfig(panel,position,pconfig.getConfigurationSection("custom-item." + pconfig.getString("empty")),p,true,true,true);
|
||||
if(pconfig.contains("custom-item." + emptyValue)){
|
||||
empty = plugin.itemCreate.makeItemFromConfig(panel,position,pconfig.getConfigurationSection("custom-item." + emptyValue),p,true,true,true);
|
||||
}else{
|
||||
empty = new ItemStack(Objects.requireNonNull(Material.matchMaterial(pconfig.getString("empty").toUpperCase())), 1,id);
|
||||
empty = new ItemStack(Objects.requireNonNull(Material.matchMaterial(emptyValue.toUpperCase())), 1,id);
|
||||
ItemMeta renamedMeta = empty.getItemMeta();
|
||||
assert renamedMeta != null;
|
||||
renamedMeta.setDisplayName(" ");
|
||||
@ -192,6 +191,12 @@ public class OpenGUI {
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
|
||||
//allows for a string to be used instead of integer, for placeholders
|
||||
private void setItem(ItemStack item, String slotName, Inventory inv, Player p, PanelPosition position) throws ArrayIndexOutOfBoundsException{
|
||||
int slot = Integer.parseInt(plugin.tex.placeholdersNoColour(null, position, p, slotName));
|
||||
setItem(item, slot, inv, p, position);
|
||||
}
|
||||
private void setItem(ItemStack item, int slot, Inventory inv, Player p, PanelPosition position) throws ArrayIndexOutOfBoundsException{
|
||||
if(position == PanelPosition.Top){
|
||||
inv.setItem(slot, item);
|
||||
|
@ -3,7 +3,6 @@ package me.rockyhawk.commandpanels.openpanelsmanager;
|
||||
import me.rockyhawk.commandpanels.CommandPanels;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import me.rockyhawk.commandpanels.api.PanelClosedEvent;
|
||||
import me.rockyhawk.commandpanels.classresources.customheads.SavedCustomHead;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -15,8 +14,6 @@ import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class UtilsPanelsLoader implements Listener {
|
||||
@ -74,13 +71,6 @@ public class UtilsPanelsLoader implements Listener {
|
||||
|
||||
//close panels and run commands for Top panel
|
||||
plugin.openPanels.closePanelForLoader(e.getPlayer().getName(),PanelPosition.Top);
|
||||
|
||||
//clear cached textures list until length limit is reached
|
||||
Iterator<Map.Entry<String, SavedCustomHead>> iterator = plugin.customHeads.savedCustomHeads.entrySet().iterator();
|
||||
while (plugin.customHeads.savedCustomHeads.size() > 2000 && iterator.hasNext()) {
|
||||
iterator.next(); // Move to next entry
|
||||
iterator.remove(); // Remove the entry
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
Loading…
Reference in New Issue
Block a user