9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-25 09:59:20 +00:00

让全部自定义方块均支持waterlogged

This commit is contained in:
XiaoMoMi
2025-06-19 04:09:00 +08:00
parent 4e1de1c9af
commit cd7d29ea15
10 changed files with 119 additions and 126 deletions

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.block;
import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBehavior;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
@@ -10,6 +11,8 @@ import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.bukkit.util.SoundUtils;
import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviors;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.CraftEngine;
@@ -46,6 +49,21 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
super(id, holder, properties, appearances, variantMapper, settings, events, behavior, lootTable);
}
@Override
protected BlockBehavior setupBehavior(List<Map<String, Object>> behaviorConfig) {
if (behaviorConfig.isEmpty()) {
return new EmptyBlockBehavior();
} else if (behaviorConfig.size() == 1) {
return BlockBehaviors.fromMap(this, behaviorConfig.get(0));
} else {
List<AbstractBlockBehavior> behaviors = new ArrayList<>();
for (Map<String, Object> config : behaviorConfig) {
behaviors.add((AbstractBlockBehavior) BlockBehaviors.fromMap(this, config));
}
return new UnsafeCompositeBlockBehavior(this, behaviors);
}
}
@SuppressWarnings("unchecked")
@Nullable
@Override

View File

@@ -1,6 +1,10 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MItems;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.MirrorUtils;
import net.momirealms.craftengine.bukkit.util.RotationUtils;
@@ -8,10 +12,8 @@ import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.HorizontalDirection;
import net.momirealms.craftengine.core.util.Mirror;
import net.momirealms.craftengine.core.util.Rotation;
import net.momirealms.craftengine.core.util.*;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
@@ -75,16 +77,20 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
});
}
@Nullable
private MirrorFunction mirrorFunction;
@Nullable
private RotateFunction rotateFunction;
@Nullable
protected final Property<Boolean> waterloggedProperty;
@SuppressWarnings("unchecked")
public BukkitBlockBehavior(CustomBlock customBlock) {
super(customBlock);
for (Property<?> property : customBlock.properties()) {
Optional.ofNullable(HARD_CODED_PROPERTY_DATA.get(property.name())).ifPresent(
c -> c.accept(this, property)
);
Optional.ofNullable(HARD_CODED_PROPERTY_DATA.get(property.name())).ifPresent(c -> c.accept(this, property));
}
this.waterloggedProperty = (Property<Boolean>) customBlock.getProperty("waterlogged");
}
@Override
@@ -118,4 +124,48 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
Object rotate(Object thisBlock, ImmutableBlockState state, Rotation rotation) throws Exception;
}
private static final int pickupBlock$world = VersionHelper.isOrAbove1_20_2() ? 1 : 0;
private static final int pickupBlock$pos = VersionHelper.isOrAbove1_20_2() ? 2 : 1;
private static final int pickupBlock$blockState = VersionHelper.isOrAbove1_20_2() ? 3 : 2;
@Override
public Object pickupBlock(Object thisBlock, Object[] args, Callable<Object> superMethod) {
if (this.waterloggedProperty == null) return CoreReflections.instance$ItemStack$EMPTY;
Object blockState = args[pickupBlock$blockState];
Object world = args[pickupBlock$world];
Object pos = args[pickupBlock$pos];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState != null) {
if (immutableBlockState.get(this.waterloggedProperty)) {
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, pos, immutableBlockState.with(this.waterloggedProperty, false).customBlockState().handle(), 3);
return FastNMS.INSTANCE.constructor$ItemStack(MItems.WATER_BUCKET, 1);
}
}
return CoreReflections.instance$ItemStack$EMPTY;
}
@Override
public boolean placeLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
if (this.waterloggedProperty == null) return false;
Object blockState = args[2];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState != null) {
Object fluidType = FastNMS.INSTANCE.method$FluidState$getType(args[3]);
if (!immutableBlockState.get(this.waterloggedProperty) && fluidType == MFluids.WATER) {
FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[1], immutableBlockState.with(this.waterloggedProperty, true).customBlockState().handle(), 3);
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[0], args[1], fluidType, 5);
return true;
}
}
return false;
}
private static final int canPlaceLiquid$liquid = VersionHelper.isOrAbove1_20_2() ? 4 : 3;
@Override
public boolean canPlaceLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
if (this.waterloggedProperty == null) return false;
return args[canPlaceLiquid$liquid] == MFluids.WATER;
}
}

View File

@@ -34,7 +34,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(SAPLING_BLOCK, SaplingBlockBehavior.FACTORY);
register(ON_LIQUID_BLOCK, OnLiquidBlockBehavior.FACTORY);
register(NEAR_LIQUID_BLOCK, NearLiquidBlockBehavior.FACTORY);
register(WATERLOGGED_BLOCK, WaterLoggedBlockBehavior.FACTORY);
register(CONCRETE_POWDER_BLOCK, ConcretePowderBlockBehavior.FACTORY);
register(VERTICAL_CROP_BLOCK, VerticalCropBlockBehavior.FACTORY);
register(CROP_BLOCK, CropBlockBehavior.FACTORY);

