mirror of
https://github.com/Xiao-MoMi/Custom-Crops.git
synced 2025-12-29 11:59:15 +00:00
3.3.0.0
This commit is contained in:
@@ -4,7 +4,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = 'net.momirealms'
|
||||
version = '3.2.5.0'
|
||||
version = '3.3.0.0-beta'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@@ -26,10 +26,10 @@ repositories {
|
||||
dependencies {
|
||||
compileOnly ('dev.dejvokep:boosted-yaml:1.3.1')
|
||||
compileOnly ('commons-io:commons-io:2.11.0')
|
||||
compileOnly ('io.papermc.paper:paper-api:1.20-R0.1-SNAPSHOT')
|
||||
compileOnly ('io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT')
|
||||
compileOnly ('me.clip:placeholderapi:2.11.3')
|
||||
compileOnly ('com.github.LoneDev6:api-itemsadder:3.4.1e')
|
||||
compileOnly('com.github.oraxen:oraxen:1.157.2')
|
||||
compileOnly ('com.github.oraxen:oraxen:1.157.2')
|
||||
compileOnly ('io.lumine:Mythic-Dist:5.0.3-SNAPSHOT')
|
||||
compileOnly ('com.willfp:eco:6.60.0')
|
||||
compileOnly ('com.willfp:EcoJobs:3.13.0')
|
||||
|
||||
@@ -349,7 +349,7 @@ public interface PlatformInterface {
|
||||
* @param itemMode itemMode
|
||||
*/
|
||||
default void placeCustomItem(Location location, String id, ItemMode itemMode) {
|
||||
if (itemMode == ItemMode.TRIPWIRE)
|
||||
if (itemMode == ItemMode.TRIPWIRE || itemMode == ItemMode.NOTE_BLOCK)
|
||||
placeTripWire(location, id);
|
||||
else if (itemMode == ItemMode.ITEM_FRAME)
|
||||
placeItemFrame(location, id);
|
||||
@@ -366,7 +366,7 @@ public interface PlatformInterface {
|
||||
* @return success or not
|
||||
*/
|
||||
default boolean removeCustomItem(Location location, ItemMode itemMode) {
|
||||
if (itemMode == ItemMode.TRIPWIRE || itemMode == ItemMode.CHORUS)
|
||||
if (itemMode == ItemMode.TRIPWIRE || itemMode == ItemMode.CHORUS || itemMode == ItemMode.NOTE_BLOCK)
|
||||
return removeCustomBlock(location);
|
||||
else if (itemMode == ItemMode.ITEM_FRAME)
|
||||
return removeItemFrame(location);
|
||||
|
||||
@@ -17,11 +17,14 @@
|
||||
|
||||
package net.momirealms.customcrops.api.object;
|
||||
|
||||
public enum ItemMode {
|
||||
import java.io.Serializable;
|
||||
|
||||
public enum ItemMode implements Serializable {
|
||||
|
||||
ARMOR_STAND,
|
||||
TRIPWIRE,
|
||||
ITEM_FRAME,
|
||||
ITEM_DISPLAY,
|
||||
NOTE_BLOCK,
|
||||
CHORUS
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package net.momirealms.customcrops.api.object;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class OfflineReplaceTask implements Serializable {
|
||||
|
||||
private final String id;
|
||||
private final ItemType itemType;
|
||||
private final ItemMode itemMode;
|
||||
|
||||
public OfflineReplaceTask(String id, ItemType itemType, ItemMode itemMode) {
|
||||
this.id = id;
|
||||
this.itemMode = itemMode;
|
||||
this.itemType = itemType;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public ItemMode getItemMode() {
|
||||
return itemMode;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return itemType;
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,7 @@ public class ConfigManager extends Function {
|
||||
public static boolean onlyInLoadedChunks;
|
||||
public static boolean enableCorruptionFixer;
|
||||
public static boolean debugWorld;
|
||||
public static boolean updateDuringLoading;
|
||||
|
||||
private final HashMap<String, Integer> cropPerWorld;
|
||||
private final CustomCrops plugin;
|
||||
@@ -99,15 +100,16 @@ public class ConfigManager extends Function {
|
||||
debugCorruption = config.getBoolean("debug.log-corruption-fixer", false);
|
||||
debugWorld = config.getBoolean("debug.log-world-state", false);
|
||||
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")));
|
||||
loadOptimization(Objects.requireNonNull(config.getConfigurationSection("optimization")));
|
||||
}
|
||||
|
||||
private void loadOptimization(ConfigurationSection section) {
|
||||
enableLimitation = section.getBoolean("limitation.growing-crop-amount.enable", true);
|
||||
maxCropPerChunk = section.getInt("limitation.growing-crop-amount.default", 64);
|
||||
updateDuringLoading = !ConfigManager.onlyInLoadedChunks && section.getBoolean("only-update-during-chunk-loading", false);
|
||||
List<String> worldSettings = section.getStringList("limitation.growing-crop-amount.worlds");
|
||||
for (String setting : worldSettings) {
|
||||
String[] split = setting.split(":", 2);
|
||||
|
||||
@@ -19,6 +19,9 @@ package net.momirealms.customcrops.api.object.condition;
|
||||
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.api.object.ItemMode;
|
||||
import net.momirealms.customcrops.api.object.ItemType;
|
||||
import net.momirealms.customcrops.api.object.OfflineReplaceTask;
|
||||
import net.momirealms.customcrops.api.object.basic.ConfigManager;
|
||||
import net.momirealms.customcrops.api.object.world.SimpleLocation;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
@@ -49,32 +52,36 @@ public class DeathCondition {
|
||||
public void applyDeadModel(SimpleLocation simpleLocation, ItemMode itemMode) {
|
||||
Location location = simpleLocation.getBukkitLocation();
|
||||
if (location == null) return;
|
||||
|
||||
if (location.getWorld().isChunkLoaded(simpleLocation.getX() >> 4, simpleLocation.getZ() >> 4)) {
|
||||
replaceDeadModels(location, itemMode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConfigManager.updateDuringLoading) {
|
||||
CustomCrops.getInstance().getWorldDataManager().addOfflineTask(simpleLocation, new OfflineReplaceTask(dead_model, ItemType.CROP, itemMode));
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture<Chunk> asyncGetChunk = location.getWorld().getChunkAtAsync(location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
if (itemMode == ItemMode.ITEM_FRAME || itemMode == ItemMode.ITEM_DISPLAY) {
|
||||
CompletableFuture<Boolean> loadEntities = asyncGetChunk.thenApply((chunk) -> {
|
||||
chunk.getEntities();
|
||||
return chunk.isEntitiesLoaded();
|
||||
});
|
||||
loadEntities.whenComplete((result, throwable) ->
|
||||
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
|
||||
if (CustomCrops.getInstance().getPlatformInterface().removeCustomItem(location, itemMode)) {
|
||||
if (dead_model != null) {
|
||||
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, dead_model, itemMode);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
}
|
||||
else {
|
||||
asyncGetChunk.whenComplete((result, throwable) ->
|
||||
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
|
||||
if (CustomCrops.getInstance().getPlatformInterface().removeCustomItem(location, itemMode)) {
|
||||
if (dead_model != null) {
|
||||
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, dead_model, itemMode);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
loadEntities.whenComplete((result, throwable) -> replaceDeadModels(location, itemMode));
|
||||
} else {
|
||||
asyncGetChunk.whenComplete((result, throwable) -> replaceDeadModels(location, itemMode));
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceDeadModels(Location location, ItemMode itemMode) {
|
||||
CustomCrops.getInstance().getScheduler().runTask(() -> {
|
||||
if (CustomCrops.getInstance().getPlatformInterface().removeCustomItem(location, itemMode)) {
|
||||
if (dead_model != null) {
|
||||
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, dead_model, itemMode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,8 +58,7 @@ public class Pot implements Serializable {
|
||||
if (water == 0) {
|
||||
this.water = Math.min(getConfig().getMaxStorage(), amount);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.water = Math.min(getConfig().getMaxStorage(), water + amount);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public class PotConfig {
|
||||
return key;
|
||||
}
|
||||
|
||||
public boolean isEnableFertilized() {
|
||||
public boolean enableFertilizedLooks() {
|
||||
return enableFertilized;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
package net.momirealms.customcrops.api.object.world;
|
||||
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.api.customplugin.PlatformInterface;
|
||||
import net.momirealms.customcrops.api.object.OfflineReplaceTask;
|
||||
import net.momirealms.customcrops.api.object.basic.ConfigManager;
|
||||
import net.momirealms.customcrops.api.object.crop.GrowingCrop;
|
||||
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
|
||||
@@ -31,12 +33,8 @@ import org.bukkit.block.data.type.Farmland;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@@ -48,6 +46,7 @@ public class CCChunk implements Serializable {
|
||||
private final ConcurrentHashMap<SimpleLocation, GrowingCrop> growingCropMap;
|
||||
private final ConcurrentHashMap<SimpleLocation, Pot> potMap;
|
||||
private final ConcurrentHashMap<SimpleLocation, Sprinkler> sprinklerMap;
|
||||
private ConcurrentHashMap<SimpleLocation, OfflineReplaceTask> replaceTaskMap;
|
||||
private final Set<SimpleLocation> greenhouseSet;
|
||||
private final Set<SimpleLocation> scarecrowSet;
|
||||
|
||||
@@ -57,6 +56,20 @@ public class CCChunk implements Serializable {
|
||||
this.sprinklerMap = new ConcurrentHashMap<>(16);
|
||||
this.greenhouseSet = Collections.synchronizedSet(new HashSet<>(64));
|
||||
this.scarecrowSet = Collections.synchronizedSet(new HashSet<>(4));
|
||||
this.replaceTaskMap = new ConcurrentHashMap<>(64);
|
||||
}
|
||||
|
||||
@Serial
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
oos.defaultWriteObject();
|
||||
}
|
||||
|
||||
@Serial
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
ois.defaultReadObject();
|
||||
if (replaceTaskMap == null) {
|
||||
replaceTaskMap = new ConcurrentHashMap<>(64);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeCropData(SimpleLocation simpleLocation) {
|
||||
@@ -114,7 +127,7 @@ public class CCChunk implements Serializable {
|
||||
}
|
||||
|
||||
public boolean isUseless() {
|
||||
return growingCropMap.size() == 0 && potMap.size() == 0 && greenhouseSet.size() == 0 && sprinklerMap.size() == 0 && scarecrowSet.size() == 0;
|
||||
return growingCropMap.size() == 0 && potMap.size() == 0 && greenhouseSet.size() == 0 && sprinklerMap.size() == 0 && scarecrowSet.size() == 0 && replaceTaskMap.size() == 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -199,4 +212,39 @@ public class CCChunk implements Serializable {
|
||||
CustomCrops.getInstance().getPlatformInterface().placeNoteBlock(location, replacer);
|
||||
}
|
||||
}
|
||||
|
||||
public void executeReplaceTask() {
|
||||
PlatformInterface platform = CustomCrops.getInstance().getPlatformInterface();
|
||||
for (Map.Entry<SimpleLocation, OfflineReplaceTask> entry : replaceTaskMap.entrySet()) {
|
||||
SimpleLocation simpleLocation = entry.getKey();
|
||||
String id = entry.getValue().getId();
|
||||
if (id == null) {
|
||||
platform.removeCustomItem(entry.getKey().getBukkitLocation(), entry.getValue().getItemMode());
|
||||
continue;
|
||||
}
|
||||
switch (entry.getValue().getItemType()) {
|
||||
case POT -> {
|
||||
Pot pot =getPotData(simpleLocation);
|
||||
if (pot == null) {
|
||||
String blockID = platform.getBlockID(simpleLocation.getBukkitLocation().getBlock());
|
||||
String potKey = CustomCrops.getInstance().getPotManager().getPotKeyByBlockID(blockID);
|
||||
if (potKey == null) continue;
|
||||
pot = new Pot(potKey, null, 0);
|
||||
}
|
||||
changePotModel(simpleLocation, pot);
|
||||
}
|
||||
case CROP -> {
|
||||
Location location = simpleLocation.getBukkitLocation();
|
||||
if (platform.removeCustomItem(location, entry.getValue().getItemMode())) {
|
||||
platform.placeCustomItem(location, id, entry.getValue().getItemMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
replaceTaskMap.clear();
|
||||
}
|
||||
|
||||
public void addReplaceTask(SimpleLocation simpleLocation, OfflineReplaceTask offlineReplaceTask) {
|
||||
replaceTaskMap.put(simpleLocation, offlineReplaceTask);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ package net.momirealms.customcrops.api.object.world;
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.api.object.Function;
|
||||
import net.momirealms.customcrops.api.object.ItemMode;
|
||||
import net.momirealms.customcrops.api.object.ItemType;
|
||||
import net.momirealms.customcrops.api.object.OfflineReplaceTask;
|
||||
import net.momirealms.customcrops.api.object.action.Action;
|
||||
import net.momirealms.customcrops.api.object.action.VariationImpl;
|
||||
import net.momirealms.customcrops.api.object.basic.ConfigManager;
|
||||
@@ -55,15 +57,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class CCWorld extends Function {
|
||||
|
||||
private final String worldName;
|
||||
private final Reference<World> world;
|
||||
private final World world;
|
||||
private final ConcurrentHashMap<ChunkCoordinate, CCChunk> chunkMap;
|
||||
private final ScheduledThreadPoolExecutor schedule;
|
||||
private long currentDay;
|
||||
@@ -86,7 +86,7 @@ public class CCWorld extends Function {
|
||||
this.chunksFolder = ConfigUtils.getFile(world, "chunks");
|
||||
this.dateFile = ConfigUtils.getFile(world, "data.yml");
|
||||
this.corruptedFile = ConfigUtils.getFile(world, "corrupted.yml");
|
||||
this.world = new WeakReference<>(world);
|
||||
this.world = world;
|
||||
this.chunkMap = new ConcurrentHashMap<>(64);
|
||||
this.schedule = new ScheduledThreadPoolExecutor(ConfigManager.corePoolSize);
|
||||
this.schedule.setMaximumPoolSize(ConfigManager.maxPoolSize);
|
||||
@@ -235,13 +235,12 @@ public class CCWorld extends Function {
|
||||
private void scheduleTask() {
|
||||
if (this.timerTask == null) {
|
||||
this.timerTask = plugin.getScheduler().runTaskTimerAsync(() -> {
|
||||
World current = world.get();
|
||||
if (current != null) {
|
||||
if (world != null) {
|
||||
if (ConfigManager.debugScheduler) {
|
||||
Log.info("Queue size: " + schedule.getQueue().size() + " Completed: " + schedule.getCompletedTaskCount());
|
||||
}
|
||||
long day = current.getFullTime() / 24000;
|
||||
long time = current.getTime();
|
||||
long day = world.getFullTime() / 24000;
|
||||
long time = world.getTime();
|
||||
this.tryDayCycleTask(time, day);
|
||||
this.timerTask();
|
||||
} else {
|
||||
@@ -334,27 +333,35 @@ public class CCWorld extends Function {
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public void loadChunk(ChunkCoordinate chunkCoordinate) {
|
||||
if (!ConfigManager.onlyInLoadedChunks) return;
|
||||
File file = new File(chunksFolder, chunkCoordinate.getFileName() + ".ccdata");
|
||||
if (file.exists()) {
|
||||
boolean delete = false;
|
||||
try (FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis)) {
|
||||
CCChunk chunk = (CCChunk) ois.readObject();
|
||||
if (chunk.isUseless()) {
|
||||
delete = true;
|
||||
} else {
|
||||
chunkMap.put(chunkCoordinate, chunk);
|
||||
if (!loadInPoint.contains(chunkCoordinate)) {
|
||||
chunk.scheduleGrowTask(this, -1);
|
||||
if (ConfigManager.onlyInLoadedChunks) {
|
||||
File file = new File(chunksFolder, chunkCoordinate.getFileName() + ".ccdata");
|
||||
if (file.exists()) {
|
||||
boolean delete = false;
|
||||
try (FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis)) {
|
||||
CCChunk chunk = (CCChunk) ois.readObject();
|
||||
if (chunk.isUseless()) {
|
||||
delete = true;
|
||||
} else {
|
||||
chunkMap.put(chunkCoordinate, chunk);
|
||||
if (!loadInPoint.contains(chunkCoordinate)) {
|
||||
chunk.scheduleGrowTask(this, -1);
|
||||
}
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
Log.info("Error at " + file.getAbsolutePath());
|
||||
} finally {
|
||||
if (delete) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
Log.info("Error at " + file.getAbsolutePath());
|
||||
} finally {
|
||||
if (delete) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ConfigManager.updateDuringLoading) {
|
||||
CCChunk chunk = chunkMap.get(chunkCoordinate);
|
||||
if (chunk != null) {
|
||||
chunk.executeReplaceTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -436,55 +443,70 @@ public class CCWorld extends Function {
|
||||
removePotData(simpleLocation);
|
||||
}
|
||||
|
||||
PotConfig potConfig = pot.getConfig();
|
||||
if (wet && fertilizer == null && !potConfig.enableFertilizedLooks()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (world.isChunkLoaded(simpleLocation.getX() >> 4, simpleLocation.getZ() >> 4)) {
|
||||
replacePot(simpleLocation, pot, potConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConfigManager.updateDuringLoading) {
|
||||
addOfflineReplaceTask(simpleLocation, new OfflineReplaceTask(pot.getPotKey(), ItemType.POT, ItemMode.NOTE_BLOCK));
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = simpleLocation.getBukkitLocation();
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PotConfig potConfig = pot.getConfig();
|
||||
if (wet && fertilizer == null && !potConfig.isEnableFertilized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture<Chunk> asyncGetChunk = location.getWorld().getChunkAtAsync(location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
asyncGetChunk.whenComplete((result, throwable) ->
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
Block block = location.getBlock();
|
||||
if (block.getType() == Material.AIR) {
|
||||
removePotData(simpleLocation);
|
||||
return;
|
||||
}
|
||||
String replacer = wet ? potConfig.getWetPot(fertilizer) : potConfig.getDryPot(fertilizer);
|
||||
String id = plugin.getPlatformInterface().getBlockID(block);
|
||||
if (ConfigManager.enableCorruptionFixer && id.equals("NOTE_BLOCK")) {
|
||||
corruptedPot.put(simpleLocation, pot.getPotKey());
|
||||
if (ConfigManager.debugCorruption) AdventureUtils.consoleMessage("[CustomCrops] Corrupted pot found at: " + simpleLocation);
|
||||
//plugin.getPlatformInterface().placeNoteBlock(location, replacer);
|
||||
return;
|
||||
}
|
||||
String potKey = plugin.getPotManager().getPotKeyByBlockID(id);
|
||||
if (potKey == null) {
|
||||
removePotData(simpleLocation);
|
||||
return;
|
||||
}
|
||||
if (!potKey.equals(pot.getPotKey())) {
|
||||
return;
|
||||
}
|
||||
if (ConfigUtils.isVanillaItem(replacer)) {
|
||||
block.setType(Material.valueOf(replacer));
|
||||
if (block.getBlockData() instanceof Farmland farmland && ConfigManager.disableMoistureMechanic) {
|
||||
farmland.setMoisture(wet ? farmland.getMaximumMoisture() : 0);
|
||||
block.setBlockData(farmland);
|
||||
}
|
||||
} else {
|
||||
plugin.getPlatformInterface().placeNoteBlock(location, replacer);
|
||||
}
|
||||
}
|
||||
));
|
||||
asyncGetChunk.whenComplete((result, throwable) -> {
|
||||
replacePot(simpleLocation, pot, potConfig);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void replacePot(SimpleLocation simpleLocation, Pot pot, PotConfig potConfig) {
|
||||
Location location = simpleLocation.getBukkitLocation();
|
||||
assert location != null;
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
Block block = location.getBlock();
|
||||
if (block.getType() == Material.AIR) {
|
||||
removePotData(simpleLocation);
|
||||
return;
|
||||
}
|
||||
String replacer = pot.isWet() ? potConfig.getWetPot(pot.getFertilizer()) : potConfig.getDryPot(pot.getFertilizer());
|
||||
String id = plugin.getPlatformInterface().getBlockID(block);
|
||||
if (ConfigManager.enableCorruptionFixer && id.equals("NOTE_BLOCK")) {
|
||||
corruptedPot.put(simpleLocation, pot.getPotKey());
|
||||
if (ConfigManager.debugCorruption) AdventureUtils.consoleMessage("[CustomCrops] Corrupted pot found at: " + simpleLocation);
|
||||
return;
|
||||
}
|
||||
String potKey = plugin.getPotManager().getPotKeyByBlockID(id);
|
||||
if (potKey == null) {
|
||||
removePotData(simpleLocation);
|
||||
return;
|
||||
}
|
||||
if (!potKey.equals(pot.getPotKey())) {
|
||||
return;
|
||||
}
|
||||
if (ConfigUtils.isVanillaItem(replacer)) {
|
||||
block.setType(Material.valueOf(replacer));
|
||||
if (block.getBlockData() instanceof Farmland farmland && ConfigManager.disableMoistureMechanic) {
|
||||
farmland.setMoisture(pot.isWet() ? farmland.getMaximumMoisture() : 0);
|
||||
block.setBlockData(farmland);
|
||||
}
|
||||
} else {
|
||||
plugin.getPlatformInterface().placeNoteBlock(location, replacer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public class SprinklerCheckTask implements Runnable {
|
||||
|
||||
private final SimpleLocation simpleLocation;
|
||||
@@ -510,12 +532,12 @@ public class CCWorld extends Function {
|
||||
}
|
||||
|
||||
SprinklerAnimation sprinklerAnimation = sprinklerConfig.getSprinklerAnimation();
|
||||
Location location = simpleLocation.getBukkitLocation();
|
||||
if (location != null && sprinklerAnimation != null) {
|
||||
|
||||
if (world.isChunkLoaded(simpleLocation.getX() >> 4, simpleLocation.getZ() >> 4) && 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());
|
||||
FakeEntityUtils.playWaterAnimation(player, simpleLocation.getBukkitLocation().add(0.5, sprinklerAnimation.offset(), 0.5), sprinklerAnimation.id(), sprinklerAnimation.duration(), sprinklerAnimation.itemMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -549,50 +571,60 @@ public class CCWorld extends Function {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Location location = simpleLocation.getBukkitLocation();
|
||||
if (location == null) return;
|
||||
CompletableFuture<Chunk> asyncGetChunk = location.getWorld().getChunkAtAsync(location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
asyncGetChunk.whenComplete((result, throwable) ->
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
String blockID = plugin.getPlatformInterface().getBlockID(location.getBlock());
|
||||
String potKey = plugin.getPotManager().getPotKeyByBlockID(blockID);
|
||||
if (potKey != null) {
|
||||
if (whitelist != null) {
|
||||
for (String pot : whitelist) {
|
||||
if (pot.equals(potKey)) {
|
||||
addWaterToPot(simpleLocation, amount, potKey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (world.isChunkLoaded(simpleLocation.getX() >> 4, simpleLocation.getZ() >> 4)) {
|
||||
replacePot(simpleLocation, amount, whitelist);
|
||||
return;
|
||||
}
|
||||
|
||||
Pot pot = getPotData(simpleLocation);
|
||||
if (ConfigManager.updateDuringLoading && pot != null) {
|
||||
pot.addWater(amount);
|
||||
addOfflineReplaceTask(simpleLocation, new OfflineReplaceTask("unknown", ItemType.POT, ItemMode.NOTE_BLOCK));
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture<Chunk> asyncGetChunk = world.getChunkAtAsync(simpleLocation.getX() >> 4, simpleLocation.getZ() >> 4);
|
||||
asyncGetChunk.whenComplete((result, throwable) -> replacePot(simpleLocation, amount, whitelist));
|
||||
}
|
||||
}
|
||||
|
||||
private void replacePot(SimpleLocation simpleLocation, int amount, String[] whitelist) {
|
||||
Location location = simpleLocation.getBukkitLocation();
|
||||
assert location != null;
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
String blockID = plugin.getPlatformInterface().getBlockID(location.getBlock());
|
||||
String potKey = plugin.getPotManager().getPotKeyByBlockID(blockID);
|
||||
if (potKey != null) {
|
||||
if (whitelist != null) {
|
||||
for (String pot : whitelist) {
|
||||
if (pot.equals(potKey)) {
|
||||
addWaterToPot(simpleLocation, amount, potKey);
|
||||
}
|
||||
} else if (ConfigManager.enableCorruptionFixer && blockID.equals("NOTE_BLOCK")) {
|
||||
Pot pot = getPotData(simpleLocation);
|
||||
if (pot != null) {
|
||||
// mark it as corrupted
|
||||
potKey = pot.getPotKey();
|
||||
if (whitelist == null) {
|
||||
pot.addWater(amount);
|
||||
} else {
|
||||
for (String potID : whitelist) {
|
||||
if (potID.equals(potKey)) {
|
||||
pot.addWater(amount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
corruptedPot.put(simpleLocation, potKey);
|
||||
if (ConfigManager.debugCorruption) AdventureUtils.consoleMessage("[CustomCrops] Corrupted pot found at: " + simpleLocation);
|
||||
// only custom blocks would corrupt
|
||||
// so it's not necessary to check if the pot is a vanilla block
|
||||
// String replacer = pot.isWet() ? pot.getConfig().getWetPot(pot.getFertilizer()) : pot.getConfig().getDryPot(pot.getFertilizer());
|
||||
// plugin.getPlatformInterface().placeNoteBlock(location, replacer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addWaterToPot(simpleLocation, amount, potKey);
|
||||
}
|
||||
));
|
||||
}
|
||||
} else if (ConfigManager.enableCorruptionFixer && blockID.equals("NOTE_BLOCK")) {
|
||||
Pot pot = getPotData(simpleLocation);
|
||||
if (pot != null) {
|
||||
potKey = pot.getPotKey();
|
||||
if (whitelist == null) {
|
||||
pot.addWater(amount);
|
||||
} else {
|
||||
for (String potID : whitelist) {
|
||||
if (potID.equals(potKey)) {
|
||||
pot.addWater(amount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
corruptedPot.put(simpleLocation, potKey);
|
||||
if (ConfigManager.debugCorruption) AdventureUtils.consoleMessage("[CustomCrops] Corrupted pot found at: " + simpleLocation);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public class CropCheckTask implements Runnable {
|
||||
@@ -689,49 +721,68 @@ public class CCWorld extends Function {
|
||||
String finalNextModel = nextModel;
|
||||
if (finalNextModel == null || location == null) return;
|
||||
|
||||
if (world.isChunkLoaded(location.getBlockX() >> 4, location.getBlockZ() >> 4)) {
|
||||
switch (itemMode) {
|
||||
case ITEM_FRAME -> replaceItemFrameCrop(location, finalNextModel, cropConfig.isRotationEnabled());
|
||||
case ITEM_DISPLAY -> replaceItemDisplayCrop(location, finalNextModel, cropConfig.isRotationEnabled());
|
||||
case TRIPWIRE -> replaceTripwireCrop(location, finalNextModel);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConfigManager.updateDuringLoading) {
|
||||
addOfflineReplaceTask(simpleLocation, new OfflineReplaceTask(finalNextModel, ItemType.CROP, itemMode));
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture<Chunk> asyncGetChunk = location.getWorld().getChunkAtAsync(location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
if (itemMode == ItemMode.ITEM_FRAME) {
|
||||
CompletableFuture<Boolean> loadEntities = asyncGetChunk.thenApply((chunk) -> {
|
||||
chunk.getEntities();
|
||||
return chunk.isEntitiesLoaded();
|
||||
});
|
||||
loadEntities.whenComplete((result, throwable) ->
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
if (plugin.getPlatformInterface().removeCustomItem(location, itemMode)) {
|
||||
ItemFrame itemFrame = plugin.getPlatformInterface().placeItemFrame(location, finalNextModel);
|
||||
if (itemFrame != null && cropConfig.isRotationEnabled()) itemFrame.setRotation(RotationUtils.getRandomRotation());
|
||||
} else {
|
||||
removeCropData(simpleLocation);
|
||||
}
|
||||
}));
|
||||
loadEntities.whenComplete((result, throwable) -> replaceItemFrameCrop(location, finalNextModel, cropConfig.isRotationEnabled()));
|
||||
} else if (itemMode == ItemMode.ITEM_DISPLAY) {
|
||||
CompletableFuture<Boolean> loadEntities = asyncGetChunk.thenApply((chunk) -> {
|
||||
chunk.getEntities();
|
||||
return chunk.isEntitiesLoaded();
|
||||
});
|
||||
loadEntities.whenComplete((result, throwable) ->
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
if (plugin.getPlatformInterface().removeCustomItem(location, itemMode)) {
|
||||
ItemDisplay itemDisplay = plugin.getPlatformInterface().placeItemDisplay(location, finalNextModel);
|
||||
if (itemDisplay != null && cropConfig.isRotationEnabled()) itemDisplay.setRotation(RotationUtils.getRandomFloatRotation(), itemDisplay.getLocation().getPitch());
|
||||
} else {
|
||||
removeCropData(simpleLocation);
|
||||
}
|
||||
}));
|
||||
loadEntities.whenComplete((result, throwable) -> replaceItemDisplayCrop(location, finalNextModel, cropConfig.isRotationEnabled()));
|
||||
} else {
|
||||
asyncGetChunk.whenComplete((result, throwable) ->
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
if (plugin.getPlatformInterface().removeCustomItem(location, itemMode)) {
|
||||
plugin.getPlatformInterface().placeTripWire(location, finalNextModel);
|
||||
} else {
|
||||
removeCropData(simpleLocation);
|
||||
}
|
||||
}));
|
||||
asyncGetChunk.whenComplete((result, throwable) -> replaceTripwireCrop(location, finalNextModel));
|
||||
}
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world.get();
|
||||
private void replaceItemFrameCrop(Location location, String model, boolean rotation) {
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
if (plugin.getPlatformInterface().removeCustomItem(location, ItemMode.ITEM_FRAME)) {
|
||||
ItemFrame itemFrame = plugin.getPlatformInterface().placeItemFrame(location, model);
|
||||
if (itemFrame != null && rotation) itemFrame.setRotation(RotationUtils.getRandomRotation());
|
||||
} else {
|
||||
removeCropData(SimpleLocation.getByBukkitLocation(location));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void replaceItemDisplayCrop(Location location, String model, boolean rotation) {
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
if (plugin.getPlatformInterface().removeCustomItem(location, ItemMode.ITEM_DISPLAY)) {
|
||||
ItemDisplay itemDisplay = plugin.getPlatformInterface().placeItemDisplay(location, model);
|
||||
if (itemDisplay != null && rotation) itemDisplay.setRotation(RotationUtils.getRandomFloatRotation(), itemDisplay.getLocation().getPitch());
|
||||
} else {
|
||||
removeCropData(SimpleLocation.getByBukkitLocation(location));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void replaceTripwireCrop(Location location, String model) {
|
||||
plugin.getScheduler().runTask(() -> {
|
||||
if (plugin.getPlatformInterface().removeCustomItem(location, ItemMode.TRIPWIRE)) {
|
||||
plugin.getPlatformInterface().placeTripWire(location, model);
|
||||
} else {
|
||||
removeCropData(SimpleLocation.getByBukkitLocation(location));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removePotData(SimpleLocation simpleLocation) {
|
||||
@@ -884,8 +935,9 @@ public class CCWorld extends Function {
|
||||
}
|
||||
|
||||
public CCChunk createNewChunk(SimpleLocation simpleLocation) {
|
||||
ChunkCoordinate chunkCoordinate = simpleLocation.getChunkCoordinate();
|
||||
CCChunk newChunk = new CCChunk();
|
||||
chunkMap.put(simpleLocation.getChunkCoordinate(), newChunk);
|
||||
chunkMap.put(chunkCoordinate, newChunk);
|
||||
return newChunk;
|
||||
}
|
||||
|
||||
@@ -913,6 +965,16 @@ public class CCWorld extends Function {
|
||||
});
|
||||
}
|
||||
|
||||
public void addOfflineReplaceTask(SimpleLocation simpleLocation, OfflineReplaceTask offlineReplaceTask) {
|
||||
CCChunk chunk = chunkMap.get(simpleLocation.getChunkCoordinate());
|
||||
if (chunk != null) {
|
||||
chunk.addReplaceTask(simpleLocation, offlineReplaceTask);
|
||||
return;
|
||||
}
|
||||
chunk = createNewChunk(simpleLocation);
|
||||
chunk.addReplaceTask(simpleLocation, offlineReplaceTask);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getCorruptedPotOriginalKey(SimpleLocation simpleLocation) {
|
||||
return corruptedPot.get(simpleLocation);
|
||||
|
||||
@@ -19,6 +19,7 @@ package net.momirealms.customcrops.api.object.world;
|
||||
|
||||
import net.momirealms.customcrops.CustomCrops;
|
||||
import net.momirealms.customcrops.api.object.Function;
|
||||
import net.momirealms.customcrops.api.object.OfflineReplaceTask;
|
||||
import net.momirealms.customcrops.api.object.basic.ConfigManager;
|
||||
import net.momirealms.customcrops.api.object.crop.GrowingCrop;
|
||||
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
|
||||
@@ -228,6 +229,13 @@ public class WorldDataManager extends Function {
|
||||
}
|
||||
}
|
||||
|
||||
public void addOfflineTask(SimpleLocation simpleLocation, OfflineReplaceTask offlineReplaceTask) {
|
||||
CCWorld ccWorld = worldMap.get(simpleLocation.getWorldName());
|
||||
if (ccWorld != null) {
|
||||
ccWorld.addOfflineReplaceTask(simpleLocation, offlineReplaceTask);
|
||||
}
|
||||
}
|
||||
|
||||
public void addWaterToSprinkler(SimpleLocation simpleLocation, int add, SprinklerConfig sprinklerConfig) {
|
||||
Sprinkler sprinkler = getSprinklerData(simpleLocation);
|
||||
if (sprinkler != null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Don't change
|
||||
config-version: '33'
|
||||
config-version: '34'
|
||||
# BStats
|
||||
metrics: true
|
||||
# Language: english / spanish / chinese / turkish / russian
|
||||
@@ -67,6 +67,12 @@ optimization:
|
||||
# 指定世界的设置
|
||||
worlds:
|
||||
- world:64
|
||||
# Experimental option (Only works when only-work-in-loaded-chunks is false)
|
||||
# This option would make the plugin no longer invoke the unloaded chunks to replace crop models/pots
|
||||
# Crops/Pots would only be updated during the chunk loading
|
||||
# 实验性选项,启用以后农作物/种植盆的模型只会在区块加载时得到更新,不再异步加载区块替换模型
|
||||
# 此选项仅在only-work-in-loaded-chunks为false时候生效
|
||||
only-update-during-chunk-loading: false
|
||||
|
||||
mechanics:
|
||||
# Does the system only work in loaded chunks (Requires you to stop the server before changing this setting)
|
||||
@@ -74,6 +80,7 @@ mechanics:
|
||||
only-work-in-loaded-chunks: true
|
||||
# 17/2/1 = 85%/10%/5%
|
||||
# 2/2/1 = 40%/40%/20%
|
||||
# You can customize more ranks like x/x/x/x/x
|
||||
default-quality-ratio: 17/2/1
|
||||
# Season mechanic
|
||||
# 季节机制
|
||||
|
||||
Reference in New Issue
Block a user