9
0
mirror of https://github.com/Xiao-MoMi/Custom-Crops.git synced 2025-12-22 08:29:35 +00:00
This commit is contained in:
Xiao-MoMi
2022-08-21 22:25:02 +08:00
parent 14f5af297e
commit aa8be827d7
40 changed files with 1991 additions and 864 deletions

View File

@@ -5,7 +5,7 @@ plugins {
group = 'net.momirealms'
version = '1.5.26.4'
version = '1.6.0'
repositories {
mavenCentral()

View File

@@ -75,10 +75,8 @@ public class ConfigReader {
public static List<Integration> integration;
public static String referenceWorld;
public static String lang;
public static boolean asyncCheck;
public static boolean enableLimit;
public static boolean hasParticle;
public static boolean rightClickHarvest;
public static String version;
public static String cropMode;
public static int cropLimit;
public static int sprinklerLimit;
public static int yMin;
@@ -87,8 +85,11 @@ public class ConfigReader {
public static int waterCanRefill;
public static int timeToGrow;
public static int timeToWork;
public static boolean logTime;
public static int growMode;
public static boolean asyncCheck;
public static boolean enableLimit;
public static boolean hasParticle;
public static boolean rightClickHarvest;
public static boolean quality;
public static boolean canAddWater;
public static boolean allWorld;
@@ -97,12 +98,14 @@ public class ConfigReader {
public static boolean needEmptyHand;
public static boolean boneMeal;
public static boolean realisticSeason;
public static Particle boneMealSuccess;
public static boolean rotation;
public static boolean variant4;
public static boolean oneTry;
public static double boneMealChance;
public static double quality_1;
public static double quality_2;
public static SkillXP skillXP;
public static String version;
public static Particle boneMealSuccess;
public static void loadConfig(){
@@ -117,7 +120,6 @@ public class ConfigReader {
timeToGrow = config.getInt("config.time-to-grow",60)*20;
timeToWork = config.getInt("config.time-to-work",30)*20;
asyncCheck = config.getBoolean("config.async-time-check",false);
logTime = config.getBoolean("config.log-time-consume",false);
growMode = config.getInt("config.grow-mode",3); if (growMode > 4 || growMode < 1) growMode = 3;
allWorld = config.getBoolean("config.all-world-grow",false);
hasParticle = config.getBoolean("config.water-particles", true);
@@ -125,6 +127,9 @@ public class ConfigReader {
needEmptyHand = config.getBoolean("config.harvest-with-empty-hand", true);
pwSeason = config.getBoolean("config.prevent-plant-if-wrong-season", true);
nwSeason = config.getBoolean("config.should-notify-if-wrong-season", true);
rotation = config.getBoolean("config.rotation.enable", false);
oneTry = config.getBoolean("config.gigantic-only-one-try", false);
variant4 = config.getInt("config.rotation.variant", 4) == 4;
boneMeal = config.getBoolean("config.bone-meal.enable", true);
if (boneMeal){
@@ -160,6 +165,7 @@ public class ConfigReader {
sprinklerRefill = config.getInt("config.sprinkler-refill",2);
waterCanRefill = config.getInt("config.water-can-refill",1);
version = config.getString("config-version");
cropMode = config.getString("config.crop-mode","tripwire");
canAddWater = config.getBoolean("config.water-can-add-water-to-sprinkler",true);
if (allWorld){
@@ -438,12 +444,21 @@ public class ConfigReader {
}
cropInstance.setGrowChance(config.getDouble("crops." + key + ".grow-chance", 1));
if (config.contains("crops." + key + ".gigantic"))
if (config.contains("crops." + key + ".gigantic.block")){
cropInstance.setGiant(config.getString("crops." + key + ".gigantic.block"));
cropInstance.setGiantChance(config.getDouble("crops." + key + ".gigantic.chance"));
cropInstance.setIsBlock(true);
}
if (config.contains("crops." + key + ".gigantic.furniture")){
cropInstance.setGiant(config.getString("crops." + key + ".gigantic.furniture"));
cropInstance.setIsBlock(false);
}
cropInstance.setGiantChance(config.getDouble("crops." + key + ".gigantic.chance",0.01));
if (Season.enable && config.contains("crops." + key + ".season"))
cropInstance.setSeasons(config.getStringList("crops." + key + ".season"));
if (config.contains("crops." + key + ".return"))
cropInstance.setReturnStage(config.getString("crops." + key + ".return"));
if (config.contains("crops." + key + ".drop-other-loots"))
cropInstance.setOtherLoots(config.getStringList("crops." + key + ".drop-other-loots"));
if (config.contains("crops." + key + ".commands"))
cropInstance.setCommands(config.getStringList("crops." + key + ".commands"));
if (config.contains("crops." + key + ".skill-xp"))
@@ -555,8 +570,7 @@ public class ConfigReader {
public static void tryEnableJedis(){
YamlConfiguration configuration = ConfigReader.getConfig("redis.yml");
JedisUtil.useRedis = configuration.getBoolean("redis.enable", false);
if (JedisUtil.useRedis)
JedisUtil.initializeRedis(configuration);
if (JedisUtil.useRedis) JedisUtil.initializeRedis(configuration);
}
private static void hookMessage(String plugin){

View File

@@ -26,6 +26,14 @@ import net.momirealms.customcrops.datamanager.SprinklerManager;
import net.momirealms.customcrops.helper.LibraryLoader;
import net.momirealms.customcrops.hook.Placeholders;
import net.momirealms.customcrops.listener.*;
import net.momirealms.customcrops.listener.itemframe.BreakBlockI;
import net.momirealms.customcrops.listener.itemframe.BreakFurnitureI;
import net.momirealms.customcrops.listener.itemframe.InteractFurnitureI;
import net.momirealms.customcrops.listener.itemframe.RightClickI;
import net.momirealms.customcrops.listener.tripwire.BreakBlockT;
import net.momirealms.customcrops.listener.tripwire.BreakFurnitureT;
import net.momirealms.customcrops.listener.tripwire.InteractFurnitureT;
import net.momirealms.customcrops.listener.tripwire.RightClickT;
import net.momirealms.customcrops.timer.CropTimer;
import net.momirealms.customcrops.utils.*;
import org.bukkit.Bukkit;
@@ -66,7 +74,11 @@ public final class CustomCrops extends JavaPlugin {
adventure = BukkitAudiences.create(plugin);
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#FFEBCD>Running on " + Bukkit.getVersion());
ConfigReader.reloadConfig();
if (!Objects.equals(ConfigReader.Config.version, "3")){
ConfigUtil.update();
}
if(Bukkit.getPluginManager().getPlugin("PlaceHolderAPI") != null){
placeholders = new Placeholders();
@@ -82,28 +94,34 @@ public final class CustomCrops extends JavaPlugin {
Bukkit.getPluginManager().registerEvents(new ItemSpawn(), this);
Bukkit.getPluginManager().registerEvents(new JoinAndQuit(), this);
Bukkit.getPluginManager().registerEvents(new RightClick(), this);
Bukkit.getPluginManager().registerEvents(new BreakBlock(), this);
Bukkit.getPluginManager().registerEvents(new BreakFurniture(), this);
Bukkit.getPluginManager().registerEvents(new InteractEntity(this), this);
ConfigReader.tryEnableJedis();
if (ConfigReader.Season.enable){
this.seasonManager = new SeasonManager();
this.seasonManager.loadData();
}
this.cropManager = new CropManager();
this.cropManager.loadData();
this.sprinklerManager = new SprinklerManager();
this.sprinklerManager.loadData();
this.potManager = new PotManager();
this.potManager.loadData();
this.cropTimer = new CropTimer();
if (ConfigReader.Config.cropMode.equalsIgnoreCase("item_frame")){
this.cropManager = new CropManager(true);
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>Crop Mode: ItemFrame");
Bukkit.getPluginManager().registerEvents(new RightClickI(), this);
Bukkit.getPluginManager().registerEvents(new BreakBlockI(), this);
Bukkit.getPluginManager().registerEvents(new BreakFurnitureI(), this);
Bukkit.getPluginManager().registerEvents(new InteractFurnitureI(), this);
}else{
this.cropManager = new CropManager(false);
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>Crop Mode: TripWire");
Bukkit.getPluginManager().registerEvents(new RightClickT(), this);
Bukkit.getPluginManager().registerEvents(new BreakBlockT(), this);
Bukkit.getPluginManager().registerEvents(new BreakFurnitureT(), this);
Bukkit.getPluginManager().registerEvents(new InteractFurnitureT(), this);
checkIAConfig();
if (!Objects.equals(ConfigReader.Config.version, "3")){
ConfigUtil.update();
}
this.cropManager.loadData();
AdventureManager.consoleMessage("<gradient:#ff206c:#fdee55>[CustomCrops] </gradient><color:#F5DEB3>Plugin Enabled!");
}

View File

@@ -21,9 +21,9 @@ import net.momirealms.customcrops.ConfigReader;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -31,8 +31,7 @@ import java.util.List;
public class Completer implements TabCompleter {
@Override
@ParametersAreNonnullByDefault
public @Nullable List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
public @Nullable List<String> onTabComplete(CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
if (!(sender.isOp() || sender.hasPermission("customcrops.admin"))){
return null;
}

View File

@@ -26,8 +26,8 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import javax.annotation.ParametersAreNonnullByDefault;
public class Executor implements CommandExecutor {
@@ -38,8 +38,7 @@ public class Executor implements CommandExecutor {
}
@Override
@ParametersAreNonnullByDefault
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (!(sender.hasPermission("customcrops.admin") || sender.isOp())){
AdventureManager.playerMessage((Player) sender, ConfigReader.Message.prefix + ConfigReader.Message.noPerm);
@@ -61,6 +60,12 @@ public class Executor implements CommandExecutor {
}
return true;
}
case "test" -> {
CustomCrops.plugin.getCropManager().testData();
}
case "test2" -> {
CustomCrops.plugin.getCropManager().testData2();
}
case "forcegrow" -> {
if (args.length < 2) {
lackArgs(sender);
@@ -106,6 +111,7 @@ public class Executor implements CommandExecutor {
lackArgs(sender);
return true;
}
Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.plugin, ()->{
switch (args[1]){
case "all" -> {
plugin.getSprinklerManager().updateData();
@@ -137,6 +143,7 @@ public class Executor implements CommandExecutor {
forceSave(sender);
}
}
});
}
case "backup" -> {
FileUtil.backUpData();

View File

@@ -18,6 +18,7 @@
package net.momirealms.customcrops.datamanager;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomFurniture;
import net.momirealms.customcrops.fertilizer.QualityCrop;
import net.momirealms.customcrops.listener.JoinAndQuit;
import net.momirealms.customcrops.utils.AdventureManager;
@@ -27,13 +28,17 @@ import net.momirealms.customcrops.fertilizer.Fertilizer;
import net.momirealms.customcrops.fertilizer.RetainingSoil;
import net.momirealms.customcrops.fertilizer.SpeedGrow;
import net.momirealms.customcrops.objects.Crop;
import net.momirealms.customcrops.utils.FurnitureUtil;
import net.momirealms.customcrops.utils.JedisUtil;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.utils.LocUtil;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.scheduler.BukkitScheduler;
import java.io.File;
@@ -41,14 +46,17 @@ import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class CropManager {
public class CropManager{
private YamlConfiguration data;
public static ConcurrentHashMap<Location, String> Cache = new ConcurrentHashMap<>();
public static ConcurrentHashMap<SimpleLocation, String> Cache = new ConcurrentHashMap<>();
public static HashSet<SimpleLocation> RemoveCache = new HashSet<>();
private final BukkitScheduler bukkitScheduler;
private final boolean isEntity;
public CropManager(){
public CropManager(boolean isEntity){
this.bukkitScheduler = Bukkit.getScheduler();
this.isEntity = isEntity;
}
/**
@@ -86,11 +94,37 @@ public class CropManager {
*/
public void updateData(){
Cache.forEach((location, String) -> {
int x = location.getBlockX();
int z = location.getBlockZ();
data.set(location.getWorld().getName() + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z, String);
int x = location.getX();
int z = location.getZ();
data.set(location.getWorldName() + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getY() + "," + z, String);
});
Cache.clear();
HashSet<SimpleLocation> set = new HashSet<>(RemoveCache);
for (SimpleLocation location : set) {
int x = location.getX();
int z = location.getZ();
data.set(location.getWorldName() + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getY() + "," + z, null);
}
RemoveCache.clear();
}
public void testData(){
for (int i = -100; i <= 100; i++){
for (int j = -100; j <= 100; j++){
SimpleLocation simpleLocation = new SimpleLocation("world",i,128,j);
Cache.put(simpleLocation, "XiaoMoMi");
}
}
}
public void testData2(){
World world = Bukkit.getWorld("world");
for (int i = -100; i <= 100; i++){
for (int j = -100; j <= 100; j++){
Location location = new Location(world, i, 128,j);
FurnitureUtil.placeCrop("customcrops:tomato_stage_1", location);
}
}
}
/**
@@ -112,34 +146,43 @@ public class CropManager {
* @param worldName 进行生长判定的世界名
*/
public void growModeOne(String worldName){
Long time1 = System.currentTimeMillis();
if(!ConfigReader.Config.allWorld){
updateData();
}
Long time2 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物数据更新" + (time2-time1) + "ms");
if(!ConfigReader.Config.allWorld) updateData();
if(!ConfigReader.Config.allWorld) saveData();
if (data.contains(worldName)){
World world = Bukkit.getWorld(worldName);
if (!isEntity){
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
String[] split = StringUtils.split(chunk,",");
if (world.isChunkLoaded(Integer.parseInt(split[0]), Integer.parseInt(split[1]))){
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLaterAsynchronously(CustomCrops.plugin, ()-> {
if (growJudge(worldName, seedLocation)){
data.set(worldName + "." + chunk + "." + key, null);
}
}, random);
});
}
});
}
else {
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
String[] split = StringUtils.split(chunk,",");
if (world.isChunkLoaded(Integer.parseInt(split[0]), Integer.parseInt(split[1]))){
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLater(CustomCrops.plugin, ()-> {
growJudgeEntity(worldName, seedLocation, worldName + "." + chunk + "." + key);
}, random);
});
}
});
}
Long time3 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物生长过程" + (time3-time2) + "ms");
if(!ConfigReader.Config.allWorld){
saveData();
}
Long time4 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物数据保存" + (time4-time3) + "ms");
}
/**
@@ -148,34 +191,40 @@ public class CropManager {
* @param worldName 进行生长判定的世界名
*/
public void growModeTwo(String worldName){
Long time1 = System.currentTimeMillis();
if(!ConfigReader.Config.allWorld){
updateData();
}
Long time2 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物数据更新" + (time2-time1) + "ms");
//HashSet<String> players = new HashSet<>(JoinAndQuit.onlinePlayers);
if(!ConfigReader.Config.allWorld) updateData();
if(!ConfigReader.Config.allWorld) saveData();
HashSet<String> players = getPlayers();
if (data.contains(worldName)){
World world = Bukkit.getWorld(worldName);
if (!isEntity){
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
if (!players.contains(value)) return;
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLaterAsynchronously(CustomCrops.plugin, ()-> {
if (growJudge(worldName, seedLocation)){
data.set(worldName + "." + chunk + "." + key, null);
}
}, random);
});
});
}
else {
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
if (!players.contains(value)) return;
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLater(CustomCrops.plugin, ()-> {
growJudgeEntity(worldName, seedLocation, worldName + "." + chunk + "." + key);
}, random);
});
});
}
Long time3 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物生长过程" + (time3-time2) + "ms");
if(!ConfigReader.Config.allWorld){
saveData();
}
Long time4 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物数据保存" + (time4-time3) + "ms");
}
/**
@@ -184,16 +233,12 @@ public class CropManager {
* @param worldName 进行生长判定的世界名
*/
public void growModeThree(String worldName){
Long time1 = System.currentTimeMillis();
if(!ConfigReader.Config.allWorld){
updateData();
}
Long time2 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物数据更新" + (time2-time1) + "ms");
//HashSet<String> players = new HashSet<>(JoinAndQuit.onlinePlayers);
if(!ConfigReader.Config.allWorld) updateData();
if(!ConfigReader.Config.allWorld) saveData();
HashSet<String> players = getPlayers();
if (data.contains(worldName)){
World world = Bukkit.getWorld(worldName);
if (!isEntity){
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
String[] split = StringUtils.split(chunk,",");
//区块被加载,则强行生长判定
@@ -201,9 +246,12 @@ public class CropManager {
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLaterAsynchronously(CustomCrops.plugin, ()-> {
if (growJudge(worldName, seedLocation)){
data.set(worldName + "." + chunk + "." + key, null);
}
}, random);
});
}
//区块未加载,玩家在线
@@ -212,20 +260,45 @@ public class CropManager {
if (!players.contains(value)) return;
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLaterAsynchronously(CustomCrops.plugin, ()-> {
if (growJudge(worldName, seedLocation)){
data.set(worldName + "." + chunk + "." + key, null);
}
}, random);
});
}
});
}
else {
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
String[] split = StringUtils.split(chunk,",");
//区块被加载,则强行生长判定
if (world.isChunkLoaded(Integer.parseInt(split[0]), Integer.parseInt(split[1]))){
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLater(CustomCrops.plugin, ()-> {
growJudgeEntity(worldName, seedLocation, worldName + "." + chunk + "." + key);
}, random);
});
}
//区块未加载,玩家在线
else{
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
if (!players.contains(value)) return;
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLater(CustomCrops.plugin, ()-> {
growJudgeEntity(worldName, seedLocation, worldName + "." + chunk + "." + key);
}, random);
});
}
});
}
Long time3 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物生长过程" + (time3-time2) + "ms");
if(!ConfigReader.Config.allWorld){
saveData();
}
Long time4 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物数据保存" + (time4-time3) + "ms");
}
/**
@@ -234,32 +307,37 @@ public class CropManager {
* @param worldName 进行生长判定的世界名
*/
public void growModeFour(String worldName){
Long time1 = System.currentTimeMillis();
if(!ConfigReader.Config.allWorld){
updateData();
}
Long time2 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物数据更新" + (time2-time1) + "ms");
if(!ConfigReader.Config.allWorld){updateData();}
if(!ConfigReader.Config.allWorld) saveData();
if (data.contains(worldName)){
World world = Bukkit.getWorld(worldName);
if (!isEntity){
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
String[] split = StringUtils.split(chunk,",");
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLaterAsynchronously(CustomCrops.plugin, ()-> {
if (growJudge(worldName, seedLocation)){
data.set(worldName + "." + chunk + "." + key, null);
}
}, random);
});
});
}
else {
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
data.getConfigurationSection(worldName + "." + chunk).getValues(false).forEach((key, value) -> {
String[] coordinate = StringUtils.split(key, ",");
Location seedLocation = new Location(world,Double.parseDouble(coordinate[0]),Double.parseDouble(coordinate[1]),Double.parseDouble(coordinate[2]));
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
bukkitScheduler.runTaskLater(CustomCrops.plugin, ()-> {
growJudgeEntity(worldName, seedLocation, worldName + "." + chunk + "." + key);
}, random);
});
});
}
Long time3 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物生长过程" + (time3-time2) + "ms");
if(!ConfigReader.Config.allWorld){
saveData();
}
Long time4 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 农作物数据保存" + (time4-time3) + "ms");
}
/**
@@ -316,17 +394,15 @@ public class CropManager {
//获取自定义方块ID
String potNamespacedID = pot.getNamespacedID();
if (potNamespacedID.equals(ConfigReader.Basic.watered_pot)){
int random = new Random().nextInt(ConfigReader.Config.timeToGrow);
//如果启用季节限制且农作物有季节需求
if (ConfigReader.Season.enable && cropInstance.getSeasons() != null){
if (isWrongSeason(seedLocation, cropInstance.getSeasons(), worldName)){
bukkitScheduler.runTaskLater(CustomCrops.plugin, () -> {
bukkitScheduler.runTask(CustomCrops.plugin, () -> {
CustomBlock.remove(seedLocation);
CustomBlock.place(ConfigReader.Basic.dead, seedLocation);
}, random);
});
return true;
}
}
//获取下一阶段
@@ -334,7 +410,7 @@ public class CropManager {
//下一阶段存在
if (CustomBlock.getInstance(StringUtils.chop(namespacedID) + nextStage) != null) {
//尝试获取肥料类型
Fertilizer fertilizer = PotManager.Cache.get(SimpleLocation.fromLocation(potLocation));
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(potLocation));
//有肥料
if (fertilizer != null){
//查询剩余使用次数
@@ -346,67 +422,67 @@ public class CropManager {
if (cropInstance.getGrowChance() > Math.random()){
//农作物存在下两个阶段
if (Math.random() < speedGrow.getChance() && CustomBlock.getInstance(StringUtils.chop(namespacedID) + (nextStage + 1)) != null){
addStage(potLocation, seedLocation, namespacedID, nextStage + 1, random);
addStage(potLocation, seedLocation, namespacedID, nextStage + 1);
}else {
addStage(potLocation, seedLocation, namespacedID, nextStage, random);
addStage(potLocation, seedLocation, namespacedID, nextStage);
}
}else {
notAddStage(potLocation, random);
notAddStage(potLocation);
}
}
//保湿土壤
else if(fertilizer instanceof RetainingSoil retainingSoil){
if (Math.random() < retainingSoil.getChance()){
if (cropInstance.getGrowChance() > Math.random()){
addStage(seedLocation, namespacedID, nextStage, random);
addStage(seedLocation, namespacedID, nextStage);
}
}else {
if (cropInstance.getGrowChance() > Math.random()){
addStage(potLocation, seedLocation, namespacedID, nextStage, random);
addStage(potLocation, seedLocation, namespacedID, nextStage);
}else {
notAddStage(potLocation, random);
notAddStage(potLocation);
}
}
}
//品质肥料
else if(fertilizer instanceof QualityCrop){
if (cropInstance.getGrowChance() > Math.random()){
addStage(potLocation, seedLocation, namespacedID, nextStage, random);
addStage(potLocation, seedLocation, namespacedID, nextStage);
}else {
notAddStage(potLocation, random);
notAddStage(potLocation);
}
}else {
//未知肥料类型处理
AdventureManager.consoleMessage("<red>[CustomCrops] Unknown fertilizer, Auto removed!</red>");
PotManager.Cache.remove(SimpleLocation.fromLocation(potLocation));
PotManager.Cache.remove(LocUtil.fromLocation(potLocation));
if (cropInstance.getGrowChance() > Math.random()){
addStage(potLocation, seedLocation, namespacedID, nextStage, random);
addStage(potLocation, seedLocation, namespacedID, nextStage);
}else {
notAddStage(potLocation, random);
notAddStage(potLocation);
}
}
//肥料的最后一次使用
if (times == 1){
PotManager.Cache.remove(SimpleLocation.fromLocation(potLocation));
PotManager.Cache.remove(LocUtil.fromLocation(potLocation));
}
}
else {
//移除肥料信息,一般不会出现此情况
PotManager.Cache.remove(SimpleLocation.fromLocation(potLocation));
PotManager.Cache.remove(LocUtil.fromLocation(potLocation));
if (cropInstance.getGrowChance() > Math.random()){
addStage(potLocation, seedLocation, namespacedID, nextStage, random);
addStage(potLocation, seedLocation, namespacedID, nextStage);
}else {
notAddStage(potLocation, random);
notAddStage(potLocation);
}
}
}
//没有肥料
else {
if (cropInstance.getGrowChance() > Math.random()){
addStage(potLocation, seedLocation, namespacedID, nextStage, random);
addStage(potLocation, seedLocation, namespacedID, nextStage);
}else {
notAddStage(potLocation, random);
notAddStage(potLocation);
}
}
}
@@ -414,29 +490,40 @@ public class CropManager {
else if(cropInstance.getGiant() != null){
//巨大化判定
if (cropInstance.getGiantChance() > Math.random()){
//成功巨大化,移除数据
bukkitScheduler.runTaskLater(CustomCrops.plugin, () ->{
if (cropInstance.isBlock()){
bukkitScheduler.runTask(CustomCrops.plugin, () ->{
CustomBlock.remove(seedLocation);
CustomBlock.place(cropInstance.getGiant(), seedLocation);
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}, random);
});
}else {
bukkitScheduler.runTask(CustomCrops.plugin, () ->{
//加载区块哦亲
CustomBlock.remove(seedLocation);
CustomFurniture.spawn(cropInstance.getGiant(), seedLocation.getBlock());
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
});
}
//成功巨大化,移除数据
return true;
}else {
//失败,转湿为干
bukkitScheduler.runTaskLater(CustomCrops.plugin, () ->{
bukkitScheduler.runTask(CustomCrops.plugin, () ->{
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}, random);
return ConfigReader.Config.growMode == 4;
});
return ConfigReader.Config.oneTry || ConfigReader.Config.growMode == 4;
}
}else {
//若无下一阶段,无巨大化,未启用季节,则移除无用数据
if (!ConfigReader.Season.enable) return true;
bukkitScheduler.runTaskLater(CustomCrops.plugin, () -> {
bukkitScheduler.runTask(CustomCrops.plugin, () -> {
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}, random);
});
}
}
//干燥的种植盆
@@ -448,10 +535,10 @@ public class CropManager {
if(seasons == null) return false;
//错误季节
if(isWrongSeason(seedLocation, seasons, worldName)){
bukkitScheduler.runTaskLater(CustomCrops.plugin, () -> {
bukkitScheduler.runTask(CustomCrops.plugin, () -> {
CustomBlock.remove(seedLocation);
CustomBlock.place(ConfigReader.Basic.dead, seedLocation);
}, new Random().nextInt(ConfigReader.Config.timeToGrow));
});
return true;
}
}
@@ -495,22 +582,211 @@ public class CropManager {
return true;
}
/**
* 对某个位置进行生长判定
* @param worldName 世界名
* @param seedLocation 种子位置
*/
private void growJudgeEntity(String worldName, Location seedLocation, String path) {
Chunk chunk = seedLocation.getChunk();
chunk.load();
bukkitScheduler.runTaskLater(CustomCrops.plugin, ()-> {
if (chunk.isEntitiesLoaded()){
CustomFurniture crop = FurnitureUtil.getFurniture(seedLocation.clone().add(0.5,0.1,0.5));
//自定义农作物家具不存在
if(crop == null) {
data.set(path, null);
return;
}
String namespacedID = crop.getNamespacedID();
//已死亡或不是农作物
if(namespacedID.equals(ConfigReader.Basic.dead) || !namespacedID.contains("_stage_")) {
data.set(path, null);
return;
}
//农作物下方自定义方块不存在
Location potLocation = seedLocation.clone().subtract(0,1,0);
CustomBlock pot = CustomBlock.byAlreadyPlaced(potLocation.getBlock());
if (pot == null){
data.set(path, null);
return;
}
//农作物实例不存在
String id = crop.getId();
String[] cropNameList = StringUtils.split(id,"_");
Crop cropInstance = ConfigReader.CROPS.get(cropNameList[0]);
if (cropInstance == null){
data.set(path, null);
return;
}
//获取自定义方块ID
String potNamespacedID = pot.getNamespacedID();
if (potNamespacedID.equals(ConfigReader.Basic.watered_pot)){
//如果启用季节限制且农作物有季节需求
if (ConfigReader.Season.enable && cropInstance.getSeasons() != null){
if (isWrongSeason(seedLocation, cropInstance.getSeasons(), worldName)){
seedLocation.getChunk().load();
CustomFurniture.remove(crop.getArmorstand(), false);
FurnitureUtil.placeCrop(ConfigReader.Basic.dead, seedLocation);
data.set(path, null);
return;
}
}
//获取下一阶段
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
//下一阶段存在
if (CustomFurniture.getInstance(StringUtils.chop(namespacedID) + nextStage) != null) {
//尝试获取肥料类型
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(potLocation));
//有肥料
if (fertilizer != null){
//查询剩余使用次数
int times = fertilizer.getTimes();
if (times > 0){
fertilizer.setTimes(times - 1);
//生长激素
if (fertilizer instanceof SpeedGrow speedGrow){
if (cropInstance.getGrowChance() > Math.random()){
//农作物存在下两个阶段
if (Math.random() < speedGrow.getChance() && CustomBlock.getInstance(StringUtils.chop(namespacedID) + (nextStage + 1)) != null){
addStageEntity(potLocation, seedLocation, crop.getArmorstand(), StringUtils.chop(namespacedID) + (nextStage + 1));
}else {
addStageEntity(potLocation, seedLocation, crop.getArmorstand(), StringUtils.chop(namespacedID) + nextStage);
}
}else {
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}
}
//保湿土壤
else if(fertilizer instanceof RetainingSoil retainingSoil){
if (Math.random() < retainingSoil.getChance()){
if (cropInstance.getGrowChance() > Math.random()){
addStageEntity(seedLocation, crop.getArmorstand(), StringUtils.chop(namespacedID) + nextStage);
}
}else {
if (cropInstance.getGrowChance() > Math.random()){
addStageEntity(potLocation, seedLocation, crop.getArmorstand(), StringUtils.chop(namespacedID) + nextStage);
}else {
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}
}
}
//品质肥料
else if(fertilizer instanceof QualityCrop){
if (cropInstance.getGrowChance() > Math.random()){
addStageEntity(potLocation, seedLocation, crop.getArmorstand(), StringUtils.chop(namespacedID) + nextStage);
}else {
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}
}else {
//未知肥料类型处理
AdventureManager.consoleMessage("<red>[CustomCrops] Unknown fertilizer, Auto removed!</red>");
PotManager.Cache.remove(LocUtil.fromLocation(potLocation));
if (cropInstance.getGrowChance() > Math.random()){
addStageEntity(potLocation, seedLocation, crop.getArmorstand(), StringUtils.chop(namespacedID) + nextStage);
}else {
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}
}
//肥料的最后一次使用
if (times == 1){
PotManager.Cache.remove(LocUtil.fromLocation(potLocation));
}
}
else {
//移除肥料信息,一般不会出现此情况
PotManager.Cache.remove(LocUtil.fromLocation(potLocation));
if (cropInstance.getGrowChance() > Math.random()){
addStageEntity(potLocation, seedLocation, crop.getArmorstand(), StringUtils.chop(namespacedID) + nextStage);
}else {
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}
}
}
//没有肥料
else {
if (cropInstance.getGrowChance() > Math.random()){
addStageEntity(potLocation, seedLocation, crop.getArmorstand(), StringUtils.chop(namespacedID) + nextStage);
}else {
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}
}
}
//农作物是否存在巨大化
else if(cropInstance.getGiant() != null){
//巨大化判定
if (cropInstance.getGiantChance() > Math.random()){
if (cropInstance.isBlock()){
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
CustomFurniture.remove(crop.getArmorstand(), false);
CustomBlock.place(cropInstance.getGiant(), seedLocation);
}else {
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
CustomFurniture.remove(crop.getArmorstand(), false);
CustomFurniture.spawn(cropInstance.getGiant(), seedLocation.getBlock());
}
//成功巨大化,移除数据
data.set(path, null);
}else {
//失败,转湿为干
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
if (ConfigReader.Config.oneTry || ConfigReader.Config.growMode == 4){
data.set(path, null);
}
}
}else {
//若无下一阶段,无巨大化,未启用季节,则移除无用数据
if (!ConfigReader.Season.enable){
data.set(path, null);
return;
}
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}
}
//干燥的种植盆
else if(potNamespacedID.equals(ConfigReader.Basic.pot)){
//未启用季节
if(!ConfigReader.Season.enable) return;
//农作物无视季节
List<String> seasons = cropInstance.getSeasons();
if(seasons == null) return;
//错误季节
if(isWrongSeason(seedLocation, seasons, worldName)){
CustomBlock.remove(seedLocation);
CustomBlock.place(ConfigReader.Basic.dead, seedLocation);
data.set(path, null);
}
}
}
},4);
}
/**
* 生长一个阶段(消耗水)
* @param potLocation 种植盆位置
* @param seedLocation 农作物位置
* @param namespacedID 农作物下一阶段的ID
* @param nextStage 农作物下一阶段的阶段数
* @param random 随机生长时间
*/
private void addStage(Location potLocation, Location seedLocation, String namespacedID, int nextStage, int random){
private void addStage(Location potLocation, Location seedLocation, String namespacedID, int nextStage){
String stage = StringUtils.chop(namespacedID) + nextStage;
bukkitScheduler.runTaskLater(CustomCrops.plugin, () ->{
bukkitScheduler.runTask(CustomCrops.plugin, () ->{
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
CustomBlock.remove(seedLocation);
CustomBlock.place(stage, seedLocation);
}, random);
});
}
/**
@@ -518,26 +794,41 @@ public class CropManager {
* @param seedLocation 农作物位置
* @param namespacedID 农作物下一阶段的ID
* @param nextStage 农作物下一阶段的阶段数
* @param random 随机生长时间
*/
private void addStage(Location seedLocation, String namespacedID, int nextStage, int random){
private void addStage(Location seedLocation, String namespacedID, int nextStage){
String stage = StringUtils.chop(namespacedID) + nextStage;
bukkitScheduler.runTaskLater(CustomCrops.plugin, () ->{
bukkitScheduler.runTask(CustomCrops.plugin, () ->{
CustomBlock.remove(seedLocation);
CustomBlock.place(stage, seedLocation);
}, random);
});
}
private void addStageEntity(Location potLocation, Location seedLocation, Entity entity, String nextStage){
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
CustomFurniture.remove(entity,false);
if (FurnitureUtil.getFurniture(seedLocation.add(0.5,0.1,0.5)) == null){
FurnitureUtil.placeCrop(nextStage, seedLocation);
}
}
private void addStageEntity(Location seedLocation, Entity entity, String nextStage){
CustomFurniture.remove(entity,false);
if (FurnitureUtil.getFurniture(seedLocation.add(0.5,0.1,0.5)) == null){
FurnitureUtil.placeCrop(nextStage, seedLocation);
}
}
/**
* 停滞阶段(消耗水)
* @param potLocation 种植盆位置
* @param random 随机生长时间
*/
private void notAddStage(Location potLocation, int random){
bukkitScheduler.runTaskLater(CustomCrops.plugin, () ->{
private void notAddStage(Location potLocation){
bukkitScheduler.runTask(CustomCrops.plugin, () ->{
CustomBlock.remove(potLocation);
CustomBlock.place(ConfigReader.Basic.pot, potLocation);
}, random);
});
}
private HashSet<String> getPlayers(){

View File

@@ -82,8 +82,11 @@ public class SeasonManager{
*/
public void getSeason(World world) {
if (ConfigReader.Config.realisticSeason){
Bukkit.getScheduler().runTaskLater(CustomCrops.plugin, ()->{
SEASON.put(world.getName(), RealisticSeason.getSeason(world));
}else {
},60);
}
else {
int season = (int) ((world.getFullTime() / 24000L) % (ConfigReader.Season.duration * 4)) / ConfigReader.Season.duration;
switch (season) {
case 0 -> SEASON.put(world.getName(), "spring");

View File

@@ -39,7 +39,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class SprinklerManager {
public YamlConfiguration data;
public static YamlConfiguration data;
public static ConcurrentHashMap<SimpleLocation, Sprinkler> Cache = new ConcurrentHashMap<>();
public static HashSet<SimpleLocation> RemoveCache = new HashSet<>();
private final BukkitScheduler bukkitScheduler;
@@ -62,7 +62,7 @@ public class SprinklerManager {
AdventureManager.consoleMessage("<red>[CustomCrops] 洒水器数据文件生成失败!</red>");
}
}
this.data = YamlConfiguration.loadConfiguration(file);
data = YamlConfiguration.loadConfiguration(file);
}
/**
@@ -120,12 +120,8 @@ public class SprinklerManager {
* @param worldName 世界名
*/
public void workModeOne(String worldName){
Long time1 = System.currentTimeMillis();
if(!ConfigReader.Config.allWorld){
updateData();
}
Long time2 = System.currentTimeMillis();
if (ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器数据更新" + (time2-time1) + "ms");
if(!ConfigReader.Config.allWorld) updateData();
if(!ConfigReader.Config.allWorld) saveData();
if (data.contains(worldName)){
World world = Bukkit.getWorld(worldName);
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
@@ -138,7 +134,7 @@ public class SprinklerManager {
bukkitScheduler.runTask(CustomCrops.plugin, ()->{
int water = (int) map.get("water");
int range = (int) Optional.ofNullable(map.get("range")).orElse(0);
if(!IAFurnitureUtil.isSprinkler(location)){
if(!FurnitureUtil.isSprinkler(location)){
data.set(worldName + "." + chunk + "." + key, null);
return;
}
@@ -159,13 +155,6 @@ public class SprinklerManager {
}
});
}
Long time3 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器工作过程" + (time3-time2) + "ms");
if(!ConfigReader.Config.allWorld){
saveData();
}
Long time4 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器数据保存" + (time4-time3) + "ms");
}
/**
@@ -173,13 +162,8 @@ public class SprinklerManager {
* @param worldName 世界名
*/
public void workModeTwo(String worldName){
Long time1 = System.currentTimeMillis();
if(!ConfigReader.Config.allWorld){
updateData();
}
Long time2 = System.currentTimeMillis();
if (ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器数据更新" + (time2-time1) + "ms");
//HashSet<String> players = new HashSet<>(JoinAndQuit.onlinePlayers);
if(!ConfigReader.Config.allWorld) updateData();
if(!ConfigReader.Config.allWorld) saveData();
HashSet<String> players = getPlayers();
if (data.contains(worldName)){
World world = Bukkit.getWorld(worldName);
@@ -194,7 +178,7 @@ public class SprinklerManager {
if (!players.contains(player)) return;
String[] coordinate = StringUtils.split(key, ",");
Location location = new Location(world,Double.parseDouble(coordinate[0])+0.5,Double.parseDouble(coordinate[1])+0.5,Double.parseDouble(coordinate[2])+0.5);
bukkitScheduler.callSyncMethod(CustomCrops.plugin, ()->{
bukkitScheduler.runTask(CustomCrops.plugin, ()->{
int water = (int) map.get("water");
int range = (int) Optional.ofNullable(map.get("range")).orElse(0);
if (water > 0){
@@ -208,19 +192,11 @@ public class SprinklerManager {
}, new Random().nextInt(ConfigReader.Config.timeToWork));
}
if (range == 0) data.set(worldName + "." + chunk + "." + key, null);
return null;
});
}
});
});
}
Long time3 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器工作过程" + (time3-time2) + "ms");
if(!ConfigReader.Config.allWorld){
saveData();
}
Long time4 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器数据保存" + (time4-time3) + "ms");
}
/**
@@ -228,13 +204,8 @@ public class SprinklerManager {
* @param worldName 世界名
*/
public void workModeThree(String worldName){
Long time1 = System.currentTimeMillis();
if(!ConfigReader.Config.allWorld){
updateData();
}
Long time2 = System.currentTimeMillis();
if (ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器数据更新" + (time2-time1) + "ms");
//HashSet<String> players = new HashSet<>(JoinAndQuit.onlinePlayers);
if(!ConfigReader.Config.allWorld) updateData();
if(!ConfigReader.Config.allWorld) saveData();
HashSet<String> players = getPlayers();
if (data.contains(worldName)){
World world = Bukkit.getWorld(worldName);
@@ -248,7 +219,7 @@ public class SprinklerManager {
String[] coordinate = StringUtils.split(key, ",");
Location location = new Location(world,Double.parseDouble(coordinate[0])+0.5,Double.parseDouble(coordinate[1])+0.5,Double.parseDouble(coordinate[2])+0.5);
bukkitScheduler.runTask(CustomCrops.plugin, ()->{
if(!IAFurnitureUtil.isSprinkler(location)){
if(!FurnitureUtil.isSprinkler(location)){
data.set(worldName + "." + chunk + "." + key, null);
return;
}
@@ -296,13 +267,6 @@ public class SprinklerManager {
}
});
}
Long time3 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器工作过程" + (time3-time2) + "ms");
if(!ConfigReader.Config.allWorld){
saveData();
}
Long time4 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器数据保存" + (time4-time3) + "ms");
}
/**
@@ -310,12 +274,8 @@ public class SprinklerManager {
* @param worldName 世界名
*/
public void workModeFour(String worldName){
Long time1 = System.currentTimeMillis();
if(!ConfigReader.Config.allWorld){
updateData();
}
Long time2 = System.currentTimeMillis();
if (ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器数据更新" + (time2-time1) + "ms");
if(!ConfigReader.Config.allWorld) updateData();
if(!ConfigReader.Config.allWorld) saveData();
if (data.contains(worldName)){
World world = Bukkit.getWorld(worldName);
data.getConfigurationSection(worldName).getKeys(false).forEach(chunk ->{
@@ -340,13 +300,6 @@ public class SprinklerManager {
});
});
}
Long time3 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器工作过程" + (time3-time2) + "ms");
if(!ConfigReader.Config.allWorld){
saveData();
}
Long time4 = System.currentTimeMillis();
if(ConfigReader.Config.logTime) AdventureManager.consoleMessage("性能监测: 洒水器数据保存" + (time4-time3) + "ms");
}
@@ -391,4 +344,24 @@ public class SprinklerManager {
return new HashSet<>(JoinAndQuit.onlinePlayers);
}
}
/**
* 获取某个洒水器的水量
* @param location 洒水器位置
* @param world 世界
* @param x 坐标
* @param z 坐标
* @param sprinkler 洒水器类型
* @return 水量
*/
public static int getCurrentWater(Location location, String world, int x, int z, Sprinkler sprinkler) {
int currentWater;
if (sprinkler != null) currentWater = sprinkler.getWater();
else {
String path = world + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z + ".water";
currentWater = data.getInt(path);
}
return currentWater;
}
}

View File

@@ -43,7 +43,6 @@ 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")
@@ -126,7 +125,6 @@ public final class LibraryLoader {
return jarDir;
}
@NonnullByDefault
public static final class Dependency {
private final String groupId;
private final String artifactId;

View File

@@ -27,33 +27,32 @@ package net.momirealms.customcrops.helper;
import net.momirealms.customcrops.CustomCrops;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
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) {
public static void info(@NotNull String s) {
CustomCrops.plugin.getLogger().info(s);
}
public static void warn(@Nonnull String s) {
public static void warn(@NotNull String s) {
CustomCrops.plugin.getLogger().warning(s);
}
public static void severe(@Nonnull String s) {
public static void severe(@NotNull String s) {
CustomCrops.plugin.getLogger().severe(s);
}
public static void warn(@Nonnull String s, Throwable t) {
public static void warn(@NotNull String s, Throwable t) {
CustomCrops.plugin.getLogger().log(Level.WARNING, s, t);
}
public static void severe(@Nonnull String s, Throwable t) {
public static void severe(@NotNull String s, Throwable t) {
CustomCrops.plugin.getLogger().log(Level.SEVERE, s, t);
}

View File

@@ -25,14 +25,14 @@
package net.momirealms.customcrops.helper;
import org.jetbrains.annotations.NotNull;
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.
*/
@@ -41,7 +41,7 @@ import javax.annotation.Nonnull;
@Retention(RetentionPolicy.RUNTIME)
public @interface MavenLibraries {
@Nonnull
@NotNull
MavenLibrary[] value() default {};
}

View File

@@ -25,6 +25,8 @@
package net.momirealms.customcrops.helper;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
@@ -32,8 +34,6 @@ 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.
*/
@@ -48,7 +48,7 @@ public @interface MavenLibrary {
*
* @return the group id of the library
*/
@Nonnull
@NotNull
String groupId();
/**
@@ -56,7 +56,7 @@ public @interface MavenLibrary {
*
* @return the artifact id of the library
*/
@Nonnull
@NotNull
String artifactId();
/**
@@ -64,7 +64,7 @@ public @interface MavenLibrary {
*
* @return the version of the library
*/
@Nonnull
@NotNull
String version();
/**
@@ -72,7 +72,7 @@ public @interface MavenLibrary {
*
* @return the repo where the library can be obtained from
*/
@Nonnull
@NotNull
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

@@ -31,8 +31,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
/**
* Represents a maven repository.
*/
@@ -46,7 +44,6 @@ public @interface Repository {
*
* @return the base url of the repository
*/
@Nonnull
String url();
}

View File

@@ -25,13 +25,13 @@
package net.momirealms.customcrops.helper;
import org.jetbrains.annotations.NotNull;
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.
*/
@@ -63,7 +63,7 @@ public abstract class URLClassLoaderAccess {
*
* @param url the URL to add
*/
public abstract void addURL(@Nonnull URL url);
public abstract void addURL(@NotNull URL url);
/**
* Accesses using sun.misc.Unsafe, supported on Java 9+.
@@ -117,7 +117,7 @@ public abstract class URLClassLoaderAccess {
}
@Override
public void addURL(@Nonnull URL url) {
public void addURL(@NotNull URL url) {
this.unopenedURLs.add(url);
this.pathURLs.add(url);
}
@@ -131,7 +131,7 @@ public abstract class URLClassLoaderAccess {
}
@Override
public void addURL(@Nonnull URL url) {
public void addURL(@NotNull 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.hook;
import me.casperge.realisticseasons.api.SeasonsAPI;

View File

@@ -24,6 +24,6 @@ public class mcMMO implements SkillXP {
@Override
public void addXp(Player player, double amount) {
ExperienceAPI.addXP(player, "Herbalism", (int) amount, "UNKNOWN");
ExperienceAPI.addRawXP(player, "Herbalism", (float) amount, "UNKNOWN");
}
}

View File

@@ -18,7 +18,7 @@
package net.momirealms.customcrops.limits;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.utils.IAFurnitureUtil;
import net.momirealms.customcrops.utils.FurnitureUtil;
import org.bukkit.Location;
public class SprinklersPerChunk {
@@ -33,7 +33,7 @@ public class SprinklersPerChunk {
Location square = chunkLocation.clone().add(i + 0.5, 0.5, j + 0.5);
for (int k = ConfigReader.Config.yMin; k <= ConfigReader.Config.yMax; ++k) {
square.add(0.0, 1.0, 0.0);
if(IAFurnitureUtil.isSprinkler(square))
if(FurnitureUtil.isSprinkler(square))
if (n++ > ConfigReader.Config.sprinklerLimit)
break Label_out;
}

View File

@@ -1,16 +1,19 @@
package net.momirealms.customcrops.listener;
import net.momirealms.customcrops.utils.JedisUtil;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.HashSet;
public class JoinAndQuit implements Listener {
public static HashSet<String> onlinePlayers = new HashSet<>();
public static HashMap<Player, Long> coolDown = new HashMap<>();
@EventHandler
public void onJoin(PlayerJoinEvent event){
@@ -22,5 +25,6 @@ public class JoinAndQuit implements Listener {
public void onQuit(PlayerQuitEvent event){
if (JedisUtil.useRedis) JedisUtil.remPlayer(event.getPlayer().getName());
else onlinePlayers.remove(event.getPlayer().getName());
coolDown.remove(event.getPlayer());
}
}

View File

@@ -0,0 +1,74 @@
package net.momirealms.customcrops.listener.itemframe;
import dev.lone.itemsadder.api.CustomFurniture;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.Events.CustomBlockBreakEvent;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.datamanager.CropManager;
import net.momirealms.customcrops.datamanager.PotManager;
import net.momirealms.customcrops.fertilizer.Fertilizer;
import net.momirealms.customcrops.fertilizer.QualityCrop;
import net.momirealms.customcrops.integrations.protection.Integration;
import net.momirealms.customcrops.objects.Crop;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.utils.DropUtil;
import net.momirealms.customcrops.utils.FurnitureUtil;
import net.momirealms.customcrops.utils.LocUtil;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import java.util.concurrent.ThreadLocalRandom;
public class BreakBlockI implements Listener {
@EventHandler
public void onBreak(CustomBlockBreakEvent event){
String namespacedId = event.getNamespacedID();
if(namespacedId.equalsIgnoreCase(ConfigReader.Basic.watered_pot) || namespacedId.equalsIgnoreCase(ConfigReader.Basic.pot)){
Location location = event.getBlock().getLocation();
PotManager.Cache.remove(LocUtil.fromLocation(location));
World world = location.getWorld();
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canBreak(location, event.getPlayer())) return;
CustomFurniture furniture = FurnitureUtil.getFurniture(location.add(0.5,1.1,0.5));
if(furniture != null){
String nsID = furniture.getNamespacedID();
if(nsID.contains("_stage_")){
SimpleLocation simpleLocation = LocUtil.fromLocation(location);
if (CropManager.Cache.remove(simpleLocation) == null){
CropManager.RemoveCache.add(simpleLocation);
}
CustomFurniture.remove(furniture.getArmorstand(), false);
if (nsID.equals(ConfigReader.Basic.dead)) return;
if (ConfigReader.Config.quality){
String[] cropNameList = StringUtils.split(StringUtils.split(nsID, ":")[1], "_");
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
if (CustomFurniture.getInstance(StringUtils.chop(nsID) + nextStage) == null) {
Crop cropInstance = ConfigReader.CROPS.get(cropNameList[0]);
ThreadLocalRandom current = ThreadLocalRandom.current();
int random = current.nextInt(cropInstance.getMin(), cropInstance.getMax() + 1);
Location itemLoc = location.clone().add(0.5,0.2,0.5);
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(location.clone().subtract(0,1,0)));
if (fertilizer != null){
if (fertilizer instanceof QualityCrop qualityCrop){
int[] weights = qualityCrop.getChance();
double weightTotal = weights[0] + weights[1] + weights[2];
for (int i = 0; i < random; i++){
double ran = Math.random();
if (ran < weights[0]/(weightTotal)) world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
else if(ran > 1 - weights[1]/(weightTotal)) world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
else world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
}
}
}
else DropUtil.normalDrop(cropInstance, random, itemLoc, world);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,83 @@
package net.momirealms.customcrops.listener.itemframe;
import dev.lone.itemsadder.api.CustomFurniture;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.Events.FurnitureBreakEvent;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.datamanager.CropManager;
import net.momirealms.customcrops.datamanager.PotManager;
import net.momirealms.customcrops.datamanager.SprinklerManager;
import net.momirealms.customcrops.fertilizer.Fertilizer;
import net.momirealms.customcrops.fertilizer.QualityCrop;
import net.momirealms.customcrops.integrations.protection.Integration;
import net.momirealms.customcrops.objects.Crop;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.objects.Sprinkler;
import net.momirealms.customcrops.utils.DropUtil;
import net.momirealms.customcrops.utils.LocUtil;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class BreakFurnitureI implements Listener {
@EventHandler
public void onBreakFurniture(FurnitureBreakEvent event){
String namespacedID = event.getNamespacedID();
Sprinkler config = ConfigReader.SPRINKLERS.get(namespacedID);
if (config != null){
SimpleLocation simpleLocation = LocUtil.fromLocation(event.getBukkitEntity().getLocation());
if (SprinklerManager.Cache.remove(simpleLocation) == null){
SprinklerManager.RemoveCache.add(simpleLocation);
}
return;
}
if (namespacedID.contains("_stage_")){
Player player = event.getPlayer();
Location location = event.getBukkitEntity().getLocation();
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canBreak(location, player)) return;
SimpleLocation simpleLocation = LocUtil.fromLocation(location);
if (CropManager.Cache.remove(simpleLocation) == null){
CropManager.RemoveCache.add(simpleLocation);
}
if (!ConfigReader.Config.quality || namespacedID.equals(ConfigReader.Basic.dead)) return;
String[] cropNameList = StringUtils.split(StringUtils.split(namespacedID, ":")[1], "_");
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
if (CustomFurniture.getInstance(StringUtils.chop(namespacedID) + nextStage) == null) {
Crop cropInstance = ConfigReader.CROPS.get(cropNameList[0]);
ThreadLocalRandom current = ThreadLocalRandom.current();
int random = current.nextInt(cropInstance.getMin(), cropInstance.getMax() + 1);
Location itemLoc = location.clone().add(0,0.2,0);
World world = location.getWorld();
List<String> commands = cropInstance.getCommands();
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(location.clone().subtract(0,1,0)));
if (commands != null)
for (String command : commands)
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command.replace("{player}", player.getName()));
if (ConfigReader.Config.skillXP != null && cropInstance.getSkillXP() != 0) ConfigReader.Config.skillXP.addXp(player, cropInstance.getSkillXP());
if (fertilizer != null){
if (fertilizer instanceof QualityCrop qualityCrop){
int[] weights = qualityCrop.getChance();
double weightTotal = weights[0] + weights[1] + weights[2];
for (int i = 0; i < random; i++){
double ran = Math.random();
if (ran < weights[0]/(weightTotal)) world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
else if(ran > 1 - weights[1]/(weightTotal)) world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
else world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
}
}
else DropUtil.normalDrop(cropInstance, random, itemLoc, world);
}
else DropUtil.normalDrop(cropInstance, random, itemLoc, world);
}
}
}
}

View File

@@ -0,0 +1,293 @@
package net.momirealms.customcrops.listener.itemframe;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
import dev.lone.itemsadder.api.CustomFurniture;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.Events.FurnitureInteractEvent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.datamanager.CropManager;
import net.momirealms.customcrops.datamanager.PotManager;
import net.momirealms.customcrops.datamanager.SprinklerManager;
import net.momirealms.customcrops.fertilizer.Fertilizer;
import net.momirealms.customcrops.fertilizer.QualityCrop;
import net.momirealms.customcrops.integrations.protection.Integration;
import net.momirealms.customcrops.listener.JoinAndQuit;
import net.momirealms.customcrops.objects.Crop;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.objects.Sprinkler;
import net.momirealms.customcrops.objects.WateringCan;
import net.momirealms.customcrops.utils.*;
import org.apache.commons.lang.StringUtils;
import org.bukkit.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
public class InteractFurnitureI implements Listener {
@EventHandler
public void onEntityInteract(FurnitureInteractEvent event){
long time = System.currentTimeMillis();
Player player = event.getPlayer();
if (time - (JoinAndQuit.coolDown.getOrDefault(player, time - 200)) < 200) return;
JoinAndQuit.coolDown.put(player, time);
String namespacedID = event.getNamespacedID();
Sprinkler config = ConfigReader.SPRINKLERS.get(namespacedID);
if(config != null){
ItemStack itemStack = player.getInventory().getItemInMainHand();
Location location = event.getBukkitEntity().getLocation();
String world = location.getWorld().getName();
int x = location.getBlockX();
int z = location.getBlockZ();
int maxWater = config.getWater();
int currentWater = 0;
Location loc = location.clone().subtract(0,1,0).getBlock().getLocation().add(0,1,0);
Sprinkler sprinkler = SprinklerManager.Cache.get(LocUtil.fromLocation(loc));
if (itemStack.getType() == Material.WATER_BUCKET){
itemStack.setType(Material.BUCKET);
if (sprinkler != null){
currentWater = sprinkler.getWater();
currentWater += ConfigReader.Config.sprinklerRefill;
if (currentWater > maxWater) currentWater = maxWater;
sprinkler.setWater(currentWater);
}else {
String path = world + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z;
currentWater = SprinklerManager.data.getInt(path+ ".water");
currentWater += ConfigReader.Config.sprinklerRefill;
if (currentWater > maxWater) currentWater = maxWater;
SprinklerManager.data.set(path + ".water", currentWater);
SprinklerManager.data.set(path + ".range", config.getRange());
}
AdventureManager.playerSound(player, ConfigReader.Sounds.addWaterToSprinklerSource, ConfigReader.Sounds.addWaterToSprinklerKey);
}
else {
if (ConfigReader.Config.canAddWater && itemStack.getType() != Material.AIR){
NBTItem nbtItem = new NBTItem(itemStack);
NBTCompound nbtCompound = nbtItem.getCompound("itemsadder");
if (nbtCompound != null) {
String id = nbtCompound.getString("id");
String namespace = nbtCompound.getString("namespace");
WateringCan wateringCan = ConfigReader.CANS.get(namespace + ":" + id);
if (wateringCan != null) {
int water = nbtItem.getInteger("WaterAmount");
if (water > 0){
nbtItem.setInteger("WaterAmount", --water);
AdventureManager.playerSound(player, ConfigReader.Sounds.addWaterToSprinklerSource, ConfigReader.Sounds.addWaterToSprinklerKey);
if (sprinkler != null){
currentWater = sprinkler.getWater();
currentWater++;
if (currentWater > maxWater) currentWater = maxWater;
sprinkler.setWater(currentWater);
}else {
String path = world + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z;
currentWater = SprinklerManager.data.getInt(path + ".water");
currentWater++;
if (currentWater > maxWater) currentWater = maxWater;
SprinklerManager.data.set(path + ".water", currentWater);
SprinklerManager.data.set(path + ".range", config.getRange());
}
}
else {
currentWater = SprinklerManager.getCurrentWater(location, world, x, z, sprinkler);
}
if (ConfigReader.Message.hasWaterInfo){
AdventureManager.playerActionbar(player,
(ConfigReader.Message.waterLeft +
ConfigReader.Message.waterFull.repeat(water) +
ConfigReader.Message.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Message.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water)));
}
if (ConfigReader.Basic.hasWaterLore){
String string =
(ConfigReader.Basic.waterLeft +
ConfigReader.Basic.waterFull.repeat(water) +
ConfigReader.Basic.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Basic.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water));
List<String> lores = nbtItem.getCompound("display").getStringList("Lore");
lores.clear();
ConfigReader.Basic.waterLore.forEach(lore -> lores.add(GsonComponentSerializer.gson().serialize(MiniMessage.miniMessage().deserialize(lore.replace("{water_info}", string)))));
}
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
}
else currentWater = SprinklerManager.getCurrentWater(location, world, x, z, sprinkler);
}
else currentWater = SprinklerManager.getCurrentWater(location, world, x, z, sprinkler);
}
if (ConfigReader.Message.hasSprinklerInfo)
HoloUtil.showHolo(
(ConfigReader.Message.sprinklerLeft +
ConfigReader.Message.sprinklerFull.repeat(currentWater) +
ConfigReader.Message.sprinklerEmpty.repeat(maxWater - currentWater) +
ConfigReader.Message.sprinklerRight)
.replace("{max_water}", String.valueOf(maxWater))
.replace("{water}", String.valueOf(currentWater)),
player,
location.add(0, ConfigReader.Message.sprinklerOffset,0),
ConfigReader.Message.sprinklerTime);
}
if (namespacedID.contains("_stage_")){
ItemStack itemStack = player.getInventory().getItemInMainHand();
if (itemStack.getType() != Material.AIR){
NBTItem nbtItem = new NBTItem(itemStack);
NBTCompound nbtCompound = nbtItem.getCompound("itemsadder");
if (nbtCompound != null){
Location location = event.getBukkitEntity().getLocation();
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canPlace(location, player)) return;
String id = nbtCompound.getString("id");
String namespace = nbtCompound.getString("namespace");
String nsID = namespace + ":" +id;
WateringCan wateringCan = ConfigReader.CANS.get(nsID);
if (wateringCan != null){
int water = nbtItem.getInteger("WaterAmount");
if (water > 0){
nbtItem.setInteger("WaterAmount", --water);
AdventureManager.playerSound(player, ConfigReader.Sounds.waterPotSource, ConfigReader.Sounds.waterPotKey);
PotUtil.waterPot(wateringCan.getWidth(), wateringCan.getLength(), location.subtract(0.5,1,0.5), player.getLocation().getYaw());
}
if (ConfigReader.Message.hasWaterInfo)
AdventureManager.playerActionbar(player,
(ConfigReader.Message.waterLeft +
ConfigReader.Message.waterFull.repeat(water) +
ConfigReader.Message.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Message.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water)));
if (ConfigReader.Basic.hasWaterLore){
List<String> lores = nbtItem.getCompound("display").getStringList("Lore");
lores.clear();
String string =
(ConfigReader.Basic.waterLeft +
ConfigReader.Basic.waterFull.repeat(water) +
ConfigReader.Basic.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Basic.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water));
ConfigReader.Basic.waterLore.forEach(lore -> lores.add(GsonComponentSerializer.gson().serialize(MiniMessage.miniMessage().deserialize(lore.replace("{water_info}", string)))));
}
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
return;
}
Fertilizer fertilizerConfig = ConfigReader.FERTILIZERS.get(id);
if (fertilizerConfig != null){
if (!fertilizerConfig.isBefore()){
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
PotUtil.addFertilizer(fertilizerConfig, event.getBukkitEntity().getLocation().subtract(0,1,0));
AdventureManager.playerSound(player, ConfigReader.Sounds.useFertilizerSource, ConfigReader.Sounds.useFertilizerKey);
}else {
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.beforePlant);
}
return;
}
if (ConfigReader.Message.hasCropInfo && nsID.equals(ConfigReader.Basic.soilDetector)){
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(location.subtract(0,1,0)));
if (fertilizer != null){
Fertilizer fertilizer1 = ConfigReader.FERTILIZERS.get(fertilizer.getKey());
if (fertilizer1 == null) return;
HoloUtil.showHolo(
ConfigReader.Message.cropText
.replace("{fertilizer}", fertilizer1.getName())
.replace("{times}", String.valueOf(fertilizer.getTimes()))
.replace("{max_times}", String.valueOf(fertilizer1.getTimes())),
player,
location.add(0, ConfigReader.Message.cropOffset, 0),
ConfigReader.Message.cropTime);
}
}
}
else if (ConfigReader.Config.boneMeal && itemStack.getType() == Material.BONE_MEAL){
Entity entity = event.getBukkitEntity();
Location location = entity.getLocation();
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canPlace(location, player)) return;
if (!namespacedID.equals(ConfigReader.Basic.dead)){
int nextStage = Integer.parseInt(namespacedID.substring(namespacedID.length()-1)) + 1;
String next = StringUtils.chop(namespacedID) + nextStage;
if (CustomFurniture.getInstance(next) != null){
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
AdventureManager.playerSound(player, ConfigReader.Sounds.boneMealSource, ConfigReader.Sounds.boneMealKey);
if (Math.random() < ConfigReader.Config.boneMealChance){
CustomFurniture.remove(entity, false);
FurnitureUtil.placeCrop(next, location);
location.getWorld().spawnParticle(ConfigReader.Config.boneMealSuccess, location.add(0,0.3,0),5,0.2,0.2,0.2);
}
}
}
}
else if(ConfigReader.Config.rightClickHarvest && !ConfigReader.Config.needEmptyHand){
rightClickHarvest(event.getFurniture(), player);
}
}
else if(ConfigReader.Config.rightClickHarvest && !Objects.equals(ConfigReader.Basic.dead, namespacedID)){
rightClickHarvest(event.getFurniture(), player);
}
}
}
/**
* 右键收获判定
* @param crop 农作物实体
* @param player 玩家
*/
private void rightClickHarvest(CustomFurniture crop, Player player) {
Entity entity = crop.getArmorstand();
Location location = entity.getLocation();
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canBreak(location, player)) return;
String namespacedID = crop.getNamespacedID();
String[] cropNameList = StringUtils.split(namespacedID, "_");
int nextStage = Integer.parseInt(cropNameList[2]) + 1;
if (CustomFurniture.getInstance(StringUtils.chop(namespacedID) + nextStage) == null) {
CustomFurniture.remove(entity, false);
Crop cropInstance = ConfigReader.CROPS.get(StringUtils.split(cropNameList[0], ":")[1]);
if (ConfigReader.Config.quality){
ThreadLocalRandom current = ThreadLocalRandom.current();
int random = current.nextInt(cropInstance.getMin(), cropInstance.getMax() + 1);
World world = location.getWorld();
Location itemLoc = location.clone().add(0,0.2,0);
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(location.clone().subtract(0,1,0)));
List<String> commands = cropInstance.getCommands();
if (commands != null)
for (String command : commands)
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command.replace("{player}", player.getName()));
if (ConfigReader.Config.skillXP != null && cropInstance.getSkillXP() != 0) ConfigReader.Config.skillXP.addXp(player, cropInstance.getSkillXP());
if (cropInstance.getOtherLoots() != null) cropInstance.getOtherLoots().forEach(s -> location.getWorld().dropItem(itemLoc, CustomStack.getInstance(s).getItemStack()));
if (fertilizer != null){
if (fertilizer instanceof QualityCrop qualityCrop){
int[] weights = qualityCrop.getChance();
double weightTotal = weights[0] + weights[1] + weights[2];
for (int i = 0; i < random; i++){
double ran = Math.random();
if (ran < weights[0]/(weightTotal)) world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
else if(ran > 1 - weights[1]/(weightTotal)) world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
else world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
}
}
else DropUtil.normalDrop(cropInstance, random, itemLoc, world);
}
else DropUtil.normalDrop(cropInstance, random, itemLoc, world);
}
AdventureManager.playerSound(player, ConfigReader.Sounds.harvestSource, ConfigReader.Sounds.harvestKey);
if(cropInstance.getReturnStage() != null){
FurnitureUtil.placeCrop(cropInstance.getReturnStage(), location);
SimpleLocation simpleLocation = LocUtil.fromLocation(location);
CropManager.RemoveCache.remove(simpleLocation);
CropManager.Cache.put(simpleLocation, player.getName());
}
}
}
}

View File

@@ -0,0 +1,260 @@
package net.momirealms.customcrops.listener.itemframe;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
import dev.lone.itemsadder.api.CustomBlock;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.datamanager.CropManager;
import net.momirealms.customcrops.datamanager.PotManager;
import net.momirealms.customcrops.datamanager.SeasonManager;
import net.momirealms.customcrops.datamanager.SprinklerManager;
import net.momirealms.customcrops.fertilizer.Fertilizer;
import net.momirealms.customcrops.integrations.protection.Integration;
import net.momirealms.customcrops.limits.CropsPerChunk;
import net.momirealms.customcrops.limits.SprinklersPerChunk;
import net.momirealms.customcrops.listener.JoinAndQuit;
import net.momirealms.customcrops.objects.Crop;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.objects.Sprinkler;
import net.momirealms.customcrops.objects.WateringCan;
import net.momirealms.customcrops.requirements.PlantingCondition;
import net.momirealms.customcrops.requirements.Requirement;
import net.momirealms.customcrops.utils.*;
import org.apache.commons.lang.StringUtils;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class RightClickI implements Listener {
@EventHandler
public void onInteract(PlayerInteractEvent event){
long time = System.currentTimeMillis();
Player player = event.getPlayer();
if (time - (JoinAndQuit.coolDown.getOrDefault(player, time - 200)) < 200) return;
JoinAndQuit.coolDown.put(player, time);
Action action = event.getAction();
if (action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK){
ItemStack itemStack = event.getItem();
if (itemStack != null && itemStack.getType() != Material.AIR){
NBTItem nbtItem = new NBTItem(itemStack);
NBTCompound nbtCompound = nbtItem.getCompound("itemsadder");
if (nbtCompound != null){
String id = nbtCompound.getString("id");
String namespace = nbtCompound.getString("namespace");
String itemNID = namespace + ":" + id;
if (id.endsWith("_seeds") && action == Action.RIGHT_CLICK_BLOCK && event.getBlockFace() == BlockFace.UP){
String cropName = StringUtils.remove(id, "_seeds");
Crop cropInstance = ConfigReader.CROPS.get(cropName);
if (cropInstance != null){
Block block = event.getClickedBlock();
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
if (customBlock == null) return;
String namespacedID = customBlock.getNamespacedID();
if (namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)){
Location location = block.getLocation().add(0,1,0); //已+1
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canPlace(location, player)) return;
if (FurnitureUtil.getNamespacedID(location.clone().add(0.5,0.1,0.5)) != null) return;
PlantingCondition plantingCondition = new PlantingCondition(player, location);
if (cropInstance.getRequirements() != null)
for (Requirement requirement : cropInstance.getRequirements())
if (!requirement.canPlant(plantingCondition)) return;
Label_out:
if (ConfigReader.Season.enable && cropInstance.getSeasons() != null){
if (!ConfigReader.Config.allWorld){
for (String season : cropInstance.getSeasons())
if (season.equals(SeasonManager.SEASON.get(location.getWorld().getName())))
break Label_out;
}else {
for(String season : cropInstance.getSeasons())
if (season.equals(SeasonManager.SEASON.get(ConfigReader.Config.referenceWorld)))
break Label_out;
}
if(ConfigReader.Season.greenhouse){
for(int i = 1; i <= ConfigReader.Season.range; i++){
CustomBlock cb = CustomBlock.byAlreadyPlaced(location.clone().add(0,i,0).getBlock());
if (cb != null)
if(cb.getNamespacedID().equalsIgnoreCase(ConfigReader.Basic.glass))
break Label_out;
}
}
if (ConfigReader.Config.nwSeason) AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.badSeason);
if (ConfigReader.Config.pwSeason) return;
}
if (location.getBlock().getType() != Material.AIR) return;
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
if (CropsPerChunk.isLimited(location)){
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.crop_limit.replace("{max}", String.valueOf(ConfigReader.Config.cropLimit)));
return;
}
SimpleLocation simpleLocation = LocUtil.fromLocation(location);
CropManager.RemoveCache.remove(simpleLocation);
CropManager.Cache.put(simpleLocation, player.getName());
FurnitureUtil.placeCrop(namespace + ":" + cropName + "_stage_1", location);
AdventureManager.playerSound(player, ConfigReader.Sounds.plantSeedSource, ConfigReader.Sounds.plantSeedKey);
}
}else AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.not_configed);
return;
}
WateringCan wateringCan = ConfigReader.CANS.get(itemNID);
if (wateringCan != null){
int water = nbtItem.getInteger("WaterAmount");
List<Block> lineOfSight = player.getLineOfSight(null, 5);
for (Block block : lineOfSight) {
if (block.getType() == Material.WATER) {
if (wateringCan.getMax() > water){
water += ConfigReader.Config.waterCanRefill;
if (water > wateringCan.getMax()) water = wateringCan.getMax();
nbtItem.setInteger("WaterAmount", water);
player.getWorld().playSound(player.getLocation(), Sound.ITEM_BUCKET_FILL,1,1);
if (ConfigReader.Message.hasWaterInfo)
AdventureManager.playerActionbar(player,
(ConfigReader.Message.waterLeft +
ConfigReader.Message.waterFull.repeat(water) +
ConfigReader.Message.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Message.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water)));
if (ConfigReader.Basic.hasWaterLore){
List<String> lores = nbtItem.getCompound("display").getStringList("Lore");
lores.clear();
String string =
(ConfigReader.Basic.waterLeft +
ConfigReader.Basic.waterFull.repeat(water) +
ConfigReader.Basic.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Basic.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water));
ConfigReader.Basic.waterLore.forEach(lore -> lores.add(GsonComponentSerializer.gson().serialize(MiniMessage.miniMessage().deserialize(lore.replace("{water_info}", string)))));
}
if (ConfigReader.Config.hasParticle) player.getWorld().spawnParticle(Particle.WATER_SPLASH, block.getLocation().add(0.5,1, 0.5),15,0.1,0.1,0.1);
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
return;
}
}
if(action == Action.RIGHT_CLICK_BLOCK){
Block block = event.getClickedBlock();
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
if (customBlock == null) return;
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canPlace(block.getLocation(), player)) return;
String namespacedID = customBlock.getNamespacedID();
if ((namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)) && event.getBlockFace() == BlockFace.UP){
if (water > 0){
nbtItem.setInteger("WaterAmount", --water);
AdventureManager.playerSound(player, ConfigReader.Sounds.waterPotSource, ConfigReader.Sounds.waterPotKey);
PotUtil.waterPot(wateringCan.getWidth(), wateringCan.getLength(), block.getLocation(), player.getLocation().getYaw());
}
if (ConfigReader.Message.hasWaterInfo)
AdventureManager.playerActionbar(player,
(ConfigReader.Message.waterLeft +
ConfigReader.Message.waterFull.repeat(water) +
ConfigReader.Message.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Message.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water)));
if (ConfigReader.Basic.hasWaterLore){
List<String> lores = nbtItem.getCompound("display").getStringList("Lore");
lores.clear();
String string =
(ConfigReader.Basic.waterLeft +
ConfigReader.Basic.waterFull.repeat(water) +
ConfigReader.Basic.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Basic.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water));
ConfigReader.Basic.waterLore.forEach(lore -> lores.add(GsonComponentSerializer.gson().serialize(MiniMessage.miniMessage().deserialize(lore.replace("{water_info}", string)))));
}
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
}
return;
}
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;
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canPlace(block.getLocation(), player)) return;
String namespacedID = customBlock.getNamespacedID();
if (namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)){
String furniture = FurnitureUtil.getNamespacedID(block.getLocation().clone().add(0.5,1.1,0.5));
if (furniture != null){
if (fertilizerConfig.isBefore() && furniture.contains("_stage_")){
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.beforePlant);
return;
}else {
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
AdventureManager.playerSound(player, ConfigReader.Sounds.useFertilizerSource, ConfigReader.Sounds.useFertilizerKey);
PotUtil.addFertilizer(fertilizerConfig, block.getLocation());
}
}else {
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
AdventureManager.playerSound(player, ConfigReader.Sounds.useFertilizerSource, ConfigReader.Sounds.useFertilizerKey);
PotUtil.addFertilizer(fertilizerConfig, block.getLocation());
}
}
return;
}
Sprinkler sprinkler = ConfigReader.SPRINKLERS.get(itemNID);
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;
if (FurnitureUtil.isSprinkler(location.clone().add(0.5, 1.5, 0.5))) return;
if (SprinklersPerChunk.isLimited(location)){
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.sprinkler_limit.replace("{max}", String.valueOf(ConfigReader.Config.sprinklerLimit)));
return;
}
Sprinkler sprinklerData = new Sprinkler(sprinkler.getRange(), 0);
sprinklerData.setPlayer(player.getName());
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
SimpleLocation simpleLocation = LocUtil.fromLocation(location.add(0,1,0));
SprinklerManager.Cache.put(simpleLocation, sprinklerData);
SprinklerManager.RemoveCache.remove(simpleLocation);
FurnitureUtil.placeFurniture(sprinkler.getNamespacedID_2(),location);
AdventureManager.playerSound(player, ConfigReader.Sounds.placeSprinklerSource, ConfigReader.Sounds.placeSprinklerKey);
return;
}
if (ConfigReader.Message.hasCropInfo && itemNID.equals(ConfigReader.Basic.soilDetector) && action == Action.RIGHT_CLICK_BLOCK){
Block block = event.getClickedBlock();
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
if (customBlock == null) return;
for (Integration integration : ConfigReader.Config.integration) if(!integration.canPlace(block.getLocation(), player)) return;
String namespacedID = customBlock.getNamespacedID();
if(namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)){
Location location = block.getLocation();
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(block.getLocation()));
if (fertilizer != null){
Fertilizer config = ConfigReader.FERTILIZERS.get(fertilizer.getKey());
String name = config.getName();
int max_times = config.getTimes();
HoloUtil.showHolo(
ConfigReader.Message.cropText
.replace("{fertilizer}", name)
.replace("{times}", String.valueOf(fertilizer.getTimes()))
.replace("{max_times}", String.valueOf(max_times)),
player,
location.add(0.5,ConfigReader.Message.cropOffset,0.5),
ConfigReader.Message.cropTime);
}
}
}
}
}
}
}
}