View File

@@ -27,27 +27,26 @@ import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.event.block.LeavesDecayEvent;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
public class LeavesBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private static final Object LOG_TAG = BlockTags.getOrCreate(Key.of("minecraft", "logs"));
private final int maxDistance;
private final Property<Integer> distanceProperty;
private final Property<Boolean> persistentProperty;
@Nullable
private final Property<Boolean> waterloggedProperty;
public LeavesBlockBehavior(CustomBlock block, int maxDistance, Property<Integer> distanceProperty, Property<Boolean> persistentProperty, @Nullable Property<Boolean> waterloggedProperty) {
super(block, waterloggedProperty);
public LeavesBlockBehavior(CustomBlock block,
int maxDistance,
Property<Integer> distanceProperty,
Property<Boolean> persistentProperty) {
super(block);
this.maxDistance = maxDistance;
this.distanceProperty = distanceProperty;
this.persistentProperty = persistentProperty;
this.waterloggedProperty = waterloggedProperty;
}
public int getDistance(ImmutableBlockState state) {
@@ -115,7 +114,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
}
@Override
public void randomTick(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
public void randomTick(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object level = args[1];
Object blockPos = args[2];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0]));
@@ -190,9 +189,8 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<Boolean> persistent = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("persistent"), "warning.config.block.behavior.leaves.missing_persistent");
Property<Integer> distance = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("distance"), "warning.config.block.behavior.leaves.missing_distance");
Property<Boolean> waterlogged = (Property<Boolean>) block.getProperty("waterlogged");
int actual = distance.possibleValues().get(distance.possibleValues().size() - 1);
return new LeavesBlockBehavior(block, actual, distance, persistent, waterlogged);
return new LeavesBlockBehavior(block, actual, distance, persistent);
}
}
}

View File

@@ -43,7 +43,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<SingleBlockHalf> halfProperty;
private final Property<HorizontalDirection> facingProperty;
@@ -55,7 +55,6 @@ public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
private final SoundData closeSound;
public TrapDoorBlockBehavior(CustomBlock block,
@Nullable Property<Boolean> waterloggedProperty,
Property<SingleBlockHalf> halfProperty,
Property<HorizontalDirection> facingProperty,
Property<Boolean> poweredProperty,
@@ -64,7 +63,7 @@ public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
boolean canOpenByWindCharge,
SoundData openSound,
SoundData closeSound) {
super(block, waterloggedProperty);
super(block);
this.halfProperty = halfProperty;
this.facingProperty = facingProperty;
this.poweredProperty = poweredProperty;
@@ -78,9 +77,9 @@ public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object blockState = args[0];
if (this.waterloggedProperty != null) {
if (super.waterloggedProperty != null) {
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (state != null && !state.isEmpty() && state.get(this.waterloggedProperty)) {
if (state != null && !state.isEmpty() && state.get(super.waterloggedProperty)) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(VersionHelper.isOrAbove1_21_2() ? args[2] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[4], MFluids.WATER, 5);
}
}
@@ -238,7 +237,6 @@ public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<Boolean> waterlogged = (Property<Boolean>) block.getProperty("waterlogged");
Property<SingleBlockHalf> half = (Property<SingleBlockHalf>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.trapdoor.missing_half");
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.trapdoor.missing_facing");
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.trapdoor.missing_open");
@@ -252,7 +250,7 @@ public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
openSound = Optional.ofNullable(sounds.get("open")).map(obj -> SoundData.create(obj, 1, 1)).orElse(null);
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, 1, 1)).orElse(null);
}
return new TrapDoorBlockBehavior(block, waterlogged, half, facing, powered, open, canOpenWithHand, canOpenByWindCharge, openSound, closeSound);
return new TrapDoorBlockBehavior(block, half, facing, powered, open, canOpenWithHand, canOpenByWindCharge, openSound, closeSound);
}
}
}

View File

@@ -1,8 +1,9 @@
package net.momirealms.craftengine.core.block.behavior;
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.item.context.UseOnContext;
@@ -11,7 +12,7 @@ import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
public class UnsafeCompositeBlockBehavior extends AbstractBlockBehavior {
public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
private final AbstractBlockBehavior[] behaviors;
public UnsafeCompositeBlockBehavior(CustomBlock customBlock, List<AbstractBlockBehavior> behaviors) {
@@ -164,4 +165,21 @@ public class UnsafeCompositeBlockBehavior extends AbstractBlockBehavior {
}
return true;
}
@Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
for (AbstractBlockBehavior behavior : this.behaviors) {
if (!behavior.isPathFindable(thisBlock, args, superMethod)) {
return false;
}
}
return (boolean) superMethod.call();
}
@Override
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
for (AbstractBlockBehavior behavior : this.behaviors) {
behavior.onExplosionHit(thisBlock, args, superMethod);
}
}
}

View File

