From 8eb277b8fc6e08b763f7943447ee77c447871432 Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <70987828+Xiao-MoMi@users.noreply.github.com> Date: Tue, 18 Apr 2023 22:47:17 +0800 Subject: [PATCH] 3.0.0-beta1 --- build.gradle | 14 +- .../momirealms/customcrops/CustomCrops.java | 16 +- .../customcrops/api/CustomCropsAPI.java | 86 ------- .../customcrops/api/customplugin/Handler.java | 1 - .../api/customplugin/PlatformInterface.java | 28 +- .../api/customplugin/PlatformManager.java | 146 ++++++----- .../itemsadder/ItemsAdderPluginImpl.java | 24 +- .../customplugin/oraxen/OraxenPluginImpl.java | 10 +- .../customcrops/api/event/CropBreakEvent.java | 62 +++++ .../customcrops/api/object/Function.java | 4 + .../api/object/action/BreakImpl.java | 3 +- .../api/object/action/ReplantImpl.java | 3 +- .../api/object/action/VariationImpl.java | 5 +- .../api/object/basic/ConfigManager.java | 7 + .../api/object/condition/DeathCondition.java | 5 +- .../api/object/crop/CropManager.java | 2 +- .../api/object/fertilizer/Fertilizer.java | 4 + .../api/object/fill/PositiveFillMethod.java | 14 +- .../api/object/hologram/AbstractHologram.java | 55 ++++ .../object/hologram/FertilizerHologram.java | 37 +++ .../{ => hologram}/HologramManager.java | 18 +- .../api/object/hologram/TextDisplayMeta.java | 38 +++ .../object/hologram/WaterAmountHologram.java | 51 ++++ .../api/object/migrate/MigrateWorld.java | 239 ++++++++++++++++++ .../customcrops/api/object/pot/PotConfig.java | 32 ++- .../api/object/pot/PotHologram.java | 122 --------- .../api/object/pot/PotManager.java | 36 ++- .../api/object/sprinkler/SprinklerConfig.java | 23 +- .../object/sprinkler/SprinklerHologram.java | 53 ---- .../object/sprinkler/SprinklerManager.java | 25 +- .../customcrops/api/object/world/CCChunk.java | 24 +- .../customcrops/api/object/world/CCWorld.java | 152 ++++++----- .../api/object/world/WorldDataManager.java | 16 +- .../customcrops/api/util/ConfigUtils.java | 11 +- .../customcrops/api/util/FakeEntityUtils.java | 29 ++- .../command/CustomCropsCommand.java | 2 + .../command/subcmd/ForceCommand.java | 33 +++ .../command/subcmd/MigrateCommand.java | 175 +++++++++++++ .../subcmd/force/ConsumeTaskCommand.java | 65 +++++ .../subcmd/force/SprinklerWorkCommand.java | 65 +++++ .../integration/IntegrationManager.java | 20 ++ .../integration/quest/BattlePassCCQuest.java | 45 ++++ .../integration/quest/BetonQuestCCQuest.java | 113 +++++++++ .../integration/quest/ClueScrollCCQuest.java | 39 +++ .../quest/LegacyBetonQuestCCQuest.java | 156 ++++++++++++ src/main/resources/config.yml | 17 +- src/main/resources/contents/crops/tomato.yml | 107 ++++++-- .../contents/fertilizers/quality.yml | 3 + .../contents/fertilizers/speed-grow.yml | 27 +- .../contents/fertilizers/variation.yml | 1 + .../contents/fertilizers/yield-increase.yml | 8 + src/main/resources/contents/pots/default.yml | 58 ++++- .../resources/contents/sprinklers/default.yml | 153 ++++++----- .../contents/watering-cans/default.yml | 54 ++-- .../resources/messages/messages_chinese.yml | 4 +- .../resources/messages/messages_english.yml | 4 +- .../resources/messages/messages_turkish.yml | 4 +- src/main/resources/plugin.yml | 24 +- 58 files changed, 1921 insertions(+), 651 deletions(-) create mode 100644 src/main/java/net/momirealms/customcrops/api/event/CropBreakEvent.java create mode 100644 src/main/java/net/momirealms/customcrops/api/object/hologram/AbstractHologram.java create mode 100644 src/main/java/net/momirealms/customcrops/api/object/hologram/FertilizerHologram.java rename src/main/java/net/momirealms/customcrops/api/object/{ => hologram}/HologramManager.java (92%) create mode 100644 src/main/java/net/momirealms/customcrops/api/object/hologram/TextDisplayMeta.java create mode 100644 src/main/java/net/momirealms/customcrops/api/object/hologram/WaterAmountHologram.java create mode 100644 src/main/java/net/momirealms/customcrops/api/object/migrate/MigrateWorld.java delete mode 100644 src/main/java/net/momirealms/customcrops/api/object/pot/PotHologram.java delete mode 100644 src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerHologram.java create mode 100644 src/main/java/net/momirealms/customcrops/command/subcmd/ForceCommand.java create mode 100644 src/main/java/net/momirealms/customcrops/command/subcmd/MigrateCommand.java create mode 100644 src/main/java/net/momirealms/customcrops/command/subcmd/force/ConsumeTaskCommand.java create mode 100644 src/main/java/net/momirealms/customcrops/command/subcmd/force/SprinklerWorkCommand.java create mode 100644 src/main/java/net/momirealms/customcrops/integration/quest/BattlePassCCQuest.java create mode 100644 src/main/java/net/momirealms/customcrops/integration/quest/BetonQuestCCQuest.java create mode 100644 src/main/java/net/momirealms/customcrops/integration/quest/ClueScrollCCQuest.java create mode 100644 src/main/java/net/momirealms/customcrops/integration/quest/LegacyBetonQuestCCQuest.java diff --git a/build.gradle b/build.gradle index 0911cd3..19bf342 100644 --- a/build.gradle +++ b/build.gradle @@ -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") diff --git a/src/main/java/net/momirealms/customcrops/CustomCrops.java b/src/main/java/net/momirealms/customcrops/CustomCrops.java index cd6ee07..5b37cce 100644 --- a/src/main/java/net/momirealms/customcrops/CustomCrops.java +++ b/src/main/java/net/momirealms/customcrops/CustomCrops.java @@ -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("========================[CustomCrops]========================="); + AdventureUtils.consoleMessage(" Spigot is not officially supported by CustomCrops"); + AdventureUtils.consoleMessage(" Please use Paper or its forks"); + AdventureUtils.consoleMessage(" Paper download link: https://papermc.io/downloads"); + AdventureUtils.consoleMessage("=============================================================="); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + protocolManager = ProtocolLibrary.getProtocolManager(); AdventureUtils.consoleMessage("[CustomCrops] Running on " + 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); diff --git a/src/main/java/net/momirealms/customcrops/api/CustomCropsAPI.java b/src/main/java/net/momirealms/customcrops/api/CustomCropsAPI.java index 3fee499..bf19146 100644 --- a/src/main/java/net/momirealms/customcrops/api/CustomCropsAPI.java +++ b/src/main/java/net/momirealms/customcrops/api/CustomCropsAPI.java @@ -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); - } } diff --git a/src/main/java/net/momirealms/customcrops/api/customplugin/Handler.java b/src/main/java/net/momirealms/customcrops/api/customplugin/Handler.java index c222881..2f019fd 100644 --- a/src/main/java/net/momirealms/customcrops/api/customplugin/Handler.java +++ b/src/main/java/net/momirealms/customcrops/api/customplugin/Handler.java @@ -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; diff --git a/src/main/java/net/momirealms/customcrops/api/customplugin/PlatformInterface.java b/src/main/java/net/momirealms/customcrops/api/customplugin/PlatformInterface.java index e2aa2fd..ddc4c89 100644 --- a/src/main/java/net/momirealms/customcrops/api/customplugin/PlatformInterface.java +++ b/src/main/java/net/momirealms/customcrops/api/customplugin/PlatformInterface.java @@ -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 itemFrames = getItemFrameLocation(location).getNearbyEntitiesByType(ItemFrame.class, 0.5, 0.5, 0.5); + Collection 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 itemDisplays = getItemFrameLocation(location).getNearbyEntitiesByType(ItemDisplay.class, 0.5, 0.5, 0.5); + Collection 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 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); + } } diff --git a/src/main/java/net/momirealms/customcrops/api/customplugin/PlatformManager.java b/src/main/java/net/momirealms/customcrops/api/customplugin/PlatformManager.java index 90c8e85..f2dc3ac 100644 --- a/src/main/java/net/momirealms/customcrops/api/customplugin/PlatformManager.java +++ b/src/main/java/net/momirealms/customcrops/api/customplugin/PlatformManager.java @@ -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 lineOfSight = player.getLineOfSight(null, 5); - List 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 lineOfSight = player.getLineOfSight(null, 5); + List 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; } - } diff --git a/src/main/java/net/momirealms/customcrops/api/customplugin/itemsadder/ItemsAdderPluginImpl.java b/src/main/java/net/momirealms/customcrops/api/customplugin/itemsadder/ItemsAdderPluginImpl.java index 6566fe3..7329170 100644 --- a/src/main/java/net/momirealms/customcrops/api/customplugin/itemsadder/ItemsAdderPluginImpl.java +++ b/src/main/java/net/momirealms/customcrops/api/customplugin/itemsadder/ItemsAdderPluginImpl.java @@ -67,6 +67,7 @@ public class ItemsAdderPluginImpl implements PlatformInterface { if (entity instanceof ItemFrame itemFrame) return itemFrame; else { + AdventureUtils.consoleMessage("[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("[CustomCrops] Furniture not exists: " + id); + return null; + } + Entity entity = customFurniture.getArmorstand(); + if (entity instanceof ItemDisplay itemDisplay) + return itemDisplay; + else { + AdventureUtils.consoleMessage("[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 diff --git a/src/main/java/net/momirealms/customcrops/api/customplugin/oraxen/OraxenPluginImpl.java b/src/main/java/net/momirealms/customcrops/api/customplugin/oraxen/OraxenPluginImpl.java index 113d756..68f891b 100644 --- a/src/main/java/net/momirealms/customcrops/api/customplugin/oraxen/OraxenPluginImpl.java +++ b/src/main/java/net/momirealms/customcrops/api/customplugin/oraxen/OraxenPluginImpl.java @@ -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("[CustomCrops] Item Frame not exists: " + id); + AdventureUtils.consoleMessage("[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("[CustomCrops] Item Display not exists: " + id); + AdventureUtils.consoleMessage("[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) { diff --git a/src/main/java/net/momirealms/customcrops/api/event/CropBreakEvent.java b/src/main/java/net/momirealms/customcrops/api/event/CropBreakEvent.java new file mode 100644 index 0000000..71ecf5b --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/api/event/CropBreakEvent.java @@ -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; + } +} diff --git a/src/main/java/net/momirealms/customcrops/api/object/Function.java b/src/main/java/net/momirealms/customcrops/api/object/Function.java index 7d66af8..386b32c 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/Function.java +++ b/src/main/java/net/momirealms/customcrops/api/object/Function.java @@ -19,6 +19,10 @@ package net.momirealms.customcrops.api.object; public class Function { + public void init() { + + } + public void load() { } diff --git a/src/main/java/net/momirealms/customcrops/api/object/action/BreakImpl.java b/src/main/java/net/momirealms/customcrops/api/object/action/BreakImpl.java index 71a4af4..408cef4 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/action/BreakImpl.java +++ b/src/main/java/net/momirealms/customcrops/api/object/action/BreakImpl.java @@ -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; }); diff --git a/src/main/java/net/momirealms/customcrops/api/object/action/ReplantImpl.java b/src/main/java/net/momirealms/customcrops/api/object/action/ReplantImpl.java index 2ae94f8..7d70388 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/action/ReplantImpl.java +++ b/src/main/java/net/momirealms/customcrops/api/object/action/ReplantImpl.java @@ -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; diff --git a/src/main/java/net/momirealms/customcrops/api/object/action/VariationImpl.java b/src/main/java/net/momirealms/customcrops/api/object/action/VariationImpl.java index 75d8ac0..2ad45bc 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/action/VariationImpl.java +++ b/src/main/java/net/momirealms/customcrops/api/object/action/VariationImpl.java @@ -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; diff --git a/src/main/java/net/momirealms/customcrops/api/object/basic/ConfigManager.java b/src/main/java/net/momirealms/customcrops/api/object/basic/ConfigManager.java index 7785613..a0838a6 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/basic/ConfigManager.java +++ b/src/main/java/net/momirealms/customcrops/api/object/basic/ConfigManager.java @@ -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) { diff --git a/src/main/java/net/momirealms/customcrops/api/object/condition/DeathCondition.java b/src/main/java/net/momirealms/customcrops/api/object/condition/DeathCondition.java index a38ed0e..9eb55e8 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/condition/DeathCondition.java +++ b/src/main/java/net/momirealms/customcrops/api/object/condition/DeathCondition.java @@ -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; }); diff --git a/src/main/java/net/momirealms/customcrops/api/object/crop/CropManager.java b/src/main/java/net/momirealms/customcrops/api/object/crop/CropManager.java index 733e656..7226e47 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/crop/CropManager.java +++ b/src/main/java/net/momirealms/customcrops/api/object/crop/CropManager.java @@ -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("[CustomCrops] pot-whitelist is not set for crop: " + key); diff --git a/src/main/java/net/momirealms/customcrops/api/object/fertilizer/Fertilizer.java b/src/main/java/net/momirealms/customcrops/api/object/fertilizer/Fertilizer.java index 5eb4a99..e1a22e7 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/fertilizer/Fertilizer.java +++ b/src/main/java/net/momirealms/customcrops/api/object/fertilizer/Fertilizer.java @@ -55,4 +55,8 @@ public class Fertilizer implements Serializable { public int getLeftTimes() { return times; } + + public void setTimes(int times) { + this.times = times; + } } diff --git a/src/main/java/net/momirealms/customcrops/api/object/fill/PositiveFillMethod.java b/src/main/java/net/momirealms/customcrops/api/object/fill/PositiveFillMethod.java index 673b2d2..551d263 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/fill/PositiveFillMethod.java +++ b/src/main/java/net/momirealms/customcrops/api/object/fill/PositiveFillMethod.java @@ -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 - } } diff --git a/src/main/java/net/momirealms/customcrops/api/object/hologram/AbstractHologram.java b/src/main/java/net/momirealms/customcrops/api/object/hologram/AbstractHologram.java new file mode 100644 index 0000000..003681f --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/api/object/hologram/AbstractHologram.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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; + } +} diff --git a/src/main/java/net/momirealms/customcrops/api/object/hologram/FertilizerHologram.java b/src/main/java/net/momirealms/customcrops/api/object/hologram/FertilizerHologram.java new file mode 100644 index 0000000..ad00245 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/api/object/hologram/FertilizerHologram.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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())); + } +} diff --git a/src/main/java/net/momirealms/customcrops/api/object/HologramManager.java b/src/main/java/net/momirealms/customcrops/api/object/hologram/HologramManager.java similarity index 92% rename from src/main/java/net/momirealms/customcrops/api/object/HologramManager.java rename to src/main/java/net/momirealms/customcrops/api/object/hologram/HologramManager.java index 9f6ed3c..a54cab3 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/HologramManager.java +++ b/src/main/java/net/momirealms/customcrops/api/object/hologram/HologramManager.java @@ -15,10 +15,12 @@ * along with this program. If not, see . */ -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)); } } } diff --git a/src/main/java/net/momirealms/customcrops/api/object/hologram/TextDisplayMeta.java b/src/main/java/net/momirealms/customcrops/api/object/hologram/TextDisplayMeta.java new file mode 100644 index 0000000..8ae1c2e --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/api/object/hologram/TextDisplayMeta.java @@ -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; + } +} diff --git a/src/main/java/net/momirealms/customcrops/api/object/hologram/WaterAmountHologram.java b/src/main/java/net/momirealms/customcrops/api/object/hologram/WaterAmountHologram.java new file mode 100644 index 0000000..67b7d2e --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/api/object/hologram/WaterAmountHologram.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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; + } +} diff --git a/src/main/java/net/momirealms/customcrops/api/object/migrate/MigrateWorld.java b/src/main/java/net/momirealms/customcrops/api/object/migrate/MigrateWorld.java new file mode 100644 index 0000000..7b4edad --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/api/object/migrate/MigrateWorld.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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 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 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; + } +} \ No newline at end of file diff --git a/src/main/java/net/momirealms/customcrops/api/object/pot/PotConfig.java b/src/main/java/net/momirealms/customcrops/api/object/pot/PotConfig.java index f21f017..9760bed 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/pot/PotConfig.java +++ b/src/main/java/net/momirealms/customcrops/api/object/pot/PotConfig.java @@ -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 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; } } diff --git a/src/main/java/net/momirealms/customcrops/api/object/pot/PotHologram.java b/src/main/java/net/momirealms/customcrops/api/object/pot/PotHologram.java deleted file mode 100644 index 3bb8b38..0000000 --- a/src/main/java/net/momirealms/customcrops/api/object/pot/PotHologram.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) <2022> - * - * 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 . - */ - -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 detectBetterPlaceholders(String text) { - List 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; - } -} diff --git a/src/main/java/net/momirealms/customcrops/api/object/pot/PotManager.java b/src/main/java/net/momirealms/customcrops/api/object/pot/PotManager.java index 5123fe1..ff4ac0f 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/pot/PotManager.java +++ b/src/main/java/net/momirealms/customcrops/api/object/pot/PotManager.java @@ -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"); diff --git a/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerConfig.java b/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerConfig.java index 0e17fa2..4485d3d 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerConfig.java +++ b/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerConfig.java @@ -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 diff --git a/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerHologram.java b/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerHologram.java deleted file mode 100644 index 1270d45..0000000 --- a/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerHologram.java +++ /dev/null @@ -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; - } - -} diff --git a/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerManager.java b/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerManager.java index 62b608d..6086cce 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerManager.java +++ b/src/main/java/net/momirealms/customcrops/api/object/sprinkler/SprinklerManager.java @@ -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; diff --git a/src/main/java/net/momirealms/customcrops/api/object/world/CCChunk.java b/src/main/java/net/momirealms/customcrops/api/object/world/CCChunk.java index ff714ec..d11bfa6 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/world/CCChunk.java +++ b/src/main/java/net/momirealms/customcrops/api/object/world/CCChunk.java @@ -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); + } + } } \ No newline at end of file diff --git a/src/main/java/net/momirealms/customcrops/api/object/world/CCWorld.java b/src/main/java/net/momirealms/customcrops/api/object/world/CCWorld.java index f117f5d..98a7052 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/world/CCWorld.java +++ b/src/main/java/net/momirealms/customcrops/api/object/world/CCWorld.java @@ -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 cropTaskPool; private final GenericObjectPool sprinklerTaskPool; private final GenericObjectPool 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("[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("[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); + } } \ No newline at end of file diff --git a/src/main/java/net/momirealms/customcrops/api/object/world/WorldDataManager.java b/src/main/java/net/momirealms/customcrops/api/object/world/WorldDataManager.java index cf048a1..6c54cbe 100644 --- a/src/main/java/net/momirealms/customcrops/api/object/world/WorldDataManager.java +++ b/src/main/java/net/momirealms/customcrops/api/object/world/WorldDataManager.java @@ -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); + } } diff --git a/src/main/java/net/momirealms/customcrops/api/util/ConfigUtils.java b/src/main/java/net/momirealms/customcrops/api/util/ConfigUtils.java index 0a44993..fdf22c9 100644 --- a/src/main/java/net/momirealms/customcrops/api/util/ConfigUtils.java +++ b/src/main/java/net/momirealms/customcrops/api/util/ConfigUtils.java @@ -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; + } } \ No newline at end of file diff --git a/src/main/java/net/momirealms/customcrops/api/util/FakeEntityUtils.java b/src/main/java/net/momirealms/customcrops/api/util/FakeEntityUtils.java index b260c79..2de9e7e 100644 --- a/src/main/java/net/momirealms/customcrops/api/util/FakeEntityUtils.java +++ b/src/main/java/net/momirealms/customcrops/api/util/FakeEntityUtils.java @@ -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; } diff --git a/src/main/java/net/momirealms/customcrops/command/CustomCropsCommand.java b/src/main/java/net/momirealms/customcrops/command/CustomCropsCommand.java index aed77e8..6470c2c 100644 --- a/src/main/java/net/momirealms/customcrops/command/CustomCropsCommand.java +++ b/src/main/java/net/momirealms/customcrops/command/CustomCropsCommand.java @@ -27,5 +27,7 @@ public class CustomCropsCommand extends AbstractMainCommand { regSubCommand(HelpCommand.INSTANCE); regSubCommand(AboutCommand.INSTANCE); regSubCommand(SetDateCommand.INSTANCE); + regSubCommand(ForceCommand.INSTANCE); + regSubCommand(MigrateCommand.INSTANCE); } } diff --git a/src/main/java/net/momirealms/customcrops/command/subcmd/ForceCommand.java b/src/main/java/net/momirealms/customcrops/command/subcmd/ForceCommand.java new file mode 100644 index 0000000..f4abc6f --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/command/subcmd/ForceCommand.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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); + } +} diff --git a/src/main/java/net/momirealms/customcrops/command/subcmd/MigrateCommand.java b/src/main/java/net/momirealms/customcrops/command/subcmd/MigrateCommand.java new file mode 100644 index 0000000..8e9e99b --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/command/subcmd/MigrateCommand.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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 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("[CustomCrops] World folder is not detected"); + return; + } + + File[] files = outer_folder.listFiles(); + if (files == null) return; + + List 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("[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("[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("[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("[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 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("[CustomCrops] Migrated " + worldName + "'s scarecrows"); + + YamlConfiguration cropData = YamlConfiguration.loadConfiguration(new File(ccDataFolder, "crops.yml")); + for (Map.Entry 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("[CustomCrops] Migrated " + worldName + "'s crops"); + migrateWorld.disable(); + } + + AdventureUtils.consoleMessage("[CustomCrops] Migration finished!"); + } + } +} diff --git a/src/main/java/net/momirealms/customcrops/command/subcmd/force/ConsumeTaskCommand.java b/src/main/java/net/momirealms/customcrops/command/subcmd/force/ConsumeTaskCommand.java new file mode 100644 index 0000000..5e3603a --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/command/subcmd/force/ConsumeTaskCommand.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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 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 onTabComplete(CommandSender sender, List 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; + } +} diff --git a/src/main/java/net/momirealms/customcrops/command/subcmd/force/SprinklerWorkCommand.java b/src/main/java/net/momirealms/customcrops/command/subcmd/force/SprinklerWorkCommand.java new file mode 100644 index 0000000..9e4f40b --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/command/subcmd/force/SprinklerWorkCommand.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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 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 onTabComplete(CommandSender sender, List 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; + } +} diff --git a/src/main/java/net/momirealms/customcrops/integration/IntegrationManager.java b/src/main/java/net/momirealms/customcrops/integration/IntegrationManager.java index ed06209..9d6b9fb 100644 --- a/src/main/java/net/momirealms/customcrops/integration/IntegrationManager.java +++ b/src/main/java/net/momirealms/customcrops/integration/IntegrationManager.java @@ -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; diff --git a/src/main/java/net/momirealms/customcrops/integration/quest/BattlePassCCQuest.java b/src/main/java/net/momirealms/customcrops/integration/quest/BattlePassCCQuest.java new file mode 100644 index 0000000..90f6d7e --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/integration/quest/BattlePassCCQuest.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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())); + } +} diff --git a/src/main/java/net/momirealms/customcrops/integration/quest/BetonQuestCCQuest.java b/src/main/java/net/momirealms/customcrops/integration/quest/BetonQuestCCQuest.java new file mode 100644 index 0000000..0c81dbc --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/integration/quest/BetonQuestCCQuest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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 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); + } +} diff --git a/src/main/java/net/momirealms/customcrops/integration/quest/ClueScrollCCQuest.java b/src/main/java/net/momirealms/customcrops/integration/quest/ClueScrollCCQuest.java new file mode 100644 index 0000000..8a6dad5 --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/integration/quest/ClueScrollCCQuest.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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())); + } +} diff --git a/src/main/java/net/momirealms/customcrops/integration/quest/LegacyBetonQuestCCQuest.java b/src/main/java/net/momirealms/customcrops/integration/quest/LegacyBetonQuestCCQuest.java new file mode 100644 index 0000000..d993e9e --- /dev/null +++ b/src/main/java/net/momirealms/customcrops/integration/quest/LegacyBetonQuestCCQuest.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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 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; + } + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 245a530..da8f40e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -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 diff --git a/src/main/resources/contents/crops/tomato.yml b/src/main/resources/contents/crops/tomato.yml index 4a25724..76ed111 100644 --- a/src/main/resources/contents/crops/tomato.yml +++ b/src/main/resources/contents/crops/tomato.yml @@ -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 diff --git a/src/main/resources/contents/fertilizers/quality.yml b/src/main/resources/contents/fertilizers/quality.yml index 2fd1a03..8a5b50a 100644 --- a/src/main/resources/contents/fertilizers/quality.yml +++ b/src/main/resources/contents/fertilizers/quality.yml @@ -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 diff --git a/src/main/resources/contents/fertilizers/speed-grow.yml b/src/main/resources/contents/fertilizers/speed-grow.yml index fabe12c..b04e394 100644 --- a/src/main/resources/contents/fertilizers/speed-grow.yml +++ b/src/main/resources/contents/fertilizers/speed-grow.yml @@ -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 \ No newline at end of file + 1: 0.8 \ No newline at end of file diff --git a/src/main/resources/contents/fertilizers/variation.yml b/src/main/resources/contents/fertilizers/variation.yml index fa97abd..c4bb238 100644 --- a/src/main/resources/contents/fertilizers/variation.yml +++ b/src/main/resources/contents/fertilizers/variation.yml @@ -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 diff --git a/src/main/resources/contents/fertilizers/yield-increase.yml b/src/main/resources/contents/fertilizers/yield-increase.yml index ed0ed59..bb4028a 100644 --- a/src/main/resources/contents/fertilizers/yield-increase.yml +++ b/src/main/resources/contents/fertilizers/yield-increase.yml @@ -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 \ No newline at end of file diff --git a/src/main/resources/contents/pots/default.yml b/src/main/resources/contents/pots/default.yml index 4260e7a..a83263f 100644 --- a/src/main/resources/contents/pots/default.yml +++ b/src/main/resources/contents/pots/default.yml @@ -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: '{icon} {left_times}/{max_times}' + content: '{icon} {left_times}/{max_times}' + # Water info + # 水分信息 water: + enable: true vertical-offset: 1.05 - text: '{water_bar}' - #text: '{current}/{storage}' + # Available placeholders + # {current} current water 当前水量 + # {storage} max water 最大储水量 + # {water_bar} water bar image 水条 + content: '{water_bar}' water-bar: left: '뀂' full: '뀁뀃' empty: '뀁뀄' - right: '뀁뀅' \ No newline at end of file + 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 \ No newline at end of file diff --git a/src/main/resources/contents/sprinklers/default.yml b/src/main/resources/contents/sprinklers/default.yml index eafcd12..2f78950 100644 --- a/src/main/resources/contents/sprinklers/default.yml +++ b/src/main/resources/contents/sprinklers/default.yml @@ -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: '{water_bar}' - 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: '{water_bar}' + 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: '{water_bar}' - 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 \ No newline at end of file + 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: '{water_bar}' + 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 \ No newline at end of file diff --git a/src/main/resources/contents/watering-cans/default.yml b/src/main/resources/contents/watering-cans/default.yml index e7ed36d..121a33a 100644 --- a/src/main/resources/contents/watering-cans/default.yml +++ b/src/main/resources/contents/watering-cans/default.yml @@ -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: - - '{water_bar}' + - '{water_bar}' - '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: '{water_bar}' water-bar: - left: '뀂' + left: '뀂' full: '뀁뀃' empty: '뀁뀄' - right: '뀁뀅' + 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: - - '{water_bar}' + - '{water_bar}' - 'Right click water to add water to the can.' actionbar: enable: true - content: '{water_bar}' + content: '{water_bar}' water-bar: - left: '뀂' + left: '뀂' full: '뀁뀃' empty: '뀁뀄' - right: '뀁뀅' + 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: - - '{water_bar}' + - '{water_bar}' - 'Right click water to add water to the can.' actionbar: enable: true - content: '{water_bar}' + content: '{water_bar}' water-bar: - left: '뀂' + left: '뀂' full: '뀁뀃' empty: '뀁뀄' - right: '뀁뀅' + 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: - - '{water_bar}' + - '{water_bar}' - 'Right click water to add water to the can.' actionbar: enable: true - content: '{water_bar}' + content: '{water_bar}' water-bar: - left: '뀂' + left: '뀂' full: '뀁뀃' empty: '뀁뀄' - right: '뀁뀅' + right: '뀁뀅' diff --git a/src/main/resources/messages/messages_chinese.yml b/src/main/resources/messages/messages_chinese.yml index 709af4e..ce657d9 100644 --- a/src/main/resources/messages/messages_chinese.yml +++ b/src/main/resources/messages/messages_chinese.yml @@ -19,4 +19,6 @@ messages: set-season: "成功将 {world} 世界的季节设置为 {season}." set-date: "成功将 {world} 世界的日期设置为 {date}." world-not-exist: '世界 {world} 不存在.' - season-not-exist: '{season} 不是一个有效的季节.' \ No newline at end of file + season-not-exist: '{season} 不是一个有效的季节.' + force-sprinkler-work: '已强制世界 {world} 的洒水器进行工作.' + force-consume: '已强制世界 {world} 的肥料、水分消耗.' \ No newline at end of file diff --git a/src/main/resources/messages/messages_english.yml b/src/main/resources/messages/messages_english.yml index f718ebe..8e3886c 100644 --- a/src/main/resources/messages/messages_english.yml +++ b/src/main/resources/messages/messages_english.yml @@ -19,4 +19,6 @@ messages: set-season: "Successfully set {world}'s season to {season}." set-date: "Successfully set {world}'s date to {date}." world-not-exist: 'World {world} does not exist.' - season-not-exist: 'Season {season} does not exist.' \ No newline at end of file + season-not-exist: 'Season {season} does not exist.' + force-sprinkler-work: "Forced {world}'s sprinklers to work" + force-consume: "Forced {world}'s pot to reduce water amount and the remaining use of fertilizers" \ No newline at end of file diff --git a/src/main/resources/messages/messages_turkish.yml b/src/main/resources/messages/messages_turkish.yml index 6127ba2..812f17a 100644 --- a/src/main/resources/messages/messages_turkish.yml +++ b/src/main/resources/messages/messages_turkish.yml @@ -19,4 +19,6 @@ messages: set-season: "{world} adlı dünyanın mevsimi başarıyla {season} ile değiştirildi." set-date: "{world} adlı dünyanın tarihi başarıyla {date} ile değiştirildi." world-not-exist: '{world} adında bir dünya bulunamadı.' - season-not-exist: '{season} adında bir mevsim bulunamadı.' \ No newline at end of file + season-not-exist: '{season} adında bir mevsim bulunamadı.' + force-sprinkler-work: "{world}'nin sulama sistemlerinin çalışmasını zorladı" + force-consume: "{world}'nin tenceresindeki su miktarını azaltmayı ve kalan gübre kullanımını zorladı" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 0c0f031..3c08173 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -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 permission: customcrops.admin aliases: - - ccrops \ No newline at end of file + - 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 \ No newline at end of file