9
0
mirror of https://github.com/Xiao-MoMi/Custom-Crops.git synced 2025-12-26 18:39:17 +00:00
This commit is contained in:
Xiao-MoMi
2023-05-06 14:10:43 +08:00
parent c1a14bf18f
commit 57253a6fbb
12 changed files with 177 additions and 75 deletions

View File

@@ -65,6 +65,7 @@ public class ConfigManager extends Function {
public static int intervalWork;
public static boolean disableMoistureMechanic;
public static boolean preventTrampling;
public static boolean onlyInLoadedChunks;
private final HashMap<String, Integer> cropPerWorld;
private final CustomCrops plugin;
@@ -72,6 +73,8 @@ public class ConfigManager extends Function {
public ConfigManager(CustomCrops plugin) {
this.plugin = plugin;
this.cropPerWorld = new HashMap<>();
YamlConfiguration config = ConfigUtils.getConfig("config.yml");
onlyInLoadedChunks = config.getBoolean("mechanics.only-work-in-loaded-chunks", false);
}
@Override

View File

@@ -0,0 +1,29 @@
package net.momirealms.customcrops.api.object.condition;
import net.momirealms.customcrops.api.object.world.SimpleLocation;
import org.bukkit.World;
public class Weather implements Condition {
private final String[] weathers;
public Weather(String[] weathers) {
this.weathers = weathers;
}
@Override
public boolean isMet(SimpleLocation simpleLocation) {
World world = simpleLocation.getBukkitWorld();
if (world == null) return false;
String currentWeather;
if (world.isThundering()) currentWeather = "thunder";
else if (world.isClearWeather()) currentWeather = "clear";
else currentWeather = "rain";
for (String weather : weathers) {
if (weather.equals(currentWeather)) {
return true;
}
}
return false;
}
}

View File

@@ -24,9 +24,9 @@ import java.util.List;
public class WeatherImpl extends AbstractRequirement implements Requirement {
private final List<String> weathers;
private final String[] weathers;
public WeatherImpl(@Nullable String[] msg, List<String> weathers) {
public WeatherImpl(@Nullable String[] msg, String[] weathers) {
super(msg);
this.weathers = weathers;
}
@@ -39,7 +39,7 @@ public class WeatherImpl extends AbstractRequirement implements Requirement {
else if (world.isClearWeather()) currentWeather = "clear";
else currentWeather = "rain";
for (String weather : weathers) {
if (weather.equalsIgnoreCase(currentWeather)) {
if (weather.equals(currentWeather)) {
return true;
}
}

View File

@@ -180,22 +180,23 @@ public class CCChunk implements Serializable {
public void scheduleGrowTask(CCWorld ccWorld) {
Random randomGenerator = ThreadLocalRandom.current();
int delay = ConfigManager.pointGainInterval * 1000;
for (SimpleLocation simpleLocation : growingCropMap.keySet()) {
ccWorld.pushCropTask(simpleLocation, randomGenerator.nextInt(ConfigManager.pointGainInterval));
ccWorld.pushCropTask(simpleLocation, randomGenerator.nextInt(delay));
}
}
public void scheduleSprinklerTask(CCWorld ccWorld) {
public void scheduleSprinklerTask(CCWorld ccWorld, int startDelay) {
Random randomGenerator = ThreadLocalRandom.current();
int delay = Math.min(30, ConfigManager.pointGainInterval);
int delay = (Math.min(30, ConfigManager.pointGainInterval) + startDelay) * 1000;
for (SimpleLocation simpleLocation : sprinklerMap.keySet()) {
ccWorld.pushSprinklerTask(simpleLocation, randomGenerator.nextInt(delay));
}
}
public void scheduleConsumeTask(CCWorld ccWorld) {
public void scheduleConsumeTask(CCWorld ccWorld, int startDelay) {
Random randomGenerator = ThreadLocalRandom.current();
int delay = Math.min(30, ConfigManager.pointGainInterval);
int delay = (Math.min(30, ConfigManager.pointGainInterval) + startDelay) * 1000;
for (SimpleLocation simpleLocation : potMap.keySet()) {
ccWorld.pushConsumeTask(simpleLocation, randomGenerator.nextInt(delay));
}

View File

@@ -48,7 +48,6 @@ import org.bukkit.block.Block;
import org.bukkit.block.data.type.Farmland;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.block.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -74,6 +73,7 @@ public class CCWorld extends Function {
private int workCounter;
private int consumeCounter;
private final HashSet<SimpleLocation> plantToday;
private File chunks_folder;
public CCWorld(World world) {
this.world = new WeakReference<>(world);
@@ -90,11 +90,25 @@ public class CCWorld extends Function {
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
public void init() {
File chunks_folder = ConfigUtils.getChunkFolder(worldName);
loadDateData();
if (!ConfigManager.onlyInLoadedChunks) {
loadAllChunkData();
}
}
@Override
public void disable() {
closePool();
saveDateData();
saveAllChunkData();
CustomCrops.getInstance().getSeasonManager().unloadSeasonData(worldName);
}
public void loadAllChunkData() {
chunks_folder = ConfigUtils.getChunkFolder(worldName);
if (!chunks_folder.exists()) chunks_folder.mkdirs();
File[] data_files = chunks_folder.listFiles();
if (data_files == null) return;
List<File> outdated = new ArrayList<>();
for (File file : data_files) {
ChunkCoordinate chunkCoordinate = ChunkCoordinate.getByString(file.getName().substring(0, file.getName().length() - 7));
@@ -111,11 +125,12 @@ public class CCWorld extends Function {
outdated.add(file);
}
}
for (File file : outdated) {
file.delete();
}
}
public void loadDateData() {
YamlConfiguration dataFile;
if (ConfigManager.worldFolderPath.equals("")) {
dataFile = ConfigUtils.readData(new File(CustomCrops.getInstance().getDataFolder().getParentFile().getParentFile(), worldName + File.separator + "customcrops" + File.separator + "data.yml"));
@@ -134,18 +149,8 @@ public class CCWorld extends Function {
this.current_day = dataFile.getLong("day", 0);
}
@Override
public void disable() {
closePool();
saveCrop();
saveDate();
CustomCrops.getInstance().getSeasonManager().unloadSeasonData(worldName);
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public void saveCrop() {
File chunks_folder = ConfigUtils.getChunkFolder(worldName);
if (!chunks_folder.exists()) chunks_folder.mkdirs();
public void saveAllChunkData() {
for (Map.Entry<ChunkCoordinate, CCChunk> entry : chunkMap.entrySet()) {
ChunkCoordinate chunkCoordinate = entry.getKey();
CCChunk chunk = entry.getValue();
@@ -163,7 +168,7 @@ public class CCWorld extends Function {
}
}
public void saveDate() {
public void saveDateData() {
YamlConfiguration dataFile = new YamlConfiguration();
if (ConfigManager.enableSeason && !ConfigManager.rsHook) {
SeasonData seasonData = CustomCrops.getInstance().getSeasonManager().getSeasonData(worldName);
@@ -191,28 +196,29 @@ public class CCWorld extends Function {
this.scheduleTask();
}
public void unload() {
if (this.timerTask != null) {
this.timerTask.cancel(false);
this.timerTask = null;
}
}
private void scheduleTask() {
if (this.timerTask == null) {
this.timerTask = CustomCrops.getInstance().getScheduler().runTaskTimerAsync(() -> {
World current = world.get();
if (current != null) {
if (ConfigManager.debug) {
Log.info("Queue size: " + schedule.getQueue().size() + " Completed: " + schedule.getCompletedTaskCount());
}
long day = current.getFullTime() / 24000;
long time = current.getTime();
this.tryDayCycleTask(time, day);
this.tryScheduleGrow();
this.timerTask();
}
else {
AdventureUtils.consoleMessage("<red>[CustomCrops] World: " + worldName + " unloaded unexpectedly. Shutdown the schedule.");
this.schedule.shutdown();
}
}, 1000, 1000L);
}
@@ -230,13 +236,13 @@ public class CCWorld extends Function {
if (cacheTimer <= 0) {
if (ConfigManager.debug) Log.info("== Save cache ==");
cacheTimer = ConfigManager.cacheSaveInterval;
schedule.execute(this::saveDate);
schedule.execute(this::saveCrop);
schedule.execute(this::saveDateData);
schedule.execute(this::saveAllChunkData);
}
}
}
private void tryScheduleGrow() {
private void timerTask() {
pointTimer--;
if (pointTimer <= 0) {
pointTimer = ConfigManager.pointGainInterval;
@@ -252,7 +258,6 @@ public class CCWorld extends Function {
schedule.getQueue().clear();
if (ConfigManager.debug) Log.info("== Clear queue ==");
}
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleGrowTask(this);
}
@@ -262,37 +267,70 @@ public class CCWorld extends Function {
if (consumeCounter <= 0) {
consumeCounter = ConfigManager.intervalConsume;
if (ConfigManager.debug) Log.info("== Consume time ==");
scheduleConsumeTask();
scheduleConsumeTask(0);
}
if (workCounter <= 0) {
workCounter = ConfigManager.intervalWork;
if (ConfigManager.debug) Log.info("== Work time ==");
scheduleSprinklerWork();
scheduleSprinklerWork(Math.min(30, ConfigManager.pointGainInterval));
}
}
}
public void unload() {
if (this.timerTask != null) {
this.timerTask.cancel(false);
this.timerTask = null;
}
}
private void closePool() {
this.schedule.shutdown();
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public void unloadChunk(ChunkCoordinate chunkCoordinate) {
CCChunk chunk = chunkMap.remove(chunkCoordinate);
if (chunk != null) {
File file = new File(chunks_folder, chunkCoordinate.getFileName() + ".ccdata");
if (chunk.isUseless() && file.exists()) {
file.delete();
return;
}
try (FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(chunk);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public void loadChunk(ChunkCoordinate chunkCoordinate) {
File file = new File(chunks_folder, 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);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
Log.info("Error at " + file.getAbsolutePath());
} finally {
if (delete) {
file.delete();
}
}
}
}
public void pushCropTask(SimpleLocation simpleLocation, int delay) {
schedule.schedule(new CropCheckTask(simpleLocation), delay, TimeUnit.SECONDS);
schedule.schedule(new CropCheckTask(simpleLocation), delay, TimeUnit.MILLISECONDS);
}
public void pushSprinklerTask(SimpleLocation simpleLocation, int delay) {
schedule.schedule(new SprinklerCheckTask(simpleLocation), delay, TimeUnit.SECONDS);
schedule.schedule(new SprinklerCheckTask(simpleLocation), delay, TimeUnit.MILLISECONDS);
}
public void pushConsumeTask(SimpleLocation simpleLocation, int delay) {
schedule.schedule(new ConsumeCheckTask(simpleLocation), delay, TimeUnit.SECONDS);
schedule.schedule(new ConsumeCheckTask(simpleLocation), delay, TimeUnit.MILLISECONDS);
}
public class ConsumeCheckTask implements Runnable {
@@ -487,22 +525,22 @@ public class CCWorld extends Function {
Location location = simpleLocation.getBukkitLocation();
String finalNextModel = nextModel;
if (finalNextModel == null || location == null) 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)) {
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, finalNextModel, itemMode);
} else {
removeCropData(simpleLocation);
}
return null;
});
});
loadEntities.whenComplete((result, throwable) ->
CustomCrops.getInstance().getScheduler().callSyncMethod(() -> {
if (CustomCrops.getInstance().getPlatformInterface().removeCustomItem(location, itemMode)) {
CustomCrops.getInstance().getPlatformInterface().placeCustomItem(location, finalNextModel, itemMode);
} else {
removeCropData(simpleLocation);
}
return null;
}));
}
else {
asyncGetChunk.whenComplete((result, throwable) ->
@@ -517,10 +555,6 @@ public class CCWorld extends Function {
}
}
public String getWorldName() {
return worldName;
}
public World getWorld() {
return world.get();
}
@@ -553,7 +587,7 @@ public class CCWorld extends Function {
if (plantToday.contains(simpleLocation)) {
return;
}
pushCropTask(simpleLocation, ThreadLocalRandom.current().nextInt(ConfigManager.pointGainInterval));
pushCropTask(simpleLocation, ThreadLocalRandom.current().nextInt(ConfigManager.pointGainInterval * 1000));
plantToday.add(simpleLocation);
}
@@ -680,19 +714,19 @@ public class CCWorld extends Function {
return newChunk;
}
public void scheduleSprinklerWork() {
public void scheduleSprinklerWork(int delay) {
schedule.execute(() -> {
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleSprinklerTask(this);
chunk.scheduleSprinklerTask(this, delay);
}
});
}
public void scheduleConsumeTask() {
schedule.schedule(() -> {
public void scheduleConsumeTask(int delay) {
schedule.execute(() -> {
for (CCChunk chunk : chunkMap.values()) {
chunk.scheduleConsumeTask(this);
chunk.scheduleConsumeTask(this, delay);
}
}, 0, TimeUnit.SECONDS);
});
}
}

View File

@@ -26,6 +26,7 @@ import net.momirealms.customcrops.api.object.pot.Pot;
import net.momirealms.customcrops.api.object.sprinkler.Sprinkler;
import net.momirealms.customcrops.api.object.sprinkler.SprinklerConfig;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.Nullable;
@@ -247,4 +248,18 @@ public class WorldDataManager extends Function {
public CCWorld getWorld(String world) {
return worldMap.get(world);
}
public void loadChunk(Chunk chunk, World world) {
CCWorld ccWorld = worldMap.get(world.getName());
if (ccWorld != null) {
ccWorld.loadChunk(new ChunkCoordinate(chunk.getX(), chunk.getZ()));
}
}
public void unloadChunk(Chunk chunk, World world) {
CCWorld ccWorld = worldMap.get(world.getName());
if (ccWorld != null) {
ccWorld.unloadChunk(new ChunkCoordinate(chunk.getX(), chunk.getZ()));
}
}
}

View File

@@ -17,8 +17,11 @@
package net.momirealms.customcrops.api.object.world;
import net.momirealms.customcrops.api.object.basic.ConfigManager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
@@ -31,12 +34,24 @@ public class WorldListener implements Listener {
}
@EventHandler
public void onChunkLoad(WorldLoadEvent event) {
public void onWorldLoad(WorldLoadEvent event) {
worldManager.loadWorld(event.getWorld());
}
@EventHandler
public void onChunkUnload(WorldUnloadEvent event) {
public void onWorldUnload(WorldUnloadEvent event) {
worldManager.unloadWorld(event.getWorld());
}
@EventHandler
public void onChunkLoad(ChunkLoadEvent event) {
if (!ConfigManager.onlyInLoadedChunks || event.isNewChunk()) return;
worldManager.loadChunk(event.getChunk(), event.getWorld());
}
@EventHandler
public void onChunkUnload(ChunkUnloadEvent event) {
if (!ConfigManager.onlyInLoadedChunks) return;
worldManager.unloadChunk(event.getChunk(), event.getWorld());
}
}

View File

@@ -186,6 +186,7 @@ public class ConfigUtils {
}
case "crow_attack" -> conditions.add(new CrowAttack(map2.getDouble("value.chance"), map2.getString("value.fly-model"), map2.getString("value.stand-model")));
case "random" -> conditions.add(new Random(map2.getDouble("value")));
case "weather" -> conditions.add(new Weather(map2.getStringList("value").toArray(new String[0])));
}
}
}
@@ -205,7 +206,7 @@ public class ConfigUtils {
String[] msg = innerSec.getStringList("message").size() == 0 ? (innerSec.getString("message") == null ? null : new String[]{innerSec.getString("message")}) : innerSec.getStringList("message").toArray(new String[0]);
switch (type) {
case "biome" -> requirements.add(new BiomeImpl(msg, new HashSet<>(innerSec.getStringList("value"))));
case "weather" -> requirements.add(new WeatherImpl(msg, innerSec.getStringList("value")));
case "weather" -> requirements.add(new WeatherImpl(msg, innerSec.getStringList("value").toArray(new String[0])));
case "ypos" -> requirements.add(new YPosImpl(msg, innerSec.getStringList("value")));
case "season" -> {
if (!ConfigManager.enableSeason) continue;

View File

@@ -50,7 +50,7 @@ public class ConsumeTaskCommand extends AbstractSubCommand {
CustomCrops.getInstance().getScheduler().runTaskAsync(() -> {
CCWorld ccworld = CustomCrops.getInstance().getWorldDataManager().getWorld(args.get(0));
if (ccworld != null) {
ccworld.scheduleConsumeTask();
ccworld.scheduleConsumeTask(0);
}
});
return true;

View File

@@ -50,7 +50,7 @@ public class SprinklerWorkCommand extends AbstractSubCommand {
CustomCrops.getInstance().getScheduler().runTaskAsync(() -> {
CCWorld ccworld = CustomCrops.getInstance().getWorldDataManager().getWorld(args.get(0));
if (ccworld != null) {
ccworld.scheduleSprinklerWork();
ccworld.scheduleSprinklerWork(0);
}
});
return true;

View File

@@ -1,5 +1,5 @@
# Don't change
config-version: '29'
config-version: '30'
# BStats
metrics: true
# Language: english / spanish / chinese / turkish
@@ -68,6 +68,10 @@ optimization:
- world:64
mechanics:
# Does the system only work in loaded chunks (Requires you to stop the server before changing this setting)
# 插件是否只在加载中的区块工作 (需要关闭服务器再设置此项)
only-work-in-loaded-chunks: false
# 17/2/1 = 85%/10%/5%
# 2/2/1 = 40%/40%/20%
default-quality-ratio: 17/2/1