diff --git a/api/src/main/java/net/momirealms/customcrops/api/manager/ConditionManager.java b/api/src/main/java/net/momirealms/customcrops/api/manager/ConditionManager.java index adf3358..59c0b70 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/manager/ConditionManager.java +++ b/api/src/main/java/net/momirealms/customcrops/api/manager/ConditionManager.java @@ -42,10 +42,10 @@ public interface ConditionManager extends Reloadable { @Nullable ConditionFactory getConditionFactory(String type); - static boolean isConditionMet(CustomCropsBlock block, Condition... conditions) { + static boolean isConditionMet(CustomCropsBlock block, boolean offline, Condition... conditions) { if (conditions == null) return true; for (Condition condition : conditions) { - if (!condition.isConditionMet(block)) { + if (!condition.isConditionMet(block, offline)) { return false; } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/condition/Condition.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/condition/Condition.java index 8b7f1e8..fc9a96f 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/mechanic/condition/Condition.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/condition/Condition.java @@ -21,5 +21,5 @@ import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; public interface Condition { - boolean isConditionMet(CustomCropsBlock block); + boolean isConditionMet(CustomCropsBlock block, boolean offline); } diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/SimpleLocation.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/SimpleLocation.java index 403dfb7..f7765a0 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/SimpleLocation.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/SimpleLocation.java @@ -57,7 +57,7 @@ public class SimpleLocation { return worldName; } - public ChunkPos getChunkCoordinate() { + public ChunkPos getChunkPos() { return new ChunkPos(x >> 4, z >> 4); } diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/Tickable.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/Tickable.java index 047517b..db95766 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/Tickable.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/Tickable.java @@ -2,5 +2,5 @@ package net.momirealms.customcrops.api.mechanic.world; public interface Tickable { - void tick(int interval); + void tick(int interval, boolean offline); } diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/level/WorldSetting.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/level/WorldSetting.java index 0ca9614..da4b268 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/level/WorldSetting.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/level/WorldSetting.java @@ -32,6 +32,7 @@ public class WorldSetting implements Cloneable { private final int potPerChunk; private final int sprinklerPerChunk; private final int randomTickSpeed; + private final int maxOfflineTime; private final boolean tickCropRandomly; private final boolean tickPotRandomly; private final boolean tickSprinklerRandomly; @@ -47,6 +48,7 @@ public class WorldSetting implements Cloneable { boolean tickSprinklerRandomly, int tickSprinklerInterval, boolean offlineGrow, + int maxOfflineTime, boolean enableSeason, boolean autoSeasonChange, int seasonDuration, @@ -61,6 +63,7 @@ public class WorldSetting implements Cloneable { this.tickPotInterval = tickPotInterval; this.tickSprinklerInterval = tickSprinklerInterval; this.offlineGrow = offlineGrow; + this.maxOfflineTime = maxOfflineTime; this.enableSeason = enableSeason; this.autoSeasonChange = autoSeasonChange; this.seasonDuration = seasonDuration; @@ -84,6 +87,7 @@ public class WorldSetting implements Cloneable { boolean tickSprinklerRandomly, int tickSprinklerInterval, boolean offlineGrow, + int maxOfflineTime, boolean enableSeason, boolean autoSeasonChange, int seasonDuration, @@ -102,6 +106,7 @@ public class WorldSetting implements Cloneable { tickSprinklerRandomly, tickSprinklerInterval, offlineGrow, + maxOfflineTime, enableSeason, autoSeasonChange, seasonDuration, @@ -168,15 +173,6 @@ public class WorldSetting implements Cloneable { return scheduledTick; } - @Override - public WorldSetting clone() { - try { - return (WorldSetting) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(); - } - } - public boolean randomTickCrop() { return tickCropRandomly; } @@ -188,4 +184,17 @@ public class WorldSetting implements Cloneable { public boolean randomTickPot() { return tickPotRandomly; } + + public int getMaxOfflineTime() { + return maxOfflineTime; + } + + @Override + public WorldSetting clone() { + try { + return (WorldSetting) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } } diff --git a/build.gradle.kts b/build.gradle.kts index 62352d7..6573a7d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { allprojects { project.group = "net.momirealms" - project.version = "3.4.3.4" + project.version = "3.4.4" apply() apply(plugin = "java") diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index b446f45..d5ff9f5 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { // Items compileOnly("com.github.LoneDev6:api-itemsadder:3.6.2-beta-r3-b") - compileOnly("com.github.oraxen:oraxen:1.168.0") + compileOnly("com.github.oraxen:oraxen:1.172.0") compileOnly("pers.neige.neigeitems:NeigeItems:1.16.24") compileOnly("net.Indyuce:MMOItems-API:6.9.2-SNAPSHOT") compileOnly("io.lumine:MythicLib-dist:1.6-SNAPSHOT") diff --git a/plugin/src/main/java/net/momirealms/customcrops/CustomCropsPluginImpl.java b/plugin/src/main/java/net/momirealms/customcrops/CustomCropsPluginImpl.java index 917ad0e..4953c70 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/CustomCropsPluginImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/CustomCropsPluginImpl.java @@ -38,7 +38,7 @@ import net.momirealms.customcrops.mechanic.misc.migrator.Migration; import net.momirealms.customcrops.mechanic.requirement.RequirementManagerImpl; import net.momirealms.customcrops.mechanic.world.WorldManagerImpl; import net.momirealms.customcrops.scheduler.SchedulerImpl; -import net.momirealms.customcrops.utils.EventUtils; +import net.momirealms.customcrops.util.EventUtils; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; diff --git a/plugin/src/main/java/net/momirealms/customcrops/manager/CommandManager.java b/plugin/src/main/java/net/momirealms/customcrops/manager/CommandManager.java index 7b2aa1f..67a71dd 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/manager/CommandManager.java +++ b/plugin/src/main/java/net/momirealms/customcrops/manager/CommandManager.java @@ -113,7 +113,7 @@ public class CommandManager implements Initable { for (CustomCropsSection section : chunk.getSections()) { for (CustomCropsBlock block : section.getBlocks()) { if (block.getType() == itemType) { - block.tick(1); + block.tick(1, false); } } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java index f1e6c42..88ee65a 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java @@ -26,7 +26,7 @@ import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings; import net.momirealms.customcrops.api.CustomCropsPlugin; import net.momirealms.customcrops.api.manager.ConfigManager; import net.momirealms.customcrops.api.util.LogUtils; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.util.ConfigUtils; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; diff --git a/plugin/src/main/java/net/momirealms/customcrops/manager/HologramManager.java b/plugin/src/main/java/net/momirealms/customcrops/manager/HologramManager.java index e5a4d1a..154f77f 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/manager/HologramManager.java +++ b/plugin/src/main/java/net/momirealms/customcrops/manager/HologramManager.java @@ -23,7 +23,7 @@ import net.momirealms.customcrops.api.common.Reloadable; import net.momirealms.customcrops.api.common.Tuple; import net.momirealms.customcrops.api.manager.VersionManager; import net.momirealms.customcrops.api.scheduler.CancellableTask; -import net.momirealms.customcrops.utils.FakeEntityUtils; +import net.momirealms.customcrops.util.FakeEntityUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.EntityType; diff --git a/plugin/src/main/java/net/momirealms/customcrops/manager/MessageManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/manager/MessageManagerImpl.java index ce26b8a..a273b22 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/manager/MessageManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/manager/MessageManagerImpl.java @@ -22,7 +22,7 @@ import net.momirealms.customcrops.api.common.Reloadable; import net.momirealms.customcrops.api.manager.ConfigManager; import net.momirealms.customcrops.api.manager.MessageManager; import net.momirealms.customcrops.api.mechanic.world.season.Season; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.util.ConfigUtils; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; diff --git a/plugin/src/main/java/net/momirealms/customcrops/manager/PlaceholderManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/manager/PlaceholderManagerImpl.java index 13da54c..0e36df4 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/manager/PlaceholderManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/manager/PlaceholderManagerImpl.java @@ -21,7 +21,7 @@ import net.momirealms.customcrops.api.CustomCropsPlugin; import net.momirealms.customcrops.api.manager.PlaceholderManager; import net.momirealms.customcrops.compatibility.papi.CCPapi; import net.momirealms.customcrops.compatibility.papi.ParseUtils; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.util.ConfigUtils; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java index e97f141..b3f4501 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java @@ -56,10 +56,10 @@ import net.momirealms.customcrops.manager.PacketManager; import net.momirealms.customcrops.mechanic.item.impl.VariationCrop; import net.momirealms.customcrops.mechanic.misc.TempFakeItem; import net.momirealms.customcrops.mechanic.world.block.MemoryCrop; -import net.momirealms.customcrops.utils.ClassUtils; -import net.momirealms.customcrops.utils.ConfigUtils; -import net.momirealms.customcrops.utils.EventUtils; -import net.momirealms.customcrops.utils.ItemUtils; +import net.momirealms.customcrops.util.ClassUtils; +import net.momirealms.customcrops.util.ConfigUtils; +import net.momirealms.customcrops.util.EventUtils; +import net.momirealms.customcrops.util.ItemUtils; import org.bukkit.*; import org.bukkit.block.BlockFace; import org.bukkit.configuration.ConfigurationSection; @@ -220,6 +220,7 @@ public class ActionManagerImpl implements ActionManager { boolean onlyShowToOne = !section.getBoolean("visible-to-all", false); return condition -> { if (Math.random() > chance) return; + if (condition.getArg("{offline}") != null) return; Location location = condition.getLocation().clone().add(x,y,z); SimpleLocation simpleLocation = SimpleLocation.of(location); if (applyCorrection) { @@ -269,6 +270,7 @@ public class ActionManagerImpl implements ActionManager { boolean onlyShowToOne = !section.getBoolean("visible-to-all", true); return condition -> { if (Math.random() > chance) return; + if (condition.getArg("{offline}") != null) return; if (item.equals("")) return; Location location = condition.getLocation().clone().add(x,y,z); new TempFakeItem(location, item, duration, onlyShowToOne ? condition.getPlayer() : null).start(); @@ -446,7 +448,7 @@ public class ActionManagerImpl implements ActionManager { .flatMap(world -> world.getLoadedChunkAt(ChunkPos.getByBukkitChunk(location.getChunk()))) .flatMap(chunk -> chunk.getBlockAt(SimpleLocation.of(location))) .ifPresent(block -> { - block.tick(1); + block.tick(1, false); if (block instanceof WorldSprinkler sprinkler) { Sprinkler config = sprinkler.getConfig(); state.setArg("{current}", String.valueOf(sprinkler.getWater())); diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/condition/ConditionManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/condition/ConditionManagerImpl.java index 6ffdb02..19356a7 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/condition/ConditionManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/condition/ConditionManagerImpl.java @@ -33,8 +33,9 @@ import net.momirealms.customcrops.api.mechanic.world.season.Season; import net.momirealms.customcrops.api.util.LogUtils; import net.momirealms.customcrops.compatibility.papi.ParseUtils; import net.momirealms.customcrops.mechanic.misc.CrowAttackAnimation; -import net.momirealms.customcrops.utils.ClassUtils; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.mechanic.world.block.MemoryCrop; +import net.momirealms.customcrops.util.ClassUtils; +import net.momirealms.customcrops.util.ConfigUtils; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.type.Farmland; @@ -95,6 +96,7 @@ public class ConditionManagerImpl implements ConditionManager { this.registerCrowAttackCondition(); this.registerPotCondition(); this.registerLightCondition(); + this.registerPointCondition(); } @Override @@ -167,7 +169,7 @@ public class ConditionManagerImpl implements ConditionManager { String flyModel = section.getString("fly-model"); String standModel = section.getString("stand-model"); double chance = section.getDouble("chance"); - return block -> { + return (block, offline) -> { if (Math.random() > chance) return false; SimpleLocation location = block.getLocation(); if (ConfigManager.enableScarecrow()) { @@ -185,7 +187,8 @@ public class ConditionManagerImpl implements ConditionManager { } } } - new CrowAttackAnimation(location, flyModel, standModel).start(); + if (!offline) + new CrowAttackAnimation(location, flyModel, standModel).start(); return true; }; } else { @@ -198,14 +201,14 @@ public class ConditionManagerImpl implements ConditionManager { private void registerBiomeRequirement() { registerCondition("biome", (args) -> { HashSet biomes = new HashSet<>(ConfigUtils.stringListArgs(args)); - return block -> { + return (block, offline) -> { String currentBiome = BiomeAPI.getBiomeAt(block.getLocation().getBukkitLocation()); return biomes.contains(currentBiome); }; }); registerCondition("!biome", (args) -> { HashSet biomes = new HashSet<>(ConfigUtils.stringListArgs(args)); - return block -> { + return (block, offline) -> { String currentBiome = BiomeAPI.getBiomeAt(block.getLocation().getBukkitLocation()); return !biomes.contains(currentBiome); }; @@ -215,21 +218,21 @@ public class ConditionManagerImpl implements ConditionManager { private void registerRandomCondition() { registerCondition("random", (args -> { double value = ConfigUtils.getDoubleValue(args); - return block -> Math.random() < value; + return (block, offline) -> Math.random() < value; })); } private void registerPotCondition() { registerCondition("pot", (args -> { HashSet pots = new HashSet<>(ConfigUtils.stringListArgs(args)); - return block -> { + return (block, offline) -> { Optional worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0)); return worldPot.filter(pot -> pots.contains(pot.getKey())).isPresent(); }; })); registerCondition("!pot", (args -> { HashSet pots = new HashSet<>(ConfigUtils.stringListArgs(args)); - return block -> { + return (block, offline) -> { Optional worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0)); return worldPot.filter(pot -> !pots.contains(pot.getKey())).isPresent(); }; @@ -239,7 +242,7 @@ public class ConditionManagerImpl implements ConditionManager { private void registerFertilizerCondition() { registerCondition("fertilizer", (args -> { HashSet fertilizer = new HashSet<>(ConfigUtils.stringListArgs(args)); - return block -> { + return (block, offline) -> { Optional worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0)); return worldPot.filter(pot -> { Fertilizer fertilizerInstance = pot.getFertilizer(); @@ -250,7 +253,7 @@ public class ConditionManagerImpl implements ConditionManager { })); registerCondition("fertilizer_type", (args -> { HashSet fertilizer = new HashSet<>(ConfigUtils.stringListArgs(args).stream().map(str -> str.toUpperCase(Locale.ENGLISH)).toList()); - return block -> { + return (block, offline) -> { Optional worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0)); return worldPot.filter(pot -> { Fertilizer fertilizerInstance = pot.getFertilizer(); @@ -265,7 +268,7 @@ public class ConditionManagerImpl implements ConditionManager { registerCondition("&&", (args -> { if (args instanceof ConfigurationSection section) { Condition[] conditions = getConditions(section); - return block -> ConditionManager.isConditionMet(block, conditions); + return (block, offline) -> ConditionManager.isConditionMet(block, offline, conditions); } else { LogUtils.warn("Wrong value format found at && condition."); return EmptyCondition.instance; @@ -277,9 +280,9 @@ public class ConditionManagerImpl implements ConditionManager { registerCondition("||", (args -> { if (args instanceof ConfigurationSection section) { Condition[] conditions = getConditions(section); - return block -> { + return (block, offline) -> { for (Condition condition : conditions) { - if (condition.isConditionMet(block)) { + if (condition.isConditionMet(block, offline)) { return true; } } @@ -295,7 +298,7 @@ public class ConditionManagerImpl implements ConditionManager { private void registerTemperatureCondition() { registerCondition("temperature", (args) -> { List> tempPairs = ConfigUtils.stringListArgs(args).stream().map(it -> ConfigUtils.splitStringIntegerArgs(it, "~")).toList(); - return block -> { + return (block, offline) -> { SimpleLocation location = block.getLocation(); World world = location.getBukkitWorld(); if (world == null) return false; @@ -316,7 +319,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return Double.parseDouble(p1) >= Double.parseDouble(p2); @@ -330,7 +333,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return Double.parseDouble(p1) > Double.parseDouble(p2); @@ -347,7 +350,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("papi", ""); String v2 = section.getString("regex", ""); - return block -> ParseUtils.setPlaceholders(null, v1).matches(v2); + return (block, offline) -> ParseUtils.setPlaceholders(null, v1).matches(v2); } else { LogUtils.warn("Wrong value format found at regex requirement."); return EmptyCondition.instance; @@ -360,7 +363,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return Double.parseDouble(p1) == Double.parseDouble(p2); @@ -374,7 +377,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return Double.parseDouble(p1) != Double.parseDouble(p2); @@ -392,7 +395,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return Double.parseDouble(p1) < Double.parseDouble(p2); @@ -406,7 +409,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return Double.parseDouble(p1) <= Double.parseDouble(p2); @@ -423,7 +426,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return p1.startsWith(p2); @@ -437,7 +440,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return !p1.startsWith(p2); @@ -454,7 +457,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return p1.endsWith(p2); @@ -468,7 +471,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return !p1.endsWith(p2); @@ -485,7 +488,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return p1.contains(p2); @@ -499,7 +502,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return !p1.contains(p2); @@ -516,7 +519,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String papi = section.getString("papi", ""); HashSet values = new HashSet<>(ConfigUtils.stringListArgs(section.get("values"))); - return block -> { + return (block, offline) -> { String p1 = papi.startsWith("%") ? ParseUtils.setPlaceholders(null, papi) : papi; return values.contains(p1); }; @@ -529,7 +532,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String papi = section.getString("papi", ""); HashSet values = new HashSet<>(ConfigUtils.stringListArgs(section.get("values"))); - return block -> { + return (block, offline) -> { String p1 = papi.startsWith("%") ? ParseUtils.setPlaceholders(null, papi) : papi; return !values.contains(p1); }; @@ -545,7 +548,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return p1.equals(p2); @@ -559,7 +562,7 @@ public class ConditionManagerImpl implements ConditionManager { if (args instanceof ConfigurationSection section) { String v1 = section.getString("value1", ""); String v2 = section.getString("value2", ""); - return block -> { + return (block, offline) -> { String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1; String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2; return !p1.equals(p2); @@ -574,7 +577,7 @@ public class ConditionManagerImpl implements ConditionManager { private void registerSeasonCondition() { registerCondition("suitable_season", (args) -> { HashSet seasons = new HashSet<>(ConfigUtils.stringListArgs(args).stream().map(it -> it.toUpperCase(Locale.ENGLISH)).toList()); - return block -> { + return (block, offline) -> { Season season = plugin.getIntegrationManager().getSeason(block.getLocation().getBukkitWorld()); if (season == null) { return true; @@ -598,7 +601,7 @@ public class ConditionManagerImpl implements ConditionManager { }); registerCondition("unsuitable_season", (args) -> { HashSet seasons = new HashSet<>(ConfigUtils.stringListArgs(args).stream().map(it -> it.toUpperCase(Locale.ENGLISH)).toList()); - return block -> { + return (block, offline) -> { Season season = plugin.getIntegrationManager().getSeason(block.getLocation().getBukkitWorld()); if (season == null) { return false; @@ -625,52 +628,73 @@ public class ConditionManagerImpl implements ConditionManager { private void registerLightCondition() { registerCondition("skylight_more_than", (args) -> { int value = (int) args; - return block -> { + return (block, offline) -> { int light = block.getLocation().getBukkitLocation().getBlock().getLightFromSky(); return value > light; }; }); registerCondition("skylight_less_than", (args) -> { int value = (int) args; - return block -> { + return (block, offline) -> { int light = block.getLocation().getBukkitLocation().getBlock().getLightFromSky(); return value < light; }; }); registerCondition("light_more_than", (args) -> { int value = (int) args; - return block -> { + return (block, offline) -> { int light = block.getLocation().getBukkitLocation().getBlock().getLightLevel(); return value > light; }; }); registerCondition("light_less_than", (args) -> { int value = (int) args; - return block -> { + return (block, offline) -> { int light = block.getLocation().getBukkitLocation().getBlock().getLightLevel(); return value < light; }; }); } + private void registerPointCondition() { + registerCondition("point_more_than", (args) -> { + int value = (int) args; + return (block, offline) -> { + if (block instanceof MemoryCrop crop) { + return crop.getPoint() > value; + } + return false; + }; + }); + registerCondition("point_less_than", (args) -> { + int value = (int) args; + return (block, offline) -> { + if (block instanceof MemoryCrop crop) { + return crop.getPoint() < value; + } + return false; + }; + }); + } + private void registerWaterCondition() { registerCondition("water_more_than", (args) -> { int value = (int) args; - return block -> { + return (block, offline) -> { Optional worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0)); return worldPot.filter(pot -> pot.getWater() > value).isPresent(); }; }); registerCondition("water_less_than", (args) -> { int value = (int) args; - return block -> { + return (block, offline) -> { Optional worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0)); return worldPot.filter(pot -> pot.getWater() < value).isPresent(); }; }); registerCondition("moisture_more_than", (args) -> { int value = (int) args; - return block -> { + return (block, offline) -> { Block underBlock = block.getLocation().copy().add(0,-1,0).getBukkitLocation().getBlock(); if (underBlock.getBlockData() instanceof Farmland farmland) { return farmland.getMoisture() > value; @@ -680,7 +704,7 @@ public class ConditionManagerImpl implements ConditionManager { }); registerCondition("moisture_less_than", (args) -> { int value = (int) args; - return block -> { + return (block, offline) -> { Block underBlock = block.getLocation().copy().add(0,-1,0).getBukkitLocation().getBlock(); if (underBlock.getBlockData() instanceof Farmland farmland) { return farmland.getMoisture() < value; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/condition/EmptyCondition.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/condition/EmptyCondition.java index 77de905..f046062 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/condition/EmptyCondition.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/condition/EmptyCondition.java @@ -25,7 +25,7 @@ public class EmptyCondition implements Condition { public static EmptyCondition instance = new EmptyCondition(); @Override - public boolean isConditionMet(CustomCropsBlock block) { + public boolean isConditionMet(CustomCropsBlock block, boolean offline) { return true; } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/CustomProvider.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/CustomProvider.java index 1f6b772..fe91882 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/CustomProvider.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/CustomProvider.java @@ -20,9 +20,9 @@ package net.momirealms.customcrops.mechanic.item; import net.momirealms.customcrops.api.manager.VersionManager; import net.momirealms.customcrops.api.mechanic.misc.CRotation; import net.momirealms.customcrops.api.util.LocationUtils; -import net.momirealms.customcrops.utils.ConfigUtils; -import net.momirealms.customcrops.utils.DisplayEntityUtils; -import net.momirealms.customcrops.utils.RotationUtils; +import net.momirealms.customcrops.util.ConfigUtils; +import net.momirealms.customcrops.util.DisplayEntityUtils; +import net.momirealms.customcrops.util.RotationUtils; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java index 97e0085..1a1428b 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java @@ -57,10 +57,10 @@ import net.momirealms.customcrops.mechanic.item.impl.SprinklerConfig; import net.momirealms.customcrops.mechanic.item.impl.WateringCanConfig; import net.momirealms.customcrops.mechanic.item.impl.fertilizer.*; import net.momirealms.customcrops.mechanic.world.block.*; -import net.momirealms.customcrops.utils.ConfigUtils; -import net.momirealms.customcrops.utils.EventUtils; -import net.momirealms.customcrops.utils.ItemUtils; -import net.momirealms.customcrops.utils.RotationUtils; +import net.momirealms.customcrops.util.ConfigUtils; +import net.momirealms.customcrops.util.EventUtils; +import net.momirealms.customcrops.util.ItemUtils; +import net.momirealms.customcrops.util.RotationUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -213,7 +213,7 @@ public class ItemManagerImpl implements ItemManager { @Override public String getItemID(ItemStack itemStack) { - if (itemStack == null) + if (itemStack == null || itemStack.getType() == Material.AIR || itemStack.getAmount() == 0) return "AIR"; String id; id = customProvider.getItemID(itemStack); diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/AbstractCustomListener.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/AbstractCustomListener.java index 198aa41..6a27fef 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/AbstractCustomListener.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/AbstractCustomListener.java @@ -27,7 +27,7 @@ import net.momirealms.customcrops.api.mechanic.requirement.State; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop; import net.momirealms.customcrops.mechanic.item.ItemManagerImpl; -import net.momirealms.customcrops.utils.EventUtils; +import net.momirealms.customcrops.util.EventUtils; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/itemsadder/ItemsAdderProvider.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/itemsadder/ItemsAdderProvider.java index 7604f3d..62e0939 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/itemsadder/ItemsAdderProvider.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/itemsadder/ItemsAdderProvider.java @@ -20,7 +20,6 @@ package net.momirealms.customcrops.mechanic.item.custom.itemsadder; import dev.lone.itemsadder.api.CustomBlock; import dev.lone.itemsadder.api.CustomFurniture; import dev.lone.itemsadder.api.CustomStack; -import net.momirealms.customcrops.api.util.LocationUtils; import net.momirealms.customcrops.api.util.LogUtils; import net.momirealms.customcrops.mechanic.item.CustomProvider; import org.bukkit.Location; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/oraxen/OraxenProvider.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/oraxen/OraxenProvider.java index 754cd9b..34f2327 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/oraxen/OraxenProvider.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/oraxen/OraxenProvider.java @@ -41,9 +41,7 @@ public class OraxenProvider implements CustomProvider { if (block.getType() == Material.AIR) { return false; } - if (!OraxenBlocks.remove(location, null, false)) { - block.setType(Material.AIR); - } + block.setType(Material.AIR); return true; } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/impl/PotConfig.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/impl/PotConfig.java index d2d3abe..ecda936 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/impl/PotConfig.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/impl/PotConfig.java @@ -26,7 +26,7 @@ import net.momirealms.customcrops.api.mechanic.item.water.PassiveFillMethod; import net.momirealms.customcrops.api.mechanic.misc.image.WaterBar; import net.momirealms.customcrops.api.mechanic.requirement.Requirement; import net.momirealms.customcrops.mechanic.item.AbstractEventItem; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.util.ConfigUtils; import java.util.HashMap; import java.util.HashSet; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/CrowAttackAnimation.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/CrowAttackAnimation.java index ba2333c..72b1b19 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/CrowAttackAnimation.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/CrowAttackAnimation.java @@ -22,7 +22,7 @@ import net.momirealms.customcrops.api.CustomCropsPlugin; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.scheduler.CancellableTask; import net.momirealms.customcrops.manager.PacketManager; -import net.momirealms.customcrops.utils.FakeEntityUtils; +import net.momirealms.customcrops.util.FakeEntityUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.EntityType; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/TempFakeItem.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/TempFakeItem.java index 871e13e..fb74bbd 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/TempFakeItem.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/TempFakeItem.java @@ -21,7 +21,7 @@ import com.comphenix.protocol.events.PacketContainer; import net.momirealms.customcrops.api.CustomCropsPlugin; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.manager.PacketManager; -import net.momirealms.customcrops.utils.FakeEntityUtils; +import net.momirealms.customcrops.util.FakeEntityUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.EntityType; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/migrator/Migration.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/migrator/Migration.java index cefe581..dac5ecb 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/migrator/Migration.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/migrator/Migration.java @@ -11,7 +11,7 @@ import net.momirealms.customcrops.api.mechanic.world.level.WorldSetting; import net.momirealms.customcrops.api.util.LogUtils; import net.momirealms.customcrops.mechanic.world.CWorld; import net.momirealms.customcrops.mechanic.world.adaptor.BukkitWorldAdaptor; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.util.ConfigUtils; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; @@ -47,7 +47,7 @@ public class Migration { if (CustomCropsPlugin.get().getWorldManager().getWorldAdaptor() instanceof BukkitWorldAdaptor adaptor) { for (World world : Bukkit.getWorlds()) { CWorld temp = new CWorld(CustomCropsPlugin.getInstance().getWorldManager(), world); - temp.setWorldSetting(WorldSetting.of(false,300,true, 1,true,2,true,2,false,false,false,28,-1,-1,-1, 0)); + temp.setWorldSetting(WorldSetting.of(false,300,true, 1,true,2,true,2,false,1200, false,false,28,-1,-1,-1, 0)); adaptor.convertWorldFromV342toV343(temp, world); } } @@ -102,7 +102,7 @@ public class Migration { if (CustomCropsPlugin.get().getWorldManager().getWorldAdaptor() instanceof BukkitWorldAdaptor adaptor) { for (World world : Bukkit.getWorlds()) { CWorld temp = new CWorld(CustomCropsPlugin.getInstance().getWorldManager(), world); - temp.setWorldSetting(WorldSetting.of(false,300,true, 1,true,2,true,2,false,false,false,28,-1,-1,-1, 0)); + temp.setWorldSetting(WorldSetting.of(false,300,true, 1,true,2,true,2,false, 1200, false,false,28,-1,-1,-1, 0)); adaptor.convertWorldFromV33toV34(temp, world); } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/value/ExpressionValue.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/value/ExpressionValue.java index ec28e0e..9125b51 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/value/ExpressionValue.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/value/ExpressionValue.java @@ -18,7 +18,7 @@ package net.momirealms.customcrops.mechanic.misc.value; import net.momirealms.customcrops.api.mechanic.misc.Value; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.util.ConfigUtils; import org.bukkit.entity.Player; import java.util.HashMap; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java index 2f87b14..73c967f 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java @@ -37,8 +37,8 @@ import net.momirealms.customcrops.api.mechanic.world.season.Season; import net.momirealms.customcrops.api.util.LogUtils; import net.momirealms.customcrops.compatibility.VaultHook; import net.momirealms.customcrops.compatibility.papi.ParseUtils; -import net.momirealms.customcrops.utils.ClassUtils; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.util.ClassUtils; +import net.momirealms.customcrops.util.ConfigUtils; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java index 2555f13..1bac59b 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java @@ -88,7 +88,26 @@ public class CChunk implements CustomCropsChunk { @Override public void notifyOfflineUpdates() { - this.lastLoadedTime = System.currentTimeMillis(); + long current = System.currentTimeMillis(); + int offlineTimeInSeconds = (int) (this.lastLoadedTime - current) / 1000; + offlineTimeInSeconds = Math.min(offlineTimeInSeconds, cWorld.getWorldSetting().getMaxOfflineTime()); + this.lastLoadedTime = current; + var setting = cWorld.getWorldSetting(); + int minTickUnit = setting.getMinTickUnit(); + + for (int i = 0; i < offlineTimeInSeconds; i++) { + this.loadedSeconds++; + if (this.loadedSeconds >= minTickUnit) { + this.loadedSeconds = 0; + this.tickedBlocks.clear(); + this.queue.clear(); + if (setting.isScheduledTick()) { + this.arrangeTasks(minTickUnit); + } + } + scheduledTick(setting, true); + randomTick(setting, true); + } } public void setWorld(CWorld cWorld) { @@ -121,10 +140,15 @@ public class CChunk implements CustomCropsChunk { this.tickedBlocks.clear(); this.queue.clear(); if (setting.isScheduledTick()) { - this.arrangeTasks(setting.getMinTickUnit()); + this.arrangeTasks(interval); } } + scheduledTick(setting, false); + randomTick(setting, false); + } + + private void scheduledTick(WorldSetting setting, boolean offline) { // scheduled tick while (!queue.isEmpty() && queue.peek().getTime() <= loadedSeconds) { TickTask task = queue.poll(); @@ -138,24 +162,26 @@ public class CChunk implements CustomCropsChunk { case SCARECROW, GREENHOUSE -> {} case POT -> { if (!setting.randomTickPot()) { - block.tick(setting.getTickPotInterval()); + block.tick(setting.getTickPotInterval(), offline); } } case CROP -> { if (!setting.randomTickCrop()) { - block.tick(setting.getTickCropInterval()); + block.tick(setting.getTickCropInterval(), offline); } } case SPRINKLER -> { if (!setting.randomTickSprinkler()) { - block.tick(setting.getTickSprinklerInterval()); + block.tick(setting.getTickSprinklerInterval(), offline); } } } } } } + } + private void randomTick(WorldSetting setting, boolean offline) { // random tick ThreadLocalRandom random = ThreadLocalRandom.current(); int randomTicks = setting.getRandomTickSpeed(); @@ -171,18 +197,18 @@ public class CChunk implements CustomCropsChunk { switch (block.getType()) { case CROP -> { if (setting.randomTickCrop()) { - block.tick(setting.getTickCropInterval()); + block.tick(setting.getTickCropInterval(), offline); } } case SPRINKLER -> { if (setting.randomTickSprinkler()) { - block.tick(setting.getTickSprinklerInterval()); + block.tick(setting.getTickSprinklerInterval(), offline); } } case POT -> { ((WorldPot) block).tickWater(this); if (setting.randomTickPot()) { - block.tick(setting.getTickPotInterval()); + block.tick(setting.getTickPotInterval(), offline); } } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java index 052024d..721724c 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java @@ -36,7 +36,7 @@ import net.momirealms.customcrops.api.mechanic.world.season.Season; import net.momirealms.customcrops.api.scheduler.CancellableTask; import net.momirealms.customcrops.api.scheduler.Scheduler; import net.momirealms.customcrops.api.util.LogUtils; -import net.momirealms.customcrops.utils.EventUtils; +import net.momirealms.customcrops.util.EventUtils; import org.bukkit.Bukkit; import org.bukkit.World; import org.jetbrains.annotations.Nullable; @@ -122,13 +122,19 @@ public class CWorld implements CustomCropsWorld { this.updateSeasonAndDate(); } if (setting.isSchedulerEnabled()) { + Scheduler scheduler = CustomCropsPlugin.get().getScheduler(); if (VersionManager.folia()) { - Scheduler scheduler = CustomCropsPlugin.get().getScheduler(); for (CChunk chunk : loadedChunks.values()) { + if (unloadIfNotLoaded(chunk.getChunkPos())) { + continue; + } scheduler.runTaskSync(chunk::secondTimer, getWorld(), chunk.getChunkPos().x(), chunk.getChunkPos().z()); } } else { for (CChunk chunk : loadedChunks.values()) { + if (unloadIfNotLoaded(chunk.getChunkPos())) { + continue; + } chunk.secondTimer(); } } @@ -302,49 +308,49 @@ public class CWorld implements CustomCropsWorld { @Override public Optional getSprinklerAt(SimpleLocation location) { - CChunk chunk = loadedChunks.get(location.getChunkCoordinate()); + CChunk chunk = loadedChunks.get(location.getChunkPos()); if (chunk == null) return Optional.empty(); return chunk.getSprinklerAt(location); } @Override public Optional getPotAt(SimpleLocation location) { - CChunk chunk = loadedChunks.get(location.getChunkCoordinate()); + CChunk chunk = loadedChunks.get(location.getChunkPos()); if (chunk == null) return Optional.empty(); return chunk.getPotAt(location); } @Override public Optional getCropAt(SimpleLocation location) { - CChunk chunk = loadedChunks.get(location.getChunkCoordinate()); + CChunk chunk = loadedChunks.get(location.getChunkPos()); if (chunk == null) return Optional.empty(); return chunk.getCropAt(location); } @Override public Optional getGlassAt(SimpleLocation location) { - CChunk chunk = loadedChunks.get(location.getChunkCoordinate()); + CChunk chunk = loadedChunks.get(location.getChunkPos()); if (chunk == null) return Optional.empty(); return chunk.getGlassAt(location); } @Override public Optional getScarecrowAt(SimpleLocation location) { - CChunk chunk = loadedChunks.get(location.getChunkCoordinate()); + CChunk chunk = loadedChunks.get(location.getChunkPos()); if (chunk == null) return Optional.empty(); return chunk.getScarecrowAt(location); } @Override public Optional getBlockAt(SimpleLocation location) { - CChunk chunk = loadedChunks.get(location.getChunkCoordinate()); + CChunk chunk = loadedChunks.get(location.getChunkPos()); if (chunk == null) return Optional.empty(); return chunk.getBlockAt(location); } @Override public void addWaterToSprinkler(Sprinkler sprinkler, SimpleLocation location, int amount) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addWaterToSprinkler(sprinkler, location, amount); } else { @@ -354,7 +360,7 @@ public class CWorld implements CustomCropsWorld { @Override public void addFertilizerToPot(Pot pot, Fertilizer fertilizer, SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addFertilizerToPot(pot, fertilizer, location); } else { @@ -364,7 +370,7 @@ public class CWorld implements CustomCropsWorld { @Override public void addWaterToPot(Pot pot, SimpleLocation location, int amount) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addWaterToPot(pot, location, amount); } else { @@ -374,7 +380,7 @@ public class CWorld implements CustomCropsWorld { @Override public void addPotAt(WorldPot pot, SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addPotAt(pot, location); } else { @@ -384,7 +390,7 @@ public class CWorld implements CustomCropsWorld { @Override public void addSprinklerAt(WorldSprinkler sprinkler, SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addSprinklerAt(sprinkler, location); } else { @@ -394,7 +400,7 @@ public class CWorld implements CustomCropsWorld { @Override public void addCropAt(WorldCrop crop, SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addCropAt(crop, location); } else { @@ -404,7 +410,7 @@ public class CWorld implements CustomCropsWorld { @Override public void addPointToCrop(Crop crop, SimpleLocation location, int points) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addPointToCrop(crop, location, points); } else { @@ -414,7 +420,7 @@ public class CWorld implements CustomCropsWorld { @Override public void addGlassAt(WorldGlass glass, SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addGlassAt(glass, location); } else { @@ -424,7 +430,7 @@ public class CWorld implements CustomCropsWorld { @Override public void addScarecrowAt(WorldScarecrow scarecrow, SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().addScarecrowAt(scarecrow, location); } else { @@ -434,7 +440,7 @@ public class CWorld implements CustomCropsWorld { @Override public void removeSprinklerAt(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().removeSprinklerAt(location); } else { @@ -444,7 +450,7 @@ public class CWorld implements CustomCropsWorld { @Override public void removePotAt(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().removePotAt(location); } else { @@ -454,7 +460,7 @@ public class CWorld implements CustomCropsWorld { @Override public void removeCropAt(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().removeCropAt(location); } else { @@ -464,7 +470,7 @@ public class CWorld implements CustomCropsWorld { @Override public void removeGlassAt(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().removeGlassAt(location); } else { @@ -474,7 +480,7 @@ public class CWorld implements CustomCropsWorld { @Override public void removeScarecrowAt(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { chunk.get().removeScarecrowAt(location); } else { @@ -484,7 +490,7 @@ public class CWorld implements CustomCropsWorld { @Override public CustomCropsBlock removeAnythingAt(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isPresent()) { return chunk.get().removeBlockAt(location); } else { @@ -514,7 +520,7 @@ public class CWorld implements CustomCropsWorld { @Override public boolean isPotReachLimit(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isEmpty()) { LogUtils.warn("Invalid operation: Querying pot amount from a not generated chunk"); return true; @@ -525,7 +531,7 @@ public class CWorld implements CustomCropsWorld { @Override public boolean isCropReachLimit(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isEmpty()) { LogUtils.warn("Invalid operation: Querying crop amount from a not generated chunk"); return true; @@ -536,7 +542,7 @@ public class CWorld implements CustomCropsWorld { @Override public boolean isSprinklerReachLimit(SimpleLocation location) { - Optional chunk = getLoadedChunkAt(location.getChunkCoordinate()); + Optional chunk = getLoadedChunkAt(location.getChunkPos()); if (chunk.isEmpty()) { LogUtils.warn("Invalid operation: Querying sprinkler amount from a not generated chunk"); return true; @@ -559,4 +565,12 @@ public class CWorld implements CustomCropsWorld { } return true; } + + private boolean unloadIfNotLoaded(ChunkPos pos) { + if (!world.get().isChunkLoaded(pos.x(), pos.z())) { + unloadChunk(pos); + return true; + } + return false; + } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/WorldManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/WorldManagerImpl.java index 24e215b..a9800bf 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/WorldManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/WorldManagerImpl.java @@ -29,7 +29,7 @@ import net.momirealms.customcrops.api.mechanic.world.level.*; import net.momirealms.customcrops.api.util.LogUtils; import net.momirealms.customcrops.mechanic.world.adaptor.BukkitWorldAdaptor; import net.momirealms.customcrops.mechanic.world.adaptor.SlimeWorldAdaptor; -import net.momirealms.customcrops.utils.ConfigUtils; +import net.momirealms.customcrops.util.ConfigUtils; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -490,6 +490,7 @@ public class WorldManagerImpl implements WorldManager, Listener { } CustomCropsChunk chunk = optionalChunk.get(); + // load the entities if not loaded bukkitChunk.getEntities(); chunk.notifyOfflineUpdates(); } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryCrop.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryCrop.java index 13094a4..7a3dec9 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryCrop.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryCrop.java @@ -101,13 +101,13 @@ public class MemoryCrop extends AbstractCustomCropsBlock implements WorldCrop { } @Override - public void tick(int interval) { + public void tick(int interval, boolean offline) { if (canTick(interval)) { - tick(); + tick(offline); } } - private void tick() { + private void tick(boolean offline) { Crop crop = getConfig(); if (crop == null) { LogUtils.warn("Found a crop without config at " + getLocation() + ". Try removing the data."); @@ -124,14 +124,14 @@ public class MemoryCrop extends AbstractCustomCropsBlock implements WorldCrop { // check death conditions for (DeathConditions deathConditions : crop.getDeathConditions()) { for (Condition condition : deathConditions.getConditions()) { - if (condition.isConditionMet(this)) { + if (condition.isConditionMet(this, offline)) { CustomCropsPlugin.get().getScheduler().runTaskSyncLater(() -> { CustomCropsPlugin.get().getWorldManager().removeCropAt(location); CustomCropsPlugin.get().getItemManager().removeAnythingAt(bukkitLocation); if (deathConditions.getDeathItem() != null) { CustomCropsPlugin.get().getItemManager().placeItem(bukkitLocation, deathConditions.getItemCarrier(), deathConditions.getDeathItem()); } - }, bukkitLocation, deathConditions.getDeathDelay()); + }, bukkitLocation, offline ? 0 : deathConditions.getDeathDelay()); return; } } @@ -144,7 +144,7 @@ public class MemoryCrop extends AbstractCustomCropsBlock implements WorldCrop { // check grow conditions for (Condition condition : crop.getGrowConditions().getConditions()) { - if (!condition.isConditionMet(this)) { + if (!condition.isConditionMet(this, offline)) { return; } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryGlass.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryGlass.java index b00ffb4..0d21d70 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryGlass.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryGlass.java @@ -54,7 +54,7 @@ public class MemoryGlass extends AbstractCustomCropsBlock implements WorldGlass } @Override - public void tick(int interval) { + public void tick(int interval, boolean offline) { } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryPot.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryPot.java index 49fefed..9f61ea6 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryPot.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryPot.java @@ -189,12 +189,13 @@ public class MemoryPot extends AbstractCustomCropsBlock implements WorldPot { } @Override - public void tick(int interval) { + public void tick(int interval, boolean offline) { if (canTick(interval)) { tick(); } } + // if the tick is triggered by offline growth private void tick() { Pot pot = getConfig(); if (pot == null) { diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryScarecrow.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryScarecrow.java index 0c78c17..0011922 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryScarecrow.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryScarecrow.java @@ -54,7 +54,7 @@ public class MemoryScarecrow extends AbstractCustomCropsBlock implements WorldSc } @Override - public void tick(int interval) { + public void tick(int interval, boolean offline) { } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemorySprinkler.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemorySprinkler.java index 8cb187e..ba9cac0 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemorySprinkler.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemorySprinkler.java @@ -26,6 +26,7 @@ import net.momirealms.customcrops.api.mechanic.item.ItemType; import net.momirealms.customcrops.api.mechanic.item.Pot; import net.momirealms.customcrops.api.mechanic.item.Sprinkler; import net.momirealms.customcrops.api.mechanic.requirement.State; +import net.momirealms.customcrops.api.mechanic.world.ChunkPos; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.level.AbstractCustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld; @@ -34,10 +35,10 @@ import net.momirealms.customcrops.api.mechanic.world.level.WorldSprinkler; import net.momirealms.customcrops.api.util.LogUtils; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.inventory.ItemStack; -import java.util.Objects; -import java.util.Optional; +import java.util.*; public class MemorySprinkler extends AbstractCustomCropsBlock implements WorldSprinkler { @@ -97,13 +98,14 @@ public class MemorySprinkler extends AbstractCustomCropsBlock implements WorldSp } @Override - public void tick(int interval) { + public void tick(int interval, boolean offline) { if (canTick(interval)) { - tick(); + tick(offline); } } - private void tick() { + // if the tick is triggered by offline growth + private void tick(boolean offline) { Sprinkler sprinkler = getConfig(); if (sprinkler == null) { LogUtils.warn("Found a sprinkler without config at " + getLocation() + ". Try removing the data."); @@ -127,7 +129,9 @@ public class MemorySprinkler extends AbstractCustomCropsBlock implements WorldSp Location bukkitLocation = location.getBukkitLocation(); if (bukkitLocation == null) return; CustomCropsPlugin.get().getScheduler().runTaskSync(() -> { - sprinkler.trigger(ActionTrigger.WORK, new State(null, new ItemStack(Material.AIR), bukkitLocation)); + State state = new State(null, new ItemStack(Material.AIR), bukkitLocation); + if (offline) state.setArg("{offline}", "true"); + sprinkler.trigger(ActionTrigger.WORK, state); if (updateState && sprinkler.get3DItemWithWater() != null) { CustomCropsPlugin.get().getItemManager().removeAnythingAt(bukkitLocation); CustomCropsPlugin.get().getItemManager().placeItem(bukkitLocation, sprinkler.getItemCarrier(), sprinkler.get3DItemID()); @@ -135,11 +139,26 @@ public class MemorySprinkler extends AbstractCustomCropsBlock implements WorldSp }, bukkitLocation); int range = sprinkler.getRange(); - CustomCropsWorld world = CustomCropsPlugin.get().getWorldManager().getCustomCropsWorld(location.getWorldName()).get(); + HashMap> map = new HashMap<>(); for (int i = -range; i <= range; i++) { for (int j = -range; j <= range; j++) { for (int k : new int[]{-1,0}) { SimpleLocation potLocation = location.copy().add(i,k,j); + var cPos = potLocation.getChunkPos(); + var list = map.computeIfAbsent(cPos, key -> new ArrayList<>()); + list.add(potLocation); + } + } + } + + CustomCropsWorld world = CustomCropsPlugin.get().getWorldManager().getCustomCropsWorld(location.getWorldName()).get(); + World bkWorld = world.getWorld(); + for (Map.Entry> entry : map.entrySet()) { + var chunkPos = entry.getKey(); + CustomCropsPlugin.get().getScheduler().runTaskSync(() -> { + // load the chunk firstly to load CustomCrops data + bkWorld.getChunkAt(chunkPos.x(), chunkPos.z()); + for (SimpleLocation potLocation : entry.getValue()) { Optional pot = world.getPotAt(potLocation); if (pot.isPresent()) { WorldPot worldPot = pot.get(); @@ -152,13 +171,13 @@ public class MemorySprinkler extends AbstractCustomCropsBlock implements WorldSp } worldPot.setWater(current + sprinkler.getWater()); if (current == 0) { - CustomCropsPlugin.get().getScheduler().runTaskSync(() -> CustomCropsPlugin.get().getItemManager().updatePotState(potLocation.getBukkitLocation(), potConfig, true, worldPot.getFertilizer()), potLocation.getBukkitLocation()); + CustomCropsPlugin.get().getItemManager().updatePotState(potLocation.getBukkitLocation(), potConfig, true, worldPot.getFertilizer()); } } } } } - } + }, bkWorld, chunkPos.x(), chunkPos.z()); } } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/ClassUtils.java b/plugin/src/main/java/net/momirealms/customcrops/util/ClassUtils.java similarity index 98% rename from plugin/src/main/java/net/momirealms/customcrops/utils/ClassUtils.java rename to plugin/src/main/java/net/momirealms/customcrops/util/ClassUtils.java index 6cd18ac..b558e6b 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/utils/ClassUtils.java +++ b/plugin/src/main/java/net/momirealms/customcrops/util/ClassUtils.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package net.momirealms.customcrops.utils; +package net.momirealms.customcrops.util; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/ConfigUtils.java b/plugin/src/main/java/net/momirealms/customcrops/util/ConfigUtils.java similarity index 98% rename from plugin/src/main/java/net/momirealms/customcrops/utils/ConfigUtils.java rename to plugin/src/main/java/net/momirealms/customcrops/util/ConfigUtils.java index ba5af1e..7ae8212 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/utils/ConfigUtils.java +++ b/plugin/src/main/java/net/momirealms/customcrops/util/ConfigUtils.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package net.momirealms.customcrops.utils; +package net.momirealms.customcrops.util; import com.google.common.base.Preconditions; import net.momirealms.customcrops.api.CustomCropsPlugin; @@ -70,7 +70,8 @@ public class ConfigUtils { section.getInt("pot.tick-interval", 2), getRandomTickModeByString(section.getString("sprinkler.mode")), section.getInt("sprinkler.tick-interval", 2), - section.getBoolean("offline-grow", false), + section.getBoolean("offline-growth.enable", false), + section.getInt("offline-growth.max-offline-seconds", 1200), section.getBoolean("season.enable", false), section.getBoolean("season.auto-alternation", false), section.getInt("season.duration", 28), diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/DisplayEntityUtils.java b/plugin/src/main/java/net/momirealms/customcrops/util/DisplayEntityUtils.java similarity index 90% rename from plugin/src/main/java/net/momirealms/customcrops/utils/DisplayEntityUtils.java rename to plugin/src/main/java/net/momirealms/customcrops/util/DisplayEntityUtils.java index e23914e..d1f0825 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/utils/DisplayEntityUtils.java +++ b/plugin/src/main/java/net/momirealms/customcrops/util/DisplayEntityUtils.java @@ -1,4 +1,4 @@ -package net.momirealms.customcrops.utils; +package net.momirealms.customcrops.util; import net.momirealms.customcrops.api.mechanic.misc.CRotation; import org.bukkit.entity.Entity; diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/EventUtils.java b/plugin/src/main/java/net/momirealms/customcrops/util/EventUtils.java similarity index 96% rename from plugin/src/main/java/net/momirealms/customcrops/utils/EventUtils.java rename to plugin/src/main/java/net/momirealms/customcrops/util/EventUtils.java index 02e02da..2f503b9 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/utils/EventUtils.java +++ b/plugin/src/main/java/net/momirealms/customcrops/util/EventUtils.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package net.momirealms.customcrops.utils; +package net.momirealms.customcrops.util; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/FakeEntityUtils.java b/plugin/src/main/java/net/momirealms/customcrops/util/FakeEntityUtils.java similarity index 99% rename from plugin/src/main/java/net/momirealms/customcrops/utils/FakeEntityUtils.java rename to plugin/src/main/java/net/momirealms/customcrops/util/FakeEntityUtils.java index 52f97dc..030c2a9 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/utils/FakeEntityUtils.java +++ b/plugin/src/main/java/net/momirealms/customcrops/util/FakeEntityUtils.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package net.momirealms.customcrops.utils; +package net.momirealms.customcrops.util; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketContainer; diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/ItemUtils.java b/plugin/src/main/java/net/momirealms/customcrops/util/ItemUtils.java similarity index 99% rename from plugin/src/main/java/net/momirealms/customcrops/utils/ItemUtils.java rename to plugin/src/main/java/net/momirealms/customcrops/util/ItemUtils.java index da89378..175872c 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/utils/ItemUtils.java +++ b/plugin/src/main/java/net/momirealms/customcrops/util/ItemUtils.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package net.momirealms.customcrops.utils; +package net.momirealms.customcrops.util; import de.tr7zw.changeme.nbtapi.NBTItem; import org.bukkit.Bukkit; diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/RotationUtils.java b/plugin/src/main/java/net/momirealms/customcrops/util/RotationUtils.java similarity index 98% rename from plugin/src/main/java/net/momirealms/customcrops/utils/RotationUtils.java rename to plugin/src/main/java/net/momirealms/customcrops/util/RotationUtils.java index fd7c07d..abf1eb5 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/utils/RotationUtils.java +++ b/plugin/src/main/java/net/momirealms/customcrops/util/RotationUtils.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package net.momirealms.customcrops.utils; +package net.momirealms.customcrops.util; import net.momirealms.customcrops.api.mechanic.misc.CRotation; import org.bukkit.Rotation; diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index fc0669e..f94b33d 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -46,6 +46,16 @@ worlds: # For crops, under the same conditions, the growth rate of crops is basically the same # For sprinklers and pots, they would work periodically. min-tick-unit: 300 + # Offline growth settings + # This option allows crops to grow even if the world is unloaded or the server is closed + # This may lead to some issues caused by timeliness conditions for instance seasons + offline-growth: + enable: false + # Maximum offline time recorded in seconds + # Please do not set this option to a value that is too large, + # as it may cause chunks that have been unloaded for a long time + # taking long to load + max-offline-seconds: 1200 # Settings for crops crop: # [RANDOM_TICK]