Skip to content

Commit

Permalink
Small optimizations and BlockStateValues reduction
Browse files Browse the repository at this point in the history
  • Loading branch information
Camotoy committed May 21, 2024
1 parent f489fd3 commit db166ad
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
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;
Expand Down Expand Up @@ -120,7 +121,7 @@ private void onPistonAction(BlockPistonEvent event) {

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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
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;
Expand Down Expand Up @@ -88,7 +87,7 @@ public int getBlockNetworkId(Block block) {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
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;
Expand Down Expand Up @@ -148,7 +149,7 @@ public void handlePickBlock(GeyserboundPickBlockPacket packet) {

@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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -36,16 +39,11 @@
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<Direction> PISTON_HEADS = new Object2IntOpenHashMap<>();
private static final Int2ObjectMap<Direction> PISTON_ORIENTATION = new Int2ObjectOpenHashMap<>();
private static final IntSet ALL_PISTON_HEADS = new IntOpenHashSet();
private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap();

Expand All @@ -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);
Expand All @@ -78,29 +72,9 @@ public static void storeBlockStateValues(String javaId, int javaBlockState) {
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) {
return ALL_PISTON_HEADS.contains(state);
}
Expand All @@ -116,17 +90,6 @@ public static int getPistonHead(Direction direction) {
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public final class Properties {
public static final Property<Direction> FACING_HOPPER = Property.create("facing");
public static final Property<Direction> HORIZONTAL_FACING = Property.create("facing");
public static final Property<Integer> FLOWER_AMOUNT = Property.create("flower_amount");
public static final Property<String> ORIENTATION = Property.create("orientation");
public static final Property<FrontAndTop> ORIENTATION = Property.create("orientation");
public static final Property<String> ATTACH_FACE = Property.create("face");
public static final Property<String> BELL_ATTACHMENT = Property.create("attachment");
public static final Property<String> EAST_WALL = Property.create("east");
Expand Down
18 changes: 18 additions & 0 deletions core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@
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<M> extends Registry<List<M>> {
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
Expand Down Expand Up @@ -85,9 +88,24 @@ public M getOrDefault(int index, M defaultValue) {
* @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<M> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public List<BlockCollision> load(Pair<String, String> input) {
}

List<BlockState> blockStates = BlockRegistries.BLOCK_STATES.get();
List<BlockCollision> collisions = new ObjectArrayList<>(blockStates.size());
var collisions = new ObjectArrayList<BlockCollision>(blockStates.size());

// Map of unique collisions to its instance
Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>();
Expand All @@ -102,6 +102,7 @@ public List<BlockCollision> load(Pair<String, String> input) {

collisions.add(newCollision);
}
collisions.trim();
return collisions;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,15 +440,8 @@ private static void registerJavaBlocks() {

BlockStateValues.storeBlockStateValues(javaId, javaRuntimeId);

//String cleanJavaIdentifier = javaBlockState.block().javaIdentifier().toString();
//String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();

BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId);

// Keeping this here since this is currently unchanged between versions
// It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions
//BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern());

if ("minecraft:water[level=0]".equals(javaId)) {
waterRuntimeId = javaRuntimeId;
}
Expand All @@ -467,8 +460,6 @@ private static void registerJavaBlocks() {
throw new RuntimeException("Duplicate runtime ID " + javaBlockState.javaId() + " for non vanilla Java block state " + javaBlockState.identifier());
}

CustomBlockState customBlockState = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().get(javaBlockState);

String javaId = javaBlockState.identifier();
int stateRuntimeId = javaBlockState.javaId();
String pistonBehavior = javaBlockState.pistonBehavior();
Expand Down Expand Up @@ -517,6 +508,8 @@ public ItemStack pickItem(BlockState state) {

BlockRegistries.INTERACTIVE.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("always_consumes")));
BlockRegistries.INTERACTIVE_MAY_BUILD.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("requires_may_build")));

BlockRegistries.BLOCK_STATES.freeze();
}

private static BitSet toBlockStateSet(ArrayNode node) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
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.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
Expand All @@ -47,7 +47,7 @@ public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nulla
} else {
// Tag is not present in at least 1.14.4 Paper
// Minecraft 1.18.1 deliberately has a fallback here, but not for any other value
bedrockNbt.putString("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState.javaId()) ? "aligned" : "rollable"); // TODO
bedrockNbt.putString("joint", blockState.getValue(Properties.ORIENTATION).isHorizontal() ? "aligned" : "rollable");
}
bedrockNbt.putString("name", javaNbt.getString("name"));
bedrockNbt.putString("target_pool", javaNbt.getString("target_pool"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.BlockEventPacket;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
Expand Down Expand Up @@ -78,8 +78,8 @@ public void translate(GeyserSession session, ClientboundBlockEventPacket packet)
// Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1
// See https://github.com/PaperMC/Paper/blob/6fa1983e9ce177a4a412d5b950fd978620174777/patches/server/0304-Fire-BlockPistonRetractEvent-for-all-empty-pistons.patch
if (action == PistonValueType.PULLING || action == PistonValueType.CANCELLED_MID_PUSH) {
int pistonBlock = session.getGeyser().getWorldManager().getBlockAt(session, position);
if (!BlockStateValues.isStickyPiston(pistonBlock)) {
BlockState pistonBlock = session.getGeyser().getWorldManager().blockAt(session, position);
if (!pistonBlock.is(Blocks.STICKY_PISTON)) {
return;
}
if (action != PistonValueType.CANCELLED_MID_PUSH) {
Expand All @@ -97,8 +97,8 @@ public void translate(GeyserSession session, ClientboundBlockEventPacket packet)
}
} else {
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> {
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);
});
Expand Down

2 comments on commit db166ad

@Atticuss26
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What optimizations were added in this commit?

@Camotoy
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the main optimization here is trimming the array list of the BlockState registry to minimize the amount that the large list uses.

Please sign in to comment.