View File

@@ -15,19 +15,22 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.listener;
package net.momirealms.customcrops.listener.tripwire;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.Events.CustomBlockBreakEvent;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.datamanager.CropManager;
import net.momirealms.customcrops.datamanager.PotManager;
import net.momirealms.customcrops.fertilizer.Fertilizer;
import net.momirealms.customcrops.fertilizer.QualityCrop;
import net.momirealms.customcrops.integrations.protection.Integration;
import net.momirealms.customcrops.objects.Crop;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.utils.DropUtil;
import net.momirealms.customcrops.utils.LocUtil;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -43,7 +46,7 @@ import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class BreakBlock implements Listener {
public class BreakBlockT implements Listener {
@EventHandler
public void onBreak(CustomBlockBreakEvent event){
@@ -53,6 +56,10 @@ public class BreakBlock implements Listener {
Location location = event.getBlock().getLocation();
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canBreak(location, player)) return;
SimpleLocation simpleLocation = LocUtil.fromLocation(location);
if (CropManager.Cache.remove(simpleLocation) == null){
CropManager.RemoveCache.add(simpleLocation);
}
if (player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH) || player.getInventory().getItemInMainHand().getType() == Material.SHEARS){
event.setCancelled(true);
CustomBlock.place(namespacedId, location);
@@ -72,7 +79,7 @@ public class BreakBlock implements Listener {
Location itemLoc = location.clone().add(0.5,0.2,0.5);
World world = location.getWorld();
List<String> commands = cropInstance.getCommands();
Fertilizer fertilizer = PotManager.Cache.get(SimpleLocation.fromLocation(location.clone().subtract(0,1,0)));
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(location.clone().subtract(0,1,0)));
if (commands != null)
Bukkit.getScheduler().runTask(CustomCrops.plugin, ()-> {
for (String command : commands)
@@ -93,15 +100,15 @@ public class BreakBlock implements Listener {
}
});
}
else Bukkit.getScheduler().runTask(CustomCrops.plugin, ()-> normalDrop(cropInstance, random, itemLoc, world));
else Bukkit.getScheduler().runTask(CustomCrops.plugin, ()-> DropUtil.normalDrop(cropInstance, random, itemLoc, world));
}
else Bukkit.getScheduler().runTask(CustomCrops.plugin, ()-> normalDrop(cropInstance, random, itemLoc, world));
else Bukkit.getScheduler().runTask(CustomCrops.plugin, ()-> DropUtil.normalDrop(cropInstance, random, itemLoc, world));
});
}
}
else if(namespacedId.equalsIgnoreCase(ConfigReader.Basic.watered_pot) || namespacedId.equalsIgnoreCase(ConfigReader.Basic.pot)){
Location location = event.getBlock().getLocation();
PotManager.Cache.remove(SimpleLocation.fromLocation(location));
PotManager.Cache.remove(LocUtil.fromLocation(location));
World world = location.getWorld();
Block blockUp = location.add(0,1,0).getBlock();
for (Integration integration : ConfigReader.Config.integration)
@@ -111,6 +118,10 @@ public class BreakBlock implements Listener {
String cropNamespacedId = customBlock.getNamespacedID();
if(cropNamespacedId.contains("_stage_")){
CustomBlock.remove(location);
SimpleLocation simpleLocation = LocUtil.fromLocation(location);
if (CropManager.Cache.remove(simpleLocation) == null){
CropManager.RemoveCache.add(simpleLocation);
}
if (cropNamespacedId.equals(ConfigReader.Basic.dead)) return;
if (ConfigReader.Config.quality){
String[] cropNameList = StringUtils.split(StringUtils.split(cropNamespacedId, ":")[1], "_");
@@ -120,7 +131,7 @@ public class BreakBlock implements Listener {
ThreadLocalRandom current = ThreadLocalRandom.current();
int random = current.nextInt(cropInstance.getMin(), cropInstance.getMax() + 1);
Location itemLoc = location.clone().add(0.5,0.2,0.5);
Fertilizer fertilizer = PotManager.Cache.get(SimpleLocation.fromLocation(location.clone().subtract(0,1,0)));
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(location.clone().subtract(0,1,0)));
if (fertilizer != null){
if (fertilizer instanceof QualityCrop qualityCrop){
int[] weights = qualityCrop.getChance();
@@ -133,35 +144,14 @@ public class BreakBlock implements Listener {
}
}
}
else normalDrop(cropInstance, random, itemLoc, world);
else DropUtil.normalDrop(cropInstance, random, itemLoc, world);
return;
}
}
for (ItemStack itemStack : customBlock.getLoot())
world.dropItem(location.clone().add(0.5, 0.2, 0.5), itemStack);
CustomBlock.remove(location);
}
}
}
}
/**
* 没有品质肥料下的普通掉落
* @param cropInstance 农作物
* @param random 随机农作物数量
* @param itemLoc 掉落物位置
* @param world 世界
*/
static void normalDrop(Crop cropInstance, int random, Location itemLoc, World world) {
for (int i = 0; i < random; i++){
double ran = Math.random();
if (ran < ConfigReader.Config.quality_1){
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
}else if(ran > ConfigReader.Config.quality_2){
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
}else {
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
}
}
}
}

