9
0
mirror of https://github.com/Xiao-MoMi/Custom-Crops.git synced 2025-12-29 11:59:15 +00:00
This commit is contained in:
XiaoMoMi
2023-06-27 00:06:45 +08:00
parent d019354c23
commit 9e5117f401
12 changed files with 340 additions and 176 deletions

View File

@@ -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')

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);
}
}
});
}
}

View File

@@ -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;
}

View File

@@ -110,7 +110,7 @@ public class PotConfig {
return key;
}
public boolean isEnableFertilized() {
public boolean enableFertilizedLooks() {
return enableFertilized;
}
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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
# 季节机制