9
0
mirror of https://github.com/Xiao-MoMi/Custom-Crops.git synced 2025-12-27 02:49:11 +00:00

3.0.0-beta1

This commit is contained in:
Xiao-MoMi
2023-04-18 22:47:17 +08:00
parent 34f0e51908
commit 8eb277b8fc
58 changed files with 1921 additions and 651 deletions

View File

@@ -42,7 +42,7 @@ dependencies {
implementation ("de.tr7zw:item-nbt-api:2.11.2")
implementation ('org.bstats:bstats-bukkit:3.0.1')
implementation ('org.apache.commons:commons-pool2:2.11.1')
implementation fileTree(dir:'libs',includes:['BiomeAPI.jar'])
implementation fileTree(dir:'libs',includes:['BiomeAPI.jar','ProtectionLib.jar'])
}
def targetJavaVersion = 17
@@ -55,23 +55,18 @@ java {
}
}
tasks.withType(JavaCompile).configureEach {
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
options.release = targetJavaVersion
}
}
processResources {
def props = [version: version]
inputs.properties props
filteringCharset 'UTF-8'
filesMatching('plugin.yml') {
filesMatching(['paper-plugin.yml', 'plugin.yml']) {
expand props
}
}
tasks.withType(JavaCompile) {
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
options.release = targetJavaVersion
}
shadowJar {
@@ -80,6 +75,7 @@ shadowJar {
relocate ('org.bstats', 'net.momirealms.customcrops.libs.org.bstats')
relocate ('org.apache.commons.pool2', 'net.momirealms.customcrops.libs.org.apache.commons.pool2')
relocate ('net.momirealms.biomeapi', 'net.momirealms.customcrops.libs.net.momirealms.biomeapi')
relocate ('net.momirealms.protectionlib', 'net.momirealms.customcrops.libs.net.momirealms.protectionlib')
}
tasks.register("delete", Delete).get().delete("build/libs/"+project.name+"-"+project.version+".jar")

View File

@@ -26,11 +26,11 @@ import net.momirealms.customcrops.api.customplugin.PlatformInterface;
import net.momirealms.customcrops.api.customplugin.PlatformManager;
import net.momirealms.customcrops.api.customplugin.itemsadder.ItemsAdderPluginImpl;
import net.momirealms.customcrops.api.customplugin.oraxen.OraxenPluginImpl;
import net.momirealms.customcrops.api.object.HologramManager;
import net.momirealms.customcrops.api.object.basic.ConfigManager;
import net.momirealms.customcrops.api.object.basic.MessageManager;
import net.momirealms.customcrops.api.object.crop.CropManager;
import net.momirealms.customcrops.api.object.fertilizer.FertilizerManager;
import net.momirealms.customcrops.api.object.hologram.HologramManager;
import net.momirealms.customcrops.api.object.pot.PotManager;
import net.momirealms.customcrops.api.object.scheduler.Scheduler;
import net.momirealms.customcrops.api.object.season.SeasonManager;
@@ -42,6 +42,7 @@ import net.momirealms.customcrops.command.CustomCropsCommand;
import net.momirealms.customcrops.helper.LibraryLoader;
import net.momirealms.customcrops.helper.VersionHelper;
import net.momirealms.customcrops.integration.IntegrationManager;
import net.momirealms.protectionlib.ProtectionLib;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -78,11 +79,23 @@ public final class CustomCrops extends JavaPlugin {
public void onLoad(){
plugin = this;
this.loadLibs();
ProtectionLib.initialize(this);
}
@Override
public void onEnable() {
adventure = BukkitAudiences.create(this);
this.versionHelper = new VersionHelper(this);
if (versionHelper.isSpigot()) {
AdventureUtils.consoleMessage("<red>========================[CustomCrops]=========================");
AdventureUtils.consoleMessage("<red> Spigot is not officially supported by CustomCrops");
AdventureUtils.consoleMessage("<red> Please use Paper or its forks");
AdventureUtils.consoleMessage("<red> Paper download link: https://papermc.io/downloads");
AdventureUtils.consoleMessage("<red>==============================================================");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
protocolManager = ProtocolLibrary.getProtocolManager();
AdventureUtils.consoleMessage("[CustomCrops] Running on <white>" + Bukkit.getVersion());
this.registerCommands();
@@ -91,7 +104,6 @@ public final class CustomCrops extends JavaPlugin {
this.scheduler = new Scheduler(this);
this.configManager = new ConfigManager(this);
this.messageManager = new MessageManager(this);
this.versionHelper = new VersionHelper(this);
this.cropManager = new CropManager(this);
this.integrationManager = new IntegrationManager(this);
this.seasonManager = new SeasonManager(this);

View File

@@ -18,19 +18,6 @@
package net.momirealms.customcrops.api;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.customplugin.PlatformInterface;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.crop.CropConfig;
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.object.pot.Pot;
import net.momirealms.customcrops.api.object.pot.PotConfig;
import net.momirealms.customcrops.api.object.season.CCSeason;
import net.momirealms.customcrops.api.object.world.SimpleLocation;
import net.momirealms.customcrops.api.util.ConfigUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.inventory.ItemStack;
public class CustomCropsAPI {
@@ -45,77 +32,4 @@ public class CustomCropsAPI {
public static CustomCropsAPI getInstance() {
return instance;
}
public boolean isCrop(String stage_id) {
return plugin.getCropManager().getCropConfigByStage(stage_id) != null;
}
public CropConfig getCropConfig(String crop_config_id) {
return plugin.getCropManager().getCropConfigByID(crop_config_id);
}
public ItemStack buildItem(String id) {
return plugin.getIntegrationManager().build(id);
}
public boolean removeCustomItem(Location location, ItemMode itemMode) {
if (itemMode == ItemMode.TRIPWIRE || itemMode == ItemMode.CHORUS)
return plugin.getPlatformInterface().removeCustomBlock(location);
else if (itemMode == ItemMode.ITEM_FRAME)
return plugin.getPlatformInterface().removeItemFrame(location);
else if (itemMode == ItemMode.ITEM_DISPLAY)
return plugin.getPlatformInterface().removeItemDisplay(location);
return false;
}
public void placeCustomItem(Location location, String id, ItemMode itemMode) {
if (itemMode == ItemMode.TRIPWIRE)
plugin.getPlatformInterface().placeTripWire(location, id);
else if (itemMode == ItemMode.ITEM_FRAME)
plugin.getPlatformInterface().placeItemFrame(location, id);
else if (itemMode == ItemMode.ITEM_DISPLAY)
plugin.getPlatformInterface().placeItemDisplay(location, id);
else if (itemMode == ItemMode.CHORUS)
plugin.getPlatformInterface().placeChorus(location, id);
}
public void changePotModel(SimpleLocation simpleLocation, Pot pot) {
Location location = simpleLocation.getBukkitLocation();
if (location == null) return;
PlatformInterface platform = plugin.getPlatformInterface();
if (platform.removeAnyBlock(location)) {
String replacer = pot.isWet() ? pot.getConfig().getWetPot(pot.getFertilizer()) : pot.getConfig().getDryPot(pot.getFertilizer());
if (ConfigUtils.isVanillaItem(replacer)) {
location.getBlock().setType(Material.valueOf(replacer));
} else {
platform.placeNoteBlock(location, replacer);
}
} else {
CustomCrops.getInstance().getWorldDataManager().removePotData(simpleLocation);
}
}
public void changePotModel(SimpleLocation simpleLocation, PotConfig potConfig, Fertilizer fertilizer, boolean wet) {
Location location = simpleLocation.getBukkitLocation();
if (location == null) return;
PlatformInterface platform = plugin.getPlatformInterface();
if (platform.removeAnyBlock(location)) {
String replacer = wet ? potConfig.getWetPot(fertilizer) : potConfig.getDryPot(fertilizer);
if (ConfigUtils.isVanillaItem(replacer)) {
location.getBlock().setType(Material.valueOf(replacer));
} else {
platform.placeNoteBlock(location, replacer);
}
} else {
CustomCrops.getInstance().getWorldDataManager().removePotData(simpleLocation);
}
}
public boolean isGreenhouse(SimpleLocation simpleLocation) {
return plugin.getWorldDataManager().isGreenhouse(simpleLocation);
}
public CCSeason getCurrentSeason(String world) {
return plugin.getIntegrationManager().getSeasonInterface().getSeason(world);
}
}

View File

@@ -24,7 +24,6 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;

View File

@@ -18,6 +18,7 @@
package net.momirealms.customcrops.api.customplugin;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.ItemMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -73,8 +74,6 @@ public interface PlatformInterface {
void placeChorus(Location location, String id);
Location getItemFrameLocation(Location location);
@NotNull
default String getAnyItemIDAt(Location location) {
String block = getBlockID(location.getBlock());
@@ -124,7 +123,7 @@ public interface PlatformInterface {
@Nullable
default ItemFrame getItemFrameAt(Location location) {
Collection<ItemFrame> itemFrames = getItemFrameLocation(location).getNearbyEntitiesByType(ItemFrame.class, 0.5, 0.5, 0.5);
Collection<ItemFrame> itemFrames = location.clone().add(0.5,0.5,0.5).getNearbyEntitiesByType(ItemFrame.class, 0.5, 0.5, 0.5);
int i = itemFrames.size();
int j = 1;
for (ItemFrame itemFrame : itemFrames) {
@@ -139,7 +138,7 @@ public interface PlatformInterface {
@Nullable
default ItemDisplay getItemDisplayAt(Location location) {
Collection<ItemDisplay> itemDisplays = getItemFrameLocation(location).getNearbyEntitiesByType(ItemDisplay.class, 0.5, 0.5, 0.5);
Collection<ItemDisplay> itemDisplays = location.clone().add(0.5,0.5,0.5).getNearbyEntitiesByType(ItemDisplay.class, 0.5, 0.5, 0.5);
int i = itemDisplays.size();
int j = 1;
for (ItemDisplay itemDisplay : itemDisplays) {
@@ -181,4 +180,25 @@ public interface PlatformInterface {
Collection<Entity> entities = location.clone().add(0.5,0.5,0.5).getNearbyEntitiesByType(ItemDisplay.class, 0.5, 0.5, 0.5);
return entities.size() != 0;
}
default boolean removeCustomItem(Location location, ItemMode itemMode) {
if (itemMode == ItemMode.TRIPWIRE || itemMode == ItemMode.CHORUS)
return removeCustomBlock(location);
else if (itemMode == ItemMode.ITEM_FRAME)
return removeItemFrame(location);
else if (itemMode == ItemMode.ITEM_DISPLAY)
return removeItemDisplay(location);
return false;
}
default void placeCustomItem(Location location, String id, ItemMode itemMode) {
if (itemMode == ItemMode.TRIPWIRE)
placeTripWire(location, id);
else if (itemMode == ItemMode.ITEM_FRAME)
placeItemFrame(location, id);
else if (itemMode == ItemMode.ITEM_DISPLAY)
placeItemDisplay(location, id);
else if (itemMode == ItemMode.CHORUS)
placeChorus(location, id);
}
}

View File

@@ -18,14 +18,12 @@
package net.momirealms.customcrops.api.customplugin;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.CustomCropsAPI;
import net.momirealms.customcrops.api.customplugin.itemsadder.ItemsAdderHandler;
import net.momirealms.customcrops.api.customplugin.oraxen.OraxenHandler;
import net.momirealms.customcrops.api.event.*;
import net.momirealms.customcrops.api.object.BoneMeal;
import net.momirealms.customcrops.api.object.Function;
import net.momirealms.customcrops.api.object.InteractWithItem;
import net.momirealms.customcrops.api.object.ItemType;
import net.momirealms.customcrops.api.object.action.Action;
import net.momirealms.customcrops.api.object.basic.ConfigManager;
import net.momirealms.customcrops.api.object.basic.MessageManager;
@@ -36,13 +34,14 @@ import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.object.fertilizer.FertilizerConfig;
import net.momirealms.customcrops.api.object.fill.PassiveFillMethod;
import net.momirealms.customcrops.api.object.fill.PositiveFillMethod;
import net.momirealms.customcrops.api.object.hologram.FertilizerHologram;
import net.momirealms.customcrops.api.object.hologram.WaterAmountHologram;
import net.momirealms.customcrops.api.object.pot.Pot;
import net.momirealms.customcrops.api.object.pot.PotConfig;
import net.momirealms.customcrops.api.object.requirement.CurrentState;
import net.momirealms.customcrops.api.object.requirement.Requirement;
import net.momirealms.customcrops.api.object.sprinkler.Sprinkler;
import net.momirealms.customcrops.api.object.sprinkler.SprinklerConfig;
import net.momirealms.customcrops.api.object.sprinkler.SprinklerHologram;
import net.momirealms.customcrops.api.object.wateringcan.WateringCanConfig;
import net.momirealms.customcrops.api.object.world.SimpleLocation;
import net.momirealms.customcrops.api.util.AdventureUtils;
@@ -59,7 +58,6 @@ import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -146,88 +144,78 @@ public class PlatformManager extends Function {
onInteractSomething(player, entity.getLocation().getBlock().getLocation(), id, event);
}
@NotNull
public ItemType onInteractAir(Player player) {
public void onInteractAir(Player player) {
ItemStack item_in_hand = player.getInventory().getItemInMainHand();
String id = plugin.getPlatformInterface().getItemStackID(item_in_hand);
if (onInteractWithWateringCan(player, id, item_in_hand)) {
return ItemType.WATERING_CAN;
if (onInteractWithWateringCan(player, id, item_in_hand, null, null)) {
return;
}
return ItemType.UNKNOWN;
}
@NotNull
public ItemType onBreakSomething(Player player, Location location, String id, Cancellable event) {
public void onBreakSomething(Player player, Location location, String id, Cancellable event) {
if (onBreakGlass(id, location)) {
return ItemType.GLASS;
return;
}
if (onBreakPot(player, id, location, event)) {
return ItemType.POT;
return;
}
if (onBreakCrop(player, id, location, event)) {
return ItemType.CROP;
return;
}
if (onBreakSprinkler(id, location)) {
return ItemType.SPRINKLER;
return;
}
if (onBreakScarecrow(id, location)) {
return ItemType.SCARECROW;
return;
}
return ItemType.UNKNOWN;
}
@NotNull
public ItemType onPlaceSomething(Location location, String id) {
public void onPlaceSomething(Location location, String id) {
if (onPlaceGlass(id, location)) {
return ItemType.GLASS;
return;
}
if (onPlacePot(id, location)) {
return ItemType.POT;
return;
}
if (onPlaceScarecrow(id, location)) {
return ItemType.SCARECROW;
return;
}
return ItemType.UNKNOWN;
}
@NotNull ItemType onInteractSomething(Player player, Location location, String id, Cancellable event) {
void onInteractSomething(Player player, Location location, String id, Cancellable event) {
ItemStack item_in_hand = player.getInventory().getItemInMainHand();
String item_in_hand_id = plugin.getPlatformInterface().getItemStackID(item_in_hand);
if (onInteractWithSprinkler(player, location, item_in_hand, item_in_hand_id)) {
return ItemType.SPRINKLER;
return;
}
if (onInteractSprinkler(player, id, location, item_in_hand, item_in_hand_id)) {
return ItemType.SPRINKLER;
if (onInteractSprinkler(player, id, location, item_in_hand, item_in_hand_id, event)) {
return;
}
if (onInteractPot(player, id, location, item_in_hand, item_in_hand_id, event)) {
return ItemType.POT;
return;
}
if (onInteractCrop(player, id, location, item_in_hand, item_in_hand_id, event)) {
return ItemType.CROP;
return;
}
if (onInteractWithWateringCan(player, item_in_hand_id, item_in_hand)) {
return ItemType.WATERING_CAN;
if (onInteractWithWateringCan(player, item_in_hand_id, item_in_hand, id, location)) {
return;
}
return ItemType.UNKNOWN;
}
public boolean onBreakGlass(String id, Location location) {
@@ -274,7 +262,7 @@ public class PlatformManager extends Function {
return true;
}
public boolean onInteractSprinkler(Player player, String id, Location location, ItemStack item_in_hand, String item_in_hand_id) {
public boolean onInteractSprinkler(Player player, String id, Location location, ItemStack item_in_hand, String item_in_hand_id, Cancellable event) {
SprinklerConfig sprinklerConfig = plugin.getSprinklerManager().getConfigByItemID(id);
if (sprinklerConfig == null) {
return false;
@@ -292,6 +280,7 @@ public class PlatformManager extends Function {
return true;
}
event.setCancelled(true);
doPassiveFillAction(player, item_in_hand, passiveFillMethod, location.clone().add(0,0.2,0));
plugin.getWorldDataManager().addWaterToSprinkler(SimpleLocation.getByBukkitLocation(location), sprinklerFillEvent.getWater(), sprinklerConfig);
break outer;
@@ -338,12 +327,17 @@ public class PlatformManager extends Function {
}
Sprinkler sprinkler = plugin.getWorldDataManager().getSprinklerData(SimpleLocation.getByBukkitLocation(location));
if (sprinkler != null && sprinklerConfig.hasHologram()) {
SprinklerHologram sprinklerHologram = sprinklerConfig.getSprinklerHologram();
if (sprinklerHologram != null) {
String content = sprinklerHologram.getContent(sprinkler.getWater(), sprinklerConfig.getStorage());
plugin.getHologramManager().showHologram(player, location.clone().add(0.5,sprinklerHologram.getOffset(),0.5), AdventureUtils.getComponentFromMiniMessage(content),
sprinklerHologram.getDuration() * 1000, sprinklerHologram.getMode());
if (sprinkler != null) {
WaterAmountHologram waterAmountHologram = sprinklerConfig.getSprinklerHologram();
if (waterAmountHologram != null) {
String content = waterAmountHologram.getContent(sprinkler.getWater(), sprinklerConfig.getStorage());
plugin.getHologramManager().showHologram(player,
location.clone().add(0.5, waterAmountHologram.getOffset(),0.5),
AdventureUtils.getComponentFromMiniMessage(content),
waterAmountHologram.getDuration() * 1000,
waterAmountHologram.getMode(),
waterAmountHologram.getTextDisplayMeta()
);
}
}
return true;
@@ -381,7 +375,7 @@ public class PlatformManager extends Function {
}
if (player.getGameMode() != GameMode.CREATIVE) item_in_hand.setAmount(item_in_hand.getAmount() - 1);
CustomCropsAPI.getInstance().placeCustomItem(sprinkler_loc, sprinklerConfig.getThreeD(), sprinklerConfig.getItemMode());
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(sprinkler_loc, sprinklerConfig.getThreeD(), sprinklerConfig.getItemMode());
if (sprinklerConfig.getSound() != null) {
AdventureUtils.playerSound(player, sprinklerConfig.getSound());
}
@@ -409,20 +403,21 @@ public class PlatformManager extends Function {
return true;
}
Pot potData = plugin.getWorldDataManager().getPotData(SimpleLocation.getByBukkitLocation(location).add(0,-1,0));
Location pot_loc = location.clone().subtract(0, 1, 0);
Pot potData = plugin.getWorldDataManager().getPotData(SimpleLocation.getByBukkitLocation(pot_loc));
if (potData != null) {
PassiveFillMethod[] passiveFillMethods = potData.getConfig().getPassiveFillMethods();
for (PassiveFillMethod passiveFillMethod : passiveFillMethods) {
if (passiveFillMethod.isRightItem(item_in_hand_id)) {
PotWaterEvent potWaterEvent = new PotWaterEvent(player, item_in_hand, passiveFillMethod.getAmount(), location);
PotWaterEvent potWaterEvent = new PotWaterEvent(player, item_in_hand, passiveFillMethod.getAmount(), pot_loc);
Bukkit.getPluginManager().callEvent(potWaterEvent);
if (potWaterEvent.isCancelled()) {
return true;
}
event.setCancelled(true);
doPassiveFillAction(player, item_in_hand, passiveFillMethod, location);
doPassiveFillAction(player, item_in_hand, passiveFillMethod, pot_loc);
potData.addWater(potWaterEvent.getWater());
return true;
}
@@ -444,7 +439,6 @@ public class PlatformManager extends Function {
int current_water = plugin.getWateringCanManager().getCurrentWater(item_in_hand);
if (current_water <= 0) return true;
Location pot_loc = location.clone().subtract(0,1,0);
PotWaterEvent potWaterEvent = new PotWaterEvent(player, item_in_hand, 1, pot_loc);
Bukkit.getPluginManager().callEvent(potWaterEvent);
if (potWaterEvent.isCancelled()) {
@@ -571,7 +565,7 @@ public class PlatformManager extends Function {
if (player.getGameMode() != GameMode.CREATIVE) item_in_hand.setAmount(item_in_hand.getAmount() - 1);
player.swingMainHand();
CustomCropsAPI.getInstance().placeCustomItem(crop_loc, cropPlantEvent.getCropModel(), cropConfig.getCropMode());
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(crop_loc, cropPlantEvent.getCropModel(), cropConfig.getCropMode());
plugin.getWorldDataManager().addCropData(SimpleLocation.getByBukkitLocation(crop_loc), new GrowingCrop(cropConfig.getKey(), cropPlantEvent.getPoint()));
return true;
}
@@ -658,13 +652,35 @@ public class PlatformManager extends Function {
PotInfoEvent potInfoEvent = new PotInfoEvent(player, location, item_in_hand, potConfig, potData == null ? null : potData.getFertilizer(), potData == null ? 0 : potData.getWater(), growingCrop);
Bukkit.getPluginManager().callEvent(potInfoEvent);
if (potConfig.isHologramEnabled() && potData != null) {
if (potConfig.getRequiredItem() != null && !item_in_hand_id.equals(potConfig.getRequiredItem())) {
return true;
}
WaterAmountHologram waterAmountHologram = potConfig.getWaterAmountHologram();
if (waterAmountHologram != null && potData != null) {
plugin.getHologramManager().showHologram(player,
location.clone().add(0.5,waterAmountHologram.getOffset(),0.5),
AdventureUtils.getComponentFromMiniMessage(waterAmountHologram.getContent(potData.getWater(), potConfig.getMaxStorage())),
waterAmountHologram.getDuration() * 1000,
waterAmountHologram.getMode(),
waterAmountHologram.getTextDisplayMeta()
);
}
FertilizerHologram fertilizerHologram = potConfig.getFertilizerHologram();
if (fertilizerHologram != null && potData != null && potData.getFertilizer() != null) {
double offset = 0;
StageConfig stageConfig = plugin.getCropManager().getStageConfig(plugin.getPlatformInterface().getAnyItemIDAt(location.clone().add(0,1,0)));
if (stageConfig != null) {
offset = stageConfig.getOffsetCorrection();
}
potConfig.getPotHologram().show(player, potData, location.clone().add(0.5,0,0.5), offset);
plugin.getHologramManager().showHologram(player,
location.clone().add(0.5,fertilizerHologram.getOffset() + offset,0.5),
AdventureUtils.getComponentFromMiniMessage(fertilizerHologram.getContent(potData.getFertilizer())),
fertilizerHologram.getDuration() * 1000,
fertilizerHologram.getMode(),
fertilizerHologram.getTextDisplayMeta()
);
}
return true;
}
@@ -701,7 +717,7 @@ public class PlatformManager extends Function {
}
private boolean onBreakSprinkler(String id, Location location) {
if (!plugin.getSprinklerManager().containsSprinkler(id)) {
if (plugin.getSprinklerManager().getConfigKeyByItemID(id) == null) {
return false;
}
@@ -804,7 +820,7 @@ public class PlatformManager extends Function {
}
}
public boolean onInteractWithWateringCan(Player player, String item_in_hand_id, ItemStack item_in_hand) {
public boolean onInteractWithWateringCan(Player player, String item_in_hand_id, ItemStack item_in_hand, @Nullable String id, @Nullable Location location) {
WateringCanConfig wateringCanConfig = plugin.getWateringCanManager().getConfigByItemID(item_in_hand_id);
if (wateringCanConfig == null) {
return false;
@@ -812,12 +828,27 @@ public class PlatformManager extends Function {
int current = plugin.getWateringCanManager().getCurrentWater(item_in_hand);
if (current >= wateringCanConfig.getStorage()) return true;
List<Block> lineOfSight = player.getLineOfSight(null, 5);
List<String> blockIds = lineOfSight.stream().map(block -> plugin.getPlatformInterface().getBlockID(block)).toList();
int add = 0;
for (PositiveFillMethod positiveFillMethod : wateringCanConfig.getPositiveFillMethods()) {
if (positiveFillMethod.getType() == PositiveFillMethod.InteractType.BLOCK) {
if (id != null && location != null) {
for (PositiveFillMethod positiveFillMethod : wateringCanConfig.getPositiveFillMethods()) {
if (positiveFillMethod.getId().equals(id)) {
add = positiveFillMethod.getAmount();
if (positiveFillMethod.getSound() != null) {
AdventureUtils.playerSound(player, positiveFillMethod.getSound());
}
if (positiveFillMethod.getParticle() != null) {
location.getWorld().spawnParticle(positiveFillMethod.getParticle(), location.clone().add(0.5,1.1, 0.5),5,0.1,0.1,0.1);
}
break;
}
}
} else {
List<Block> lineOfSight = player.getLineOfSight(null, 5);
List<String> blockIds = lineOfSight.stream().map(block -> plugin.getPlatformInterface().getBlockID(block)).toList();
for (PositiveFillMethod positiveFillMethod : wateringCanConfig.getPositiveFillMethods()) {
int index = 0;
for (String blockId : blockIds) {
if (positiveFillMethod.getId().equals(blockId)) {
@@ -827,7 +858,7 @@ public class PlatformManager extends Function {
}
if (positiveFillMethod.getParticle() != null) {
Block block = lineOfSight.get(index);
block.getWorld().spawnParticle(positiveFillMethod.getParticle(), block.getLocation().add(0.5,1, 0.5),5,0.1,0.1,0.1);
block.getWorld().spawnParticle(positiveFillMethod.getParticle(), block.getLocation().add(0.5,1.1, 0.5),5,0.1,0.1,0.1);
}
break;
}
@@ -844,5 +875,4 @@ public class PlatformManager extends Function {
}
return true;
}
}

View File

@@ -67,6 +67,7 @@ public class ItemsAdderPluginImpl implements PlatformInterface {
if (entity instanceof ItemFrame itemFrame)
return itemFrame;
else {
AdventureUtils.consoleMessage("<red>[CustomCrops] Item Frame not exists: " + id);
customFurniture.remove(false);
}
return null;
@@ -75,7 +76,18 @@ public class ItemsAdderPluginImpl implements PlatformInterface {
@Nullable
@Override
public ItemDisplay placeItemDisplay(Location location, String id) {
//TODO Not implemented
CustomFurniture customFurniture = CustomFurniture.spawn(id, location.getBlock());
if (customFurniture == null) {
AdventureUtils.consoleMessage("<red>[CustomCrops] Furniture not exists: " + id);
return null;
}
Entity entity = customFurniture.getArmorstand();
if (entity instanceof ItemDisplay itemDisplay)
return itemDisplay;
else {
AdventureUtils.consoleMessage("<red>[CustomCrops] Item Display not exists: " + id);
customFurniture.remove(false);
}
return null;
}
@@ -116,11 +128,6 @@ public class ItemsAdderPluginImpl implements PlatformInterface {
CustomBlock.place(id, location);
}
@Override
public Location getItemFrameLocation(Location location) {
return location.clone().add(0.5, 0.5, 0.5);
}
@NotNull
@Override
public String getItemStackID(@NotNull ItemStack itemStack) {
@@ -135,8 +142,9 @@ public class ItemsAdderPluginImpl implements PlatformInterface {
@Nullable
@Override
public String getItemDisplayID(ItemDisplay itemDisplay) {
//TODO Not implemented
return null;
CustomFurniture customFurniture = CustomFurniture.byAlreadySpawned(itemDisplay);
if (customFurniture == null) return null;
return customFurniture.getNamespacedID();
}
@Nullable

View File

@@ -71,7 +71,7 @@ public class OraxenPluginImpl implements PlatformInterface {
public ItemFrame placeItemFrame(Location location, String id) {
FurnitureMechanic mechanic = (FurnitureMechanic) FurnitureFactory.getInstance().getMechanic(id);
if (mechanic == null) {
AdventureUtils.consoleMessage("<red>[CustomCrops] Item Frame not exists: " + id);
AdventureUtils.consoleMessage("<red>[CustomCrops] Furniture not exists: " + id);
return null;
}
Entity entity = mechanic.place(location, 0, Rotation.NONE, BlockFace.UP);
@@ -89,7 +89,7 @@ public class OraxenPluginImpl implements PlatformInterface {
public ItemDisplay placeItemDisplay(Location location, String id) {
FurnitureMechanic mechanic = (FurnitureMechanic) FurnitureFactory.getInstance().getMechanic(id);
if (mechanic == null) {
AdventureUtils.consoleMessage("<red>[CustomCrops] Item Display not exists: " + id);
AdventureUtils.consoleMessage("<red>[CustomCrops] Furniture not exists: " + id);
return null;
}
Entity entity = mechanic.place(location);
@@ -135,15 +135,9 @@ public class OraxenPluginImpl implements PlatformInterface {
@Override
public void placeChorus(Location location, String id) {
//TODO Not implemented, so use tripwire instead
StringBlockMechanicFactory.setBlockModel(location.getBlock(), id);
}
@Override
public Location getItemFrameLocation(Location location) {
return location.clone().add(0.5,0.5,0.5);
}
@Nullable
@Override
public String getItemDisplayID(ItemDisplay itemDisplay) {

View File

@@ -0,0 +1,62 @@
package net.momirealms.customcrops.api.event;
import net.momirealms.customcrops.api.object.crop.CropConfig;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
public class CropBreakEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private final CropConfig cropConfig;
private final String crop_id;
private final Location location;
public CropBreakEvent(@NotNull Player who, CropConfig cropConfig, String crop_id, Location location) {
super(who);
this.cropConfig = cropConfig;
this.crop_id = crop_id;
this.location = location;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
public CropConfig getCropConfig() {
return cropConfig;
}
/**
* Get the crop item id in IA/Oraxen
* @return item id
*/
public String getCropItemID() {
return crop_id;
}
public Location getLocation() {
return location;
}
}

View File

@@ -19,6 +19,10 @@ package net.momirealms.customcrops.api.object;
public class Function {
public void init() {
}
public void load() {
}

View File

@@ -18,7 +18,6 @@
package net.momirealms.customcrops.api.object.action;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.CustomCropsAPI;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.crop.StageConfig;
import net.momirealms.customcrops.api.object.world.SimpleLocation;
@@ -39,7 +38,7 @@ public class BreakImpl implements Action {
public void doOn(@Nullable Player player, @Nullable SimpleLocation crop_loc, ItemMode itemMode) {
if (crop_loc == null) return;
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
CustomCropsAPI.getInstance().removeCustomItem(crop_loc.getBukkitLocation(), itemMode);
CustomCrops.getInstance().getPlatformInterface().removeCustomItem(crop_loc.getBukkitLocation(), itemMode);
CustomCrops.getInstance().getWorldDataManager().removeCropData(crop_loc);
return null;
});

View File

@@ -18,7 +18,6 @@
package net.momirealms.customcrops.api.object.action;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.CustomCropsAPI;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.basic.ConfigManager;
import net.momirealms.customcrops.api.object.basic.MessageManager;
@@ -55,7 +54,7 @@ public class ReplantImpl implements Action {
return null;
}
if (!CustomCrops.getInstance().getPlatformInterface().detectAnyThing(location)) {
CustomCropsAPI.getInstance().placeCustomItem(location, model, newCMode);
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, model, newCMode);
CustomCrops.getInstance().getWorldDataManager().addCropData(crop_loc, new GrowingCrop(crop, point));
}
return null;

View File

@@ -18,7 +18,6 @@
package net.momirealms.customcrops.api.object.action;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.CustomCropsAPI;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.crop.VariationCrop;
import net.momirealms.customcrops.api.object.fertilizer.Variation;
@@ -66,8 +65,8 @@ public record VariationImpl(VariationCrop[] variationCrops) implements Action {
private void doVariation(@NotNull SimpleLocation crop_loc, ItemMode itemMode, VariationCrop variationCrop) {
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
Location location = crop_loc.getBukkitLocation();
if (CustomCropsAPI.getInstance().removeCustomItem(location, itemMode)) {
CustomCropsAPI.getInstance().placeCustomItem(location, variationCrop.getId(), variationCrop.getCropMode());
if (CustomCrops.getInstance().getPlatformInterface().removeCustomItem(location, itemMode)) {
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, variationCrop.getId(), variationCrop.getCropMode());
}
CustomCrops.getInstance().getWorldDataManager().removeCropData(crop_loc);
return null;

View File

@@ -76,11 +76,17 @@ public class ConfigManager extends Function {
debug = config.getBoolean("debug");
setUpMode = config.getBoolean("set-up-mode", true);
loadWorlds(Objects.requireNonNull(config.getConfigurationSection("worlds")));
loadOptimization(Objects.requireNonNull(config.getConfigurationSection("optimization")));
loadScheduleSystem(Objects.requireNonNull(config.getConfigurationSection("schedule-system")));
loadMechanic(Objects.requireNonNull(config.getConfigurationSection("mechanics")));
loadOtherSetting(Objects.requireNonNull(config.getConfigurationSection("other-settings")));
}
private void loadOptimization(ConfigurationSection section) {
enableLimitation = section.getBoolean("limitation.enable");
maxCropPerChunk = section.getInt("limitation.valid-crop-amount");
}
private void loadWorlds(ConfigurationSection section) {
worldFolderPath = section.getString("folder", "");
whiteListWorlds = section.getString("mode", "whitelist").equalsIgnoreCase("whitelist");
@@ -105,6 +111,7 @@ public class ConfigManager extends Function {
enableGreenhouse = section.getBoolean("season.greenhouse.enable", true);
greenhouseRange = section.getInt("season.greenhouse.range", 5);
greenhouseBlock = section.getString("season.greenhouse.block");
scarecrow = section.getString("scarecrow");
}
private void loadOtherSetting(ConfigurationSection section) {

View File

@@ -18,7 +18,6 @@
package net.momirealms.customcrops.api.object.condition;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.CustomCropsAPI;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.world.SimpleLocation;
import org.bukkit.Location;
@@ -48,9 +47,9 @@ public class DeathCondition {
Location location = simpleLocation.getBukkitLocation();
if (location == null) return;
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
CustomCropsAPI.getInstance().removeCustomItem(location, itemMode);
CustomCrops.getInstance().getPlatformInterface().removeCustomItem(location, itemMode);
if (dead_model != null) {
CustomCropsAPI.getInstance().placeCustomItem(location, dead_model, itemMode);
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, dead_model, itemMode);
}
return null;
});

View File

@@ -86,7 +86,7 @@ public class CropManager extends Function implements Listener {
for (String key : config.getKeys(false)) {
ConfigurationSection cropSec = config.getConfigurationSection(key);
if (cropSec == null) continue;
ItemMode itemMode = ItemMode.valueOf(cropSec.getString("crop-mode", "TripWire").toUpperCase());
ItemMode itemMode = ItemMode.valueOf(cropSec.getString("type", "TripWire").toUpperCase());
String[] bottomBlocks = cropSec.getStringList("pot-whitelist").toArray(new String[0]);
if (bottomBlocks.length == 0) {
AdventureUtils.consoleMessage("<red>[CustomCrops] pot-whitelist is not set for crop: " + key);

View File

@@ -55,4 +55,8 @@ public class Fertilizer implements Serializable {
public int getLeftTimes() {
return times;
}
public void setTimes(int times) {
this.times = times;
}
}

View File

@@ -22,26 +22,14 @@ import org.bukkit.Particle;
public class PositiveFillMethod extends AbstractFillMethod {
private final InteractType type;
private final String id;
public PositiveFillMethod(InteractType type, String id, int amount, Particle particle, Sound sound) {
public PositiveFillMethod(String id, int amount, Particle particle, Sound sound) {
super(amount, particle, sound);
this.type = type;
this.id = id;
}
public InteractType getType() {
return type;
}
public String getId() {
return id;
}
public enum InteractType {
BLOCK,
ENTITY,
MM
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.api.object.hologram;
public abstract class AbstractHologram {
protected final String content;
private final double offset;
private final HologramManager.Mode mode;
private final int duration;
private TextDisplayMeta textDisplayMeta;
public AbstractHologram(String content, double offset, HologramManager.Mode mode, int duration, TextDisplayMeta textDisplayMeta) {
this.content = content;
this.offset = offset;
this.mode = mode;
this.duration = duration;
this.textDisplayMeta = textDisplayMeta;
}
public String getContent() {
return content;
}
public double getOffset() {
return offset;
}
public HologramManager.Mode getMode() {
return mode;
}
public int getDuration() {
return duration;
}
public TextDisplayMeta getTextDisplayMeta() {
return textDisplayMeta;
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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.api.object.hologram;
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.object.fertilizer.FertilizerConfig;
import org.jetbrains.annotations.NotNull;
public class FertilizerHologram extends AbstractHologram {
public FertilizerHologram(@NotNull String content, double offset, HologramManager.Mode mode, int duration, TextDisplayMeta textDisplayMeta) {
super(content, offset, mode, duration, textDisplayMeta);
}
public String getContent(Fertilizer fertilizer) {
FertilizerConfig fertilizerConfig = fertilizer.getConfig();
return content.replace("{icon}", String.valueOf(fertilizerConfig.getIcon()))
.replace("{left_times}", String.valueOf(fertilizer.getLeftTimes()))
.replace("{max_times}", String.valueOf(fertilizerConfig.getTimes()));
}
}

View File

@@ -15,10 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.api.object;
package net.momirealms.customcrops.api.object.hologram;
import net.kyori.adventure.text.Component;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.Function;
import net.momirealms.customcrops.api.object.Tuple;
import net.momirealms.customcrops.api.util.FakeEntityUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -86,13 +88,13 @@ public class HologramManager extends Function implements Listener {
this.hologramMap.remove(event.getPlayer().getUniqueId());
}
public void showHologram(Player player, Location location, Component component, int millis, Mode mode) {
public void showHologram(Player player, Location location, Component component, int millis, Mode mode, TextDisplayMeta textDisplayMeta) {
HologramCache hologramCache = hologramMap.get(player.getUniqueId());
if (hologramCache != null) {
hologramCache.showHologram(player, location, component, millis, mode);
hologramCache.showHologram(player, location, component, millis, mode, textDisplayMeta);
} else {
hologramCache = new HologramCache();
hologramCache.showHologram(player, location, component, millis, mode);
hologramCache.showHologram(player, location, component, millis, mode, textDisplayMeta);
hologramMap.put(player.getUniqueId(), hologramCache);
}
}
@@ -133,7 +135,7 @@ public class HologramManager extends Function implements Listener {
}
}
public void showHologram(Player player, Location location, Component component, int millis, Mode mode) {
public void showHologram(Player player, Location location, Component component, int millis, Mode mode, TextDisplayMeta textDisplayMeta) {
int entity_id = push(location, millis);
if (entity_id == 0) {
int random = ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE);
@@ -143,14 +145,14 @@ public class HologramManager extends Function implements Listener {
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getSpawnPacket(random, location, EntityType.ARMOR_STAND));
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getVanishArmorStandMetaPacket(random, component));
} else if (mode == Mode.TEXT_DISPLAY) {
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getSpawnPacket(random, location, EntityType.TEXT_DISPLAY));
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getTextDisplayMetaPacket(random, component));
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getSpawnPacket(random, location.clone().add(0,1,0), EntityType.TEXT_DISPLAY));
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getTextDisplayMetaPacket(random, component, textDisplayMeta));
}
} else {
if (mode == Mode.ARMOR_STAND) {
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getVanishArmorStandMetaPacket(entity_id, component));
} else if (mode == Mode.TEXT_DISPLAY) {
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getTextDisplayMetaPacket(entity_id, component));
CustomCrops.getProtocolManager().sendServerPacket(player, FakeEntityUtils.getTextDisplayMetaPacket(entity_id, component, textDisplayMeta));
}
}
}

View File

@@ -0,0 +1,38 @@
package net.momirealms.customcrops.api.object.hologram;
public class TextDisplayMeta {
private final boolean hasShadow;
private final boolean isSeeThrough;
private final boolean useDefaultBackground;
private final int backgroundColor;
private final byte opacity;
public TextDisplayMeta(boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackground, int backgroundColor, byte opacity) {
this.hasShadow = hasShadow;
this.isSeeThrough = isSeeThrough;
this.useDefaultBackground = useDefaultBackground;
this.backgroundColor = backgroundColor;
this.opacity = opacity;
}
public boolean isHasShadow() {
return hasShadow;
}
public boolean isSeeThrough() {
return isSeeThrough;
}
public boolean isUseDefaultBackground() {
return useDefaultBackground;
}
public int getBackgroundColor() {
return backgroundColor;
}
public byte getOpacity() {
return opacity;
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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.api.object.hologram;
import org.jetbrains.annotations.NotNull;
public class WaterAmountHologram extends AbstractHologram {
private final String bar_left;
private final String bar_full;
private final String bar_empty;
private final String bar_right;
public WaterAmountHologram(@NotNull String content, double offset, HologramManager.Mode mode, int duration,
String bar_left, String bar_full, String bar_empty, String bar_right, TextDisplayMeta textDisplayMeta) {
super(content, offset, mode, duration, textDisplayMeta);
this.bar_left = bar_left;
this.bar_full = bar_full;
this.bar_empty = bar_empty;
this.bar_right = bar_right;
}
public String getContent(int current, int storage) {
return super.content.replace("{current}", String.valueOf(current))
.replace("{storage}", String.valueOf(storage))
.replace("{water_bar}", getWaterBar(current, storage));
}
private String getWaterBar(int current, int storage) {
return bar_left +
String.valueOf(bar_full).repeat(current) +
String.valueOf(bar_empty).repeat(Math.max(storage - current, 0)) +
bar_right;
}
}

View File

@@ -0,0 +1,239 @@
/*
* 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.api.object.migrate;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.Function;
import net.momirealms.customcrops.api.object.basic.ConfigManager;
import net.momirealms.customcrops.api.object.crop.GrowingCrop;
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.object.pot.Pot;
import net.momirealms.customcrops.api.object.sprinkler.Sprinkler;
import net.momirealms.customcrops.api.object.world.CCChunk;
import net.momirealms.customcrops.api.object.world.ChunkCoordinate;
import net.momirealms.customcrops.api.object.world.SimpleLocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class MigrateWorld extends Function {
private final String worldName;
private final ConcurrentHashMap<ChunkCoordinate, CCChunk> chunkMap;
public MigrateWorld(String world) {
this.worldName = world;
this.chunkMap = new ConcurrentHashMap<>(64);
}
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
public void init() {
File chunks_folder = new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), ConfigManager.worldFolderPath + worldName + File.separator + "customcrops" + File.separator + "chunks");
if (!chunks_folder.exists()) chunks_folder.mkdirs();
File[] data_files = chunks_folder.listFiles();
if (data_files == null) return;
for (File file : data_files) {
ChunkCoordinate chunkCoordinate = ChunkCoordinate.getByString(file.getName().substring(0, file.getName().length() - 7));
try (FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis)) {
CCChunk chunk = (CCChunk) ois.readObject();
if (chunk.isUseless()) {
file.delete();
continue;
}
if (chunkCoordinate != null) chunkMap.put(chunkCoordinate, chunk);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
public void disable() {
File chunks_folder = new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), ConfigManager.worldFolderPath + worldName + File.separator + "customcrops" + File.separator + "chunks");
if (!chunks_folder.exists()) chunks_folder.mkdirs();
for (Map.Entry<ChunkCoordinate, CCChunk> entry : chunkMap.entrySet()) {
ChunkCoordinate chunkCoordinate = entry.getKey();
CCChunk chunk = entry.getValue();
String fileName = chunkCoordinate.getFileName() + ".ccdata";
File file = new File(chunks_folder, fileName);
if (chunk.isUseless() && file.exists()) {
file.delete();
continue;
}
try (FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(chunk);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public String getWorldName() {
return worldName;
}
public void removePotData(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return;
chunk.removePotData(simpleLocation);
}
public void removeCropData(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return;
chunk.removeCropData(simpleLocation);
}
public void addCropData(SimpleLocation simpleLocation, GrowingCrop growingCrop) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk != null) {
chunk.addCropData(simpleLocation, growingCrop);
return;
}
chunk = createNewChunk(simpleLocation);
chunk.addCropData(simpleLocation, growingCrop);
}
public GrowingCrop getCropData(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk != null) {
return chunk.getCropData(simpleLocation);
}
return null;
}
public int getChunkCropAmount(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return 0;
return chunk.getCropAmount();
}
public void removeGreenhouse(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return;
chunk.removeGreenhouse(simpleLocation);
}
public void addGreenhouse(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk != null) {
chunk.addGreenhouse(simpleLocation);
return;
}
chunk = createNewChunk(simpleLocation);
chunk.addGreenhouse(simpleLocation);
}
public boolean isGreenhouse(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return false;
return chunk.isGreenhouse(simpleLocation);
}
public void removeScarecrow(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return;
chunk.removeScarecrow(simpleLocation);
}
public void addScarecrow(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk != null) {
chunk.addScarecrow(simpleLocation);
return;
}
chunk = createNewChunk(simpleLocation);
chunk.addScarecrow(simpleLocation);
}
public boolean hasScarecrow(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return false;
return chunk.hasScarecrow();
}
public void removeSprinklerData(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return;
chunk.removeSprinklerData(simpleLocation);
}
public void addSprinklerData(SimpleLocation simpleLocation, Sprinkler sprinkler) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk != null) {
chunk.addSprinklerData(simpleLocation, sprinkler);
return;
}
chunk = createNewChunk(simpleLocation);
chunk.addSprinklerData(simpleLocation, sprinkler);
}
@Nullable
public Sprinkler getSprinklerData(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return null;
return chunk.getSprinklerData(simpleLocation);
}
public void addWaterToPot(SimpleLocation simpleLocation, int amount, @Nullable String pot_id) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk != null) {
chunk.addWaterToPot(simpleLocation, amount, pot_id);
return;
}
chunk = createNewChunk(simpleLocation);
chunk.addWaterToPot(simpleLocation, amount, pot_id);
}
public void addFertilizerToPot(SimpleLocation simpleLocation, Fertilizer fertilizer, @NotNull String pot_id) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk != null) {
chunk.addFertilizerToPot(simpleLocation, fertilizer, pot_id);
return;
}
chunk = createNewChunk(simpleLocation);
chunk.addFertilizerToPot(simpleLocation, fertilizer, pot_id);
}
public Pot getPotData(SimpleLocation simpleLocation) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk == null) return null;
return chunk.getPotData(simpleLocation);
}
public void addPotData(SimpleLocation simpleLocation, Pot pot) {
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
if (chunk != null) {
chunk.addPotData(simpleLocation, pot);
return;
}
chunk = createNewChunk(simpleLocation);
chunk.addPotData(simpleLocation, pot);
}
public CCChunk createNewChunk(SimpleLocation simpleLocation) {
CCChunk newChunk = new CCChunk();
chunkMap.put(simpleLocation.getChunkCoordinate(), newChunk);
return newChunk;
}
}

View File

@@ -22,6 +22,8 @@ import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.object.fertilizer.FertilizerConfig;
import net.momirealms.customcrops.api.object.fertilizer.FertilizerType;
import net.momirealms.customcrops.api.object.fill.PassiveFillMethod;
import net.momirealms.customcrops.api.object.hologram.FertilizerHologram;
import net.momirealms.customcrops.api.object.hologram.WaterAmountHologram;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -34,18 +36,23 @@ public class PotConfig {
private final Pair<String, String> pot;
private final boolean enableFertilized;
private final PassiveFillMethod[] passiveFillMethods;
private final boolean enableHologram;
private final PotHologram potHologram;
private final FertilizerHologram fertilizerHologram;
private final WaterAmountHologram waterAmountHologram;
private final String requiredItem;
public PotConfig(int max_storage, String dry_pot, String wet_pot, boolean enableFertilized,
@NotNull PassiveFillMethod[] passiveFillMethods, boolean enableHologram, @Nullable PotHologram potHologram) {
@NotNull PassiveFillMethod[] passiveFillMethods,
@Nullable FertilizerHologram fertilizerHologram,
@Nullable WaterAmountHologram waterAmountHologram,
String requiredItem) {
this.max_storage = max_storage;
this.pot = Pair.of(dry_pot, wet_pot);
this.enableFertilized = enableFertilized;
this.fertilizerConvertMap = new HashMap<>();
this.passiveFillMethods = passiveFillMethods;
this.enableHologram = enableHologram;
this.potHologram = potHologram;
this.fertilizerHologram = fertilizerHologram;
this.waterAmountHologram = waterAmountHologram;
this.requiredItem = requiredItem;
}
public void registerFertilizedPot(FertilizerType fertilizerType, String dry_pot, String wet_pot) {
@@ -81,11 +88,18 @@ public class PotConfig {
return passiveFillMethods;
}
public boolean isHologramEnabled() {
return enableHologram;
@Nullable
public FertilizerHologram getFertilizerHologram() {
return fertilizerHologram;
}
public PotHologram getPotHologram() {
return potHologram;
@Nullable
public WaterAmountHologram getWaterAmountHologram() {
return waterAmountHologram;
}
@Nullable
public String getRequiredItem() {
return requiredItem;
}
}

View File

@@ -1,122 +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.api.object.pot;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.HologramManager;
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.util.AdventureUtils;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PotHologram {
private final String fertilizerText;
private final double fertilizerOffset;
private final String waterText;
private final double waterOffset;
private final HologramManager.Mode mode;
private final int duration;
private final String bar_left;
private final String bar_full;
private final String bar_empty;
private final String bar_right;
private final Pattern betterPattern = Pattern.compile("\\{(.+?)\\}");
public PotHologram(String fertilizerText, double fertilizerOffset, String waterText, double waterOffset, HologramManager.Mode mode, int duration,
String bar_left, String bar_full, String bar_empty, String bar_right) {
this.mode = mode;
this.duration = duration;
this.fertilizerText = fertilizerText;
this.waterText = waterText;
this.fertilizerOffset = fertilizerOffset;
this.waterOffset = waterOffset;
this.bar_left = bar_left;
this.bar_full = bar_full;
this.bar_empty = bar_empty;
this.bar_right = bar_right;
}
private List<String> detectBetterPlaceholders(String text) {
List<String> placeholders = new ArrayList<>();
Matcher matcher = betterPattern.matcher(text);
while (matcher.find()) placeholders.add(matcher.group());
return placeholders;
}
public void show(Player player, Pot pot, Location location, double offset) {
if (fertilizerText != null && pot.getFertilizer() != null) {
String parsed = CustomCrops.getInstance().getIntegrationManager().getPlaceholderManager().parse(player, fertilizerText);
parseAndSend(parsed, player, pot, location, offset + fertilizerOffset);
}
if (waterText != null) {
String parsed = CustomCrops.getInstance().getIntegrationManager().getPlaceholderManager().parse(player, waterText);
parseAndSend(parsed, player, pot, location, offset + waterOffset);
}
}
public void parseAndSend(String parsed, Player player, Pot pot, Location location, double offset) {
for (String detected : detectBetterPlaceholders(parsed)) {
String replacer = getReplacer(detected, pot);
parsed = parsed.replace(detected, replacer);
}
CustomCrops.getInstance().getHologramManager().showHologram(player, location.clone().add(0, offset, 0), AdventureUtils.getComponentFromMiniMessage(parsed), duration * 1000, mode);
}
public String getReplacer(String text, Pot pot) {
switch (text) {
case "{icon}" -> {
Fertilizer fertilizer = pot.getFertilizer();
if (fertilizer == null) return "";
return fertilizer.getConfig().getIcon();
}
case "{left_times}" -> {
Fertilizer fertilizer = pot.getFertilizer();
if (fertilizer == null) return "";
return String.valueOf(fertilizer.getLeftTimes());
}
case "{max_times}" -> {
Fertilizer fertilizer = pot.getFertilizer();
if (fertilizer == null) return "";
return String.valueOf(fertilizer.getConfig().getTimes());
}
case "{current}" -> {
return String.valueOf(pot.getWater());
}
case "{storage}" -> {
return String.valueOf(pot.getConfig().getMaxStorage());
}
case "{water_bar}" -> {
return getWaterBar(pot.getWater(), pot.getConfig().getMaxStorage());
}
}
return "";
}
public String getWaterBar(int current, int storage) {
return bar_left +
String.valueOf(bar_full).repeat(current) +
String.valueOf(bar_empty).repeat(Math.max(storage - current, 0)) +
bar_right;
}
}

View File

@@ -19,9 +19,12 @@ package net.momirealms.customcrops.api.object.pot;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.Function;
import net.momirealms.customcrops.api.object.HologramManager;
import net.momirealms.customcrops.api.object.fertilizer.FertilizerType;
import net.momirealms.customcrops.api.object.fill.PassiveFillMethod;
import net.momirealms.customcrops.api.object.hologram.FertilizerHologram;
import net.momirealms.customcrops.api.object.hologram.HologramManager;
import net.momirealms.customcrops.api.object.hologram.TextDisplayMeta;
import net.momirealms.customcrops.api.object.hologram.WaterAmountHologram;
import net.momirealms.customcrops.api.util.AdventureUtils;
import net.momirealms.customcrops.api.util.ConfigUtils;
import org.bukkit.configuration.ConfigurationSection;
@@ -81,26 +84,43 @@ public class PotManager extends Function {
}
blockToPotKey.put(base_wet, key);
blockToPotKey.put(base_dry, key);
boolean enableHolo = section.getBoolean("hologram.enable", false);
PotConfig potConfig = new PotConfig(
section.getInt("max-water-storage"),
base_dry,
base_wet,
enableFertilized,
methods,
enableHolo,
enableHolo ? new PotHologram(
section.getString("hologram.fertilizer.text"),
section.getBoolean("hologram.fertilizer.enable", false) ? new FertilizerHologram(
section.getString("hologram.fertilizer.content", ""),
section.getDouble("hologram.fertilizer.vertical-offset"),
section.getString("hologram.water.text"),
HologramManager.Mode.valueOf(section.getString("hologram.type", "ARMOR_STAND").toUpperCase()),
section.getInt("hologram.duration"),
new TextDisplayMeta(
section.getBoolean("hologram.text-display-options.has-shadow", false),
section.getBoolean("hologram.text-display-options.is-see-through", false),
section.getBoolean("hologram.text-display-options.use-default-background-color", false),
ConfigUtils.rgbToDecimal(section.getString("hologram.text-display-options.background-color", "0,0,0,128")),
(byte) section.getInt("hologram.text-display-options.text-opacity")
)
) : null,
section.getBoolean("hologram.water.enable", false) ? new WaterAmountHologram(
section.getString("hologram.water.content", ""),
section.getDouble("hologram.water.vertical-offset"),
HologramManager.Mode.valueOf(section.getString("hologram.type", "ARMOR_STAND").toUpperCase()),
section.getInt("hologram.duration"),
section.getString("hologram.water.water-bar.left"),
section.getString("hologram.water.water-bar.full"),
section.getString("hologram.water.water-bar.empty"),
section.getString("hologram.water.water-bar.right")
) : null
section.getString("hologram.water.water-bar.right"),
new TextDisplayMeta(
section.getBoolean("hologram.text-display-options.has-shadow", false),
section.getBoolean("hologram.text-display-options.is-see-through", false),
section.getBoolean("hologram.text-display-options.use-default-background-color", false),
ConfigUtils.rgbToDecimal(section.getString("hologram.text-display-options.background-color", "0,0,0,128")),
(byte) section.getInt("hologram.text-display-options.text-opacity")
)
) : null,
section.getString("hologram.require-item")
);
if (enableFertilized) {
ConfigurationSection fertilizedSec = section.getConfigurationSection("fertilized-pots");

View File

@@ -20,6 +20,7 @@ package net.momirealms.customcrops.api.object.sprinkler;
import net.kyori.adventure.sound.Sound;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.fill.PassiveFillMethod;
import net.momirealms.customcrops.api.object.hologram.WaterAmountHologram;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -33,13 +34,11 @@ public class SprinklerConfig {
private final String threeD;
private final String twoD;
private final PassiveFillMethod[] passiveFillMethods;
private final boolean hasAnimation;
private final boolean hasHologram;
private final SprinklerHologram sprinklerHologram;
private final WaterAmountHologram waterAmountHologram;
private final SprinklerAnimation sprinklerAnimation;
public SprinklerConfig(String key, int storage, int range, @Nullable Sound sound, @NotNull ItemMode itemMode, @NotNull String threeD, @NotNull String twoD,
@NotNull PassiveFillMethod[] passiveFillMethods, boolean hasHologram, boolean hasAnimation, @Nullable SprinklerHologram sprinklerHologram, SprinklerAnimation sprinklerAnimation) {
@NotNull PassiveFillMethod[] passiveFillMethods, @Nullable WaterAmountHologram waterAmountHologram, SprinklerAnimation sprinklerAnimation) {
this.key = key;
this.storage = storage;
this.range = range;
@@ -48,10 +47,8 @@ public class SprinklerConfig {
this.threeD = threeD;
this.twoD = twoD;
this.passiveFillMethods = passiveFillMethods;
this.hasAnimation = hasAnimation;
this.hasHologram = hasHologram;
this.sprinklerAnimation = sprinklerAnimation;
this.sprinklerHologram = sprinklerHologram;
this.waterAmountHologram = waterAmountHologram;
}
public String getKey() {
@@ -91,17 +88,9 @@ public class SprinklerConfig {
return passiveFillMethods;
}
public boolean hasAnimation() {
return hasAnimation;
}
public boolean hasHologram() {
return hasHologram;
}
@Nullable
public SprinklerHologram getSprinklerHologram() {
return sprinklerHologram;
public WaterAmountHologram getSprinklerHologram() {
return waterAmountHologram;
}
@Nullable

View File

@@ -1,53 +0,0 @@
package net.momirealms.customcrops.api.object.sprinkler;
import net.momirealms.customcrops.api.object.HologramManager;
import org.jetbrains.annotations.NotNull;
public class SprinklerHologram {
private final double offset;
private final HologramManager.Mode mode;
private final String content;
private final int duration;
private final String bar_left;
private final String bar_full;
private final String bar_empty;
private final String bar_right;
public SprinklerHologram(@NotNull String content, double offset, HologramManager.Mode mode, int duration, String bar_left, String bar_full, String bar_empty, String bar_right) {
this.offset = offset;
this.content = content;
this.mode = mode;
this.duration = duration;
this.bar_left = bar_left;
this.bar_full = bar_full;
this.bar_empty = bar_empty;
this.bar_right = bar_right;
}
public double getOffset() {
return offset;
}
public HologramManager.Mode getMode() {
return mode;
}
public int getDuration() {
return duration;
}
public String getContent(int current, int storage) {
return content.replace("{current}", String.valueOf(current))
.replace("{storage}", String.valueOf(storage))
.replace("{water_bar}", getWaterBar(current, storage));
}
public String getWaterBar(int current, int storage) {
return bar_left +
String.valueOf(bar_full).repeat(current) +
String.valueOf(bar_empty).repeat(Math.max(storage - current, 0)) +
bar_right;
}
}

View File

@@ -21,9 +21,11 @@ import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.Function;
import net.momirealms.customcrops.api.object.HologramManager;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.fill.PassiveFillMethod;
import net.momirealms.customcrops.api.object.hologram.HologramManager;
import net.momirealms.customcrops.api.object.hologram.TextDisplayMeta;
import net.momirealms.customcrops.api.object.hologram.WaterAmountHologram;
import net.momirealms.customcrops.api.util.AdventureUtils;
import net.momirealms.customcrops.api.util.ConfigUtils;
import org.bukkit.Bukkit;
@@ -93,8 +95,6 @@ public class SprinklerManager extends Function implements Listener {
@Subst("namespace:key") String soundKey = sprinklerSec.getString("place-sound", "minecraft:block.bone_block.place");
Sound sound = sprinklerSec.contains("place-sound") ? Sound.sound(Key.key(soundKey), Sound.Source.PLAYER, 1, 1) : null;
ItemMode itemMode = ItemMode.valueOf(sprinklerSec.getString("type","ITEM_FRAME").toUpperCase());
boolean hasAnimation = sprinklerSec.getBoolean("animation.enable");
boolean hasHologram = sprinklerSec.getBoolean("hologram.enable");
SprinklerConfig sprinklerConfig = new SprinklerConfig(
key,
sprinklerSec.getInt("storage", 3),
@@ -104,9 +104,7 @@ public class SprinklerManager extends Function implements Listener {
threeD,
twoD,
methods,
hasHologram,
hasAnimation,
hasHologram ? new SprinklerHologram(
sprinklerSec.getBoolean("hologram.enable") ? new WaterAmountHologram(
sprinklerSec.getString("hologram.content",""),
sprinklerSec.getDouble("hologram.vertical-offset"),
HologramManager.Mode.valueOf(sprinklerSec.getString("hologram.type", "ARMOR_STAND").toUpperCase()),
@@ -114,9 +112,16 @@ public class SprinklerManager extends Function implements Listener {
sprinklerSec.getString("hologram.water-bar.left"),
sprinklerSec.getString("hologram.water-bar.full"),
sprinklerSec.getString("hologram.water-bar.empty"),
sprinklerSec.getString("hologram.water-bar.right")
sprinklerSec.getString("hologram.water-bar.right"),
new TextDisplayMeta(
sprinklerSec.getBoolean("hologram.text-display-options.has-shadow", false),
sprinklerSec.getBoolean("hologram.text-display-options.is-see-through", false),
sprinklerSec.getBoolean("hologram.text-display-options.use-default-background-color", false),
ConfigUtils.rgbToDecimal(sprinklerSec.getString("hologram.text-display-options.background-color", "0,0,0,128")),
(byte) sprinklerSec.getInt("hologram.text-display-options.text-opacity")
)
) : null,
hasAnimation ? new SprinklerAnimation(
sprinklerSec.getBoolean("animation.enable") ? new SprinklerAnimation(
sprinklerSec.getInt("animation.duration"),
sprinklerSec.getString("animation.item"),
sprinklerSec.getDouble("animation.vertical-offset"),
@@ -148,10 +153,6 @@ public class SprinklerManager extends Function implements Listener {
return sprinklerConfigMap.get(key);
}
public boolean containsSprinkler(String key) {
return sprinklerConfigMap.containsKey(key);
}
@EventHandler
public void onItemSpawn(ItemSpawnEvent event) {
if (event.isCancelled()) return;

View File

@@ -18,12 +18,14 @@
package net.momirealms.customcrops.api.object.world;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.CustomCropsAPI;
import net.momirealms.customcrops.api.object.basic.ConfigManager;
import net.momirealms.customcrops.api.object.crop.GrowingCrop;
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.object.pot.Pot;
import net.momirealms.customcrops.api.object.sprinkler.Sprinkler;
import net.momirealms.customcrops.api.util.ConfigUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -127,7 +129,7 @@ public class CCChunk implements Serializable {
if (pot != null) {
if (pot.addWater(amount)) {
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
CustomCropsAPI.getInstance().changePotModel(simpleLocation, pot);
changePotModel(simpleLocation, pot);
return null;
});
}
@@ -136,7 +138,7 @@ public class CCChunk implements Serializable {
Pot newPot = new Pot(pot_id, null, amount);
potMap.put(simpleLocation, newPot);
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
CustomCropsAPI.getInstance().changePotModel(simpleLocation, newPot);
changePotModel(simpleLocation, newPot);
return null;
});
}
@@ -147,7 +149,7 @@ public class CCChunk implements Serializable {
if (pot != null) {
pot.setFertilizer(fertilizer);
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
CustomCropsAPI.getInstance().changePotModel(simpleLocation, pot);
changePotModel(simpleLocation, pot);
return null;
});
}
@@ -155,7 +157,7 @@ public class CCChunk implements Serializable {
Pot newPot = new Pot(pot_id, fertilizer, 0);
potMap.put(simpleLocation, newPot);
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
CustomCropsAPI.getInstance().changePotModel(simpleLocation, newPot);
changePotModel(simpleLocation, newPot);
return null;
});
}
@@ -181,4 +183,16 @@ public class CCChunk implements Serializable {
ccWorld.pushConsumeTask(simpleLocation, randomGenerator.nextInt(60));
}
}
public void changePotModel(SimpleLocation simpleLocation, Pot pot) {
Location location = simpleLocation.getBukkitLocation();
if (location == null) return;
if (CustomCrops.getInstance().getPlatformInterface().removeAnyBlock(location)) {
String replacer = pot.isWet() ? pot.getConfig().getWetPot(pot.getFertilizer()) : pot.getConfig().getDryPot(pot.getFertilizer());
if (ConfigUtils.isVanillaItem(replacer)) location.getBlock().setType(Material.valueOf(replacer));
else CustomCrops.getInstance().getPlatformInterface().placeNoteBlock(location, replacer);
} else {
CustomCrops.getInstance().getWorldDataManager().removePotData(simpleLocation);
}
}
}

View File

@@ -18,8 +18,6 @@
package net.momirealms.customcrops.api.object.world;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.CustomCropsAPI;
import net.momirealms.customcrops.api.object.CrowTask;
import net.momirealms.customcrops.api.object.Function;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.action.Action;
@@ -50,10 +48,7 @@ import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.*;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@@ -74,8 +69,9 @@ public class CCWorld extends Function {
private final GenericObjectPool<CropCheckTask> cropTaskPool;
private final GenericObjectPool<SprinklerCheckTask> sprinklerTaskPool;
private final GenericObjectPool<ConsumeCheckTask> consumeTaskPool;
private boolean hasWorkedToday;
private boolean hasConsumedToday;
private long lastWorkDay;
private long lastConsumeDay;
private ScheduledFuture<?> scheduledTimerTask;
public CCWorld(World world) {
this.world = new WeakReference<>(world);
@@ -94,12 +90,11 @@ public class CCWorld extends Function {
this.consumeTaskPool = new GenericObjectPool<>(new ConsumeTaskFactory(), new GenericObjectPoolConfig<>());
this.consumeTaskPool.setMaxTotal(10);
this.consumeTaskPool.setMinIdle(1);
this.hasConsumedToday = false;
this.hasWorkedToday = false;
}
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
public void load() {
public void init() {
File chunks_folder = new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), ConfigManager.worldFolderPath + worldName + File.separator + "customcrops" + File.separator + "chunks");
if (!chunks_folder.exists()) chunks_folder.mkdirs();
File[] data_files = chunks_folder.listFiles();
@@ -117,21 +112,24 @@ public class CCWorld extends Function {
e.printStackTrace();
}
}
YamlConfiguration dataFile = ConfigUtils.readData(new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), ConfigManager.worldFolderPath + worldName + File.separator + "customcrops" + File.separator + "data.yml"));
if (ConfigManager.enableSeason && !ConfigManager.rsHook) {
YamlConfiguration seasonDataFile = ConfigUtils.readData(new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), ConfigManager.worldFolderPath + worldName + File.separator + "customcrops" + File.separator + "data.yml"));
SeasonData seasonData;
if (seasonDataFile.contains("season") && seasonDataFile.contains("date")) {
seasonData = new SeasonData(worldName, CCSeason.valueOf(seasonDataFile.getString("season")), seasonDataFile.getInt("date"));
if (dataFile.contains("season") && dataFile.contains("date")) {
seasonData = new SeasonData(worldName, CCSeason.valueOf(dataFile.getString("season")), dataFile.getInt("date"));
} else {
seasonData = new SeasonData(worldName);
}
CustomCrops.getInstance().getSeasonManager().loadSeasonData(seasonData);
}
this.lastConsumeDay = dataFile.getLong("last-consume-day", 0);
this.lastWorkDay = dataFile.getLong("last-work-day", 0);
this.arrangeTask();
}
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
public void unload() {
public void disable() {
closePool();
File chunks_folder = new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), ConfigManager.worldFolderPath + worldName + File.separator + "customcrops" + File.separator + "chunks");
if (!chunks_folder.exists()) chunks_folder.mkdirs();
@@ -150,22 +148,41 @@ public class CCWorld extends Function {
e.printStackTrace();
}
}
YamlConfiguration dataFile = new YamlConfiguration();
if (ConfigManager.enableSeason && !ConfigManager.rsHook) {
YamlConfiguration seasonDataFile = new YamlConfiguration();
SeasonData seasonData = CustomCrops.getInstance().getSeasonManager().unloadSeasonData(worldName);
if (seasonData == null) {
seasonDataFile.set("season", "SPRING");
seasonDataFile.set("date", 1);
dataFile.set("season", "SPRING");
dataFile.set("date", 1);
} else {
seasonDataFile.set("season", seasonData.getSeason().name());
seasonDataFile.set("date", seasonData.getDate());
}
try {
seasonDataFile.save(new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), ConfigManager.worldFolderPath + worldName + File.separator + "customcrops" + File.separator + "data.yml"));
} catch (IOException e) {
AdventureUtils.consoleMessage("<red>[CustomCrops] Failed to save season data for world: " + worldName);
dataFile.set("season", seasonData.getSeason().name());
dataFile.set("date", seasonData.getDate());
}
}
dataFile.set("last-consume-day", lastConsumeDay);
dataFile.set("last-work-day", lastWorkDay);
try {
dataFile.save(new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), ConfigManager.worldFolderPath + worldName + File.separator + "customcrops" + File.separator + "data.yml"));
} catch (IOException e) {
AdventureUtils.consoleMessage("<red>[CustomCrops] Failed to save season data for world: " + worldName);
}
}
public void load() {
if (this.scheduledTimerTask == null) {
this.scheduledTimerTask = this.schedule.scheduleAtFixedRate(() -> {
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleGrowTask(this);
}
}, ThreadLocalRandom.current().nextInt(20), ConfigManager.pointGainInterval, TimeUnit.SECONDS);
}
}
public void unload() {
if (this.scheduledTimerTask != null) {
this.scheduledTimerTask.cancel(false);
this.scheduledTimerTask = null;
}
}
/**
@@ -176,45 +193,29 @@ public class CCWorld extends Function {
this.schedule.scheduleAtFixedRate(() -> {
World current = world.get();
if (current != null) {
long fullTime = current.getFullTime();
long day = fullTime / 24000;
long time = current.getTime();
if (time < 100 && !hasConsumedToday) {
hasConsumedToday = true;
if (time < 100 && day != lastConsumeDay) {
lastConsumeDay = day;
if (ConfigManager.enableSeason && !ConfigManager.rsHook && ConfigManager.autoSeasonChange) {
CustomCrops.getInstance().getSeasonManager().addDate(worldName);
}
if (ConfigManager.enableScheduleSystem) {
schedule.schedule(() -> {
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleConsumeTask(this);
}
}, 0, TimeUnit.SECONDS);
scheduleConsumeTask();
}
}
else if (time > 1950 && time < 2050 && !hasWorkedToday) {
hasWorkedToday = true;
else if (time > 1950 && time < 2050 && lastWorkDay != day) {
lastWorkDay = day;
if (ConfigManager.enableScheduleSystem) {
schedule.schedule(() -> {
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleSprinklerTask(this);
}
}, 0, TimeUnit.SECONDS);
scheduleSprinklerWork();
}
}
else if (time > 23900) {
hasConsumedToday = false;
hasWorkedToday = false;
}
}
else {
this.schedule.shutdown();
}
}, 2, 2, TimeUnit.SECONDS);
this.schedule.scheduleAtFixedRate(() -> {
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleGrowTask(this);
}
}, 1, ConfigManager.pointGainInterval, TimeUnit.SECONDS);
}
private void closePool() {
@@ -327,12 +328,19 @@ public class CCWorld extends Function {
pot.setWater(pot.getWater() + 1);
}
if (pot.reduceWater() | pot.reduceFertilizer()) {
SimpleLocation temp = simpleLocation.copy();
PotConfig potConfig = pot.getConfig();
Fertilizer fertilizer = pot.getFertilizer();
boolean wet = pot.isWet();
Location location = simpleLocation.getBukkitLocation();
if (location == null) return;
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
CustomCropsAPI.getInstance().changePotModel(temp, potConfig, fertilizer, wet);
if (CustomCrops.getInstance().getPlatformInterface().removeAnyBlock(location)) {
String replacer = wet ? potConfig.getWetPot(fertilizer) : potConfig.getDryPot(fertilizer);
if (ConfigUtils.isVanillaItem(replacer)) location.getBlock().setType(Material.valueOf(replacer));
else CustomCrops.getInstance().getPlatformInterface().placeNoteBlock(location, replacer);
} else {
CustomCrops.getInstance().getWorldDataManager().removePotData(SimpleLocation.getByBukkitLocation(location));
}
return null;
});
}
@@ -366,18 +374,18 @@ public class CCWorld extends Function {
removeSprinklerData(simpleLocation);
return;
}
if (sprinklerConfig.hasAnimation()) {
SprinklerAnimation sprinklerAnimation = sprinklerConfig.getSprinklerAnimation();
Location location = simpleLocation.getBukkitLocation();
if (location != null && sprinklerAnimation != null) {
for (Player player : Bukkit.getOnlinePlayers()) {
SimpleLocation playerLoc = SimpleLocation.getByBukkitLocation(player.getLocation());
if (playerLoc.isNear(simpleLocation, 48)) {
FakeEntityUtils.playWaterAnimation(player, location.clone().add(0.5, sprinklerAnimation.offset(), 0.5), sprinklerAnimation.id(), sprinklerAnimation.duration(), sprinklerAnimation.itemMode());
}
SprinklerAnimation sprinklerAnimation = sprinklerConfig.getSprinklerAnimation();
Location location = simpleLocation.getBukkitLocation();
if (location != null && sprinklerAnimation != null) {
for (Player player : Bukkit.getOnlinePlayers()) {
SimpleLocation playerLoc = SimpleLocation.getByBukkitLocation(player.getLocation());
if (playerLoc.isNear(simpleLocation, 48)) {
FakeEntityUtils.playWaterAnimation(player, location.clone().add(0.5, sprinklerAnimation.offset(), 0.5), sprinklerAnimation.id(), sprinklerAnimation.duration(), sprinklerAnimation.itemMode());
}
}
}
sprinkler.setWater(--water);
if (water == 0) {
removeSprinklerData(simpleLocation);
@@ -512,8 +520,8 @@ public class CCWorld extends Function {
});
loadEntities.whenComplete((result, throwable) ->
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
if (CustomCropsAPI.getInstance().removeCustomItem(location, itemMode)) {
CustomCropsAPI.getInstance().placeCustomItem(location, finalNextModel, itemMode);
if (CustomCrops.getInstance().getPlatformInterface().removeCustomItem(location, itemMode)) {
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, finalNextModel, itemMode);
} else {
removeCropData(simpleLocation);
}
@@ -523,8 +531,8 @@ public class CCWorld extends Function {
else {
asyncGetChunk.whenComplete((result, throwable) ->
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
if (CustomCropsAPI.getInstance().removeCustomItem(location, itemMode)) {
CustomCropsAPI.getInstance().placeCustomItem(location, finalNextModel, itemMode);
if (CustomCrops.getInstance().getPlatformInterface().removeCustomItem(location, itemMode)) {
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, finalNextModel, itemMode);
} else {
removeCropData(simpleLocation);
}
@@ -739,4 +747,20 @@ public class CCWorld extends Function {
chunkMap.put(simpleLocation.getChunkCoordinate(), newChunk);
return newChunk;
}
public void scheduleSprinklerWork() {
schedule.execute(() -> {
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleSprinklerTask(this);
}
});
}
public void scheduleConsumeTask() {
schedule.schedule(() -> {
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleConsumeTask(this);
}
}, 0, TimeUnit.SECONDS);
}
}

View File

@@ -47,18 +47,24 @@ public class WorldDataManager extends Function {
@Override
public void load() {
Bukkit.getPluginManager().registerEvents(worldListener, plugin);
for (CCWorld ccWorld : worldMap.values()) {
ccWorld.load();
}
}
@Override
public void unload() {
HandlerList.unregisterAll(worldListener);
for (CCWorld ccWorld : worldMap.values()) {
ccWorld.unload();
}
}
@Override
public void disable() {
this.unload();
for (CCWorld ccWorld : worldMap.values()) {
ccWorld.unload();
ccWorld.disable();
}
this.worldMap.clear();
}
@@ -66,6 +72,7 @@ public class WorldDataManager extends Function {
public void loadWorld(World world) {
if (!isWorldAllowed(world)) return;
CCWorld ccWorld = new CCWorld(world);
ccWorld.init();
ccWorld.load();
worldMap.put(world.getName(), ccWorld);
}
@@ -73,7 +80,7 @@ public class WorldDataManager extends Function {
public void unloadWorld(World world) {
CCWorld ccWorld = worldMap.remove(world.getName());
if (ccWorld != null) {
ccWorld.unload();
ccWorld.disable();
}
}
@@ -234,4 +241,9 @@ public class WorldDataManager extends Function {
}
return null;
}
@Nullable
public CCWorld getWorld(String world) {
return worldMap.get(world);
}
}

View File

@@ -389,11 +389,9 @@ public class ConfigUtils {
ConfigurationSection methodSec = section.getConfigurationSection(key);
if (methodSec == null) continue;
String id = methodSec.getString("target", "WATER");
PositiveFillMethod.InteractType type = PositiveFillMethod.InteractType.valueOf(methodSec.getString("type", "block").toUpperCase());
@Subst("namespace:key") String soundKey = methodSec.getString("sound", "minecraft:item.bucket.fill");
Sound sound = Sound.sound(Key.key(soundKey), Sound.Source.PLAYER, 1, 1);
PositiveFillMethod method = new PositiveFillMethod(
type,
id,
methodSec.getInt("amount"),
methodSec.contains("particle") ? Particle.valueOf(methodSec.getString("particle", "WATER_SPLASH").toUpperCase()) : null,
@@ -420,4 +418,13 @@ public class ConfigUtils {
}
return interactWithItems.toArray(new InteractWithItem[0]);
}
public static int rgbToDecimal(String rgba) {
String[] split = rgba.split(",");
int r = Integer.parseInt(split[0]);
int g = Integer.parseInt(split[1]);
int b = Integer.parseInt(split[2]);
int a = Integer.parseInt(split[3]);
return (a << 24) | (r << 16) | (g << 8) | b;
}
}

View File

@@ -25,6 +25,7 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.ItemMode;
import net.momirealms.customcrops.api.object.hologram.TextDisplayMeta;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
@@ -44,9 +45,7 @@ public class FakeEntityUtils {
CustomCrops.getProtocolManager().sendServerPacket(player, getSpawnPacket(id, location, EntityType.ITEM_DISPLAY));
CustomCrops.getProtocolManager().sendServerPacket(player, getItemDisplayMetaPacket(id, CustomCrops.getInstance().getIntegrationManager().build(animation_id)));
}
CustomCrops.getInstance().getScheduler().runTaskAsyncLater(() -> {
CustomCrops.getProtocolManager().sendServerPacket(player, getDestroyPacket(id));
}, 1000L * duration);
CustomCrops.getInstance().getScheduler().runTaskAsyncLater(() -> CustomCrops.getProtocolManager().sendServerPacket(player, getDestroyPacket(id)), 1000L * duration);
}
public static WrappedDataWatcher createInvisibleDataWatcher() {
@@ -110,15 +109,13 @@ public class FakeEntityUtils {
public static PacketContainer getVanishArmorStandMetaPacket(int id, Component component) {
PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher();
WrappedDataWatcher.Serializer serializer1 = WrappedDataWatcher.Registry.get(Boolean.class);
WrappedDataWatcher.Serializer serializer2 = WrappedDataWatcher.Registry.get(Byte.class);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(2, WrappedDataWatcher.Registry.getChatComponentSerializer(true)), Optional.of(WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component)).getHandle()));
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, serializer1), true);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(5, serializer1), true);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, WrappedDataWatcher.Registry.get(Boolean.class)), true);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(5, WrappedDataWatcher.Registry.get(Boolean.class)), true);
byte mask1 = 0x20;
byte mask2 = 0x01;
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, serializer2), mask1);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(15, serializer2), mask2);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, WrappedDataWatcher.Registry.get(Byte.class)), mask1);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(15, WrappedDataWatcher.Registry.get(Byte.class)), mask2);
metaPacket.getModifier().write(0, id);
if (CustomCrops.getInstance().getVersionHelper().isVersionNewerThan1_19_R2()) {
setWrappedDataValue(metaPacket, wrappedDataWatcher);
@@ -132,16 +129,24 @@ public class FakeEntityUtils {
PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
metaPacket.getModifier().write(0, id);
WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher();
wrappedDataWatcher.setObject(22, itemStack);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(22, WrappedDataWatcher.Registry.getItemStackSerializer(false)), itemStack);
setWrappedDataValue(metaPacket, wrappedDataWatcher);
return metaPacket;
}
public static PacketContainer getTextDisplayMetaPacket(int id, Component component) {
public static PacketContainer getTextDisplayMetaPacket(int id, Component component, TextDisplayMeta textDisplayMeta) {
PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
metaPacket.getModifier().write(0, id);
WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher();
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(22, WrappedDataWatcher.Registry.getChatComponentSerializer(true)), Optional.of(WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component)).getHandle()));
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(22, WrappedDataWatcher.Registry.getChatComponentSerializer(false)), WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component)));
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(24, WrappedDataWatcher.Registry.get(Integer.class)), textDisplayMeta.getBackgroundColor());
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(14, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 3);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(25, WrappedDataWatcher.Registry.get(Byte.class)), textDisplayMeta.getOpacity());
int mask = 0;
if (textDisplayMeta.isHasShadow()) mask += 1;
if (textDisplayMeta.isSeeThrough()) mask += 2;
if (textDisplayMeta.isUseDefaultBackground()) mask += 4;
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(26, WrappedDataWatcher.Registry.get(Byte.class)), (byte) mask);
setWrappedDataValue(metaPacket, wrappedDataWatcher);
return metaPacket;
}

View File

@@ -27,5 +27,7 @@ public class CustomCropsCommand extends AbstractMainCommand {
regSubCommand(HelpCommand.INSTANCE);
regSubCommand(AboutCommand.INSTANCE);
regSubCommand(SetDateCommand.INSTANCE);
regSubCommand(ForceCommand.INSTANCE);
regSubCommand(MigrateCommand.INSTANCE);
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.command.subcmd;
import net.momirealms.customcrops.command.AbstractSubCommand;
import net.momirealms.customcrops.command.subcmd.force.ConsumeTaskCommand;
import net.momirealms.customcrops.command.subcmd.force.SprinklerWorkCommand;
public class ForceCommand extends AbstractSubCommand {
public static final ForceCommand INSTANCE = new ForceCommand();
public ForceCommand() {
super("force");
regSubCommand(SprinklerWorkCommand.INSTANCE);
regSubCommand(ConsumeTaskCommand.INSTANCE);
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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.command.subcmd;
import com.google.gson.*;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.basic.ConfigManager;
import net.momirealms.customcrops.api.object.crop.GrowingCrop;
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.object.fertilizer.FertilizerConfig;
import net.momirealms.customcrops.api.object.migrate.MigrateWorld;
import net.momirealms.customcrops.api.object.season.CCSeason;
import net.momirealms.customcrops.api.object.season.SeasonData;
import net.momirealms.customcrops.api.object.world.SimpleLocation;
import net.momirealms.customcrops.api.util.AdventureUtils;
import net.momirealms.customcrops.command.AbstractSubCommand;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class MigrateCommand extends AbstractSubCommand {
public static final MigrateCommand INSTANCE = new MigrateCommand();
public MigrateCommand() {
super("migrate");
}
@Override
public boolean onCommand(CommandSender sender, List<String> args) {
if (sender instanceof Player player) {
AdventureUtils.playerMessage(player, "Migration started. See the console for more information.");
}
AdventureUtils.consoleMessage("[CustomCrops] Migration has started.");
Bukkit.getScheduler().runTaskAsynchronously(CustomCrops.getInstance(), new MigrationTask());
return true;
}
public static class MigrationTask implements Runnable {
@Override
public void run() {
File outer_folder = new File(CustomCrops.getInstance().getDataFolder().getAbsoluteFile().getParentFile().getParentFile() + ConfigManager.worldFolderPath);
if (!outer_folder.isDirectory()) {
AdventureUtils.consoleMessage("<red>[CustomCrops] World folder is not detected");
return;
}
File[] files = outer_folder.listFiles();
if (files == null) return;
List<File> world_folders = Arrays.stream(files).filter(File::isDirectory).toList();
for (File world_folder : world_folders) {
File ccDataFolder = new File(world_folder, "customcrops_data");
if (!ccDataFolder.isDirectory()) continue;
String worldName = world_folder.getName();
AdventureUtils.consoleMessage("<green>[CustomCrops] Migrating world: " + worldName);
MigrateWorld migrateWorld = new MigrateWorld(worldName);
migrateWorld.init();
try {
JsonElement json = JsonParser.parseReader(new FileReader(new File(ccDataFolder, "season.json")));
if (json.isJsonObject()) {
JsonObject jsonObject = json.getAsJsonObject();
if (jsonObject.has("season")) {
JsonPrimitive jsonPrimitive = jsonObject.getAsJsonPrimitive("season");
String season = jsonPrimitive.getAsString();
CustomCrops.getInstance().getSeasonManager().loadSeasonData(new SeasonData(worldName, CCSeason.valueOf(season), 1));
}
}
} catch (FileNotFoundException ignored) {
}
AdventureUtils.consoleMessage("<white>[CustomCrops] Migrated " + worldName + "'s season");
try {
JsonElement json= JsonParser.parseReader(new FileReader(new File(ccDataFolder, "pot.json")));
if (json.isJsonObject()) {
JsonObject jsonObject = json.getAsJsonObject();
if (jsonObject.has("pot")) {
JsonArray jsonArray = jsonObject.getAsJsonArray("pot");
for (JsonElement jsonElement : jsonArray) {
String loc = jsonElement.getAsString();
String[] locs = StringUtils.split(loc, ",");
SimpleLocation simpleLocation = new SimpleLocation(worldName, Integer.parseInt(locs[0]), Integer.parseInt(locs[1]), Integer.parseInt(locs[2]));
migrateWorld.addWaterToPot(simpleLocation, 1, "default");
}
}
}
} catch (FileNotFoundException ignored) {
}
AdventureUtils.consoleMessage("<white>[CustomCrops] Migrated " + worldName + "'s pots");
YamlConfiguration data = YamlConfiguration.loadConfiguration(new File(ccDataFolder, "fertilizers.yml"));
for (String key : data.getKeys(false)) {
String[] loc = StringUtils.split(key, ",");
SimpleLocation location = new SimpleLocation(worldName, Integer.parseInt(loc[0]), Integer.parseInt(loc[1]), Integer.parseInt(loc[2]));
String fertilizer = data.getString(key + ".type");
int times = data.getInt(key + ".times");
FertilizerConfig fertilizerConfig = CustomCrops.getInstance().getFertilizerManager().getConfigByKey(fertilizer);
if (fertilizerConfig != null) {
Fertilizer fertilizer1 = new Fertilizer(fertilizerConfig);
fertilizer1.setTimes(times);
migrateWorld.addFertilizerToPot(location, fertilizer1, "default");
}
}
AdventureUtils.consoleMessage("<white>[CustomCrops] Migrated " + worldName + "'s fertilizers");
try {
JsonElement json= JsonParser.parseReader(new FileReader(new File(ccDataFolder, "scarecrow.json")));
if (json.isJsonObject()) {
JsonObject jsonObject = json.getAsJsonObject();
for (Map.Entry<String, JsonElement> en : jsonObject.entrySet()) {
JsonArray jsonArray = en.getValue().getAsJsonArray();
int size = jsonArray.size();
for (int i = 0; i < size; i++) {
String[] loc = StringUtils.split(jsonArray.get(i).getAsString(), ",");
migrateWorld.addScarecrow(new SimpleLocation(worldName, Integer.parseInt(loc[0]), Integer.parseInt(loc[1]), Integer.parseInt(loc[2])));
}
}
}
}
catch (FileNotFoundException ignore) {
}
AdventureUtils.consoleMessage("<white>[CustomCrops] Migrated " + worldName + "'s scarecrows");
YamlConfiguration cropData = YamlConfiguration.loadConfiguration(new File(ccDataFolder, "crops.yml"));
for (Map.Entry<String, Object> entry : cropData.getValues(false).entrySet()) {
String crop = (String) entry.getValue();
GrowingCrop growingCrop;
if (crop.contains("_")) {
String stageStr = crop.substring(crop.indexOf("_stage_") + 7);
int stage = Integer.parseInt(stageStr);
growingCrop = new GrowingCrop(crop.substring(0, crop.indexOf("_stage_")), stage);
String[] loc = StringUtils.split(entry.getKey(), ",");
SimpleLocation simpleLocation = new SimpleLocation(worldName, Integer.parseInt(loc[0]), Integer.parseInt(loc[1]), Integer.parseInt(loc[2]));
migrateWorld.addCropData(simpleLocation, growingCrop);
}
}
AdventureUtils.consoleMessage("<white>[CustomCrops] Migrated " + worldName + "'s crops");
migrateWorld.disable();
}
AdventureUtils.consoleMessage("<green>[CustomCrops] Migration finished!");
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.command.subcmd.force;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.basic.MessageManager;
import net.momirealms.customcrops.api.object.world.CCWorld;
import net.momirealms.customcrops.api.util.AdventureUtils;
import net.momirealms.customcrops.command.AbstractSubCommand;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.generator.WorldInfo;
import java.util.List;
import java.util.stream.Collectors;
public class ConsumeTaskCommand extends AbstractSubCommand {
public static final ConsumeTaskCommand INSTANCE = new ConsumeTaskCommand();
public ConsumeTaskCommand() {
super("consume");
}
@Override
public boolean onCommand(CommandSender sender, List<String> args) {
if (lackArgs(sender, 1, args.size())) return true;
World world = Bukkit.getWorld(args.get(0));
if (world == null) {
AdventureUtils.sendMessage(sender, MessageManager.prefix + MessageManager.worldNotExist.replace("{world}", args.get(0)));
return true;
}
CustomCrops.getInstance().getScheduler().runTaskAsync(() -> {
CCWorld ccworld = CustomCrops.getInstance().getWorldDataManager().getWorld(args.get(0));
if (ccworld != null) {
ccworld.scheduleConsumeTask();
}
});
return true;
}
@Override
public List<String> onTabComplete(CommandSender sender, List<String> args) {
if (args.size() == 1) {
return super.filterStartingWith(Bukkit.getWorlds().stream().filter(world -> CustomCrops.getInstance().getWorldDataManager().isWorldAllowed(world)).map(WorldInfo::getName).collect(Collectors.toList()), args.get(0));
}
return null;
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.command.subcmd.force;
import net.momirealms.customcrops.CustomCrops;
import net.momirealms.customcrops.api.object.basic.MessageManager;
import net.momirealms.customcrops.api.object.world.CCWorld;
import net.momirealms.customcrops.api.util.AdventureUtils;
import net.momirealms.customcrops.command.AbstractSubCommand;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.generator.WorldInfo;
import java.util.List;
import java.util.stream.Collectors;
public class SprinklerWorkCommand extends AbstractSubCommand {
public static final SprinklerWorkCommand INSTANCE = new SprinklerWorkCommand();
public SprinklerWorkCommand() {
super("sprinklerwork");
}
@Override
public boolean onCommand(CommandSender sender, List<String> args) {
if (lackArgs(sender, 1, args.size())) return true;
World world = Bukkit.getWorld(args.get(0));
if (world == null) {
AdventureUtils.sendMessage(sender, MessageManager.prefix + MessageManager.worldNotExist.replace("{world}", args.get(0)));
return true;
}
CustomCrops.getInstance().getScheduler().runTaskAsync(() -> {
CCWorld ccworld = CustomCrops.getInstance().getWorldDataManager().getWorld(args.get(0));
if (ccworld != null) {
ccworld.scheduleSprinklerWork();
}
});
return true;
}
@Override
public List<String> onTabComplete(CommandSender sender, List<String> args) {
if (args.size() == 1) {
return super.filterStartingWith(Bukkit.getWorlds().stream().filter(world -> CustomCrops.getInstance().getWorldDataManager().isWorldAllowed(world)).map(WorldInfo::getName).collect(Collectors.toList()), args.get(0));
}
return null;
}
}

View File

@@ -27,6 +27,10 @@ import net.momirealms.customcrops.integration.item.MMOItemsItemImpl;
import net.momirealms.customcrops.integration.job.EcoJobsImpl;
import net.momirealms.customcrops.integration.job.JobsRebornImpl;
import net.momirealms.customcrops.integration.papi.PlaceholderManager;
import net.momirealms.customcrops.integration.quest.BattlePassCCQuest;
import net.momirealms.customcrops.integration.quest.BetonQuestCCQuest;
import net.momirealms.customcrops.integration.quest.ClueScrollCCQuest;
import net.momirealms.customcrops.integration.quest.LegacyBetonQuestCCQuest;
import net.momirealms.customcrops.integration.season.CustomCropsSeasonImpl;
import net.momirealms.customcrops.integration.season.RealisticSeasonsImpl;
import net.momirealms.customcrops.integration.skill.AureliumsImpl;
@@ -56,6 +60,7 @@ public class IntegrationManager extends Function {
this.plugin = plugin;
this.pluginManager = Bukkit.getPluginManager();
this.placeholderManager = new PlaceholderManager(plugin);
this.registerQuests();
}
@Override
@@ -141,6 +146,21 @@ public class IntegrationManager extends Function {
return new ItemStack(Material.AIR);
}
private void registerQuests() {
PluginManager pluginManager = Bukkit.getPluginManager();
if (pluginManager.isPluginEnabled("ClueScrolls")) {
ClueScrollCCQuest quest = new ClueScrollCCQuest(plugin);
Bukkit.getPluginManager().registerEvents(quest, plugin);
}
if (pluginManager.isPluginEnabled("BetonQuest")) {
if (Bukkit.getPluginManager().getPlugin("BetonQuest").getDescription().getVersion().startsWith("2")) BetonQuestCCQuest.register();
else LegacyBetonQuestCCQuest.register();
}
if (pluginManager.isPluginEnabled("BattlePass")) {
BattlePassCCQuest.register();
}
}
@Nullable
public SkillInterface getSkillInterface() {
return skillInterface;

View File

@@ -0,0 +1,45 @@
/*
* 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.integration.quest;
import io.github.battlepass.BattlePlugin;
import io.github.battlepass.quests.quests.external.executor.ExternalQuestExecutor;
import io.github.battlepass.registry.quest.QuestRegistry;
import net.momirealms.customcrops.api.event.CropBreakEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class BattlePassCCQuest extends ExternalQuestExecutor implements Listener {
public static void register() {
QuestRegistry questRegistry = BattlePlugin.getApi().getQuestRegistry();
questRegistry.hook("customcrops", BattlePassCCQuest::new);
}
public BattlePassCCQuest(BattlePlugin battlePlugin) {
super(battlePlugin, "customcrops");
}
@EventHandler
public void onHarvest(CropBreakEvent event) {
if (event.isCancelled()) return;
Player player = event.getPlayer();
this.execute("harvest", player, (var1x) -> var1x.root(event.getCropItemID()));
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.integration.quest;
import net.momirealms.customcrops.api.event.CropBreakEvent;
import net.momirealms.customcrops.api.util.AdventureUtils;
import org.betonquest.betonquest.BetonQuest;
import org.betonquest.betonquest.Instruction;
import org.betonquest.betonquest.VariableNumber;
import org.betonquest.betonquest.api.CountingObjective;
import org.betonquest.betonquest.api.profiles.OnlineProfile;
import org.betonquest.betonquest.api.profiles.Profile;
import org.betonquest.betonquest.exceptions.InstructionParseException;
import org.betonquest.betonquest.utils.PlayerConverter;
import org.betonquest.betonquest.utils.location.CompoundLocation;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import java.util.Collections;
import java.util.HashSet;
public class BetonQuestCCQuest extends CountingObjective implements Listener {
private final CompoundLocation playerLocation;
private final VariableNumber rangeVar;
private final HashSet<String> crop_ids;
public BetonQuestCCQuest(Instruction instruction) throws InstructionParseException {
super(instruction, "crop_to_harvest");
crop_ids = new HashSet<>();
Collections.addAll(crop_ids, instruction.getArray());
targetAmount = instruction.getInt();
final String pack = instruction.getPackage().getQuestPath();
final String loc = instruction.getOptional("playerLocation");
final String range = instruction.getOptional("range");
if (loc != null && range != null) {
playerLocation = new CompoundLocation(pack, loc);
rangeVar = new VariableNumber(pack, range);
} else {
playerLocation = null;
rangeVar = null;
}
if (targetAmount <= 0) {
throw new InstructionParseException("Crop amount cannot be less than 0");
}
}
public static void register() {
BetonQuest.getInstance().registerObjectives("customcrops", BetonQuestCCQuest.class);
}
@EventHandler
public void onHarvest(CropBreakEvent event) {
OnlineProfile onlineProfile = PlayerConverter.getID(event.getPlayer());
if (!containsPlayer(onlineProfile)) {
return;
}
if (isInvalidLocation(event, onlineProfile)) {
return;
}
if (this.crop_ids.contains(event.getCropItemID()) && this.checkConditions(onlineProfile)) {
getCountingData(onlineProfile).progress(1);
completeIfDoneOrNotify(onlineProfile);
}
}
private boolean isInvalidLocation(CropBreakEvent event, final Profile profile) {
if (playerLocation == null || rangeVar == null) {
return false;
}
final Location targetLocation;
try {
targetLocation = playerLocation.getLocation(profile);
} catch (final org.betonquest.betonquest.exceptions.QuestRuntimeException e) {
AdventureUtils.consoleMessage(e.getMessage());
return true;
}
final int range = rangeVar.getInt(profile);
final Location playerLoc = event.getPlayer().getLocation();
return !playerLoc.getWorld().equals(targetLocation.getWorld()) || targetLocation.distanceSquared(playerLoc) > range * range;
}
@Override
public void start() {
Bukkit.getPluginManager().registerEvents(this, BetonQuest.getInstance());
}
@Override
public void stop() {
HandlerList.unregisterAll(this);
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.integration.quest;
import com.electro2560.dev.cluescrolls.api.*;
import net.momirealms.customcrops.api.event.CropBreakEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
public class ClueScrollCCQuest implements Listener {
private final CustomClue commonClue;
public ClueScrollCCQuest(Plugin plugin) {
commonClue = ClueScrollsAPI.getInstance().registerCustomClue(plugin, "harvest", new ClueConfigData("crop_id", DataType.STRING));
}
@EventHandler
public void onHarvest(CropBreakEvent event) {
if (event.isCancelled()) return;
commonClue.handle(event.getPlayer(), 1, new ClueDataPair("crop_id", event.getCropItemID()));
}
}

View File

@@ -0,0 +1,156 @@
/*
* 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.integration.quest;
import net.momirealms.customcrops.api.event.CropBreakEvent;
import net.momirealms.customcrops.api.util.AdventureUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import pl.betoncraft.betonquest.BetonQuest;
import pl.betoncraft.betonquest.Instruction;
import pl.betoncraft.betonquest.api.Objective;
import pl.betoncraft.betonquest.config.Config;
import pl.betoncraft.betonquest.exceptions.InstructionParseException;
import pl.betoncraft.betonquest.exceptions.QuestRuntimeException;
import pl.betoncraft.betonquest.utils.LogUtils;
import pl.betoncraft.betonquest.utils.PlayerConverter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.logging.Level;
public class LegacyBetonQuestCCQuest extends Objective implements Listener {
private final HashSet<String> crop_ids = new HashSet<>();
private final int amount;
private final boolean notify;
private final int notifyInterval;
public LegacyBetonQuestCCQuest(Instruction instruction) throws InstructionParseException {
super(instruction);
this.template = CropData.class;
this.notifyInterval = instruction.getInt(instruction.getOptional("notify"), 1);
this.notify = instruction.hasArgument("notify") || this.notifyInterval > 1;
this.amount = instruction.getInt(instruction.getOptional("amount"), 1);
Collections.addAll(this.crop_ids, instruction.getArray());
}
public static void register() {
BetonQuest.getInstance().registerObjectives("customfishing", LegacyBetonQuestCCQuest.class);
}
@Override
public void start() {
Bukkit.getPluginManager().registerEvents(this, BetonQuest.getInstance());
}
@Override
public void stop() {
HandlerList.unregisterAll(this);
}
@Override
public String getDefaultDataInstruction() {
return Integer.toString(this.amount);
}
@Override
public String getProperty(String name, String playerID) {
return switch (name.toLowerCase(Locale.ROOT)) {
case "amount" ->
Integer.toString(this.amount - ((LegacyBetonQuestCCQuest.CropData) this.dataMap.get(playerID)).getAmount());
case "left" -> Integer.toString(((LegacyBetonQuestCCQuest.CropData) this.dataMap.get(playerID)).getAmount());
case "total" -> Integer.toString(this.amount);
default -> "";
};
}
private boolean isValidPlayer(Player player) {
if (player == null) {
return false;
} else {
return player.isOnline() && player.isValid();
}
}
@EventHandler
public void onHarvest(CropBreakEvent event) {
String playerID = PlayerConverter.getID(event.getPlayer());
if (this.containsPlayer(playerID)) {
if (this.crop_ids.contains(event.getCropItemID())) {
if (this.checkConditions(playerID)) {
if (!isValidPlayer(event.getPlayer())) {
return;
}
CropData cropData = (CropData) this.dataMap.get(playerID);
cropData.harvest(1);
if (cropData.finished()) {
this.completeObjective(playerID);
}
else if (this.notify && cropData.getAmount() % this.notifyInterval == 0) {
try {
Config.sendNotify(this.instruction.getPackage().getName(), playerID, "crop_to_harvest", new String[]{String.valueOf(cropData.getAmount())}, "crop_to_harvest,info");
} catch (QuestRuntimeException e1) {
try {
LogUtils.getLogger().log(Level.WARNING, "The notify system was unable to play a sound for the 'crop_to_harvest' category in '" + this.instruction.getObjective().getFullID() + "'. Error was: '" + e1.getMessage() + "'");
} catch (InstructionParseException e2) {
LogUtils.logThrowableReport(e2);
}
}
}
}
}
}
}
public static class CropData extends Objective.ObjectiveData {
private int amount;
public CropData(String instruction, String playerID, String objID) {
super(instruction, playerID, objID);
try {
this.amount = Integer.parseInt(instruction);
}
catch (NumberFormatException e) {
AdventureUtils.consoleMessage("[CustomCrops] NumberFormatException");
this.amount = 1;
}
}
public void harvest(int caughtAmount) {
this.amount -= caughtAmount;
this.update();
}
public int getAmount() {
return this.amount;
}
public String toString() {
return String.valueOf(this.amount);
}
public boolean finished() {
return this.amount <= 0;
}
}
}

View File

@@ -4,20 +4,6 @@ config-version: '25'
metrics: true
# Language: english / spanish / chinese / turkish
lang: english
# AntiGrief
integrations:
Residence: false
WorldGuard: false
Kingdoms: false
GriefDefender: false
PlotSquared: false
Towny: false
Lands: false
GriefPrevention: false
CrashClaim: false
BentoBox: false
IridiumSkyBlock: false
SuperiorSkyBlock: false
worlds:
# This is designed for servers that using a separate folder for worlds
@@ -84,6 +70,9 @@ mechanics:
# effective range (Y axis)
# Y轴有效范围
range: 5
# scarecrow item id
# 稻草人物品id
scarecrow: customcrops:scarecrow
other-settings:
# This option requires a skill-plugin hook

View File

@@ -1,20 +1,33 @@
# Crop key name
# 农作物配置名
tomato:
# TripWire / Item_Frame / Item_Display (1.19.4+)
crop-mode: Item_Frame
# Crop mode, make sure that type is consistent with IA/Oraxen configs
# Otherwise some unexpected problems would occur
# TRIPWIRE / ITEM_FRAME / ITEM_DISPLAY (1.19.4+)
# 农作物模式请确保和你的资源包配置等一致否则会出现bug
type: ITEM_FRAME
# The crop can only be planted on certain pots
# Pot are stored in /CustomCrops/contents/pots
# 农作物只能在指定的种植盆中种植
pot-whitelist:
- default
# Seed
# Crop's seed, if you want to use Vanilla items, just use Capital letters. (Example APPLE)
# 农作物的种子,如果你想用原版物品做种子,就使用大写字母
seed: customcrops:tomato_seeds
# break/plant requirements
# 破坏/种植农作物的需求
requirements:
break:
requirement_1:
# Requirement type, you can get a full list of requirements on wiki page
# 需求类型,wiki中有详细的全部需求类型和示范
type: permission
value: tomato.break
# The message to show when not meeting the requirement(Supports multiple lines)
# 不满足需求的提示,支持多行
message: "You don't have permission to harvest the tomato"
plant:
requirement_1:
@@ -29,8 +42,11 @@ tomato:
message: "It's not a good season to plant tomato"
# plant actions
# 种植时发生的动作
plant-actions:
action_1:
# Requirement type, you can get a full list of actions on wiki page
# 动作类型,wiki中有详细的全部动作类型和示范
type: sound
value:
source: player
@@ -39,11 +55,23 @@ tomato:
pitch: 1
# This decides when the crop data would be removed from cache
# 这决定了农作物数据什么时候从缓存中移除
max-points: 6
# What should a crop do when gaining a certain amount of points
# 农作物在获取指定生长点数时候执行的动作
points:
0:
# change the crop's model
# 改变农作物的模型
model: customcrops:tomato_stage_1
# As crop's models are different and have various height
# So sometimes the pot information hologram can't show in a proper place
# Set "hologram-offset-correction" to a high value would increase the
# vertical position of the hologram
# 因为不同农作物有不同的模型高度,所以在显示悬浮信息的时候,可能会导致模型遮挡了悬浮信息
# 因此设置 "hologram-offset-correction" 为更大值可以提升悬浮字的高度,以免遮挡
hologram-offset-correction: 0.2
# Available events: break/grow/interact-by-hand/interact-with-item
events:
break:
action_1:
@@ -51,9 +79,13 @@ tomato:
value:
other-items:
loot_1:
# Other plugin item compatibility(Can also be used in quality-crops)
# MMOItems:TYPE:ID
# MythicMobs:id
item: customcrops:tomato_seeds
min: 1
max: 1
# 0-1
chance: 0.3
action_2:
type: sound
@@ -128,9 +160,6 @@ tomato:
min: 1
max: 4
items:
# Other plugin item compatibility(Can also be used in other-items)
# MMOItems:TYPE:ID
# MythicMobs:id
1: customcrops:tomato
2: customcrops:tomato_silver_star
3: customcrops:tomato_golden_star
@@ -146,22 +175,31 @@ tomato:
value:
golden:
item: customcrops:tomato_stage_golden
type: TripWire
type: TRIPWIRE
chance: 0.01
interact-by-hand:
action_1:
type: break
value: true # whether to trigger break event too 是否触发break事件
action_2:
type: replant
value:
point: 0
crop: tomato # Replant the crop
model: customcrops:tomato_stage_1
crop: tomato # Replant the crop 重新种植农作物
model: customcrops:tomato_stage_1 # crop model 农作物模型
interact-with-item:
interact_1:
# the item to use
# 使用的物品
item: customcrops:i_want_overgrown_tomato_right_now
# whether to reduce the amount
# 是否减少数量
reduce-amount: true
# the item to return, remove this section if you don't want item back
# 返还的物品,如果你不想要返还物品,请删除此项目
return: customcrops:returned_item
# actions to perform
# 执行的动作
actions:
action_1:
type: variation
@@ -171,6 +209,13 @@ tomato:
type: CHORUS
chance: 1
6:
# In this example, the model is not set, so the crop would not change its model
# when reaching this point. But here's a section called variation, which means that
# the crop has a little chance to be gigantic when it's already ripe. Since it reaches
# "max-points", the crop data would be removed from data and no longer affect server performance
# 在这个示范中model没有被设置因此农作物不会在此生长点数时替换模型
# 但是这里有一个生长时候触发的变异动作,意味着农作物有小概率在此阶段发生变异
# 因为农作物已经达到了最大生长点数,农作物数据将自此从数据中移除,不再对服务器性能造成影响
events:
grow:
action_1:
@@ -182,7 +227,9 @@ tomato:
chance: 0.02
# The crop would actually not gain so many points
999:
# But you can set some special crops' loots here
# 农作物实际上并不会获取这么多生长点数,但是你可以在此设置一些特殊掉落物
99:
model: customcrops:tomato_stage_golden
events:
break:
@@ -205,15 +252,6 @@ tomato:
min: 1
max: 2
chance: 0.3
interact-by-hand:
action_1:
type: break
action_2:
type: replant
value:
point: 0
crop: tomato # Replant the crop
model: customcrops:tomato_stage_1
interact-with-item:
interact_1:
item: GOLDEN_HOE
@@ -228,7 +266,13 @@ tomato:
crop: tomato
model: customcrops:tomato_stage_1
# grow conditions
# Custom grow conditions
# You can get a full list of grow conditions on wiki page.
# The default config tells that the crop would only grow in Spring and Autumn,
# and it requires at least a certain amount of water to grow.
# Though it would not grow in Summer, but it would still be alive. If you want
# the crop to die, see the "death-conditions" below.
# 自定义生长条件默认配置是农作物会在春和秋两个季节生长并且要求种植盆水量大于3
grow-conditions:
condition_1:
type: suitable_season
@@ -237,20 +281,27 @@ tomato:
- Autumn
condition_2:
type: water_more_than
value: 3
value: 2
# death conditions
# Custom death conditions
# 自定义死亡条件
death-conditions:
no_water:
# You can customize the dead models according to the reasons
# 你可以根据死因设置不同的死亡模型
model: customcrops:crop_stage_death
conditions:
# "&&" represents "And"
# "||" represents "Or"
# the default config tells that the crop would have 70% chance to die if the pot is dry
# 默认配置农作物有70%概率在种植盆干燥情况下死亡
'&&':
condition_1:
type: water_less_than
value: 1
condition_2:
type: random
value: 0.7 # 70% chance to die if the pot is not wet
value: 0.7
unsuitable_season:
model: customcrops:crop_stage_death
conditions:
@@ -259,7 +310,8 @@ tomato:
value:
- Winter
crow_attack:
# crop would be removed if dead-model is not set
# Crop would be removed if "model" is not set
# 如果没有设置model农作物会直接被移除而不是替换模型
conditions:
condition_1:
type: crow_attack
@@ -268,12 +320,17 @@ tomato:
fly-model: customcrops:crow_fly
stand-model: customcrops:crow_stand
# custom bone meal
# Custom bone meal
# 自定义骨粉
custom-bone-meal:
bone_meal_1:
item: BONE_MEAL
particle: VILLAGER_HAPPY
sound: minecraft:item.bone_meal.use
# 20% chance to grow 2 points
# (100% - 20%) * 60% = 48% chance to grow 1 point
# 20%概率获得两个生长点数
# (100% - 20%) * 60% = 48% 概率获得一个生长点数
chance:
2: 0.2
1: 0.6

View File

@@ -3,6 +3,7 @@ quality_1:
icon: '뀆'
chance: 1
times: 28
# 70%/20%/10%
ratio: 7/2/1
item: customcrops:quality_1
before-plant: true
@@ -15,6 +16,7 @@ quality_2:
icon: '뀇'
chance: 1
times: 28
# 55%/30%/15%
ratio: 11/6/3
item: customcrops:quality_2
before-plant: true
@@ -27,6 +29,7 @@ quality_3:
icon: '뀈'
chance: 1
times: 28
# 40%/40%/20%
ratio: 2/2/1
item: customcrops:quality_3
before-plant: true

View File

@@ -1,19 +1,29 @@
speed_grow_1:
type: SPEED_GROW
# Fertilizer Hologram display name
# Fertilizer Hologram display icon
# 肥料在悬浮字中显示的图标
icon: '뀌'
# How many days can this fertilizer stay in pot
# 肥料有效时间(游戏日)
times: 14
# ItemsAdder item namespacedID
# item id
# 物品ID
item: customcrops:speed_grow_1
# Should this fertilizer be used before planting
# 肥料是否只能在种植前使用
before-plant: true
# The particle to be displayed when using fertilizer
# 使用肥料的粒子效果
# https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Particle.html
particle: SPELL_WITCH
# The sound to play when using
# 使用肥料的声音
sound: minecraft:item.hoe.till
# Pot whitelist
# 种植盆白名单
pot-whitelist:
- default
# 50% chance to gain another 1 points
chance:
1: 0.5
speed_grow_2:
@@ -26,8 +36,11 @@ speed_grow_2:
sound: minecraft:item.hoe.till
pot-whitelist:
- default
# 10% chance to gain another 2 points
# (100% - 10%) * 70% = 63% chance to gain another 1 point
chance:
1: 0.9
2: 0.1
1: 0.7
speed_grow_3:
type: SPEED_GROW
icon: '뀎'
@@ -38,8 +51,10 @@ speed_grow_3:
sound: minecraft:item.hoe.till
pot-whitelist:
- default
# 40% chance to gain another 2 points
# 100% chance to gain another 1 point
# 10% chance to gain another 3 points
# (100% - 10%) * 40% = 36% chance to gain another 2 points
# (100% - (36% + 10%)) * 80% = 43.2% chance to gain another 1 point
chance:
3: 0.1
2: 0.4
1: 1
1: 0.8

View File

@@ -3,6 +3,7 @@ variation_1:
icon: '뀒'
times: 14
# If a crop's default variation chance is 0.01, now it's 0.03
# 如果农作物的变异概率是0.01那么使用肥料后变成了0.03
chance: 0.02
item: customcrops:variation_1
before-plant: true

View File

@@ -8,6 +8,9 @@ yield_increase_1:
sound: minecraft:item.hoe.till
pot-whitelist:
- default
# 10% chance to gain another 3 crops
# (100% - 10%) * 40% = 36% chance to gain another 2 crops
# (100% - (10% + 36%)) * 80% = 43.2% chance to gain another 1 crop
chance:
3: 0.1
2: 0.4
@@ -22,6 +25,9 @@ yield_increase_2:
sound: minecraft:item.hoe.till
pot-whitelist:
- default
# 20% chance to gain another 3 crops
# (100% - 20%) * 60% = 48% chance to gain another 2 crops
# (100% - (20% + 48%)) * 80% = 25.6% chance to gain another 1 crop
chance:
3: 0.2
2: 0.6
@@ -36,6 +42,8 @@ yield_increase_3:
sound: minecraft:item.hoe.till
pot-whitelist:
- default
# 40% chance to gain another 3 crops
# (100% - 40%) * 100% = 60% chance to gain another 2 crops
chance:
3: 0.4
2: 1

View File

@@ -1,11 +1,16 @@
# Pot key name
default:
max-water-storage: 4
# The max water storage
# 最大储水量
max-water-storage: 5
base:
# basic models
# basic models, use capital letters if you want to use vanilla blocks
# Example: FARMLAND
# 基础模型如果你想要使用原版方块请使用大写字母例如FARMLAND耕地
dry: customcrops:dry_pot
wet: customcrops:wet_pot
# If you want fertilized pots to have different looks
# Don't forget to set more bottom-block types in crop's config
# 如果你想让施肥的种植盆有不同的外观
fertilized-pots:
enable: false
quality:
@@ -23,12 +28,22 @@ default:
speed-grow:
dry: customcrops:dry_pot
wet: customcrops:wet_pot
# Methods to fill the pot
# 浇水的方法
fill-method:
method_1:
# The item to use
# 使用的物品
item: WATER_BUCKET
# The item returned
# 返还的物品
return: BUCKET
# water amount to add
# 增加的水量
amount: 3
# 粒子效果
particle: WATER_SPLASH
# 声音
sound: minecraft:block.water.ambient
method_2:
item: WATER
@@ -42,24 +57,49 @@ default:
particle: WATER_SPLASH
sound: minecraft:block.water.ambient
method_4:
# This is just an example
# "customcrops:magic_water" actually not exists
# 这只是个示例, "customcrops:magic_water"事实上不存在
item: customcrops:magic_water
amount: 10
amount: 5
particle: WATER_SPLASH
sound: minecraft:block.water.ambient
# Pot info hologram
# 种植盆悬浮信息
hologram:
enable: true
# ARMOR_STAND / TEXT_DISPLAY (1.19.4+)
# 显示载体
type: ARMOR_STAND
# in seconds
# 持续时间
duration: 2
# remove this if you want players can see the pot info even with empty hands
# 如果你想要空手也能查看种植盆信息,那么移除这个项目
require-item: customcrops:soil_surveyor
# Fertilizer info
# 肥料信息
fertilizer:
enable: true
vertical-offset: 0.8
text: '<font:customcrops:default>{icon}</font> {left_times}/{max_times}'
content: '<font:customcrops:default>{icon}</font> {left_times}/{max_times}'
# Water info
# 水分信息
water:
enable: true
vertical-offset: 1.05
text: '<font:customcrops:default>{water_bar}</font>'
#text: '{current}/{storage}'
# Available placeholders
# {current} current water 当前水量
# {storage} max water 最大储水量
# {water_bar} water bar image 水条
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅'
right: '뀁뀅'
text-display-options:
background-color: 0,0,0,0
has-shadow: false
is-see-through: false
use-default-background-color: false
text-opacity: -1

View File

@@ -1,20 +1,51 @@
# Sprinkler key name
sprinkler_1:
# This decides the work range
# (1+1x2)²=9
# 洒水器工作范围 3x3
range: 1
storage: 5
# max water storage
# 最大储水量
storage: 4
# 2/3D物品
3D-item: customcrops:sprinkler_1
2D-item: customcrops:sprinkler_1_item
# Item_Frame / Tripwire / Item_Display (1.19.4+)
type: Item_Frame
# ITEM_FRAME / TRIPWIRE / ITEM_DISPLAY (1.19.4+)
# Sprinkler item type
type: ITEM_FRAME
# The sprinkler can only add water to certain pots
# 洒水器只能对指定种植盆浇水
pot-whitelist:
- default
# see how fill-method works in /CustomCrops/contents/pots/default.yml
# 请在CustomCrops/contents/pots/default.yml查看"fill-method"如何使用
fill-method:
method_1:
item: WATER_BUCKET
return: BUCKET
amount: 3
particle: WATER_SPLASH
sound: minecraft:block.water.ambient
method_2:
item: WATER
return: GLASS_BOTTLE
amount: 1
particle: WATER_SPLASH
sound: minecraft:block.water.ambient
# The sound to play when placing
# 放置时候的声音
place-sound: minecraft:block.bone_block.place
# The hologram to show when interacting
# 交互时候产生的悬浮信息
hologram:
enable: true
# ARMOR_STAND / TEXT_DISPLAY (1.19.4+)
type: ARMOR_STAND
vertical-offset: -0.3
# vertical offset(change this according to your model size)
# 竖直方向的偏移
vertical-offset: -0.1
duration: 1
# Available variables:
# Available placeholders:
# {water_bar} water bar image
# {current} current water
# {storage} max storage
@@ -24,29 +55,23 @@ sprinkler_1:
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅'
text-display-options:
background-color: 0,0,0,0
has-shadow: false
is-see-through: false
use-default-background-color: false
text-opacity: -1
# Water splash animation when sprinkler works
# 洒水器在工作时候的洒水效果
animation:
enable: true
# in seconds
# 持续时间
duration: 10
vertical-offset: 0.4
item: customcrops:water_effect
# ARMOR_STAND / ITEM_DISPLAY (1.19.4+)
type: ARMOR_STAND
pot-whitelist:
- default
fill-method:
method_1:
item: WATER_BUCKET
return: BUCKET
amount: 3
particle: WATER_SPLASH
sound: minecraft:block.water.ambient
method_2:
item: WATER
return: GLASS_BOTTLE
amount: 1
particle: WATER_SPLASH
sound: minecraft:block.water.ambient
sprinkler_2:
# (1+2x2)²=25
@@ -54,24 +79,7 @@ sprinkler_2:
storage: 5
3D-item: customcrops:sprinkler_2
2D-item: customcrops:sprinkler_2_item
type: Item_Frame
place-sound: minecraft:block.bone_block.place
hologram:
enable: true
type: ARMOR_STAND
vertical-offset: -0.3
duration: 1
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅'
animation:
enable: true
vertical-offset: 0.4
item: customcrops:water_effect
type: ARMOR_STAND
type: ITEM_FRAME
pot-whitelist:
- default
fill-method:
@@ -87,30 +95,37 @@ sprinkler_2:
amount: 1
particle: WATER_SPLASH
sound: minecraft:block.water.ambient
place-sound: minecraft:block.bone_block.place
hologram:
enable: true
type: ARMOR_STAND
vertical-offset: -0.1
duration: 1
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅'
text-display-options:
background-color: 0,0,0,0
has-shadow: false
is-see-through: false
use-default-background-color: false
text-opacity: -1
animation:
enable: true
duration: 10
vertical-offset: 0.4
item: customcrops:water_effect
type: ARMOR_STAND
sprinkler_3:
range: 2
storage: 7
3D-item: customcrops:sprinkler_3
2D-item: customcrops:sprinkler_3_item
type: Item_Frame
place-sound: minecraft:block.bone_block.place
hologram:
enable: true
type: ARMOR_STAND
vertical-offset: -0.3
duration: 1
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅'
animation:
enable: true
vertical-offset: 0.4
item: customcrops:water_effect
type: ARMOR_STAND
type: ITEM_FRAME
pot-whitelist:
- default
fill-method:
@@ -125,4 +140,28 @@ sprinkler_3:
return: GLASS_BOTTLE
amount: 1
particle: WATER_SPLASH
sound: minecraft:block.water.ambient
sound: minecraft:block.water.ambient
place-sound: minecraft:block.bone_block.place
hologram:
enable: true
type: ARMOR_STAND
vertical-offset: -0.1
duration: 1
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅'
text-display-options:
background-color: 0,0,0,0
has-shadow: false
is-see-through: false
use-default-background-color: false
text-opacity: -1
animation:
enable: true
duration: 10
vertical-offset: 0.4
item: customcrops:water_effect
type: ARMOR_STAND

View File

@@ -1,22 +1,34 @@
watering_can_1:
# 物品 id
item: customcrops:watering_can_1
# 储水量
capacity: 3
# Effective Range
# 有效范围
effective-range:
width: 1
length: 1
# 粒子效果
particle: WATER_SPLASH
# 声音
sound: minecraft:block.water.ambient
# Methods to fill the watering can
fill-method:
method_1:
# The target block/furniture id
# use capital letters for vanilla items
target: WATER
type: block
# water amount to add
# 加水量
amount: 1
particle: WATER_SPLASH
sound: minecraft:item.bucket.fill
# This decides where the watering can can be used
# 这决定了水壶能使用在哪些种植盆上
pot-whitelist:
- default
# allows you to add water to sprinkler by clicking with a watering can
# 允许水壶对洒水器加水
sprinkler-whitelist:
- sprinkler_1
- sprinkler_2
@@ -25,23 +37,24 @@ watering_can_1:
# Should watering-can has dynamic lore according to the water amount
# 水壶是否有根据水量变化的动态lore
enable: true
# Available variables:
# Available placeholders:
# {water_bar} water bar image
# {current} current water
# {storage} max storage
lore:
- '<italic:false><white>{water_bar}'
- '<italic:false><white><font:customcrops:default>{water_bar}</font>'
- '<italic:false><gray>Right click water to add water to the can.'
actionbar:
# Should actionbar be sent when using watering-can
# 是否发送动作栏信息
enable: true
# Available variables {current} {storage} {water_bar}
content: '{water_bar}'
# Available placeholders {current} {storage} {water_bar}
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '<font:customcrops:default>뀂'
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅</font>'
right: '뀁뀅'
watering_can_2:
item: customcrops:watering_can_2
@@ -54,7 +67,6 @@ watering_can_2:
fill-method:
method_1:
target: WATER
type: block
amount: 1
particle: WATER_SPLASH
pot-whitelist:
@@ -66,16 +78,16 @@ watering_can_2:
dynamic-lore:
enable: true
lore:
- '<italic:false><white>{water_bar}'
- '<italic:false><white><font:customcrops:default>{water_bar}</font>'
- '<italic:false><gray>Right click water to add water to the can.'
actionbar:
enable: true
content: '{water_bar}'
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '<font:customcrops:default>뀂'
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅</font>'
right: '뀁뀅'
watering_can_3:
item: customcrops:watering_can_3
@@ -88,7 +100,6 @@ watering_can_3:
fill-method:
method_1:
target: WATER
type: block
amount: 1
particle: WATER_SPLASH
pot-whitelist:
@@ -100,16 +111,16 @@ watering_can_3:
dynamic-lore:
enable: true
lore:
- '<italic:false><white>{water_bar}'
- '<italic:false><white><font:customcrops:default>{water_bar}</font>'
- '<italic:false><gray>Right click water to add water to the can.'
actionbar:
enable: true
content: '{water_bar}'
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '<font:customcrops:default>뀂'
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅</font>'
right: '뀁뀅'
watering_can_4:
item: customcrops:watering_can_4
@@ -122,7 +133,6 @@ watering_can_4:
fill-method:
method_1:
target: WATER
type: block
amount: 1
particle: WATER_SPLASH
pot-whitelist:
@@ -134,13 +144,13 @@ watering_can_4:
dynamic-lore:
enable: true
lore:
- '<italic:false><white>{water_bar}'
- '<italic:false><white><font:customcrops:default>{water_bar}</font>'
- '<italic:false><gray>Right click water to add water to the can.'
actionbar:
enable: true
content: '{water_bar}'
content: '<font:customcrops:default>{water_bar}</font>'
water-bar:
left: '<font:customcrops:default>뀂'
left: '뀂'
full: '뀁뀃'
empty: '뀁뀄'
right: '뀁뀅</font>'
right: '뀁뀅'

View File

@@ -19,4 +19,6 @@ messages:
set-season: "<white>成功将 {world} 世界的季节设置为 {season}."
set-date: "<white>成功将 {world} 世界的日期设置为 {date}."
world-not-exist: '<white>世界 {world} 不存在.'
season-not-exist: '<white>{season} 不是一个有效的季节.'
season-not-exist: '<white>{season} 不是一个有效的季节.'
force-sprinkler-work: '<white>已强制世界 {world} 的洒水器进行工作.'
force-consume: '<white>已强制世界 {world} 的肥料、水分消耗.'

View File

@@ -19,4 +19,6 @@ messages:
set-season: "<white>Successfully set {world}'s season to {season}."
set-date: "<white>Successfully set {world}'s date to {date}."
world-not-exist: '<white>World {world} does not exist.'
season-not-exist: '<white>Season {season} does not exist.'
season-not-exist: '<white>Season {season} does not exist.'
force-sprinkler-work: "<white>Forced {world}'s sprinklers to work"
force-consume: "<white>Forced {world}'s pot to reduce water amount and the remaining use of fertilizers"

View File

@@ -19,4 +19,6 @@ messages:
set-season: "<white>{world} adlı dünyanın mevsimi başarıyla {season} ile değiştirildi."
set-date: "<white>{world} adlı dünyanın tarihi başarıyla {date} ile değiştirildi."
world-not-exist: '<white>{world} adında bir dünya bulunamadı.'
season-not-exist: '<white>{season} adında bir mevsim bulunamadı.'
season-not-exist: '<white>{season} adında bir mevsim bulunamadı.'
force-sprinkler-work: "<white>{world}'nin sulama sistemlerinin çalışmasını zorladı"
force-consume: "<white>{world}'nin tenceresindeki su miktarını azaltmayı ve kalan gübre kullanımını zorladı"

View File

@@ -2,6 +2,7 @@ name: CustomCrops
version: '${version}'
main: net.momirealms.customcrops.CustomCrops
api-version: 1.17
load: POSTWORLD
authors: [ XiaoMoMi ]
depend:
- ProtocolLib
@@ -31,9 +32,30 @@ softdepend:
- BattlePass
- BetonQuest
- ClueScrolls
- HuskTowns
commands:
customcrops:
usage: /customcrops <args>
permission: customcrops.admin
aliases:
- ccrops
- ccrops
permissions :
customcrops.*:
default: op
children:
customcrops.admin: true
customcrops.reload: true
customcrops.help: true
customcrops.about: true
customcrops.setdate: true
customcrops.setseason: true
customcrops.reload:
default: op
customcrops.help:
default: op
customcrops.about:
default: op
customcrops.setdate:
default: op
customcrops.setseason:
default: op