mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-27 02:49:15 +00:00
add crop block
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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> 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 {
|
||||
}
|
||||
}
|
||||
@@ -62,4 +62,4 @@ categories:
|
||||
- default:flame_cane
|
||||
- default:gunpowder_block
|
||||
- default:solid_gunpowder_block
|
||||
- default:ender_pearl_flower_seed
|
||||
- default:ender_pearl_flower_seeds
|
||||
@@ -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: "木椅"
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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: "<!i><i18n:item.ender_pearl_flower_seed>"
|
||||
item-name: "<!i><i18n:item.ender_pearl_flower_seeds>"
|
||||
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"
|
||||
item: "default:ender_pearl_flower_seeds"
|
||||
@@ -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"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 183 B |
Binary file not shown.
|
After Width: | Height: | Size: 331 B |
Binary file not shown.
|
After Width: | Height: | Size: 455 B |
Binary file not shown.
|
After Width: | Height: | Size: 362 B |
Binary file not shown.
|
After Width: | Height: | Size: 280 B |
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<UUID, CEWorld> 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 <T> 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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
<T> World wrap(T world);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user