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

1.5.19-PRE1

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

View File

@@ -1,146 +0,0 @@
#############################################
#############################################
## ##
## 本配置文件为范例 ##
## 仅作为参考测试用 ##
## ##
#############################################
#############################################
info:
namespace: customcrops
items:
cabbage_stage_1:
display_name: ""
resource:
generate: false
material: PAPER
model_path: cabbage/stage_1
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
cabbage_stage_2:
display_name: ""
resource:
generate: false
material: PAPER
model_path: cabbage/stage_2
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
cabbage_stage_3:
display_name: ""
resource:
generate: false
material: PAPER
model_path: cabbage/stage_3
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
cabbage_stage_4:
display_name: ""
resource:
generate: false
material: PAPER
model_path: cabbage/stage_4
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
cabbage_seeds:
display_name: "卷心菜种子"
resource:
generate: false
material: PAPER
model_path: cabbage/cabbage_seeds
cabbage:
display_name: "卷心菜"
resource:
generate: false
material: APPLE
model_path: cabbage/cabbage
cabbage_silver_star:
display_name: "卷心菜"
resource:
generate: false
material: APPLE
model_path: cabbage/cabbage_silver_star
cabbage_golden_star:
display_name: "卷心菜"
resource:
generate: false
material: APPLE
model_path: cabbage/cabbage_golden_star
gigantic_cabbage:
display_name: "巨型卷心菜"
resource:
generate: false
material: PAPER
model_path: cabbage/gigantic_cabbage
specific_properties:
block:
placed_model:
type: REAL_TRANSPARENT
loots:
blocks:
cabbage_stage_1:
type: customcrops:cabbage_stage_1
items:
result_1:
item: customcrops:cabbage_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
cabbage_stage_2:
type: customcrops:cabbage_stage_2
items:
result_1:
item: customcrops:cabbage_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
cabbage_stage_3:
type: customcrops:cabbage_stage_3
items:
result_1:
item: customcrops:cabbage_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
# cabbage_stage_4:
# type: customcrops:cabbage_stage_4
# items:
# result_1:
# item: customcrops:cabbage
# min_amount: 1
# max_amount: 3
# chance: 100

View File

@@ -1,63 +0,0 @@
info:
namespace: customcrops
categories:
customcrops:
enabled: true
icon: customcrops:tomato_seeds
name: '自定义农作物'
items:
- customcrops:pot
- customcrops:watered_pot
- customcrops:sprinkler_1_item
- customcrops:sprinkler_2_item
- customcrops:greenhouse_glass
- customcrops:soil_detector
- customcrops:watering_can_1
- customcrops:watering_can_2
- customcrops:watering_can_3
- customcrops:watering_can_4
- customcrops:speed_1
- customcrops:speed_2
- customcrops:speed_3
- customcrops:retaining_1
- customcrops:retaining_2
- customcrops:retaining_3
- customcrops:quality_1
- customcrops:quality_2
- customcrops:quality_3
- customcrops:tomato
- customcrops:tomato_silver_star
- customcrops:tomato_golden_star
- customcrops:tomato_seeds
- customcrops:tomato_stage_1
- customcrops:tomato_stage_2
- customcrops:tomato_stage_3
- customcrops:tomato_stage_4
- customcrops:gigantic_tomato
- customcrops:cabbage
- customcrops:cabbage_silver_star
- customcrops:cabbage_golden_star
- customcrops:cabbage_seeds
- customcrops:cabbage_stage_1
- customcrops:cabbage_stage_2
- customcrops:cabbage_stage_3
- customcrops:cabbage_stage_4
- customcrops:gigantic_cabbage
- customcrops:grape
- customcrops:grape_silver_star
- customcrops:grape_golden_star
- customcrops:grape_seeds
- customcrops:grape_stage_1
- customcrops:grape_stage_2
- customcrops:grape_stage_3
- customcrops:grape_stage_4
- customcrops:grape_stage_5
- customcrops:grape_stage_6
- customcrops:corn
- customcrops:corn_silver_star
- customcrops:corn_golden_star
- customcrops:corn_seeds
- customcrops:corn_stage_1
- customcrops:corn_stage_2
- customcrops:corn_stage_3
- customcrops:corn_stage_4