@@ -1,85 +0,0 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MItems;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.concurrent.Callable;
public class WaterLoggedBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
@Nullable
protected final Property<Boolean> waterloggedProperty;
public WaterLoggedBlockBehavior(CustomBlock block, @Nullable Property<Boolean> waterloggedProperty) {
super(block);
this.waterloggedProperty = waterloggedProperty;
}
@Override
public Object pickupBlock(Object thisBlock, Object[] args, Callable<Object> superMethod) {
if (this.waterloggedProperty == null) return CoreReflections.instance$ItemStack$EMPTY;
Object blockState;
Object world;
Object pos;
if (VersionHelper.isOrAbove1_20_2()) {
world = args[1];
pos = args[2];
blockState = args[3];
} else {
world = args[0];
pos = args[1];
blockState = args[2];
}
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState != null) {
if (immutableBlockState.get(this.waterloggedProperty)) {
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, pos, immutableBlockState.with(this.waterloggedProperty, false).customBlockState().handle(), 3);
return FastNMS.INSTANCE.constructor$ItemStack(MItems.WATER_BUCKET, 1);
}
}
return CoreReflections.instance$ItemStack$EMPTY;
}
@Override
public boolean placeLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
if (this.waterloggedProperty == null) return false;
Object blockState = args[2];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState != null) {
Object fluidType = FastNMS.INSTANCE.method$FluidState$getType(args[3]);
if (!immutableBlockState.get(this.waterloggedProperty) && fluidType == MFluids.WATER) {
FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[1], immutableBlockState.with(this.waterloggedProperty, true).customBlockState().handle(), 3);
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[0], args[1], fluidType, 5);
return true;
}
}
return false;
}
@Override
public boolean canPlaceLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
if (this.waterloggedProperty == null) return false;
return (VersionHelper.isOrAbove1_20_2() ? args[4] : args[3]) == MFluids.WATER;
}
@SuppressWarnings("unchecked")
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<Boolean> waterlogged = (Property<Boolean>) block.getProperty("waterlogged");
return new WaterLoggedBlockBehavior(block, waterlogged);
}
}
}

View File

@@ -2,8 +2,6 @@ package net.momirealms.craftengine.core.block;
import com.google.common.collect.ImmutableMap;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviors;
import net.momirealms.craftengine.core.block.behavior.UnsafeCompositeBlockBehavior;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.loot.LootTable;
@@ -53,17 +51,7 @@ public abstract class AbstractCustomBlock implements CustomBlock {
this.events = events;
this.variantProvider = new BlockStateVariantProvider(holder, ImmutableBlockState::new, properties);
this.defaultState = this.variantProvider.getDefaultState();
if (behaviorConfig.isEmpty()) {
this.behavior = new EmptyBlockBehavior();
} else if (behaviorConfig.size() == 1) {
this.behavior = BlockBehaviors.fromMap(this, behaviorConfig.get(0));
} else {
List<AbstractBlockBehavior> behaviors = new ArrayList<>();
for (Map<String, Object> config : behaviorConfig) {
behaviors.add((AbstractBlockBehavior) BlockBehaviors.fromMap(this, config));
}
this.behavior = new UnsafeCompositeBlockBehavior(this, behaviors);
}
this.behavior = setupBehavior(behaviorConfig);
List<BiFunction<BlockPlaceContext, ImmutableBlockState, ImmutableBlockState>> placements = new ArrayList<>(4);
for (Map.Entry<String, Property<?>> propertyEntry : this.properties.entrySet()) {
placements.add(Property.createStateForPlacement(propertyEntry.getKey(), propertyEntry.getValue()));
@@ -98,6 +86,10 @@ public abstract class AbstractCustomBlock implements CustomBlock {
this.applyPlatformSettings();
}
protected BlockBehavior setupBehavior(List<Map<String, Object>> behaviorConfig) {
return EmptyBlockBehavior.INSTANCE;
}
private static BiFunction<BlockPlaceContext, ImmutableBlockState, ImmutableBlockState> composite(List<BiFunction<BlockPlaceContext, ImmutableBlockState, ImmutableBlockState>> placements) {
return switch (placements.size()) {
case 0 -> (c, i) -> i;

View File

@@ -4,9 +4,13 @@ import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
public abstract class AbstractBlockBehavior extends BlockBehavior {
protected CustomBlock customBlock;
protected final CustomBlock customBlock;
public AbstractBlockBehavior(CustomBlock customBlock) {
this.customBlock = customBlock;
}
public CustomBlock block() {
return this.customBlock;
}
}

View File

@@ -17,6 +17,7 @@ import java.util.Map;
public class BlockBehaviors {
public static final Key EMPTY = Key.from("craftengine:empty");
public static final Key UNSAFE_COMBINED = Key.from("craftengine:unsafe_combined");
public static void register(Key key, BlockBehaviorFactory factory) {
Holder.Reference<BlockBehaviorFactory> holder = ((WritableRegistry<BlockBehaviorFactory>) BuiltInRegistries.BLOCK_BEHAVIOR_FACTORY)