mirror of
https://github.com/Xiao-MoMi/Custom-Crops.git
synced 2025-12-22 16:39:36 +00:00
1.3.0 性能优化
This commit is contained in:
@@ -100,6 +100,9 @@ public class CommandHandler implements CommandExecutor {
|
|||||||
MessageManager.consoleMessage(config.getString("messages.prefix") + config.getString("messages.nextseason"), Bukkit.getConsoleSender());
|
MessageManager.consoleMessage(config.getString("messages.prefix") + config.getString("messages.nextseason"), Bukkit.getConsoleSender());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(args[0].equalsIgnoreCase("test")){
|
||||||
|
CropManager.testData_2();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,106 +3,133 @@ package net.momirealms.customcrops.Crops;
|
|||||||
import dev.lone.itemsadder.api.CustomBlock;
|
import dev.lone.itemsadder.api.CustomBlock;
|
||||||
import net.momirealms.customcrops.CustomCrops;
|
import net.momirealms.customcrops.CustomCrops;
|
||||||
import net.momirealms.customcrops.DataManager.CropManager;
|
import net.momirealms.customcrops.DataManager.CropManager;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class CropGrow {
|
public class CropGrow {
|
||||||
public static void cropGrow(){
|
public static void cropGrow(){
|
||||||
|
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml");
|
File file = new File(CustomCrops.instance.getDataFolder(), "crop-data.yml");
|
||||||
FileConfiguration data;
|
FileConfiguration data;
|
||||||
data = YamlConfiguration.loadConfiguration(file);
|
data = YamlConfiguration.loadConfiguration(file);
|
||||||
|
|
||||||
boolean enable_season = config.getBoolean("enable-season");
|
boolean enable_season = config.getBoolean("enable-season");
|
||||||
boolean enable_greenhouse = config.getBoolean("config.enable-greenhouse");
|
boolean enable_greenhouse = config.getBoolean("config.enable-greenhouse");
|
||||||
int range = config.getInt("config.greenhouse-range");
|
int range = config.getInt("config.greenhouse-range");
|
||||||
|
double growChance = config.getDouble("config.grow-success-chance");
|
||||||
String glass = config.getString("config.greenhouse-glass");
|
String glass = config.getString("config.greenhouse-glass");
|
||||||
config.getStringList("config.whitelist-worlds").forEach(worldName -> CropManager.getCrops(Objects.requireNonNull(Bukkit.getWorld(worldName))).forEach(seedLocation -> {
|
String wateredPot = config.getString("config.watered-pot");
|
||||||
|
String pot = config.getString("config.pot");
|
||||||
|
String deadCrop = config.getString("config.dead-crop");
|
||||||
|
String current = config.getString("current-season");
|
||||||
|
BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||||
|
|
||||||
|
config.getStringList("config.whitelist-worlds").forEach(worldName -> {
|
||||||
|
|
||||||
World world = Bukkit.getWorld(worldName);
|
World world = Bukkit.getWorld(worldName);
|
||||||
Location potLocation = seedLocation.clone().subtract(0,1,0);
|
CropManager.getCrops(Bukkit.getWorld(worldName)).forEach(seedLocation -> {
|
||||||
String[] seasons = Objects.requireNonNull(data.getString(worldName + "." + seedLocation.getBlockX() + "," + seedLocation.getBlockY() + "," + seedLocation.getBlockZ())).split(",");
|
|
||||||
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(potLocation)) != null && CustomBlock.byAlreadyPlaced(world.getBlockAt(seedLocation)) != null){
|
Location potLocation = seedLocation.clone().subtract(0,1,0);
|
||||||
if (CustomBlock.byAlreadyPlaced((world.getBlockAt(potLocation))).getNamespacedID().equalsIgnoreCase(config.getString("config.watered-pot")) && CustomBlock.byAlreadyPlaced(world.getBlockAt(seedLocation)).getNamespacedID().contains("stage")){
|
Block seedBlock = world.getBlockAt(seedLocation);
|
||||||
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(seedLocation)).getNamespacedID().equalsIgnoreCase(config.getString("config.dead-crop"))){
|
Block potBlock = world.getBlockAt(potLocation);
|
||||||
return;
|
|
||||||
}
|
String[] seasons = StringUtils.split(data.getString(worldName + "." + seedLocation.getBlockX() + "," + seedLocation.getBlockY() + "," + seedLocation.getBlockZ()),",");
|
||||||
String namespace = CustomBlock.byAlreadyPlaced(world.getBlockAt(seedLocation)).getNamespacedID().split(":")[0];
|
|
||||||
String[] cropNameList = CustomBlock.byAlreadyPlaced(world.getBlockAt(seedLocation)).getNamespacedID().split(":")[1].split("_");
|
if (CustomBlock.byAlreadyPlaced(potBlock) != null && CustomBlock.byAlreadyPlaced(seedBlock) != null){
|
||||||
Label_out:
|
|
||||||
if(enable_season){
|
String seedNamespace = CustomBlock.byAlreadyPlaced(seedBlock).getNamespacedID();
|
||||||
if(enable_greenhouse){
|
|
||||||
for(int i = 1; i <= range; i++){
|
if (CustomBlock.byAlreadyPlaced(potBlock).getNamespacedID().equalsIgnoreCase(wateredPot) && seedNamespace.contains("stage")){
|
||||||
Location tempLocation = seedLocation.clone().add(0,i,0);
|
if (seedNamespace.equalsIgnoreCase(deadCrop)){
|
||||||
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)) != null){
|
|
||||||
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)).getNamespacedID().equalsIgnoreCase(glass)){
|
|
||||||
break Label_out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean wrongSeason = true;
|
|
||||||
for(String season : seasons){
|
|
||||||
if(Objects.equals(season, config.getString("current-season"))){
|
|
||||||
wrongSeason = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(wrongSeason){
|
|
||||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () -> {
|
|
||||||
CustomBlock.remove(seedLocation);
|
|
||||||
CustomBlock.place(config.getString("config.dead-crop"),seedLocation);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
String[] split = StringUtils.split(seedNamespace,":");
|
||||||
if (CustomBlock.getInstance( namespace +":"+cropNameList[0] + "_stage_" + nextStage) != null) {
|
String[] cropNameList = StringUtils.split(split[1],"_");
|
||||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () ->{
|
|
||||||
CustomBlock.remove(potLocation);
|
Label_out:
|
||||||
CustomBlock.place(config.getString("config.pot"),potLocation);
|
if(enable_season){
|
||||||
if(Math.random()< config.getDouble("config.grow-success-chance")){
|
if(enable_greenhouse){
|
||||||
CustomBlock.remove(seedLocation);
|
for(int i = 1; i <= range; i++){
|
||||||
CustomBlock.place(namespace + ":" + cropNameList[0] + "_stage_" + nextStage,seedLocation);
|
Location tempLocation = seedLocation.clone().add(0,i,0);
|
||||||
}
|
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)) != null){
|
||||||
return null;
|
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)).getNamespacedID().equalsIgnoreCase(glass)){
|
||||||
});
|
break Label_out;
|
||||||
}
|
}
|
||||||
}else if(CustomBlock.byAlreadyPlaced((world.getBlockAt(potLocation))).getNamespacedID().equalsIgnoreCase(config.getString("config.pot")) && CustomBlock.byAlreadyPlaced(world.getBlockAt(seedLocation)).getNamespacedID().contains("stage")){
|
|
||||||
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(seedLocation)).getNamespacedID().equalsIgnoreCase(config.getString("config.dead-crop"))){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(enable_season) {
|
|
||||||
if(enable_greenhouse){
|
|
||||||
for(int i = 1; i <= range; i++){
|
|
||||||
Location tempLocation = seedLocation.clone().add(0,i,0);
|
|
||||||
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)) != null){
|
|
||||||
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)).getNamespacedID().equalsIgnoreCase(config.getString("config.greenhouse-glass"))){
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
boolean wrongSeason = true;
|
||||||
boolean wrongSeason = true;
|
for(String season : seasons){
|
||||||
for (String season : seasons) {
|
if (Objects.equals(season, current)) {
|
||||||
if (Objects.equals(season, config.getString("current-season"))) {
|
wrongSeason = false;
|
||||||
wrongSeason = false;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(wrongSeason){
|
||||||
|
bukkitScheduler.callSyncMethod(CustomCrops.instance, () -> {
|
||||||
|
CustomBlock.remove(seedLocation);
|
||||||
|
CustomBlock.place(deadCrop,seedLocation);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (wrongSeason) {
|
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, () -> {
|
if (CustomBlock.getInstance( split[0] +":"+cropNameList[0] + "_stage_" + nextStage) != null) {
|
||||||
CustomBlock.remove(seedLocation);
|
bukkitScheduler.callSyncMethod(CustomCrops.instance, () ->{
|
||||||
CustomBlock.place(config.getString("config.dead-crop"), seedLocation);
|
CustomBlock.remove(potLocation);
|
||||||
|
CustomBlock.place(pot,potLocation);
|
||||||
|
if(Math.random()< growChance){
|
||||||
|
CustomBlock.remove(seedLocation);
|
||||||
|
CustomBlock.place(split[0] + ":" + cropNameList[0] + "_stage_" + nextStage,seedLocation);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}else if(CustomBlock.byAlreadyPlaced(potBlock).getNamespacedID().equalsIgnoreCase(pot) && seedNamespace.contains("stage")){
|
||||||
|
if (seedNamespace.equalsIgnoreCase(deadCrop)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(enable_season) {
|
||||||
|
if(enable_greenhouse){
|
||||||
|
for(int i = 1; i <= range; i++){
|
||||||
|
Location tempLocation = seedLocation.clone().add(0,i,0);
|
||||||
|
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)) != null){
|
||||||
|
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)).getNamespacedID().equalsIgnoreCase(glass)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean wrongSeason = true;
|
||||||
|
for (String season : seasons) {
|
||||||
|
if (Objects.equals(season, current)) {
|
||||||
|
wrongSeason = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wrongSeason) {
|
||||||
|
bukkitScheduler.callSyncMethod(CustomCrops.instance, () -> {
|
||||||
|
CustomBlock.remove(seedLocation);
|
||||||
|
CustomBlock.place(deadCrop, seedLocation);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class CropTimer {
|
|||||||
|
|
||||||
public CropTimer() {
|
public CropTimer() {
|
||||||
TimeCheck tc = new TimeCheck();
|
TimeCheck tc = new TimeCheck();
|
||||||
BukkitTask task = tc.runTaskTimerAsynchronously(CustomCrops.instance, 1,1);
|
BukkitTask task = tc.runTaskTimer(CustomCrops.instance, 1,1);
|
||||||
this.taskID = task.getTaskId();
|
this.taskID = task.getTaskId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,30 +15,38 @@ import java.io.File;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class SprinklerWork {
|
public class SprinklerWork {
|
||||||
|
|
||||||
public static void sprinklerWork(){
|
public static void sprinklerWork(){
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
|
||||||
File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml");
|
File file = new File(CustomCrops.instance.getDataFolder(), "sprinkler-data.yml");
|
||||||
FileConfiguration data;
|
FileConfiguration data;
|
||||||
data = YamlConfiguration.loadConfiguration(file);
|
data = YamlConfiguration.loadConfiguration(file);
|
||||||
config.getStringList("config.whitelist-worlds").forEach(worldName -> SprinklerManager.getSprinklers(Objects.requireNonNull(Bukkit.getWorld(worldName))).forEach(location -> {
|
|
||||||
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
|
|
||||||
|
config.getStringList("config.whitelist-worlds").forEach(worldName -> {
|
||||||
|
|
||||||
World world = Bukkit.getWorld(worldName);
|
World world = Bukkit.getWorld(worldName);
|
||||||
String type = Objects.requireNonNull(data.getString(worldName + "." + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ()));
|
SprinklerManager.getSprinklers(Bukkit.getWorld(worldName)).forEach(location -> {
|
||||||
if(type.equals("s1")){
|
|
||||||
for(int i = -1; i <= 1;i++){
|
String type = Objects.requireNonNull(data.getString(worldName + "." + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ()));
|
||||||
for (int j = -1; j <= 1; j++){
|
if(type.equals("s1")){
|
||||||
Location tempLoc = location.clone().add(i,-1,j);
|
for(int i = -1; i <= 1;i++){
|
||||||
waterPot(tempLoc, world, config);
|
for (int j = -1; j <= 1; j++){
|
||||||
|
Location tempLoc = location.clone().add(i,-1,j);
|
||||||
|
waterPot(tempLoc, world, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if(type.equals("s2")){
|
||||||
|
for(int i = -2; i <= 2;i++){
|
||||||
|
for (int j = -2; j <= 2; j++){
|
||||||
|
Location tempLoc = location.clone().add(i,-1,j);
|
||||||
|
waterPot(tempLoc, world, config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if(type.equals("s2")){
|
});
|
||||||
for(int i = -2; i <= 2;i++){
|
});
|
||||||
for (int j = -2; j <= 2; j++){
|
|
||||||
Location tempLoc = location.clone().add(i,-1,j);
|
|
||||||
waterPot(tempLoc, world, config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
private static void waterPot(Location tempLoc, World world, FileConfiguration config) {
|
private static void waterPot(Location tempLoc, World world, FileConfiguration config) {
|
||||||
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLoc)) != null){
|
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLoc)) != null){
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package net.momirealms.customcrops.Crops;
|
|||||||
import net.momirealms.customcrops.CustomCrops;
|
import net.momirealms.customcrops.CustomCrops;
|
||||||
import net.momirealms.customcrops.DataManager.CropManager;
|
import net.momirealms.customcrops.DataManager.CropManager;
|
||||||
import net.momirealms.customcrops.DataManager.SprinklerManager;
|
import net.momirealms.customcrops.DataManager.SprinklerManager;
|
||||||
|
import net.momirealms.customcrops.MessageManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -15,6 +17,7 @@ public class TimeCheck extends BukkitRunnable {
|
|||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
List<Long> cropGrowTimeList = config.getLongList("config.grow-time");
|
List<Long> cropGrowTimeList = config.getLongList("config.grow-time");
|
||||||
List<Long> sprinklerWorkTimeList = config.getLongList("config.sprinkler-time");
|
List<Long> sprinklerWorkTimeList = config.getLongList("config.sprinkler-time");
|
||||||
|
BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -23,26 +26,40 @@ public class TimeCheck extends BukkitRunnable {
|
|||||||
cropGrowTimeList.forEach(cropGrowTime -> {
|
cropGrowTimeList.forEach(cropGrowTime -> {
|
||||||
|
|
||||||
if(time == cropGrowTime){
|
if(time == cropGrowTime){
|
||||||
CropManager.cleanLoadedCache();
|
bukkitScheduler.runTaskAsynchronously(CustomCrops.instance,()->{
|
||||||
}
|
long start1 = System.currentTimeMillis();
|
||||||
if(time == (cropGrowTime + 50)){
|
CropManager.cleanLoadedCache();
|
||||||
CropManager.saveData();
|
long finish1 = System.currentTimeMillis();
|
||||||
}
|
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f农作物缓存清理耗时&a" + String.valueOf(finish1-start1) + "&fms(异步)",Bukkit.getConsoleSender());
|
||||||
if(time == (cropGrowTime + 100)){
|
long start2 = System.currentTimeMillis();
|
||||||
CropGrow.cropGrow();
|
CropManager.saveData();
|
||||||
|
long finish2 = System.currentTimeMillis();
|
||||||
|
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f农作物数据保存耗时&a" + String.valueOf(finish2-start2) + "&fms(异步)",Bukkit.getConsoleSender());
|
||||||
|
long start3 = System.currentTimeMillis();
|
||||||
|
CropGrow.cropGrow();
|
||||||
|
long finish3 = System.currentTimeMillis();
|
||||||
|
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f农作物生长耗时&a" + String.valueOf(finish3-start3) + "&fms(部分异步)",Bukkit.getConsoleSender());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sprinklerWorkTimeList.forEach(sprinklerTime -> {
|
sprinklerWorkTimeList.forEach(sprinklerTime -> {
|
||||||
|
|
||||||
if(time == sprinklerTime){
|
if(time == sprinklerTime){
|
||||||
SprinklerManager.cleanCache();
|
bukkitScheduler.runTaskAsynchronously(CustomCrops.instance,()->{
|
||||||
}
|
long start1 = System.currentTimeMillis();
|
||||||
if(time == (sprinklerTime + 50)){
|
SprinklerManager.cleanCache();
|
||||||
SprinklerManager.saveData();
|
long finish1 = System.currentTimeMillis();
|
||||||
}
|
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f洒水器缓存清理耗时&a" + String.valueOf(finish1-start1) + "&fms(部分异步)",Bukkit.getConsoleSender());
|
||||||
if(time == (sprinklerTime + 100)){
|
long start2 = System.currentTimeMillis();
|
||||||
SprinklerWork.sprinklerWork();
|
SprinklerManager.saveData();
|
||||||
|
long finish2 = System.currentTimeMillis();
|
||||||
|
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f洒水器数据保存耗时&a" + String.valueOf(finish2-start2) + "&fms(异步)",Bukkit.getConsoleSender());
|
||||||
|
long start3 = System.currentTimeMillis();
|
||||||
|
SprinklerWork.sprinklerWork();
|
||||||
|
long finish3 = System.currentTimeMillis();
|
||||||
|
MessageManager.consoleMessage("&#ccfbff-#ef96c5&[CustomCrops|性能监测] &f洒水器工作耗时&a" + String.valueOf(finish3-start3) + "&fms(部分异步)",Bukkit.getConsoleSender());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class BackUp {
|
public class BackUp {
|
||||||
|
|
||||||
public static void backUpData(){
|
public static void backUpData(){
|
||||||
|
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
@@ -22,6 +23,10 @@ public class BackUp {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
BackUp.backUp(crop_data,cropBackUp);
|
BackUp.backUp(crop_data,cropBackUp);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
BackUp.backUp(sprinkler_data,sprinklerBackUp);
|
BackUp.backUp(sprinkler_data,sprinklerBackUp);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.momirealms.customcrops.DataManager;
|
package net.momirealms.customcrops.DataManager;
|
||||||
|
|
||||||
import net.momirealms.customcrops.CustomCrops;
|
import net.momirealms.customcrops.CustomCrops;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -11,10 +12,31 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class CropManager {
|
public class CropManager {
|
||||||
|
|
||||||
public static HashMap<Location, String> instances;
|
public static ConcurrentHashMap<Location, String> instances;
|
||||||
|
|
||||||
|
//4W性能测试
|
||||||
|
public static void testData_1(){
|
||||||
|
for(int i = -100; i < 100; i++){
|
||||||
|
for(int j = -100; j < 100; j++){
|
||||||
|
Location tempLoc = new Location(Bukkit.getWorld("world"),i,100,j);
|
||||||
|
String name = "spring";
|
||||||
|
instances.put(tempLoc, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//20W性能测试
|
||||||
|
public static void testData_2(){
|
||||||
|
for(int i = -100000; i < 100000; i++){
|
||||||
|
Location tempLoc = new Location(Bukkit.getWorld("world"),i,100,i);
|
||||||
|
String name = "spring";
|
||||||
|
instances.put(tempLoc, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//开服的时候将文件的数据读入
|
//开服的时候将文件的数据读入
|
||||||
public CropManager(FileConfiguration data) {
|
public CropManager(FileConfiguration data) {
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
@@ -22,7 +44,7 @@ public class CropManager {
|
|||||||
data = YamlConfiguration.loadConfiguration(file);
|
data = YamlConfiguration.loadConfiguration(file);
|
||||||
try {
|
try {
|
||||||
for (String world : config.getStringList("config.whitelist-worlds")) {
|
for (String world : config.getStringList("config.whitelist-worlds")) {
|
||||||
CropManager.instances = new HashMap<Location, String>();
|
CropManager.instances = new ConcurrentHashMap<Location, String>();
|
||||||
if(data.getConfigurationSection(world) != null){
|
if(data.getConfigurationSection(world) != null){
|
||||||
for (String coordinate : data.getConfigurationSection(world).getKeys(false)) {
|
for (String coordinate : data.getConfigurationSection(world).getKeys(false)) {
|
||||||
Location tempLocation = new Location(Bukkit.getWorld(world), (double)Integer.parseInt(coordinate.split(",")[0]), (double)Integer.parseInt(coordinate.split(",")[1]), (double)Integer.parseInt(coordinate.split(",")[2]));
|
Location tempLocation = new Location(Bukkit.getWorld(world), (double)Integer.parseInt(coordinate.split(",")[0]), (double)Integer.parseInt(coordinate.split(",")[1]), (double)Integer.parseInt(coordinate.split(",")[2]));
|
||||||
@@ -33,7 +55,7 @@ public class CropManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
CropManager.instances = new HashMap<Location, String>();
|
CropManager.instances = new ConcurrentHashMap<Location, String>();
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
saveData();
|
saveData();
|
||||||
@@ -74,7 +96,7 @@ public class CropManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CropManager.instances = new HashMap<Location, String>();
|
CropManager.instances = new ConcurrentHashMap<Location, String>();
|
||||||
Bukkit.getConsoleSender().sendMessage("错误:空数据");
|
Bukkit.getConsoleSender().sendMessage("错误:空数据");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -88,7 +110,7 @@ public class CropManager {
|
|||||||
public static void putInstance(Location location, String season) {
|
public static void putInstance(Location location, String season) {
|
||||||
CropManager.instances.put(location, season);
|
CropManager.instances.put(location, season);
|
||||||
}
|
}
|
||||||
public HashMap<Location, String> getMap() {
|
public ConcurrentHashMap<Location, String> getMap() {
|
||||||
return CropManager.instances;
|
return CropManager.instances;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +124,7 @@ public class CropManager {
|
|||||||
if(data.contains(worldName)){
|
if(data.contains(worldName)){
|
||||||
World world = Bukkit.getWorld(worldName);
|
World world = Bukkit.getWorld(worldName);
|
||||||
data.getConfigurationSection(worldName).getKeys(false).forEach(key ->{
|
data.getConfigurationSection(worldName).getKeys(false).forEach(key ->{
|
||||||
String[] string_list = key.split(",");
|
String[] string_list = StringUtils.split(key,",");
|
||||||
if (world.isChunkLoaded(Integer.parseInt(string_list[0])/16, Integer.parseInt(string_list[2])/16)){
|
if (world.isChunkLoaded(Integer.parseInt(string_list[0])/16, Integer.parseInt(string_list[2])/16)){
|
||||||
Location tempLoc = new Location(world,Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]));
|
Location tempLoc = new Location(world,Double.parseDouble(string_list[0]),Double.parseDouble(string_list[1]),Double.parseDouble(string_list[2]));
|
||||||
if(world.getBlockAt(tempLoc).getType() != Material.TRIPWIRE){
|
if(world.getBlockAt(tempLoc).getType() != Material.TRIPWIRE){
|
||||||
|
|||||||
@@ -3,12 +3,15 @@ package net.momirealms.customcrops.DataManager;
|
|||||||
import dev.lone.itemsadder.api.CustomBlock;
|
import dev.lone.itemsadder.api.CustomBlock;
|
||||||
import net.momirealms.customcrops.CustomCrops;
|
import net.momirealms.customcrops.CustomCrops;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
public class MaxCropsPerChunk {
|
public class MaxCropsPerChunk {
|
||||||
|
|
||||||
|
static FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
|
|
||||||
public static boolean maxCropsPerChunk(Location location){
|
public static boolean maxCropsPerChunk(Location location){
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
|
||||||
if(!config.getBoolean("config.enable-limit")){
|
if(!config.getBoolean("config.enable-limit")){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -23,11 +26,12 @@ public class MaxCropsPerChunk {
|
|||||||
Label_out:
|
Label_out:
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
for (int j = 0; j < 16; ++j) {
|
for (int j = 0; j < 16; ++j) {
|
||||||
final Location square = chunkLocation.clone().add((double)i, 0.0, (double)j);
|
Location square = chunkLocation.clone().add(i, 0.0, j);
|
||||||
for (int k = minY; k <= maxY; ++k) {
|
for (int k = minY; k <= maxY; ++k) {
|
||||||
square.add(0.0, 1.0, 0.0);
|
square.add(0.0, 1.0, 0.0);
|
||||||
if(CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(square))!= null){
|
Block b = location.getWorld().getBlockAt(square);
|
||||||
if (CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(square)).getNamespacedID().contains("stage")) {
|
if(CustomBlock.byAlreadyPlaced(b)!= null){
|
||||||
|
if (CustomBlock.byAlreadyPlaced(b).getNamespacedID().contains("stage")) {
|
||||||
if (n++ > maxAmount) {
|
if (n++ > maxAmount) {
|
||||||
break Label_out;
|
break Label_out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
public class MaxSprinklersPerChunk {
|
public class MaxSprinklersPerChunk {
|
||||||
|
|
||||||
|
static FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
|
|
||||||
public static boolean maxSprinklersPerChunk(Location location){
|
public static boolean maxSprinklersPerChunk(Location location){
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
|
||||||
if(!config.getBoolean("config.enable-limit")){
|
if(!config.getBoolean("config.enable-limit")){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -24,10 +27,10 @@ public class MaxSprinklersPerChunk {
|
|||||||
Label_out:
|
Label_out:
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
for (int j = 0; j < 16; ++j) {
|
for (int j = 0; j < 16; ++j) {
|
||||||
final Location square = chunkLocation.clone().add((double)i, 0.0, (double)j);
|
Location square = chunkLocation.clone().add(i+0.5, 0.5, j+0.5);
|
||||||
for (int k = minY; k <= maxY; ++k) {
|
for (int k = minY; k <= maxY; ++k) {
|
||||||
square.add(0.0, 1.0, 0.0);
|
square.add(0.0, 1.0, 0.0);
|
||||||
if(IAFurniture.getFromLocation(square.clone().add(0.5,0.5,0.5), world)){
|
if(IAFurniture.getFromLocation(square, world)){
|
||||||
if (n++ > maxAmount) {
|
if (n++ > maxAmount) {
|
||||||
break Label_out;
|
break Label_out;
|
||||||
}
|
}
|
||||||
@@ -37,4 +40,7 @@ public class MaxSprinklersPerChunk {
|
|||||||
}
|
}
|
||||||
return n > maxAmount;
|
return n > maxAmount;
|
||||||
}
|
}
|
||||||
|
public static boolean alreadyPlaced(Location location){
|
||||||
|
return IAFurniture.getFromLocation(location.clone().add(0.5, 1.5, 0.5), location.getWorld());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class SprinklerManager {
|
public class SprinklerManager {
|
||||||
|
|
||||||
public static HashMap<Location, String> instances;
|
public static ConcurrentHashMap<Location, String> instances;
|
||||||
|
|
||||||
//开服的时候将文件的数据读入
|
//开服的时候将文件的数据读入
|
||||||
public SprinklerManager(FileConfiguration data) {
|
public SprinklerManager(FileConfiguration data) {
|
||||||
@@ -23,7 +24,7 @@ public class SprinklerManager {
|
|||||||
data = YamlConfiguration.loadConfiguration(file);
|
data = YamlConfiguration.loadConfiguration(file);
|
||||||
try {
|
try {
|
||||||
for (String world : config.getStringList("config.whitelist-worlds")) {
|
for (String world : config.getStringList("config.whitelist-worlds")) {
|
||||||
SprinklerManager.instances = new HashMap<Location, String>();
|
SprinklerManager.instances = new ConcurrentHashMap<Location, String>();
|
||||||
if(data.getConfigurationSection(world) != null){
|
if(data.getConfigurationSection(world) != null){
|
||||||
for (String coordinate : data.getConfigurationSection(world).getKeys(false)) {
|
for (String coordinate : data.getConfigurationSection(world).getKeys(false)) {
|
||||||
Location tempLocation = new Location(Bukkit.getWorld(world), Integer.parseInt(coordinate.split(",")[0]), Integer.parseInt(coordinate.split(",")[1]), Integer.parseInt(coordinate.split(",")[2]));
|
Location tempLocation = new Location(Bukkit.getWorld(world), Integer.parseInt(coordinate.split(",")[0]), Integer.parseInt(coordinate.split(",")[1]), Integer.parseInt(coordinate.split(",")[2]));
|
||||||
@@ -34,7 +35,7 @@ public class SprinklerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
SprinklerManager.instances = new HashMap<Location, String>();
|
SprinklerManager.instances = new ConcurrentHashMap<Location, String>();
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
saveData();
|
saveData();
|
||||||
@@ -76,7 +77,7 @@ public class SprinklerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SprinklerManager.instances = new HashMap<Location, String>();
|
SprinklerManager.instances = new ConcurrentHashMap<Location, String>();
|
||||||
Bukkit.getConsoleSender().sendMessage("错误:空数据");
|
Bukkit.getConsoleSender().sendMessage("错误:空数据");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package net.momirealms.customcrops.Integrations;
|
||||||
|
|
||||||
|
import net.momirealms.customcrops.CustomCrops;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class IntegrationCheck {
|
||||||
|
|
||||||
|
static FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
|
|
||||||
|
//收获权限检测
|
||||||
|
public static boolean HarvestCheck(Location location, Player player){
|
||||||
|
if(config.getBoolean("config.integration.kingdomsX")){
|
||||||
|
if(KingdomsXIntegrations.checkKDBuild(location,player)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(config.getBoolean("config.integration.residence")){
|
||||||
|
if(ResidenceIntegrations.checkResHarvest(location,player)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(config.getBoolean("config.integration.worldguard")){
|
||||||
|
return WorldGuardIntegrations.checkWGHarvest(location, player);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//种植等权限检测
|
||||||
|
public static boolean PlaceCheck(Location location, Player player){
|
||||||
|
if(config.getBoolean("config.integration.kingdomsX")){
|
||||||
|
if(KingdomsXIntegrations.checkKDBuild(location,player)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(config.getBoolean("config.integration.residence")){
|
||||||
|
if(ResidenceIntegrations.checkResBuild(location,player)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(config.getBoolean("config.integration.worldguard")){
|
||||||
|
return WorldGuardIntegrations.checkWGBuild(location, player);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,9 +13,7 @@ public class ResidenceIntegrations {
|
|||||||
ClaimedResidence res = com.bekvon.bukkit.residence.Residence.getInstance().getResidenceManager().getByLoc(location);
|
ClaimedResidence res = com.bekvon.bukkit.residence.Residence.getInstance().getResidenceManager().getByLoc(location);
|
||||||
if(res!=null){
|
if(res!=null){
|
||||||
ResidencePermissions perms = res.getPermissions();
|
ResidencePermissions perms = res.getPermissions();
|
||||||
String playerName = player.getName();
|
|
||||||
boolean hasPermission = perms.playerHas(player, Flags.build, true);
|
boolean hasPermission = perms.playerHas(player, Flags.build, true);
|
||||||
///perms.playerHas(playerName, "build", true);
|
|
||||||
return !hasPermission;
|
return !hasPermission;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -25,9 +23,7 @@ public class ResidenceIntegrations {
|
|||||||
ClaimedResidence res = com.bekvon.bukkit.residence.Residence.getInstance().getResidenceManager().getByLoc(location);
|
ClaimedResidence res = com.bekvon.bukkit.residence.Residence.getInstance().getResidenceManager().getByLoc(location);
|
||||||
if(res!=null){
|
if(res!=null){
|
||||||
ResidencePermissions perms = res.getPermissions();
|
ResidencePermissions perms = res.getPermissions();
|
||||||
String playerName = player.getName();
|
|
||||||
boolean hasPermission = perms.playerHas(player, Flags.harvest, true);
|
boolean hasPermission = perms.playerHas(player, Flags.harvest, true);
|
||||||
//boolean hasPermission = perms.playerHas(playerName, "harvest", true);
|
|
||||||
return !hasPermission;
|
return !hasPermission;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -17,10 +17,7 @@ public class WorldGuardIntegrations {
|
|||||||
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||||
RegionQuery query = container.createQuery();
|
RegionQuery query = container.createQuery();
|
||||||
|
|
||||||
if (!query.testState(BukkitAdapter.adapt(loc), localPlayer, Flags.BUILD)) {
|
return !query.testState(BukkitAdapter.adapt(loc), localPlayer, Flags.BUILD);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
public static boolean checkWGHarvest(Location loc,Player player){
|
public static boolean checkWGHarvest(Location loc,Player player){
|
||||||
|
|
||||||
@@ -28,9 +25,6 @@ public class WorldGuardIntegrations {
|
|||||||
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||||
RegionQuery query = container.createQuery();
|
RegionQuery query = container.createQuery();
|
||||||
|
|
||||||
if (!query.testState(BukkitAdapter.adapt(loc), localPlayer, Flags.BLOCK_BREAK)) {
|
return !query.testState(BukkitAdapter.adapt(loc), localPlayer, Flags.BLOCK_BREAK);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,499 +0,0 @@
|
|||||||
package net.momirealms.customcrops.Libs.minedown;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <h2>MineDown</h2>
|
|
||||||
* A MarkDown inspired markup for Minecraft chat components
|
|
||||||
* <p>
|
|
||||||
* This lets you convert string messages into chat components by using a custom mark up syntax
|
|
||||||
* which is loosely based on MarkDown while still supporting legacy formatting codes.
|
|
||||||
*
|
|
||||||
* <table>
|
|
||||||
* <caption><strong> Inline Formatting </strong></caption>
|
|
||||||
* <tr><td> Color legacy </td><td><code> &6Text </code></td><td> {@link ChatColor} codes </td></tr>
|
|
||||||
* <tr><td> Color </td><td><code> &gold&Text </code></td><td> {@link ChatColor} codes </td></tr>
|
|
||||||
* <tr><td> RGB Hex Color </td><td><code> &ff00ff&Text </code></td><td> Full hexadecimal format </td></tr>
|
|
||||||
* <tr><td> RGB Hex Color </td><td><code> &f0f&Text </code></td><td> Short format (equivalent to long one) </td></tr>
|
|
||||||
* <tr><td> Bold </td><td><code> **Text** </code></td></tr>
|
|
||||||
* <tr><td> Italic </td><td><code> ##Text## </code></td></tr>
|
|
||||||
* <tr><td> Underlined </td><td><code> __Text__ </code></td></tr>
|
|
||||||
* <tr><td> Strikethrough </td><td><code> ~~Text~~ </code></td></tr>
|
|
||||||
* <tr><td> Obfuscated </td><td><code> ??Text?? </code></td></tr>
|
|
||||||
* </table>
|
|
||||||
*
|
|
||||||
* <h3>Events</h3>
|
|
||||||
* You can define click and hover events with the commonly used MarkDown link syntax.
|
|
||||||
* <p>
|
|
||||||
* <table>
|
|
||||||
* <caption><strong> Simple Syntax </strong></caption>
|
|
||||||
* <tr><td> General syntax </td><td><code> [Text](text-color text-formatting... link hover text) </code></td></tr>
|
|
||||||
* <tr><td> Simple Link </td><td><code> [Text](https://example.com) </code></td></tr>
|
|
||||||
* <tr><td> Simple Command </td><td><code> [Text](/command to run) </code></td></tr>
|
|
||||||
* <tr><td> Link + Hover </td><td><code> [Text](https://example.com Hover Text) </code></td></tr>
|
|
||||||
* <tr><td> Text formatting + Link + Hover </td><td><code> [Text](blue underline https://example.com Hover Text) </code></td></tr>
|
|
||||||
* </table>
|
|
||||||
* <p>
|
|
||||||
* <table>
|
|
||||||
* <caption><strong> Advanced Syntax </strong></caption>
|
|
||||||
* <tr><td> General syntax </td><td><code> [Text](action=value) </code></td><td> {@link ClickEvent.Action}, {@link HoverEvent.Action} </td></tr>
|
|
||||||
* <tr><td> Link </td><td><code> [Text](open_url=https://example.com) </code></td></tr>
|
|
||||||
* <tr><td> Color </td><td><code> [Text](color=red) </code></td></tr>
|
|
||||||
* <tr><td> RGB Hex Color </td><td><code> [Text](color=#ff00ff) </code></td><td> Full hexadecimal format </td></tr>
|
|
||||||
* <tr><td> RGB Hex Color </td><td><code> [Text](color=#f0f) </code></td><td> Short format (equivalent to long one) </td></tr>
|
|
||||||
* <tr><td> Formatting </td><td><code> [Text](format=underline,bold) </code></td></tr>
|
|
||||||
* <tr><td> Font </td><td><code> [Text](format=underline,bold) </code></td></tr>
|
|
||||||
* <tr><td> Run Command </td><td><code> [Text](run_command=/command string) </code></td></tr>
|
|
||||||
* <tr><td> Suggest Command </td><td><code> [Text](suggest_command=/command) </code></td></tr>
|
|
||||||
* <tr><td> Simple Hover </td><td><code> [Text](hover=Hover Text) </code></td></tr>
|
|
||||||
* <tr><td> Hover Text </td><td><code> [Text](show_text=Hover Text) </code></td></tr>
|
|
||||||
* <tr><td> Hover Entity Info </td><td><code> [Text](show_entity=uuid:pig Name) </code></td></tr>
|
|
||||||
* <tr><td> Hover Item Info </td><td><code> [Text](show_item=stone*2 nbt...) </code></td></tr>
|
|
||||||
* </table>
|
|
||||||
* <p>
|
|
||||||
* All advanced settings can be chained/included in a event definition.
|
|
||||||
* You can't however add multiple different colors or click and hover actions!
|
|
||||||
*/
|
|
||||||
public class MineDown {
|
|
||||||
public static final String FONT_PREFIX = "font=";
|
|
||||||
public static final String COLOR_PREFIX = "color=";
|
|
||||||
public static final String FORMAT_PREFIX = "format=";
|
|
||||||
public static final String HOVER_PREFIX = "hover=";
|
|
||||||
public static final String INSERTION_PREFIX = "insert=";
|
|
||||||
|
|
||||||
private String message;
|
|
||||||
private final Replacer replacer = new Replacer();
|
|
||||||
private final MineDownParser parser = new MineDownParser();
|
|
||||||
private BaseComponent[] baseComponents = null;
|
|
||||||
private boolean replaceFirst = Boolean.getBoolean("de.themoep.minedown.replacefirst");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new MineDown builder with a certain message
|
|
||||||
* @param message The message to parse
|
|
||||||
*/
|
|
||||||
public MineDown(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a MineDown string to components
|
|
||||||
* @param message The message to translate
|
|
||||||
* @param replacements Optional placeholder replacements
|
|
||||||
* @return The parsed components
|
|
||||||
*/
|
|
||||||
public static BaseComponent[] parse(String message, String... replacements) {
|
|
||||||
return new MineDown(message).replace(replacements).toComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert components to a MineDown string
|
|
||||||
* @param components The components to convert
|
|
||||||
* @return The components represented as a MineDown string
|
|
||||||
*/
|
|
||||||
public static String stringify(BaseComponent[] components) {
|
|
||||||
return new MineDownStringifier().stringify(components);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse and convert the message to the component
|
|
||||||
* @return The parsed component message
|
|
||||||
*/
|
|
||||||
public BaseComponent[] toComponent() {
|
|
||||||
if (baseComponents() == null) {
|
|
||||||
if (replaceFirst()) {
|
|
||||||
Replacer componentReplacer = new Replacer();
|
|
||||||
for (Map.Entry<String, BaseComponent[]> entry : replacer().componentReplacements().entrySet()) {
|
|
||||||
componentReplacer.replace(entry.getKey(), stringify(entry.getValue()));
|
|
||||||
}
|
|
||||||
baseComponents = parser().parse(componentReplacer.replaceIn(replacer().replaceIn(message()))).create();
|
|
||||||
} else {
|
|
||||||
baseComponents = replacer().replaceIn(parser().parse(message()).create());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return baseComponents();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a cached component and re-parse the next time {@link #toComponent} is called
|
|
||||||
*/
|
|
||||||
private void reset() {
|
|
||||||
baseComponents = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not replacements should be replaced before or after the components are created.
|
|
||||||
* When replacing first it will not replace any placeholders with component replacement values!
|
|
||||||
* Default is after. (replaceFirst = false)
|
|
||||||
* @param replaceFirst Whether or not to replace first or parse first
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown replaceFirst(boolean replaceFirst) {
|
|
||||||
reset();
|
|
||||||
this.replaceFirst = replaceFirst;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not replacements should be replaced before or after the components are created.
|
|
||||||
* When replacing first it will not replace any placeholders with component replacement values!
|
|
||||||
* Default is after. (replaceFirst = false)
|
|
||||||
* @return Whether or not to replace first or parse first
|
|
||||||
*/
|
|
||||||
public boolean replaceFirst() {
|
|
||||||
return replaceFirst;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an array with placeholders and values that should get replaced in the message
|
|
||||||
* @param replacements The replacements, nth element is the placeholder, n+1th the value
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown replace(String... replacements) {
|
|
||||||
reset();
|
|
||||||
replacer().replace(replacements);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a map with placeholders and values that should get replaced in the message
|
|
||||||
* @param replacements The replacements mapped placeholder to value
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown replace(Map<String, ?> replacements) {
|
|
||||||
reset();
|
|
||||||
replacer().replace(replacements);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a placeholder to component mapping that should get replaced in the message
|
|
||||||
* @param placeholder The placeholder to replace
|
|
||||||
* @param replacement The replacement components
|
|
||||||
* @return The Replacer instance
|
|
||||||
*/
|
|
||||||
public MineDown replace(String placeholder, BaseComponent... replacement) {
|
|
||||||
reset();
|
|
||||||
replacer().replace(placeholder,replacement);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the placeholder indicator for both prefix and suffix
|
|
||||||
* @param placeholderIndicator The character to use as a placeholder indicator
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown placeholderIndicator(String placeholderIndicator) {
|
|
||||||
placeholderPrefix(placeholderIndicator);
|
|
||||||
placeholderSuffix(placeholderIndicator);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the placeholder indicator's prefix character
|
|
||||||
* @param placeholderPrefix The character to use as the placeholder indicator's prefix
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown placeholderPrefix(String placeholderPrefix) {
|
|
||||||
reset();
|
|
||||||
replacer().placeholderPrefix(placeholderPrefix);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the placeholder indicator's prefix character
|
|
||||||
* @return The placeholder indicator's prefix character
|
|
||||||
*/
|
|
||||||
public String placeholderPrefix() {
|
|
||||||
return replacer().placeholderPrefix();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the placeholder indicator's suffix character
|
|
||||||
* @param placeholderSuffix The character to use as the placeholder indicator's suffix
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown placeholderSuffix(String placeholderSuffix) {
|
|
||||||
reset();
|
|
||||||
replacer().placeholderSuffix(placeholderSuffix);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the placeholder indicator's suffix character
|
|
||||||
* @return The placeholder indicator's suffix character
|
|
||||||
*/
|
|
||||||
public String placeholderSuffix() {
|
|
||||||
return replacer().placeholderSuffix();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not the case of the placeholder should be ignored when replacing
|
|
||||||
* @param ignorePlaceholderCase Whether or not to ignore the case of the placeholders
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown ignorePlaceholderCase(boolean ignorePlaceholderCase) {
|
|
||||||
reset();
|
|
||||||
replacer().ignorePlaceholderCase(ignorePlaceholderCase);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not the case of the placeholder should be ignored when replacing
|
|
||||||
* @return Whether or not to ignore the case of the placeholders
|
|
||||||
*/
|
|
||||||
public boolean ignorePlaceholderCase() {
|
|
||||||
return replacer().ignorePlaceholderCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable or disable the translation of legacy color codes
|
|
||||||
* @param translateLegacyColors Whether or not to translate legacy color codes (Default: true)
|
|
||||||
* @return The MineDown instance
|
|
||||||
* @deprecated Use {@link #enable(MineDownParser.Option)} and {@link #disable(MineDownParser.Option)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public MineDown translateLegacyColors(boolean translateLegacyColors) {
|
|
||||||
reset();
|
|
||||||
parser().translateLegacyColors(translateLegacyColors);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect urls in strings and add events to them? (Default: true)
|
|
||||||
* @param enabled Whether or not to detect URLs and add events to them
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown urlDetection(boolean enabled) {
|
|
||||||
reset();
|
|
||||||
parser().urlDetection(enabled);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automatically add http to values of open_url when there doesn't exist any? (Default: true)
|
|
||||||
* @param enabled Whether or not to automatically add http when missing
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown autoAddUrlPrefix(boolean enabled) {
|
|
||||||
reset();
|
|
||||||
parser().autoAddUrlPrefix(enabled);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The text to display when hovering over an URL
|
|
||||||
* @param text The text to display when hovering over an URL
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown urlHoverText(String text) {
|
|
||||||
reset();
|
|
||||||
parser().urlHoverText(text);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the max width the hover text should have.
|
|
||||||
* Minecraft itself will wrap after 60 characters.
|
|
||||||
* Won't apply if the text already includes new lines.
|
|
||||||
* @param hoverTextWidth The url hover text length
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown hoverTextWidth(int hoverTextWidth) {
|
|
||||||
reset();
|
|
||||||
parser().hoverTextWidth(hoverTextWidth);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable an option. Unfilter it if you filtered it before.
|
|
||||||
* @param option The option to enable
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown enable(MineDownParser.Option option) {
|
|
||||||
reset();
|
|
||||||
parser().enable(option);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable an option. Disabling an option will stop the parser from replacing
|
|
||||||
* this option's chars in the string. Use {@link #filter(MineDownParser.Option)} to completely
|
|
||||||
* remove the characters used by this option from the message instead.
|
|
||||||
* @param option The option to disable
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown disable(MineDownParser.Option option) {
|
|
||||||
reset();
|
|
||||||
parser().disable(option);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter an option. This completely removes the characters of this option from
|
|
||||||
* the string ignoring whether the option is enabled or not.
|
|
||||||
* @param option The option to add to the filter
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown filter(MineDownParser.Option option) {
|
|
||||||
reset();
|
|
||||||
parser().filter(option);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unfilter an option. Does not enable it!
|
|
||||||
* @param option The option to remove from the filter
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown unfilter(MineDownParser.Option option) {
|
|
||||||
reset();
|
|
||||||
parser().unfilter(option);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a special character to replace color codes by if translating legacy colors is enabled.
|
|
||||||
* @param colorChar The character to use as a special color code. (Default: ampersand &)
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown colorChar(char colorChar) {
|
|
||||||
reset();
|
|
||||||
parser().colorChar(colorChar);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the set message that is to be parsed
|
|
||||||
* @return The to be parsed message
|
|
||||||
*/
|
|
||||||
public String message() {
|
|
||||||
return this.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the message that is to be parsed
|
|
||||||
* @param message The message to be parsed
|
|
||||||
* @return The MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown message(String message) {
|
|
||||||
this.message = message;
|
|
||||||
reset();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the replacer instance that is currently used
|
|
||||||
* @return The currently used replacer instance
|
|
||||||
*/
|
|
||||||
public Replacer replacer() {
|
|
||||||
return this.replacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the parser instance that is currently used
|
|
||||||
* @return The currently used parser instance
|
|
||||||
*/
|
|
||||||
public MineDownParser parser() {
|
|
||||||
return this.parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected BaseComponent[] baseComponents() {
|
|
||||||
return this.baseComponents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy all MineDown settings to a new instance
|
|
||||||
* @return The new MineDown instance with all settings copied
|
|
||||||
*/
|
|
||||||
public MineDown copy() {
|
|
||||||
return new MineDown(message()).copy(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy all MineDown settings from another one
|
|
||||||
* @param from The MineDown to copy from
|
|
||||||
* @return This MineDown instance
|
|
||||||
*/
|
|
||||||
public MineDown copy(MineDown from) {
|
|
||||||
replacer().copy(from.replacer());
|
|
||||||
parser().copy(from.parser());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the string that represents the format in MineDown
|
|
||||||
* @param format The format
|
|
||||||
* @return The MineDown string or an empty one if it's not a format
|
|
||||||
*/
|
|
||||||
public static String getFormatString(ChatColor format) {
|
|
||||||
if (format == ChatColor.BOLD) {
|
|
||||||
return "**";
|
|
||||||
} else if (format == ChatColor.ITALIC) {
|
|
||||||
return "##";
|
|
||||||
} else if (format == ChatColor.UNDERLINE) {
|
|
||||||
return "__";
|
|
||||||
} else if (format == ChatColor.STRIKETHROUGH) {
|
|
||||||
return "~~";
|
|
||||||
} else if (format == ChatColor.MAGIC) {
|
|
||||||
return "??";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the ChatColor format from a MineDown string
|
|
||||||
* @param c The character
|
|
||||||
* @return The ChatColor of that format or <code>null</code> it none was found
|
|
||||||
*/
|
|
||||||
public static ChatColor getFormatFromChar(char c) {
|
|
||||||
switch (c) {
|
|
||||||
case '~':
|
|
||||||
return ChatColor.STRIKETHROUGH;
|
|
||||||
case '_':
|
|
||||||
return ChatColor.UNDERLINE;
|
|
||||||
case '*':
|
|
||||||
return ChatColor.BOLD;
|
|
||||||
case '#':
|
|
||||||
return ChatColor.ITALIC;
|
|
||||||
case '?':
|
|
||||||
return ChatColor.MAGIC;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escape all MineDown formatting in a string. This will escape backslashes too!
|
|
||||||
* @param string The string to escape in
|
|
||||||
* @return The string with formatting escaped
|
|
||||||
*/
|
|
||||||
public static String escape(String string) {
|
|
||||||
return new MineDown(string).parser().escape(string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,423 +0,0 @@
|
|||||||
package net.momirealms.customcrops.Libs.minedown;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Content;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Entity;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Item;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
|
||||||
import static net.momirealms.customcrops.Libs.minedown.MineDown.COLOR_PREFIX;
|
|
||||||
import static net.momirealms.customcrops.Libs.minedown.MineDown.FONT_PREFIX;
|
|
||||||
import static net.momirealms.customcrops.Libs.minedown.MineDown.FORMAT_PREFIX;
|
|
||||||
import static net.momirealms.customcrops.Libs.minedown.MineDown.HOVER_PREFIX;
|
|
||||||
import static net.momirealms.customcrops.Libs.minedown.MineDown.INSERTION_PREFIX;
|
|
||||||
|
|
||||||
public class MineDownStringifier {
|
|
||||||
|
|
||||||
private static final boolean HAS_FONT_SUPPORT = Util.hasMethod(BaseComponent.class, "getFontRaw");
|
|
||||||
private static final boolean HAS_INSERTION_SUPPORT = Util.hasMethod(BaseComponent.class, "getInsertion");
|
|
||||||
private static final boolean HAS_HOVER_CONTENT_SUPPORT = Util.hasMethod(HoverEvent.class, "getContents");
|
|
||||||
private static final Method HOVER_GET_VALUE = Util.getMethod(HoverEvent.class, "getValue");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not to use legacy color codes (Default: false)
|
|
||||||
*/
|
|
||||||
private boolean useLegacyColors = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not to translate legacy formatting codes over Minedown ones (Default: false)
|
|
||||||
*/
|
|
||||||
private boolean useLegacyFormatting = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not to use simple event definitions or specific ones (Default: true)
|
|
||||||
*/
|
|
||||||
private boolean preferSimpleEvents = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not to put formatting in event definitions (Default: false)
|
|
||||||
*/
|
|
||||||
private boolean formattingInEventDefinition = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not to put colors in event definitions (Default: true)
|
|
||||||
*/
|
|
||||||
private boolean colorInEventDefinition = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The character to use as a special color code. (Default: ampersand &)
|
|
||||||
*/
|
|
||||||
private char colorChar = '&';
|
|
||||||
|
|
||||||
private StringBuilder value = new StringBuilder();
|
|
||||||
|
|
||||||
private ChatColor color = null;
|
|
||||||
private ClickEvent clickEvent = null;
|
|
||||||
private HoverEvent hoverEvent = null;
|
|
||||||
private Set<ChatColor> formats = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a {@link MineDown} string from a component message
|
|
||||||
* @param components The components to generate a MineDown string from
|
|
||||||
* @return The MineDown string
|
|
||||||
*/
|
|
||||||
public String stringify(BaseComponent... components) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (BaseComponent component : components) {
|
|
||||||
if (!component.hasFormatting()) {
|
|
||||||
appendText(sb, component);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
boolean hasEvent = component.getFontRaw() != null || component.getInsertion() != null
|
|
||||||
|| component.getClickEvent() != clickEvent || component.getHoverEvent() != hoverEvent;
|
|
||||||
if (hasEvent) {
|
|
||||||
sb.append('[');
|
|
||||||
if (!formattingInEventDefinition()) {
|
|
||||||
appendFormat(sb, component);
|
|
||||||
}
|
|
||||||
if (!colorInEventDefinition()) {
|
|
||||||
appendColor(sb, component.getColor());
|
|
||||||
}
|
|
||||||
} else if (component.getColorRaw() != null) {
|
|
||||||
appendFormat(sb, component);
|
|
||||||
appendColor(sb, component.getColor());
|
|
||||||
} else {
|
|
||||||
appendFormat(sb, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
appendText(sb, component);
|
|
||||||
|
|
||||||
if (component.getExtra() != null && !component.getExtra().isEmpty()) {
|
|
||||||
sb.append(copy().stringify(component.getExtra().toArray(new BaseComponent[0])));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasEvent) {
|
|
||||||
clickEvent = component.getClickEvent();
|
|
||||||
hoverEvent = component.getHoverEvent();
|
|
||||||
if (!formattingInEventDefinition()) {
|
|
||||||
appendFormatSuffix(sb, component);
|
|
||||||
}
|
|
||||||
sb.append("](");
|
|
||||||
List<String> definitions = new ArrayList<>();
|
|
||||||
if (colorInEventDefinition()) {
|
|
||||||
StringBuilder sbi = new StringBuilder();
|
|
||||||
if (!preferSimpleEvents()) {
|
|
||||||
sbi.append(COLOR_PREFIX);
|
|
||||||
}
|
|
||||||
sbi.append(component.getColor().getName().toLowerCase(Locale.ROOT));
|
|
||||||
definitions.add(sbi.toString());
|
|
||||||
}
|
|
||||||
if (formattingInEventDefinition()) {
|
|
||||||
StringBuilder sbi = new StringBuilder();
|
|
||||||
if (!preferSimpleEvents) {
|
|
||||||
sbi.append(FORMAT_PREFIX);
|
|
||||||
}
|
|
||||||
sbi.append(Util.getFormats(component, true).stream().map(c -> c.getName().toLowerCase(Locale.ROOT)).collect(Collectors.joining(" ")));
|
|
||||||
definitions.add(sbi.toString());
|
|
||||||
}
|
|
||||||
if (HAS_FONT_SUPPORT && component.getFontRaw() != null) {
|
|
||||||
definitions.add(FONT_PREFIX + component.getFontRaw());
|
|
||||||
}
|
|
||||||
if (HAS_INSERTION_SUPPORT && component.getInsertion() != null) {
|
|
||||||
if (component.getInsertion().contains(" ")) {
|
|
||||||
definitions.add(INSERTION_PREFIX + "{" + component.getInsertion() + "}");
|
|
||||||
} else {
|
|
||||||
definitions.add(INSERTION_PREFIX + component.getInsertion());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (component.getClickEvent() != null) {
|
|
||||||
if (preferSimpleEvents() && component.getClickEvent().getAction() == ClickEvent.Action.OPEN_URL) {
|
|
||||||
definitions.add(component.getClickEvent().getValue());
|
|
||||||
} else {
|
|
||||||
definitions.add(component.getClickEvent().getAction().toString().toLowerCase(Locale.ROOT) + "=" + component.getClickEvent().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (component.getHoverEvent() != null) {
|
|
||||||
StringBuilder sbi = new StringBuilder();
|
|
||||||
if (preferSimpleEvents() && component.getHoverEvent().getAction() == HoverEvent.Action.SHOW_TEXT &&
|
|
||||||
(component.getClickEvent() == null || component.getClickEvent().getAction() != ClickEvent.Action.OPEN_URL)) {
|
|
||||||
sbi.append(HOVER_PREFIX);
|
|
||||||
} else {
|
|
||||||
sbi.append(component.getHoverEvent().getAction().toString().toLowerCase(Locale.ROOT)).append('=');
|
|
||||||
}
|
|
||||||
if (HAS_HOVER_CONTENT_SUPPORT) {
|
|
||||||
sbi.append(copy().stringify(component.getHoverEvent().getContents()));
|
|
||||||
} else if (HOVER_GET_VALUE != null) {
|
|
||||||
try {
|
|
||||||
sbi.append(copy().stringify((BaseComponent[]) HOVER_GET_VALUE.invoke(component.getHoverEvent())));
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
definitions.add(sbi.toString());
|
|
||||||
}
|
|
||||||
sb.append(definitions.stream().collect(Collectors.joining(" ")));
|
|
||||||
sb.append(')');
|
|
||||||
} else {
|
|
||||||
appendFormatSuffix(sb, component);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringBuilder stringify(List<Content> contents) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (Content content : contents) {
|
|
||||||
if (content instanceof Text) {
|
|
||||||
Object value = ((Text) content).getValue();
|
|
||||||
if (value instanceof BaseComponent[]) {
|
|
||||||
sb.append(stringify((BaseComponent[]) value));
|
|
||||||
} else {
|
|
||||||
sb.append(value);
|
|
||||||
}
|
|
||||||
} else if (content instanceof Entity) {
|
|
||||||
Entity contentEntity = (Entity) content;
|
|
||||||
sb.append(contentEntity.getId());
|
|
||||||
if (contentEntity.getType() != null) {
|
|
||||||
sb.append(":").append(contentEntity.getType());
|
|
||||||
}
|
|
||||||
if (contentEntity.getName() != null) {
|
|
||||||
sb.append(" ").append(stringify(contentEntity.getName()));
|
|
||||||
}
|
|
||||||
} else if (content instanceof Item) {
|
|
||||||
Item contentItem = (Item) content;
|
|
||||||
sb.append(contentItem.getId());
|
|
||||||
if (contentItem.getCount() > 0) {
|
|
||||||
sb.append("*").append(contentItem.getCount());
|
|
||||||
}
|
|
||||||
if (contentItem.getTag() != null) {
|
|
||||||
sb.append(" ").append(contentItem.getTag().getNbt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendText(StringBuilder sb, BaseComponent component) {
|
|
||||||
if (component instanceof TextComponent) {
|
|
||||||
sb.append(((TextComponent) component).getText());
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot stringify " + component.getClass().getTypeName() + " yet! Only TextComponents are supported right now. Sorry. :(");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendColor(StringBuilder sb, ChatColor color) {
|
|
||||||
if (this.color != color) {
|
|
||||||
this.color = color;
|
|
||||||
if (useLegacyColors()) {
|
|
||||||
sb.append(colorChar()).append(color.toString().substring(1));
|
|
||||||
} else {
|
|
||||||
sb.append(colorChar()).append(color.getName()).append(colorChar());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendFormat(StringBuilder sb, BaseComponent component) {
|
|
||||||
Set<ChatColor> formats = Util.getFormats(component, true);
|
|
||||||
if (!formats.containsAll(this.formats)) {
|
|
||||||
if (useLegacyFormatting()) {
|
|
||||||
sb.append(colorChar()).append(ChatColor.RESET.toString().charAt(1));
|
|
||||||
} else {
|
|
||||||
Deque<ChatColor> formatDeque = new ArrayDeque<>(this.formats);
|
|
||||||
while (!formatDeque.isEmpty()) {
|
|
||||||
ChatColor format = formatDeque.pollLast();
|
|
||||||
if (!formats.contains(format)) {
|
|
||||||
sb.append(MineDown.getFormatString(format));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
formats.removeAll(this.formats);
|
|
||||||
}
|
|
||||||
for (ChatColor format : formats) {
|
|
||||||
if (useLegacyFormatting()) {
|
|
||||||
sb.append(colorChar()).append(format.toString().charAt(1));
|
|
||||||
} else {
|
|
||||||
sb.append(MineDown.getFormatString(format));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.formats.clear();
|
|
||||||
this.formats.addAll(formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendFormatSuffix(StringBuilder sb, BaseComponent component) {
|
|
||||||
if (!useLegacyFormatting()) {
|
|
||||||
Set<ChatColor> formats = Util.getFormats(component, true);
|
|
||||||
for (ChatColor format : formats) {
|
|
||||||
sb.append(MineDown.getFormatString(format));
|
|
||||||
}
|
|
||||||
this.formats.removeAll(formats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy all the parser's setting to a new instance
|
|
||||||
* @return The new parser instance with all settings copied
|
|
||||||
*/
|
|
||||||
public MineDownStringifier copy() {
|
|
||||||
return new MineDownStringifier().copy(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy all the parser's settings from another parser
|
|
||||||
* @param from The stringifier to copy from
|
|
||||||
* @return This stringifier's instance
|
|
||||||
*/
|
|
||||||
public MineDownStringifier copy(MineDownStringifier from) {
|
|
||||||
MineDownStringifier copy = new MineDownStringifier();
|
|
||||||
useLegacyColors(from.useLegacyColors());
|
|
||||||
useLegacyFormatting(from.useLegacyFormatting());
|
|
||||||
preferSimpleEvents(from.preferSimpleEvents());
|
|
||||||
formattingInEventDefinition(from.formattingInEventDefinition());
|
|
||||||
colorInEventDefinition(from.colorInEventDefinition());
|
|
||||||
colorChar(from.colorChar());
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not to use legacy color codes
|
|
||||||
* @return whether or not to use legacy color codes when possible (Default: true)
|
|
||||||
*/
|
|
||||||
public boolean useLegacyColors() {
|
|
||||||
return this.useLegacyColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not to use legacy color codes
|
|
||||||
* @param useLegacyColors Whether or not to use legacy colors (Default: true)
|
|
||||||
* @return The MineDownStringifier instance
|
|
||||||
*/
|
|
||||||
public MineDownStringifier useLegacyColors(boolean useLegacyColors) {
|
|
||||||
this.useLegacyColors = useLegacyColors;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not to translate legacy formatting codes over MineDown ones
|
|
||||||
* @return whether or not to use legacy formatting codes (Default: false)
|
|
||||||
*/
|
|
||||||
public boolean useLegacyFormatting() {
|
|
||||||
return this.useLegacyFormatting;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not to translate legacy formatting codes over MineDown ones
|
|
||||||
* @param useLegacyFormatting Whether or not to translate legacy formatting codes (Default: false)
|
|
||||||
* @return The MineDownStringifier instance
|
|
||||||
*/
|
|
||||||
public MineDownStringifier useLegacyFormatting(boolean useLegacyFormatting) {
|
|
||||||
this.useLegacyFormatting = useLegacyFormatting;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not to use simple event definitions or specific ones (Default: true)
|
|
||||||
* @return whether or not to use simple events
|
|
||||||
*/
|
|
||||||
public boolean preferSimpleEvents() {
|
|
||||||
return this.preferSimpleEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not to use simple event definitions or specific ones
|
|
||||||
* @param preferSimpleEvents Whether or not to prefer simple events (Default: true)
|
|
||||||
* @return The MineDownStringifier instance
|
|
||||||
*/
|
|
||||||
public MineDownStringifier preferSimpleEvents(boolean preferSimpleEvents) {
|
|
||||||
this.preferSimpleEvents = preferSimpleEvents;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not to put colors in event definitions or use inline color definitions
|
|
||||||
* @return whether or not to put colors in event definitions (Default: false)
|
|
||||||
*/
|
|
||||||
public boolean colorInEventDefinition() {
|
|
||||||
return this.colorInEventDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not to put colors in event definitions or use inline color definitions
|
|
||||||
* @param colorInEventDefinition Whether or not to put colors in event definitions (Default: false)
|
|
||||||
* @return The MineDownStringifier instance
|
|
||||||
*/
|
|
||||||
public MineDownStringifier colorInEventDefinition(boolean colorInEventDefinition) {
|
|
||||||
this.colorInEventDefinition = colorInEventDefinition;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not to put formatting in event definitions or use inline formatting definitions
|
|
||||||
* @return whether or not to put formatting in event definitions (Default: false)
|
|
||||||
*/
|
|
||||||
public boolean formattingInEventDefinition() {
|
|
||||||
return this.formattingInEventDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not to put formatting in event definitions or use inline formatting definitions
|
|
||||||
* @param formattingInEventDefinition Whether or not to put formatting in event definitions (Default: false)
|
|
||||||
* @return The MineDownStringifier instance
|
|
||||||
*/
|
|
||||||
public MineDownStringifier formattingInEventDefinition(boolean formattingInEventDefinition) {
|
|
||||||
this.formattingInEventDefinition = formattingInEventDefinition;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the character to use as a special color code. (Default: ampersand &)
|
|
||||||
* @return the color character
|
|
||||||
*/
|
|
||||||
public char colorChar() {
|
|
||||||
return this.colorChar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the character to use as a special color code.
|
|
||||||
* @param colorChar The character to be used as the color char (for legacy and MineDown colors, default: ampersand &)
|
|
||||||
* @return The MineDownStringifier instance
|
|
||||||
*/
|
|
||||||
public MineDownStringifier colorChar(char colorChar) {
|
|
||||||
this.colorChar = colorChar;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,471 +0,0 @@
|
|||||||
package net.momirealms.customcrops.Libs.minedown;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
|
||||||
import net.md_5.bungee.api.chat.ItemTag;
|
|
||||||
import net.md_5.bungee.api.chat.KeybindComponent;
|
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Content;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Entity;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Item;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class offers the ability to replace placeholders with values in strings and components.
|
|
||||||
* It also lets you define which placeholders indicators (prefix and suffix) should be used.
|
|
||||||
* By default these are the % character.
|
|
||||||
*/
|
|
||||||
public class Replacer {
|
|
||||||
|
|
||||||
private static final boolean HAS_KEYBIND_SUPPORT = Util.hasClass("net.md_5.bungee.api.chat.KeybindComponent");
|
|
||||||
private static final boolean HAS_INSERTION_SUPPORT = Util.hasMethod(BaseComponent.class, "getInsertion");
|
|
||||||
private static final boolean HAS_HOVER_CONTENT_SUPPORT = Util.hasMethod(HoverEvent.class, "getContents");
|
|
||||||
private static final Method HOVER_GET_VALUE = Util.getMethod(HoverEvent.class, "getValue");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A cache of compiled replacement patterns
|
|
||||||
*/
|
|
||||||
private static final Map<String, Pattern> PATTERN_CACHE = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The creator of the patterns for the pattern cache
|
|
||||||
*/
|
|
||||||
private static final Function<String, Pattern> PATTERN_CREATOR = p -> Pattern.compile(p, Pattern.LITERAL);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The map of placeholders with their string replacements
|
|
||||||
*/
|
|
||||||
private final Map<String, String> replacements = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The map of placeholders with their component array replacements
|
|
||||||
*/
|
|
||||||
private final Map<String, BaseComponent[]> componentReplacements = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The placeholder indicator's prefix character
|
|
||||||
*/
|
|
||||||
private String placeholderPrefix = "%";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The placeholder indicator's suffix character
|
|
||||||
*/
|
|
||||||
private String placeholderSuffix = "%";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the placeholder no matter what the case of it is
|
|
||||||
*/
|
|
||||||
private boolean ignorePlaceholderCase = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace certain placeholders with values in string.
|
|
||||||
* This uses the % character as placeholder indicators (suffix and prefix)
|
|
||||||
* @param message The string to replace in
|
|
||||||
* @param replacements The replacements, nth element is the placeholder, n+1th the value
|
|
||||||
* @return The string with all the placeholders replaced
|
|
||||||
*/
|
|
||||||
public static String replaceIn(String message, String... replacements) {
|
|
||||||
return new Replacer().replace(replacements).replaceIn(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace certain placeholders with values in a component array.
|
|
||||||
* This uses the % character as placeholder indicators (suffix and prefix)
|
|
||||||
* @param message The BaseComponent array to replace in
|
|
||||||
* @param replacements The replacements, nth element is the placeholder, n+1th the value
|
|
||||||
* @return A copy of the BaseComponent array with all the placeholders replaced
|
|
||||||
*/
|
|
||||||
public static BaseComponent[] replaceIn(BaseComponent[] message, String... replacements) {
|
|
||||||
return new Replacer().replace(replacements).replaceIn(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace a certain placeholder with a component array in a component array.
|
|
||||||
* This uses the % character as placeholder indicators (suffix and prefix)
|
|
||||||
* @param message The BaseComponent array to replace in
|
|
||||||
* @param placeholder The placeholder to replace
|
|
||||||
* @param replacement The replacement components
|
|
||||||
* @return A copy of the BaseComponent array with all the placeholders replaced
|
|
||||||
*/
|
|
||||||
public static BaseComponent[] replaceIn(BaseComponent[] message, String placeholder, BaseComponent... replacement) {
|
|
||||||
return new Replacer().replace(placeholder, replacement).replaceIn(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an array with placeholders and values that should get replaced in the message
|
|
||||||
* @param replacements The replacements, nth element is the placeholder, n+1th the value
|
|
||||||
* @return The Replacer instance
|
|
||||||
*/
|
|
||||||
public Replacer replace(String... replacements) {
|
|
||||||
Util.validate(replacements.length % 2 == 0, "The replacement length has to be even, " +
|
|
||||||
"mapping i % 2 == 0 to the placeholder and i % 2 = 1 to the placeholder's value");
|
|
||||||
Map<String, String> replacementMap = new LinkedHashMap<>();
|
|
||||||
for (int i = 0; i + 1 < replacements.length; i += 2) {
|
|
||||||
replacementMap.put(replacements[i], replacements[i + 1]);
|
|
||||||
}
|
|
||||||
return replace(replacementMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a map with placeholders and values that should get replaced in the message
|
|
||||||
* @param replacements The replacements mapped placeholder to value
|
|
||||||
* @return The Replacer instance
|
|
||||||
*/
|
|
||||||
public Replacer replace(Map<String, ?> replacements) {
|
|
||||||
if (replacements != null && !replacements.isEmpty()) {
|
|
||||||
Object any = replacements.values().stream().filter(Objects::nonNull).findAny().orElse(null);
|
|
||||||
if (any instanceof String) {
|
|
||||||
replacements().putAll((Map<String, String>) replacements);
|
|
||||||
} else if (any != null && any.getClass().isArray() && BaseComponent.class.isAssignableFrom(any.getClass().getComponentType())) {
|
|
||||||
componentReplacements().putAll((Map<String, BaseComponent[]>) replacements);
|
|
||||||
} else {
|
|
||||||
for (Map.Entry<String, ?> entry : replacements.entrySet()) {
|
|
||||||
replacements().put(entry.getKey(), String.valueOf(entry.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a placeholder to component mapping that should get replaced in the message
|
|
||||||
* @param placeholder The placeholder to replace
|
|
||||||
* @param replacement The replacement components
|
|
||||||
* @return The Replacer instance
|
|
||||||
*/
|
|
||||||
public Replacer replace(String placeholder, BaseComponent... replacement) {
|
|
||||||
componentReplacements().put(placeholder, replacement);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the placeholder indicator for both prefix and suffix
|
|
||||||
* @param placeholderIndicator The character to use as a placeholder indicator
|
|
||||||
* @return The Replacer instance
|
|
||||||
*/
|
|
||||||
public Replacer placeholderIndicator(String placeholderIndicator) {
|
|
||||||
placeholderPrefix(placeholderIndicator);
|
|
||||||
placeholderSuffix(placeholderIndicator);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the placeholders in a component array
|
|
||||||
* @param components The BaseComponent array to replace in
|
|
||||||
* @return A copy of the array with the placeholders replaced
|
|
||||||
*/
|
|
||||||
public BaseComponent[] replaceIn(BaseComponent... components) {
|
|
||||||
return replaceIn(Arrays.asList(components));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the placeholders in a component list
|
|
||||||
* @param components The BaseComponent list to replace in
|
|
||||||
* @return A copy of the array with the placeholders replaced
|
|
||||||
*/
|
|
||||||
public BaseComponent[] replaceIn(List<BaseComponent> components) {
|
|
||||||
List<BaseComponent> returnList = new ArrayList<>();
|
|
||||||
// String replacements:
|
|
||||||
for (int i = 0; i < components.size(); i++) {
|
|
||||||
BaseComponent component = components.get(i).duplicate();
|
|
||||||
if (HAS_KEYBIND_SUPPORT && component instanceof KeybindComponent) {
|
|
||||||
((KeybindComponent) component).setKeybind(replaceIn(((KeybindComponent) component).getKeybind()));
|
|
||||||
}
|
|
||||||
if (component instanceof TextComponent) {
|
|
||||||
String replaced = replaceIn(((TextComponent) component).getText());
|
|
||||||
int sectionIndex = replaced.indexOf(ChatColor.COLOR_CHAR);
|
|
||||||
if (sectionIndex > -1 && replaced.length() > sectionIndex + 1
|
|
||||||
&& ChatColor.getByChar(replaced.charAt(sectionIndex + 1)) != null) {
|
|
||||||
// replacement contain legacy code, parse to components and append them as extra
|
|
||||||
BaseComponent[] replacedComponent = TextComponent.fromLegacyText(replaced);
|
|
||||||
((TextComponent) component).setText("");
|
|
||||||
List<BaseComponent> extra = new ArrayList<>();
|
|
||||||
Collections.addAll(extra, replacedComponent);
|
|
||||||
if (component.getExtra() != null) {
|
|
||||||
Collections.addAll(extra, replaceIn(component.getExtra()));
|
|
||||||
}
|
|
||||||
component.setExtra(extra);
|
|
||||||
} else {
|
|
||||||
((TextComponent) component).setText(replaced);
|
|
||||||
if (component.getExtra() != null) {
|
|
||||||
component.setExtra(Arrays.asList(replaceIn(component.getExtra())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (component.getExtra() != null) {
|
|
||||||
component.setExtra(Arrays.asList(replaceIn(component.getExtra())));
|
|
||||||
}
|
|
||||||
if (component instanceof TranslatableComponent) {
|
|
||||||
((TranslatableComponent) component).setTranslate(replaceIn(((TranslatableComponent) component).getTranslate()));
|
|
||||||
((TranslatableComponent) component).setWith(Arrays.asList(replaceIn(((TranslatableComponent) component).getWith())));
|
|
||||||
}
|
|
||||||
if (HAS_INSERTION_SUPPORT && component.getInsertion() != null) {
|
|
||||||
component.setInsertion(replaceIn(component.getInsertion()));
|
|
||||||
}
|
|
||||||
if (component.getClickEvent() != null) {
|
|
||||||
component.setClickEvent(new ClickEvent(
|
|
||||||
component.getClickEvent().getAction(),
|
|
||||||
replaceIn(component.getClickEvent().getValue())
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if (component.getHoverEvent() != null) {
|
|
||||||
if (HAS_HOVER_CONTENT_SUPPORT) {
|
|
||||||
component.setHoverEvent(new HoverEvent(
|
|
||||||
component.getHoverEvent().getAction(),
|
|
||||||
replaceInContents(component.getHoverEvent().getContents())
|
|
||||||
));
|
|
||||||
} else if (HOVER_GET_VALUE != null) {
|
|
||||||
try {
|
|
||||||
component.setHoverEvent(new HoverEvent(
|
|
||||||
component.getHoverEvent().getAction(),
|
|
||||||
replaceIn((BaseComponent[]) HOVER_GET_VALUE.invoke(component.getHoverEvent()))
|
|
||||||
));
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Component replacements
|
|
||||||
List<BaseComponent> replacedComponents = new ArrayList<>();
|
|
||||||
replacedComponents.add(component);
|
|
||||||
|
|
||||||
for (Map.Entry<String, BaseComponent[]> replacement : componentReplacements().entrySet()) {
|
|
||||||
List<BaseComponent> newReplacedComponents = new ArrayList<>();
|
|
||||||
|
|
||||||
for (BaseComponent replaceComponent : replacedComponents) {
|
|
||||||
if (replaceComponent instanceof TextComponent) {
|
|
||||||
TextComponent textComponent = (TextComponent) replaceComponent;
|
|
||||||
String placeHolder = placeholderPrefix()
|
|
||||||
+ (ignorePlaceholderCase() ? replacement.getKey().toLowerCase(Locale.ROOT) : replacement.getKey())
|
|
||||||
+ placeholderSuffix();
|
|
||||||
String text = ignorePlaceholderCase() ? textComponent.getText().toLowerCase(Locale.ROOT) : textComponent.getText();
|
|
||||||
int index = text.indexOf(placeHolder);
|
|
||||||
if (index > -1) {
|
|
||||||
do {
|
|
||||||
TextComponent startComponent = new TextComponent(textComponent);
|
|
||||||
if (index > 0) {
|
|
||||||
startComponent.setText(textComponent.getText().substring(0, index));
|
|
||||||
} else {
|
|
||||||
startComponent.setText("");
|
|
||||||
}
|
|
||||||
startComponent.setExtra(Arrays.asList(replacement.getValue()));
|
|
||||||
newReplacedComponents.add(startComponent);
|
|
||||||
|
|
||||||
if (index + placeHolder.length() < textComponent.getText().length()) {
|
|
||||||
textComponent.setText(textComponent.getText().substring(index + placeHolder.length()));
|
|
||||||
} else {
|
|
||||||
textComponent.setText("");
|
|
||||||
}
|
|
||||||
text = ignorePlaceholderCase() ? textComponent.getText().toLowerCase(Locale.ROOT) : textComponent.getText();
|
|
||||||
newReplacedComponents.add(textComponent);
|
|
||||||
} while (!text.isEmpty() && (index = text.indexOf(placeHolder)) > -1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing was replaced, just add it
|
|
||||||
newReplacedComponents.add(replaceComponent);
|
|
||||||
}
|
|
||||||
replacedComponents = newReplacedComponents;
|
|
||||||
}
|
|
||||||
returnList.addAll(replacedComponents);
|
|
||||||
}
|
|
||||||
return returnList.toArray(new BaseComponent[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Content> replaceInContents(List<Content> contents) {
|
|
||||||
List<Content> replacedContents = new ArrayList<>();
|
|
||||||
for (Content content : contents) {
|
|
||||||
if (content instanceof Text) {
|
|
||||||
Object value = ((Text) content).getValue();
|
|
||||||
if (value instanceof BaseComponent[]) {
|
|
||||||
replacedContents.add(new Text(replaceIn((BaseComponent[]) value)));
|
|
||||||
} else if (value instanceof String) {
|
|
||||||
replacedContents.add(new Text(replaceIn((String) value)));
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot replace in " + value.getClass() + "!");
|
|
||||||
}
|
|
||||||
} else if (content instanceof Entity) {
|
|
||||||
Entity entity = (Entity) content;
|
|
||||||
String id = replaceIn(entity.getId());
|
|
||||||
String type;
|
|
||||||
if (entity.getType() != null) {
|
|
||||||
type = replaceIn(entity.getType());
|
|
||||||
} else {
|
|
||||||
type = "minecraft:pig"; // Meh
|
|
||||||
}
|
|
||||||
BaseComponent name = null;
|
|
||||||
if (entity.getName() != null) {
|
|
||||||
name = new TextComponent(replaceIn(TextComponent.toLegacyText(entity.getName())));
|
|
||||||
}
|
|
||||||
replacedContents.add(new Entity(type, id, name));
|
|
||||||
} else if (content instanceof Item) {
|
|
||||||
Item item = (Item) content;
|
|
||||||
String id = replaceIn(item.getId());
|
|
||||||
ItemTag itemTag = item.getTag() != null ? ItemTag.ofNbt(replaceIn(item.getTag().getNbt())) : null;
|
|
||||||
replacedContents.add(new Item(id, item.getCount(), itemTag));
|
|
||||||
} else {
|
|
||||||
replacedContents.add(content); // TODO: Find a good way to clone this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return replacedContents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the placeholders in a string. Does not replace component replacements!
|
|
||||||
* @param string The String list to replace in
|
|
||||||
* @return The string with the placeholders replaced
|
|
||||||
*/
|
|
||||||
public String replaceIn(String string) {
|
|
||||||
for (Map.Entry<String, String> replacement : replacements().entrySet()) {
|
|
||||||
String replValue = replacement.getValue() != null ? replacement.getValue() : "null";
|
|
||||||
if (ignorePlaceholderCase()) {
|
|
||||||
String placeholder = placeholderPrefix() + replacement.getKey().toLowerCase(Locale.ROOT) + placeholderSuffix();
|
|
||||||
int nextStart = 0;
|
|
||||||
int startIndex;
|
|
||||||
while (nextStart < string.length() && (startIndex = string.toLowerCase(Locale.ROOT).indexOf(placeholder, nextStart)) > -1) {
|
|
||||||
nextStart = startIndex + replValue.length();
|
|
||||||
string = string.substring(0, startIndex) + replValue + string.substring(startIndex + placeholder.length());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String placeholder = placeholderPrefix() + replacement.getKey() + placeholderSuffix();
|
|
||||||
Pattern pattern = PATTERN_CACHE.computeIfAbsent(placeholder, PATTERN_CREATOR);
|
|
||||||
string = pattern.matcher(string).replaceAll(Matcher.quoteReplacement(replValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a copy of this Replacer
|
|
||||||
* @return A copy of this Replacer
|
|
||||||
*/
|
|
||||||
public Replacer copy() {
|
|
||||||
return new Replacer().copy(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy all the values of another Replacer
|
|
||||||
* @param from The replacer to copy
|
|
||||||
* @return The Replacer instance
|
|
||||||
*/
|
|
||||||
public Replacer copy(Replacer from) {
|
|
||||||
replacements().clear();
|
|
||||||
replacements().putAll(from.replacements());
|
|
||||||
componentReplacements().clear();
|
|
||||||
componentReplacements().putAll(from.componentReplacements());
|
|
||||||
placeholderPrefix(from.placeholderPrefix());
|
|
||||||
placeholderSuffix(from.placeholderSuffix());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the map of placeholders with their string replacements
|
|
||||||
* @return the replacement map
|
|
||||||
*/
|
|
||||||
public Map<String, String> replacements() {
|
|
||||||
return this.replacements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the map of placeholders with their component array replacements
|
|
||||||
* @return the replacement map
|
|
||||||
*/
|
|
||||||
public Map<String, BaseComponent[]> componentReplacements() {
|
|
||||||
return this.componentReplacements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the placeholder indicator's prefix string
|
|
||||||
* @return the prefix characters
|
|
||||||
*/
|
|
||||||
public String placeholderPrefix() {
|
|
||||||
return this.placeholderPrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the placeholder indicator's prefix string
|
|
||||||
* @param placeholderPrefix The placeholder prefix string
|
|
||||||
* @return the instance of this Replacer
|
|
||||||
*/
|
|
||||||
public Replacer placeholderPrefix(String placeholderPrefix) {
|
|
||||||
this.placeholderPrefix = placeholderPrefix;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the placeholder indicator's suffix string
|
|
||||||
* @return the suffix characters
|
|
||||||
*/
|
|
||||||
public String placeholderSuffix() {
|
|
||||||
return this.placeholderSuffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the placeholder indicator's suffix string
|
|
||||||
* @param placeholderSuffix The placeholder suffix string
|
|
||||||
* @return the instance of this Replacer
|
|
||||||
*/
|
|
||||||
public Replacer placeholderSuffix(String placeholderSuffix) {
|
|
||||||
this.placeholderSuffix = placeholderSuffix;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the placeholder no matter what the case of it is
|
|
||||||
* @return whether or not to ignore the placeholder case (Default: true)
|
|
||||||
*/
|
|
||||||
public boolean ignorePlaceholderCase() {
|
|
||||||
return this.ignorePlaceholderCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not the placeholder should be replaced no matter what the case of it is
|
|
||||||
* @param ignorePlaceholderCase Whether or not to ignore the case in placeholders (Default: true)
|
|
||||||
* @return the instance of this Replacer
|
|
||||||
*/
|
|
||||||
public Replacer ignorePlaceholderCase(boolean ignorePlaceholderCase) {
|
|
||||||
this.ignorePlaceholderCase = ignorePlaceholderCase;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,590 +0,0 @@
|
|||||||
package net.momirealms.customcrops.Libs.minedown;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class Util {
|
|
||||||
|
|
||||||
private static final Pattern WRAP_PATTERN = Pattern.compile(" ", Pattern.LITERAL);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility method to throw an IllegalArgumentException if the value is false
|
|
||||||
* @param value The value to validate
|
|
||||||
* @param message The message for the exception
|
|
||||||
* @throws IllegalArgumentException Thrown if the value is false
|
|
||||||
*/
|
|
||||||
public static void validate(boolean value, String message) throws IllegalArgumentException {
|
|
||||||
if (!value) {
|
|
||||||
throw new IllegalArgumentException(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply a collection of colors/formats to a component
|
|
||||||
* @param component The BaseComponent
|
|
||||||
* @param formats The collection of ChatColor formats to apply
|
|
||||||
* @return The component that was modified
|
|
||||||
*/
|
|
||||||
public static BaseComponent applyFormat(BaseComponent component, Collection<ChatColor> formats) {
|
|
||||||
for (ChatColor format : formats) {
|
|
||||||
if (format == ChatColor.BOLD) {
|
|
||||||
component.setBold(true);
|
|
||||||
} else if (format == ChatColor.ITALIC) {
|
|
||||||
component.setItalic(true);
|
|
||||||
} else if (format == ChatColor.UNDERLINE) {
|
|
||||||
component.setUnderlined(true);
|
|
||||||
} else if (format == ChatColor.STRIKETHROUGH) {
|
|
||||||
component.setStrikethrough(true);
|
|
||||||
} else if (format == ChatColor.MAGIC) {
|
|
||||||
component.setObfuscated(true);
|
|
||||||
} else if (format == ChatColor.RESET) {
|
|
||||||
component.setBold(false);
|
|
||||||
component.setItalic(false);
|
|
||||||
component.setUnderlined(false);
|
|
||||||
component.setStrikethrough(false);
|
|
||||||
component.setObfuscated(false);
|
|
||||||
component.setColor(ChatColor.WHITE);
|
|
||||||
} else {
|
|
||||||
component.setColor(format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (component.getExtra() != null) {
|
|
||||||
for (BaseComponent extra : component.getExtra()) {
|
|
||||||
applyFormat(extra, formats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply a collection of colors/formats to a component builder
|
|
||||||
* @param builder The ComponentBuilder
|
|
||||||
* @param formats The collection of ChatColor formats to apply
|
|
||||||
* @return The component builder that was modified
|
|
||||||
* @deprecated Use {@link #applyFormat(BaseComponent, Collection)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static ComponentBuilder applyFormat(ComponentBuilder builder, Set<ChatColor> formats) {
|
|
||||||
Map<ChatColor, Boolean> formatMap = new HashMap<>();
|
|
||||||
for (ChatColor format : formats) {
|
|
||||||
formatMap.put(format, true);
|
|
||||||
}
|
|
||||||
return applyFormat(builder, formatMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply a collection of colors/formats to a component builder
|
|
||||||
* @param builder The ComponentBuilder
|
|
||||||
* @param formats The collection of ChatColor formats to apply
|
|
||||||
* @return The component builder that was modified
|
|
||||||
*/
|
|
||||||
public static ComponentBuilder applyFormat(ComponentBuilder builder, Map<ChatColor, Boolean> formats) {
|
|
||||||
for (Map.Entry<ChatColor, Boolean> e : formats.entrySet()) {
|
|
||||||
if (e.getKey() == ChatColor.BOLD) {
|
|
||||||
builder.bold(e.getValue());
|
|
||||||
} else if (e.getKey() == ChatColor.ITALIC) {
|
|
||||||
builder.italic(e.getValue());
|
|
||||||
} else if (e.getKey() == ChatColor.UNDERLINE) {
|
|
||||||
builder.underlined(e.getValue());
|
|
||||||
} else if (e.getKey() == ChatColor.STRIKETHROUGH) {
|
|
||||||
builder.strikethrough(e.getValue());
|
|
||||||
} else if (e.getKey() == ChatColor.MAGIC) {
|
|
||||||
builder.obfuscated(e.getValue());
|
|
||||||
} else if (e.getKey() == ChatColor.RESET) {
|
|
||||||
builder.bold(!e.getValue());
|
|
||||||
builder.italic(!e.getValue());
|
|
||||||
builder.underlined(!e.getValue());
|
|
||||||
builder.strikethrough(!e.getValue());
|
|
||||||
builder.obfuscated(!e.getValue());
|
|
||||||
builder.color(ChatColor.WHITE);
|
|
||||||
} else if (e.getValue()) {
|
|
||||||
builder.color(e.getKey());
|
|
||||||
} else if (builder.getCurrentComponent().getColor() == e.getKey()) {
|
|
||||||
builder.color(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether or not a character at a certain index of a string repeats itself
|
|
||||||
* @param string The string to check
|
|
||||||
* @param index The index at which to check the character
|
|
||||||
* @return Whether or not the character at that index repeated itself
|
|
||||||
*/
|
|
||||||
public static boolean isDouble(String string, int index) {
|
|
||||||
return index + 1 < string.length() && string.charAt(index) == string.charAt(index + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether a certain ChatColor is formatting or not
|
|
||||||
* @param format The ChatColor to check
|
|
||||||
* @return <code>true</code> if it's a format, <code>false</code> if it's a color
|
|
||||||
*/
|
|
||||||
public static boolean isFormat(ChatColor format) {
|
|
||||||
return !MineDown.getFormatString(format).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a set of ChatColor formats all formats that a component includes
|
|
||||||
* @param component The component to get the formats from
|
|
||||||
* @param ignoreParent Whether or not to include the parent's format
|
|
||||||
* @return A set of all the format ChatColors that the component includes
|
|
||||||
*/
|
|
||||||
public static Set<ChatColor> getFormats(BaseComponent component, boolean ignoreParent) {
|
|
||||||
Set<ChatColor> formats = new LinkedHashSet<>();
|
|
||||||
if ((!ignoreParent && component.isBold()) || (component.isBoldRaw() != null && component.isBoldRaw())) {
|
|
||||||
formats.add(ChatColor.BOLD);
|
|
||||||
}
|
|
||||||
if ((!ignoreParent && component.isItalic()) || (component.isItalicRaw() != null && component.isItalicRaw())) {
|
|
||||||
formats.add(ChatColor.ITALIC);
|
|
||||||
}
|
|
||||||
if ((!ignoreParent && component.isUnderlined()) || (component.isUnderlinedRaw() != null && component.isUnderlinedRaw())) {
|
|
||||||
formats.add(ChatColor.UNDERLINE);
|
|
||||||
}
|
|
||||||
if ((!ignoreParent && component.isStrikethrough()) || (component.isStrikethroughRaw() != null && component.isStrikethroughRaw())) {
|
|
||||||
formats.add(ChatColor.STRIKETHROUGH);
|
|
||||||
}
|
|
||||||
if ((!ignoreParent && component.isObfuscated()) || (component.isObfuscatedRaw() != null && component.isObfuscatedRaw())) {
|
|
||||||
formats.add(ChatColor.MAGIC);
|
|
||||||
}
|
|
||||||
return formats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the index of the first occurrences of a not escaped character
|
|
||||||
* @param string The string to search
|
|
||||||
* @param chars The characters to search for
|
|
||||||
* @return The first unescaped index or -1 if not found
|
|
||||||
*/
|
|
||||||
public static int indexOfNotEscaped(String string, String chars) {
|
|
||||||
return indexOfNotEscaped(string, chars, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the index of the first occurrences of a not escaped character
|
|
||||||
* @param string The string to search
|
|
||||||
* @param chars The characters to search for
|
|
||||||
* @param fromIndex Start searching from that index
|
|
||||||
* @return The first unescaped index or {@code -1} if not found
|
|
||||||
*/
|
|
||||||
public static int indexOfNotEscaped(String string, String chars, int fromIndex) {
|
|
||||||
for (int i = fromIndex; i < string.length(); i++) {
|
|
||||||
int index = string.indexOf(chars, i);
|
|
||||||
if (index == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!isEscaped(string, index)) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a character at a certain index is escaped
|
|
||||||
* @param string The string to check
|
|
||||||
* @param index The index of the character in the string to check
|
|
||||||
* @return Whether or not the character is escaped (uneven number of backslashes in front of char mains it is escaped)
|
|
||||||
* @throws IndexOutOfBoundsException if the {@code index} argument is not less than the length of this string.
|
|
||||||
*/
|
|
||||||
public static boolean isEscaped(String string, int index) {
|
|
||||||
if (index - 1 > string.length()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int e = 0;
|
|
||||||
while (index > e && string.charAt(index - e - 1) == '\\') {
|
|
||||||
e++;
|
|
||||||
}
|
|
||||||
return e % 2 != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrap a string if it is longer than the line length and contains no new line.
|
|
||||||
* Will try to wrap at spaces between words.
|
|
||||||
* @param string The string to wrap
|
|
||||||
* @param lineLength The max length of a line
|
|
||||||
* @return The wrapped string
|
|
||||||
*/
|
|
||||||
public static String wrap(String string, int lineLength) {
|
|
||||||
if (string.length() <= lineLength || string.contains("\n")) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> lines = new ArrayList<>();
|
|
||||||
StringBuilder currentLine = new StringBuilder();
|
|
||||||
for (String s : WRAP_PATTERN.split(string)) {
|
|
||||||
if (currentLine.length() + s.length() + 1 > lineLength) {
|
|
||||||
int rest = lineLength - currentLine.length() - 1;
|
|
||||||
if (rest > lineLength / 4 && s.length() > Math.min(rest * 2, lineLength / 4)) {
|
|
||||||
currentLine.append(" ").append(s, 0, rest);
|
|
||||||
} else {
|
|
||||||
rest = 0;
|
|
||||||
}
|
|
||||||
lines.add(currentLine.toString());
|
|
||||||
String restString = s.substring(rest);
|
|
||||||
while (restString.length() >= lineLength) {
|
|
||||||
lines.add(restString.substring(0, lineLength));
|
|
||||||
restString = restString.substring(lineLength);
|
|
||||||
}
|
|
||||||
currentLine = new StringBuilder(restString);
|
|
||||||
} else {
|
|
||||||
if (currentLine.length() > 0) {
|
|
||||||
currentLine.append(" ");
|
|
||||||
}
|
|
||||||
currentLine.append(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentLine.length() > 0) {
|
|
||||||
lines.add(currentLine.toString());
|
|
||||||
}
|
|
||||||
return String.join("\n", lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<ChatColor, Color> legacyColors = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
legacyColors.put(ChatColor.BLACK, new Color(0x000000));
|
|
||||||
legacyColors.put(ChatColor.DARK_BLUE, new Color(0x0000AA));
|
|
||||||
legacyColors.put(ChatColor.DARK_GREEN, new Color(0x00AA00));
|
|
||||||
legacyColors.put(ChatColor.DARK_AQUA, new Color(0x00AAAA));
|
|
||||||
legacyColors.put(ChatColor.DARK_RED, new Color(0xAA0000));
|
|
||||||
legacyColors.put(ChatColor.DARK_PURPLE, new Color(0xAA00AA));
|
|
||||||
legacyColors.put(ChatColor.GOLD, new Color(0xFFAA00));
|
|
||||||
legacyColors.put(ChatColor.GRAY, new Color(0xAAAAAA));
|
|
||||||
legacyColors.put(ChatColor.DARK_GRAY, new Color(0x555555));
|
|
||||||
legacyColors.put(ChatColor.BLUE, new Color(0x05555FF));
|
|
||||||
legacyColors.put(ChatColor.GREEN, new Color(0x55FF55));
|
|
||||||
legacyColors.put(ChatColor.AQUA, new Color(0x55FFFF));
|
|
||||||
legacyColors.put(ChatColor.RED, new Color(0xFF5555));
|
|
||||||
legacyColors.put(ChatColor.LIGHT_PURPLE, new Color(0xFF55FF));
|
|
||||||
legacyColors.put(ChatColor.YELLOW, new Color(0xFFFF55));
|
|
||||||
legacyColors.put(ChatColor.WHITE, new Color(0xFFFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility method to remove RGB colors from components. This modifies the input array!
|
|
||||||
* @param components The components to remove the rgb colors from
|
|
||||||
* @return The modified components (same as input).
|
|
||||||
*/
|
|
||||||
public static BaseComponent[] rgbColorsToLegacy(BaseComponent[] components) {
|
|
||||||
for (BaseComponent component : components) {
|
|
||||||
if (component.getColorRaw() != null && component.getColorRaw().getName().startsWith("#")) {
|
|
||||||
component.setColor(getClosestLegacy(new Color(Integer.parseInt(component.getColorRaw().getName().substring(1), 16))));
|
|
||||||
}
|
|
||||||
if (component.getExtra() != null) {
|
|
||||||
rgbColorsToLegacy(component.getExtra().toArray(new BaseComponent[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return components;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the legacy color closest to a certain RGB color
|
|
||||||
* @param color The color to get the closest legacy color for
|
|
||||||
* @return The closest legacy color
|
|
||||||
*/
|
|
||||||
public static ChatColor getClosestLegacy(Color color) {
|
|
||||||
ChatColor closest = null;
|
|
||||||
double smallestDistance = Double.MAX_VALUE;
|
|
||||||
for (Map.Entry<ChatColor, Color> legacy : legacyColors.entrySet()) {
|
|
||||||
double distance = distance(color, legacy.getValue());
|
|
||||||
if (distance < smallestDistance) {
|
|
||||||
smallestDistance = distance;
|
|
||||||
closest = legacy.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return closest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the distance between two colors
|
|
||||||
* @param c1 Color A
|
|
||||||
* @param c2 Color B
|
|
||||||
* @return The distance or 0 if they are equal
|
|
||||||
*/
|
|
||||||
public static double distance(Color c1, Color c2) {
|
|
||||||
if (c1.getRGB() == c2.getRGB()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return Math.sqrt(Math.pow(c1.getRed() - c2.getRed(), 2) + Math.pow(c1.getGreen() - c2.getGreen(), 2) + Math.pow(c1.getBlue() - c2.getBlue(), 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* createRainbow is adapted from the net.kyori.adventure.text.minimessage.fancy.Rainbow class
|
|
||||||
* in adventure-text-minimessage, licensed under the MIT License.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2018-2020 KyoriPowered
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Generate a rainbow with a certain length and phase
|
|
||||||
* @param length The length of the rainbow
|
|
||||||
* @param phase The phase of the rainbow.
|
|
||||||
* @param rgb Whether or not to use RGB colors
|
|
||||||
* @return the colors in the rainbow
|
|
||||||
* @deprecated Use {@link #createRainbow(long, int, boolean)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static List<ChatColor> createRainbow(int length, int phase, boolean rgb) {
|
|
||||||
return createRainbow((long) length, phase, rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a rainbow with a certain length and phase
|
|
||||||
* @param length The length of the rainbow
|
|
||||||
* @param phase The phase of the rainbow.
|
|
||||||
* @param rgb Whether or not to use RGB colors
|
|
||||||
* @return the colors in the rainbow
|
|
||||||
*/
|
|
||||||
public static List<ChatColor> createRainbow(long length, int phase, boolean rgb) {
|
|
||||||
List<ChatColor> colors = new ArrayList<>();
|
|
||||||
|
|
||||||
float fPhase = phase / 10f;
|
|
||||||
|
|
||||||
float center = 128;
|
|
||||||
float width = 127;
|
|
||||||
double frequency = Math.PI * 2 / length;
|
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
Color color = new Color(
|
|
||||||
(int) (Math.sin(frequency * i + 2 + fPhase) * width + center),
|
|
||||||
(int) (Math.sin(frequency * i + 0 + fPhase) * width + center),
|
|
||||||
(int) (Math.sin(frequency * i + 4 + fPhase) * width + center)
|
|
||||||
);
|
|
||||||
if (rgb) {
|
|
||||||
colors.add(ChatColor.of(color));
|
|
||||||
} else {
|
|
||||||
ChatColor chatColor = getClosestLegacy(color);
|
|
||||||
if (colors.isEmpty() || chatColor != colors.get(colors.size() - 1)) {
|
|
||||||
colors.add(chatColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return colors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* createGradient is adapted from the net.kyori.adventure.text.minimessage.fancy.Gradient class
|
|
||||||
* in adventure-text-minimessage, licensed under the MIT License.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2018-2020 KyoriPowered
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Generate a gradient with certain colors
|
|
||||||
* @param length The length of the gradient
|
|
||||||
* @param gradient The colors of the gradient.
|
|
||||||
* @param rgb Whether or not to use RGB colors
|
|
||||||
* @return the colors in the gradient
|
|
||||||
* @deprecated Use {@link #createRainbow(long, int, boolean)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static List<ChatColor> createGradient(int length, List<ChatColor> gradient, boolean rgb) {
|
|
||||||
return createGradient((long) length, gradient, rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a gradient with certain colors
|
|
||||||
* @param length The length of the gradient
|
|
||||||
* @param gradient The colors of the gradient.
|
|
||||||
* @param rgb Whether or not to use RGB colors
|
|
||||||
* @return the colors in the gradient
|
|
||||||
*/
|
|
||||||
public static List<ChatColor> createGradient(long length, List<ChatColor> gradient, boolean rgb) {
|
|
||||||
List<ChatColor> colors = new ArrayList<>();
|
|
||||||
if (gradient.size() < 2 || length < 2) {
|
|
||||||
if (gradient.isEmpty()) {
|
|
||||||
return gradient;
|
|
||||||
}
|
|
||||||
return Collections.singletonList(gradient.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
float fPhase = 0;
|
|
||||||
|
|
||||||
float sectorLength = (float) (length - 1) / (gradient.size() - 1);
|
|
||||||
float factorStep = 1.0f / (sectorLength);
|
|
||||||
|
|
||||||
long index = 0;
|
|
||||||
|
|
||||||
int colorIndex = 0;
|
|
||||||
|
|
||||||
for (long i = 0; i < length; i++) {
|
|
||||||
|
|
||||||
if (factorStep * index > 1) {
|
|
||||||
colorIndex++;
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float factor = factorStep * (index++ + fPhase);
|
|
||||||
// loop around if needed
|
|
||||||
if (factor > 1) {
|
|
||||||
factor = 1 - (factor - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Color color = interpolate(
|
|
||||||
getColor(gradient.get(colorIndex), rgb),
|
|
||||||
getColor(gradient.get(Math.min(gradient.size() - 1, colorIndex + 1)), rgb),
|
|
||||||
factor
|
|
||||||
);
|
|
||||||
|
|
||||||
if (color != null) {
|
|
||||||
if (rgb) {
|
|
||||||
colors.add(ChatColor.of(color));
|
|
||||||
} else {
|
|
||||||
ChatColor chatColor = getClosestLegacy(color);
|
|
||||||
if (colors.isEmpty() || chatColor != colors.get(colors.size() - 1)) {
|
|
||||||
colors.add(chatColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return colors;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Color getColor(ChatColor color, boolean rgb) {
|
|
||||||
if (legacyColors.containsKey(color)) {
|
|
||||||
return legacyColors.get(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color.getName().startsWith("#")) {
|
|
||||||
Color c = new Color(Integer.parseInt(color.getName().substring(1), 16));
|
|
||||||
if (rgb) {
|
|
||||||
return c;
|
|
||||||
} else {
|
|
||||||
return legacyColors.get(getClosestLegacy(c));
|
|
||||||
}
|
|
||||||
} else if (rgb) {
|
|
||||||
return color.getColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Color interpolate(Color color1, Color color2, float factor) {
|
|
||||||
if (color1 == null || color2 == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Color(
|
|
||||||
Math.round(color1.getRed() + factor * (color2.getRed() - color1.getRed())),
|
|
||||||
Math.round(color1.getGreen() + factor * (color2.getGreen() - color1.getGreen())),
|
|
||||||
Math.round(color1.getBlue() + factor * (color2.getBlue() - color1.getBlue()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a certain class exists. See {@link Class#forName(String)}
|
|
||||||
* @param className The class name to check
|
|
||||||
* @return <code>true</code> if the class exists, <code>false</code> if not
|
|
||||||
*/
|
|
||||||
public static boolean hasClass(String className) {
|
|
||||||
try {
|
|
||||||
Class.forName(className);
|
|
||||||
return true;
|
|
||||||
} catch (ClassNotFoundException classDoesntExist) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a class has a certain method. See {@link Class#getMethod(String, Class[])}
|
|
||||||
* @param clazz The class to check
|
|
||||||
* @param method The method to check for
|
|
||||||
* @param parameter Method parameter types
|
|
||||||
* @return <code>true</code> if the class has the method, <code>false</code> if not
|
|
||||||
*/
|
|
||||||
public static boolean hasMethod(Class<?> clazz, String method, Class<?>... parameter) {
|
|
||||||
try {
|
|
||||||
clazz.getMethod(method, parameter);
|
|
||||||
return true;
|
|
||||||
} catch (NoSuchMethodException methodDoesntExist) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a method from a class if it exists. See {@link Class#getMethod(String, Class[])}
|
|
||||||
* @param clazz The class
|
|
||||||
* @param method The method name to get
|
|
||||||
* @param parameter Method parameter types
|
|
||||||
* @return the method, null if it doesn't exist
|
|
||||||
*/
|
|
||||||
public static Method getMethod(Class<?> clazz, String method, Class<?>... parameter) {
|
|
||||||
try {
|
|
||||||
return clazz.getMethod(method, parameter);
|
|
||||||
} catch (NoSuchMethodException methodDoesntExist) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,8 @@ import dev.lone.itemsadder.api.Events.CustomBlockBreakEvent;
|
|||||||
import net.momirealms.customcrops.CustomCrops;
|
import net.momirealms.customcrops.CustomCrops;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -13,27 +15,31 @@ import org.bukkit.event.Listener;
|
|||||||
|
|
||||||
public class BreakCustomBlock implements Listener {
|
public class BreakCustomBlock implements Listener {
|
||||||
|
|
||||||
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void breakCustomBlock(CustomBlockBreakEvent event){
|
public void breakCustomBlock(CustomBlockBreakEvent event){
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
|
||||||
Player player =event.getPlayer();
|
Player player =event.getPlayer();
|
||||||
Location location = event.getBlock().getLocation();
|
Location location = event.getBlock().getLocation();
|
||||||
if(event.getNamespacedID().contains("stage")){
|
String namespacedId = event.getNamespacedID();
|
||||||
|
if(namespacedId.contains("stage")){
|
||||||
if(player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH) || player.getInventory().getItemInMainHand().getType() == Material.SHEARS){
|
if(player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH) || player.getInventory().getItemInMainHand().getType() == Material.SHEARS){
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
CustomBlock.place(event.getNamespacedID(), location);
|
CustomBlock.place(namespacedId, location);
|
||||||
CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(location)).getLoot().forEach(itemStack -> {
|
CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(location)).getLoot().forEach(itemStack -> {
|
||||||
location.getWorld().dropItem(location.clone().add(0.5,0.2,0.5), itemStack);
|
location.getWorld().dropItem(location.clone().add(0.5,0.2,0.5), itemStack);
|
||||||
CustomBlock.remove(location);
|
CustomBlock.remove(location);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}else if(event.getNamespacedID().equalsIgnoreCase(config.getString("config.watered-pot")) || event.getNamespacedID().equalsIgnoreCase(config.getString("config.pot"))){
|
}else if(namespacedId.equalsIgnoreCase(config.getString("config.watered-pot")) || namespacedId.equalsIgnoreCase(config.getString("config.pot"))){
|
||||||
if(CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(location.clone().add(0,1,0))) != null){
|
World world = location.getWorld();
|
||||||
if(CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(location.clone().add(0,1,0))).getNamespacedID().contains("stage")){
|
Block blockUp = world.getBlockAt(location.add(0,1,0));
|
||||||
CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(location.clone().add(0,1,0))).getLoot().forEach(itemStack -> {
|
if(CustomBlock.byAlreadyPlaced(blockUp) != null){
|
||||||
location.getWorld().dropItem(location.clone().add(0.5,1.2,0.5), itemStack);
|
if(CustomBlock.byAlreadyPlaced(blockUp).getNamespacedID().contains("stage")){
|
||||||
|
CustomBlock.byAlreadyPlaced(blockUp).getLoot().forEach(itemStack -> {
|
||||||
|
world.dropItem(location.clone().add(0.5,0.2,0.5), itemStack);
|
||||||
});
|
});
|
||||||
CustomBlock.remove(location.clone().add(0,1,0));
|
CustomBlock.remove(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,20 +11,20 @@ import org.bukkit.event.entity.EntitySpawnEvent;
|
|||||||
|
|
||||||
public class BreakFurniture implements Listener {
|
public class BreakFurniture implements Listener {
|
||||||
|
|
||||||
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void breakFurniture(EntitySpawnEvent event){
|
public void breakFurniture(EntitySpawnEvent event){
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
|
||||||
Entity entity = event.getEntity();
|
Entity entity = event.getEntity();
|
||||||
if(!(entity instanceof Item)){
|
if(!(entity instanceof Item)) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(CustomStack.byItemStack(((Item) entity).getItemStack()) != null){
|
if(CustomStack.byItemStack(((Item) entity).getItemStack()) != null){
|
||||||
if(CustomStack.byItemStack(((Item) entity).getItemStack()).getNamespacedID().equalsIgnoreCase(config.getString("config.sprinkler-1"))){
|
String namespacedId = CustomStack.byItemStack(((Item) entity).getItemStack()).getNamespacedID();
|
||||||
|
if(namespacedId.equalsIgnoreCase(config.getString("config.sprinkler-1"))){
|
||||||
entity.remove();
|
entity.remove();
|
||||||
entity.getWorld().dropItem(entity.getLocation() ,CustomStack.getInstance(config.getString("config.sprinkler-1-item")).getItemStack());
|
entity.getWorld().dropItem(entity.getLocation() ,CustomStack.getInstance(namespacedId + "_item").getItemStack());
|
||||||
}else if(CustomStack.byItemStack(((Item) entity).getItemStack()).getNamespacedID().equalsIgnoreCase(config.getString("config.sprinkler-2"))){
|
}else if(namespacedId.equalsIgnoreCase(config.getString("config.sprinkler-2"))){
|
||||||
entity.remove();
|
entity.remove();
|
||||||
entity.getWorld().dropItem(entity.getLocation() ,CustomStack.getInstance(config.getString("config.sprinkler-2-item")).getItemStack());
|
entity.getWorld().dropItem(entity.getLocation() ,CustomStack.getInstance(namespacedId + "_item").getItemStack());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import net.momirealms.customcrops.CustomCrops;
|
|||||||
import net.momirealms.customcrops.DataManager.MaxSprinklersPerChunk;
|
import net.momirealms.customcrops.DataManager.MaxSprinklersPerChunk;
|
||||||
import net.momirealms.customcrops.DataManager.SprinklerManager;
|
import net.momirealms.customcrops.DataManager.SprinklerManager;
|
||||||
import net.momirealms.customcrops.IAFurniture;
|
import net.momirealms.customcrops.IAFurniture;
|
||||||
import net.momirealms.customcrops.Integrations.KingdomsXIntegrations;
|
import net.momirealms.customcrops.Integrations.IntegrationCheck;
|
||||||
import net.momirealms.customcrops.Integrations.ResidenceIntegrations;
|
|
||||||
import net.momirealms.customcrops.Integrations.WorldGuardIntegrations;
|
|
||||||
import net.momirealms.customcrops.MessageManager;
|
import net.momirealms.customcrops.MessageManager;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -32,110 +30,69 @@ public class RightClickBlock implements Listener {
|
|||||||
|
|
||||||
if(!event.hasItem()) return;
|
if(!event.hasItem()) return;
|
||||||
if(event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_AIR) return;
|
if(event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_AIR) return;
|
||||||
if(CustomStack.byItemStack(event.getItem()) == null) return;
|
|
||||||
|
|
||||||
Player player = event.getPlayer();
|
CustomStack customStack = CustomStack.byItemStack(event.getItem());
|
||||||
ItemStack itemStack = event.getItem();
|
|
||||||
//水壶加水
|
|
||||||
if(itemStack.getType() == Material.WOODEN_SWORD){
|
|
||||||
List<Block> lineOfSight = player.getLineOfSight(null, 3);
|
|
||||||
boolean hasWater = false;
|
|
||||||
for (final Block block : lineOfSight) {
|
|
||||||
if (block.getType() == Material.WATER) {
|
|
||||||
hasWater = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(hasWater){
|
|
||||||
addWater(itemStack,player);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
|
||||||
if(event.getBlockFace() != BlockFace.UP) return;
|
|
||||||
|
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
if(customStack != null){
|
||||||
Location location = event.getClickedBlock().getLocation();
|
Player player = event.getPlayer();
|
||||||
|
ItemStack itemStack = event.getItem();
|
||||||
if(CustomStack.byItemStack(event.getItem()).getNamespacedID().equalsIgnoreCase(config.getString("config.sprinkler-1-item"))){
|
String namespacedId = customStack.getNamespacedID();
|
||||||
//res兼容
|
//检测手中物品是否可能为水壶
|
||||||
if(config.getBoolean("config.integration.residence")){
|
if(itemStack.getType() == Material.WOODEN_SWORD){
|
||||||
if(ResidenceIntegrations.checkResBuild(location,player)){
|
List<Block> lineOfSight = player.getLineOfSight(null, 3);
|
||||||
return;
|
//检测范围内是否有水
|
||||||
|
boolean hasWater = false;
|
||||||
|
for (final Block block : lineOfSight) {
|
||||||
|
if (block.getType() == Material.WATER) {
|
||||||
|
hasWater = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if(hasWater){
|
||||||
//wg兼容
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
if(config.getBoolean("config.integration.worldguard")){
|
if(namespacedId.equalsIgnoreCase(config.getString("config.watering-can-1")) ||
|
||||||
if(WorldGuardIntegrations.checkWGBuild(location,player)){
|
namespacedId.equalsIgnoreCase(config.getString("config.watering-can-2")) ||
|
||||||
return;
|
namespacedId.equalsIgnoreCase(config.getString("config.watering-can-3"))) {
|
||||||
|
if(customStack.getMaxDurability() == customStack.getDurability()){
|
||||||
|
MessageManager.playerMessage(config.getString("messages.prefix") + config.getString("messages.can-full"),player);
|
||||||
|
}else {
|
||||||
|
customStack.setDurability(customStack.getDurability() + 1);
|
||||||
|
player.getWorld().playSound(player.getLocation(),Sound.ITEM_BUCKET_FILL,1,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
//kingdomsX兼容
|
|
||||||
if(config.getBoolean("config.integration.kingdomsX")){
|
|
||||||
if(KingdomsXIntegrations.checkKDBuild(location,player)){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event.getClickedBlock().getY() > config.getInt("config.height.max") || event.getClickedBlock().getY() < config.getInt("config.height.min")){
|
|
||||||
MessageManager.playerMessage(config.getString("messages.prefix") + config.getString("messages.not-a-good-place"),player);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(MaxSprinklersPerChunk.maxSprinklersPerChunk(location)){
|
if(event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getBlockFace() == BlockFace.UP) {
|
||||||
MessageManager.playerMessage(config.getString("messages.prefix")+config.getString("messages.reach-limit-sprinkler").replace("{Max}", config.getString("config.max-sprinklers")),player);
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
return;
|
if(namespacedId.equalsIgnoreCase(config.getString("config.sprinkler-1-item")) || namespacedId.equalsIgnoreCase(config.getString("config.sprinkler-2-item"))){
|
||||||
}
|
Location location = event.getClickedBlock().getLocation();
|
||||||
if(player.getGameMode() != GameMode.CREATIVE){
|
//兼容性检测
|
||||||
itemStack.setAmount(itemStack.getAmount() -1);
|
if(IntegrationCheck.PlaceCheck(location,player)){
|
||||||
}
|
return;
|
||||||
IAFurniture.placeFurniture(config.getString("config.sprinkler-1"),location.clone().add(0,1,0));
|
}
|
||||||
SprinklerManager.putInstance(location.clone().add(0,1,0),"s1");
|
//高度限制
|
||||||
}else if(CustomStack.byItemStack(event.getItem()).getNamespacedID().equalsIgnoreCase(config.getString("config.sprinkler-2-item"))){
|
if(event.getClickedBlock().getY() > config.getInt("config.height.max") || event.getClickedBlock().getY() < config.getInt("config.height.min")){
|
||||||
//res兼容
|
MessageManager.playerMessage(config.getString("messages.prefix") + config.getString("messages.not-a-good-place"),player);
|
||||||
if(config.getBoolean("config.integration.residence")){
|
return;
|
||||||
if(ResidenceIntegrations.checkResBuild(location,player)){
|
}
|
||||||
return;
|
//此位置是否已有洒水器
|
||||||
}
|
if(MaxSprinklersPerChunk.alreadyPlaced(location)){
|
||||||
}
|
return;
|
||||||
//wg兼容
|
}
|
||||||
if(config.getBoolean("config.integration.worldguard")){
|
//区块上限
|
||||||
if(WorldGuardIntegrations.checkWGBuild(location,player)){
|
if(MaxSprinklersPerChunk.maxSprinklersPerChunk(location)){
|
||||||
return;
|
MessageManager.playerMessage(config.getString("messages.prefix")+config.getString("messages.reach-limit-sprinkler").replace("{Max}", config.getString("config.max-sprinklers")),player);
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
//kingdomsX兼容
|
if(player.getGameMode() != GameMode.CREATIVE){
|
||||||
if(config.getBoolean("config.integration.kingdomsX")){
|
itemStack.setAmount(itemStack.getAmount() -1);
|
||||||
if(KingdomsXIntegrations.checkKDBuild(location,player)){
|
}
|
||||||
return;
|
if(namespacedId.equalsIgnoreCase(config.getString("config.sprinkler-1-item"))){
|
||||||
}
|
SprinklerManager.putInstance(location.clone().add(0,1,0),"s1");
|
||||||
}
|
}else {
|
||||||
if(event.getClickedBlock().getY() > config.getInt("config.height.max") || event.getClickedBlock().getY() < config.getInt("config.height.min")){
|
SprinklerManager.putInstance(location.clone().add(0,1,0),"s2");
|
||||||
MessageManager.playerMessage(config.getString("messages.prefix") + config.getString("messages.not-a-good-place"),player);
|
}
|
||||||
return;
|
IAFurniture.placeFurniture(namespacedId.replace("_item",""),location.clone().add(0,1,0));
|
||||||
}
|
|
||||||
if(MaxSprinklersPerChunk.maxSprinklersPerChunk(location)){
|
|
||||||
MessageManager.playerMessage(config.getString("messages.prefix")+config.getString("messages.reach-limit-sprinkler").replace("{Max}", config.getString("config.max-sprinklers")),player);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(player.getGameMode() != GameMode.CREATIVE){
|
|
||||||
itemStack.setAmount(itemStack.getAmount() -1);
|
|
||||||
}
|
|
||||||
IAFurniture.placeFurniture(config.getString("config.sprinkler-2"),location.clone().add(0,1,0));
|
|
||||||
SprinklerManager.putInstance(location.clone().add(0,1,0),"s2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void addWater(ItemStack itemStack, Player player){
|
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
|
||||||
if(CustomStack.byItemStack(itemStack)!= null){
|
|
||||||
CustomStack customStack = CustomStack.byItemStack(itemStack);
|
|
||||||
if(customStack.getNamespacedID().equalsIgnoreCase(config.getString("config.watering-can-1")) ||
|
|
||||||
customStack.getNamespacedID().equalsIgnoreCase(config.getString("config.watering-can-2")) ||
|
|
||||||
customStack.getNamespacedID().equalsIgnoreCase(config.getString("config.watering-can-3")))
|
|
||||||
{
|
|
||||||
if(customStack.getMaxDurability() == customStack.getDurability()){
|
|
||||||
MessageManager.playerMessage(config.getString("messages.prefix") + config.getString("messages.can-full"),player);
|
|
||||||
}else {
|
|
||||||
customStack.setDurability(customStack.getDurability() + 1);
|
|
||||||
player.getWorld().playSound(player.getLocation(),Sound.ITEM_BUCKET_FILL,1,1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ import dev.lone.itemsadder.api.Events.CustomBlockInteractEvent;
|
|||||||
import net.momirealms.customcrops.CustomCrops;
|
import net.momirealms.customcrops.CustomCrops;
|
||||||
import net.momirealms.customcrops.DataManager.CropManager;
|
import net.momirealms.customcrops.DataManager.CropManager;
|
||||||
import net.momirealms.customcrops.DataManager.MaxCropsPerChunk;
|
import net.momirealms.customcrops.DataManager.MaxCropsPerChunk;
|
||||||
import net.momirealms.customcrops.Integrations.KingdomsXIntegrations;
|
import net.momirealms.customcrops.Integrations.IntegrationCheck;
|
||||||
import net.momirealms.customcrops.Integrations.ResidenceIntegrations;
|
|
||||||
import net.momirealms.customcrops.Integrations.WorldGuardIntegrations;
|
|
||||||
import net.momirealms.customcrops.MessageManager;
|
import net.momirealms.customcrops.MessageManager;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
@@ -19,6 +18,7 @@ import org.bukkit.event.EventHandler;
|
|||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -29,166 +29,200 @@ public class RightClickCustomBlock implements Listener {
|
|||||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Block clickedBlock = event.getBlockClicked();
|
//获取配置文件
|
||||||
Location clickedBlockLocation = clickedBlock.getLocation();
|
|
||||||
CustomBlock clickedCustomBlock = CustomBlock.byAlreadyPlaced(clickedBlock);
|
|
||||||
FileConfiguration config = CustomCrops.instance.getConfig();
|
FileConfiguration config = CustomCrops.instance.getConfig();
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
if(config.getBoolean("config.integration.kingdomsX")){
|
Block clickedBlock = event.getBlockClicked();
|
||||||
if(KingdomsXIntegrations.checkKDBuild(clickedBlockLocation,player)){
|
Location clickedBlockLocation = clickedBlock.getLocation();
|
||||||
return;
|
/*
|
||||||
}
|
手里无物品,则进行收获判断
|
||||||
}
|
手里有物品,则进行浇水,骨粉,种植判断
|
||||||
|
*/
|
||||||
|
//手无物品部分
|
||||||
if (event.getItem() == null) {
|
if (event.getItem() == null) {
|
||||||
if(config.getBoolean("config.integration.residence")){
|
CustomBlock clickedCustomBlock = CustomBlock.byAlreadyPlaced(clickedBlock);
|
||||||
if(ResidenceIntegrations.checkResHarvest(clickedBlockLocation,player)){
|
if(clickedCustomBlock == null) return;
|
||||||
return;
|
//兼容性检测
|
||||||
}
|
if(!IntegrationCheck.HarvestCheck(clickedBlockLocation, player)){
|
||||||
}
|
//获取点击方块的命名空间与ID
|
||||||
if(config.getBoolean("config.integration.worldguard")){
|
String namespacedID = clickedCustomBlock.getNamespacedID();
|
||||||
if(WorldGuardIntegrations.checkWGHarvest(clickedBlockLocation,player)){
|
//如果ID内有stage则进行下一步
|
||||||
return;
|
if (namespacedID.contains("stage")){
|
||||||
}
|
//是否为枯萎植物
|
||||||
}
|
if(namespacedID.equalsIgnoreCase(config.getString("config.dead-crop"))) return;
|
||||||
if (clickedCustomBlock.getNamespacedID().contains("stage")){
|
//String namespace = clickedCustomBlock.getNamespacedID().split(":")[0];
|
||||||
if(clickedCustomBlock.getNamespacedID().equalsIgnoreCase(config.getString("config.dead-crop"))) return;
|
String[] split = StringUtils.split(namespacedID,":");
|
||||||
String namespace = clickedCustomBlock.getNamespacedID().split(":")[0];
|
//String[] cropNameList = clickedCustomBlock.getNamespacedID().split(":")[1].split("_");
|
||||||
String[] cropNameList = clickedCustomBlock.getNamespacedID().split(":")[1].split("_");
|
String[] cropNameList = StringUtils.split(split[1],"_");
|
||||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
|
||||||
if (CustomBlock.getInstance(namespace + ":" + cropNameList[0] + "_" +cropNameList[1] +"_" + nextStage) == null) {
|
|
||||||
clickedCustomBlock.getLoot().forEach(itemStack -> {
|
|
||||||
clickedBlockLocation.getWorld().dropItem(clickedBlockLocation.clone().add(0.5,0.2,0.5),itemStack);
|
|
||||||
});
|
|
||||||
CustomBlock.remove(clickedBlockLocation);
|
|
||||||
if(config.getConfigurationSection("crops." + cropNameList[0]).getKeys(false).contains("return")){
|
|
||||||
CustomBlock.place(config.getString("crops." + cropNameList[0] + ".return"), clickedBlockLocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//res兼容
|
|
||||||
if(config.getBoolean("config.integration.residence")){
|
|
||||||
if(ResidenceIntegrations.checkResBuild(clickedBlockLocation,player)){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//wg兼容
|
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||||
if(config.getBoolean("config.integration.worldguard")){
|
//农作物是否存在下一阶段
|
||||||
if(WorldGuardIntegrations.checkWGBuild(clickedBlockLocation,player)){
|
if (CustomBlock.getInstance(split[0] + ":" + cropNameList[0] + "_stage_" + nextStage) == null) {
|
||||||
return;
|
//如果不存在下一阶段说明已是最终阶段,可以收获
|
||||||
}
|
//遍历掉落物并删除方块
|
||||||
}
|
clickedCustomBlock.getLoot().forEach(itemStack -> {
|
||||||
|
clickedBlockLocation.getWorld().dropItem(clickedBlockLocation.clone().add(0.5,0.2,0.5),itemStack);
|
||||||
World world = player.getWorld();
|
});
|
||||||
ItemStack mainHandItem = player.getInventory().getItemInMainHand();
|
CustomBlock.remove(clickedBlockLocation);
|
||||||
|
//如果配置文件中有return项目则放置方块
|
||||||
//右键的作物下方是否为自定义方块
|
if(config.getConfigurationSection("crops." + cropNameList[0]).getKeys(false).contains("return")){
|
||||||
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(clickedBlockLocation.clone().subtract(0,1,0))) != null && clickedBlock.getType() == Material.TRIPWIRE) {
|
CustomBlock.place(config.getString("crops." + cropNameList[0] + ".return"), clickedBlockLocation);
|
||||||
//检测右键的方块下方是否为干燥的种植盆方块
|
|
||||||
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(clickedBlockLocation.clone().subtract(0,1,0))).getNamespacedID().equalsIgnoreCase(config.getString("config.pot"))) {
|
|
||||||
//如果手中的是水桶,那么转干为湿
|
|
||||||
if (mainHandItem.getType() == Material.WATER_BUCKET) {
|
|
||||||
//扣除水桶
|
|
||||||
if(player.getGameMode() != GameMode.CREATIVE){
|
|
||||||
mainHandItem.setAmount(mainHandItem.getAmount() - 1);
|
|
||||||
player.getInventory().addItem(new ItemStack(Material.BUCKET));
|
|
||||||
}
|
|
||||||
CustomBlock.remove(clickedBlockLocation.clone().subtract(0, 1, 0));
|
|
||||||
CustomBlock.place(config.getString("config.watered-pot"), clickedBlockLocation.clone().subtract(0, 1, 0));
|
|
||||||
}else if(mainHandItem.getType() == Material.WOODEN_SWORD){
|
|
||||||
waterPot(mainHandItem,player,clickedBlockLocation.clone().subtract(0,1,0),config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//检测右键的方块下方是否为湿润的种植盆方块
|
|
||||||
else if(CustomBlock.byAlreadyPlaced(world.getBlockAt(clickedBlockLocation.clone().subtract(0,1,0))).getNamespacedID().equalsIgnoreCase(config.getString("config.watered-pot"))){
|
|
||||||
//如果是骨粉
|
|
||||||
if (mainHandItem.getType() == Material.BONE_MEAL){
|
|
||||||
//植物是否具有stage属性
|
|
||||||
if (clickedCustomBlock.getNamespacedID().contains("stage")){
|
|
||||||
String namespace = clickedCustomBlock.getNamespacedID().split(":")[0];
|
|
||||||
String[] cropNameList = clickedCustomBlock.getNamespacedID().split(":")[1].split("_");
|
|
||||||
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
|
||||||
//植物是否存在下一个stage
|
|
||||||
if (CustomBlock.getInstance(namespace+ ":" + cropNameList[0] + "_stage_" + nextStage) != null){
|
|
||||||
if(player.getGameMode() != GameMode.CREATIVE){
|
|
||||||
mainHandItem.setAmount(mainHandItem.getAmount() - 1);
|
|
||||||
}
|
|
||||||
//骨粉的成功率
|
|
||||||
if (Math.random() < config.getDouble("config.bone-meal-chance")){
|
|
||||||
CustomBlock.remove(clickedBlockLocation);
|
|
||||||
CustomBlock.place(namespace + ":" + cropNameList[0] + "_stage_" + nextStage,clickedBlockLocation);
|
|
||||||
Particle particleSuccess = Particle.valueOf(config.getString("config.particle.success"));
|
|
||||||
world.spawnParticle(particleSuccess, clickedBlockLocation.clone().add(0.5, 0.1,0.5), 1 ,0,0,0,0);
|
|
||||||
//使用骨粉是否消耗水分
|
|
||||||
if(config.getBoolean("config.bone-meal-consume-water")){
|
|
||||||
CustomBlock.remove(clickedBlockLocation.clone().subtract(0,1,0));
|
|
||||||
CustomBlock.place(config.getString("config.pot"), clickedBlockLocation.clone().subtract(0,1,0));
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
Particle particleFailure = Particle.valueOf(config.getString("config.particle.failure"));
|
|
||||||
world.spawnParticle(particleFailure, clickedBlockLocation.clone().add(0.5, 0.1,0.5), 1 ,0,0,0,0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (CustomBlock.byAlreadyPlaced(world.getBlockAt(clickedBlockLocation)) != null && event.getBlockFace() == BlockFace.UP){
|
}else{
|
||||||
//检测右键的方块是否为干燥的种植盆方块
|
//非空手状态
|
||||||
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(clickedBlockLocation)).getNamespacedID().equalsIgnoreCase(config.getString("config.pot"))){
|
//右键的不是自定义方块返回
|
||||||
//如果手中的是水桶,那么转干为湿
|
CustomBlock clickedCustomBlock = CustomBlock.byAlreadyPlaced(clickedBlock);
|
||||||
if (mainHandItem.getType() == Material.WATER_BUCKET){
|
if(clickedCustomBlock == null) return;
|
||||||
//扣除水桶
|
|
||||||
if(player.getGameMode() != GameMode.CREATIVE){
|
|
||||||
mainHandItem.setAmount(mainHandItem.getAmount() - 1);
|
|
||||||
player.getInventory().addItem(new ItemStack(Material.BUCKET));
|
|
||||||
}
|
|
||||||
CustomBlock.remove(clickedBlockLocation);
|
|
||||||
CustomBlock.place(config.getString("config.watered-pot"),clickedBlockLocation);
|
|
||||||
} else if (mainHandItem.getType() == Material.WOODEN_SWORD){
|
|
||||||
waterPot(mainHandItem, player,clickedBlockLocation, config);
|
|
||||||
} else {
|
|
||||||
tryPlantSeed(clickedBlockLocation, mainHandItem, player, config);
|
|
||||||
}
|
|
||||||
//检测右键的方块是否为湿润的种植盆方块
|
|
||||||
}else if(CustomBlock.byAlreadyPlaced(world.getBlockAt(clickedBlockLocation)).getNamespacedID().equalsIgnoreCase(config.getString("config.watered-pot"))){
|
|
||||||
|
|
||||||
tryPlantSeed(clickedBlockLocation, mainHandItem, player, config);
|
//获取右键物品的namespaceID
|
||||||
|
String namespacedId = clickedCustomBlock.getNamespacedID();
|
||||||
|
|
||||||
|
/*
|
||||||
|
右键的是特殊作物吗
|
||||||
|
*/
|
||||||
|
if (namespacedId.contains("stage")) {
|
||||||
|
//下方方块不是自定义方块则返回
|
||||||
|
World world = player.getWorld();
|
||||||
|
Block blockUnder = world.getBlockAt(clickedBlockLocation.clone().subtract(0,1,0));
|
||||||
|
if (CustomBlock.byAlreadyPlaced(blockUnder) == null) return;
|
||||||
|
//检测右键的方块下方是否为干燥的种植盆方块
|
||||||
|
if (CustomBlock.byAlreadyPlaced(blockUnder).getNamespacedID().equalsIgnoreCase(config.getString("config.pot"))) {
|
||||||
|
//获取手中的物品
|
||||||
|
ItemStack mainHandItem = player.getInventory().getItemInMainHand();
|
||||||
|
Location locUnder = clickedBlockLocation.clone().subtract(0,1,0);
|
||||||
|
//如果手中的是水桶,那么转干为湿
|
||||||
|
if (mainHandItem.getType() == Material.WATER_BUCKET) {
|
||||||
|
//扣除水桶
|
||||||
|
if (player.getGameMode() != GameMode.CREATIVE) {
|
||||||
|
mainHandItem.setAmount(mainHandItem.getAmount() - 1);
|
||||||
|
player.getInventory().addItem(new ItemStack(Material.BUCKET));
|
||||||
|
}
|
||||||
|
CustomBlock.remove(locUnder);
|
||||||
|
CustomBlock.place(config.getString("config.watered-pot"), locUnder);
|
||||||
|
} else if (mainHandItem.getType() == Material.WOODEN_SWORD) {
|
||||||
|
waterPot(mainHandItem, player, locUnder, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//检测右键的方块下方是否为湿润的种植盆方块
|
||||||
|
else if(CustomBlock.byAlreadyPlaced(blockUnder).getNamespacedID().equalsIgnoreCase(config.getString("config.watered-pot"))){
|
||||||
|
//获取手中的物品
|
||||||
|
ItemStack mainHandItem = player.getInventory().getItemInMainHand();
|
||||||
|
//如果是骨粉
|
||||||
|
if (mainHandItem.getType() == Material.BONE_MEAL){
|
||||||
|
//植物是否具有stage属性
|
||||||
|
if (clickedCustomBlock.getNamespacedID().contains("stage")){
|
||||||
|
//获取点击方块的命名空间与ID
|
||||||
|
String namespacedID = clickedCustomBlock.getNamespacedID();
|
||||||
|
//String namespace = clickedCustomBlock.getNamespacedID().split(":")[0];
|
||||||
|
String[] split = StringUtils.split(namespacedID,":");
|
||||||
|
//String[] cropNameList = clickedCustomBlock.getNamespacedID().split(":")[1].split("_");
|
||||||
|
String[] cropNameList = StringUtils.split(split[1],"_");
|
||||||
|
//下一生长阶段
|
||||||
|
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
|
||||||
|
//植物是否存在下一个stage
|
||||||
|
if (CustomBlock.getInstance(split[0]+ ":" + cropNameList[0] + "_stage_" + nextStage) != null){
|
||||||
|
if(player.getGameMode() != GameMode.CREATIVE){
|
||||||
|
mainHandItem.setAmount(mainHandItem.getAmount() - 1);
|
||||||
|
}
|
||||||
|
//骨粉的成功率
|
||||||
|
if (Math.random() < config.getDouble("config.bone-meal-chance")){
|
||||||
|
CustomBlock.remove(clickedBlockLocation);
|
||||||
|
CustomBlock.place(split[0] + ":" + cropNameList[0] + "_stage_" + nextStage,clickedBlockLocation);
|
||||||
|
Particle particleSuccess = Particle.valueOf(config.getString("config.particle.success"));
|
||||||
|
world.spawnParticle(particleSuccess, clickedBlockLocation.clone().add(0.5, 0.1,0.5), 1 ,0,0,0,0);
|
||||||
|
//使用骨粉是否消耗水分
|
||||||
|
if(config.getBoolean("config.bone-meal-consume-water")){
|
||||||
|
CustomBlock.remove(clickedBlockLocation.clone().subtract(0,1,0));
|
||||||
|
CustomBlock.place(config.getString("config.pot"), clickedBlockLocation.clone().subtract(0,1,0));
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
Particle particleFailure = Particle.valueOf(config.getString("config.particle.failure"));
|
||||||
|
world.spawnParticle(particleFailure, clickedBlockLocation.clone().add(0.5, 0.1,0.5), 1 ,0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
右键的是种植盆吗
|
||||||
|
*/
|
||||||
|
else if (event.getBlockFace() == BlockFace.UP){
|
||||||
|
//获取手中的物品
|
||||||
|
ItemStack mainHandItem = player.getInventory().getItemInMainHand();
|
||||||
|
World world = player.getWorld();
|
||||||
|
|
||||||
|
//检测右键的方块是否为干燥的种植盆方块
|
||||||
|
if (namespacedId.equalsIgnoreCase(config.getString("config.pot"))){
|
||||||
|
//如果手中的是水桶,那么转干为湿
|
||||||
|
|
||||||
|
if (mainHandItem.getType() == Material.WATER_BUCKET){
|
||||||
|
//扣除水桶
|
||||||
|
if(player.getGameMode() != GameMode.CREATIVE){
|
||||||
|
mainHandItem.setAmount(mainHandItem.getAmount() - 1);
|
||||||
|
player.getInventory().addItem(new ItemStack(Material.BUCKET));
|
||||||
|
}
|
||||||
|
CustomBlock.remove(clickedBlockLocation);
|
||||||
|
CustomBlock.place(config.getString("config.watered-pot"),clickedBlockLocation);
|
||||||
|
} else if (mainHandItem.getType() == Material.WOODEN_SWORD){
|
||||||
|
waterPot(mainHandItem, player,clickedBlockLocation, config);
|
||||||
|
} else {
|
||||||
|
tryPlantSeed(clickedBlockLocation, mainHandItem, player, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//检测右键的方块是否为湿润的种植盆方块
|
||||||
|
else if(namespacedId.equalsIgnoreCase(config.getString("config.watered-pot"))){
|
||||||
|
tryPlantSeed(clickedBlockLocation, mainHandItem, player, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//尝试种植植物
|
//尝试种植植物
|
||||||
private void tryPlantSeed(Location clickedBlockLocation, ItemStack mainHandItem, Player player, FileConfiguration config) {
|
private void tryPlantSeed(Location clickedBlockLocation, ItemStack mainHandItem, Player player, FileConfiguration config) {
|
||||||
|
//是否为IA物品
|
||||||
if(CustomStack.byItemStack(mainHandItem) == null) return;
|
if(CustomStack.byItemStack(mainHandItem) == null) return;
|
||||||
if (CustomStack.byItemStack(mainHandItem).getNamespacedID().toLowerCase().endsWith("_seeds")){
|
//获取命名空间名与ID
|
||||||
String namespaced_id = CustomStack.byItemStack(mainHandItem).getNamespacedID().toLowerCase();
|
String namespaced_id = CustomStack.byItemStack(mainHandItem).getNamespacedID();
|
||||||
String[] crop = CustomStack.byItemStack(mainHandItem).getNamespacedID().toLowerCase().replace("_seeds","").split(":");
|
//是否为种子
|
||||||
|
if (namespaced_id.endsWith("_seeds")){
|
||||||
|
//获取农作物名
|
||||||
|
String cropName = StringUtils.split(namespaced_id.replace("_seeds",""),":")[1];
|
||||||
|
//String[] crop = CustomStack.byItemStack(mainHandItem).getNamespacedID().toLowerCase().replace("_seeds","").split(":");
|
||||||
//该种子是否存在于配置文件中
|
//该种子是否存在于配置文件中
|
||||||
if(!config.getConfigurationSection("crops").getKeys(false).contains(crop[1])){
|
if(!config.getConfigurationSection("crops").getKeys(false).contains(cropName)){
|
||||||
MessageManager.playerMessage(config.getString("messages.prefix")+config.getString("messages.no-such-seed"),player);
|
MessageManager.playerMessage(config.getString("messages.prefix")+config.getString("messages.no-such-seed"),player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//检测上方为空气
|
||||||
|
if(clickedBlockLocation.getWorld().getBlockAt(clickedBlockLocation.clone().add(0, 1, 0)).getType() != Material.AIR){
|
||||||
|
return;
|
||||||
|
}
|
||||||
//是否超高超低
|
//是否超高超低
|
||||||
if (clickedBlockLocation.getY() < config.getInt("config.height.min") || clickedBlockLocation.getY() > config.getInt("config.height.max")){
|
if (clickedBlockLocation.getY() < config.getInt("config.height.min") || clickedBlockLocation.getY() > config.getInt("config.height.max")){
|
||||||
MessageManager.playerMessage(config.getString("messages.prefix") + config.getString("messages.not-a-good-place"),player);
|
MessageManager.playerMessage(config.getString("messages.prefix") + config.getString("messages.not-a-good-place"),player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Location locUp = clickedBlockLocation.clone().add(0,1,0);
|
||||||
//是否启用了季节
|
//是否启用了季节
|
||||||
Label_out:
|
Label_out:
|
||||||
if(config.getBoolean("enable-season")){
|
if(config.getBoolean("enable-season")){
|
||||||
if(config.getBoolean("config.enable-greenhouse")){
|
if(config.getBoolean("config.enable-greenhouse")){
|
||||||
|
World world = player.getWorld();
|
||||||
for(int i = 1; i <= config.getInt("config.greenhouse-range"); i++){
|
for(int i = 1; i <= config.getInt("config.greenhouse-range"); i++){
|
||||||
Location tempLocation = clickedBlockLocation.clone().add(0,i+1,0);
|
Location tempLocation = locUp.clone().add(0,i,0);
|
||||||
if (CustomBlock.byAlreadyPlaced(clickedBlockLocation.getWorld().getBlockAt(tempLocation)) != null){
|
if (CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)) != null){
|
||||||
if(CustomBlock.byAlreadyPlaced(clickedBlockLocation.getWorld().getBlockAt(tempLocation)).getNamespacedID().equalsIgnoreCase(config.getString("config.greenhouse-glass"))){
|
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLocation)).getNamespacedID().equalsIgnoreCase(config.getString("config.greenhouse-glass"))){
|
||||||
break Label_out;
|
break Label_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String[] seasons = config.getString("crops."+crop[1]+".season").split(",");
|
//获取种子适宜生长的季节
|
||||||
|
String[] seasons = config.getString("crops."+cropName+".season").split(",");
|
||||||
boolean wrongSeason = true;
|
boolean wrongSeason = true;
|
||||||
for(String season : seasons){
|
for(String season : seasons){
|
||||||
if(Objects.equals(season, config.getString("current-season"))){
|
if(Objects.equals(season, config.getString("current-season"))){
|
||||||
@@ -207,50 +241,58 @@ public class RightClickCustomBlock implements Listener {
|
|||||||
}
|
}
|
||||||
//添加到缓存中
|
//添加到缓存中
|
||||||
if(config.getBoolean("enable-season")){
|
if(config.getBoolean("enable-season")){
|
||||||
CropManager.putInstance(clickedBlockLocation.clone().add(0,1,0), config.getString("crops."+crop[1]+".season"));
|
CropManager.putInstance(locUp, config.getString("crops."+cropName+".season"));
|
||||||
}else{
|
}else{
|
||||||
CropManager.putInstance(clickedBlockLocation.clone().add(0,1,0), "all");
|
CropManager.putInstance(locUp, "all");
|
||||||
}
|
}
|
||||||
//减少种子数量
|
//减少种子数量
|
||||||
if(player.getGameMode() != GameMode.CREATIVE){
|
if(player.getGameMode() != GameMode.CREATIVE){
|
||||||
mainHandItem.setAmount(mainHandItem.getAmount() -1);
|
mainHandItem.setAmount(mainHandItem.getAmount() -1);
|
||||||
}
|
}
|
||||||
//放置自定义农作物
|
//放置自定义农作物
|
||||||
CustomBlock.place(namespaced_id.replace("_seeds","_stage_1"),clickedBlockLocation.clone().add(0,1,0));
|
CustomBlock.place(namespaced_id.replace("_seeds","_stage_1"),locUp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void waterPot(ItemStack itemStack, Player player, Location location, FileConfiguration config){
|
private void waterPot(ItemStack itemStack, Player player, Location location, FileConfiguration config){
|
||||||
|
//是否为IA物品
|
||||||
if(CustomStack.byItemStack(itemStack) == null) return;
|
if(CustomStack.byItemStack(itemStack) == null) return;
|
||||||
|
|
||||||
CustomStack customStack = CustomStack.byItemStack(itemStack);
|
BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||||
|
|
||||||
if(customStack.getDurability() > 0){
|
bukkitScheduler.runTaskAsynchronously(CustomCrops.instance,()-> {
|
||||||
CustomStack.byItemStack(itemStack).setDurability(CustomStack.byItemStack(itemStack).getDurability() - 1);
|
//获取IA物品
|
||||||
}else return;
|
CustomStack customStack = CustomStack.byItemStack(itemStack);
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.instance,()-> {
|
String namespacedId = customStack.getNamespacedID();
|
||||||
|
World world = player.getWorld();
|
||||||
|
|
||||||
int x;
|
int x;
|
||||||
int z;
|
int z;
|
||||||
|
|
||||||
if (customStack.getNamespacedID().equalsIgnoreCase(config.getString("config.watering-can-1"))) {
|
if (namespacedId.equalsIgnoreCase(config.getString("config.watering-can-1"))) {
|
||||||
x = 0;
|
x = 0;
|
||||||
z = 0;
|
z = 0;
|
||||||
} else if (customStack.getNamespacedID().equalsIgnoreCase(config.getString("config.watering-can-2"))) {
|
} else if (namespacedId.equalsIgnoreCase(config.getString("config.watering-can-2"))) {
|
||||||
x = 2;
|
x = 2;
|
||||||
z = 2;
|
z = 2;
|
||||||
} else if (customStack.getNamespacedID().equalsIgnoreCase(config.getString("config.watering-can-3"))) {
|
} else if (namespacedId.equalsIgnoreCase(config.getString("config.watering-can-3"))) {
|
||||||
x = 4;
|
x = 4;
|
||||||
z = 4;
|
z = 4;
|
||||||
} else return;
|
} else return;
|
||||||
/*
|
//虽Who cares一点水呢?
|
||||||
-45 < yaw < 45 z+
|
if(customStack.getDurability() > 0){
|
||||||
-135 < yaw < -45 x+
|
CustomStack.byItemStack(itemStack).setDurability(CustomStack.byItemStack(itemStack).getDurability() - 1);
|
||||||
45 < yaw < 135 x-
|
}else return;
|
||||||
else z-
|
//播放洒水音效
|
||||||
*/
|
|
||||||
player.getWorld().playSound(player.getLocation(),Sound.BLOCK_WATER_AMBIENT,1,1);
|
world.playSound(player.getLocation(),Sound.BLOCK_WATER_AMBIENT,1,1);
|
||||||
|
//获取玩家朝向
|
||||||
float yaw = player.getLocation().getYaw();
|
float yaw = player.getLocation().getYaw();
|
||||||
|
|
||||||
|
//提前获取ID与命名空间,以免for循环循环get
|
||||||
|
String wateredPot = config.getString("config.watered-pot");
|
||||||
|
String pot = config.getString("config.pot");
|
||||||
|
|
||||||
|
//根据朝向确定浇水方向
|
||||||
if (yaw <= 45 && yaw >= -135) {
|
if (yaw <= 45 && yaw >= -135) {
|
||||||
if (yaw > -45) {
|
if (yaw > -45) {
|
||||||
x = 0;
|
x = 0;
|
||||||
@@ -260,7 +302,16 @@ public class RightClickCustomBlock implements Listener {
|
|||||||
for (int i = 0; i <= x; i++) {
|
for (int i = 0; i <= x; i++) {
|
||||||
for (int j = 0; j <= z; j++) {
|
for (int j = 0; j <= z; j++) {
|
||||||
Location tempLoc = location.clone().add(i, 0, j);
|
Location tempLoc = location.clone().add(i, 0, j);
|
||||||
canWaterPot(tempLoc,config);
|
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLoc)) != null){
|
||||||
|
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLoc)).getNamespacedID().equalsIgnoreCase(pot)){
|
||||||
|
//同步替换方块
|
||||||
|
bukkitScheduler.callSyncMethod(CustomCrops.instance,()->{
|
||||||
|
CustomBlock.remove(tempLoc);
|
||||||
|
CustomBlock.place(wateredPot,tempLoc);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -272,21 +323,19 @@ public class RightClickCustomBlock implements Listener {
|
|||||||
for (int i = 0; i <= x; i++) {
|
for (int i = 0; i <= x; i++) {
|
||||||
for (int j = 0; j <= z; j++) {
|
for (int j = 0; j <= z; j++) {
|
||||||
Location tempLoc = location.clone().subtract(i, 0, j);
|
Location tempLoc = location.clone().subtract(i, 0, j);
|
||||||
canWaterPot(tempLoc,config);
|
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLoc)) != null){
|
||||||
|
if(CustomBlock.byAlreadyPlaced(world.getBlockAt(tempLoc)).getNamespacedID().equalsIgnoreCase(pot)){
|
||||||
|
//同步替换方块
|
||||||
|
bukkitScheduler.callSyncMethod(CustomCrops.instance,()->{
|
||||||
|
CustomBlock.remove(tempLoc);
|
||||||
|
CustomBlock.place(wateredPot,tempLoc);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private void canWaterPot(Location location, FileConfiguration config){
|
|
||||||
if(CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(location)) != null){
|
|
||||||
if(CustomBlock.byAlreadyPlaced(location.getWorld().getBlockAt(location)).getNamespacedID().equalsIgnoreCase(config.getString("config.pot"))){
|
|
||||||
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance,()->{
|
|
||||||
CustomBlock.remove(location);
|
|
||||||
CustomBlock.place(config.getString("config.watered-pot"),location);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,23 +12,23 @@ current-season: spring
|
|||||||
config:
|
config:
|
||||||
# ######################
|
# ######################
|
||||||
# 基础设置 #
|
# 基础设置 #
|
||||||
|
# 重启服务器生效 #
|
||||||
# ######################
|
# ######################
|
||||||
# 植物生长的可能时间点,你可以在一天设置多个时间点判断生长
|
# 植物生长的可能时间点,你可以在一天设置多个时间点判断生长
|
||||||
# 为了防止植物生长过快你可以适当调低生长一个阶段的概率
|
# 为了防止植物生长过快你可以适当调低生长一个阶段的概率
|
||||||
# 你设置的时间节点越多,则服务器计算量也越大
|
# 你设置的时间节点越多,则服务器计算量也越大
|
||||||
# 请尽量在植物生长后200ticks以上设置洒水器工作点,如果生长和洒水时间靠太近可能会带来一些不必要的麻烦
|
# 请尽量在植物生长后200ticks以上设置洒水器工作点,如果生长和洒水时间靠太近可能会带来一些不必要的麻烦(例如数据太多,植物还没来得及生长完洒水器就开始工作)
|
||||||
# mc的时间范围为0-23999ticks,1秒=20ticks
|
# mc的时间范围为0-23999ticks,1秒=20ticks
|
||||||
# 你可以设置的时间范围为0-23899ticks(需要预留100tick)
|
|
||||||
# 此设置需要重启服务器生效!
|
|
||||||
|
|
||||||
# 生长时间点
|
# 生长时间点
|
||||||
grow-time:
|
grow-time:
|
||||||
- 0
|
- 0
|
||||||
# - 12000
|
# - 12000
|
||||||
|
|
||||||
# 洒水器工作点
|
# 洒水器工作点
|
||||||
sprinkler-time:
|
sprinkler-time:
|
||||||
- 200
|
- 200
|
||||||
# - 12200
|
# - 12200
|
||||||
|
|
||||||
# 生长生效的世界
|
# 生长生效的世界
|
||||||
whitelist-worlds:
|
whitelist-worlds:
|
||||||
@@ -80,11 +80,11 @@ config:
|
|||||||
greenhouse-glass: customcrops:greenhouse_glass
|
greenhouse-glass: customcrops:greenhouse_glass
|
||||||
# 洒水器的家具
|
# 洒水器的家具
|
||||||
sprinkler-1: customcrops:sprinkler_1
|
sprinkler-1: customcrops:sprinkler_1
|
||||||
# 洒水器的方块的物品
|
# 洒水器的方块的物品(请以_item结尾)
|
||||||
sprinkler-1-item: customcrops:sprinkler_1_item
|
sprinkler-1-item: customcrops:sprinkler_1_item
|
||||||
# 优质洒水器的家具
|
# 优质洒水器的家具
|
||||||
sprinkler-2: customcrops:sprinkler_2
|
sprinkler-2: customcrops:sprinkler_2
|
||||||
# 优质洒水器的方块的物品
|
# 优质洒水器的方块的物品(请以_item结尾)
|
||||||
sprinkler-2-item: customcrops:sprinkler_2_item
|
sprinkler-2-item: customcrops:sprinkler_2_item
|
||||||
# 农作物枯萎后变成的方块,物品ID中请保留stage以保持其下方方块被破坏时,枯萎作物也被破坏的特性
|
# 农作物枯萎后变成的方块,物品ID中请保留stage以保持其下方方块被破坏时,枯萎作物也被破坏的特性
|
||||||
dead-crop: customcrops:crop_stage_death
|
dead-crop: customcrops:crop_stage_death
|
||||||
@@ -106,6 +106,7 @@ config:
|
|||||||
|
|
||||||
# ######################
|
# ######################
|
||||||
# 插件兼容 #
|
# 插件兼容 #
|
||||||
|
# 重启服务器生效 #
|
||||||
# ######################
|
# ######################
|
||||||
integration:
|
integration:
|
||||||
# 收获权限为harvest 浇水种植权限为build
|
# 收获权限为harvest 浇水种植权限为build
|
||||||
@@ -147,7 +148,7 @@ messages:
|
|||||||
# ######################
|
# ######################
|
||||||
crops:
|
crops:
|
||||||
tomato:
|
tomato:
|
||||||
# 在IA配置文件中命名农作物时请以_seeds和_stage_X结尾,否则会报错
|
# 在IA配置文件中命名农作物时请以_seeds和_stage_X结尾,否则会无法生长和种植
|
||||||
# 适宜的生长季节,若未启用季节系统可以无视此项目
|
# 适宜的生长季节,若未启用季节系统可以无视此项目
|
||||||
season: spring,summer
|
season: spring,summer
|
||||||
# 空手收获后返回第几个生长状态
|
# 空手收获后返回第几个生长状态
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: CustomCrops
|
name: CustomCrops
|
||||||
version: '1.2.4'
|
version: '1.2.7'
|
||||||
main: net.momirealms.customcrops.CustomCrops
|
main: net.momirealms.customcrops.CustomCrops
|
||||||
api-version: 1.16
|
api-version: 1.16
|
||||||
depend: [ ItemsAdder , ProtocolLib ]
|
depend: [ ItemsAdder , ProtocolLib ]
|
||||||
|
|||||||
Reference in New Issue
Block a user