View File

@@ -1,137 +0,0 @@
#############################################
#############################################
## ##
## 本配置文件为范例 ##
## 仅作为参考测试用 ##
## ##
#############################################
#############################################
info:
namespace: customcrops
items:
corn_stage_1:
display_name: ""
resource:
generate: false
material: PAPER
model_path: corn/stage_1
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
corn_stage_2:
display_name: ""
resource:
generate: false
material: PAPER
model_path: corn/stage_2
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
corn_stage_3:
display_name: ""
resource:
generate: false
material: PAPER
model_path: corn/stage_3
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
corn_stage_4:
display_name: ""
resource:
generate: false
material: PAPER
model_path: corn/stage_4
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
corn_seeds:
display_name: "玉米种子"
resource:
generate: false
material: PAPER
model_path: corn/corn_seeds
corn:
display_name: "玉米"
resource:
generate: false
material: APPLE
model_path: corn/corn
corn_silver_star:
display_name: "玉米"
resource:
generate: false
material: APPLE
model_path: corn/corn_silver_star
corn_golden_star:
display_name: "玉米"
resource:
generate: false
material: APPLE
model_path: corn/corn_golden_star
loots:
blocks:
corn_stage_1:
type: customcrops:corn_stage_1
items:
result_1:
item: customcrops:corn_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
corn_stage_2:
type: customcrops:corn_stage_2
items:
result_1:
item: customcrops:corn_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
corn_stage_3:
type: customcrops:corn_stage_3
items:
result_1:
item: customcrops:corn_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
# corn_stage_4:
# type: customcrops:corn_stage_4
# items:
# result_1:
# item: customcrops:corn
# min_amount: 1
# max_amount: 1
# chance: 100
# ignore_fortune: true

View File

@@ -1,186 +0,0 @@
#############################################
#############################################
## ##
## 本配置文件为范例 ##
## 仅作为参考测试用 ##
## ##
#############################################
#############################################
info:
namespace: customcrops
items:
grape_stage_1:
display_name: ""
resource:
generate: false
material: PAPER
model_path: grape/stage_1
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
grape_stage_2:
display_name: ""
resource:
generate: false
material: PAPER
model_path: grape/stage_2
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
grape_stage_3:
display_name: ""
resource:
generate: false
material: PAPER
model_path: grape/stage_3
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
grape_stage_4:
display_name: ""
resource:
generate: false
material: PAPER
model_path: grape/stage_4
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
grape_stage_5:
display_name: ""
resource:
generate: false
material: PAPER
model_path: grape/stage_5
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
grape_stage_6:
display_name: ""
resource:
generate: false
material: PAPER
model_path: grape/stage_6
specific_properties:
block:
placed_model:
type: REAL_WIRE
cancel_drop: true
sound:
place:
name: block.azalea.place
break:
name: block.azalea.break
grape_seeds:
display_name: "葡萄种子"
resource:
generate: false
material: PAPER
model_path: grape/grape_seeds
grape:
display_name: "葡萄"
resource:
generate: false
material: APPLE
model_path: grape/grape
grape_silver_star:
display_name: "葡萄"
resource:
generate: false
material: APPLE
model_path: grape/grape_silver_star
grape_golden_star:
display_name: "葡萄"
resource:
generate: false
material: APPLE
model_path: grape/grape_golden_star
loots:
blocks:
grape_stage_1:
type: customcrops:grape_stage_1
items:
result_1:
item: customcrops:grape_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
grape_stage_2:
type: customcrops:grape_stage_2
items:
result_1:
item: customcrops:grape_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
grape_stage_3:
type: customcrops:grape_stage_3
items:
result_1:
item: customcrops:grape_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
grape_stage_4:
type: customcrops:grape_stage_4
items:
result_1:
item: customcrops:grape_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
grape_stage_5:
type: customcrops:grape_stage_5
items:
result_1:
item: customcrops:grape_seeds
min_amount: 1
max_amount: 1
chance: 100
ignore_fortune: true
# grape_stage_6:
# type: customcrops:grape_stage_6
# items:
# result_1:
# item: customcrops:grape
# min_amount: 1
# max_amount: 3
# chance: 100

