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

完善门音效

This commit is contained in:
XiaoMoMi
2025-06-20 22:36:17 +08:00
parent 134e14351b
commit fc0e11cafb
13 changed files with 187 additions and 36 deletions

View File

@@ -39,6 +39,8 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.registry.WritableRegistry;
import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.sound.Sounds;
import net.momirealms.craftengine.core.util.*;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -53,6 +55,10 @@ import java.io.File;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class BukkitBlockManager extends AbstractBlockManager {
private static BukkitBlockManager instance;
@@ -74,6 +80,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
private Map<Key, Integer> registeredRealBlockSlots;
// A set of blocks that sounds have been removed
private Set<Object> affectedSoundBlocks;
private Map<Object, Pair<SoundData, SoundData>> affectedOpenableBlockSounds;
private Map<Key, Key> soundMapper;
// A list to record the order of registration
private List<Key> blockRegisterOrder = new ObjectArrayList<>();
@@ -285,7 +292,8 @@ public class BukkitBlockManager extends AbstractBlockManager {
ImmutableMap.Builder<Key, Integer> builder1 = ImmutableMap.builder();
ImmutableMap.Builder<Integer, Object> builder2 = ImmutableMap.builder();
ImmutableMap.Builder<Key, List<Integer>> builder3 = ImmutableMap.builder();
Set<Object> affectedSounds = new HashSet<>();
Set<Object> affectedBlockSounds = new HashSet<>();
Map<Object, Pair<SoundData, SoundData>> affectedDoors = new IdentityHashMap<>();
Set<Object> affectedBlocks = new HashSet<>();
List<Key> order = new ArrayList<>();
@@ -293,7 +301,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
int counter = 0;
for (Map.Entry<Key, Integer> baseBlockAndItsCount : this.registeredRealBlockSlots.entrySet()) {
counter = registerBlockVariants(baseBlockAndItsCount, counter, builder1, builder2, builder3, affectedSounds, order);
counter = registerBlockVariants(baseBlockAndItsCount, counter, builder1, builder2, builder3, affectedBlockSounds, order);
}
freezeRegistry();
@@ -306,7 +314,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
for (Object block : (Iterable<Object>) MBuiltInRegistries.BLOCK) {
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(block);
if (affectedSounds.contains(soundType)) {
if (affectedBlockSounds.contains(soundType)) {
Object state = getOnlyBlockState(block);
if (BlockStateUtils.isVanillaBlock(state)) {
affectedBlocks.add(block);
@@ -320,7 +328,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
this.affectedSoundBlocks = ImmutableSet.copyOf(affectedBlocks);
ImmutableMap.Builder<Key, Key> soundMapperBuilder = ImmutableMap.builder();
for (Object soundType : affectedSounds) {
for (Object soundType : affectedBlockSounds) {
for (Field field : List.of(CoreReflections.field$SoundType$placeSound, CoreReflections.field$SoundType$fallSound, CoreReflections.field$SoundType$hitSound, CoreReflections.field$SoundType$stepSound, CoreReflections.field$SoundType$breakSound)) {
Object soundEvent = field.get(soundType);
Key previousId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(soundEvent).toString());
@@ -328,12 +336,53 @@ public class BukkitBlockManager extends AbstractBlockManager {
}
}
Predicate<Key> predicate = it -> this.realBlockArranger.containsKey(it);
Consumer<Key> soundCallback = s -> soundMapperBuilder.put(s, Key.of("replaced." + s.value()));
BiConsumer<Object, Pair<SoundData, SoundData>> affectedBlockCallback = affectedDoors::put;
Function<Key, SoundData> soundMapper = (k) -> SoundData.of(k, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f));
collectDoorSounds(predicate, Sounds.WOODEN_TRAPDOOR_OPEN, Sounds.WOODEN_TRAPDOOR_CLOSE, Sounds.WOODEN_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.NETHER_WOOD_TRAPDOOR_OPEN, Sounds.NETHER_WOOD_TRAPDOOR_CLOSE, Sounds.NETHER_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_TRAPDOOR_OPEN, Sounds.BAMBOO_WOOD_TRAPDOOR_CLOSE, Sounds.BAMBOO_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.CHERRY_WOOD_TRAPDOOR_OPEN, Sounds.CHERRY_WOOD_TRAPDOOR_CLOSE, Sounds.CHERRY_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.COPPER_TRAPDOOR_OPEN, Sounds.COPPER_TRAPDOOR_CLOSE, Sounds.COPPER_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.WOODEN_DOOR_OPEN, Sounds.WOODEN_DOOR_CLOSE, Sounds.WOODEN_DOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.NETHER_WOOD_DOOR_OPEN, Sounds.NETHER_WOOD_DOOR_CLOSE, Sounds.NETHER_DOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_DOOR_OPEN, Sounds.BAMBOO_WOOD_DOOR_CLOSE, Sounds.BAMBOO_DOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.CHERRY_WOOD_DOOR_OPEN, Sounds.CHERRY_WOOD_DOOR_CLOSE, Sounds.CHERRY_DOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.COPPER_DOOR_OPEN, Sounds.COPPER_DOOR_CLOSE, Sounds.COPPER_DOORS, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.WOODEN_FENCE_GATE_OPEN, Sounds.WOODEN_FENCE_GATE_CLOSE, Sounds.WOODEN_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.NETHER_WOOD_FENCE_GATE_OPEN, Sounds.NETHER_WOOD_FENCE_GATE_CLOSE, Sounds.NETHER_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_FENCE_GATE_OPEN, Sounds.BAMBOO_WOOD_FENCE_GATE_CLOSE, Sounds.BAMBOO_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback);
collectDoorSounds(predicate, Sounds.CHERRY_WOOD_FENCE_GATE_OPEN, Sounds.CHERRY_WOOD_FENCE_GATE_CLOSE, Sounds.CHERRY_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback);
this.affectedOpenableBlockSounds = ImmutableMap.copyOf(affectedDoors);
this.soundMapper = soundMapperBuilder.buildKeepingLast();
} catch (Throwable e) {
plugin.logger().warn("Failed to inject blocks.", e);
}
}
private void collectDoorSounds(Predicate<Key> isUsedForCustomBlock,
Key openSound,
Key closeSound,
List<Key> doors,
Function<Key, SoundData> soundMapper,
Consumer<Key> soundCallback,
BiConsumer<Object, Pair<SoundData, SoundData>> affectedBlockCallback) {
for (Key d : doors) {
if (isUsedForCustomBlock.test(d)) {
soundCallback.accept(openSound);
soundCallback.accept(closeSound);
for (Key door : doors) {
Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(door));
if (block != null) {
affectedBlockCallback.accept(block, Pair.of(soundMapper.apply(Key.of("replaced." + openSound.value())), soundMapper.apply(Key.of("replaced." + closeSound.value()))));
}
}
break;
}
}
}
public class BlockParser implements ConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"};
@@ -598,6 +647,14 @@ public class BukkitBlockManager extends AbstractBlockManager {
return this.affectedSoundBlocks.contains(block);
}
public boolean isOpenableBlockSoundRemoved(Object block) {
return this.affectedOpenableBlockSounds.containsKey(block);
}
public SoundData getRemovedOpenableBlockSound(Object block, boolean open) {
return open ? this.affectedOpenableBlockSounds.get(block).left() : this.affectedOpenableBlockSounds.get(block).right();
}
private Map<String, String> loadBlockStateMappings(YamlDocument mappings) {
Map<String, String> blockStateMappings = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : mappings.getStringRouteMappedValues(false).entrySet()) {

View File

@@ -238,15 +238,8 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
if (!this.canOpenWithHand) {
return InteractionResult.PASS;
}
if (context.getItem() == null) {
setOpen(context.getPlayer(), context.getLevel().serverWorld(), state, context.getClickedPos(), !state.get(this.openProperty));
return InteractionResult.SUCCESS;
} else if (!context.getPlayer().isSecondaryUseActive()) {
setOpen(context.getPlayer(), context.getLevel().serverWorld(), state, context.getClickedPos(), !state.get(this.openProperty));
return InteractionResult.SUCCESS_AND_CANCEL;
} else {
return InteractionResult.PASS;
}
setOpen(context.getPlayer(), context.getLevel().serverWorld(), state, context.getClickedPos(), !state.get(this.openProperty));
return InteractionResult.SUCCESS_AND_CANCEL;
}
@Override

View File

@@ -21,7 +21,6 @@ import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World;
import org.bukkit.Location;
import org.bukkit.SoundCategory;
import org.bukkit.inventory.ItemStack;
import java.util.List;

View File

@@ -49,6 +49,7 @@ public class StrippableBlockBehavior extends BukkitBlockBehavior {
return this.stripped;
}
// TODO 转移到 axe_item里
@SuppressWarnings("unchecked")
@Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {

View File

@@ -108,19 +108,12 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
}
@Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
public InteractionResult useWithoutItem(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;
}
playerToggle(context, state);
return InteractionResult.SUCCESS_AND_CANCEL;
}
@SuppressWarnings("unchecked")

View File

@@ -20,18 +20,23 @@ import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.item.setting.FoodData;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.world.BlockHitResult;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Vec3d;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Openable;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -167,17 +172,45 @@ public class ItemEventListener implements Listener {
if (hitResult != null) {
UseOnContext useOnContext = new UseOnContext(serverPlayer, hand, itemInHand, hitResult);
if (immutableBlockState.behavior() instanceof AbstractBlockBehavior behavior) {
InteractionResult result = behavior.useOnBlock(useOnContext, immutableBlockState);
if (result.success()) {
serverPlayer.updateLastSuccessfulInteractionTick(serverPlayer.gameTicks());
boolean hasItem = player.getInventory().getItemInMainHand().getType() != Material.AIR || player.getInventory().getItemInOffHand().getType() != Material.AIR;
boolean flag = player.isSneaking() && hasItem;
if (!flag) {
if (immutableBlockState.behavior() instanceof AbstractBlockBehavior behavior) {
InteractionResult result = behavior.useOnBlock(useOnContext, immutableBlockState);
if (result.success()) {
serverPlayer.updateLastSuccessfulInteractionTick(serverPlayer.gameTicks());
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
event.setCancelled(true);
}
return;
}
if (result == InteractionResult.TRY_EMPTY_HAND && hand == InteractionHand.MAIN_HAND) {
result = behavior.useWithoutItem(useOnContext, immutableBlockState);
if (result.success()) {
serverPlayer.updateLastSuccessfulInteractionTick(serverPlayer.gameTicks());
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
event.setCancelled(true);
}
return;
}
}
if (result == InteractionResult.FAIL) {
return;
}
}
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
event.setCancelled(true);
return;
}
if (result != InteractionResult.PASS) {
return;
}
}
} else {
if (Config.enableSoundSystem() && hitResult != null) {
Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState);
if (this.plugin.blockManager().isOpenableBlockSoundRemoved(blockOwner)) {
boolean hasItem = player.getInventory().getItemInMainHand().getType() != Material.AIR || player.getInventory().getItemInOffHand().getType() != Material.AIR;
boolean flag = player.isSneaking() && hasItem;
if (!flag) {
if (blockData instanceof Openable openable) {
SoundData soundData = this.plugin.blockManager().getRemovedOpenableBlockSound(blockOwner, !openable.isOpen());
serverPlayer.playSound(soundData.id(), SoundSource.BLOCK, soundData.volume().get(), soundData.pitch().get());
}
}
}
}

View File

@@ -6,6 +6,10 @@
# An anvil has four possible orientations, but the east-west and north-south orientations look exactly the same.
minecraft:anvil[facing=north]: minecraft:anvil[facing=south]
minecraft:anvil[facing=east]: minecraft:anvil[facing=west]
minecraft:chipped_anvil[facing=north]: minecraft:chipped_anvil[facing=south]
minecraft:chipped_anvil[facing=east]: minecraft:chipped_anvil[facing=west]
minecraft:damaged_anvil[facing=north]: minecraft:damaged_anvil[facing=south]
minecraft:damaged_anvil[facing=east]: minecraft:damaged_anvil[facing=west]
#### Sapling ####
# Every sapling has two stages, 0 and 1, but they look exactly the same.

View File

@@ -463,7 +463,7 @@ items:
model_fence_gate_generation:
parent: minecraft:block/template_fence_gate
textures: &textures
texture: minecraft:block/custom/palm_fence_gate
texture: minecraft:block/custom/palm_planks
model_fence_gate_open_path: minecraft:block/custom/palm_fence_gate_open
model_fence_gate_open_generation:
parent: minecraft:block/template_fence_gate_open

View File

@@ -99,6 +99,10 @@ public abstract class BlockBehavior {
}
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
return InteractionResult.TRY_EMPTY_HAND;
}
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
return InteractionResult.PASS;
}

