9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-28 19:39:11 +00:00

add on liquid blocks

This commit is contained in:
XiaoMoMi
2025-03-22 04:27:20 +08:00
parent 876b41aee1
commit b290af81f7
37 changed files with 518 additions and 62 deletions

View File

@@ -5,12 +5,12 @@ import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.shared.block.EmptyBlockBehavior;
public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key EMPTY = Key.from("craftengine:empty");
public static final Key BUSH_BLOCK = Key.from("craftengine:bush_block");
public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block");
public static final Key LEAVES_BLOCK = Key.from("craftengine:leaves_block");
public static final Key STRIPPABLE_BLOCK = Key.from("craftengine:strippable_block");
public static final Key SAPLING_BLOCK = Key.from("craftengine:sapling_block");
public static final Key ON_LIQUID_BLOCK = Key.from("craftengine:on_liquid_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -19,5 +19,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(LEAVES_BLOCK, LeavesBlockBehavior.FACTORY);
register(STRIPPABLE_BLOCK, StrippableBlockBehavior.FACTORY);
register(SAPLING_BLOCK, SaplingBlockBehavior.FACTORY);
register(ON_LIQUID_BLOCK, OnLiquidBlockBehavior.FACTORY);
}
}

View File

@@ -83,7 +83,9 @@ public class BushBlockBehavior extends BlockBehavior {
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
if (arguments.containsKey("tags")) {
if (arguments.containsKey("bottom-block-tags")) {
return new BushBlockBehavior(MiscUtils.getAsStringList(arguments.get("bottom-block-tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList());
} else if (arguments.containsKey("tags")) {
return new BushBlockBehavior(MiscUtils.getAsStringList(arguments.get("tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList());
} else {
return INSTANCE;
@@ -100,7 +102,7 @@ public class BushBlockBehavior extends BlockBehavior {
return mayPlaceOn(belowState, world, belowPos);
}
private boolean mayPlaceOn(Object belowState, Object world, Object blockPos) throws ReflectiveOperationException {
protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException {
for (Object tag : this.tagsCanSurviveOn) {
if ((boolean) Reflections.method$BlockStateBase$hasTag.invoke(belowState, tag)) {
return true;

View File

@@ -0,0 +1,55 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.shared.block.BlockBehavior;
import java.util.List;
import java.util.Map;
public class OnLiquidBlockBehavior extends BushBlockBehavior {
public static final Factory FACTORY = new Factory();
private final boolean onWater;
private final boolean onLava;
public OnLiquidBlockBehavior(List<Object> tagsCanSurviveOn, boolean onWater, boolean onLava) {
super(tagsCanSurviveOn);
this.onWater = onWater;
this.onLava = onLava;
}
public boolean onWater() {
return this.onWater;
}
public boolean onLava() {
return this.onLava;
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water")));
return new OnLiquidBlockBehavior(List.of(), liquidTypes.contains("water"), liquidTypes.contains("lava"));
}
}
@Override
protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException {
Object fluidState = Reflections.method$Level$getFluidState.invoke(world, belowPos);
Object fluidStateAbove = Reflections.method$Level$getFluidState.invoke(world, LocationUtils.above(belowPos));
if (Reflections.method$FluidState$getType.invoke(fluidStateAbove) != Reflections.instance$Fluids$EMPTY) {
return false;
}
if (this.onWater && (Reflections.method$FluidState$getType.invoke(fluidState) == Reflections.instance$Fluids$WATER || Reflections.field$StateHolder$owner.get(belowState) == Reflections.instance$Blocks$ICE)) {
return true;
}
if (this.onLava && Reflections.method$FluidState$getType.invoke(fluidState) == Reflections.instance$Fluids$LAVA) {
return true;
}
return false;
}
}

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.bukkit.item;
import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.BoneMealBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior;
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
@@ -50,7 +49,6 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.AXES);
registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS);
registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET);
registerVanillaItemExtraBehavior(BoneMealBehavior.INSTANCE, ItemKeys.BONE_MEAL);
}
private static BukkitItemManager instance;

View File

@@ -157,6 +157,8 @@ public class ItemEventListener implements Listener {
}
for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) {
InteractionResult result = itemBehavior.useOnBlock(new UseOnContext(player, hand, hitResult));
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
event.setCancelled(true);

View File

@@ -79,7 +79,7 @@ public class BlockItemBehavior extends ItemBehavior {
BlockPos pos = placeContext.getClickedPos();
BlockPos againstPos = placeContext.getAgainstPos();
World world = (World) placeContext.getLevel().getHandle();
World world = (World) placeContext.getLevel().platformWorld();
Location placeLocation = new Location(world, pos.x(), pos.y(), pos.z());
Block bukkitBlock = world.getBlockAt(placeLocation);
@@ -151,7 +151,7 @@ public class BlockItemBehavior extends ItemBehavior {
Object blockState = state.customBlockState().handle();
Object blockPos = LocationUtils.toBlockPos(context.getClickedPos());
Object voxelShape = Reflections.method$CollisionContext$of.invoke(null, player);
Object world = Reflections.field$CraftWorld$ServerLevel.get(context.getLevel().getHandle());
Object world = Reflections.field$CraftWorld$ServerLevel.get(context.getLevel().platformWorld());
boolean defaultReturn = ((!this.checkStatePlacement() || (boolean) Reflections.method$BlockStateBase$canSurvive.invoke(blockState, world, blockPos))
&& (boolean) Reflections.method$ServerLevel$checkEntityCollision.invoke(world, blockState, player, voxelShape, blockPos, true));
Block block = (Block) Reflections.method$CraftBlock$at.invoke(null, world, blockPos);

View File

@@ -1,27 +0,0 @@
package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.util.Key;
import java.nio.file.Path;
import java.util.Map;
public class BoneMealBehavior extends ItemBehavior {
public static final BoneMealBehavior INSTANCE = new BoneMealBehavior();
@Override
public InteractionResult useOnBlock(UseOnContext context) {
return super.useOnBlock(context);
}
public static class Factory implements ItemBehaviorFactory {
@Override
public ItemBehavior create(Pack pack, Path path, Key id, Map<String, Object> arguments) {
return INSTANCE;
}
}
}

View File

@@ -5,16 +5,17 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviors;
import net.momirealms.craftengine.core.util.Key;
public class BukkitItemBehaviors extends ItemBehaviors {
public static final Key EMPTY = Key.from("craftengine:empty");
public static final Key BLOCK_ITEM = Key.from("craftengine:block_item");
public static final Key ON_LIQUID_BLOCK_ITEM = Key.from("craftengine:liquid_collision_block_item");
public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item");
public static final Key AXE_ITEM = Key.from("craftengine:axe_item");
public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item");
public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item");
public static void init() {
register(EMPTY, (pack, path, args, id) -> EmptyItemBehavior.INSTANCE);
register(EMPTY, EmptyItemBehavior.FACTORY);
register(BLOCK_ITEM, BlockItemBehavior.FACTORY);
register(ON_LIQUID_BLOCK_ITEM, LiquidCollisionBlockItemBehavior.FACTORY);
register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY);
register(AXE_ITEM, AxeItemBehavior.FACTORY);
register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY);

View File

@@ -77,7 +77,7 @@ public class FurnitureItemBehavior extends ItemBehavior {
// trigger event
org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) player.platformPlayer();
World world = (World) context.getLevel().getHandle();
World world = (World) context.getLevel().platformWorld();
// get position and rotation for placement
Vec3d finalPlacePosition;

View File

@@ -0,0 +1,76 @@
package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.world.BlockHitResult;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World;
import java.nio.file.Path;
import java.util.Map;
public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior {
public static final Factory FACTORY = new Factory();
private final int offsetY;
public LiquidCollisionBlockItemBehavior(Key blockId, int offsetY) {
super(blockId);
this.offsetY = offsetY;
}
@Override
public InteractionResult useOnBlock(UseOnContext context) {
return use(context.getLevel(), context.getPlayer(), context.getHand());
}
@Override
public InteractionResult use(World world, Player player, InteractionHand hand) {
try {
Object blockHitResult = Reflections.method$Item$getPlayerPOVHitResult.invoke(null, world.serverWorld(), player.serverPlayer(), Reflections.instance$ClipContext$Fluid$SOURCE_ONLY);
Object blockPos = Reflections.field$BlockHitResul$blockPos.get(blockHitResult);
BlockPos above = new BlockPos(Reflections.field$Vec3i$x.getInt(blockPos), Reflections.field$Vec3i$y.getInt(blockPos) + offsetY, Reflections.field$Vec3i$z.getInt(blockPos));
Direction direction = Direction.values()[(int) Reflections.method$Direction$ordinal.invoke(Reflections.field$BlockHitResul$direction.get(blockHitResult))];
boolean miss = Reflections.field$BlockHitResul$miss.getBoolean(blockHitResult);
Vec3d hitPos = LocationUtils.fromVec(Reflections.field$HitResult$location.get(blockHitResult));
if (miss) {
return super.useOnBlock(new UseOnContext(player, hand, BlockHitResult.miss(hitPos, direction, above)));
} else {
boolean inside = Reflections.field$BlockHitResul$inside.getBoolean(blockHitResult);
return super.useOnBlock(new UseOnContext(player, hand, new BlockHitResult(hitPos, direction, above, inside)));
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Error handling use", e);
return InteractionResult.FAIL;
}
}
public static class Factory implements ItemBehaviorFactory {
@Override
public ItemBehavior create(Pack pack, Path path, Key key, Map<String, Object> arguments) {
Object id = arguments.get("block");
if (id == null) {
throw new IllegalArgumentException("Missing required parameter 'block' for on_liquid_block_item behavior");
}
int offset = MiscUtils.getAsInt(arguments.getOrDefault("y-offset", 1));
if (id instanceof Map<?, ?> map) {
BukkitBlockManager.instance().parseSection(pack, path, key, MiscUtils.castToMap(map, false));
return new LiquidCollisionBlockItemBehavior(key, offset);
} else {
return new LiquidCollisionBlockItemBehavior(Key.of(id.toString()), offset);
}
}
}
}

View File

@@ -344,7 +344,7 @@ public class PacketConsumers {
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e);
}
}, (World) player.level().getHandle(), (MCUtils.fastFloor(player.x())) >> 4, (MCUtils.fastFloor(player.z())) >> 4);
}, (World) player.level().platformWorld(), (MCUtils.fastFloor(player.x())) >> 4, (MCUtils.fastFloor(player.z())) >> 4);
} else {
handleSetCreativeSlotPacketOnMainThread(player, packet);
}

View File

@@ -16,15 +16,15 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.*;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
import java.lang.ref.Reference;
@@ -201,6 +201,31 @@ public class BukkitServerPlayer extends Player {
platformPlayer().closeInventory();
}
// TODO DO NOT USE BUKKIT API
@Override
public BlockHitResult rayTrace(double distance, FluidCollisionRule collisionRule) {
RayTraceResult result = platformPlayer().rayTraceBlocks(distance, FluidUtils.toCollisionRule(collisionRule));
if (result == null) {
Location eyeLocation = platformPlayer().getEyeLocation();
Location targetLocation = eyeLocation.clone();
targetLocation.add(eyeLocation.getDirection().multiply(distance));
return BlockHitResult.miss(new Vec3d(eyeLocation.getX(), eyeLocation.getY(), eyeLocation.getZ()),
Direction.getApproximateNearest(eyeLocation.getX() - targetLocation.getX(), eyeLocation.getY() - targetLocation.getY(), eyeLocation.getZ() - targetLocation.getZ()),
new BlockPos(targetLocation.getBlockX(), targetLocation.getBlockY(), targetLocation.getBlockZ())
);
} else {
Vector hitPos = result.getHitPosition();
Block hitBlock = result.getHitBlock();
Location hitBlockLocation = hitBlock.getLocation();
return new BlockHitResult(
new Vec3d(hitPos.getX(), hitPos.getY(), hitPos.getZ()),
DirectionUtils.toDirection(result.getHitBlockFace()),
new BlockPos(hitBlockLocation.getBlockX(), hitBlockLocation.getBlockY(), hitBlockLocation.getBlockZ()),
false
);
}
}
@Override
public void sendPacket(Object packet, boolean immediately) {
this.plugin.networkManager().sendPacket(this, packet, immediately);

View File

@@ -0,0 +1,24 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.core.world.FluidCollisionRule;
import org.bukkit.FluidCollisionMode;
public class FluidUtils {
private FluidUtils() {}
public static FluidCollisionMode toCollisionRule(FluidCollisionRule rule) {
switch (rule) {
case NONE -> {
return FluidCollisionMode.NEVER;
}
case ALWAYS -> {
return FluidCollisionMode.ALWAYS;
}
case SOURCE_ONLY -> {
return FluidCollisionMode.SOURCE_ONLY;
}
}
return FluidCollisionMode.NEVER;
}
}

View File

@@ -13,6 +13,14 @@ public class LocationUtils {
return new Vec3d(loc.getX(), loc.getY(), loc.getZ());
}
public static Vec3d fromVec(Object vec) throws ReflectiveOperationException {
return new Vec3d(
Reflections.field$Vec3$x.getDouble(vec),
Reflections.field$Vec3$y.getDouble(vec),
Reflections.field$Vec3$z.getDouble(vec)
);
}
public static Object toBlockPos(BlockPos pos) {
try {
return Reflections.constructor$BlockPos.newInstance(pos.x(), pos.y(), pos.z());
@@ -21,6 +29,14 @@ public class LocationUtils {
}
}
public static Object above(Object blockPos) throws ReflectiveOperationException {
return toBlockPos(
Reflections.field$Vec3i$x.getInt(blockPos),
Reflections.field$Vec3i$y.getInt(blockPos) + 1,
Reflections.field$Vec3i$z.getInt(blockPos)
);
}
public static Object toBlockPos(int x, int y, int z) {
try {
return Reflections.constructor$BlockPos.newInstance(x, y, z);

View File

@@ -1455,6 +1455,12 @@ public class Reflections {
)
);
public static final Method method$Direction$ordinal = requireNonNull(
ReflectionUtils.getMethod(
clazz$Direction, new String[]{"ordinal"}
)
);
public static final Method method$Direction$values = requireNonNull(
ReflectionUtils.getStaticMethod(
clazz$Direction, clazz$Direction.arrayType()
@@ -3326,6 +3332,7 @@ public class Reflections {
public static final Object instance$Blocks$STONE;
public static final Object instance$Blocks$STONE$defaultState;
public static final Object instance$Blocks$FIRE;
public static final Object instance$Blocks$ICE;
static {
try {
@@ -3337,6 +3344,8 @@ public class Reflections {
Object stone = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "stone");
instance$Blocks$STONE = method$Registry$get.invoke(instance$BuiltInRegistries$BLOCK, stone);
instance$Blocks$STONE$defaultState = method$Block$defaultBlockState.invoke(instance$Blocks$STONE);
Object ice = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "ice");
instance$Blocks$ICE = method$Registry$get.invoke(instance$BuiltInRegistries$BLOCK, ice);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
@@ -3862,11 +3871,17 @@ public class Reflections {
);
public static final Object instance$Fluids$WATER;
public static final Object instance$Fluids$LAVA;
public static final Object instance$Fluids$EMPTY;
static {
try {
Object waterId = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "water");
instance$Fluids$WATER = method$Registry$get.invoke(instance$BuiltInRegistries$FLUID, waterId);
Object lavaId = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "lava");
instance$Fluids$LAVA = method$Registry$get.invoke(instance$BuiltInRegistries$FLUID, lavaId);
Object emptyId = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "empty");
instance$Fluids$EMPTY = method$Registry$get.invoke(instance$BuiltInRegistries$FLUID, emptyId);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
@@ -5015,4 +5030,85 @@ public class Reflections {
clazz$ItemStack, clazz$Item
)
);
public static final Class<?> clazz$BlockHitResult = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.phys.BlockHitResult")
)
);
public static final Class<?> clazz$ClipContext$Fluid = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.level.ClipContext$Fluid")
)
);
public static final Method method$ClipContext$Fluid$values = requireNonNull(
ReflectionUtils.getStaticMethod(
clazz$ClipContext$Fluid, clazz$ClipContext$Fluid.arrayType()
)
);
public static final Object instance$ClipContext$Fluid$NONE;
public static final Object instance$ClipContext$Fluid$SOURCE_ONLY;
public static final Object instance$ClipContext$Fluid$ANY;
static {
try {
Object[] values = (Object[]) method$ClipContext$Fluid$values.invoke(null);
instance$ClipContext$Fluid$NONE = values[0];
instance$ClipContext$Fluid$SOURCE_ONLY = values[1];
instance$ClipContext$Fluid$ANY = values[2];
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static final Method method$Item$getPlayerPOVHitResult = requireNonNull(
ReflectionUtils.getDeclaredMethod(
clazz$Item, clazz$BlockHitResult, clazz$Level, clazz$Player, clazz$ClipContext$Fluid
)
);
public static final Method method$BlockHitResult$withPosition = requireNonNull(
ReflectionUtils.getMethod(
clazz$BlockHitResult, clazz$BlockHitResult, clazz$BlockPos
)
);
public static final Field field$BlockHitResul$blockPos = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$BlockHitResult, clazz$BlockPos, 0
)
);
public static final Field field$BlockHitResul$direction = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$BlockHitResult, clazz$Direction, 0
)
);
public static final Field field$BlockHitResul$miss = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$BlockHitResult, boolean.class, 0
)
);
public static final Field field$BlockHitResul$inside = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$BlockHitResult, boolean.class, 1
)
);
public static final Class<?> clazz$HitResult = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.phys.HitResult")
)
);
public static final Field field$HitResult$location = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$HitResult, clazz$Vec3, 0
)
);
}

View File

@@ -15,7 +15,7 @@ public class BukkitCEWorld extends CEWorld {
@Override
public void tick() {
if (ConfigManager.enableLightSystem()) {
LightUtils.updateChunkLight((org.bukkit.World) world.getHandle(), SectionPosUtils.toMap(super.updatedSectionPositions, world.worldHeight().getMinSection() - 1, world.worldHeight().getMaxSection() + 1));
LightUtils.updateChunkLight((org.bukkit.World) world.platformWorld(), SectionPosUtils.toMap(super.updatedSectionPositions, world.worldHeight().getMinSection() - 1, world.worldHeight().getMaxSection() + 1));
super.updatedSectionPositions.clear();
}
}

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.world;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
@@ -28,36 +29,45 @@ public class BukkitWorld implements World {
}
@Override
public org.bukkit.World getHandle() {
public org.bukkit.World platformWorld() {
return world.get();
}
@Override
public Object serverWorld() {
try {
return Reflections.field$CraftWorld$ServerLevel.get(platformWorld());
} catch (Exception e) {
throw new RuntimeException("Failed to get server world", e);
}
}
@Override
public WorldHeight worldHeight() {
if (this.worldHeight == null) {
this.worldHeight = WorldHeight.create(getHandle().getMinHeight(), getHandle().getMaxHeight() - getHandle().getMinHeight());
this.worldHeight = WorldHeight.create(platformWorld().getMinHeight(), platformWorld().getMaxHeight() - platformWorld().getMinHeight());
}
return this.worldHeight;
}
@Override
public WorldBlock getBlockAt(int x, int y, int z) {
return new BukkitWorldBlock(getHandle().getBlockAt(x, y, z));
return new BukkitWorldBlock(platformWorld().getBlockAt(x, y, z));
}
@Override
public String name() {
return getHandle().getName();
return platformWorld().getName();
}
@Override
public Path directory() {
return getHandle().getWorldFolder().toPath();
return platformWorld().getWorldFolder().toPath();
}
@Override
public UUID uuid() {
return getHandle().getUID();
return platformWorld().getUID();
}
@Override
@@ -65,16 +75,16 @@ public class BukkitWorld implements World {
ItemStack itemStack = (ItemStack) item.load();
if (ItemUtils.isEmpty(itemStack)) return;
if (VersionHelper.isVersionNewerThan1_21_2()) {
getHandle().dropItemNaturally(new Location(null, location.x(), location.y(), location.z()), (ItemStack) item.getItem());
platformWorld().dropItemNaturally(new Location(null, location.x(), location.y(), location.z()), (ItemStack) item.getItem());
} else {
getHandle().dropItemNaturally(new Location(null, location.x() - 0.5, location.y() - 0.5, location.z() - 0.5), (ItemStack) item.getItem());
platformWorld().dropItemNaturally(new Location(null, location.x() - 0.5, location.y() - 0.5, location.z() - 0.5), (ItemStack) item.getItem());
}
}
@Override
public void dropExp(Vec3d location, int amount) {
if (amount <= 0) return;
EntityUtils.spawnEntity(getHandle(), new Location(getHandle(), location.x(), location.y(), location.z()), EntityType.EXPERIENCE_ORB, (e) -> {
EntityUtils.spawnEntity(platformWorld(), new Location(platformWorld(), location.x(), location.y(), location.z()), EntityType.EXPERIENCE_ORB, (e) -> {
ExperienceOrb orb = (ExperienceOrb) e;
orb.setExperience(amount);
});
@@ -82,6 +92,6 @@ public class BukkitWorld implements World {
@Override
public void playBlockSound(Vec3d location, Key sound, float volume, float pitch) {
getHandle().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch);
platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch);
}
}