View File

@@ -1,80 +0,0 @@
![2](https://user-images.githubusercontent.com/70987828/179509189-0f609f88-170a-4fc1-8b1b-19f10ba40647.png)
# Custom-Crops
StardewValley Like Farming System
### How to buy
https://afdian.net/@xiaomomi
https://polymart.org/resource/customcrops.2625
### How to compile
Just compile it with -gradle shadowjar. Some premium plugins are used as
local libraries. If you don't need those integrations just remove them!
Default ItemsAdder Config is also included in this project, which will
provide a template and help you understand how this plugin works.
### Game Mechanics
Crops will grow at a specified time which you will see in the config.\
1000 is default (7am) As we know, Minecraft has 24000 ticks / Day\
All crops will grow successively if their pot is watered.
### Season & Greenhouse
Season is an important part of StardewValley Farming System
which means crops only grow in a suitable season. Inproper
seasons will make crops into dead stage but you can use
greenhouse glass to allow them grow all year.\
Season change has two modes: Automatic and Command\
You might use command to change season to sync other plugin's season for example RealisticSeason.
### Fertilizer
There are three templates of fertiziliers: \
SpeedGrow: Crops have a small chance to grow two stages at a time\
RetainingSoil: Pot have a small chance to retain its water after crops grow\
QuailityCrops: When haveresting, players have a higher chance to get high quality crops.
### Sprinkler & WateringCan
Sprinkler is a semi-automatic way of watering pot. You can add water to sprinkler with
water bucket or watering can. Max storage and range can be customized.\
Watering can also has its max storage and range. 1x1 1x3 3x3 and even 9x99 is supported!
### OverWeight
If configurated, crops will still absorb water every day and have a very little chance to be OverWeight(gigantic) before it's dead.
### Quality
Crops have three qualities, if you don't want this feature just disable it in config.
Quality is determined by the fertizilier players use and their luck!
### Harvest Repeatedly
If configurated, crops can be harvested with hands repeatedly and return to a specified stage.
### Highly Optimizied
1.Crops only grow at the specified time and won't impact the performance in other times.\
2.Growing judge is async and only the last step ** replace blcoks ** is sync.\
3.Crops will not actually grow at the same time. It's laggy to replace so many blocks at the same time. They will grow in a random time(in seconds) which you can specified in the config after "grow-time"(7am default)\
4.Defaultly crops will only grow in loaded chunks. If you want a mechanic similar to OriginRealms just DISABLE SEASON, GIGANTIC(OverWeight) and REPEATED HARVESTING.\
In this way crops data will be removed from file after it comes to its max stage. In other words, plugin will only record the crops still on growing.\
NEVER SET "only-grow-in-loaded-chunks" FALSE IF YOU DON'T DISABLE THE THREE FEATURES MENTIONED ABOVE.
### Commands
/customcrops setseason [world] [season] # set a specified world's season\
/customcrops reload # reload the plugin\
/customcrops backup # back up the data\
/customcrops forcegrow [world] # force a specified world's crops to grow a stage\
/customcrops forcewater [world] # force a specified world's sprinklers to work\
/customcrops forcesave [file] # save the cache to file
### Placeholders
%customcrops_season% show the season in the world\
%customcrops_season_[world]%\
<<<<<<< HEAD
=======
>>>>>>> 5b4051e47471e1fef498039557036ccff8060511
==== these papi below will be accurate only in "Auto" mode ====\
%customcrops_nextseason% show the days to the next season\
%customcrops_nextseason_[world]%\
%customcrops_current% show the days the current season has gone\
%customcrops_current_[world]%

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,12 +4,21 @@
crops:
tomato:
amount: 1~4
quality:
1: customcrops:tomato
2: customcrops:tomato_silver_star
3: customcrops:tomato_golden_star
#optional
#The chance that a crop grow a stage at grow time
grow-chance: 0.9
#When harvesting, should the crop drop the loots from ItemsAdder too
#This is useful for droping seeds and other items
drop-ia-loots: false
#optional
#Overweight
gigantic: