diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java index 2a6dc7a81..963f5bac3 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java @@ -41,6 +41,7 @@ import org.bukkit.event.block.BlockPistonRetractEvent; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; @@ -120,7 +121,7 @@ public class GeyserPistonListener implements Listener { int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock()); // event.getDirection() is unreliable - Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId); + Direction orientation = BlockState.of(pistonBlockId).getValue(Properties.FACING); session.executeInEventLoop(() -> { PistonCache pistonCache = session.getPistonCache(); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index a04c60126..f45b68675 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -42,7 +42,6 @@ import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.WorldManager; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; @@ -88,7 +87,7 @@ public class GeyserSpigotWorldManager extends WorldManager { Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString())); return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); } - return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); + return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); // TODO could just make this a BlockState lookup? } @Override diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index 9894a4ba2..c8cbe384b 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -44,6 +44,7 @@ import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket; import org.geysermc.erosion.packet.backendbound.BackendboundPacket; import org.geysermc.erosion.packet.geyserbound.*; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; @@ -148,7 +149,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke @Override public void handlePistonEvent(GeyserboundPistonEventPacket packet) { - Direction orientation = BlockStateValues.getPistonOrientation(packet.getBlockId()); + Direction orientation = BlockState.of(packet.getBlockId()).getValue(Properties.FACING); Vector3i position = packet.getPos(); boolean isExtend = packet.isExtend(); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 8bc9cf1e2..d52c46e33 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -25,7 +25,10 @@ package org.geysermc.geyser.level.block; -import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.geysermc.geyser.level.block.property.Properties; @@ -36,16 +39,11 @@ import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; -import java.util.Locale; - /** * Used for block entities if the Java block state contains Bedrock block information. */ public final class BlockStateValues { - private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet(); - private static final IntSet STICKY_PISTONS = new IntOpenHashSet(); private static final Object2IntMap PISTON_HEADS = new Object2IntOpenHashMap<>(); - private static final Int2ObjectMap PISTON_ORIENTATION = new Int2ObjectOpenHashMap<>(); private static final IntSet ALL_PISTON_HEADS = new IntOpenHashSet(); private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap(); @@ -61,10 +59,6 @@ public final class BlockStateValues { */ public static void storeBlockStateValues(String javaId, int javaBlockState) { if (javaId.contains("piston[")) { // minecraft:moving_piston, minecraft:sticky_piston, minecraft:piston - if (javaId.contains("sticky")) { - STICKY_PISTONS.add(javaBlockState); - } - PISTON_ORIENTATION.put(javaBlockState, getBlockDirection(javaId)); return; } else if (javaId.startsWith("minecraft:piston_head")) { ALL_PISTON_HEADS.add(javaBlockState); @@ -78,27 +72,7 @@ public final class BlockStateValues { String strLevel = javaId.substring(javaId.lastIndexOf("level=") + 6, javaId.length() - 1); int level = Integer.parseInt(strLevel); WATER_LEVEL.put(javaBlockState, level); - return; } - - if (javaId.startsWith("minecraft:jigsaw[orientation=")) { - String blockStateData = javaId.substring(javaId.indexOf("orientation=") + "orientation=".length(), javaId.lastIndexOf('_')); - Direction direction = Direction.valueOf(blockStateData.toUpperCase(Locale.ROOT)); - if (direction.isHorizontal()) { - HORIZONTAL_FACING_JIGSAWS.add(javaBlockState); - } - } - } - - /** - * @return a set of all forward-facing jigsaws, to use as a fallback if NBT is missing. - */ - public static IntSet getHorizontalFacingJigsaws() { - return HORIZONTAL_FACING_JIGSAWS; - } - - public static boolean isStickyPiston(int blockState) { - return STICKY_PISTONS.contains(blockState); } public static boolean isPistonHead(int state) { @@ -116,17 +90,6 @@ public final class BlockStateValues { return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID); } - /** - * This is used in GeyserPistonEvents.java and accepts minecraft:piston, - * minecraft:sticky_piston, and minecraft:moving_piston. - * - * @param state The block state of the piston base - * @return The direction in which the piston faces - */ - public static Direction getPistonOrientation(int state) { - return PISTON_ORIENTATION.get(state); - } - /** * Checks if a block sticks to other blocks * (Slime and honey blocks) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java b/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java index 91f02d65e..283ca2503 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.level.block; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.property.ChestType; +import org.geysermc.geyser.level.block.property.FrontAndTop; import org.geysermc.geyser.level.block.type.*; import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Direction; @@ -2169,7 +2170,7 @@ public final class Blocks { public static final Block STRUCTURE_BLOCK = register(new Block("structure_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .enumState(STRUCTUREBLOCK_MODE, "save", "load", "corner", "data"))); public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) - .enumState(ORIENTATION, "down_east", "down_north", "down_south", "down_west", "up_east", "up_north", "up_south", "up_west", "west_up", "east_up", "north_up", "south_up"))); + .enumState(ORIENTATION, FrontAndTop.VALUES))); public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f) .intState(LEVEL_COMPOSTER, 0, 8))); public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f) @@ -2799,7 +2800,7 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block CRAFTER = register(new Block("crafter", builder().setBlockEntity().destroyTime(1.5f) .booleanState(CRAFTING) - .enumState(ORIENTATION, "down_east", "down_north", "down_south", "down_west", "up_east", "up_north", "up_south", "up_west", "west_up", "east_up", "north_up", "south_up") + .enumState(ORIENTATION, FrontAndTop.VALUES) .booleanState(TRIGGERED))); public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f) .booleanState(OMINOUS) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/FrontAndTop.java b/core/src/main/java/org/geysermc/geyser/level/block/property/FrontAndTop.java new file mode 100644 index 000000000..e674ac424 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/FrontAndTop.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.level.block.property; + +import org.geysermc.geyser.level.physics.Direction; + +public enum FrontAndTop { + DOWN_EAST(Direction.DOWN), + DOWN_NORTH(Direction.DOWN), + DOWN_SOUTH(Direction.DOWN), + DOWN_WEST(Direction.DOWN), + UP_EAST(Direction.UP), + UP_NORTH(Direction.UP), + UP_SOUTH(Direction.UP), + UP_WEST(Direction.UP), + WEST_UP(Direction.WEST), + EAST_UP(Direction.EAST), + NORTH_UP(Direction.NORTH), + SOUTH_UP(Direction.SOUTH); + + private final boolean horizontal; + + FrontAndTop(Direction front) { + this.horizontal = front.isHorizontal(); + } + + public boolean isHorizontal() { + return horizontal; + } + + public static final FrontAndTop[] VALUES = values(); +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java b/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java index 339d82f96..7df09003d 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java @@ -74,7 +74,7 @@ public final class Properties { public static final Property FACING_HOPPER = Property.create("facing"); public static final Property HORIZONTAL_FACING = Property.create("facing"); public static final Property FLOWER_AMOUNT = Property.create("flower_amount"); - public static final Property ORIENTATION = Property.create("orientation"); + public static final Property ORIENTATION = Property.create("orientation"); public static final Property ATTACH_FACE = Property.create("face"); public static final Property BELL_ATTACHMENT = Property.create("attachment"); public static final Property EAST_WALL = Property.create("east"); diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java index d13c47ba8..34a78c370 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java @@ -28,10 +28,13 @@ package org.geysermc.geyser.registry; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.registry.loader.RegistryLoader; +import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; public class ListRegistry extends Registry> { + private boolean frozen = false; + /** * Creates a new instance of this class with the given input and * {@link RegistryLoader}. The input specified is what the registry @@ -85,9 +88,24 @@ public class ListRegistry extends Registry> { * @return a new value into this registry with the given index. */ public M register(int index, M value) { + if (this.frozen) { + throw new IllegalStateException("Registry should not be modified after frozen!"); + } return this.mappings.set(index, value); } + /** + * Mark this registry as unsuitable for new additions. The backing list will then be optimized for storage. + */ + public void freeze() { + if (!this.frozen) { + this.frozen = true; + if (this.mappings instanceof ArrayList arrayList) { + arrayList.trimToSize(); + } + } + } + /** * Creates a new array registry with the given {@link RegistryLoader}. The * input type is not specified here, meaning the loader return type is either diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java index 2cd7f82d6..bd98ae0a5 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java @@ -77,7 +77,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader blockStates = BlockRegistries.BLOCK_STATES.get(); - List collisions = new ObjectArrayList<>(blockStates.size()); + var collisions = new ObjectArrayList(blockStates.size()); // Map of unique collisions to its instance Map collisionInstances = new Object2ObjectOpenHashMap<>(); @@ -102,6 +102,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader { - int blockId = session.getGeyser().getWorldManager().getBlockAt(session, position); - boolean sticky = BlockStateValues.isStickyPiston(blockId); + BlockState state = session.getGeyser().getWorldManager().blockAt(session, position); + boolean sticky = state.is(Blocks.STICKY_PISTON); boolean extended = action != PistonValueType.PUSHING; return new PistonBlockEntity(session, pos, direction, sticky, extended); });