View File

@@ -118,6 +118,7 @@ public class BlockKeys {
public static final Key BAMBOO_TRAPDOOR = Key.of("minecraft:bamboo_trapdoor");
public static final Key CRIMSON_TRAPDOOR = Key.of("minecraft:crimson_trapdoor");
public static final Key WARPED_TRAPDOOR = Key.of("minecraft:warped_trapdoor");
public static final Key IRON_TRAPDOOR = Key.of("minecraft:iron_trapdoor");
public static final Key OAK_DOOR = Key.of("minecraft:oak_door");
public static final Key SPRUCE_DOOR = Key.of("minecraft:spruce_door");
@@ -131,6 +132,7 @@ public class BlockKeys {
public static final Key BAMBOO_DOOR = Key.of("minecraft:bamboo_door");
public static final Key CRIMSON_DOOR = Key.of("minecraft:crimson_door");
public static final Key WARPED_DOOR = Key.of("minecraft:warped_door");
public static final Key IRON_DOOR = Key.of("minecraft:iron_door");
public static final Key COPPER_DOOR = Key.of("minecraft:copper_door");
public static final Key EXPOSED_COPPER_DOOR = Key.of("minecraft:exposed_copper_door");

View File

@@ -4,6 +4,7 @@ public enum InteractionResult {
FAIL(false),
SUCCESS(true),
PASS(false),
TRY_EMPTY_HAND(false),
SUCCESS_AND_CANCEL(true);
private final boolean success;

View File

@@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.sound;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.RandomUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.HashMap;
import java.util.Map;
@@ -26,6 +25,10 @@ public record SoundData(Key id, SoundValue volume, SoundValue pitch) {
}
}
public static SoundData of(Key id, SoundValue volume, SoundValue pitch) {
return new SoundData(id, volume, pitch);
}
public interface SoundValue extends Supplier<Float> {
Map<Float, SoundValue> FIXED = new HashMap<>();
SoundValue FIXED_1 = new Fixed(1f);

View File

@@ -0,0 +1,61 @@
package net.momirealms.craftengine.core.sound;
import net.momirealms.craftengine.core.block.BlockKeys;
import net.momirealms.craftengine.core.util.Key;
import java.util.List;
public final class Sounds {
private Sounds() {}
public static final List<Key> WOODEN_TRAPDOORS = List.of(BlockKeys.OAK_TRAPDOOR, BlockKeys.SPRUCE_TRAPDOOR, BlockKeys.BIRCH_TRAPDOOR,
BlockKeys.ACACIA_TRAPDOOR, BlockKeys.PALE_OAK_TRAPDOOR, BlockKeys.DARK_OAK_TRAPDOOR, BlockKeys.MANGROVE_TRAPDOOR, BlockKeys.JUNGLE_TRAPDOOR);
public static final List<Key> CHERRY_TRAPDOORS = List.of(BlockKeys.CHERRY_TRAPDOOR);
public static final List<Key> BAMBOO_TRAPDOORS = List.of(BlockKeys.BAMBOO_TRAPDOOR);
public static final List<Key> NETHER_TRAPDOORS = List.of(BlockKeys.WARPED_TRAPDOOR, BlockKeys.CRIMSON_TRAPDOOR);
public static final List<Key> COPPER_TRAPDOORS = List.of(BlockKeys.COPPER_TRAPDOOR, BlockKeys.EXPOSED_COPPER_TRAPDOOR, BlockKeys.WEATHERED_COPPER_TRAPDOOR, BlockKeys.OXIDIZED_COPPER_DOOR,
BlockKeys.WAXED_COPPER_TRAPDOOR, BlockKeys.WAXED_EXPOSED_COPPER_TRAPDOOR, BlockKeys.WAXED_WEATHERED_COPPER_TRAPDOOR, BlockKeys.WAXED_OXIDIZED_COPPER_TRAPDOOR);
public static final List<Key> WOODEN_DOORS = List.of(BlockKeys.OAK_DOOR, BlockKeys.SPRUCE_DOOR, BlockKeys.BIRCH_DOOR,
BlockKeys.ACACIA_DOOR, BlockKeys.PALE_OAK_DOOR, BlockKeys.DARK_OAK_DOOR, BlockKeys.MANGROVE_DOOR, BlockKeys.JUNGLE_DOOR);
public static final List<Key> CHERRY_DOORS = List.of(BlockKeys.CHERRY_DOOR);
public static final List<Key> BAMBOO_DOORS = List.of(BlockKeys.BAMBOO_DOOR);
public static final List<Key> NETHER_DOORS = List.of(BlockKeys.WARPED_DOOR, BlockKeys.CRIMSON_DOOR);
public static final List<Key> COPPER_DOORS = List.of(BlockKeys.COPPER_DOOR, BlockKeys.EXPOSED_COPPER_DOOR, BlockKeys.WEATHERED_COPPER_DOOR, BlockKeys.OXIDIZED_COPPER_DOOR,
BlockKeys.WAXED_COPPER_DOOR, BlockKeys.WAXED_EXPOSED_COPPER_DOOR, BlockKeys.WAXED_WEATHERED_COPPER_DOOR, BlockKeys.WAXED_OXIDIZED_COPPER_DOOR);
public static final List<Key> WOODEN_FENCE_GATES = List.of(BlockKeys.OAK_FENCE_GATE, BlockKeys.SPRUCE_FENCE_GATE, BlockKeys.BIRCH_FENCE_GATE,
BlockKeys.ACACIA_FENCE_GATE, BlockKeys.PALE_OAK_FENCE_GATE, BlockKeys.DARK_OAK_FENCE_GATE, BlockKeys.MANGROVE_FENCE_GATE, BlockKeys.JUNGLE_FENCE_GATE);
public static final List<Key> CHERRY_FENCE_GATES = List.of(BlockKeys.CHERRY_FENCE_GATE);
public static final List<Key> BAMBOO_FENCE_GATES = List.of(BlockKeys.BAMBOO_FENCE_GATE);
public static final List<Key> NETHER_FENCE_GATES = List.of(BlockKeys.WARPED_FENCE_GATE, BlockKeys.CRIMSON_FENCE_GATE);
public static final Key WOODEN_TRAPDOOR_OPEN = Key.of("block.wooden_trapdoor.open");
public static final Key WOODEN_TRAPDOOR_CLOSE = Key.of("block.wooden_trapdoor.close");
public static final Key WOODEN_DOOR_OPEN = Key.of("block.wooden_door.open");
public static final Key WOODEN_DOOR_CLOSE = Key.of("block.wooden_door.close");
public static final Key WOODEN_FENCE_GATE_OPEN = Key.of("block.fence_gate.open");
public static final Key WOODEN_FENCE_GATE_CLOSE = Key.of("block.fence_gate.close");
public static final Key NETHER_WOOD_TRAPDOOR_OPEN = Key.of("block.nether_wood_trapdoor.open");
public static final Key NETHER_WOOD_TRAPDOOR_CLOSE = Key.of("block.nether_wood_trapdoor.close");
public static final Key NETHER_WOOD_DOOR_OPEN = Key.of("block.nether_wood_door.open");
public static final Key NETHER_WOOD_DOOR_CLOSE = Key.of("block.nether_wood_door.close");
public static final Key NETHER_WOOD_FENCE_GATE_OPEN = Key.of("block.nether_wood_fence_gate.open");
public static final Key NETHER_WOOD_FENCE_GATE_CLOSE = Key.of("block.nether_wood_fence_gate.close");
public static final Key BAMBOO_WOOD_TRAPDOOR_OPEN = Key.of("block.bamboo_wood_trapdoor.open");
public static final Key BAMBOO_WOOD_TRAPDOOR_CLOSE = Key.of("block.bamboo_wood_trapdoor.close");
public static final Key BAMBOO_WOOD_DOOR_OPEN = Key.of("block.bamboo_wood_door.open");
public static final Key BAMBOO_WOOD_DOOR_CLOSE = Key.of("block.bamboo_wood_door.close");
public static final Key BAMBOO_WOOD_FENCE_GATE_OPEN = Key.of("block.bamboo_wood_fence_gate.open");
public static final Key BAMBOO_WOOD_FENCE_GATE_CLOSE = Key.of("block.bamboo_wood_fence_gate.close");
public static final Key CHERRY_WOOD_TRAPDOOR_OPEN = Key.of("block.cherry_wood_trapdoor.open");
public static final Key CHERRY_WOOD_TRAPDOOR_CLOSE = Key.of("block.cherry_wood_trapdoor.close");
public static final Key CHERRY_WOOD_DOOR_OPEN = Key.of("block.cherry_wood_door.open");
public static final Key CHERRY_WOOD_DOOR_CLOSE = Key.of("block.cherry_wood_door.close");
public static final Key CHERRY_WOOD_FENCE_GATE_OPEN = Key.of("block.cherry_wood_fence_gate.open");
public static final Key CHERRY_WOOD_FENCE_GATE_CLOSE = Key.of("block.cherry_wood_fence_gate.close");
public static final Key COPPER_TRAPDOOR_OPEN = Key.of("block.copper_trapdoor.open");
public static final Key COPPER_TRAPDOOR_CLOSE = Key.of("block.copper_trapdoor.close");
public static final Key COPPER_DOOR_OPEN = Key.of("block.copper_door.open");
public static final Key COPPER_DOOR_CLOSE = Key.of("block.copper_door.close");
}