9
0
mirror of https://github.com/Xiao-MoMi/Custom-Crops.git synced 2025-12-22 16:39:36 +00:00

region file

This commit is contained in:
XiaoMoMi
2024-03-18 05:05:56 +08:00
parent 0ce4d5a836
commit 68585d124a
26 changed files with 792 additions and 196 deletions

View File

@@ -133,7 +133,9 @@ public interface WorldManager extends Reloadable {
void handleChunkUnload(Chunk bukkitChunk); void handleChunkUnload(Chunk bukkitChunk);
void saveChunkToFile(CustomCropsChunk chunk); void saveChunkToCachedRegion(CustomCropsChunk chunk);
void saveRegionToFile(CustomCropsRegion region);
void removeGlassAt(@NotNull SimpleLocation location); void removeGlassAt(@NotNull SimpleLocation location);
@@ -142,4 +144,6 @@ public interface WorldManager extends Reloadable {
CustomCropsBlock removeAnythingAt(SimpleLocation location); CustomCropsBlock removeAnythingAt(SimpleLocation location);
AbstractWorldAdaptor getWorldAdaptor(); AbstractWorldAdaptor getWorldAdaptor();
void saveInfoData(CustomCropsWorld customCropsWorld);
} }

View File

@@ -56,4 +56,6 @@ public interface Pot extends KeyItem {
String getBlockState(boolean water, FertilizerType type); String getBlockState(boolean water, FertilizerType type);
boolean isVanillaBlock(); boolean isVanillaBlock();
boolean isWetPot(String id);
} }

View File

