mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 18:09:27 +00:00
@@ -13,7 +13,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
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 final Key NEAR_LIQUID_BLOCK = Key.from("craftengine:near_liquid_block");
|
||||
public static final Key WATERLOGGED_BLOCK = Key.from("craftengine:waterlogged_block");
|
||||
public static final Key CONCRETE_POWDER_BLOCK = Key.from("craftengine:concrete_powder_block");
|
||||
public static final Key VERTICAL_CROP_BLOCK = Key.from("craftengine:vertical_crop_block");
|
||||
public static final Key CROP_BLOCK = Key.from("craftengine:crop_block");
|
||||
@@ -23,6 +22,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
public static final Key DOOR_BLOCK = Key.from("craftengine:door_block");
|
||||
public static final Key STACKABLE_BLOCK = Key.from("craftengine:stackable_block");
|
||||
public static final Key STURDY_BASE_BLOCK = Key.from("craftengine:sturdy_base_block");
|
||||
public static final Key FENCE_GATE_BLOCK = Key.from("craftengine:fence_gate_block");
|
||||
|
||||
public static void init() {
|
||||
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
|
||||
@@ -43,5 +43,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
register(DOOR_BLOCK, DoorBlockBehavior.FACTORY);
|
||||
register(STACKABLE_BLOCK, StackableBlockBehavior.FACTORY);
|
||||
register(STURDY_BASE_BLOCK, SturdyBaseBlockBehavior.FACTORY);
|
||||
register(FENCE_GATE_BLOCK, FenceGateBlockBehavior.FACTORY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MTagKey;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.InteractUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
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.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
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 org.bukkit.Bukkit;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<HorizontalDirection> facingProperty;
|
||||
private final Property<Boolean> inWallProperty;
|
||||
private final Property<Boolean> openProperty;
|
||||
private final Property<Boolean> poweredProperty;
|
||||
private final boolean canOpenWithHand;
|
||||
private final boolean canOpenByWindCharge;
|
||||
private final SoundData openSound;
|
||||
private final SoundData closeSound;
|
||||
|
||||
public FenceGateBlockBehavior(
|
||||
CustomBlock customBlock,
|
||||
Property<HorizontalDirection> facing,
|
||||
Property<Boolean> inWall,
|
||||
Property<Boolean> open,
|
||||
Property<Boolean> powered,
|
||||
boolean canOpenWithHand,
|
||||
boolean canOpenByWindCharge,
|
||||
SoundData openSound,
|
||||
SoundData closeSound
|
||||
) {
|
||||
super(customBlock);
|
||||
this.facingProperty = facing;
|
||||
this.inWallProperty = inWall;
|
||||
this.openProperty = open;
|
||||
this.poweredProperty = powered;
|
||||
this.canOpenWithHand = canOpenWithHand;
|
||||
this.canOpenByWindCharge = canOpenByWindCharge;
|
||||
this.openSound = openSound;
|
||||
this.closeSound = closeSound;
|
||||
}
|
||||
|
||||
public boolean isOpen(ImmutableBlockState state) {
|
||||
if (state == null || state.isEmpty() || !state.contains(this.openProperty)) return false;
|
||||
return state.get(this.openProperty);
|
||||
}
|
||||
|
||||
public boolean isWall(Object state) {
|
||||
if (state == null) return false;
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isTagKeyBlock(state, MTagKey.Block$WALLS);
|
||||
}
|
||||
|
||||
private Object getBlockState(Object level, BlockPos blockPos) {
|
||||
return FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(blockPos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object blockState = args[0];
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[0]);
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return blockState;
|
||||
if (state.get(this.facingProperty).toDirection().clockWise().axis() != direction.axis()) {
|
||||
return superMethod.call();
|
||||
}
|
||||
Object neighborState = VersionHelper.isOrAbove1_21_2() ? args[6] : args[2];
|
||||
Object level = VersionHelper.isOrAbove1_21_2() ? args[1] : args[3];
|
||||
BlockPos blockPos = LocationUtils.fromBlockPos(VersionHelper.isOrAbove1_21_2() ? args[3] : args[4]);
|
||||
Object relativeState = getBlockState(level, blockPos.relative(direction.opposite()));
|
||||
boolean neighborStateIsWall = this.isWall(neighborState);
|
||||
boolean relativeStateIsWall = this.isWall(relativeState);
|
||||
boolean flag = neighborStateIsWall || relativeStateIsWall;
|
||||
if (neighborStateIsWall) {
|
||||
// TODO: 连接原版方块
|
||||
}
|
||||
if (relativeStateIsWall) {
|
||||
// TODO: 连接原版方块
|
||||
}
|
||||
return state.with(this.inWallProperty, flag).customBlockState().handle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
Object level = context.getLevel().serverWorld();
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
boolean hasNeighborSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, LocationUtils.toBlockPos(clickedPos));
|
||||
Direction horizontalDirection = context.getHorizontalDirection();
|
||||
Direction.Axis axis = horizontalDirection.axis();
|
||||
boolean flag = axis == Direction.Axis.Z && (this.isWall(getBlockState(level, clickedPos.relative(Direction.WEST))))
|
||||
|| this.isWall(getBlockState(level, clickedPos.relative(Direction.EAST)))
|
||||
|| axis == Direction.Axis.X && (this.isWall(getBlockState(level, clickedPos.relative(Direction.NORTH)))
|
||||
|| this.isWall(getBlockState(level, clickedPos.relative(Direction.SOUTH))));
|
||||
// TODO: 连接原版方块
|
||||
return state.owner().value().defaultState()
|
||||
.with(this.facingProperty, horizontalDirection.toHorizontalDirection())
|
||||
.with(this.openProperty, hasNeighborSignal)
|
||||
.with(this.poweredProperty, hasNeighborSignal)
|
||||
.with(this.inWallProperty, flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
if (!this.canOpenWithHand) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
if (context.getItem() == null) {
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS;
|
||||
} else if (!context.getPlayer().isSecondaryUseActive()) {
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
} else {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void playerToggle(UseOnContext context, ImmutableBlockState state) {
|
||||
Player player = context.getPlayer();
|
||||
this.toggle(state, context.getLevel(), context.getClickedPos(), player);
|
||||
if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object type = VersionHelper.isOrAbove1_20_5() ? args[1] : args[3];
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return false;
|
||||
if (type == CoreReflections.instance$PathComputationType$LAND || type == CoreReflections.instance$PathComputationType$AIR) {
|
||||
return isOpen(state);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) {
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0]));
|
||||
if (state == null || state.isEmpty()) return;
|
||||
this.toggle(state, new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(args[1])), LocationUtils.fromBlockPos(args[2]), null);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Override
|
||||
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
Object level = args[1];
|
||||
Object blockPos = args[2];
|
||||
boolean hasSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, blockPos);
|
||||
if (hasSignal == immutableBlockState.get(this.poweredProperty)) return;
|
||||
|
||||
Block bblock = FastNMS.INSTANCE.method$CraftBlock$at(level, blockPos);
|
||||
int power = bblock.getBlockPower();
|
||||
int oldPower = isOpen(immutableBlockState) ? 15 : 0;
|
||||
Object neighborBlock = args[3];
|
||||
|
||||
if (oldPower == 0 ^ power == 0 || FastNMS.INSTANCE.method$BlockStateBase$isSignalSource(FastNMS.INSTANCE.method$Block$defaultState(neighborBlock))) {
|
||||
BlockRedstoneEvent event = new BlockRedstoneEvent(bblock, oldPower, power);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
hasSignal = event.getNewCurrent() > 0;
|
||||
}
|
||||
|
||||
World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
boolean changed = isOpen(immutableBlockState) != hasSignal;
|
||||
if (hasSignal && changed) {
|
||||
Object abovePos = LocationUtils.above(blockPos);
|
||||
Object aboveBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, abovePos);
|
||||
if (CoreReflections.clazz$RedStoneWireBlock.isInstance(FastNMS.INSTANCE.method$BlockState$getBlock(aboveBlockState))) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, abovePos, MBlocks.AIR$defaultState, UpdateOption.UPDATE_ALL.flags());
|
||||
world.dropItemNaturally(
|
||||
new Vec3d(FastNMS.INSTANCE.field$Vec3i$x(abovePos) + 0.5, FastNMS.INSTANCE.field$Vec3i$y(abovePos) + 0.5, FastNMS.INSTANCE.field$Vec3i$z(abovePos) + 0.5),
|
||||
BukkitItemManager.instance().createWrappedItem(ItemKeys.REDSTONE, null)
|
||||
);
|
||||
if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos) != blockPos) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
immutableBlockState = immutableBlockState.with(this.openProperty, hasSignal);
|
||||
FastNMS.INSTANCE.method$Level$getCraftWorld(level).sendGameEvent(null,
|
||||
hasSignal ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE,
|
||||
new Vector(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos), FastNMS.INSTANCE.field$Vec3i$z(blockPos))
|
||||
);
|
||||
this.playSound(LocationUtils.fromBlockPos(blockPos), world, hasSignal);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, immutableBlockState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
}
|
||||
private void toggle(ImmutableBlockState state, World world, BlockPos pos, @Nullable Player player) {
|
||||
ImmutableBlockState newState;
|
||||
if (state.get(this.openProperty)) {
|
||||
newState = state.with(this.openProperty, false);
|
||||
} else {
|
||||
ImmutableBlockState blockState = state;
|
||||
if (player != null) {
|
||||
Direction direction = player.getDirection();
|
||||
if (state.get(this.facingProperty).toDirection() == direction.opposite()) {
|
||||
blockState = blockState.with(this.facingProperty, direction.toHorizontalDirection());
|
||||
}
|
||||
}
|
||||
newState = blockState.with(this.openProperty, true);
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
boolean open = isOpen(newState);
|
||||
((org.bukkit.World) world.platformWorld()).sendGameEvent(
|
||||
player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null,
|
||||
open ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE,
|
||||
new Vector(pos.x(), pos.y(), pos.z())
|
||||
);
|
||||
this.playSound(pos, world, open);
|
||||
}
|
||||
|
||||
private void playSound(BlockPos pos, World world, boolean open) {
|
||||
if (open) {
|
||||
if (this.openSound != null) {
|
||||
world.playBlockSound(new Vec3d(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5), this.openSound);
|
||||
}
|
||||
} else {
|
||||
if (this.closeSound != null) {
|
||||
world.playBlockSound(new Vec3d(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5), this.closeSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.fence_gate.missing_facing");
|
||||
Property<Boolean> inWall = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("in_wall"), "warning.config.block.behavior.fence_gate.missing_in_wall");
|
||||
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.fence_gate.missing_open");
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.fence_gate.missing_powered");
|
||||
boolean canOpenWithHand = (boolean) arguments.getOrDefault("can-open-with-hand", true);
|
||||
boolean canOpenByWindCharge = (boolean) arguments.getOrDefault("can-open-by-wind-charge", true);
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
SoundData openSound = null;
|
||||
SoundData closeSound = null;
|
||||
if (sounds != null) {
|
||||
openSound = Optional.ofNullable(sounds.get("open")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
}
|
||||
return new FenceGateBlockBehavior(block, facing, inWall, open, powered, canOpenWithHand, canOpenByWindCharge, openSound, closeSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MTagKey {
|
||||
private MTagKey() {}
|
||||
|
||||
public static final Object Item$WOOL = create(MRegistries.ITEM, "wool");
|
||||
public static final Object Block$WALLS = create(MRegistries.BLOCK, "walls");
|
||||
|
||||
private static Object create(Object registry, String location) {
|
||||
Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location);
|
||||
Object tagKey = FastNMS.INSTANCE.method$TagKey$create(registry, resourceLocation);
|
||||
return Objects.requireNonNull(tagKey);
|
||||
}
|
||||
}
|
||||
@@ -63,4 +63,5 @@ minecraft:oxidized_copper_door: 32
|
||||
minecraft:waxed_copper_door: 32
|
||||
minecraft:waxed_exposed_copper_door: 32
|
||||
minecraft:waxed_weathered_copper_door: 32
|
||||
minecraft:waxed_oxidized_copper_door: 32
|
||||
minecraft:waxed_oxidized_copper_door: 32
|
||||
minecraft:oak_fence_gate: 16
|
||||
@@ -3723,6 +3723,24 @@ minecraft:iron_door[facing=west,half=upper,hinge=right,open=true,powered=true]:
|
||||
# minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=true,powered=false]
|
||||
# minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=true,powered=false]
|
||||
|
||||
#### Fence Gate ####
|
||||
minecraft:oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=false,open=false,powered=false]
|
||||
minecraft:oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=false,open=true,powered=false]
|
||||
minecraft:oak_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=true,open=false,powered=false]
|
||||
minecraft:oak_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=true,open=true,powered=false]
|
||||
minecraft:oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=false,open=false,powered=false]
|
||||
minecraft:oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=false,open=true,powered=false]
|
||||
minecraft:oak_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=true,open=false,powered=false]
|
||||
minecraft:oak_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=true,open=true,powered=false]
|
||||
minecraft:oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=false,open=false,powered=false]
|
||||
minecraft:oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=false,open=true,powered=false]
|
||||
minecraft:oak_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=true,open=false,powered=false]
|
||||
minecraft:oak_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=true,open=true,powered=false]
|
||||
minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]
|
||||
minecraft:oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=false,open=true,powered=false]
|
||||
minecraft:oak_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=true,open=false,powered=false]
|
||||
minecraft:oak_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=true,open=true,powered=false]
|
||||
|
||||
#### Chorus Plant ####
|
||||
# Chorus Plant does support transparent textures, but man... its hitbox is super weird. You're probably better off using leaves.
|
||||
# minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true]
|
||||
|
||||
@@ -16,6 +16,7 @@ lang:
|
||||
block_name:default:palm_leaves: Palm Leaves
|
||||
block_name:default:palm_trapdoor: Palm Trapdoor
|
||||
block_name:default:palm_door: Palm Door
|
||||
block_name:default:palm_fence_gate: Palm Fence Gate
|
||||
block_name:default:fairy_flower: Fairy Flower
|
||||
block_name:default:reed: Reed
|
||||
block_name:default:flame_cane: Flame Cane
|
||||
@@ -37,6 +38,7 @@ lang:
|
||||
block_name:default:palm_leaves: 棕榈树叶
|
||||
block_name:default:palm_trapdoor: 棕榈木活板门
|
||||
block_name:default:palm_door: 棕榈木门
|
||||
block_name:default:palm_fence_gate: 棕榈木栅门
|
||||
block_name:default:fairy_flower: 仙灵花
|
||||
block_name:default:reed: 芦苇
|
||||
block_name:default:flame_cane: 烈焰甘蔗
|
||||
|
||||
@@ -24,6 +24,7 @@ categories:
|
||||
- default:palm_planks
|
||||
- default:palm_trapdoor
|
||||
- default:palm_door
|
||||
- default:palm_fence_gate
|
||||
default:topaz:
|
||||
name: <!i><#FF8C00><i18n:category.topaz></#FF8C00>
|
||||
hidden: true
|
||||
|
||||
@@ -33,6 +33,7 @@ i18n:
|
||||
item.palm_leaves: Palm Leaves
|
||||
item.palm_trapdoor: Palm Trapdoor
|
||||
item.palm_door: Palm Door
|
||||
item.palm_fence_gate: Palm Fence Gate
|
||||
item.netherite_anvil: Netherite Anvil
|
||||
item.gunpowder_block: GunPowder Block
|
||||
item.solid_gunpowder_block: Solid GunPowder Block
|
||||
@@ -82,6 +83,7 @@ i18n:
|
||||
item.palm_leaves: 棕榈树叶
|
||||
item.palm_trapdoor: 棕榈木活板门
|
||||
item.palm_door: 棕榈木门
|
||||
item.palm_fence_gate: 棕榈木栅栏门
|
||||
item.netherite_anvil: 下界合金砧
|
||||
item.gunpowder_block: 火药粉末
|
||||
item.solid_gunpowder_block: 凝固火药块
|
||||
|
||||
@@ -421,6 +421,61 @@ items:
|
||||
textures:
|
||||
bottom: minecraft:block/custom/palm_door_bottom
|
||||
top: minecraft:block/custom/palm_door_top
|
||||
default:palm_fence_gate:
|
||||
material: nether_brick
|
||||
custom-model-data: 1008
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_fence_gate>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/palm_fence_gate
|
||||
generation:
|
||||
parent: minecraft:block/custom/palm_fence_gate
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
behaviors:
|
||||
type: fence_gate_block
|
||||
can-open-with-hand: true
|
||||
can-open-by-wind-charge: true
|
||||
sounds:
|
||||
open: block.fence_gate.open
|
||||
close: block.fence_gate.close
|
||||
loot:
|
||||
template: default:loot_table/self
|
||||
settings:
|
||||
item: default:palm_fence_gate
|
||||
sounds:
|
||||
break: minecraft:block.wood.break
|
||||
step: minecraft:block.wood.step
|
||||
place: minecraft:block.wood.place
|
||||
hit: minecraft:block.wood.hit
|
||||
fall: minecraft:block.wood.fall
|
||||
tags:
|
||||
- minecraft:fence_gates
|
||||
- minecraft:mineable/axe
|
||||
- minecraft:unstable_bottom_center
|
||||
states:
|
||||
template: default:block_state/fence_gate
|
||||
arguments:
|
||||
base_block: oak_fence_gate
|
||||
model_fence_gate_path: minecraft:block/custom/palm_fence_gate
|
||||
model_fence_gate_generation:
|
||||
parent: minecraft:block/template_fence_gate
|
||||
textures: &textures
|
||||
texture: minecraft:block/custom/palm_fence_gate
|
||||
model_fence_gate_open_path: minecraft:block/custom/palm_fence_gate_open
|
||||
model_fence_gate_open_generation:
|
||||
parent: minecraft:block/template_fence_gate_open
|
||||
textures: *textures
|
||||
model_fence_gate_wall_path: minecraft:block/custom/palm_fence_gate_wall
|
||||
model_fence_gate_wall_generation:
|
||||
parent: minecraft:block/template_fence_gate_wall
|
||||
textures: *textures
|
||||
model_fence_gate_wall_open_path: minecraft:block/custom/palm_fence_gate_wall_open
|
||||
model_fence_gate_wall_open_generation:
|
||||
parent: minecraft:block/template_fence_gate_wall_open
|
||||
textures: *textures
|
||||
recipes:
|
||||
default:palm_planks:
|
||||
template: default:recipe/planks
|
||||
|
||||
@@ -1831,6 +1831,214 @@ templates#block_states:
|
||||
facing=west,half=upper,hinge=right,open=true,powered=false:
|
||||
appearance: facing=west,half=upper,hinge=right,open=true
|
||||
id: 63
|
||||
# fence gate block
|
||||
default:block_state/fence_gate:
|
||||
properties:
|
||||
facing:
|
||||
type: horizontal_direction
|
||||
in_wall:
|
||||
type: boolean
|
||||
default: false
|
||||
open:
|
||||
type: boolean
|
||||
default: false
|
||||
powered:
|
||||
type: boolean
|
||||
default: false
|
||||
appearances:
|
||||
facing=east,in_wall=false,open=false:
|
||||
state: ${base_block}[facing=east,in_wall=false,open=false,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_path}
|
||||
y: 270
|
||||
uvlock: true
|
||||
generation: ${model_fence_gate_generation}
|
||||
facing=east,in_wall=false,open=true:
|
||||
state: ${base_block}[facing=east,in_wall=false,open=true,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_open_path}
|
||||
y: 270
|
||||
uvlock: true
|
||||
generation: ${model_fence_gate_open_generation}
|
||||
facing=east,in_wall=true,open=false:
|
||||
state: ${base_block}[facing=east,in_wall=true,open=false,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_wall_path}
|
||||
y: 270
|
||||
uvlock: true
|
||||
generation: ${model_fence_gate_wall_generation}
|
||||
facing=east,in_wall=true,open=true:
|
||||
state: ${base_block}[facing=east,in_wall=true,open=true,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_wall_open_path}
|
||||
y: 270
|
||||
uvlock: true
|
||||
generation: ${model_fence_gate_wall_open_generation}
|
||||
facing=north,in_wall=false,open=false:
|
||||
state: ${base_block}[facing=north,in_wall=false,open=false,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_path}
|
||||
y: 180
|
||||
uvlock: true
|
||||
facing=north,in_wall=false,open=true:
|
||||
state: ${base_block}[facing=north,in_wall=false,open=true,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_open_path}
|
||||
y: 180
|
||||
uvlock: true
|
||||
facing=north,in_wall=true,open=false:
|
||||
state: ${base_block}[facing=north,in_wall=true,open=false,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_wall_path}
|
||||
y: 180
|
||||
uvlock: true
|
||||
facing=north,in_wall=true,open=true:
|
||||
state: ${base_block}[facing=north,in_wall=true,open=true,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_wall_open_path}
|
||||
y: 180
|
||||
uvlock: true
|
||||
facing=south,in_wall=false,open=false:
|
||||
state: ${base_block}[facing=south,in_wall=false,open=false,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_path}
|
||||
uvlock: true
|
||||
facing=south,in_wall=false,open=true:
|
||||
state: ${base_block}[facing=south,in_wall=false,open=true,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_open_path}
|
||||
uvlock: true
|
||||
facing=south,in_wall=true,open=false:
|
||||
state: ${base_block}[facing=south,in_wall=true,open=false,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_wall_path}
|
||||
uvlock: true
|
||||
facing=south,in_wall=true,open=true:
|
||||
state: ${base_block}[facing=south,in_wall=true,open=true,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_wall_open_path}
|
||||
uvlock: true
|
||||
facing=west,in_wall=false,open=false:
|
||||
state: ${base_block}[facing=west,in_wall=false,open=false,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_path}
|
||||
y: 90
|
||||
uvlock: true
|
||||
facing=west,in_wall=false,open=true:
|
||||
state: ${base_block}[facing=west,in_wall=false,open=true,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_open_path}
|
||||
y: 90
|
||||
uvlock: true
|
||||
facing=west,in_wall=true,open=false:
|
||||
state: ${base_block}[facing=west,in_wall=true,open=false,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_wall_path}
|
||||
y: 90
|
||||
uvlock: true
|
||||
facing=west,in_wall=true,open=true:
|
||||
state: ${base_block}[facing=west,in_wall=true,open=true,powered=true]
|
||||
model:
|
||||
path: ${model_fence_gate_wall_open_path}
|
||||
y: 90
|
||||
uvlock: true
|
||||
variants:
|
||||
facing=east,in_wall=false,open=false,powered=true:
|
||||
appearance: facing=east,in_wall=false,open=false
|
||||
id: 0
|
||||
facing=east,in_wall=false,open=false,powered=false:
|
||||
appearance: facing=east,in_wall=false,open=false
|
||||
id: 1
|
||||
facing=east,in_wall=false,open=true,powered=true:
|
||||
appearance: facing=east,in_wall=false,open=true
|
||||
id: 2
|
||||
facing=east,in_wall=false,open=true,powered=false:
|
||||
appearance: facing=east,in_wall=false,open=true
|
||||
id: 3
|
||||
facing=east,in_wall=true,open=false,powered=true:
|
||||
appearance: facing=east,in_wall=true,open=false
|
||||
id: 4
|
||||
facing=east,in_wall=true,open=false,powered=false:
|
||||
appearance: facing=east,in_wall=true,open=false
|
||||
id: 5
|
||||
facing=east,in_wall=true,open=true,powered=true:
|
||||
appearance: facing=east,in_wall=true,open=true
|
||||
id: 6
|
||||
facing=east,in_wall=true,open=true,powered=false:
|
||||
appearance: facing=east,in_wall=true,open=true
|
||||
id: 7
|
||||
facing=south,in_wall=false,open=false,powered=true:
|
||||
appearance: facing=south,in_wall=false,open=false
|
||||
id: 8
|
||||
facing=south,in_wall=false,open=false,powered=false:
|
||||
appearance: facing=south,in_wall=false,open=false
|
||||
id: 9
|
||||
facing=south,in_wall=false,open=true,powered=true:
|
||||
appearance: facing=south,in_wall=false,open=true
|
||||
id: 10
|
||||
facing=south,in_wall=false,open=true,powered=false:
|
||||
appearance: facing=south,in_wall=false,open=true
|
||||
id: 11
|
||||
facing=south,in_wall=true,open=false,powered=true:
|
||||
appearance: facing=south,in_wall=true,open=false
|
||||
id: 12
|
||||
facing=south,in_wall=true,open=false,powered=false:
|
||||
appearance: facing=south,in_wall=true,open=false
|
||||
id: 13
|
||||
facing=south,in_wall=true,open=true,powered=true:
|
||||
appearance: facing=south,in_wall=true,open=true
|
||||
id: 14
|
||||
facing=south,in_wall=true,open=true,powered=false:
|
||||
appearance: facing=south,in_wall=true,open=true
|
||||
id: 15
|
||||
facing=west,in_wall=false,open=false,powered=true:
|
||||
appearance: facing=west,in_wall=false,open=false
|
||||
id: 16
|
||||
facing=west,in_wall=false,open=false,powered=false:
|
||||
appearance: facing=west,in_wall=false,open=false
|
||||
id: 17
|
||||
facing=west,in_wall=false,open=true,powered=true:
|
||||
appearance: facing=west,in_wall=false,open=true
|
||||
id: 18
|
||||
facing=west,in_wall=false,open=true,powered=false:
|
||||
appearance: facing=west,in_wall=false,open=true
|
||||
id: 19
|
||||
facing=west,in_wall=true,open=false,powered=true:
|
||||
appearance: facing=west,in_wall=true,open=false
|
||||
id: 20
|
||||
facing=west,in_wall=true,open=false,powered=false:
|
||||
appearance: facing=west,in_wall=true,open=false
|
||||
id: 21
|
||||
facing=west,in_wall=true,open=true,powered=true:
|
||||
appearance: facing=west,in_wall=true,open=true
|
||||
id: 22
|
||||
facing=west,in_wall=true,open=true,powered=false:
|
||||
appearance: facing=west,in_wall=true,open=true
|
||||
id: 23
|
||||
facing=north,in_wall=false,open=false,powered=true:
|
||||
appearance: facing=north,in_wall=false,open=false
|
||||
id: 24
|
||||
facing=north,in_wall=false,open=false,powered=false:
|
||||
appearance: facing=north,in_wall=false,open=false
|
||||
id: 25
|
||||
facing=north,in_wall=false,open=true,powered=true:
|
||||
appearance: facing=north,in_wall=false,open=true
|
||||
id: 26
|
||||
facing=north,in_wall=false,open=true,powered=false:
|
||||
appearance: facing=north,in_wall=false,open=true
|
||||
id: 27
|
||||
facing=north,in_wall=true,open=false,powered=true:
|
||||
appearance: facing=north,in_wall=true,open=false
|
||||
id: 28
|
||||
facing=north,in_wall=true,open=false,powered=false:
|
||||
appearance: facing=north,in_wall=true,open=false
|
||||
id: 29
|
||||
facing=north,in_wall=true,open=true,powered=true:
|
||||
appearance: facing=north,in_wall=true,open=true
|
||||
id: 30
|
||||
facing=north,in_wall=true,open=true,powered=false:
|
||||
appearance: facing=north,in_wall=true,open=true
|
||||
id: 31
|
||||
|
||||
# recipes
|
||||
templates#recipes:
|
||||
|
||||
@@ -258,6 +258,10 @@ warning.config.block.behavior.trapdoor.missing_open: "<yellow>Issue found in fil
|
||||
warning.config.block.behavior.trapdoor.missing_powered: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'powered' property for 'trapdoor_block' behavior.</yellow>"
|
||||
warning.config.block.behavior.stackable.missing_amount: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'amount' property for 'stackable_block' behavior.</yellow>"
|
||||
warning.config.block.behavior.stackable.missing_items: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'items' argument for 'stackable_block' behavior.</yellow>"
|
||||
warning.config.block.behavior.fence_gate.missing_facing: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'facing' argument for 'fence_gate' behavior.</yellow>"
|
||||
warning.config.block.behavior.fence_gate.missing_in_wall: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'in_wall' argument for 'fence_gate' behavior.</yellow>"
|
||||
warning.config.block.behavior.fence_gate.missing_open: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'powered' argument for 'fence_gate' behavior.</yellow>"
|
||||
warning.config.block.behavior.fence_gate.missing_powered: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'open' argument for 'fence_gate' behavior.</yellow>"
|
||||
warning.config.model.generation.missing_parent: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'parent' argument in 'generation' section.</yellow>"
|
||||
warning.config.model.generation.invalid_display_position: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid display position '<arg:2>' in 'generation.display' section. Allowed display positions: [<arg:3>]</yellow>"
|
||||
warning.config.model.generation.invalid_gui_light: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid gui-light option '<arg:2>' in 'generation' section. Allowed gui light options: [<arg:3>]</yellow>"
|
||||
|
||||
@@ -258,6 +258,10 @@ warning.config.block.behavior.trapdoor.missing_open: "<yellow>在文件 <arg:0>
|
||||
warning.config.block.behavior.trapdoor.missing_powered: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'trapdoor_block' 行为缺少必需的 'powered' 属性</yellow>"
|
||||
warning.config.block.behavior.stackable.missing_amount: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'stackable_block' 行为缺少必需的 'amount' 属性</yellow>"
|
||||
warning.config.block.behavior.stackable.missing_items: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'stackable_block' 行为缺少必需的 'items' 参数</yellow>"
|
||||
warning.config.block.behavior.fence_gate.missing_facing: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'fence_gate' 行为缺少必需的 'facing' 属性</yellow>"
|
||||
warning.config.block.behavior.fence_gate.missing_in_wall: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'fence_gate' 行为缺少必需的 'in_wall' 属性</yellow>"
|
||||
warning.config.block.behavior.fence_gate.missing_open: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'fence_gate' 行为缺少必需的 'open' 属性</yellow>"
|
||||
warning.config.block.behavior.fence_gate.missing_powered: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'fence_gate' 行为缺少必需的 'powered' 属性</yellow>"
|
||||
warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</yellow>"
|
||||
warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 发现问题 - 无法为 '<arg:1>' 生成模型 存在多个配置尝试使用相同路径 '<arg:2>' 生成不同的 JSON 模型</yellow>"
|
||||
warning.config.model.generation.invalid_display_position: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 在 'generation.display' 区域使用了无效的 display 位置类型 '<arg:2>'. 可用展示类型: [<arg:3>]</yellow>"
|
||||
|
||||
@@ -12,18 +12,13 @@ public final class ClassTreeIdRegistry {
|
||||
|
||||
public int getLastIdFor(Class<?> clazz) {
|
||||
int cachedId = this.classToLastIdCache.getInt(clazz);
|
||||
if (cachedId == -1) {
|
||||
Class<?> currentClass = clazz;
|
||||
while ((currentClass = currentClass.getSuperclass()) != Object.class) {
|
||||
int parentCachedId = this.classToLastIdCache.getInt(currentClass);
|
||||
if (parentCachedId != -1) {
|
||||
return parentCachedId;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
return cachedId;
|
||||
if (cachedId != -1) return cachedId;
|
||||
Class<?> currentClass = clazz;
|
||||
while ((currentClass = currentClass.getSuperclass()) != Object.class) {
|
||||
int parentCachedId = this.classToLastIdCache.getInt(currentClass);
|
||||
if (parentCachedId != -1) return parentCachedId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int define(Class<?> clazz) {
|
||||
|
||||
@@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=0.0.57.5
|
||||
config_version=37
|
||||
lang_version=17
|
||||
lang_version=18
|
||||
project_group=net.momirealms
|
||||
latest_supported_version=1.21.6
|
||||
|
||||
@@ -51,7 +51,7 @@ byte_buddy_version=1.17.5
|
||||
ahocorasick_version=0.6.3
|
||||
snake_yaml_version=2.4
|
||||
anti_grief_version=0.17
|
||||
nms_helper_version=0.67.26
|
||||
nms_helper_version=0.67.27
|
||||
evalex_version=3.5.0
|
||||
reactive_streams_version=1.0.4
|
||||
amazon_awssdk_version=2.31.23
|
||||
|
||||
Reference in New Issue
Block a user