9
0
mirror of https://github.com/Xiao-MoMi/Custom-Crops.git synced 2025-12-22 16:39:36 +00:00

1.5.19-PRE1

This commit is contained in:
Xiao-MoMi
2022-07-29 23:57:43 +08:00
parent e6b8523a3b
commit 4f348fc884
41 changed files with 427 additions and 1577 deletions

View File

@@ -336,7 +336,7 @@ public class ConfigReader {
}
});
}
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><white>" + SPRINKLERS.size()/2 + "<color:#FFEBCD> srpinklers loaded!");
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><white>" + SPRINKLERS.size()/2 + "<color:#FFEBCD> sprinklers loaded!");
}
}
@@ -505,10 +505,22 @@ public class ConfigReader {
});
cropInstance.setRequirements(requirements);
}
if (config.contains("crops." + key + ".grow-chance")){
cropInstance.setGrowChance(config.getDouble("crops." + key + ".grow-chance"));
}else {
cropInstance.setGrowChance(1);
}
if (Config.quality){
cropInstance.setQuality_1(config.getString("crops." + key + ".quality.1"));
cropInstance.setQuality_2(config.getString("crops." + key + ".quality.2"));
cropInstance.setQuality_3(config.getString("crops." + key + ".quality.3"));
if (config.contains("crops." + key + ".drop-ia-loots")){
cropInstance.setDropIALoot(config.getBoolean("crops." + key + ".drop-ia-loots"));
}else {
cropInstance.setDropIALoot(false);
}
}else {
cropInstance.setDropIALoot(false);
}
CROPS.put(key, cropInstance);
});

View File

@@ -42,11 +42,18 @@ public final class CustomCrops extends JavaPlugin {
public static JavaPlugin instance;
public static BukkitAudiences adventure;
private CropTimer cropTimer;
private CropManager cropManager;
private SprinklerManager sprinklerManager;
private SeasonManager seasonManager;
private PotManager potManager;
private Placeholders placeholders;
public CropManager getCropManager() { return this.cropManager; }
public SprinklerManager getSprinklerManager() { return sprinklerManager; }
public SeasonManager getSeasonManager() { return seasonManager; }
public PotManager getPotManager() { return potManager; }
@Override
public void onEnable() {
@@ -56,40 +63,83 @@ public final class CustomCrops extends JavaPlugin {
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#FFEBCD>Running on " + Bukkit.getVersion());
//加载配置文件
ConfigReader.ReloadConfig();
//PAPI
if(Bukkit.getPluginManager().getPlugin("PlaceHolderAPI") != null){
new Placeholders().register();
placeholders = new Placeholders();
placeholders.register();
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><gold>PlaceHolderAPI <color:#FFEBCD>Hooked!");
}
//指令注册
Objects.requireNonNull(Bukkit.getPluginCommand("customcrops")).setExecutor(new Executor(this));
Objects.requireNonNull(Bukkit.getPluginCommand("customcrops")).setTabCompleter(new Completer());
//注册事件
Bukkit.getPluginManager().registerEvents(new ItemSpawn(), this);
Bukkit.getPluginManager().registerEvents(new RightClick(), this);
Bukkit.getPluginManager().registerEvents(new BreakBlock(), this);
Bukkit.getPluginManager().registerEvents(new InteractEntity(this), this);
//开始计时器
this.cropTimer = new CropTimer(this);
//载入数据
if (ConfigReader.Season.enable){
this.seasonManager = new SeasonManager(this);
this.seasonManager = new SeasonManager();
this.seasonManager.loadData();
}
this.cropManager = new CropManager(this);
this.cropManager = new CropManager();
this.cropManager.loadData();
this.sprinklerManager = new SprinklerManager(this);
this.sprinklerManager = new SprinklerManager();
this.sprinklerManager.loadData();
this.potManager = new PotManager(this);
this.potManager = new PotManager();
this.potManager.loadData();
this.cropTimer = new CropTimer(this);
checkIAConfig();
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>Plugin Enabled!");
}
@Override
public void onDisable() {
HoloUtil.cache.keySet().forEach(location -> HoloUtil.cache.get(location).remove());
if (this.cropManager != null){
this.cropManager.cleanData();
this.cropManager.saveData();
this.cropManager = null;
}
if (this.potManager != null){
this.potManager.saveData();
this.potManager = null;
}
if (this.sprinklerManager != null){
this.sprinklerManager.cleanData();
this.sprinklerManager.saveData();
this.sprinklerManager = null;
}
if (ConfigReader.Season.enable && !ConfigReader.Season.seasonChange && this.seasonManager != null){
this.seasonManager.saveData();
this.seasonManager = null;
}
if (this.placeholders != null){
placeholders.unregister();
placeholders = null;
}
getLogger().info("Backing Up...");
BackUp.backUpData();
getLogger().info("Done.");
if (cropTimer != null) {
this.cropTimer.stopTimer(cropTimer.getTaskID());
}
if (adventure != null) {
adventure.close();
}
if (instance != null) {
instance = null;
}
}
private void checkIAConfig(){
FileConfiguration fileConfiguration = Bukkit.getPluginManager().getPlugin("ItemsAdder").getConfig();
if (fileConfiguration.getBoolean("blocks.disable-REAL_WIRE")){
fileConfiguration.set("blocks.disable-REAL_WIRE", false);
@@ -100,46 +150,6 @@ public final class CustomCrops extends JavaPlugin {
}
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><red>Detected that you might have not set \"disable-REAL_WIRE\" false in ItemsAdder's config!");
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><red>You need a restart to apply that config :)");
}else {
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>Plugin Enabled!");
}
}
@Override
public void onDisable() {
//保存数据
this.cropManager.cleanData();
this.cropManager.saveData();
this.sprinklerManager.cleanData();
this.sprinklerManager.saveData();
this.potManager.saveData();
if (ConfigReader.Season.enable && !ConfigReader.Season.seasonChange){
this.seasonManager.saveData();
}
//备份数据
getLogger().info("Back Up...");
BackUp.backUpData();
getLogger().info("Done.");
//清除悬浮展示实体
HoloUtil.cache.keySet().forEach(location -> {
HoloUtil.cache.get(location).remove();
});
//关闭计时器
if (cropTimer != null) {
this.cropTimer.stopTimer(cropTimer.getTaskID());
}
if (adventure != null) {
adventure.close();
}
}
public CropManager getCropManager() { return this.cropManager; }
public SprinklerManager getSprinklerManager() { return sprinklerManager; }
public SeasonManager getSeasonManager() { return seasonManager; }
public PotManager getPotManager() { return potManager; }
}