@@ -19,12 +19,14 @@ package net.momirealms.customcrops.api.mechanic.world;
import net.momirealms.customcrops.api.manager.WorldManager; import net.momirealms.customcrops.api.manager.WorldManager;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsRegion;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
public abstract class AbstractWorldAdaptor implements Listener { public abstract class AbstractWorldAdaptor implements Listener {
public static final int version = 1; public static final int chunkVersion = 1;
public static final int regionVersion = 1;
protected WorldManager worldManager; protected WorldManager worldManager;
public AbstractWorldAdaptor(WorldManager worldManager) { public AbstractWorldAdaptor(WorldManager worldManager) {
@@ -35,9 +37,13 @@ public abstract class AbstractWorldAdaptor implements Listener {
public abstract void init(CustomCropsWorld customCropsWorld); public abstract void init(CustomCropsWorld customCropsWorld);
public abstract void loadDynamicData(CustomCropsWorld customCropsWorld, ChunkCoordinate chunkCoordinate); public abstract void loadChunkData(CustomCropsWorld customCropsWorld, ChunkPos chunkPos);
public abstract void unloadDynamicData(CustomCropsWorld customCropsWorld, ChunkCoordinate chunkCoordinate); public abstract void unloadChunkData(CustomCropsWorld customCropsWorld, ChunkPos chunkPos);
public abstract void saveDynamicData(CustomCropsWorld ccWorld, CustomCropsChunk chunk); public abstract void saveChunkToCachedRegion(CustomCropsChunk customCropsChunk);
public abstract void saveRegion(CustomCropsRegion customCropsRegion);
public abstract void saveInfoData(CustomCropsWorld customCropsWorld);
} }

View File

@@ -35,7 +35,7 @@ public class BlockPos {
return new BlockPos(location.getX() % 16, location.getY(), location.getZ() % 16); return new BlockPos(location.getX() % 16, location.getY(), location.getZ() % 16);
} }
public SimpleLocation getLocation(String world, ChunkCoordinate coordinate) { public SimpleLocation getLocation(String world, ChunkPos coordinate) {
return new SimpleLocation(world, coordinate.x() * 16 + getX(), getY(), coordinate.z() * 16 + getZ()); return new SimpleLocation(world, coordinate.x() * 16 + getX(), getY(), coordinate.z() * 16 + getZ());
} }

View File

@@ -20,20 +20,18 @@ package net.momirealms.customcrops.api.mechanic.world;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public record ChunkCoordinate(int x, int z) { public record ChunkPos(int x, int z) {
private static final ChunkCoordinate empty = new ChunkCoordinate(0, 0); public static ChunkPos of(int x, int z) {
return new ChunkPos(x, z);
public static ChunkCoordinate of(int x, int z) {
return new ChunkCoordinate(x, z);
} }
public static ChunkCoordinate getByString(String coordinate) { public static ChunkPos getByString(String coordinate) {
String[] split = coordinate.split(",", 2); String[] split = coordinate.split(",", 2);
try { try {
int x = Integer.parseInt(split[0]); int x = Integer.parseInt(split[0]);
int z = Integer.parseInt(split[1]); int z = Integer.parseInt(split[1]);
return new ChunkCoordinate(x, z); return new ChunkPos(x, z);
} }
catch (NumberFormatException e) { catch (NumberFormatException e) {
e.printStackTrace(); e.printStackTrace();
@@ -55,7 +53,7 @@ public record ChunkCoordinate(int x, int z) {
if (getClass() != obj.getClass()) { if (getClass() != obj.getClass()) {
return false; return false;
} }
final ChunkCoordinate other = (ChunkCoordinate) obj; final ChunkPos other = (ChunkPos) obj;
if (this.x != other.x) { if (this.x != other.x) {
return false; return false;
} }
@@ -66,13 +64,22 @@ public record ChunkCoordinate(int x, int z) {
} }
@NotNull @NotNull
public static ChunkCoordinate getByBukkitChunk(@NotNull Chunk chunk) { public RegionPos getRegionPos() {
return new ChunkCoordinate(chunk.getX(), chunk.getZ()); return RegionPos.getByChunkPos(this);
}
@NotNull
public static ChunkPos getByBukkitChunk(@NotNull Chunk chunk) {
return new ChunkPos(chunk.getX(), chunk.getZ());
}
public String getAsString() {
return x + "," + z;
} }
@Override @Override
public String toString() { public String toString() {
return "ChunkCoordinate{" + return "ChunkPos{" +
"x=" + x + "x=" + x +
", z=" + z + ", z=" + z +
'}'; '}';

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.api.mechanic.world;
import org.bukkit.Chunk;
import org.jetbrains.annotations.NotNull;
public record RegionPos(int x, int z) {
public static RegionPos of(int x, int z) {
return new RegionPos(x, z);
}
public static RegionPos getByString(String coordinate) {
String[] split = coordinate.split(",", 2);
try {
int x = Integer.parseInt(split[0]);
int z = Integer.parseInt(split[1]);
return new RegionPos(x, z);
}
catch (NumberFormatException e) {
e.printStackTrace();
return null;
}
}
@Override
public int hashCode() {
long combined = (long) x << 32 | z;
return Long.hashCode(combined);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final RegionPos other = (RegionPos) obj;
if (this.x != other.x) {
return false;
}
if (this.z != other.z) {
return false;
}
return true;
}
@NotNull
public static RegionPos getByBukkitChunk(@NotNull Chunk chunk) {
int regionX = (int) Math.floor((double) chunk.getX() / 32.0);
int regionZ = (int) Math.floor((double) chunk.getZ() / 32.0);
return new RegionPos(regionX, regionZ);
}
@NotNull
public static RegionPos getByChunkPos(@NotNull ChunkPos chunk) {
int regionX = (int) Math.floor((double) chunk.x() / 32.0);
int regionZ = (int) Math.floor((double) chunk.z() / 32.0);
return new RegionPos(regionX, regionZ);
}
@Override
public String toString() {
return "RegionPos{" +
"x=" + x +
", z=" + z +
'}';
}
}

View File

@@ -57,8 +57,8 @@ public class SimpleLocation {
return worldName; return worldName;
} }
public ChunkCoordinate getChunkCoordinate() { public ChunkPos getChunkCoordinate() {
return new ChunkCoordinate(x >> 4, z >> 4); return new ChunkPos(x >> 4, z >> 4);
} }
public SimpleLocation add(int x, int y, int z) { public SimpleLocation add(int x, int y, int z) {

View File

@@ -21,7 +21,7 @@ import net.momirealms.customcrops.api.mechanic.item.Crop;
import net.momirealms.customcrops.api.mechanic.item.Fertilizer; import net.momirealms.customcrops.api.mechanic.item.Fertilizer;
import net.momirealms.customcrops.api.mechanic.item.Pot; import net.momirealms.customcrops.api.mechanic.item.Pot;
import net.momirealms.customcrops.api.mechanic.item.Sprinkler; import net.momirealms.customcrops.api.mechanic.item.Sprinkler;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate; import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
@@ -33,7 +33,9 @@ public interface CustomCropsChunk {
CustomCropsWorld getCustomCropsWorld(); CustomCropsWorld getCustomCropsWorld();
ChunkCoordinate getChunkCoordinate(); CustomCropsRegion getCustomCropsRegion();
ChunkPos getChunkPos();
void secondTimer(); void secondTimer();

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.api.mechanic.world.level;
import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.RegionPos;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public interface CustomCropsRegion {
CustomCropsWorld getCustomCropsWorld();
byte @Nullable [] getChunkBytes(ChunkPos pos);
RegionPos getRegionPos();
void removeChunk(ChunkPos pos);
void saveChunk(ChunkPos pos, byte[] data);
Map<ChunkPos, byte[]> getRegionDataToSave();
boolean canPrune();
}

View File

@@ -21,8 +21,9 @@ import net.momirealms.customcrops.api.mechanic.item.Crop;
import net.momirealms.customcrops.api.mechanic.item.Fertilizer; import net.momirealms.customcrops.api.mechanic.item.Fertilizer;
import net.momirealms.customcrops.api.mechanic.item.Pot; import net.momirealms.customcrops.api.mechanic.item.Pot;
import net.momirealms.customcrops.api.mechanic.item.Sprinkler; import net.momirealms.customcrops.api.mechanic.item.Sprinkler;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate; import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.RegionPos;
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
import net.momirealms.customcrops.api.mechanic.world.season.Season; import net.momirealms.customcrops.api.mechanic.world.season.Season;
import org.bukkit.World; import org.bukkit.World;
@@ -33,11 +34,15 @@ import java.util.Optional;
public interface CustomCropsWorld { public interface CustomCropsWorld {
void save();
void startTick(); void startTick();
void cancelTick(); void cancelTick();
CustomCropsChunk removeLazyChunkAt(ChunkCoordinate chunkCoordinate); boolean isRegionLoaded(RegionPos regionPos);
CustomCropsChunk removeLazyChunkAt(ChunkPos chunkPos);
WorldSetting getWorldSetting(); WorldSetting getWorldSetting();
@@ -49,13 +54,17 @@ public interface CustomCropsWorld {
String getWorldName(); String getWorldName();
boolean isChunkLoaded(ChunkCoordinate chunkCoordinate); boolean isChunkLoaded(ChunkPos chunkPos);
Optional<CustomCropsChunk> getChunkAt(ChunkCoordinate chunkCoordinate); Optional<CustomCropsChunk> getLoadedChunkAt(ChunkPos chunkPos);
Optional<CustomCropsRegion> getLoadedRegionAt(RegionPos regionPos);
void loadRegion(CustomCropsRegion region);
void loadChunk(CustomCropsChunk chunk); void loadChunk(CustomCropsChunk chunk);
void unloadChunk(ChunkCoordinate chunkCoordinate); void unloadChunk(ChunkPos chunkPos);
void setInfoData(WorldInfoData infoData); void setInfoData(WorldInfoData infoData);

View File

@@ -8,7 +8,7 @@ plugins {
allprojects { allprojects {
project.group = "net.momirealms" project.group = "net.momirealms"
project.version = "3.4.2.3" project.version = "3.4.3.0"
apply<JavaPlugin>() apply<JavaPlugin>()
apply(plugin = "java") apply(plugin = "java")

View File

@@ -103,7 +103,6 @@ public class CustomCropsPluginImpl extends CustomCropsPlugin {
this.disableNBTAPILogs(); this.disableNBTAPILogs();
Migration.tryUpdating(); Migration.tryUpdating();
this.reload(); this.reload();
this.worldManager.init();
if (ConfigManager.metrics()) new Metrics(this, 16593); if (ConfigManager.metrics()) new Metrics(this, 16593);
if (ConfigManager.checkUpdate()) { if (ConfigManager.checkUpdate()) {
this.versionManager.checkUpdate().thenAccept(result -> { this.versionManager.checkUpdate().thenAccept(result -> {

View File

@@ -21,7 +21,6 @@ import dev.jorel.commandapi.*;
import dev.jorel.commandapi.arguments.ArgumentSuggestions; import dev.jorel.commandapi.arguments.ArgumentSuggestions;
import dev.jorel.commandapi.arguments.IntegerArgument; import dev.jorel.commandapi.arguments.IntegerArgument;
import dev.jorel.commandapi.arguments.StringArgument; import dev.jorel.commandapi.arguments.StringArgument;
import dev.jorel.commandapi.arguments.WorldArgument;
import net.momirealms.customcrops.api.CustomCropsPlugin; import net.momirealms.customcrops.api.CustomCropsPlugin;
import net.momirealms.customcrops.api.common.Initable; import net.momirealms.customcrops.api.common.Initable;
import net.momirealms.customcrops.api.integration.SeasonInterface; import net.momirealms.customcrops.api.integration.SeasonInterface;
@@ -33,7 +32,9 @@ import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsSection;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
import net.momirealms.customcrops.api.mechanic.world.season.Season; import net.momirealms.customcrops.api.mechanic.world.season.Season;
import net.momirealms.customcrops.compatibility.season.InBuiltSeason; import net.momirealms.customcrops.compatibility.season.InBuiltSeason;
import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.generator.WorldInfo;
import java.util.Locale; import java.util.Locale;
import java.util.Optional; import java.util.Optional;
@@ -91,10 +92,15 @@ public class CommandManager implements Initable {
private CommandAPICommand getForceTickCommand() { private CommandAPICommand getForceTickCommand() {
return new CommandAPICommand("force-tick") return new CommandAPICommand("force-tick")
.withArguments(new WorldArgument("world")) .withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> Bukkit.getWorlds().stream().map(WorldInfo::getName).toList().toArray(new String[0]))))
.withArguments(new StringArgument("type").replaceSuggestions(ArgumentSuggestions.strings("sprinkler", "crop", "pot", "scarecrow", "greenhouse"))) .withArguments(new StringArgument("type").replaceSuggestions(ArgumentSuggestions.strings("sprinkler", "crop", "pot", "scarecrow", "greenhouse")))
.executes((sender, args) -> { .executes((sender, args) -> {
World world = (World) args.get("world"); String worldName = (String) args.get("world");
World world = Bukkit.getWorld(worldName);
if (world == null) {
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
return;
}
ItemType itemType = ItemType.valueOf(((String) args.get("type")).toUpperCase(Locale.ENGLISH)); ItemType itemType = ItemType.valueOf(((String) args.get("type")).toUpperCase(Locale.ENGLISH));
Optional<CustomCropsWorld> customCropsWorld = plugin.getWorldManager().getCustomCropsWorld(world); Optional<CustomCropsWorld> customCropsWorld = plugin.getWorldManager().getCustomCropsWorld(world);
if (customCropsWorld.isEmpty()) { if (customCropsWorld.isEmpty()) {
@@ -119,16 +125,26 @@ public class CommandManager implements Initable {
return new CommandAPICommand("date") return new CommandAPICommand("date")
.withSubcommands( .withSubcommands(
new CommandAPICommand("get") new CommandAPICommand("get")
.withArguments(new WorldArgument("world")) .withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> Bukkit.getWorlds().stream().map(WorldInfo::getName).toList().toArray(new String[0]))))
.executes((sender, args) -> { .executes((sender, args) -> {
World world = (World) args.get("world"); String worldName = (String) args.get("world");
World world = Bukkit.getWorld(worldName);
if (world == null) {
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
return;
}
plugin.getAdventure().sendMessageWithPrefix(sender, String.valueOf(plugin.getIntegrationManager().getDate(world))); plugin.getAdventure().sendMessageWithPrefix(sender, String.valueOf(plugin.getIntegrationManager().getDate(world)));
}), }),
new CommandAPICommand("set") new CommandAPICommand("set")
.withArguments(new WorldArgument("world")) .withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> Bukkit.getWorlds().stream().map(WorldInfo::getName).toList().toArray(new String[0]))))
.withArguments(new IntegerArgument("date",1)) .withArguments(new IntegerArgument("date",1))
.executes((sender, args) -> { .executes((sender, args) -> {
World world = (World) args.get("world"); String worldName = (String) args.get("world");
World world = Bukkit.getWorld(worldName);
if (world == null) {
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
return;
}
int date = (int) args.getOrDefault("date", 1); int date = (int) args.getOrDefault("date", 1);
SeasonInterface seasonInterface = plugin.getIntegrationManager().getSeasonInterface(); SeasonInterface seasonInterface = plugin.getIntegrationManager().getSeasonInterface();
if (!(seasonInterface instanceof InBuiltSeason inBuiltSeason)) { if (!(seasonInterface instanceof InBuiltSeason inBuiltSeason)) {
@@ -159,13 +175,18 @@ public class CommandManager implements Initable {
return new CommandAPICommand("season") return new CommandAPICommand("season")
.withSubcommands( .withSubcommands(
new CommandAPICommand("get") new CommandAPICommand("get")
.withArguments(new WorldArgument("world")) .withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> Bukkit.getWorlds().stream().map(WorldInfo::getName).toList().toArray(new String[0]))))
.executes((sender, args) -> { .executes((sender, args) -> {
World world = (World) args.get("world"); String worldName = (String) args.get("world");
World world = Bukkit.getWorld(worldName);
if (world == null) {
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
return;
}
plugin.getAdventure().sendMessageWithPrefix(sender, MessageManager.seasonTranslation(plugin.getIntegrationManager().getSeason(world))); plugin.getAdventure().sendMessageWithPrefix(sender, MessageManager.seasonTranslation(plugin.getIntegrationManager().getSeason(world)));
}), }),
new CommandAPICommand("set") new CommandAPICommand("set")
.withArguments(new WorldArgument("world")) .withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> Bukkit.getWorlds().stream().map(WorldInfo::getName).toList().toArray(new String[0]))))
.withArguments(new StringArgument("season") .withArguments(new StringArgument("season")
.replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(info -> .replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(info ->
new IStringTooltip[] { new IStringTooltip[] {
@@ -177,7 +198,12 @@ public class CommandManager implements Initable {
)) ))
) )
.executes((sender, args) -> { .executes((sender, args) -> {
World world = (World) args.get("world"); String worldName = (String) args.get("world");
World world = Bukkit.getWorld(worldName);
if (world == null) {
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
return;
}
String seasonName = (String) args.get("season"); String seasonName = (String) args.get("season");
SeasonInterface seasonInterface = plugin.getIntegrationManager().getSeasonInterface(); SeasonInterface seasonInterface = plugin.getIntegrationManager().getSeasonInterface();

View File

@@ -41,7 +41,7 @@ import net.momirealms.customcrops.api.mechanic.misc.CRotation;
import net.momirealms.customcrops.api.mechanic.misc.Reason; import net.momirealms.customcrops.api.mechanic.misc.Reason;
import net.momirealms.customcrops.api.mechanic.misc.Value; import net.momirealms.customcrops.api.mechanic.misc.Value;
import net.momirealms.customcrops.api.mechanic.requirement.Requirement; import net.momirealms.customcrops.api.mechanic.requirement.Requirement;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate; import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop; import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop;
@@ -443,7 +443,7 @@ public class ActionManagerImpl implements ActionManager {
if (Math.random() > chance) return; if (Math.random() > chance) return;
Location location = state.getLocation(); Location location = state.getLocation();
plugin.getWorldManager().getCustomCropsWorld(location.getWorld()) plugin.getWorldManager().getCustomCropsWorld(location.getWorld())
.flatMap(world -> world.getChunkAt(ChunkCoordinate.getByBukkitChunk(location.getChunk()))) .flatMap(world -> world.getLoadedChunkAt(ChunkPos.getByBukkitChunk(location.getChunk())))
.flatMap(chunk -> chunk.getBlockAt(SimpleLocation.of(location))) .flatMap(chunk -> chunk.getBlockAt(SimpleLocation.of(location)))
.ifPresent(block -> { .ifPresent(block -> {
block.tick(1); block.tick(1);

View File

@@ -2020,6 +2020,9 @@ public class ItemManagerImpl implements ItemManager {
if (optionalPot.isEmpty()) { if (optionalPot.isEmpty()) {
plugin.debug("Found a pot without data interacted by " + player.getName() + " at " + location); plugin.debug("Found a pot without data interacted by " + player.getName() + " at " + location);
WorldPot newPot = new MemoryPot(simpleLocation, pot.getKey()); WorldPot newPot = new MemoryPot(simpleLocation, pot.getKey());
if (pot.isWetPot(potItemID)) {
newPot.setWater(1);
}
plugin.getWorldManager().addPotAt(newPot, simpleLocation); plugin.getWorldManager().addPotAt(newPot, simpleLocation);
optionalPot = Optional.of(newPot); optionalPot = Optional.of(newPot);
} else { } else {

View File

@@ -45,6 +45,7 @@ import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemDamageEvent; import org.bukkit.event.player.PlayerItemDamageEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;

View File

@@ -161,4 +161,17 @@ public class PotConfig extends AbstractEventItem implements Pot {
public boolean isVanillaBlock() { public boolean isVanillaBlock() {
return isVanillaBlock; return isVanillaBlock;
} }
@Override
public boolean isWetPot(String id) {
if (id.equals(getWetItem())) {
return true;
}
for (Pair<String, String> pair : fertilizedPotMap.values()) {
if (pair.right().equals(id)) {
return true;
}
}
return false;
}
} }

View File

@@ -34,10 +34,26 @@ public class Migration {
if (version == null) return; if (version == null) return;
int versionNumber = Integer.parseInt(version); int versionNumber = Integer.parseInt(version);
if (!(versionNumber >= 25 && versionNumber <= 34)) { if (versionNumber >= 25 && versionNumber <= 34) {
doV33Migration(config);
return; return;
} }
if (versionNumber == 35) {
doV343Migration();
}
}
private static void doV343Migration() {
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));
adaptor.convertWorldFromV342toV343(temp, world);
}
}
}
private static void doV33Migration(YamlConfiguration config) {
// do migration // do migration
if (config.contains("mechanics.season.sync-season")) { if (config.contains("mechanics.season.sync-season")) {
config.set("mechanics.sync-season.enable", config.getBoolean("mechanics.season.sync-season.enable")); config.set("mechanics.sync-season.enable", config.getBoolean("mechanics.season.sync-season.enable"));
@@ -53,7 +69,7 @@ public class Migration {
} }
try { try {
config.save(configFile); config.save(new File(CustomCropsPlugin.getInstance().getDataFolder(), "config.yml"));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -87,7 +103,7 @@ public class Migration {
for (World world : Bukkit.getWorlds()) { for (World world : Bukkit.getWorlds()) {
CWorld temp = new CWorld(CustomCropsPlugin.getInstance().getWorldManager(), world); 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,false,false,28,-1,-1,-1, 0));
adaptor.convertWorld(temp, world); adaptor.convertWorldFromV33toV34(temp, world);
} }
} }
} }

View File

@@ -25,8 +25,8 @@ import net.momirealms.customcrops.api.mechanic.item.Pot;
import net.momirealms.customcrops.api.mechanic.item.Sprinkler; import net.momirealms.customcrops.api.mechanic.item.Sprinkler;
import net.momirealms.customcrops.api.mechanic.misc.CRotation; import net.momirealms.customcrops.api.mechanic.misc.CRotation;
import net.momirealms.customcrops.api.mechanic.requirement.State; import net.momirealms.customcrops.api.mechanic.requirement.State;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate;
import net.momirealms.customcrops.api.mechanic.world.BlockPos; import net.momirealms.customcrops.api.mechanic.world.BlockPos;
import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
import net.momirealms.customcrops.api.mechanic.world.level.*; import net.momirealms.customcrops.api.mechanic.world.level.*;
@@ -44,7 +44,7 @@ import java.util.concurrent.ThreadLocalRandom;
public class CChunk implements CustomCropsChunk { public class CChunk implements CustomCropsChunk {
private transient CWorld cWorld; private transient CWorld cWorld;
private final ChunkCoordinate chunkCoordinate; private final ChunkPos chunkPos;
private final ConcurrentHashMap<Integer, CSection> loadedSections; private final ConcurrentHashMap<Integer, CSection> loadedSections;
private final PriorityQueue<TickTask> queue; private final PriorityQueue<TickTask> queue;
private final Set<BlockPos> tickedBlocks; private final Set<BlockPos> tickedBlocks;
@@ -52,9 +52,9 @@ public class CChunk implements CustomCropsChunk {
private int loadedSeconds; private int loadedSeconds;
private int unloadedSeconds; private int unloadedSeconds;
public CChunk(CWorld cWorld, ChunkCoordinate chunkCoordinate) { public CChunk(CWorld cWorld, ChunkPos chunkPos) {
this.cWorld = cWorld; this.cWorld = cWorld;
this.chunkCoordinate = chunkCoordinate; this.chunkPos = chunkPos;
this.loadedSections = new ConcurrentHashMap<>(64); this.loadedSections = new ConcurrentHashMap<>(64);
this.queue = new PriorityQueue<>(); this.queue = new PriorityQueue<>();
this.unloadedSeconds = 0; this.unloadedSeconds = 0;
@@ -64,7 +64,7 @@ public class CChunk implements CustomCropsChunk {
public CChunk( public CChunk(
CWorld cWorld, CWorld cWorld,
ChunkCoordinate chunkCoordinate, ChunkPos chunkPos,
int loadedSeconds, int loadedSeconds,
long lastLoadedTime, long lastLoadedTime,
ConcurrentHashMap<Integer, CSection> loadedSections, ConcurrentHashMap<Integer, CSection> loadedSections,
@@ -72,7 +72,7 @@ public class CChunk implements CustomCropsChunk {
HashSet<BlockPos> tickedBlocks HashSet<BlockPos> tickedBlocks
) { ) {
this.cWorld = cWorld; this.cWorld = cWorld;
this.chunkCoordinate = chunkCoordinate; this.chunkPos = chunkPos;
this.loadedSections = loadedSections; this.loadedSections = loadedSections;
this.lastLoadedTime = lastLoadedTime; this.lastLoadedTime = lastLoadedTime;
this.loadedSeconds = loadedSeconds; this.loadedSeconds = loadedSeconds;
@@ -101,8 +101,13 @@ public class CChunk implements CustomCropsChunk {
} }
@Override @Override
public ChunkCoordinate getChunkCoordinate() { public CustomCropsRegion getCustomCropsRegion() {
return chunkCoordinate; return cWorld.getLoadedRegionAt(chunkPos.getRegionPos()).orElse(null);
}
@Override
public ChunkPos getChunkPos() {
return chunkPos;
} }
@Override @Override

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customcrops.mechanic.world;
import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.RegionPos;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsRegion;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class CRegion implements CustomCropsRegion {
private final CWorld cWorld;
private final RegionPos regionPos;
private final ConcurrentHashMap<ChunkPos, byte[]> cachedChunkBytes;
public CRegion(CWorld cWorld, RegionPos regionPos) {
this.cWorld = cWorld;
this.regionPos = regionPos;
this.cachedChunkBytes = new ConcurrentHashMap<>();
}
public CRegion(CWorld cWorld, RegionPos regionPos, ConcurrentHashMap<ChunkPos, byte[]> cachedChunkBytes) {
this.cWorld = cWorld;
this.regionPos = regionPos;
this.cachedChunkBytes = cachedChunkBytes;
}
@Override
public CustomCropsWorld getCustomCropsWorld() {
return cWorld;
}
@Nullable
@Override
public byte[] getChunkBytes(ChunkPos pos) {
return cachedChunkBytes.get(pos);
}
@Override
public RegionPos getRegionPos() {
return regionPos;
}
@Override
public void removeChunk(ChunkPos pos) {
cachedChunkBytes.remove(pos);
}
@Override
public void saveChunk(ChunkPos pos, byte[] data) {
cachedChunkBytes.put(pos, data);
}
@Override
public Map<ChunkPos, byte[]> getRegionDataToSave() {
return new HashMap<>(cachedChunkBytes);
}
@Override
public boolean canPrune() {
return cachedChunkBytes.size() == 0;
}
}

View File

@@ -26,20 +26,23 @@ import net.momirealms.customcrops.api.mechanic.item.Crop;
import net.momirealms.customcrops.api.mechanic.item.Fertilizer; import net.momirealms.customcrops.api.mechanic.item.Fertilizer;
import net.momirealms.customcrops.api.mechanic.item.Pot; import net.momirealms.customcrops.api.mechanic.item.Pot;
import net.momirealms.customcrops.api.mechanic.item.Sprinkler; import net.momirealms.customcrops.api.mechanic.item.Sprinkler;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate; import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.RegionPos;
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
import net.momirealms.customcrops.api.mechanic.world.level.*; import net.momirealms.customcrops.api.mechanic.world.level.*;
import net.momirealms.customcrops.api.mechanic.world.season.Season; import net.momirealms.customcrops.api.mechanic.world.season.Season;
import net.momirealms.customcrops.api.scheduler.CancellableTask; import net.momirealms.customcrops.api.scheduler.CancellableTask;
import net.momirealms.customcrops.api.util.LogUtils; import net.momirealms.customcrops.api.util.LogUtils;
import net.momirealms.customcrops.utils.EventUtils; import net.momirealms.customcrops.utils.EventUtils;
import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.*; import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -47,21 +50,42 @@ public class CWorld implements CustomCropsWorld {
private final WorldManager worldManager; private final WorldManager worldManager;
private final WeakReference<World> world; private final WeakReference<World> world;
private final ConcurrentHashMap<ChunkCoordinate, CChunk> loadedChunks; private final ConcurrentHashMap<ChunkPos, CChunk> loadedChunks;
private final ConcurrentHashMap<ChunkCoordinate, CChunk> lazyChunks; private final ConcurrentHashMap<ChunkPos, CChunk> lazyChunks;
private final ConcurrentHashMap<RegionPos, CRegion> loadedRegions;
private WorldSetting setting; private WorldSetting setting;
private WorldInfoData infoData; private WorldInfoData infoData;
private final String worldName; private final String worldName;
private CancellableTask worldTask; private CancellableTask worldTask;
private int currentMinecraftDay; private int currentMinecraftDay;
private int regionTimer;
public CWorld(WorldManager worldManager, World world) { public CWorld(WorldManager worldManager, World world) {
this.world = new WeakReference<>(world); this.world = new WeakReference<>(world);
this.worldManager = worldManager; this.worldManager = worldManager;
this.loadedChunks = new ConcurrentHashMap<>(); this.loadedChunks = new ConcurrentHashMap<>();
this.lazyChunks = new ConcurrentHashMap<>(); this.lazyChunks = new ConcurrentHashMap<>();
this.loadedRegions = new ConcurrentHashMap<>();
this.worldName = world.getName(); this.worldName = world.getName();
this.currentMinecraftDay = (int) (world.getFullTime() / 24000); this.currentMinecraftDay = (int) (world.getFullTime() / 24000);
this.regionTimer = 0;
}
@Override
public void save() {
long time1 = System.currentTimeMillis();
worldManager.saveInfoData(this);
for (CChunk chunk : loadedChunks.values()) {
worldManager.saveChunkToCachedRegion(chunk);
}
for (CChunk chunk : lazyChunks.values()) {
worldManager.saveChunkToCachedRegion(chunk);
}
for (CRegion region : loadedRegions.values()) {
worldManager.saveRegionToFile(region);
}
long time2 = System.currentTimeMillis();
CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to save world " + worldName + ". Saved " + (lazyChunks.size() + loadedChunks.size()) + " chunks.");
} }
@Override @Override
@@ -77,8 +101,8 @@ public class CWorld implements CustomCropsWorld {
} }
private void timer() { private void timer() {
ArrayList<Pair<ChunkCoordinate, CChunk>> chunksToSave = new ArrayList<>(); ArrayList<Pair<ChunkPos, CChunk>> chunksToSave = new ArrayList<>();
for (Map.Entry<ChunkCoordinate, CChunk> lazyEntry : lazyChunks.entrySet()) { for (Map.Entry<ChunkPos, CChunk> lazyEntry : lazyChunks.entrySet()) {
CChunk chunk = lazyEntry.getValue(); CChunk chunk = lazyEntry.getValue();
int sec = chunk.getUnloadedSeconds() + 1; int sec = chunk.getUnloadedSeconds() + 1;
if (sec >= 30) { if (sec >= 30) {
@@ -87,9 +111,9 @@ public class CWorld implements CustomCropsWorld {
chunk.setUnloadedSeconds(sec); chunk.setUnloadedSeconds(sec);
} }
} }
for (Pair<ChunkCoordinate, CChunk> pair : chunksToSave) { for (Pair<ChunkPos, CChunk> pair : chunksToSave) {
lazyChunks.remove(pair.left()); lazyChunks.remove(pair.left());
worldManager.saveChunkToFile(pair.right()); worldManager.saveChunkToCachedRegion(pair.right());
} }
if (setting.isAutoSeasonChange()) { if (setting.isAutoSeasonChange()) {
this.updateSeasonAndDate(); this.updateSeasonAndDate();
@@ -99,6 +123,22 @@ public class CWorld implements CustomCropsWorld {
chunk.secondTimer(); chunk.secondTimer();
} }
} }
// timer check to unload regions
this.regionTimer++;
if (this.regionTimer >= 600) {
this.regionTimer = 0;
ArrayList<RegionPos> removed = new ArrayList<>();
for (Map.Entry<RegionPos, CRegion> entry : loadedRegions.entrySet()) {
if (isRegionNoLongerLoaded(entry.getKey())) {
worldManager.saveRegionToFile(entry.getValue());
removed.add(entry.getKey());
}
}
for (RegionPos pos : removed) {
loadedRegions.remove(pos);
}
}
} }
private void updateSeasonAndDate() { private void updateSeasonAndDate() {
@@ -130,8 +170,8 @@ public class CWorld implements CustomCropsWorld {
} }
@Override @Override
public CustomCropsChunk removeLazyChunkAt(ChunkCoordinate chunkCoordinate) { public CustomCropsChunk removeLazyChunkAt(ChunkPos chunkPos) {
return lazyChunks.remove(chunkCoordinate); return lazyChunks.remove(chunkPos);
} }
@Override @Override
@@ -161,31 +201,51 @@ public class CWorld implements CustomCropsWorld {
} }
@Override @Override
public boolean isChunkLoaded(ChunkCoordinate chunkCoordinate) { public boolean isChunkLoaded(ChunkPos chunkPos) {
return loadedChunks.containsKey(chunkCoordinate); return loadedChunks.containsKey(chunkPos);
} }
@Override @Override
public Optional<CustomCropsChunk> getChunkAt(ChunkCoordinate chunkCoordinate) { public boolean isRegionLoaded(RegionPos regionPos) {
return Optional.ofNullable(createOrGetChunk(chunkCoordinate)); return loadedRegions.containsKey(regionPos);
}
@Override
public Optional<CustomCropsChunk> getLoadedChunkAt(ChunkPos chunkPos) {
return Optional.ofNullable(createOrGetChunk(chunkPos));
}
@Override
public Optional<CustomCropsRegion> getLoadedRegionAt(RegionPos regionPos) {
return Optional.ofNullable(loadedRegions.get(regionPos));
}
@Override
public void loadRegion(CustomCropsRegion region) {
RegionPos regionPos = region.getRegionPos();
if (loadedRegions.containsKey(regionPos)) {
LogUtils.warn("Invalid operation: Loaded region is loaded again." + regionPos);
return;
}
loadedRegions.put(regionPos, (CRegion) region);
} }
@Override @Override
public void loadChunk(CustomCropsChunk chunk) { public void loadChunk(CustomCropsChunk chunk) {
ChunkCoordinate chunkCoordinate = chunk.getChunkCoordinate(); ChunkPos chunkPos = chunk.getChunkPos();
if (loadedChunks.containsKey(chunkCoordinate)) { if (loadedChunks.containsKey(chunkPos)) {
LogUtils.warn("Invalid operation: Loaded chunk is loaded again." + chunkCoordinate); LogUtils.warn("Invalid operation: Loaded chunk is loaded again." + chunkPos);
return; return;
} }
loadedChunks.put(chunkCoordinate, (CChunk) chunk); loadedChunks.put(chunkPos, (CChunk) chunk);
} }
@Override @Override
public void unloadChunk(ChunkCoordinate chunkCoordinate) { public void unloadChunk(ChunkPos chunkPos) {
CChunk chunk = loadedChunks.remove(chunkCoordinate); CChunk chunk = loadedChunks.remove(chunkPos);
if (chunk != null) { if (chunk != null) {
chunk.updateLastLoadedTime(); chunk.updateLastLoadedTime();
lazyChunks.put(chunkCoordinate, chunk); lazyChunks.put(chunkPos, chunk);
} }
} }
@@ -256,7 +316,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addWaterToSprinkler(Sprinkler sprinkler, SimpleLocation location, int amount) { public void addWaterToSprinkler(Sprinkler sprinkler, SimpleLocation location, int amount) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addWaterToSprinkler(sprinkler, location, amount); chunk.get().addWaterToSprinkler(sprinkler, location, amount);
} else { } else {
@@ -266,7 +326,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addFertilizerToPot(Pot pot, Fertilizer fertilizer, SimpleLocation location) { public void addFertilizerToPot(Pot pot, Fertilizer fertilizer, SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addFertilizerToPot(pot, fertilizer, location); chunk.get().addFertilizerToPot(pot, fertilizer, location);
} else { } else {
@@ -276,7 +336,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addWaterToPot(Pot pot, SimpleLocation location, int amount) { public void addWaterToPot(Pot pot, SimpleLocation location, int amount) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addWaterToPot(pot, location, amount); chunk.get().addWaterToPot(pot, location, amount);
} else { } else {
@@ -286,7 +346,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addPotAt(WorldPot pot, SimpleLocation location) { public void addPotAt(WorldPot pot, SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addPotAt(pot, location); chunk.get().addPotAt(pot, location);
} else { } else {
@@ -296,7 +356,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addSprinklerAt(WorldSprinkler sprinkler, SimpleLocation location) { public void addSprinklerAt(WorldSprinkler sprinkler, SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addSprinklerAt(sprinkler, location); chunk.get().addSprinklerAt(sprinkler, location);
} else { } else {
@@ -306,7 +366,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addCropAt(WorldCrop crop, SimpleLocation location) { public void addCropAt(WorldCrop crop, SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addCropAt(crop, location); chunk.get().addCropAt(crop, location);
} else { } else {
@@ -316,7 +376,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addPointToCrop(Crop crop, SimpleLocation location, int points) { public void addPointToCrop(Crop crop, SimpleLocation location, int points) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addPointToCrop(crop, location, points); chunk.get().addPointToCrop(crop, location, points);
} else { } else {
@@ -326,7 +386,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addGlassAt(WorldGlass glass, SimpleLocation location) { public void addGlassAt(WorldGlass glass, SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addGlassAt(glass, location); chunk.get().addGlassAt(glass, location);
} else { } else {
@@ -336,7 +396,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void addScarecrowAt(WorldScarecrow scarecrow, SimpleLocation location) { public void addScarecrowAt(WorldScarecrow scarecrow, SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().addScarecrowAt(scarecrow, location); chunk.get().addScarecrowAt(scarecrow, location);
} else { } else {
@@ -346,7 +406,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void removeSprinklerAt(SimpleLocation location) { public void removeSprinklerAt(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().removeSprinklerAt(location); chunk.get().removeSprinklerAt(location);
} else { } else {
@@ -356,7 +416,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void removePotAt(SimpleLocation location) { public void removePotAt(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().removePotAt(location); chunk.get().removePotAt(location);
} else { } else {
@@ -366,7 +426,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void removeCropAt(SimpleLocation location) { public void removeCropAt(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().removeCropAt(location); chunk.get().removeCropAt(location);
} else { } else {
@@ -376,7 +436,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void removeGlassAt(SimpleLocation location) { public void removeGlassAt(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().removeGlassAt(location); chunk.get().removeGlassAt(location);
} else { } else {
@@ -386,7 +446,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public void removeScarecrowAt(SimpleLocation location) { public void removeScarecrowAt(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
chunk.get().removeScarecrowAt(location); chunk.get().removeScarecrowAt(location);
} else { } else {
@@ -396,7 +456,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public CustomCropsBlock removeAnythingAt(SimpleLocation location) { public CustomCropsBlock removeAnythingAt(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isPresent()) { if (chunk.isPresent()) {
return chunk.get().removeBlockAt(location); return chunk.get().removeBlockAt(location);
} else { } else {
@@ -406,33 +466,35 @@ public class CWorld implements CustomCropsWorld {
} }
@Nullable @Nullable
private CustomCropsChunk createOrGetChunk(ChunkCoordinate chunkCoordinate) { private CustomCropsChunk createOrGetChunk(ChunkPos chunkPos) {
World bukkitWorld = world.get(); World bukkitWorld = world.get();
if (bukkitWorld == null) if (bukkitWorld == null)
return null; return null;
CChunk chunk = loadedChunks.get(chunkCoordinate); CChunk chunk = loadedChunks.get(chunkPos);
if (chunk != null) { if (chunk != null) {
return chunk; return chunk;
} }
if (bukkitWorld.isChunkLoaded(chunkCoordinate.x(), chunkCoordinate.z())) { // is a loaded chunk, but it doesn't have customcrops data
chunk = new CChunk(this, chunkCoordinate); if (bukkitWorld.isChunkLoaded(chunkPos.x(), chunkPos.z())) {
chunk = new CChunk(this, chunkPos);
loadChunk(chunk); loadChunk(chunk);
return chunk; return chunk;
} else { } else {
if (bukkitWorld.isChunkGenerated(chunkCoordinate.x(), chunkCoordinate.z())) { // is an unloaded chunk, but has been generated
Chunk bukkitChunk = bukkitWorld.getChunkAt(chunkCoordinate.x(), chunkCoordinate.z()); // if (bukkitWorld.isChunkGenerated(chunkPos.x(), chunkPos.z())) {
worldManager.handleChunkLoad(bukkitChunk); // Chunk bukkitChunk = bukkitWorld.getChunkAt(chunkPos.x(), chunkPos.z());
chunk = loadedChunks.get(chunkCoordinate); // worldManager.handleChunkLoad(bukkitChunk);
return Objects.requireNonNullElseGet(chunk, () -> new CChunk(this, chunkCoordinate)); // chunk = loadedChunks.get(chunkPos);
} else { // return Objects.requireNonNullElseGet(chunk, () -> new CChunk(this, chunkPos));
// } else {
return null; return null;
} // }
} }
} }
@Override @Override
public boolean isPotReachLimit(SimpleLocation location) { public boolean isPotReachLimit(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isEmpty()) { if (chunk.isEmpty()) {
LogUtils.warn("Invalid operation: Querying pot amount from a not generated chunk"); LogUtils.warn("Invalid operation: Querying pot amount from a not generated chunk");
return true; return true;
@@ -443,7 +505,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public boolean isCropReachLimit(SimpleLocation location) { public boolean isCropReachLimit(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isEmpty()) { if (chunk.isEmpty()) {
LogUtils.warn("Invalid operation: Querying crop amount from a not generated chunk"); LogUtils.warn("Invalid operation: Querying crop amount from a not generated chunk");
return true; return true;
@@ -454,7 +516,7 @@ public class CWorld implements CustomCropsWorld {
@Override @Override
public boolean isSprinklerReachLimit(SimpleLocation location) { public boolean isSprinklerReachLimit(SimpleLocation location) {
Optional<CustomCropsChunk> chunk = getChunkAt(location.getChunkCoordinate()); Optional<CustomCropsChunk> chunk = getLoadedChunkAt(location.getChunkCoordinate());
if (chunk.isEmpty()) { if (chunk.isEmpty()) {
LogUtils.warn("Invalid operation: Querying sprinkler amount from a not generated chunk"); LogUtils.warn("Invalid operation: Querying sprinkler amount from a not generated chunk");
return true; return true;
@@ -463,10 +525,18 @@ public class CWorld implements CustomCropsWorld {
return chunk.get().getSprinklerAmount() >= setting.getSprinklerPerChunk(); return chunk.get().getSprinklerAmount() >= setting.getSprinklerPerChunk();
} }
public Collection<CChunk> getAllChunksToSave() { private boolean isRegionNoLongerLoaded(RegionPos region) {
ArrayList<CChunk> chunks = new ArrayList<>(); World w = world.get();
chunks.addAll(lazyChunks.values()); if (w != null) {
chunks.addAll(loadedChunks.values()); for (int chunkX = region.x() * 32; chunkX < region.x() * 32 + 32; chunkX++) {
return chunks; for (int chunkZ = region.z() * 32; chunkZ < region.z() * 32 + 32; chunkZ++) {
// if a chunk is unloaded, then it should not be in the loaded chunks map
if (w.isChunkLoaded(chunkX, chunkZ) || lazyChunks.containsKey(ChunkPos.of(chunkX, chunkZ))) {
return false;
}
}
}
}
return true;
} }
} }

View File

@@ -66,4 +66,8 @@ public class SerializableChunk {
public int[] getTicked() { public int[] getTicked() {
return ticked; return ticked;
} }
public boolean canPrune() {
return sections.size() == 0;
}
} }

View File

@@ -21,7 +21,7 @@ import net.momirealms.customcrops.api.CustomCropsPlugin;
import net.momirealms.customcrops.api.manager.WorldManager; import net.momirealms.customcrops.api.manager.WorldManager;
import net.momirealms.customcrops.api.mechanic.item.*; import net.momirealms.customcrops.api.mechanic.item.*;
import net.momirealms.customcrops.api.mechanic.world.AbstractWorldAdaptor; import net.momirealms.customcrops.api.mechanic.world.AbstractWorldAdaptor;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate; import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
import net.momirealms.customcrops.api.mechanic.world.level.*; import net.momirealms.customcrops.api.mechanic.world.level.*;
@@ -39,6 +39,7 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
@@ -404,7 +405,7 @@ public class WorldManagerImpl implements WorldManager, Listener {
public void removeGlassAt(@NotNull SimpleLocation location) { public void removeGlassAt(@NotNull SimpleLocation location) {
CWorld cWorld = loadedWorlds.get(location.getWorldName()); CWorld cWorld = loadedWorlds.get(location.getWorldName());
if (cWorld == null) { if (cWorld == null) {
LogUtils.warn("Unsupported operation: Removing crop from unloaded world " + location); LogUtils.warn("Unsupported operation: Removing glass from unloaded world " + location);
return; return;
} }
cWorld.removeGlassAt(location); cWorld.removeGlassAt(location);
@@ -463,20 +464,20 @@ public class WorldManagerImpl implements WorldManager, Listener {
return; return;
CustomCropsWorld customCropsWorld = optional.get(); CustomCropsWorld customCropsWorld = optional.get();
ChunkCoordinate chunkCoordinate = ChunkCoordinate.getByBukkitChunk(bukkitChunk); ChunkPos chunkPos = ChunkPos.getByBukkitChunk(bukkitChunk);
if (customCropsWorld.isChunkLoaded(chunkCoordinate)) { if (customCropsWorld.isChunkLoaded(chunkPos)) {
return; return;
} }
// load chunks // load chunks
this.worldAdaptor.loadDynamicData(customCropsWorld, chunkCoordinate); this.worldAdaptor.loadChunkData(customCropsWorld, chunkPos);
// offline grow part // offline grow part
if (!customCropsWorld.getWorldSetting().isOfflineGrow()) return; if (!customCropsWorld.getWorldSetting().isOfflineGrow()) return;
// If chunk data not exists, return // If chunk data not exists, return
Optional<CustomCropsChunk> optionalChunk = customCropsWorld.getChunkAt(chunkCoordinate); Optional<CustomCropsChunk> optionalChunk = customCropsWorld.getLoadedChunkAt(chunkPos);
if (optionalChunk.isEmpty()) { if (optionalChunk.isEmpty()) {
return; return;
} }
@@ -493,9 +494,9 @@ public class WorldManagerImpl implements WorldManager, Listener {
return; return;
CustomCropsWorld customCropsWorld = optional.get(); CustomCropsWorld customCropsWorld = optional.get();
ChunkCoordinate chunkCoordinate = ChunkCoordinate.getByBukkitChunk(bukkitChunk); ChunkPos chunkPos = ChunkPos.getByBukkitChunk(bukkitChunk);
this.worldAdaptor.unloadDynamicData(customCropsWorld, chunkCoordinate); this.worldAdaptor.unloadChunkData(customCropsWorld, chunkPos);
} }
@EventHandler @EventHandler
@@ -509,12 +510,22 @@ public class WorldManagerImpl implements WorldManager, Listener {
} }
@Override @Override
public void saveChunkToFile(CustomCropsChunk chunk) { public void saveChunkToCachedRegion(CustomCropsChunk chunk) {
this.worldAdaptor.saveDynamicData(chunk.getCustomCropsWorld(), chunk); this.worldAdaptor.saveChunkToCachedRegion(chunk);
}
@Override
public void saveRegionToFile(CustomCropsRegion region) {
this.worldAdaptor.saveRegion(region);
} }
@Override @Override
public AbstractWorldAdaptor getWorldAdaptor() { public AbstractWorldAdaptor getWorldAdaptor() {
return worldAdaptor; return worldAdaptor;
} }
@Override
public void saveInfoData(CustomCropsWorld customCropsWorld) {
this.worldAdaptor.saveInfoData(customCropsWorld);
}
} }

View File

@@ -30,6 +30,7 @@ import net.momirealms.customcrops.api.manager.ConfigManager;
import net.momirealms.customcrops.api.manager.WorldManager; import net.momirealms.customcrops.api.manager.WorldManager;
import net.momirealms.customcrops.api.mechanic.world.*; import net.momirealms.customcrops.api.mechanic.world.*;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsRegion;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
import net.momirealms.customcrops.api.mechanic.world.level.WorldInfoData; import net.momirealms.customcrops.api.mechanic.world.level.WorldInfoData;
import net.momirealms.customcrops.api.mechanic.world.season.Season; import net.momirealms.customcrops.api.mechanic.world.season.Season;
@@ -47,6 +48,7 @@ import org.bukkit.World;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -70,6 +72,15 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
@Override @Override
public void unload(CustomCropsWorld customCropsWorld) { public void unload(CustomCropsWorld customCropsWorld) {
World world = customCropsWorld.getWorld();
if (world != null) {
new File(world.getWorldFolder(), "customcrops").mkdir();
customCropsWorld.save();
}
}
@Override
public void saveInfoData(CustomCropsWorld customCropsWorld) {
CWorld cWorld = (CWorld) customCropsWorld; CWorld cWorld = (CWorld) customCropsWorld;
World world = cWorld.getWorld(); World world = cWorld.getWorld();
if (world == null) { if (world == null) {
@@ -77,15 +88,8 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
return; return;
} }
// save world data into psd
world.getPersistentDataContainer().set(key, PersistentDataType.STRING, world.getPersistentDataContainer().set(key, PersistentDataType.STRING,
gson.toJson(cWorld.getInfoData())); gson.toJson(cWorld.getInfoData()));
new File(world.getWorldFolder(), "customcrops").mkdir();
for (CChunk chunk : cWorld.getAllChunksToSave()) {
saveDynamicData(cWorld, chunk);
}
} }
@Override @Override
@@ -102,7 +106,7 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
// try converting legacy worlds // try converting legacy worlds
if (ConfigManager.convertWorldOnLoad()) { if (ConfigManager.convertWorldOnLoad()) {
convertWorld(cWorld, world); convertWorldFromV33toV34(cWorld, world);
return; return;
} }
@@ -113,7 +117,7 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
} }
@Override @Override
public void loadDynamicData(CustomCropsWorld customCropsWorld, ChunkCoordinate chunkCoordinate) { public void loadChunkData(CustomCropsWorld customCropsWorld, ChunkPos chunkPos) {
CWorld cWorld = (CWorld) customCropsWorld; CWorld cWorld = (CWorld) customCropsWorld;
World world = cWorld.getWorld(); World world = cWorld.getWorld();
if (world == null) { if (world == null) {
@@ -121,35 +125,81 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
return; return;
} }
long time1 = System.currentTimeMillis();
// load lazy chunks firstly // load lazy chunks firstly
CustomCropsChunk lazyChunk = customCropsWorld.removeLazyChunkAt(chunkCoordinate); CustomCropsChunk lazyChunk = cWorld.removeLazyChunkAt(chunkPos);
if (lazyChunk != null) { if (lazyChunk != null) {
CChunk cChunk = (CChunk) lazyChunk; CChunk cChunk = (CChunk) lazyChunk;
cChunk.setUnloadedSeconds(0); cChunk.setUnloadedSeconds(0);
cWorld.loadChunk(cChunk); cWorld.loadChunk(cChunk);
long time2 = System.currentTimeMillis();
CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to load chunk " + chunkPos + " from lazy chunks");
return; return;
} }
// create or get chunk files
File data = getChunkDataFilePath(world, chunkCoordinate); // check if region is loaded, load if not loaded
if (!data.exists()) RegionPos regionPos = RegionPos.getByChunkPos(chunkPos);
return; Optional<CustomCropsRegion> optionalRegion = cWorld.getLoadedRegionAt(regionPos);
// load chunk from local files if (optionalRegion.isPresent()) {
long time1 = System.currentTimeMillis(); CustomCropsRegion region = optionalRegion.get();
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(getChunkDataFilePath(world, chunkCoordinate)))) { byte[] bytes = region.getChunkBytes(chunkPos);
DataInputStream dataStream = new DataInputStream(bis); if (bytes != null) {
CChunk chunk = deserialize(cWorld, dataStream); try {
DataInputStream dataStream = new DataInputStream(new ByteArrayInputStream(bytes));
CChunk chunk = deserializeChunk(cWorld, dataStream);
dataStream.close(); dataStream.close();
cWorld.loadChunk(chunk); cWorld.loadChunk(chunk);
long time2 = System.currentTimeMillis(); long time2 = System.currentTimeMillis();
CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to load chunk " + chunkCoordinate); CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to load chunk " + chunkPos + " from cached region");
} catch (IOException e) { } catch (IOException e) {
LogUtils.severe("Failed to load CustomCrops data at " + chunkCoordinate); LogUtils.severe("Failed to load CustomCrops data at " + chunkPos);
e.printStackTrace(); e.printStackTrace();
region.removeChunk(chunkPos);
}
}
return;
}
// if region file not exist, create one
File data = getRegionDataFilePath(world, regionPos);
if (!data.exists()) {
cWorld.loadRegion(new CRegion(cWorld, regionPos));
return;
}
// load region from local files
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(data))) {
DataInputStream dataStream = new DataInputStream(bis);
CRegion region = deserializeRegion(cWorld, dataStream);
dataStream.close();
cWorld.loadRegion(region);
byte[] bytes = region.getChunkBytes(chunkPos);
if (bytes != null) {
try {
DataInputStream chunkStream = new DataInputStream(new ByteArrayInputStream(bytes));
CChunk chunk = deserializeChunk(cWorld, chunkStream);
chunkStream.close();
cWorld.loadChunk(chunk);
long time2 = System.currentTimeMillis();
CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to load chunk " + chunkPos);
} catch (IOException e) {
LogUtils.severe("Failed to load CustomCrops data at " + chunkPos + ". Deleting corrupted chunk.");
e.printStackTrace();
region.removeChunk(chunkPos);
}
} else {
long time2 = System.currentTimeMillis();
CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to load region " + regionPos);
}
} catch (IOException e) {
LogUtils.severe("Failed to load CustomCrops region data at " + chunkPos + ". Deleting corrupted region.");
e.printStackTrace();
data.delete();
} }
} }
@Override @Override
public void unloadDynamicData(CustomCropsWorld ccWorld, ChunkCoordinate chunkCoordinate) { public void unloadChunkData(CustomCropsWorld ccWorld, ChunkPos chunkPos) {
CWorld cWorld = (CWorld) ccWorld; CWorld cWorld = (CWorld) ccWorld;
World world = cWorld.getWorld(); World world = cWorld.getWorld();
if (world == null) { if (world == null) {
@@ -157,18 +207,35 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
return; return;
} }
cWorld.unloadChunk(chunkCoordinate); cWorld.unloadChunk(chunkPos);
} }
@Override @Override
public void saveDynamicData(CustomCropsWorld ccWorld, CustomCropsChunk chunk) { public void saveChunkToCachedRegion(CustomCropsChunk customCropsChunk) {
CustomCropsRegion customCropsRegion = customCropsChunk.getCustomCropsRegion();
SerializableChunk serializableChunk = toSerializableChunk((CChunk) customCropsChunk);
if (serializableChunk.canPrune()) {
customCropsRegion.removeChunk(customCropsChunk.getChunkPos());
} else {
customCropsRegion.saveChunk(customCropsChunk.getChunkPos(), serialize(serializableChunk));
}
}
@Override
public void saveRegion(CustomCropsRegion customCropsRegion) {
File file = getRegionDataFilePath(customCropsRegion.getCustomCropsWorld().getWorld(), customCropsRegion.getRegionPos());
if (customCropsRegion.canPrune()) {
file.delete();
return;
}
long time1 = System.currentTimeMillis(); long time1 = System.currentTimeMillis();
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(getChunkDataFilePath(ccWorld.getWorld(), chunk.getChunkCoordinate())))) { try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
bos.write(serialize((CChunk) chunk)); bos.write(serialize(customCropsRegion));
long time2 = System.currentTimeMillis(); long time2 = System.currentTimeMillis();
CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to save chunk " + chunk.getChunkCoordinate()); CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to save region " + customCropsRegion.getRegionPos());
} catch (IOException e) { } catch (IOException e) {
LogUtils.severe("Failed to save CustomCrops data."); LogUtils.severe("Failed to save CustomCrops region data." + customCropsRegion.getRegionPos());
e.printStackTrace(); e.printStackTrace();
} }
} }
@@ -186,15 +253,35 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
worldManager.unloadWorld(event.getWorld()); worldManager.unloadWorld(event.getWorld());
} }
private String getChunkDataFile(ChunkCoordinate chunkCoordinate) { @EventHandler (ignoreCancelled = true)
return chunkCoordinate.x() + "," + chunkCoordinate.z() + ".ccd"; public void onWorldSave(WorldSaveEvent event) {
World world = event.getWorld();
worldManager.getCustomCropsWorld(world).ifPresent(CustomCropsWorld::save);
} }
private File getChunkDataFilePath(World world, ChunkCoordinate chunkCoordinate) { @Deprecated
private String getChunkDataFile(ChunkPos chunkPos) {
return chunkPos.x() + "," + chunkPos.z() + ".ccd";
}
private String getRegionDataFile(RegionPos regionPos) {
return "r." + regionPos.x() + "." + regionPos.z() + ".mcc";
}
@Deprecated
private File getChunkDataFilePath(World world, ChunkPos chunkPos) {
if (worldFolder.isEmpty()) { if (worldFolder.isEmpty()) {
return new File(world.getWorldFolder(), "customcrops" + File.separator + getChunkDataFile(chunkCoordinate)); return new File(world.getWorldFolder(), "customcrops" + File.separator + getChunkDataFile(chunkPos));
} else { } else {
return new File(worldFolder, world.getName() + File.separator + "customcrops" + File.separator + getChunkDataFile(chunkCoordinate)); return new File(worldFolder, world.getName() + File.separator + "customcrops" + File.separator + getChunkDataFile(chunkPos));
}
}
private File getRegionDataFilePath(World world, RegionPos regionPos) {
if (worldFolder.isEmpty()) {
return new File(world.getWorldFolder(), "customcrops" + File.separator + getRegionDataFile(regionPos));
} else {
return new File(worldFolder, world.getName() + File.separator + "customcrops" + File.separator + getRegionDataFile(regionPos));
} }
} }
@@ -202,12 +289,51 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
this.worldFolder = folder; this.worldFolder = folder;
} }
public byte[] serialize(CChunk chunk) { public byte[] serialize(CustomCropsRegion region) {
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream(); ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
DataOutputStream outStream = new DataOutputStream(outByteStream); DataOutputStream outStream = new DataOutputStream(outByteStream);
SerializableChunk serializableChunk = toSerializableChunk(chunk);
try { try {
outStream.writeByte(version); outStream.writeByte(regionVersion);
outStream.writeInt(region.getRegionPos().x());
outStream.writeInt(region.getRegionPos().z());
Map<ChunkPos, byte[]> map = region.getRegionDataToSave();
outStream.writeInt(map.size());
for (Map.Entry<ChunkPos, byte[]> entry : map.entrySet()) {
outStream.writeInt(entry.getKey().x());
outStream.writeInt(entry.getKey().z());
byte[] dataArray = entry.getValue();
outStream.writeInt(dataArray.length);
outStream.write(dataArray);
}
} catch (IOException e) {
e.printStackTrace();
}
return outByteStream.toByteArray();
}
public CRegion deserializeRegion(CWorld world, DataInputStream dataStream) throws IOException {
int regionVersion = dataStream.readByte();
int regionX = dataStream.readInt();
int regionZ = dataStream.readInt();
RegionPos regionPos = RegionPos.of(regionX, regionZ);
ConcurrentHashMap<ChunkPos, byte[]> map = new ConcurrentHashMap<>();
int chunkAmount = dataStream.readInt();
for (int i = 0; i < chunkAmount; i++) {
int chunkX = dataStream.readInt();
int chunkZ = dataStream.readInt();
ChunkPos chunkPos = ChunkPos.of(chunkX, chunkZ);
byte[] chunkData = new byte[dataStream.readInt()];
dataStream.read(chunkData);
map.put(chunkPos, chunkData);
}
return new CRegion(world, regionPos, map);
}
public byte[] serialize(SerializableChunk serializableChunk) {
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
DataOutputStream outStream = new DataOutputStream(outByteStream);
try {
outStream.writeByte(chunkVersion);
byte[] serializedSections = serializeChunk(serializableChunk); byte[] serializedSections = serializeChunk(serializableChunk);
byte[] compressed = Zstd.compress(serializedSections); byte[] compressed = Zstd.compress(serializedSections);
outStream.writeInt(compressed.length); outStream.writeInt(compressed.length);
@@ -219,8 +345,8 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
return outByteStream.toByteArray(); return outByteStream.toByteArray();
} }
public CChunk deserialize(CWorld world, DataInputStream dataStream) throws IOException { public CChunk deserializeChunk(CWorld world, DataInputStream dataStream) throws IOException {
int worldVersion = dataStream.readByte(); int chunkVersion = dataStream.readByte();
byte[] blockData = readCompressedBytes(dataStream); byte[] blockData = readCompressedBytes(dataStream);
return deserializeChunk(world, blockData); return deserializeChunk(world, blockData);
} }
@@ -231,7 +357,7 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
// read coordinate // read coordinate
int x = chunkData.readInt(); int x = chunkData.readInt();
int z = chunkData.readInt(); int z = chunkData.readInt();
ChunkCoordinate coordinate = new ChunkCoordinate(x, z); ChunkPos coordinate = new ChunkPos(x, z);
// read loading info // read loading info
int loadedSeconds = chunkData.readInt(); int loadedSeconds = chunkData.readInt();
long lastLoadedTime = chunkData.readLong(); long lastLoadedTime = chunkData.readLong();
@@ -362,10 +488,10 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
} }
public SerializableChunk toSerializableChunk(CChunk chunk) { public SerializableChunk toSerializableChunk(CChunk chunk) {
ChunkCoordinate chunkCoordinate = chunk.getChunkCoordinate(); ChunkPos chunkPos = chunk.getChunkPos();
return new SerializableChunk( return new SerializableChunk(
chunkCoordinate.x(), chunkPos.x(),
chunkCoordinate.z(), chunkPos.z(),
chunk.getLoadedSeconds(), chunk.getLoadedSeconds(),
chunk.getLastLoadedTime(), chunk.getLastLoadedTime(),
Arrays.stream(chunk.getSectionsForSerialization()).map(this::toSerializableSection).toList(), Arrays.stream(chunk.getSectionsForSerialization()).map(this::toSerializableSection).toList(),
@@ -451,7 +577,7 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
return outByteStream.toByteArray(); return outByteStream.toByteArray();
} }
public void convertWorld(@Nullable CWorld cWorld, World world) { public void convertWorldFromV33toV34(@Nullable CWorld cWorld, World world) {
// handle legacy files // handle legacy files
File leagcyFile = new File(world.getWorldFolder(), "customcrops" + File.separator + "data.yml"); File leagcyFile = new File(world.getWorldFolder(), "customcrops" + File.separator + "data.yml");
if (leagcyFile.exists()) { if (leagcyFile.exists()) {
@@ -477,11 +603,14 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
LogUtils.warn("Converting chunks for world " + world.getName() + " from 3.3 to 3.4... This might take some time."); LogUtils.warn("Converting chunks for world " + world.getName() + " from 3.3 to 3.4... This might take some time.");
File[] data_files = folder.listFiles(); File[] data_files = folder.listFiles();
if (data_files == null) return; if (data_files == null) return;
HashMap<RegionPos, CustomCropsRegion> regionHashMap = new HashMap<>();
for (File file : data_files) { for (File file : data_files) {
ChunkCoordinate chunkCoordinate = ChunkCoordinate.getByString(file.getName().substring(0, file.getName().length() - 7)); ChunkPos chunkPos = ChunkPos.getByString(file.getName().substring(0, file.getName().length() - 7));
try (FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis)) { try (FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis)) {
CCChunk chunk = (CCChunk) ois.readObject(); CCChunk chunk = (CCChunk) ois.readObject();
CChunk cChunk = new CChunk(cWorld, chunkCoordinate); CChunk cChunk = new CChunk(cWorld, chunkPos);
for (net.momirealms.customcrops.api.object.world.SimpleLocation legacyLocation : chunk.getGreenhouseSet()) { for (net.momirealms.customcrops.api.object.world.SimpleLocation legacyLocation : chunk.getGreenhouseSet()) {
SimpleLocation simpleLocation = new SimpleLocation(legacyLocation.getWorldName(), legacyLocation.getX(), legacyLocation.getY(), legacyLocation.getZ()); SimpleLocation simpleLocation = new SimpleLocation(legacyLocation.getWorldName(), legacyLocation.getX(), legacyLocation.getY(), legacyLocation.getZ());
cChunk.addGlassAt(new MemoryGlass(simpleLocation), simpleLocation); cChunk.addGlassAt(new MemoryGlass(simpleLocation), simpleLocation);
@@ -506,19 +635,56 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
Fertilizer fertilizer = entry.getValue().getFertilizer(); Fertilizer fertilizer = entry.getValue().getFertilizer();
cChunk.addPotAt(new MemoryPot(simpleLocation, entry.getValue().getKey(), entry.getValue().getWater(), fertilizer == null ? "" : fertilizer.getKey(), fertilizer == null ? 0 : fertilizer.getTimes()), simpleLocation); cChunk.addPotAt(new MemoryPot(simpleLocation, entry.getValue().getKey(), entry.getValue().getWater(), fertilizer == null ? "" : fertilizer.getKey(), fertilizer == null ? 0 : fertilizer.getTimes()), simpleLocation);
} }
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(getChunkDataFilePath(world, cChunk.getChunkCoordinate())))) { CustomCropsRegion region = regionHashMap.get(chunkPos.getRegionPos());
bos.write(serialize(cChunk)); if (region == null) {
} catch (IOException e) { region = new CRegion(cWorld, chunkPos.getRegionPos());
LogUtils.severe("Failed to save CustomCrops data."); regionHashMap.put(chunkPos.getRegionPos(), region);
e.printStackTrace();
} }
region.saveChunk(chunkPos, serialize(toSerializableChunk(cChunk)));
} catch (IOException | ClassNotFoundException e) { } catch (IOException | ClassNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
LogUtils.info("Error at " + file.getAbsolutePath()); LogUtils.info("Error at " + file.getAbsolutePath());
} }
} }
LogUtils.info("Successfully converted chunks for world: " + world); for (CustomCropsRegion region : regionHashMap.values()) {
saveRegion(region);
} }
LogUtils.info("Successfully converted chunks for world: " + world.getName());
}
}
public void convertWorldFromV342toV343(@Nullable CWorld cWorld, World world) {
File folder = new File(world.getWorldFolder(), "customcrops");
if (!folder.exists()) return;
LogUtils.warn("Converting chunks for world " + world.getName() + " from 3.4.2 to 3.4.3... This might take some time.");
File[] data_files = folder.listFiles();
if (data_files == null) return;
HashMap<RegionPos, CustomCropsRegion> regionHashMap = new HashMap<>();
for (File file : data_files) {
String fileName = file.getName();
if (fileName.endsWith(".ccd")) {
String chunkStr = file.getName().substring(0, fileName.length()-4);
ChunkPos chunkPos = ChunkPos.getByString(chunkStr);
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
DataInputStream dataStream = new DataInputStream(bis);
byte[] chunkData = dataStream.readAllBytes();
dataStream.close();
CustomCropsRegion region = regionHashMap.get(chunkPos.getRegionPos());
if (region == null) {
region = new CRegion(cWorld, chunkPos.getRegionPos());
regionHashMap.put(chunkPos.getRegionPos(), region);
}
region.saveChunk(chunkPos, chunkData);
} catch (IOException e) {
e.printStackTrace();
}
file.delete();
}
}
for (CustomCropsRegion region : regionHashMap.values()) {
saveRegion(region);
}
LogUtils.info("Successfully converted chunks for world: " + world.getName());
} }
} }

View File

@@ -23,10 +23,11 @@ import com.infernalsuite.aswm.api.events.LoadSlimeWorldEvent;
import com.infernalsuite.aswm.api.world.SlimeWorld; import com.infernalsuite.aswm.api.world.SlimeWorld;
import net.momirealms.customcrops.api.CustomCropsPlugin; import net.momirealms.customcrops.api.CustomCropsPlugin;
import net.momirealms.customcrops.api.manager.WorldManager; import net.momirealms.customcrops.api.manager.WorldManager;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate;
import net.momirealms.customcrops.api.mechanic.world.BlockPos; import net.momirealms.customcrops.api.mechanic.world.BlockPos;
import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsRegion;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
import net.momirealms.customcrops.api.mechanic.world.level.WorldInfoData; import net.momirealms.customcrops.api.mechanic.world.level.WorldInfoData;
import net.momirealms.customcrops.api.util.LogUtils; import net.momirealms.customcrops.api.util.LogUtils;
@@ -65,13 +66,13 @@ public class SlimeWorldAdaptor extends BukkitWorldAdaptor {
} }
@Override @Override
public void unload(CustomCropsWorld customCropsWorld) { public void saveInfoData(CustomCropsWorld customCropsWorld) {
SlimeWorld slimeWorld = slimePlugin.getWorld(customCropsWorld.getWorldName()); SlimeWorld slimeWorld = slimePlugin.getWorld(customCropsWorld.getWorldName());
if (slimeWorld == null) { if (slimeWorld == null) {
super.unload(customCropsWorld); super.saveInfoData(customCropsWorld);
return; return;
} }
CWorld cWorld = (CWorld) customCropsWorld;
Optional<CompoundTag> optionalCompoundTag = slimeWorld.getExtraData().getAsCompoundTag("customcrops"); Optional<CompoundTag> optionalCompoundTag = slimeWorld.getExtraData().getAsCompoundTag("customcrops");
if (optionalCompoundTag.isEmpty()) { if (optionalCompoundTag.isEmpty()) {
LogUtils.warn("Failed to unload data for world " + customCropsWorld.getWorldName() + " because slime world format is incorrect."); LogUtils.warn("Failed to unload data for world " + customCropsWorld.getWorldName() + " because slime world format is incorrect.");
@@ -80,9 +81,16 @@ public class SlimeWorldAdaptor extends BukkitWorldAdaptor {
CompoundMap ccDataMap = optionalCompoundTag.get().getValue(); CompoundMap ccDataMap = optionalCompoundTag.get().getValue();
ccDataMap.put(new StringTag("world-info", gson.toJson(customCropsWorld.getInfoData()))); ccDataMap.put(new StringTag("world-info", gson.toJson(customCropsWorld.getInfoData())));
for (CChunk chunk : cWorld.getAllChunksToSave()) {
ccDataMap.put(chunkToTag(chunk));
} }
@Override
public void unload(CustomCropsWorld customCropsWorld) {
SlimeWorld slimeWorld = slimePlugin.getWorld(customCropsWorld.getWorldName());
if (slimeWorld == null) {
super.unload(customCropsWorld);
return;
}
customCropsWorld.save();
} }
@Override @Override
@@ -108,64 +116,97 @@ public class SlimeWorldAdaptor extends BukkitWorldAdaptor {
} }
@Override @Override
public void loadDynamicData(CustomCropsWorld customCropsWorld, ChunkCoordinate chunkCoordinate) { public void loadChunkData(CustomCropsWorld customCropsWorld, ChunkPos chunkPos) {
SlimeWorld slimeWorld = slimePlugin.getWorld(customCropsWorld.getWorldName()); SlimeWorld slimeWorld = slimePlugin.getWorld(customCropsWorld.getWorldName());
if (slimeWorld == null) { if (slimeWorld == null) {
super.loadDynamicData(customCropsWorld, chunkCoordinate); super.loadChunkData(customCropsWorld, chunkPos);
return; return;
} }
long time1 = System.currentTimeMillis();
CWorld cWorld = (CWorld) customCropsWorld; CWorld cWorld = (CWorld) customCropsWorld;
// load lazy chunks firstly // load lazy chunks firstly
CustomCropsChunk lazyChunk = customCropsWorld.removeLazyChunkAt(chunkCoordinate); CustomCropsChunk lazyChunk = customCropsWorld.removeLazyChunkAt(chunkPos);
if (lazyChunk != null) { if (lazyChunk != null) {
CChunk cChunk = (CChunk) lazyChunk; CChunk cChunk = (CChunk) lazyChunk;
cChunk.setUnloadedSeconds(0); cChunk.setUnloadedSeconds(0);
cWorld.loadChunk(cChunk); cWorld.loadChunk(cChunk);
long time2 = System.currentTimeMillis();
CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to load chunk " + chunkPos + " from lazy chunks");
return; return;
} }
Optional<CompoundTag> optionalCompoundTag = slimeWorld.getExtraData().getAsCompoundTag("customcrops"); Optional<CompoundTag> optionalCompoundTag = slimeWorld.getExtraData().getAsCompoundTag("customcrops");
if (optionalCompoundTag.isEmpty()) { if (optionalCompoundTag.isEmpty()) {
LogUtils.warn("Failed to load data for " + chunkCoordinate + " in world " + customCropsWorld.getWorldName() + " because slime world format is incorrect."); LogUtils.warn("Failed to load data for " + chunkPos + " in world " + customCropsWorld.getWorldName() + " because slime world format is incorrect.");
return; return;
} }
Tag<?> chunkTag = optionalCompoundTag.get().getValue().get(chunkCoordinate.toString()); Tag<?> chunkTag = optionalCompoundTag.get().getValue().get(chunkPos.getAsString());
if (chunkTag == null) return; if (chunkTag == null) {
return;
}
Optional<CompoundTag> chunkCompoundTag = chunkTag.getAsCompoundTag(); Optional<CompoundTag> chunkCompoundTag = chunkTag.getAsCompoundTag();
if (chunkCompoundTag.isEmpty()) return; if (chunkCompoundTag.isEmpty()) {
return;
}
// load chunk from local files // load chunk from slime world
long time1 = System.currentTimeMillis();
cWorld.loadChunk(tagToChunk(cWorld, chunkCompoundTag.get())); cWorld.loadChunk(tagToChunk(cWorld, chunkCompoundTag.get()));
long time2 = System.currentTimeMillis(); long time2 = System.currentTimeMillis();
CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to load chunk " + chunkCoordinate); CustomCropsPlugin.get().debug("Took " + (time2-time1) + "ms to load chunk " + chunkPos);
} }
@Override @Override
public void saveDynamicData(CustomCropsWorld customCropsWorld, CustomCropsChunk chunk) { public void saveChunkToCachedRegion(CustomCropsChunk customCropsChunk) {
SlimeWorld slimeWorld = getSlimeWorld(customCropsWorld.getWorldName()); CustomCropsWorld customCropsWorld = customCropsChunk.getCustomCropsWorld();
SlimeWorld slimeWorld = getSlimeWorld(customCropsChunk.getCustomCropsWorld().getWorldName());
if (slimeWorld == null) { if (slimeWorld == null) {
super.saveDynamicData(customCropsWorld, chunk); super.saveChunkToCachedRegion(customCropsChunk);
return; return;
} }
Optional<CompoundTag> optionalCompoundTag = slimeWorld.getExtraData().getAsCompoundTag("customcrops"); Optional<CompoundTag> optionalCompoundTag = slimeWorld.getExtraData().getAsCompoundTag("customcrops");
if (optionalCompoundTag.isEmpty()) { if (optionalCompoundTag.isEmpty()) {
LogUtils.warn("Failed to save data for " + chunk + " in world " + customCropsWorld.getWorldName() + " because slime world format is incorrect."); LogUtils.warn("Failed to save data for " + customCropsChunk.getChunkPos() + " in world " + customCropsWorld.getWorldName() + " because slime world format is incorrect.");
return; return;
} }
CustomCropsPlugin.get().getScheduler().runTaskSync(() -> optionalCompoundTag.get().getValue().put(chunkToTag((CChunk) chunk)), null); SerializableChunk serializableChunk = toSerializableChunk((CChunk) customCropsChunk);
if (Bukkit.isPrimaryThread()) {
if (serializableChunk.canPrune()) {
optionalCompoundTag.get().getValue().remove(customCropsChunk.getChunkPos().getAsString());
} else {
optionalCompoundTag.get().getValue().put(chunkToTag(serializableChunk));
}
} else {
CustomCropsPlugin.get().getScheduler().runTaskSync(() -> {
if (serializableChunk.canPrune()) {
optionalCompoundTag.get().getValue().remove(customCropsChunk.getChunkPos().getAsString());
} else {
optionalCompoundTag.get().getValue().put(chunkToTag(serializableChunk));
}
}, null);
}
}
@Override
public void saveRegion(CustomCropsRegion customCropsRegion) {
CustomCropsWorld customCropsWorld = customCropsRegion.getCustomCropsWorld();
SlimeWorld slimeWorld = getSlimeWorld(customCropsWorld.getWorldName());
if (slimeWorld == null) {
super.saveRegion(customCropsRegion);
return;
}
// don't need to save region to slime world
} }
private SlimeWorld getSlimeWorld(String name) { private SlimeWorld getSlimeWorld(String name) {
return slimePlugin.getWorld(name); return slimePlugin.getWorld(name);
} }
private CompoundTag chunkToTag(CChunk chunk) { private CompoundTag chunkToTag(SerializableChunk serializableChunk) {
SerializableChunk serializableChunk = toSerializableChunk(chunk);
CompoundMap map = new CompoundMap(); CompoundMap map = new CompoundMap();
map.put(new IntTag("x", serializableChunk.getX())); map.put(new IntTag("x", serializableChunk.getX()));
map.put(new IntTag("z", serializableChunk.getZ())); map.put(new IntTag("z", serializableChunk.getZ()));
@@ -178,7 +219,7 @@ public class SlimeWorldAdaptor extends BukkitWorldAdaptor {
sectionMap.put(new ListTag<>(String.valueOf(section.getSectionID()), TagType.TAG_COMPOUND, section.getBlocks())); sectionMap.put(new ListTag<>(String.valueOf(section.getSectionID()), TagType.TAG_COMPOUND, section.getBlocks()));
} }
map.put(new CompoundTag("sections", sectionMap)); map.put(new CompoundTag("sections", sectionMap));
return new CompoundTag(chunk.getChunkCoordinate().toString(), map); return new CompoundTag(serializableChunk.getX() + "," + serializableChunk.getZ(), map);
} }
private CChunk tagToChunk(CWorld cWorld, CompoundTag tag) { private CChunk tagToChunk(CWorld cWorld, CompoundTag tag) {
@@ -186,7 +227,7 @@ public class SlimeWorldAdaptor extends BukkitWorldAdaptor {
CompoundMap map = tag.getValue(); CompoundMap map = tag.getValue();
int x = map.get("x").getAsIntTag().get().getValue(); int x = map.get("x").getAsIntTag().get().getValue();
int z = map.get("z").getAsIntTag().get().getValue(); int z = map.get("z").getAsIntTag().get().getValue();
ChunkCoordinate coordinate = new ChunkCoordinate(x, z); ChunkPos coordinate = new ChunkPos(x, z);
int loadedSeconds = map.get("loadedSeconds").getAsIntTag().get().getValue(); int loadedSeconds = map.get("loadedSeconds").getAsIntTag().get().getValue();
long lastLoadedTime = map.get("lastLoadedTime").getAsLongTag().get().getValue(); long lastLoadedTime = map.get("lastLoadedTime").getAsLongTag().get().getValue();
int[] queued = map.get("queued").getAsIntArrayTag().get().getValue(); int[] queued = map.get("queued").getAsIntArrayTag().get().getValue();

View File

@@ -1,5 +1,5 @@
# Don't change # Don't change
config-version: '35' config-version: '36'
# Debug # Debug
debug: false debug: false