View File

@@ -1,22 +1,24 @@
package net.momirealms.customcrops.listener;
package net.momirealms.customcrops.listener.tripwire;
import dev.lone.itemsadder.api.Events.FurnitureBreakEvent;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.datamanager.SprinklerManager;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.objects.Sprinkler;
import net.momirealms.customcrops.utils.LocUtil;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class BreakFurniture implements Listener {
public class BreakFurnitureT implements Listener {
@EventHandler
public void onBreakFurniture(FurnitureBreakEvent event){
Sprinkler config = ConfigReader.SPRINKLERS.get(event.getNamespacedID());
if (config != null){
SimpleLocation simpleLocation = SimpleLocation.fromLocation(event.getBukkitEntity().getLocation());
SprinklerManager.Cache.remove(simpleLocation);
SimpleLocation simpleLocation = LocUtil.fromLocation(event.getBukkitEntity().getLocation());
if(SprinklerManager.Cache.remove(simpleLocation) == null){
SprinklerManager.RemoveCache.add(simpleLocation);
}
}
}
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.listener;
package net.momirealms.customcrops.listener.tripwire;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
@@ -25,6 +25,7 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.datamanager.SprinklerManager;
import net.momirealms.customcrops.listener.JoinAndQuit;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.objects.Sprinkler;
import net.momirealms.customcrops.objects.WateringCan;
@@ -40,14 +41,7 @@ import java.util.HashMap;
import java.util.List;
public class InteractEntity implements Listener {
private final CustomCrops plugin;
private final HashMap<Player, Long> coolDown = new HashMap<>();
public InteractEntity(CustomCrops plugin){
this.plugin = plugin;
}
public class InteractFurnitureT implements Listener {
@EventHandler
public void onEntityInteract(FurnitureInteractEvent event){
@@ -55,8 +49,8 @@ public class InteractEntity implements Listener {
if(config != null){
long time = System.currentTimeMillis();
Player player = event.getPlayer();
if (time - (coolDown.getOrDefault(player, time - 200)) < 200) return;
coolDown.put(player, time);
if (time - (JoinAndQuit.coolDown.getOrDefault(player, time - 200)) < 200) return;
JoinAndQuit.coolDown.put(player, time);
ItemStack itemStack = player.getInventory().getItemInMainHand();
Location location = event.getBukkitEntity().getLocation();
String world = location.getWorld().getName();
@@ -65,7 +59,7 @@ public class InteractEntity implements Listener {
int maxWater = config.getWater();
int currentWater = 0;
Location loc = location.clone().subtract(0,1,0).getBlock().getLocation().add(0,1,0);
Sprinkler sprinkler = SprinklerManager.Cache.get(SimpleLocation.fromLocation(loc));
Sprinkler sprinkler = SprinklerManager.Cache.get(LocUtil.fromLocation(loc));
if (itemStack.getType() == Material.WATER_BUCKET){
itemStack.setType(Material.BUCKET);
if (sprinkler != null){
@@ -75,25 +69,25 @@ public class InteractEntity implements Listener {
sprinkler.setWater(currentWater);
}else {
String path = world + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z ;
currentWater = plugin.getSprinklerManager().data.getInt(path+ ".water");
currentWater = SprinklerManager.data.getInt(path+ ".water");
currentWater += ConfigReader.Config.sprinklerRefill;
if (currentWater > maxWater) currentWater = maxWater;
plugin.getSprinklerManager().data.set(path + ".water", currentWater);
plugin.getSprinklerManager().data.set(path + ".range", config.getRange());
SprinklerManager.data.set(path + ".water", currentWater);
SprinklerManager.data.set(path + ".range", config.getRange());
}
AdventureManager.playerSound(player, ConfigReader.Sounds.addWaterToSprinklerSource, ConfigReader.Sounds.addWaterToSprinklerKey);
}
else {
if (ConfigReader.Config.canAddWater && itemStack.getType() != Material.AIR){
NBTItem nbtItem = new NBTItem(itemStack);
int water = nbtItem.getInteger("WaterAmount");
if (water > 0){
NBTCompound nbtCompound = nbtItem.getCompound("itemsadder");
if (nbtCompound != null) {
String id = nbtCompound.getString("id");
String namespace = nbtCompound.getString("namespace");
WateringCan wateringCan = ConfigReader.CANS.get(namespace + ":" + id);
if (wateringCan != null) {
int water = nbtItem.getInteger("WaterAmount");
if (water > 0){
nbtItem.setInteger("WaterAmount", --water);
AdventureManager.playerSound(player, ConfigReader.Sounds.addWaterToSprinklerSource, ConfigReader.Sounds.addWaterToSprinklerKey);
if (sprinkler != null){
@@ -102,11 +96,16 @@ public class InteractEntity implements Listener {
if (currentWater > maxWater) currentWater = maxWater;
sprinkler.setWater(currentWater);
}else {
String path = world + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z + ".water";
currentWater = plugin.getSprinklerManager().data.getInt(path);
String path = world + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z ;
currentWater = SprinklerManager.data.getInt(path + ".water");
currentWater++;
if (currentWater > maxWater) currentWater = maxWater;
plugin.getSprinklerManager().data.set(path, currentWater);
SprinklerManager.data.set(path + ".water", currentWater);
SprinklerManager.data.set(path + ".range", config.getRange());
}
}
else {
currentWater = SprinklerManager.getCurrentWater(location, world, x, z, sprinkler);
}
if (ConfigReader.Message.hasWaterInfo){
AdventureManager.playerActionbar(player,
@@ -132,10 +131,9 @@ public class InteractEntity implements Listener {
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
}
else currentWater = SprinklerManager.getCurrentWater(location, world, x, z, sprinkler);
}
else currentWater = getCurrentWater(location, world, x, z, sprinkler);
}
else currentWater = getCurrentWater(location, world, x, z, sprinkler);
else currentWater = SprinklerManager.getCurrentWater(location, world, x, z, sprinkler);
}
if (ConfigReader.Message.hasSprinklerInfo)
HoloUtil.showHolo(
@@ -150,23 +148,4 @@ public class InteractEntity implements Listener {
ConfigReader.Message.sprinklerTime);
}
}
/**
* 获取某个洒水器的水量
* @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) currentWater = sprinkler.getWater();
else {
String path = world + "." + x / 16 + "," + z / 16 + "." + x + "," + location.getBlockY() + "," + z + ".water";
currentWater = plugin.getSprinklerManager().data.getInt(path);
}
return currentWater;
}
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.listener;
package net.momirealms.customcrops.listener.tripwire;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
@@ -30,11 +30,10 @@ import net.momirealms.customcrops.datamanager.SeasonManager;
import net.momirealms.customcrops.datamanager.SprinklerManager;
import net.momirealms.customcrops.fertilizer.Fertilizer;
import net.momirealms.customcrops.fertilizer.QualityCrop;
import net.momirealms.customcrops.fertilizer.RetainingSoil;
import net.momirealms.customcrops.fertilizer.SpeedGrow;
import net.momirealms.customcrops.integrations.protection.Integration;
import net.momirealms.customcrops.limits.CropsPerChunk;
import net.momirealms.customcrops.limits.SprinklersPerChunk;
import net.momirealms.customcrops.listener.JoinAndQuit;
import net.momirealms.customcrops.objects.Crop;
import net.momirealms.customcrops.objects.SimpleLocation;
import net.momirealms.customcrops.objects.Sprinkler;
@@ -51,23 +50,19 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class RightClick implements Listener {
private final HashMap<Player, Long> coolDown = new HashMap<>();
public class RightClickT implements Listener {
@EventHandler
public void onInteract(PlayerInteractEvent event){
long time = System.currentTimeMillis();
Player player = event.getPlayer();
if (time - (coolDown.getOrDefault(player, time - 250)) < 250) return;
coolDown.put(player, time);
if (time - (JoinAndQuit.coolDown.getOrDefault(player, time - 200)) < 200) return;
JoinAndQuit.coolDown.put(player, time);
Action action = event.getAction();
if (action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK){
ItemStack itemStack = event.getItem();
@@ -90,7 +85,7 @@ public class RightClick implements Listener {
Location location = block.getLocation().add(0,1,0); //+1
for (Integration integration : ConfigReader.Config.integration)
if(!integration.canPlace(location, player)) return;
if(IAFurnitureUtil.isSprinkler(location.clone().add(0.5, 0.5, 0.5))) return;
if(FurnitureUtil.isSprinkler(location.clone().add(0.5, 0.5, 0.5))) return;
PlantingCondition plantingCondition = new PlantingCondition(player, location);
if (cropInstance.getRequirements() != null)
for (Requirement requirement : cropInstance.getRequirements())
@@ -123,7 +118,9 @@ public class RightClick implements Listener {
AdventureManager.playerMessage(player,ConfigReader.Message.prefix + ConfigReader.Message.crop_limit.replace("{max}", String.valueOf(ConfigReader.Config.cropLimit)));
return;
}
CropManager.Cache.put(location, player.getName());
SimpleLocation simpleLocation = LocUtil.fromLocation(location);
CropManager.RemoveCache.remove(simpleLocation);
CropManager.Cache.put(simpleLocation, player.getName());
CustomBlock.place((namespace + ":" + cropName + "_stage_1"), location);
AdventureManager.playerSound(player, ConfigReader.Sounds.plantSeedSource, ConfigReader.Sounds.plantSeedKey);
}
@@ -167,7 +164,7 @@ public class RightClick implements Listener {
return;
}
}
if(water != 0 && action == Action.RIGHT_CLICK_BLOCK){
if(action == Action.RIGHT_CLICK_BLOCK){
Block block = event.getClickedBlock();
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
if (customBlock == null) return;
@@ -175,53 +172,57 @@ public class RightClick implements Listener {
if(!integration.canPlace(block.getLocation(), player)) return;
String namespacedID = customBlock.getNamespacedID();
if ((namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)) && event.getBlockFace() == BlockFace.UP){
nbtItem.setInteger("WaterAmount", water - 1);
if (water > 0){
nbtItem.setInteger("WaterAmount", --water);
AdventureManager.playerSound(player, ConfigReader.Sounds.waterPotSource, ConfigReader.Sounds.waterPotKey);
waterPot(wateringCan.getWidth(), wateringCan.getLength(), block.getLocation(), player.getLocation().getYaw());
PotUtil.waterPot(wateringCan.getWidth(), wateringCan.getLength(), block.getLocation(), player.getLocation().getYaw());
}
if (ConfigReader.Message.hasWaterInfo)
AdventureManager.playerActionbar(player,
(ConfigReader.Message.waterLeft +
ConfigReader.Message.waterFull.repeat(water - 1) +
ConfigReader.Message.waterEmpty.repeat(wateringCan.getMax() - water + 1) +
ConfigReader.Message.waterFull.repeat(water) +
ConfigReader.Message.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Message.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water -1)));
.replace("{water}", String.valueOf(water)));
if (ConfigReader.Basic.hasWaterLore){
List<String> lores = nbtItem.getCompound("display").getStringList("Lore");
lores.clear();
String string =
(ConfigReader.Basic.waterLeft +
ConfigReader.Basic.waterFull.repeat(water - 1) +
ConfigReader.Basic.waterEmpty.repeat(wateringCan.getMax() - water + 1) +
ConfigReader.Basic.waterFull.repeat(water) +
ConfigReader.Basic.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Basic.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water -1));
.replace("{water}", String.valueOf(water));
ConfigReader.Basic.waterLore.forEach(lore -> lores.add(GsonComponentSerializer.gson().serialize(MiniMessage.miniMessage().deserialize(lore.replace("{water_info}", string)))));
}
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
else if (namespacedID.contains("_stage_")){
nbtItem.setInteger("WaterAmount", water - 1);
if (water > 0) {
nbtItem.setInteger("WaterAmount", --water);
AdventureManager.playerSound(player, ConfigReader.Sounds.waterPotSource, ConfigReader.Sounds.waterPotKey);
waterPot(wateringCan.getWidth(), wateringCan.getLength(), block.getLocation().subtract(0,1,0), player.getLocation().getYaw());
PotUtil.waterPot(wateringCan.getWidth(), wateringCan.getLength(), block.getLocation().subtract(0, 1, 0), player.getLocation().getYaw());
}
if (ConfigReader.Message.hasWaterInfo)
AdventureManager.playerActionbar(player,
(ConfigReader.Message.waterLeft +
ConfigReader.Message.waterFull.repeat(water - 1) +
ConfigReader.Message.waterEmpty.repeat(wateringCan.getMax() - water + 1) +
ConfigReader.Message.waterFull.repeat(water) +
ConfigReader.Message.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Message.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water -1)));
.replace("{water}", String.valueOf(water)));
if (ConfigReader.Basic.hasWaterLore){
List<String> lores = nbtItem.getCompound("display").getStringList("Lore");
lores.clear();
String string =
(ConfigReader.Basic.waterLeft +
ConfigReader.Basic.waterFull.repeat(water - 1) +
ConfigReader.Basic.waterEmpty.repeat(wateringCan.getMax() - water + 1) +
ConfigReader.Basic.waterFull.repeat(water) +
ConfigReader.Basic.waterEmpty.repeat(wateringCan.getMax() - water) +
ConfigReader.Basic.waterRight)
.replace("{max_water}", String.valueOf(wateringCan.getMax()))
.replace("{water}", String.valueOf(water -1));
.replace("{water}", String.valueOf(water));
ConfigReader.Basic.waterLore.forEach(lore -> lores.add(GsonComponentSerializer.gson().serialize(MiniMessage.miniMessage().deserialize(lore.replace("{water_info}", string)))));
}
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
@@ -246,17 +247,17 @@ public class RightClick implements Listener {
}else {
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
AdventureManager.playerSound(player, ConfigReader.Sounds.useFertilizerSource, ConfigReader.Sounds.useFertilizerKey);
addFertilizer(fertilizerConfig, block.getLocation());
PotUtil.addFertilizer(fertilizerConfig, block.getLocation());
}
}else {
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
AdventureManager.playerSound(player, ConfigReader.Sounds.useFertilizerSource, ConfigReader.Sounds.useFertilizerKey);
addFertilizer(fertilizerConfig, block.getLocation());
PotUtil.addFertilizer(fertilizerConfig, block.getLocation());
}
}else if (namespacedID.contains("_stage_")){
if (!fertilizerConfig.isBefore()){
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
addFertilizer(fertilizerConfig, block.getLocation().subtract(0,1,0));
PotUtil.addFertilizer(fertilizerConfig, block.getLocation().subtract(0,1,0));
AdventureManager.playerSound(player, ConfigReader.Sounds.useFertilizerSource, ConfigReader.Sounds.useFertilizerKey);
}else {
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.beforePlant);
@@ -270,7 +271,7 @@ public class RightClick implements Listener {
Location location = event.getClickedBlock().getLocation();
for (Integration integration : ConfigReader.Config.integration)
if (!integration.canPlace(location, player)) return;
if (IAFurnitureUtil.isSprinkler(location.clone().add(0.5, 1.5, 0.5))) return;
if (FurnitureUtil.isSprinkler(location.clone().add(0.5, 1.5, 0.5))) return;
if (SprinklersPerChunk.isLimited(location)){
AdventureManager.playerMessage(player, ConfigReader.Message.prefix + ConfigReader.Message.sprinkler_limit.replace("{max}", String.valueOf(ConfigReader.Config.sprinklerLimit)));
return;
@@ -278,10 +279,10 @@ public class RightClick implements Listener {
Sprinkler sprinklerData = new Sprinkler(sprinkler.getRange(), 0);
sprinklerData.setPlayer(player.getName());
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
SimpleLocation simpleLocation = SimpleLocation.fromLocation(location.add(0,1,0));
SimpleLocation simpleLocation = LocUtil.fromLocation(location.add(0,1,0));
SprinklerManager.Cache.put(simpleLocation, sprinklerData);
SprinklerManager.RemoveCache.remove(simpleLocation);
IAFurnitureUtil.placeFurniture(sprinkler.getNamespacedID_2(),location);
FurnitureUtil.placeFurniture(sprinkler.getNamespacedID_2(),location);
AdventureManager.playerSound(player, ConfigReader.Sounds.placeSprinklerSource, ConfigReader.Sounds.placeSprinklerKey);
return;
}
@@ -293,7 +294,7 @@ public class RightClick implements Listener {
String namespacedID = customBlock.getNamespacedID();
if (namespacedID.contains("_stage_")){
Location location = block.getLocation().subtract(0,1,0);
Fertilizer fertilizer = PotManager.Cache.get(SimpleLocation.fromLocation(location));
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(location));
if (fertilizer != null){
Fertilizer config = ConfigReader.FERTILIZERS.get(fertilizer.getKey());
if (config == null) return;
@@ -308,7 +309,7 @@ public class RightClick implements Listener {
}
}else if(namespacedID.equals(ConfigReader.Basic.pot) || namespacedID.equals(ConfigReader.Basic.watered_pot)){
Location location = block.getLocation();
Fertilizer fertilizer = PotManager.Cache.get(SimpleLocation.fromLocation(block.getLocation()));
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(block.getLocation()));
if (fertilizer != null){
Fertilizer config = ConfigReader.FERTILIZERS.get(fertilizer.getKey());
String name = config.getName();
@@ -378,13 +379,14 @@ public class RightClick implements Listener {
int random = current.nextInt(cropInstance.getMin(), cropInstance.getMax() + 1);
World world = location.getWorld();
Location itemLoc = location.clone().add(0.5,0.2,0.5);
Fertilizer fertilizer = PotManager.Cache.get(SimpleLocation.fromLocation(location.clone().subtract(0,1,0)));
Fertilizer fertilizer = PotManager.Cache.get(LocUtil.fromLocation(location.clone().subtract(0,1,0)));
List<String> commands = cropInstance.getCommands();
if (commands != null)
for (String command : commands)
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command.replace("{player}", player.getName()));
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 (cropInstance.getOtherLoots() != null) cropInstance.getOtherLoots().forEach(s -> location.getWorld().dropItem(location.clone().add(0.5,0.2,0.5), CustomStack.getInstance(s).getItemStack()));
if (fertilizer != null){
if (fertilizer instanceof QualityCrop qualityCrop){
int[] weights = qualityCrop.getChance();
@@ -396,118 +398,18 @@ public class RightClick implements Listener {
else world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
}
}
else BreakBlock.normalDrop(cropInstance, random, itemLoc, world);
else DropUtil.normalDrop(cropInstance, random, itemLoc, world);
}
else BreakBlock.normalDrop(cropInstance, random, itemLoc, world);
else DropUtil.normalDrop(cropInstance, random, itemLoc, world);
}
else customBlock.getLoot().forEach(loot-> location.getWorld().dropItem(location.clone().add(0.5,0.2,0.5), loot));
CustomBlock.remove(location);
AdventureManager.playerSound(player, ConfigReader.Sounds.harvestSource, ConfigReader.Sounds.harvestKey);
if(cropInstance.getReturnStage() != null){
CustomBlock.place(cropInstance.getReturnStage(), location);
CropManager.Cache.put(location, player.getName());
}
}
}
}
@EventHandler
public void onQuit(PlayerQuitEvent event){
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());
PotManager.Cache.put(SimpleLocation.fromLocation(location), qualityCrop);
}else if (fertilizerConfig instanceof SpeedGrow config){
SpeedGrow speedGrow = new SpeedGrow(config.getKey(), config.getTimes(),config.getChance(), config.isBefore());
PotManager.Cache.put(SimpleLocation.fromLocation(location), speedGrow);
}else if (fertilizerConfig instanceof RetainingSoil config){
RetainingSoil retainingSoil = new RetainingSoil(config.getKey(), config.getTimes(),config.getChance(), config.isBefore());
PotManager.Cache.put(SimpleLocation.fromLocation(location), retainingSoil);
}
if (fertilizerConfig.getParticle() != null)
location.getWorld().spawnParticle(fertilizerConfig.getParticle(), location.add(0.5,1.3,0.5), 5,0.2,0.2,0.2);
}
/**
* 水壶浇水判定
* @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);
int extend = width / 2;
if (yaw < 45 && yaw > -135) {
if (yaw > -45) {
for (int i = -extend; i <= extend; i++) {
Location tempLoc = location.clone().add(i, 0, -1);
for (int j = 0; j < length; j++){
tempLoc.add(0,0,1);
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
if(customBlock != null){
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
CustomBlock.remove(tempLoc);
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
}
}
}
}
}
else {
for (int i = -extend; i <= extend; i++) {
Location tempLoc = location.clone().add(-1, 0, i);
for (int j = 0; j < length; j++){
tempLoc.add(1,0,0);
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
if(customBlock != null){
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
CustomBlock.remove(tempLoc);
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
}
}
}
}
}
}
else {
if (yaw > 45 && yaw < 135) {
for (int i = -extend; i <= extend; i++) {
Location tempLoc = location.clone().add(1, 0, i);
for (int j = 0; j < length; j++){
tempLoc.subtract(1,0,0);
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
if(customBlock != null){
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
CustomBlock.remove(tempLoc);
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
}
}
}
}
}
else {
for (int i = -extend; i <= extend; i++) {
Location tempLoc = location.clone().add(i, 0, 1);
for (int j = 0; j < length; j++){
tempLoc.subtract(0,0,1);
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
if(customBlock != null){
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
CustomBlock.remove(tempLoc);
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
}
}
}
SimpleLocation simpleLocation = LocUtil.fromLocation(location);
CropManager.RemoveCache.remove(simpleLocation);
CropManager.Cache.put(simpleLocation, player.getName());
}
}
}

View File

@@ -27,6 +27,7 @@ public class Crop {
private String giant;
private List<Requirement> requirements;
private List<String> seasons;
private List<String> otherLoots;
private String returnStage;
private final int min;
private final int max;
@@ -37,6 +38,7 @@ public class Crop {
private boolean dropIALoot;
private List<String> commands;
private double growChance;
private boolean isBlock;
public Crop(int min, int max){
this.min = min;
@@ -61,6 +63,8 @@ public class Crop {
public double getSkillXP() {return skillXP;}
public boolean doesDropIALoot() {return dropIALoot;}
public double getGrowChance() {return growChance;}
public boolean isBlock() {return isBlock;}
public List<String> getOtherLoots() {return otherLoots;}
public void setReturnStage(String stage){ this.returnStage = stage; }
public void setGiant(String giant) { this.giant = giant; }
@@ -74,4 +78,6 @@ public class Crop {
public void setSkillXP(double skillXP) {this.skillXP = skillXP;}
public void setDropIALoot(boolean dropIALoot) {this.dropIALoot = dropIALoot;}
public void setGrowChance(double growChance) {this.growChance = growChance;}
public void setIsBlock(boolean isBlock) {this.isBlock = isBlock;}
public void setOtherLoots(List<String> otherLoots) {this.otherLoots = otherLoots;}
}

View File

@@ -17,8 +17,6 @@
package net.momirealms.customcrops.objects;
import org.bukkit.Location;
import java.util.Objects;
public class SimpleLocation {
@@ -35,15 +33,6 @@ 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;}

View File

@@ -0,0 +1,31 @@
package net.momirealms.customcrops.utils;
import dev.lone.itemsadder.api.CustomStack;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.objects.Crop;
import org.bukkit.Location;
import org.bukkit.World;
public class DropUtil {
/**
* 没有品质肥料下的普通掉落
* @param cropInstance 农作物
* @param random 随机农作物数量
* @param itemLoc 掉落物位置
* @param world 世界
*/
public static void normalDrop(Crop cropInstance, int random, Location itemLoc, World world) {
for (int i = 0; i < random; i++){
double ran = Math.random();
if (ran < ConfigReader.Config.quality_1){
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_1()).getItemStack());
}else if(ran > ConfigReader.Config.quality_2){
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_2()).getItemStack());
}else {
world.dropItem(itemLoc, CustomStack.getInstance(cropInstance.getQuality_3()).getItemStack());
}
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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 dev.lone.itemsadder.api.CustomFurniture;
import net.momirealms.customcrops.ConfigReader;
import org.bukkit.Location;
import org.bukkit.Rotation;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import java.util.Random;
public class FurnitureUtil {
static Rotation[] rotations4 = {Rotation.NONE, Rotation.FLIPPED, Rotation.CLOCKWISE, Rotation.COUNTER_CLOCKWISE};
static Rotation[] rotations8 = {Rotation.NONE, Rotation.FLIPPED, Rotation.CLOCKWISE, Rotation.COUNTER_CLOCKWISE,
Rotation.CLOCKWISE_45, Rotation.CLOCKWISE_135, Rotation.FLIPPED_45, Rotation.COUNTER_CLOCKWISE_45};
/**
* 在指定位置放置家具
* @param name 物品名
* @param location 位置
*/
public static void placeFurniture(String name, Location location){
CustomFurniture.spawn(name, location.getBlock());
}
/**
* 在指定位置放置农作物
* @param name 农作物命名空间id
* @param location 位置
*/
public static void placeCrop(String name, Location location){
CustomFurniture customFurniture = CustomFurniture.spawn(name, location.getBlock());
Entity entity = customFurniture.getArmorstand();
if (ConfigReader.Config.rotation && entity instanceof ItemFrame itemFrame){
if (ConfigReader.Config.variant4) itemFrame.setRotation(rotations4[new Random().nextInt(rotations4.length-1)]);
else itemFrame.setRotation(rotations8[new Random().nextInt(rotations8.length-1)]);
}
}
/**
* 获取指定位置的家具名
* 仅限加载中的区块
* @param location 位置
* @return 是/否
*/
public static String getNamespacedID(Location location){
CustomFurniture furniture = getFurniture(location);
if (furniture != null){
return furniture.getNamespacedID();
}else {
return null;
}
}
/**
* 获取指定位置的家具名
* 仅限加载中的区块
* @param location 位置
* @return 是/否
*/
public static CustomFurniture getFurniture(Location location){
for(Entity entity : location.getWorld().getNearbyEntities(location,0,0,0)){
CustomFurniture furniture = CustomFurniture.byAlreadySpawned(entity);
if(furniture != null) return furniture;
}
return null;
}
/**
* 判断指定位置的家具是不是洒水器
* @param location 位置
* @return 是/否
*/
public static boolean isSprinkler(Location location){
String furniture = getNamespacedID(location);
if (furniture != null) return ConfigReader.SPRINKLERS.get(furniture) != null;
else return false;
}
}

View File

@@ -1,55 +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 dev.lone.itemsadder.api.CustomFurniture;
import net.momirealms.customcrops.ConfigReader;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
public class IAFurnitureUtil {
/**
* 在指定位置放置家具
* @param name 物品名
* @param location 位置
*/
public static void placeFurniture(String name, Location location){
CustomFurniture.spawn(name, location.getBlock());
}
/**
* 判断指定位置的盔甲架是不是洒水器
* 仅限加载中的区块
* @param location 位置
* @return 是/否
*/
public static String getFromLocation(Location location){
for(Entity entity : location.getWorld().getNearbyEntities(location,0,0,0)){
CustomFurniture furniture = CustomFurniture.byAlreadySpawned(entity);
if(furniture != null) return furniture.getNamespacedID();
}
return null;
}
public static boolean isSprinkler(Location location){
String furniture = getFromLocation(location);
if (furniture != null) return ConfigReader.SPRINKLERS.get(furniture) != null;
else return false;
}
}

View File

@@ -0,0 +1,15 @@
package net.momirealms.customcrops.utils;
import net.momirealms.customcrops.objects.SimpleLocation;
import org.bukkit.Location;
public class LocUtil {
/**
* 将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());
}
}

View File

@@ -0,0 +1,111 @@
package net.momirealms.customcrops.utils;
import dev.lone.itemsadder.api.CustomBlock;
import net.momirealms.customcrops.ConfigReader;
import net.momirealms.customcrops.datamanager.PotManager;
import net.momirealms.customcrops.fertilizer.Fertilizer;
import net.momirealms.customcrops.fertilizer.QualityCrop;
import net.momirealms.customcrops.fertilizer.RetainingSoil;
import net.momirealms.customcrops.fertilizer.SpeedGrow;
import net.momirealms.customcrops.objects.SimpleLocation;
import org.bukkit.Location;
import org.bukkit.Particle;
public class PotUtil {
/**
* 水壶浇水判定
* @param width 宽度
* @param length 长度
* @param location 位置
* @param yaw 视角
*/
public static 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);
int extend = width / 2;
if (yaw < 45 && yaw > -135) {
if (yaw > -45) {
for (int i = -extend; i <= extend; i++) {
Location tempLoc = location.clone().add(i, 0, -1);
for (int j = 0; j < length; j++){
tempLoc.add(0,0,1);
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
if(customBlock != null){
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
CustomBlock.remove(tempLoc);
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
}
}
}
}
}
else {
for (int i = -extend; i <= extend; i++) {
Location tempLoc = location.clone().add(-1, 0, i);
for (int j = 0; j < length; j++){
tempLoc.add(1,0,0);
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
if(customBlock != null){
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
CustomBlock.remove(tempLoc);
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
}
}
}
}
}
}
else {
if (yaw > 45 && yaw < 135) {
for (int i = -extend; i <= extend; i++) {
Location tempLoc = location.clone().add(1, 0, i);
for (int j = 0; j < length; j++){
tempLoc.subtract(1,0,0);
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
if(customBlock != null){
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
CustomBlock.remove(tempLoc);
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
}
}
}
}
}
else {
for (int i = -extend; i <= extend; i++) {
Location tempLoc = location.clone().add(i, 0, 1);
for (int j = 0; j < length; j++){
tempLoc.subtract(0,0,1);
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(tempLoc.getBlock());
if(customBlock != null){
if(customBlock.getNamespacedID().equals(ConfigReader.Basic.pot)){
CustomBlock.remove(tempLoc);
CustomBlock.place(ConfigReader.Basic.watered_pot, tempLoc);
}
}
}
}
}
}
}
/**
* 添加肥料
* @param fertilizerConfig 肥料配置
* @param location 种植盆位置
*/
public static void addFertilizer(Fertilizer fertilizerConfig, Location location) {
if (fertilizerConfig instanceof QualityCrop config){
QualityCrop qualityCrop = new QualityCrop(config.getKey(), config.getTimes(), config.getChance(), config.isBefore());
PotManager.Cache.put(LocUtil.fromLocation(location), qualityCrop);
}else if (fertilizerConfig instanceof SpeedGrow config){
SpeedGrow speedGrow = new SpeedGrow(config.getKey(), config.getTimes(),config.getChance(), config.isBefore());
PotManager.Cache.put(LocUtil.fromLocation(location), speedGrow);
}else if (fertilizerConfig instanceof RetainingSoil config){
RetainingSoil retainingSoil = new RetainingSoil(config.getKey(), config.getTimes(),config.getChance(), config.isBefore());
PotManager.Cache.put(LocUtil.fromLocation(location), retainingSoil);
}
if (fertilizerConfig.getParticle() != null) location.getWorld().spawnParticle(fertilizerConfig.getParticle(), location.add(0.5,1.3,0.5), 5,0.2,0.2,0.2);
}
}

View File

@@ -1,12 +1,54 @@
#Don't change
config-version: 3
config-version: '4'
#Want to sell the crops?
#Try this plugin: https://www.spigotmc.org/resources/shipping-bin.104591/
#You can use it with a command binding to an ItemsAdder furniture
#Shipping Bin is similar to the way how players sell items in Stardrew Valley
config:
#english spanish chinese
# lang: english / spanish / chinese
lang: english
# mode: tripwire / item_frame
# This option requires a server restart
# ------------ tripwire ------------
# Advantage:
# ● async check, less lag
# ● Real block hitbox like vanilla
#
# Disadvantage:
# ● limited amount
# ● visual problem when breaking crops
# ● Can't remove tripwire break sound
#
# ------------ item_frame ------------
# Advantage:
# ● unlimited amount
# ● No tripwire break sound
# ● Rotation
#
# Disadvantage:
# ● entities are very laggy(loading every 5 item frames need 0.01 mspt)
# ● spigot optimized the view distance of entities
# ● crops would go missing if server is lagging
# ● No real block hitbox
# ● itemsAdder loot system doesn't apply to furnitures.
#
crop-mode: tripwire
# Should crops be planted in random rotation?
# only works in item_frame mode
rotation:
enable: false
# 4 / 8
variant: 4
integration:
#integration to prevent other players' grief
Residence: false
@@ -28,62 +70,64 @@ config:
#Mode 1:
# Crops in loaded chunks will grow
#Mode 2:
# Online players' crops will grow
#Mode 3:
# Recommended
# Mode 1 + Mode 2
#Mode 4:
# Please disable season in this mode!
# All the crops will grow
# Mode 1:
# Crops in loaded chunks will grow
# Mode 2:
# Online players' crops will grow
# Mode 3:
# Recommended Mode 1 + Mode 2
# Mode 4:
# ● Please disable season in this mode!
# ● All the crops will grow
grow-mode: 3
#The time to start growing(ticks)
#1000ticks is 7am in game. (0-23999)
#Sprinklers will work after all crops finish growing
# The time to start growing(ticks)
# 1000ticks is 7am in game. (0-23999)
# Sprinklers will work after all crops finish growing
grow-time:
- 1000
#Time in random a single crop need to growseconds
#This prevents a large amount of crops grow at the same time
#Large amount of block replacement would cause lag.
# Time in random a single crop need to growseconds
# This prevents a large amount of crops grow at the same time
# Large amount of block replacement would cause lag.
time-to-grow: 60
#Similar to "time-to-grow", this prevent all sprinklers work at the same time
# Similar to "time-to-grow", this prevent all sprinklers work at the same time
time-to-work: 30
#Async Time Check (requires restart)
#Crops might not grow when using async.
#It is not really necessary to be Async
# Async Time Check (requires restart)
# Crops might not grow when using async.
# It is not really necessary to be Async
async-time-check: false
#Worlds where crops would grow
# Worlds where crops would grow
whitelist-worlds:
- world
#Should all the worlds' crops grow?
#This is useful for per player per world server.
#In this mode, whitelist world can only have one as the standard of time & season judgment.
# Should all the worlds' crops grow?
# This is useful for per player per world server.
# In this mode, whitelist world can only have one for time & season judgment.
all-world-grow: false
# How does gigantic work?
# In stardrew valley, crops will still absorb water every day after it is ripe to be gigantic
# But you can give it only one chance to be gigantic(This is also good for performance)
gigantic-only-one-try: false
quality:
#If disabled, you need to configurate the loot in ItemsAdder config
# If disabled, you need to configurate the loots in ItemsAdder config
enable: true
#Default ratio
# Default ratio
default-ratio: 17/2/1
#Water Amount to refill when using water bucket
# Water Amount to refill when using water bucket
sprinkler-refill: 2
#Water Amount to refill with a sigle click to water block
# Water Amount to refill with a single click to water block
water-can-refill: 1
#Can watering-can add water to sprinklers?
# Can watering-can add water to sprinklers?
water-can-add-water-to-sprinkler: true
#Should particles be displayed when using watering can?
# Should particles be displayed when using watering can?
water-particles: true
#Will bone meal accelerate the growth of crop
# Will bone meal accelerate the growth of crop
bone-meal:
enable: true
chance: 0.5
@@ -91,9 +135,9 @@ config:
#Should we limit the max amount of crops and sprinkler in one chunk
#Recommended to enable because ItemsAdder might throw StackOverFlow
#when there are too many custom blocks in one chunk
# Should we limit the max amount of crops and sprinkler in one chunk
# Recommended to enable because ItemsAdder might throw StackOverFlow
# when there are too many custom blocks in one chunk
limit:
enable: true
crop: 64
@@ -101,13 +145,13 @@ config:
#can player harvest crops with right click?
#if set "false" crops can't be harvested repeatedly
# can player harvest crops with right click?
# if set "false" crops can't be harvested repeatedly
right-click-harvest: true
#If "right-click-harvest" is true
#Should player be allowed to harvest with items in hand
# If "right-click-harvest" is true
# Should player must harvest with empty hands?
harvest-with-empty-hand: true
#Should player be prevented from planting if wrong season
# Should player be prevented from planting if wrong season
prevent-plant-if-wrong-season: true
#Should notify player of the wrong season?
# Should player be notified of the wrong season?
should-notify-if-wrong-season: true

View File

@@ -13,10 +13,18 @@ crops:
2: customcrops:tomato_silver_star
3: customcrops:tomato_golden_star
#When harvesting, should the crop drop the loots from ItemsAdder too
#This is useful for dropping seeds and other items
#When you break the crop, the event will be handled by ItemsAdder & Customcrops so IA loots would be certainly dropped
#When you right click the crop, the event will only be handled by Customcrops so IA loots would be optional
#**right click** harvest, should the crop drop the loots from ItemsAdder too
#This is useful for dropping seeds and other items(only works in tripwire mode, furnitures don't support loot at the moment)
drop-ia-loots: false
#**right click** harvest, should the crop drop other loots
#This is useful for dropping seeds and other items(Works in both tripwire/item_frame mode)
drop-other-loots:
- customcrops:tomato_seeds
#optional
#The chance that a crop grow a stage at grow time
grow-chance: 0.9
@@ -27,6 +35,12 @@ crops:
block: customcrops:gigantic_tomato
chance: 0.01
#If you want to use item_frame/armor_stand for gigantic crops
#You should config like this
#gigantic:
# furniture: customcrops:gigantic_tomato
# chance: 0.01
#optional
commands:
- 'say {player} harvested a tomato! lol'

View File

@@ -1,7 +1,7 @@
name: CustomCrops
version: '${version}'
main: net.momirealms.customcrops.CustomCrops
api-version: 1.16
api-version: 1.17
authors: [ XiaoMoMi ]
depend:
- ItemsAdder

View File

@@ -1,9 +1,50 @@
#Don't change
config-version: 1
#请不要修改此值
config-version: '4'
config:
#插件兼容
# 语言: english / spanish / chinese
lang: chinese
# 模式: tripwire / item_frame
# 此设置需要重启服务器
# ------------ tripwire ------------
# 优势:
# ● 几乎完全异步
# ● 有原版一样的真实碰撞体积
#
# 劣势:
# ● 拌线数量限制127
# ● 破坏拌线产生的视觉问题
# ● 无法移除破坏拌线的音效
#
# ------------ item_frame ------------
# 优势:
# ● 无限制农作物数量
# ● 支持旋转
#
# 劣势:
# ● 展示框是实体,相对较卡
# ● Spigot优化了实体可见距离
# ● 没有真实的碰撞体积
# ● ItemsAdder的战利品系统无法应用于家具
#
crop-mode: tripwire
# 农作物会有随机的朝向吗?
# 这只在展示框模式中生效
rotation:
enable: false
# 4 / 8
variant: 4
integration:
#领地保护
Residence: false
WorldGuard: false
Kingdoms: false
@@ -11,91 +52,99 @@ config:
PlotSquared: false
Towny: false
Lands: false
GriefPrevention: false
CrashClaim: false
#增加技能经验
AureliumSkills: false
mcMMO: false
MMOCore: false
EcoSkills: false
#季节同步
RealisticSeasons: false
#生长时间点(tick)
#1000代表上午7点农作物陆续开始生长
#洒水器将会在农作物全部完成生长后开始工作
# Mode 1:
# ● 农作物仅在加载中的区块生长
# Mode 2:
# ● 在线玩家种植的农作物会生长
# Mode 3:
# ● (推荐) Mode 1 + Mode 2
# Mode 4:
# ● 在这个模式下请关闭季节
# ● 所有数据内的农作物都会生长
grow-mode: 3
# 开始生长的时间(ticks)
# 1000ticks 代表游戏时间 7点 (0-23999)
# 洒水器将在所有农作物完成生长后开始工作
grow-time:
- 1000
#生长点后农作物成长所需的时间(秒)
#农作物将在60秒内随机完成生长以避免在短时间内大量方块替换造成卡顿
#但也不建议设置过长时间,否则内存无法及时释放,区块会被持续加载
#配合上方的默认时间点意思为每天上午7点后农作物将在60秒内完成生长过程
# 农作物将在开始生长的时间点后多少秒内完成生长seconds
# 这是为了避免大量农作物在同一时间点进行判断和方块替换,否则会造成卡顿
# 假如你有100个农作物默认配置代表在游戏时间7点后的现实时间60秒内100个农作物会在这60秒内随机时间点完成生长
time-to-grow: 60
#农作物全部完成生长后洒水器工作所需的时间
# 和上面的配置类似,只不过这一次是洒水器工作的时间
time-to-work: 30
#产物品质
quality:
#若不启用则植物成熟阶段会掉落IA配置里的loot
#如果关闭产物品质需要在IA物品配置内自行添加最后一阶段掉落物
enable: true
#默认品质权重比
default-ratio: 17/2/1
#异步时间检测,此设置需要重启生效
#启用异步时间检测会带来更好的性能但是可能会因为服务器的跳tick原因错过一些生长时间点
# 异步时间检测 (需要重启)
# 服务端可能因为某些原因跳tick所以异步模式下可能会错过生长判断
# 异步检测不是很有必要,同步的检测也不会造成性能问题,除非你设置了几百个白名单世界
async-time-check: false
#使用一次水桶可以补充几个洒水器水槽
sprinkler-refill: 2
#水壶右键一次水方块能补充多少水量
water-can-refill: 1
#是否可以用水壶为洒水器加水
water-can-add-water-to-sprinkler: true
#使用水的时候是否产生粒子效果
water-particles: true
#生长生效的世界
# 哪些世界的农作物能够生长(即白名单世界)
whitelist-worlds:
- world
# 所有世界的农作物都生长吗?
# 此选项适用于单玩家单世界服务器.
# 这种模式下你只能填写一个白名单世界作为时间,季节的判断依据.
all-world-grow: false
# 农作物巨大化是否仅进行一次尝试
# 如果你喜欢星露谷模式,农作物将在成熟后继续吸收水分,每天都有概率巨大化
# 如果你喜欢起源模式,你可以设置巨大化农作物为金农作物,并且仅有一次成为金农作物的机会
gigantic-only-one-try: false
#每个区块最大农作物数量和洒水器数量
#是否启用限制
quality:
# 如果禁用品质系统你需要在ItemsAdder的配置文件中单独设置每个农作物的掉落物
enable: true
# 默认品质比例
default-ratio: 17/2/1
# 使用水桶右键洒水器能够补充几格水量
sprinkler-refill: 2
# 使用水壶右键水方块的时候能够为水壶补充多少水量
water-can-refill: 1
# 能否使用水壶为洒水器加水
water-can-add-water-to-sprinkler: true
# 使用水壶的时候发送水花粒子效果吗
water-particles: true
# 是否启用骨粉特性
bone-meal:
enable: true
chance: 0.5
success-particle: VILLAGER_HAPPY
# 区块限制最大农作物和洒水器数量
# 建议开启限制因为一个区块内过多的农作物方块会导致IA插件报错Stack Overflow
limit:
enable: true
crop: 64
sprinkler: 8
#记录生长判断和洒水所需的时间(测试性能用)
log-time-consume: false
#Mode 1:
# 加载中区块的农作物生长
#Mode 2:
# 在线玩家的农作物生长
#Mode 3:
# Mode 1 + Mode 2
#Mode 4:
# 所有农作物生长
# 可能会造成卡顿!不建议使用此模式
grow-mode: 3
#是否所有加载中的世界都要进行生长判断
#本选项适用于使用玩家独立世界的服务器
#因为有大量世界所以无法通过添加白名单世界的方式生长
#在此选项开启的状态下,白名单世界只能填写一个
#作为所有世界农作物生长的时间、季节判断依据
all-world-grow: false
#玩家是否能右键收获
# 玩家是否可以使用右键收获农作物
# 如果禁用右键收获,那么重复收获的特性也会被关闭
right-click-harvest: true
#玩家是否需要空手右键收获
# 玩家是否必须要空手才能右键收获
harvest-with-empty-hand: true
#是否阻止玩家在错误的季节种植
# 是否阻止玩家在错误季节的种植
prevent-plant-if-wrong-season: true
#是否告知玩家这是错误的季节
# 是否告知玩家这是错误的季节
should-notify-if-wrong-season: true
#骨粉设置
bone-meal:
enable: true
chance: 0.5
success-particle: VILLAGER_HAPPY

View File

@@ -3,45 +3,73 @@
#农作物生长阶段请以 _stage_X 结尾
#生长阶段从1开始依次累加
#若无法理解可以参考范例配置文件
crops:
tomato:
#收获时获取的基础数量
#收获时候掉落多少个农产品
amount: 1~4
#农作物收获得到的三种品质
#品质农作物掉落
quality:
1: customcrops:tomato
2: customcrops:tomato_silver_star
3: customcrops:tomato_golden_star
#农作物每个时间点生长一个阶段的概率
#不设置默认为1
grow-chance: 0.9
#收获的时候是否额外掉落IA配置里的战利品
#可用于最后一阶段掉落种子等操作
#当你破坏农作物的时候这个事件会同时被ItemsAdder和CustomCrops处理所以IA配置内的掉落物会被必定掉落
#当你右键收获农作物的时候这个事件仅被CustomCrops处理因此是否掉落IA配置内的掉落物为可选项目
#右键收获的时候是否掉落IA配置内的掉落物
#这对于那些需要农作物掉落额外物品的用户帮助很大,比如掉落种子(但是此设置仅适用于拌线模式因为IA的家具没有掉落物系统)
drop-ia-loots: false
#巨大化植物,以极低的概率生长为另一种形态
#右键收获的时候是否额外掉落IA物品
#这对于那些需要农作物掉落额外物品的用户帮助很大,比如掉落种子(这是本插件提供的额外掉落物系统独立于IA存在所以拌线和展示框模式都适用)
drop-other-loots:
- customcrops:tomato_seeds
#可选
#农作物在某个生长点的生长概率
#比如你可以设置一天在0点6点12点18点进行生长判断不建议设置太多每次生长概率为0.25,这样即可增大玩家加载到农作物区块的概率
#但是同一时间点种植的农作物,可能会出现一个已经成熟,而另一个还在第一阶段(如果你喜欢这种模式,可以这样设置)
grow-chance: 0.9
#可选
#巨大化农作物
gigantic:
block: customcrops:gigantic_tomato
chance: 0.01
#收获时候执行指令
#如果你想要使用展示框/盔甲架作为巨大化农作物的载体
#你需要像这样填写注意IA的API不提供solid屏障方块的放置
#所以家具模式下的巨大化作物无法被屏障包裹
#gigantic:
# furniture: customcrops:gigantic_tomato
# chance: 0.01
#可选
commands:
- 'say {player} harvested a tomato! lol'
#生长季节
#可选
#如果你启用了技能插件的兼容,那么可以设置收获该农作物的经验值
#skill-xp: 100
#可选
#若不填写则农作物四季生长
season:
- summer
- autumn
#种植所需的条件
#可选
#一些农作物种植的其他条件
requirements:
#适宜的生长高度
yPos:
- 50~100
- 150~200
#适宜的生长群系
biome:
- minecraft:plains
#适宜的世界
world:
- world
#种植此农作物需要玩家有什么权限
permission: 'customcrops.plant.tomato'
cabbage:
@@ -62,13 +90,14 @@ crops:
1: customcrops:grape
2: customcrops:grape_silver_star
3: customcrops:grape_golden_star
#空手收获后返回第几个生长状态
#可选
#右键收获的时候农作物返回哪一个阶段
return: customcrops:grape_stage_4
season:
- autumn
corn:
amount: 1~2
amount: 2~3
quality:
1: customcrops:corn
2: customcrops:corn_silver_star

View File

@@ -1,60 +0,0 @@
#MiniMessage Format
#https://docs.adventure.kyori.net/minimessage/format.html
messages:
prefix: '<gradient:#ff206c:#fdee55>[CustomCrops] </gradient>'
reload: '<white>重载成功! 耗时 <green>{time}ms'
no-perm: '<red>权限不足!'
lack-args: '<white>参数不足!'
wrong-args: '<white>参数错误!'
spring: '春'
summer: '夏'
autumn: '秋'
winter: '冬'
sprinkler-limit: '<white>此区块的洒水器已到达上限{max}'
crop-limit: '<white>此区块的农作物数量已到达上限{max}'
not-configed: '<white>此种子未在配置文件中配置!'
bad-Y: '<white>此高度不适合这种农作物生长!'
bad-biome: '<white>此生物群系不适合这种农作物生长!'
bad-perm: '<white>你还没有权限种植这种农作物呢!'
bad-world: '<white>这个农作物无法在这个世界生长!'
bad-season: '<white>当前季节不适合这种农作物生长!'
force-grow: '<white>成功强制 {world} 的农作物生长!'
force-water: '<white>成功强制 {world} 的洒水器洒水!'
force-save: '<white>成功强制保存缓存信息!'
back-up: '<white>已完成数据备份!'
set-season: '<white>成功切换世界 {world} 的季节为 {season}!'
before-plant: '<white>这种肥料必须在种植前使用!'
no-season: '当前世界没有季节'
#全息信息显示
hologram:
#农作物肥料信息
grow-info:
enable: true
#悬浮信息高度偏移
y-offset: 0.8
#悬浮信息持续时间(秒)
duration: 1
#悬浮信息内容
#可用变量 {fertilizer}肥料名 {times}剩余生效次数 {max_times}最大生效次数
text: '<font:customcrops:default>{fertilizer} </font><white>{times}<gray>/<white>{max_times}'
#洒水器信息
sprinkler-info:
enable: true
y-offset: -0.2
duration: 1
#可用变量 {water}当前水量 {max_water}最大蓄水量
left: '<font:customcrops:default>뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅</font>'
actionbar:
#使用水壶的时候是否发送actionbar
watering-can:
enable: true
#可用变量 {water}当前水量 {max_water}最大蓄水量
left: '<font:customcrops:default>뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅</font>'