View File

@@ -40,12 +40,12 @@ public class Executor implements CommandExecutor {
@Override
@ParametersAreNonnullByDefault
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
//权限不足
if (!(sender.hasPermission("customcrops.admin") || sender.isOp())){
AdventureManager.playerMessage((Player) sender, ConfigReader.Message.prefix + ConfigReader.Message.noPerm);
return true;
}
//参数不足
if (args.length < 1) {
lackArgs(sender);
return true;
@@ -182,6 +182,10 @@ public class Executor implements CommandExecutor {
return true;
}
/**
* 缺少参数的提示语
* @param sender 发送者
*/
private void lackArgs(CommandSender sender){
if (sender instanceof Player){
AdventureManager.playerMessage((Player) sender,ConfigReader.Message.prefix + ConfigReader.Message.lackArgs);
@@ -190,6 +194,10 @@ public class Executor implements CommandExecutor {
}
}
/**
* 强制保存的提示语
* @param sender 发送者
*/
private void forceSave(CommandSender sender){
if (sender instanceof Player player){
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.forceSave);

View File

@@ -45,16 +45,16 @@ import java.util.concurrent.ConcurrentHashMap;
public class CropManager {
private YamlConfiguration data;
private final CustomCrops plugin;
public static ConcurrentHashMap<Location, String> Cache = new ConcurrentHashMap<>();
private BukkitScheduler bukkitScheduler;
private final BukkitScheduler bukkitScheduler;
public CropManager(CustomCrops plugin){
this.plugin = plugin;
public CropManager(){
this.bukkitScheduler = Bukkit.getScheduler();
}
//载入数据
/**
* 载入数据
*/
public void loadData() {
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "crop.yml");
if(!file.exists()){
@@ -69,7 +69,9 @@ public class CropManager {
this.data = YamlConfiguration.loadConfiguration(file);
}
//保存数据
/**
* 保存数据
*/
public void saveData() {
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "crop.yml");
try{
@@ -80,7 +82,9 @@ public class CropManager {
}
}
//将缓存内新数据更新到data内
/**
* 将hashmap中的数据保存到data中
*/
public void updateData(){
Cache.forEach((location, String) -> {
int x = location.getBlockX();
@@ -90,7 +94,9 @@ public class CropManager {
Cache.clear();
}
//隐藏指令,清除无用数据
/**
* 清除无用数据
*/
public void cleanData(){
data.getKeys(false).forEach(world -> {
data.getConfigurationSection(world).getKeys(false).forEach(chunk ->{
@@ -101,7 +107,10 @@ public class CropManager {
});
}
//农作物生长
/**
* 农作物生长
* @param worldName 进行生长判定的世界名
*/
public void cropGrow(String worldName){
Long time1 = System.currentTimeMillis();
@@ -155,7 +164,7 @@ public class CropManager {
}
}
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
if (CustomBlock.getInstance(StringUtils.chop(namespacedID) + nextStage) != null) {
if (CustomBlock.getInstance(StringUtils.chop(namespacedID) + nextStage) != null && cropInstance.getGrowChance() > Math.random()) {
Fertilizer fertilizer = PotManager.Cache.get(SimpleLocation.fromLocation(potLocation));
if (fertilizer != null){
int times = fertilizer.getTimes();
@@ -229,7 +238,10 @@ public class CropManager {
}
}
//农作物生长
/**
* 全部世界农作物生长
* 对于使用动态加载世界的服务器有效
*/
public void cropGrowAll(){
Long time1 = System.currentTimeMillis();
updateData();
@@ -271,7 +283,6 @@ public class CropManager {
CropInstance cropInstance = ConfigReader.CROPS.get(cropNameList[0]);
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
if (potNamespacedID.equals(ConfigReader.Basic.watered_pot)){
//如果启用季节限制且农作物有季节需求
if (ConfigReader.Season.enable && cropInstance.getSeasons() != null){
if (isWrongSeason(seedLocation, cropInstance.getSeasons(), worldName)){
data.set(stringBuilder.toString(), null);
@@ -283,7 +294,7 @@ public class CropManager {
}
}
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
if (CustomBlock.getInstance(StringUtils.chop(namespacedID) + nextStage) != null) {
if (CustomBlock.getInstance(StringUtils.chop(namespacedID) + nextStage) != null && cropInstance.getGrowChance() > Math.random()) {
Fertilizer fertilizer = PotManager.Cache.get(SimpleLocation.fromLocation(potLocation));
if (fertilizer != null){
int times = fertilizer.getTimes();
@@ -358,6 +369,12 @@ public class CropManager {
}
}
/**
* 判定季节
* @param worldName 世界名
* @param seasons 农作物能生长的季节
* @param seedLocation 农作物的位置
*/
private boolean isWrongSeason(Location seedLocation, List<String> seasons, String worldName){
if(ConfigReader.Season.greenhouse){
for(int i = 1; i <= ConfigReader.Season.range; i++){
@@ -385,19 +402,36 @@ public class CropManager {
return true;
}
/**
* 生长一个阶段(消耗水)
* @param potLocation 种植盆位置
* @param seedLocation 农作物位置
* @param namespacedID 农作物下一阶段的ID
* @param nextStage 农作物下一阶段的阶段数
* @param random 随机生长时间
*/
private void addStage(Location potLocation, Location seedLocation, String namespacedID, int nextStage, int random){
String stage = StringUtils.chop(namespacedID) + nextStage;
bukkitScheduler.runTaskLater(CustomCrops.instance, () ->{
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
CustomBlock.remove(seedLocation);
CustomBlock.place(StringUtils.chop(namespacedID) + nextStage, seedLocation);
CustomBlock.place(stage, seedLocation);
}, random);
}
/**
* 生长一个阶段(不消耗水)
* @param seedLocation 农作物位置
* @param namespacedID 农作物下一阶段的ID
* @param nextStage 农作物下一阶段的阶段数
* @param random 随机生长时间
*/
private void addStage(Location seedLocation, String namespacedID, int nextStage, int random){
String stage = StringUtils.chop(namespacedID) + nextStage;
bukkitScheduler.runTaskLater(CustomCrops.instance, () ->{
CustomBlock.remove(seedLocation);
CustomBlock.place(StringUtils.chop(namespacedID) + nextStage, seedLocation);
CustomBlock.place(stage, seedLocation);
}, random);
}
}

View File

@@ -37,13 +37,11 @@ import java.util.concurrent.ConcurrentHashMap;
public class PotManager {
private CustomCrops plugin;
public static ConcurrentHashMap<SimpleLocation, Fertilizer> Cache = new ConcurrentHashMap<>();
public PotManager(CustomCrops plugin){
this.plugin = plugin;
}
/**
* 载入数据
*/
public void loadData(){
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "pot.yml");
if(!file.exists()){
@@ -65,13 +63,10 @@ public class PotManager {
if (fertilizer == null) return;
if (fertilizer instanceof SpeedGrow speedGrow){
Cache.put(new SimpleLocation(worldName, Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])), new SpeedGrow(name, (int) map.get("times"), speedGrow.getChance(), speedGrow.isBefore()));
//Cache.put(new Location(Bukkit.getWorld(worldName), Double.parseDouble(split[0]), Double.parseDouble(split[1]), Double.parseDouble(split[2])), new SpeedGrow(name, (int) map.get("times"), speedGrow.getChance(), speedGrow.isBefore()));
}else if (fertilizer instanceof QualityCrop qualityCrop){
Cache.put(new SimpleLocation(worldName, Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])), new QualityCrop(name, (int) map.get("times"), qualityCrop.getChance(), qualityCrop.isBefore()));
//Cache.put(new Location(Bukkit.getWorld(worldName), Double.parseDouble(split[0]), Double.parseDouble(split[1]), Double.parseDouble(split[2])), new QualityCrop(name, (int) map.get("times"), qualityCrop.getChance(), qualityCrop.isBefore()));
}else if (fertilizer instanceof RetainingSoil retainingSoil){
Cache.put(new SimpleLocation(worldName, Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])), new RetainingSoil(name, (int) map.get("times"), retainingSoil.getChance(), retainingSoil.isBefore()));
//Cache.put(new Location(Bukkit.getWorld(worldName), Double.parseDouble(split[0]), Double.parseDouble(split[1]), Double.parseDouble(split[2])), new RetainingSoil(name, (int) map.get("times"), retainingSoil.getChance(), retainingSoil.isBefore()));
}else {
AdventureManager.consoleMessage("<red>[CustomCrops] 未知肥料类型错误!</red>");
}
@@ -80,6 +75,9 @@ public class PotManager {
});
}
/**
* 保存数据
*/
public void saveData(){
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "pot.yml");
YamlConfiguration data = new YamlConfiguration();

View File

@@ -30,10 +30,14 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
public record SeasonManager(CustomCrops plugin) {
public class SeasonManager{
public static HashMap<String, String> SEASON = new HashMap<>();
/**
* 读取文件中的季节
* @param file 季节数据文件
*/
private YamlConfiguration readData(File file) {
if (!file.exists()) {
try {
@@ -47,6 +51,9 @@ public record SeasonManager(CustomCrops plugin) {
return YamlConfiguration.loadConfiguration(file);
}
/**
* 载入数据
*/
public void loadData() {
SEASON.clear();
YamlConfiguration data = readData(new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "season.yml"));
@@ -68,8 +75,11 @@ public record SeasonManager(CustomCrops plugin) {
ConfigReader.Config.worlds.forEach(this::getSeason);
}
/**
* 计算某个世界的季节
* @param world 世界
*/
public void getSeason(World world) {
int season = (int) ((world.getFullTime() / 24000L) % (ConfigReader.Season.duration * 4)) / ConfigReader.Season.duration;
switch (season) {
case 0 -> SEASON.put(world.getName(), "spring");
@@ -80,6 +90,9 @@ public record SeasonManager(CustomCrops plugin) {
}
}
/**
* 保存数据
*/
public void saveData() {
SEASON.forEach((key, value) -> {
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "season.yml");
@@ -94,6 +107,11 @@ public record SeasonManager(CustomCrops plugin) {
});
}
/**
* 设置季节
* @param worldName 世界名
* @param season 季节
*/
public boolean setSeason(String worldName, String season){
if (!ConfigReader.Config.worldNames.contains(worldName)){
return false;

View File

@@ -39,13 +39,11 @@ import java.util.concurrent.ConcurrentHashMap;
public class SprinklerManager {
public YamlConfiguration data;
private final CustomCrops plugin;
public static ConcurrentHashMap<Location, Sprinkler> Cache = new ConcurrentHashMap<>();
public SprinklerManager(CustomCrops plugin){
this.plugin = plugin;
}
/**
* 载入数据
*/
public void loadData() {
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "sprinkler.yml");
if(!file.exists()){
@@ -60,6 +58,9 @@ public class SprinklerManager {
this.data = YamlConfiguration.loadConfiguration(file);
}
/**
* 保存数据
*/
public void saveData(){
File file = new File(CustomCrops.instance.getDataFolder(), "data" + File.separator + "sprinkler.yml");
try{
@@ -70,6 +71,9 @@ public class SprinklerManager {
}
}
/**
* 清理无用数据
*/
public void cleanData(){
data.getKeys(false).forEach(world -> {
data.getConfigurationSection(world).getKeys(false).forEach(chunk ->{
@@ -80,6 +84,9 @@ public class SprinklerManager {
});
}
/**
* 将hashmap中的数据保存到data中
*/
public void updateData(){
Cache.forEach((location, sprinklerData) -> {
String world = location.getWorld().getName();
@@ -92,6 +99,10 @@ public class SprinklerManager {
Cache.clear();
}
/**
* 指定世界的洒水器工作
* @param worldName 世界名
*/
public void sprinklerWork(String worldName){
Long time1 = System.currentTimeMillis();
updateData();
@@ -146,6 +157,9 @@ public class SprinklerManager {
}
}
/**
* 所有世界的洒水器工作
*/
public void sprinklerWorkAll(){
Long time1 = System.currentTimeMillis();
updateData();
@@ -202,6 +216,10 @@ public class SprinklerManager {
}
}
/**
* 转干为湿
* @param potLoc 种植盆的位置
*/
private void waterPot(Location potLoc) {
CustomBlock cb = CustomBlock.byAlreadyPlaced(potLoc.getBlock());
if(cb != null){

View File

@@ -33,43 +33,18 @@ public class QualityCrop implements Fertilizer{
}
@Override
public String getKey() {
return this.key;
}
public String getKey() {return this.key;}
@Override
public int getTimes() {
return this.times;
}
public int getTimes() {return this.times;}
@Override
public void setTimes(int times) {
this.times = times;
}
public void setTimes(int times) {this.times = times;}
@Override
public boolean isBefore() {
return this.before;
}
public boolean isBefore() {return this.before;}
@Override
public String getName() {
return this.name;
}
public String getName() {return this.name;}
public void setName(String name) {
this.name = name;
}
public void setChance(int[] chance) {
this.chance = chance;
}
public void setKey(String key) {
this.key = key;
}
public int[] getChance() {
return chance;
}
public void setName(String name) {this.name = name;}
public void setChance(int[] chance) {this.chance = chance;}
public void setKey(String key) {this.key = key;}
public int[] getChance() {return chance;}
}

View File

@@ -22,7 +22,7 @@ public class RetainingSoil implements Fertilizer{
private double chance;
private String key;
private int times;
private boolean before;
private final boolean before;
public String name;
public RetainingSoil(String key, int times, double chance, boolean before){
@@ -33,43 +33,18 @@ public class RetainingSoil implements Fertilizer{
}
@Override
public String getKey() {
return this.key;
}
public String getKey() {return this.key;}
@Override
public int getTimes() {
return this.times;
}
public int getTimes() {return this.times;}
@Override
public void setTimes(int times) {
this.times = times;
}
public void setTimes(int times) {this.times = times;}
@Override
public boolean isBefore() {
return this.before;
}
public boolean isBefore() {return this.before;}
@Override
public String getName() {
return this.name;
}
public String getName() {return this.name;}
public void setName(String name) {
this.name = name;
}
public void setChance(double chance) {
this.chance = chance;
}
public void setKey(String key) {
this.key = key;
}
public double getChance() {
return chance;
}
public void setName(String name) {this.name = name;}
public void setChance(double chance) {this.chance = chance;}
public void setKey(String key) {this.key = key;}
public double getChance() {return chance;}
}

View File

@@ -33,43 +33,18 @@ public class SpeedGrow implements Fertilizer{
}
@Override
public String getKey() {
return this.key;
}
public String getKey() {return this.key;}
@Override
public int getTimes() {
return this.times;
}
public int getTimes() {return this.times;}
@Override
public void setTimes(int times) {
this.times = times;
}
public void setTimes(int times) {this.times = times;}
@Override
public boolean isBefore() {
return this.before;
}
public boolean isBefore() {return this.before;}
@Override
public String getName() {
return this.name;
}
public String getName() {return this.name;}
public void setName(String name) {
this.name = name;
}
public double getChance() {
return chance;
}
public void setChance(double chance) {
this.chance = chance;
}
public void setKey(String key) {
this.key = key;
}
public void setName(String name) {this.name = name;}
public double getChance() {return chance;}
public void setChance(double chance) {this.chance = chance;}
public void setKey(String key) {this.key = key;}
}

View File

@@ -1,196 +0,0 @@
/*
* This file is part of helper, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.momirealms.customcrops.helper;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import net.momirealms.customcrops.CustomCrops;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.util.Objects;
/**
* Resolves {@link MavenLibrary} annotations for a class, and loads the dependency
* into the classloader.
*/
@NonnullByDefault
public final class LibraryLoader {
@SuppressWarnings("Guava")
private static final Supplier<URLClassLoaderAccess> URL_INJECTOR = Suppliers.memoize(() -> URLClassLoaderAccess.create((URLClassLoader) CustomCrops.instance.getClass().getClassLoader()));
/**
* Resolves all {@link MavenLibrary} annotations on the given object.
*
* @param object the object to load libraries for.
*/
public static void loadAll(Object object) {
loadAll(object.getClass());
}
/**
* Resolves all {@link MavenLibrary} annotations on the given class.
*
* @param clazz the class to load libraries for.
*/
public static void loadAll(Class<?> clazz) {
MavenLibrary[] libs = clazz.getDeclaredAnnotationsByType(MavenLibrary.class);
if (libs == null) {
return;
}
for (MavenLibrary lib : libs) {
load(lib.groupId(), lib.artifactId(), lib.version(), lib.repo().url());
}
}
public static void load(String groupId, String artifactId, String version, String repoUrl) {
load(new Dependency(groupId, artifactId, version, repoUrl));
}
public static void load(Dependency d) {
//Log.info(String.format("Loading dependency %s:%s:%s from %s", d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getRepoUrl()));
String name = d.getArtifactId() + "-" + d.getVersion();
File saveLocation = new File(getLibFolder(d), name + ".jar");
if (!saveLocation.exists()) {
try {
Log.info("Dependency '" + name + "' is not already in the libraries folder. Attempting to download...");
URL url = d.getUrl();
try (InputStream is = url.openStream()) {
Files.copy(is, saveLocation.toPath());
Log.info("Dependency '" + name + "' successfully downloaded.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (!saveLocation.exists()) {
throw new RuntimeException("Unable to download dependency: " + d.toString());
}
try {
URL_INJECTOR.get().addURL(saveLocation.toURI().toURL());
} catch (Exception e) {
throw new RuntimeException("Unable to load dependency: " + saveLocation.toString(), e);
}
}
private static File getLibFolder(Dependency dependency) {
File pluginDataFolder = CustomCrops.instance.getDataFolder();
File serverDir = pluginDataFolder.getParentFile().getParentFile();
File helperDir = new File(serverDir, "libraries");
String[] split = StringUtils.split(dependency.getGroupId(), ".");
File jarDir = new File(helperDir, split[0] + File.separator + split[1] + File.separator + dependency.artifactId + File.separator + dependency.version );
jarDir.mkdirs();
return jarDir;
}
@NonnullByDefault
public static final class Dependency {
private final String groupId;
private final String artifactId;
private final String version;
private final String repoUrl;
public Dependency(String groupId, String artifactId, String version, String repoUrl) {
this.groupId = Objects.requireNonNull(groupId, "groupId");
this.artifactId = Objects.requireNonNull(artifactId, "artifactId");
this.version = Objects.requireNonNull(version, "version");
this.repoUrl = Objects.requireNonNull(repoUrl, "repoUrl");
}
public String getGroupId() {
return this.groupId;
}
public String getArtifactId() {
return this.artifactId;
}
public String getVersion() {
return this.version;
}
public String getRepoUrl() {
return this.repoUrl;
}
public URL getUrl() throws MalformedURLException {
String repo = this.repoUrl;
if (!repo.endsWith("/")) {
repo += "/";
}
repo += "%s/%s/%s/%s-%s.jar";
String url = String.format(repo, this.groupId.replace(".", "/"), this.artifactId, this.version, this.artifactId, this.version);
return new URL(url);
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Dependency)) return false;
final Dependency other = (Dependency) o;
return this.getGroupId().equals(other.getGroupId()) &&
this.getArtifactId().equals(other.getArtifactId()) &&
this.getVersion().equals(other.getVersion()) &&
this.getRepoUrl().equals(other.getRepoUrl());
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.getGroupId().hashCode();
result = result * PRIME + this.getArtifactId().hashCode();
result = result * PRIME + this.getVersion().hashCode();
result = result * PRIME + this.getRepoUrl().hashCode();
return result;
}
@Override
public String toString() {
return "LibraryLoader.Dependency(" +
"groupId=" + this.getGroupId() + ", " +
"artifactId=" + this.getArtifactId() + ", " +
"version=" + this.getVersion() + ", " +
"repoUrl=" + this.getRepoUrl() + ")";
}
}
}

View File

@@ -1,64 +0,0 @@
/*
* This file is part of helper, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.momirealms.customcrops.helper;
import net.momirealms.customcrops.CustomCrops;
import org.bukkit.Bukkit;
import java.util.logging.Level;
import javax.annotation.Nonnull;
/**
* Utility for quickly accessing a logger instance without using {@link Bukkit#getLogger()}
*/
public final class Log {
public static void info(@Nonnull String s) {
CustomCrops.instance.getLogger().info(s);
}
public static void warn(@Nonnull String s) {
CustomCrops.instance.getLogger().warning(s);
}
public static void severe(@Nonnull String s) {
CustomCrops.instance.getLogger().severe(s);
}
public static void warn(@Nonnull String s, Throwable t) {
CustomCrops.instance.getLogger().log(Level.WARNING, s, t);
}
public static void severe(@Nonnull String s, Throwable t) {
CustomCrops.instance.getLogger().log(Level.SEVERE, s, t);
}
private Log() {
throw new UnsupportedOperationException("This class cannot be instantiated");
}
}

View File

@@ -1,47 +0,0 @@
/*
* This file is part of helper, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.momirealms.customcrops.helper;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
/**
* Annotation to indicate the required libraries for a class.
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MavenLibraries {
@Nonnull
MavenLibrary[] value() default {};
}

View File

@@ -1,78 +0,0 @@
/*
* This file is part of helper, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.momirealms.customcrops.helper;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
/**
* Annotation to indicate a required library for a class.
*/
@Documented
@Repeatable(MavenLibraries.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MavenLibrary {
/**
* The group id of the library
*
* @return the group id of the library
*/
@Nonnull
String groupId();
/**
* The artifact id of the library
*
* @return the artifact id of the library
*/
@Nonnull
String artifactId();
/**
* The version of the library
*
* @return the version of the library
*/
@Nonnull
String version();
/**
* The repo where the library can be obtained from
*
* @return the repo where the library can be obtained from
*/
@Nonnull
Repository repo() default @Repository(url = "https://repo1.maven.org/maven2");
}

View File

@@ -1,46 +0,0 @@
/*
* This file is part of helper, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.momirealms.customcrops.helper;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
@Nonnull
@Documented
@TypeQualifierDefault({
ElementType.FIELD,
ElementType.METHOD,
ElementType.PARAMETER
})
@Retention(RetentionPolicy.RUNTIME)
public @interface NonnullByDefault {
}

View File

@@ -1,52 +0,0 @@
/*
* This file is part of helper, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.momirealms.customcrops.helper;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
/**
* Represents a maven repository.
*/
@Documented
@Target(ElementType.LOCAL_VARIABLE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Repository {
/**
* Gets the base url of the repository.
*
* @return the base url of the repository
*/
@Nonnull
String url();
}

View File

@@ -1,139 +0,0 @@
/*
* This file is part of helper, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.momirealms.customcrops.helper;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import javax.annotation.Nonnull;
/**
* Provides access to {@link URLClassLoader}#addURL.
*/
public abstract class URLClassLoaderAccess {
/**
* Creates a {@link URLClassLoaderAccess} for the given class loader.
*
* @param classLoader the class loader
* @return the access object
*/
static URLClassLoaderAccess create(URLClassLoader classLoader) {
if (Unsafe.isSupported()) {
return new Unsafe(classLoader);
} else {
return Noop.INSTANCE;
}
}
private final URLClassLoader classLoader;
protected URLClassLoaderAccess(URLClassLoader classLoader) {
this.classLoader = classLoader;
}
/**
* Adds the given URL to the class loader.
*
* @param url the URL to add
*/
public abstract void addURL(@Nonnull URL url);
/**
* Accesses using sun.misc.Unsafe, supported on Java 9+.
*
* @author Vaishnav Anil (https://github.com/slimjar/slimjar)
*/
private static class Unsafe extends URLClassLoaderAccess {
private static final sun.misc.Unsafe UNSAFE;
static {
sun.misc.Unsafe unsafe;
try {
Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
unsafe = (sun.misc.Unsafe) unsafeField.get(null);
} catch (Throwable t) {
unsafe = null;
}
UNSAFE = unsafe;
}
private static boolean isSupported() {
return UNSAFE != null;
}
private final Collection<URL> unopenedURLs;
private final Collection<URL> pathURLs;
@SuppressWarnings("unchecked")
Unsafe(URLClassLoader classLoader) {
super(classLoader);
Collection<URL> unopenedURLs;
Collection<URL> pathURLs;
try {
Object ucp = fetchField(URLClassLoader.class, classLoader, "ucp");
unopenedURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "unopenedUrls");
pathURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "path");
} catch (Throwable e) {
unopenedURLs = null;
pathURLs = null;
}
this.unopenedURLs = unopenedURLs;
this.pathURLs = pathURLs;
}
private static Object fetchField(final Class<?> clazz, final Object object, final String name) throws NoSuchFieldException {
Field field = clazz.getDeclaredField(name);
long offset = UNSAFE.objectFieldOffset(field);
return UNSAFE.getObject(object, offset);
}
@Override
public void addURL(@Nonnull URL url) {
this.unopenedURLs.add(url);
this.pathURLs.add(url);
}
}
private static class Noop extends URLClassLoaderAccess {
private static final Noop INSTANCE = new Noop();
private Noop() {
super(null);
}
@Override
public void addURL(@Nonnull URL url) {
throw new UnsupportedOperationException();
}
}
}

View File

@@ -1,3 +1,20 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.integrations.skill;
import com.archyx.aureliumskills.api.AureliumAPI;

View File

@@ -1,3 +1,20 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.integrations.skill;
import net.Indyuce.mmocore.experience.EXPSource;

View File

@@ -1,7 +1,24 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.integrations.skill;
import org.bukkit.entity.Player;
public interface SkillXP {
void addXp(Player player, double amount);
}
}

View File

@@ -1,3 +1,20 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.integrations.skill;
import com.gmail.nossr50.api.ExperienceAPI;

View File

@@ -115,7 +115,6 @@ public class BreakBlock implements Listener {
normalDrop(cropInstance, random, itemLoc, world);
return null;
});
}
} else {
Bukkit.getScheduler().callSyncMethod(CustomCrops.instance, ()-> {
@@ -124,7 +123,6 @@ public class BreakBlock implements Listener {
});
}
});
}
}
else if(namespacedId.equalsIgnoreCase(ConfigReader.Basic.watered_pot) || namespacedId.equalsIgnoreCase(ConfigReader.Basic.pot)){
@@ -138,9 +136,8 @@ public class BreakBlock implements Listener {
if(CustomBlock.byAlreadyPlaced(blockUp) != null){
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(blockUp);
String cropNamespacedId = customBlock.getNamespacedID();
if(cropNamespacedId.contains("_stage_")){
if(cropNamespacedId.contains("_stage_") && !cropNamespacedId.equals(ConfigReader.Basic.dead)){
CustomBlock.remove(location);
if (cropNamespacedId.equals(ConfigReader.Basic.dead)) return;
if (ConfigReader.Config.quality){
String[] cropNameList = StringUtils.split(StringUtils.split(cropNamespacedId, ":")[1], "_");
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
@@ -183,6 +180,13 @@ public class BreakBlock implements Listener {
}
}
/**
* 没有品质肥料下的普通掉落
* @param cropInstance 农作物
* @param random 随机农作物数量
* @param itemLoc 掉落物位置
* @param world 世界
*/
static void normalDrop(CropInstance cropInstance, int random, Location itemLoc, World world) {
for (int i = 0; i < random; i++){
double ran = Math.random();

View File

@@ -31,7 +31,6 @@ import net.momirealms.customcrops.utils.Sprinkler;
import net.momirealms.customcrops.utils.WateringCan;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@@ -160,6 +159,15 @@ public class InteractEntity implements Listener {
}
}
/**
* 获取某个洒水器的水量
* @param location 洒水器位置
* @param world 世界
* @param x 坐标
* @param z 坐标
* @param sprinkler 洒水器类型
* @return 水量
*/
private int getCurrentWater(Location location, String world, int x, int z, Sprinkler sprinkler) {
int currentWater;
if (sprinkler != null){

View File

@@ -70,8 +70,7 @@ public class RightClick implements Listener {
Action action = event.getAction();
if (action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK){
ItemStack itemStack = event.getItem();
if (itemStack != null){
if (itemStack.getType() == Material.AIR) return;
if (itemStack != null && itemStack.getType() != Material.AIR){
NBTItem nbtItem = new NBTItem(itemStack);
NBTCompound nbtCompound = nbtItem.getCompound("itemsadder");
if (nbtCompound != null){
@@ -145,9 +144,8 @@ public class RightClick implements Listener {
}
return;
}
Optional<WateringCan> can = Optional.ofNullable(ConfigReader.CANS.get(id));
if (can.isPresent()){
WateringCan wateringCan = can.get();
WateringCan wateringCan = ConfigReader.CANS.get(id);
if (wateringCan != null){
int water = nbtItem.getInteger("WaterAmount");
List<Block> lineOfSight = player.getLineOfSight(null, 5);
for (Block block : lineOfSight) {
@@ -226,9 +224,8 @@ public class RightClick implements Listener {
}
return;
}
Optional<Fertilizer> fertilize = Optional.ofNullable(ConfigReader.FERTILIZERS.get(id));
if (fertilize.isPresent() && action == Action.RIGHT_CLICK_BLOCK){
Fertilizer fertilizerConfig = fertilize.get();
Fertilizer fertilizerConfig = ConfigReader.FERTILIZERS.get(id);
if (fertilizerConfig != null && action == Action.RIGHT_CLICK_BLOCK){
Block block = event.getClickedBlock();
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
if (customBlock == null) return;
@@ -264,8 +261,8 @@ public class RightClick implements Listener {
}
return;
}
Optional<Sprinkler> sprinkler = Optional.ofNullable(ConfigReader.SPRINKLERS.get(id));
if (sprinkler.isPresent() && action == Action.RIGHT_CLICK_BLOCK && event.getBlockFace() == BlockFace.UP){
Sprinkler sprinkler = ConfigReader.SPRINKLERS.get(id);
if (sprinkler != null && action == Action.RIGHT_CLICK_BLOCK && event.getBlockFace() == BlockFace.UP){
Location location = event.getClickedBlock().getLocation();
for (Integration integration : ConfigReader.Config.integration){
if (!integration.canPlace(location, player)) return;
@@ -277,10 +274,10 @@ public class RightClick implements Listener {
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.sprinkler_limit.replace("{max}", String.valueOf(ConfigReader.Config.sprinklerLimit)));
return;
}
Sprinkler sprinklerData = new Sprinkler(sprinkler.get().getRange(), 0);
Sprinkler sprinklerData = new Sprinkler(sprinkler.getRange(), 0);
itemStack.setAmount(itemStack.getAmount() - 1);
SprinklerManager.Cache.put(location.add(0,1,0), sprinklerData);
IAFurniture.placeFurniture(sprinkler.get().getNamespacedID_2(),location);
IAFurniture.placeFurniture(sprinkler.getNamespacedID_2(),location);
AdventureManager.playerSound(player, ConfigReader.Sounds.placeSprinklerSource, ConfigReader.Sounds.placeSprinklerKey);
return;
}
@@ -318,17 +315,27 @@ public class RightClick implements Listener {
}
}
else if(ConfigReader.Config.rightClickHarvest && !ConfigReader.Config.needEmptyHand){
rightClickHarvest(event, player);
Block block = event.getClickedBlock();
if (block != null){
rightClickHarvest(block, player);
}
}
}
else if (ConfigReader.Config.rightClickHarvest && action == Action.RIGHT_CLICK_BLOCK) {
rightClickHarvest(event, player);
Block block = event.getClickedBlock();
if (block != null){
rightClickHarvest(block, player);
}
}
}
}
private void rightClickHarvest(PlayerInteractEvent event, Player player) {
Block block = event.getClickedBlock();
/**
* 右键收获判定
* @param block 农作物方块
* @param player 玩家
*/
private void rightClickHarvest(Block block, Player player) {
Location location = block.getLocation();
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
if (customBlock == null) return;
@@ -357,6 +364,11 @@ public class RightClick implements Listener {
if (ConfigReader.Config.skillXP != null && cropInstance.getSkillXP() != 0){
ConfigReader.Config.skillXP.addXp(player, cropInstance.getSkillXP());
}
if (cropInstance.doesDropIALoot()){
customBlock.getLoot().forEach(itemStack -> {
location.getWorld().dropItem(location.clone().add(0.5,0.2,0.5), itemStack);
});
}
if (fertilizer != null){
if (fertilizer instanceof QualityCrop qualityCrop){
int[] weights = qualityCrop.getChance();
@@ -398,6 +410,11 @@ public class RightClick implements Listener {
coolDown.remove(event.getPlayer());
}
/**
* 添加肥料
* @param fertilizerConfig 肥料配置
* @param location 种植盆位置
*/
private void addFertilizer(Fertilizer fertilizerConfig, Location location) {
if (fertilizerConfig instanceof QualityCrop config){
QualityCrop qualityCrop = new QualityCrop(config.getKey(), config.getTimes(), config.getChance(), config.isBefore());
@@ -411,6 +428,13 @@ public class RightClick implements Listener {
}
}
/**
* 水壶浇水判定
* @param width 宽度
* @param length 长度
* @param location 位置
* @param yaw 视角
*/
private void waterPot(int width, int length, Location location, float yaw){
if (ConfigReader.Config.hasParticle){
location.getWorld().spawnParticle(Particle.WATER_SPLASH, location.clone().add(0.5,1.2,0.5),15,0.1,0.1, 0.1);

View File

@@ -31,6 +31,10 @@ import java.time.Duration;
public class AdventureManager {
/**
* 发送控制台信息
* @param s 文本
*/
public static void consoleMessage(String s) {
Audience au = CustomCrops.adventure.sender(Bukkit.getConsoleSender());
MiniMessage mm = MiniMessage.miniMessage();
@@ -38,6 +42,11 @@ public class AdventureManager {
au.sendMessage(parsed);
}
/**
* 发送玩家信息
* @param player 玩家
* @param s 文本
*/
public static void playerMessage(Player player, String s) {
Audience au = CustomCrops.adventure.player(player);
MiniMessage mm = MiniMessage.miniMessage();
@@ -45,6 +54,15 @@ public class AdventureManager {
au.sendMessage(parsed);
}
/**
* 发送玩家标题
* @param player 玩家
* @param s1 主标题
* @param s2 副标题
* @param in 淡入时间
* @param duration 停留时间
* @param out 淡出时间
*/
public static void playerTitle(Player player, String s1, String s2, int in, int duration, int out) {
Audience au = CustomCrops.adventure.player(player);
MiniMessage mm = MiniMessage.miniMessage();
@@ -53,12 +71,23 @@ public class AdventureManager {
au.showTitle(title);
}
/**
* 发送动作消息
* @param player 玩家
* @param s 文本
*/
public static void playerActionbar(Player player, String s) {
Audience au = CustomCrops.adventure.player(player);
MiniMessage mm = MiniMessage.miniMessage();
au.sendActionBar(mm.deserialize(s));
}
/**
* 发送声音
* @param player 玩家
* @param source 来源
* @param key 键
*/
public static void playerSound(Player player, Sound.Source source, Key key) {
Sound sound = Sound.sound(key, source, 1, 1);
Audience au = CustomCrops.adventure.player(player);

View File

@@ -30,6 +30,9 @@ import java.util.List;
public class BackUp {
/**
* 备份全部文件
*/
public static void backUpData(){
List<String> files = Arrays.asList("crop","sprinkler","pot","season");
@@ -49,6 +52,12 @@ public class BackUp {
});
}
/**
* 复制某个文件
* @param file_from 源文件
* @param file_to 目标文件
* @throws IOException IO异常
*/
private static void backUp(File file_from, File file_to) throws IOException {
if(!file_to.exists()){
file_to.getParentFile().mkdirs();

View File

@@ -17,7 +17,6 @@
package net.momirealms.customcrops.utils;
import net.momirealms.customcrops.integrations.skill.SkillXP;
import net.momirealms.customcrops.requirements.Requirement;
import java.util.List;
@@ -35,7 +34,9 @@ public class CropInstance {
private String quality_2;
private String quality_3;
private double skillXP;
private boolean dropIALoot;
private List<String> commands;
private double growChance;
public CropInstance(int min, int max){
this.min = min;
@@ -58,6 +59,8 @@ public class CropInstance {
public int getMin() { return min; }
public List<String> getCommands() { return commands; }
public double getSkillXP() {return skillXP;}
public boolean doesDropIALoot() {return dropIALoot;}
public double getGrowChance() {return growChance;}
public void setReturnStage(String stage){ this.returnStage = stage; }
public void setGiant(String giant) { this.giant = giant; }
@@ -69,4 +72,6 @@ public class CropInstance {
public void setQuality_3(String quality_3) { this.quality_3 = quality_3; }
public void setCommands(List<String> commands) { this.commands = commands; }
public void setSkillXP(double skillXP) {this.skillXP = skillXP;}
public void setDropIALoot(boolean dropIALoot) {this.dropIALoot = dropIALoot;}
public void setGrowChance(double growChance) {this.growChance = growChance;}
}

View File

@@ -39,6 +39,13 @@ public class HoloUtil {
public static HashMap<Location, Entity> cache = new HashMap<>();
/**
* 对指定玩家展示在指定位置的盔甲架
* @param text 文本
* @param player 玩家
* @param location 位置
* @param duration 持续时间
*/
public static void showHolo(String text, Player player, Location location, int duration){
ArmorStand entity = location.getWorld().spawn(location, ArmorStand.class, a -> {

View File

@@ -26,10 +26,21 @@ import org.bukkit.entity.Entity;
public class IAFurniture {
/**
* 在指定位置放置家具
* @param name 物品名
* @param location 位置
*/
public static void placeFurniture(String name, Location location){
CustomFurniture.spawn(name, location.getBlock());
}
/**
* 判断指定位置的盔甲架是不是洒水器
* @param location 位置
* @param world 世界
* @return 是/否
*/
public static boolean getFromLocation(Location location, World world){
for(Entity entity : world.getNearbyEntities(location,0,0,0)){
if(entity instanceof ArmorStand armorStand){

View File

@@ -1,91 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.utils;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
import org.bukkit.inventory.ItemStack;
import java.util.*;
public class NBTUtil {
private final Map<?,?> nbt;
private final NBTItem nbtItem;
public NBTUtil(Map<?,?> nbt, ItemStack itemStack){
this.nbt = nbt;
this.nbtItem = new NBTItem(itemStack);
}
public NBTItem getNBTItem(){
nbt.keySet().forEach(key -> {
if (nbt.get(key) instanceof Map<?,?> map){
nbtItem.addCompound((String) key);
setTags(map, nbtItem.getCompound((String) key));
}else {
setNbt(nbtItem, (String) key, nbt.get(key));
}
});
return this.nbtItem;
}
private void setTags(Map<?,?> map, NBTCompound nbtCompound){
map.keySet().forEach(key -> {
if (map.get(key) instanceof Map map2){
nbtCompound.addCompound((String) key);
setTags(map2, nbtCompound.getCompound((String) key));
}else {
setNbt(nbtCompound, (String) key, map.get(key));
}
});
}
private void setNbt(NBTCompound nbtCompound, String key, Object value){
if (value instanceof String string){
if (string.startsWith("(Int) ")){
nbtCompound.setInteger(key, Integer.valueOf(string.substring(6)));
}else if (string.startsWith("(String) ")){
nbtCompound.setString(key, string.substring(9));
}else if (string.startsWith("(Long) ")){
nbtCompound.setLong(key, Long.valueOf(string.substring(7)));
}else if (string.startsWith("(Float) ")){
nbtCompound.setFloat(key, Float.valueOf(string.substring(8)));
} else if (string.startsWith("(Double) ")){
nbtCompound.setDouble(key, Double.valueOf(string.substring(9)));
}else if (string.startsWith("(Short) ")){
nbtCompound.setShort(key, Short.valueOf(string.substring(8)));
}else if (string.startsWith("(Boolean) ")){
nbtCompound.setBoolean(key, Boolean.valueOf(string.substring(10)));
}else if (string.startsWith("(UUID) ")){
nbtCompound.setUUID(key, UUID.fromString(string.substring(7)));
}else if (string.startsWith("(Byte) ")){
nbtCompound.setByte(key, Byte.valueOf(string.substring(7)));
}else {
nbtCompound.setString(key, string);
}
}else {
try {
nbtCompound.setInteger(key, (Integer) value);
}catch (ClassCastException e){
e.printStackTrace();
AdventureManager.consoleMessage("<red>[CustomCrops] 非Int类型数字必须加上强制转换标识!</red>");
}
}
}
}

View File

@@ -35,25 +35,19 @@ public class SimpleLocation {
this.z = z;
}
/**
* 将Location转换为SimpleLocation
* @param location Location
* @return SimpleLocation
*/
public static SimpleLocation fromLocation(Location location){
return new SimpleLocation(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
public int getY() {
return y;
}
public String getWorldName() {
return worldName;
}
public int getX() {return x;}
public int getZ() {return z;}
public int getY() {return y;}
public String getWorldName() {return worldName;}
@Override
public boolean equals(Object obj) {

View File

@@ -29,29 +29,13 @@ public class Sprinkler {
this.range = range;
}
public int getWater() {
return water;
}
public String getNamespacedID_1() {
return namespacedID_1;
}
public String getNamespacedID_2() {
return namespacedID_2;
}
public int getRange() {
return range;
}
public int getWater() {return water;}
public String getNamespacedID_1() {return namespacedID_1;}
public String getNamespacedID_2() {return namespacedID_2;}
public int getRange() {return range;}
public void setRange(int range) {
this.range = range;
}
public void setNamespacedID_2(String namespacedID_2) {
this.namespacedID_2 = namespacedID_2;
}
public void setNamespacedID_1(String namespacedID_1) {
this.namespacedID_1 = namespacedID_1;
}
public void setWater(int water) {
this.water = water;
}
public void setRange(int range) {this.range = range;}
public void setNamespacedID_2(String namespacedID_2) {this.namespacedID_2 = namespacedID_2;}
public void setNamespacedID_1(String namespacedID_1) {this.namespacedID_1 = namespacedID_1;}
public void setWater(int water) {this.water = water;}
}