diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index 55c07995f..71a1c68ae 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -4,10 +4,14 @@ repositories { maven("https://r.irepo.space/maven/") maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // papi maven("https://maven.enginehub.org/repo/") // worldguard worldedit + maven("https://repo.rapture.pw/repository/maven-releases/") // slime world + maven("https://repo.infernalsuite.com/repository/maven-snapshots/") // slime world + maven("https://repo.momirealms.net/releases/") } dependencies { compileOnly(project(":core")) + compileOnly("net.momirealms:sparrow-nbt:${rootProject.properties["sparrow_nbt_version"]}") // Platform compileOnly("dev.folia:folia-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT") // NeigeItems @@ -17,6 +21,8 @@ dependencies { // WorldEdit compileOnly("com.sk89q.worldedit:worldedit-core:7.2.19") compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.19") + // SlimeWorld + compileOnly("com.infernalsuite.asp:api:4.0.0-SNAPSHOT") } java { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java new file mode 100644 index 000000000..b5ce5a6e6 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.bukkit.compatibility.slimeworld; + +import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; +import com.infernalsuite.asp.api.events.LoadSlimeWorldEvent; +import com.infernalsuite.asp.api.world.SlimeWorld; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldManager; +import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; + +public class SlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements Listener { + private final WorldManager worldManager; + + @EventHandler + public void onWorldLoad(LoadSlimeWorldEvent event) { + org.bukkit.World world = Bukkit.getWorld(event.getSlimeWorld().getName()); + this.worldManager.loadWorld(this.worldManager.wrap(world)); + } + + public SlimeFormatStorageAdaptor(WorldManager worldManager) { + this.worldManager = worldManager; + } + + public SlimeWorld getWorld(String name) { + return AdvancedSlimePaperAPI.instance().getLoadedWorld(name); + } + + @Override + public @NotNull WorldDataStorage adapt(@NotNull World world) { + SlimeWorld slimeWorld = getWorld(world.name()); + if (slimeWorld == null) { + return super.adapt(world); + } + return new SlimeWorldDataStorage(slimeWorld); + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java new file mode 100644 index 000000000..b9b63ded4 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java @@ -0,0 +1,68 @@ +package net.momirealms.craftengine.bukkit.compatibility.slimeworld; + +import com.infernalsuite.asp.api.world.SlimeChunk; +import com.infernalsuite.asp.api.world.SlimeWorld; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.ByteArrayBinaryTag; +import net.momirealms.craftengine.core.world.ChunkPos; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.NBT; +import org.jetbrains.annotations.Nullable; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.lang.ref.WeakReference; + +public class SlimeWorldDataStorage implements WorldDataStorage { + private final WeakReference slimeWorld; + + public SlimeWorldDataStorage(SlimeWorld slimeWorld) { + this.slimeWorld = new WeakReference<>(slimeWorld); + } + + public SlimeWorld getWorld() { + return slimeWorld.get(); + } + + @Nullable + @Override + public CompoundTag readChunkTagAt(ChunkPos pos) { + SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); + if (slimeChunk == null) return null; + BinaryTag tag = slimeChunk.getExtraData().get("craftengine"); + if (tag == null) return null; + ByteArrayBinaryTag byteArrayBinaryTag = (ByteArrayBinaryTag) tag; + try { + return NBT.readCompound(new DataInputStream(new ByteArrayInputStream(byteArrayBinaryTag.value()))); + } catch (IOException e) { + throw new RuntimeException("Failed to read chunk tag from slime world. " + pos, e); + } + } + + @Override + public void writeChunkTagAt(ChunkPos pos, @Nullable CompoundTag nbt) { + SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); + if (slimeChunk == null) return; + if (nbt == null) { + slimeChunk.getExtraData().remove("craftengine"); + } else { + slimeChunk.getExtraData().computeIfAbsent("craftengine", l -> { + try { + return ByteArrayBinaryTag.byteArrayBinaryTag(NBT.toBytes(nbt)); + } catch (IOException e) { + throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e); + } + }); + } + } + + @Override + public void flush() { + } + + @Override + public void close() throws IOException { + } +} diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index f7678758f..3c8d218d6 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -62,4 +62,4 @@ categories: - default:flame_cane - default:gunpowder_block - default:solid_gunpowder_block - - default:ender_pearl_flower_seed \ No newline at end of file + - default:ender_pearl_flower_seeds \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index 23a9f8b8a..51b178e1b 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -4,7 +4,7 @@ i18n: item.fairy_flower: "Fairy Flower" item.reed: "Reed" item.flame_cane: "Flame Cane" - item.ender_pearl_flower_seed: "Ender Pearl Flower Seeds" + item.ender_pearl_flower_seeds: "Ender Pearl Flower Seeds" item.bench: "Bench" item.table_lamp: "Table Lamp" item.wooden_chair: "Wooden Chair" @@ -44,7 +44,7 @@ i18n: item.fairy_flower: "仙灵花" item.reed: "芦苇" item.flame_cane: "烈焰甘蔗" - item.ender_pearl_flower_seed: "末影珍珠花种子" + item.ender_pearl_flower_seeds: "末影珍珠花种子" item.bench: "长椅" item.table_lamp: "台灯" item.wooden_chair: "木椅" diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/icons.yml b/bukkit/loader/src/main/resources/resources/default/configuration/icons.yml index 47cda9d4c..6b2db4498 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/icons.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/icons.yml @@ -2,7 +2,7 @@ images: default:icons: height: 10 ascent: 9 - font: minecraft:default # Consider using other fonts if other plugins support custom font! + font: minecraft:icons # Do not use 'minecraft:default' unless other plugins don't support custom font! file: minecraft:font/image/icons.png chars: - '\ub000\ub001' diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index e5e40e9d5..989ef3b9a 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -35,15 +35,15 @@ items: behavior: type: block_item block: default:flame_cane - default:ender_pearl_flower_seed: + default:ender_pearl_flower_seeds: material: paper custom-model-data: 4003 data: - item-name: "" + item-name: "" model: template: default:model/simplified_generated arguments: - path: "minecraft:block/custom/ender_pearl_flower_seed" + path: "minecraft:item/custom/ender_pearl_flower_seeds" behavior: type: block_item block: default:ender_pearl_flower @@ -185,45 +185,53 @@ blocks: - default:hardness/none - default:sound/grass overrides: - item: default:ender_pearl_flower_seed + item: default:ender_pearl_flower_seeds push-reaction: DESTROY map-color: 24 is-randomly-ticking: true behavior: type: crop_block - grow-speed: 1 - min-grow-light: 9 + grow-speed: 0.25 + light-requirement: 9 bottom-blocks: - minecraft:end_stone loot: template: default:loot_table/seed_crop arguments: crop_item: minecraft:ender_pearl - crop_seed: default:ender_pearl_flower_seed - ripe_age: 3 + crop_seed: default:ender_pearl_flower_seeds + ripe_age: 2 states: properties: age: type: int default: 0 - range: 0~3 + range: 0~2 appearances: stage_0: state: "tripwire:0" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_0" + generation: + parent: "minecraft:block/cross" + textures: + "cross": "minecraft:block/custom/ender_pearl_flower_stage_0" stage_1: state: "tripwire:1" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_1" + generation: + parent: "minecraft:block/cross" + textures: + "cross": "minecraft:block/custom/ender_pearl_flower_stage_1" stage_2: state: "tripwire:2" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_2" - stage_3: - state: "sugar_cane:3" - models: - - path: "minecraft:block/custom/ender_pearl_flower_stage_3" + generation: + parent: "minecraft:block/cross" + textures: + "cross": "minecraft:block/custom/ender_pearl_flower_stage_2" variants: age=0: appearance: stage_0 @@ -234,9 +242,6 @@ blocks: age=2: appearance: stage_2 id: 2 - age=3: - appearance: stage_3 - id: 8 recipes: default:paper_from_reed: type: shaped @@ -269,8 +274,9 @@ recipes: result: id: minecraft:magma_block count: 2 + vanilla-loots: - minecraft:ender_pearl_flower_seed_from_endermite: + minecraft:ender_pearl_flower_seeds_from_endermite: type: entity target: "minecraft:endermite" override: false @@ -287,4 +293,4 @@ vanilla-loots: - 1 entries: - type: item - item: "default:ender_pearl_flower_seed" \ No newline at end of file + item: "default:ender_pearl_flower_seeds" \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json new file mode 100644 index 000000000..c65bc426f --- /dev/null +++ b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json @@ -0,0 +1,43 @@ +{ + "ambientocclusion": false, + "textures": { + "1": "item/ender_pearl", + "particle": "block/custom/ender_pearl_flower_stage_3", + "cross": "block/custom/ender_pearl_flower_stage_3" + }, + "elements": [ + { + "from": [0.8, 0, 8], + "to": [15.2, 16, 8], + "shade": false, + "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#cross"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#cross"} + } + }, + { + "from": [8, 0, 0.8], + "to": [8, 16, 15.2], + "shade": false, + "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, + "faces": { + "east": {"uv": [0, 0, 16, 16], "texture": "#cross"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#cross"} + } + }, + { + "from": [8, 5, -1], + "to": [8, 21, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 5, 7]}, + "faces": { + "north": {"uv": [0, 0, 0, 16], "texture": "#1"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "south": {"uv": [0, 0, 0, 16], "texture": "#1"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "up": {"uv": [0, 0, 0, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 0, 16], "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_0.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_0.png new file mode 100644 index 000000000..4cd8a2d81 Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_0.png differ diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_1.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_1.png new file mode 100644 index 000000000..93c0ebc31 Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_1.png differ diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_2.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_2.png new file mode 100644 index 000000000..1fd5925e4 Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_2.png differ diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png new file mode 100644 index 000000000..358b7874c Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png differ diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/ender_pearl_flower_seeds.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/ender_pearl_flower_seeds.png new file mode 100644 index 000000000..48b377350 Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/ender_pearl_flower_seeds.png differ diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 21e375a24..5fcaaba2e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -34,46 +34,16 @@ public class CropBlockBehavior extends BushBlockBehavior { this.minGrowLight = minGrowLight; } - public final boolean isMaxAge(Object state) { - return this.getAge(state) >= this.ageProperty.max; - } - - public final boolean isMaxAge(ImmutableBlockState state) { - return this.getAge(state) >= this.ageProperty.max; - } - - public static ImmutableBlockState getCEBlockState(Object nmsState) { - return BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(nmsState)); - } - - public final int getAge(Object state) { - return getCEBlockState(state).get(ageProperty); - } - public final int getAge(ImmutableBlockState state) { return state.get(ageProperty); } - public Object getStateForAge(Object state, int age) { - ImmutableBlockState afterState = getCEBlockState(state).owner().value().defaultState().with(ageProperty, age); - return afterState.customBlockState().handle(); - } - - public void growCrops(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException { - int i = this.getAge(state) + RandomUtils.generateRandomInt(2, 5); - int maxAge = this.ageProperty.max; - if (i > maxAge) { - i = maxAge; - } - Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, i), UpdateOption.UPDATE_NONE.flags()); - } - private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { return (int) Reflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0); } private boolean hasSufficientLight(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { - return getRawBrightness(level, pos) >= minGrowLight - 1; + return getRawBrightness(level, pos) >= this.minGrowLight - 1; } @Override @@ -81,11 +51,13 @@ public class CropBlockBehavior extends BushBlockBehavior { Object state = args[0]; Object level = args[1]; Object pos = args[2]; - if (getRawBrightness(level, pos) >= minGrowLight) { - int age = this.getAge(state); - float randomFloat = RandomUtils.generateRandomFloat(0, 1); - if (age < this.ageProperty.max && randomFloat < 1.0 / Math.floor(25.0 / this.growSpeed + 1.0)) { - Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, age + 1), UpdateOption.UPDATE_ALL.flags()); + if (getRawBrightness(level, pos) >= this.minGrowLight) { + ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); + if (currentState != null && !currentState.isEmpty()) { + int age = this.getAge(currentState); + if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { + Reflections.method$Level$setBlock.invoke(level, pos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + } } } } @@ -103,12 +75,30 @@ public class CropBlockBehavior extends BushBlockBehavior { @Override public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) { Object state = args[2]; - return !this.isMaxAge(state); + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); + if (immutableBlockState != null && !immutableBlockState.isEmpty()) { + return getAge(immutableBlockState) != this.ageProperty.max; + } else { + return false; + } } @Override public void performBoneMeal(Object thisBlock, Object[] args) throws Exception { - this.growCrops(args[0], args[2], args[3]); + this.performBoneMeal(args[0], args[2], args[3]); + } + + private void performBoneMeal(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException { + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); + if (immutableBlockState == null || immutableBlockState.isEmpty()) { + return; + } + int i = this.getAge(immutableBlockState) + RandomUtils.generateRandomInt(2, 5); + int maxAge = this.ageProperty.max; + if (i > maxAge) { + i = maxAge; + } + Reflections.method$Level$setBlock.invoke(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); } public static class Factory implements BlockBehaviorFactory { @@ -122,8 +112,8 @@ public class CropBlockBehavior extends BushBlockBehavior { throw new IllegalArgumentException("age property not set for crop"); } // 存活条件是最小生长亮度-1 - int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("min-grow-light", 9)); - float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1)); + int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("light-requirement", 9)); + float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.25f)); return new CropBlockBehavior(tuple.left(), tuple.mid(), tuple.right(), ageProperty, growSpeed, minGrowLight); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java index b5cddf244..fb4f0e365 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java @@ -5,11 +5,12 @@ import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.util.SectionPosUtils; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; public class BukkitCEWorld extends CEWorld { - public BukkitCEWorld(World world) { - super(world); + public BukkitCEWorld(World world, StorageAdaptor adaptor) { + super(world, adaptor); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 8248c227f..623540d88 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.world; +import net.momirealms.craftengine.bukkit.compatibility.slimeworld.SlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; @@ -8,6 +9,7 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.ChunkPos; import net.momirealms.craftengine.core.world.SectionPos; @@ -15,6 +17,8 @@ import net.momirealms.craftengine.core.world.WorldManager; import net.momirealms.craftengine.core.world.chunk.CEChunk; import net.momirealms.craftengine.core.world.chunk.CESection; import net.momirealms.craftengine.core.world.chunk.serialization.ChunkSerializer; +import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; +import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.sparrow.nbt.CompoundTag; import org.bukkit.Bukkit; import org.bukkit.Chunk; @@ -27,6 +31,7 @@ import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.HashMap; @@ -38,18 +43,34 @@ public class BukkitWorldManager implements WorldManager, Listener { private static BukkitWorldManager instance; private final BukkitCraftEngine plugin; private final Map worlds; - private CEWorld[] worldArray; + private CEWorld[] worldArray = new CEWorld[0]; private final ReentrantReadWriteLock worldMapLock = new ReentrantReadWriteLock(); private SchedulerTask tickTask; // cache private UUID lastVisitedUUID; private CEWorld lastVisitedWorld; + private StorageAdaptor storageAdaptor; public BukkitWorldManager(BukkitCraftEngine plugin) { instance = this; this.plugin = plugin; this.worlds = new HashMap<>(); - resetWorldArray(); + if (VersionHelper.isVersionNewerThan1_21_4()) { + try { + Class.forName("com.infernalsuite.asp.api.AdvancedSlimePaperAPI"); + SlimeFormatStorageAdaptor adaptor = new SlimeFormatStorageAdaptor(this); + this.storageAdaptor = adaptor; + Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap()); + return; + } catch (ClassNotFoundException ignored) { + } + } + this.storageAdaptor = new DefaultStorageAdaptor(); + } + + @Override + public void setStorageAdaptor(@NotNull StorageAdaptor storageAdaptor) { + this.storageAdaptor = storageAdaptor; } public static BukkitWorldManager instance() { @@ -95,7 +116,7 @@ public class BukkitWorldManager implements WorldManager, Listener { this.worldMapLock.writeLock().lock(); try { for (World world : Bukkit.getWorlds()) { - CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world)); + CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor); this.worlds.put(world.getUID(), ceWorld); this.resetWorldArray(); for (Chunk chunk : world.getLoadedChunks()) { @@ -110,8 +131,11 @@ public class BukkitWorldManager implements WorldManager, Listener { @Override public void disable() { HandlerList.unregisterAll(this); - if (tickTask != null && !tickTask.cancelled()) { - tickTask.cancel(); + if (this.storageAdaptor instanceof Listener listener) { + HandlerList.unregisterAll(listener); + } + if (this.tickTask != null && !this.tickTask.cancelled()) { + this.tickTask.cancel(); } for (World world : Bukkit.getWorlds()) { @@ -125,14 +149,18 @@ public class BukkitWorldManager implements WorldManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onWorldLoad(WorldLoadEvent event) { - World world = event.getWorld(); - CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world)); + this.loadWorld(new BukkitWorld(event.getWorld())); + } + + @Override + public void loadWorld(net.momirealms.craftengine.core.world.World world) { this.worldMapLock.writeLock().lock(); try { - if (this.worlds.containsKey(world.getUID())) return; - this.worlds.put(event.getWorld().getUID(), ceWorld); + if (this.worlds.containsKey(world.uuid())) return; + CEWorld ceWorld = new BukkitCEWorld(world, this.storageAdaptor); + this.worlds.put(world.uuid(), ceWorld); this.resetWorldArray(); - for (Chunk chunk : world.getLoadedChunks()) { + for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) { handleChunkLoad(ceWorld, chunk); } } finally { @@ -142,11 +170,15 @@ public class BukkitWorldManager implements WorldManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onWorldUnload(WorldUnloadEvent event) { - World world = event.getWorld(); + unloadWorld(new BukkitWorld(event.getWorld())); + } + + @Override + public void unloadWorld(net.momirealms.craftengine.core.world.World world) { CEWorld ceWorld; this.worldMapLock.writeLock().lock(); try { - ceWorld = this.worlds.remove(world.getUID()); + ceWorld = this.worlds.remove(world.uuid()); if (ceWorld == null) { return; } @@ -158,11 +190,20 @@ public class BukkitWorldManager implements WorldManager, Listener { } finally { this.worldMapLock.writeLock().unlock(); } - for (Chunk chunk : world.getLoadedChunks()) { + for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) { handleChunkUnload(ceWorld, chunk); } } + @Override + public net.momirealms.craftengine.core.world.World wrap(T world) { + if (world instanceof World w) { + return new BukkitWorld(w); + } else { + throw new IllegalArgumentException(world.getClass() + " is not a Bukkit World"); + } + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onChunkLoad(ChunkLoadEvent event) { this.worldMapLock.readLock().lock(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 60168df84..8e5093864 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -286,8 +286,6 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/netherite_anvil_top.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/solid_gunpowder_block.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/gunpowder_block.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_1.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_2.png"); // items plugin.saveResource("resources/default/configuration/items.yml"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_rod.png"); @@ -302,7 +300,6 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_1.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_2.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_cane.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid/topaz.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid_leggings/topaz.png"); for (String item : List.of("helmet", "chestplate", "leggings", "boots", "pickaxe", "axe", "sword", "hoe", "shovel")) { @@ -334,8 +331,15 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/fairy_flower_3.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/fairy_flower_4.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/reed.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_1.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_2.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_0.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_1.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_2.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/fairy_flower.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/reed.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_cane.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/ender_pearl_flower_seeds.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/reed.json"); // furniture diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index cae381027..f604df05d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.world; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.world.chunk.CEChunk; -import net.momirealms.craftengine.core.world.chunk.storage.DefaultRegionFileStorage; +import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import org.jetbrains.annotations.Nullable; @@ -25,10 +25,10 @@ public abstract class CEWorld { private CEChunk lastChunk; private long lastChunkPos; - public CEWorld(World world) { + public CEWorld(World world, StorageAdaptor adaptor) { this.world = world; this.loadedChunkMap = new Long2ObjectOpenHashMap<>(1024, 0.5f); - this.worldDataStorage = new DefaultRegionFileStorage(world.directory().resolve(REGION_DIRECTORY)); + this.worldDataStorage = adaptor.adapt(world); this.worldHeightAccessor = world.worldHeight(); this.lastChunkPos = ChunkPos.INVALID_CHUNK_POS; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java index 24f615730..ee5ab39a0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java @@ -1,12 +1,22 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; +import org.jetbrains.annotations.NotNull; import java.util.UUID; public interface WorldManager extends Reloadable { + void setStorageAdaptor(@NotNull StorageAdaptor storageAdaptor); + CEWorld getWorld(UUID uuid); void delayedInit(); + + void loadWorld(World world); + + void unloadWorld(World world); + + World wrap(T world); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java new file mode 100644 index 000000000..9de5d571c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.world.chunk.storage; + +import net.momirealms.craftengine.core.world.CEWorld; +import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.NotNull; + +public class DefaultStorageAdaptor implements StorageAdaptor { + + @Override + public @NotNull WorldDataStorage adapt(@NotNull World world) { + return new DefaultRegionFileStorage(world.directory().resolve(CEWorld.REGION_DIRECTORY)); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/StorageAdaptor.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/StorageAdaptor.java new file mode 100644 index 000000000..8a9790462 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/StorageAdaptor.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.world.chunk.storage; + +import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.NotNull; + +public interface StorageAdaptor { + + @NotNull + WorldDataStorage adapt(@NotNull World world); +} diff --git a/gradle.properties b/gradle.properties index 96a6a3b08..77319d3f9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -40,7 +40,7 @@ geantyref_version=1.3.16 zstd_version=1.5.6-9 commons_io_version=2.17.0 sparrow_nbt_version=0.3 -sparrow_util_version=0.33 +sparrow_util_version=0.34 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8