Block refactory

This commit is contained in:
Camotoy 2024-05-16 23:12:06 -04:00
parent 9bca012194
commit cbaa9cd2a0
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
54 changed files with 3620 additions and 157 deletions

View file

@ -34,6 +34,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
@ -59,7 +60,7 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
} else {
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID)));
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, Block.JAVA_AIR_ID)));
}
placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket);

View file

@ -34,6 +34,7 @@ import org.geysermc.geyser.adapters.WorldAdapter;
import org.geysermc.geyser.adapters.paper.PaperAdapters;
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.session.GeyserSession;
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
@ -52,7 +53,7 @@ public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return BlockStateValues.JAVA_AIR_ID;
return Block.JAVA_AIR_ID;
}
return adapter.getBlockAt(player.getWorld(), x, y, z);
}

View file

@ -70,12 +70,12 @@ public class GeyserSpigotWorldManager extends WorldManager {
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return BlockStateValues.JAVA_AIR_ID;
return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
}
World world = bukkitPlayer.getWorld();
if (!world.isChunkLoaded(x >> 4, z >> 4)) {
// If the chunk isn't loaded, how could we even be here?
return BlockStateValues.JAVA_AIR_ID;
return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
}
return getBlockNetworkId(world.getBlockAt(x, y, z));
@ -86,9 +86,9 @@ public class GeyserSpigotWorldManager extends WorldManager {
// Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
CompletableFuture<String> blockData = new CompletableFuture<>();
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID);
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(), BlockStateValues.JAVA_AIR_ID);
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID);
}
@Override

View file

@ -69,6 +69,7 @@ import org.geysermc.geyser.event.GeyserEventBus;
import org.geysermc.geyser.extension.GeyserExtensionManager;
import org.geysermc.geyser.impl.MinecraftVersionImpl;
import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.network.netty.GeyserServer;
import org.geysermc.geyser.registry.BlockRegistries;
@ -256,6 +257,18 @@ public class GeyserImpl implements GeyserApi {
}
VersionCheckUtils.checkForOutdatedJava(logger);
Blocks.VAULT.javaId();
for (int i = 0; i < BlockRegistries.JAVA_BLOCKS.get().length; i++) {
String cleanIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getCleanJavaIdentifier();
String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier();
if (!cleanIdentifier.equals(newIdentifier)) {
System.out.println("Check block " + BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier());
break;
}
}
System.out.println(BlockRegistries.JAVA_BLOCKS.get().length);
System.out.println(BlockRegistries.BLOCK_STATES.get().size());
}
private void startInstance() {

View file

@ -33,6 +33,7 @@ import org.geysermc.erosion.util.BlockPositionIterator;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.collision.BlockCollision;
@ -162,7 +163,7 @@ public class FishingHookEntity extends ThrowableEntity {
*/
protected boolean isInAir() {
int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt());
return block == BlockStateValues.JAVA_AIR_ID;
return block == Block.JAVA_AIR_ID;
}
@Override

View file

@ -43,6 +43,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.type.Block;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession;
@ -119,7 +120,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
}
CompletableFuture<Integer> future = this.asyncPendingLookups.remove(transactionId);
if (future != null) {
future.complete(BlockStateValues.JAVA_AIR_ID);
future.complete(Block.JAVA_AIR_ID);
}
}

View file

@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.level.physics.PistonBehavior;
import org.geysermc.geyser.registry.BlockRegistries;
@ -48,7 +49,6 @@ public final class BlockStateValues {
private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap();
private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap();
private static final Int2IntMap BRUSH_PROGRESS = new Int2IntOpenHashMap();
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
private static final Int2ObjectMap<DoubleChestValue> DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<String> FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>();
private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet();
@ -110,11 +110,6 @@ public final class BlockStateValues {
}
}
if (javaId.contains("command_block")) {
COMMAND_BLOCK_VALUES.put(javaBlockState, javaId.contains("conditional=true") ? (byte) 1 : (byte) 0);
return;
}
if (blockData.get("double_chest_position") != null) {
boolean isX = (blockData.get("x") != null);
boolean isDirectionPositive = ((blockData.get("x") != null && blockData.get("x").asBoolean()) ||
@ -277,16 +272,6 @@ public final class BlockStateValues {
return ALL_CAULDRONS.contains(state);
}
/**
* The block state in Java and Bedrock both contain the conditional bit, however command block block entity tags
* in Bedrock need the conditional information.
*
* @return the list of all command blocks and if they are conditional (1 or 0)
*/
public static Int2ByteMap getCommandBlockValues() {
return COMMAND_BLOCK_VALUES;
}
/**
* All double chest values are part of the block state in Java and part of the block entity tag in Bedrock.
* This gives the DoubleChestValue that can be calculated into the final tag.
@ -356,7 +341,7 @@ public final class BlockStateValues {
* @return Block state for the piston head
*/
public static int getPistonHead(Direction direction) {
return PISTON_HEADS.getOrDefault(direction, BlockStateValues.JAVA_AIR_ID);
return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID);
}
/**
@ -420,7 +405,7 @@ public final class BlockStateValues {
}
public static boolean canPistonMoveBlock(int javaId, boolean isPushing) {
if (javaId == JAVA_AIR_ID) {
if (javaId == Block.JAVA_AIR_ID) {
return true;
}
// Pistons can only be moved if they aren't extended

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
/*
* 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;
public enum ChestType {
SINGLE,
LEFT,
RIGHT;
public static final ChestType[] VALUES = values();
}

View file

@ -0,0 +1,146 @@
/*
* 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.Axis;
import org.geysermc.geyser.level.physics.Direction;
public final class Properties {
public static final Property<Boolean> ATTACHED = Property.create("attached");
public static final Property<Boolean> BOTTOM = Property.create("bottom");
public static final Property<Boolean> CONDITIONAL = Property.create("conditional");
public static final Property<Boolean> DISARMED = Property.create("disarmed");
public static final Property<Boolean> DRAG = Property.create("drag");
public static final Property<Boolean> ENABLED = Property.create("enabled");
public static final Property<Boolean> EXTENDED = Property.create("extended");
public static final Property<Boolean> EYE = Property.create("eye");
public static final Property<Boolean> FALLING = Property.create("falling");
public static final Property<Boolean> HANGING = Property.create("hanging");
public static final Property<Boolean> HAS_BOTTLE_0 = Property.create("has_bottle_0");
public static final Property<Boolean> HAS_BOTTLE_1 = Property.create("has_bottle_1");
public static final Property<Boolean> HAS_BOTTLE_2 = Property.create("has_bottle_2");
public static final Property<Boolean> HAS_RECORD = Property.create("has_record");
public static final Property<Boolean> HAS_BOOK = Property.create("has_book");
public static final Property<Boolean> INVERTED = Property.create("inverted");
public static final Property<Boolean> IN_WALL = Property.create("in_wall");
public static final Property<Boolean> LIT = Property.create("lit");
public static final Property<Boolean> LOCKED = Property.create("locked");
public static final Property<Boolean> OCCUPIED = Property.create("occupied");
public static final Property<Boolean> OPEN = Property.create("open");
public static final Property<Boolean> PERSISTENT = Property.create("persistent");
public static final Property<Boolean> POWERED = Property.create("powered");
public static final Property<Boolean> SHORT = Property.create("short");
public static final Property<Boolean> SIGNAL_FIRE = Property.create("signal_fire");
public static final Property<Boolean> SNOWY = Property.create("snowy");
public static final Property<Boolean> TRIGGERED = Property.create("triggered");
public static final Property<Boolean> UNSTABLE = Property.create("unstable");
public static final Property<Boolean> WATERLOGGED = Property.create("waterlogged");
public static final Property<Boolean> BERRIES = Property.create("berries");
public static final Property<Boolean> BLOOM = Property.create("bloom");
public static final Property<Boolean> SHRIEKING = Property.create("shrieking");
public static final Property<Boolean> CAN_SUMMON = Property.create("can_summon");
public static final Property<Axis> HORIZONTAL_AXIS = Property.create("axis");
public static final Property<Axis> AXIS = Property.create("axis");
public static final Property<Boolean> UP = Property.create("up");
public static final Property<Boolean> DOWN = Property.create("down");
public static final Property<Boolean> NORTH = Property.create("north");
public static final Property<Boolean> EAST = Property.create("east");
public static final Property<Boolean> SOUTH = Property.create("south");
public static final Property<Boolean> WEST = Property.create("west");
public static final Property<Direction> FACING = Property.create("facing");
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<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");
public static final Property<String> NORTH_WALL = Property.create("north");
public static final Property<String> SOUTH_WALL = Property.create("south");
public static final Property<String> WEST_WALL = Property.create("west");
public static final Property<String> EAST_REDSTONE = Property.create("east");
public static final Property<String> NORTH_REDSTONE = Property.create("north");
public static final Property<String> SOUTH_REDSTONE = Property.create("south");
public static final Property<String> WEST_REDSTONE = Property.create("west");
public static final Property<String> DOUBLE_BLOCK_HALF = Property.create("half");
public static final Property<String> HALF = Property.create("half");
public static final Property<String> RAIL_SHAPE = Property.create("shape");
public static final Property<String> RAIL_SHAPE_STRAIGHT = Property.create("shape");
public static final Property<Integer> AGE_1 = Property.create("age");
public static final Property<Integer> AGE_2 = Property.create("age");
public static final Property<Integer> AGE_3 = Property.create("age");
public static final Property<Integer> AGE_4 = Property.create("age");
public static final Property<Integer> AGE_5 = Property.create("age");
public static final Property<Integer> AGE_7 = Property.create("age");
public static final Property<Integer> AGE_15 = Property.create("age");
public static final Property<Integer> AGE_25 = Property.create("age");
public static final Property<Integer> BITES = Property.create("bites");
public static final Property<Integer> CANDLES = Property.create("candles");
public static final Property<Integer> DELAY = Property.create("delay");
public static final Property<Integer> DISTANCE = Property.create("distance");
public static final Property<Integer> EGGS = Property.create("eggs");
public static final Property<Integer> HATCH = Property.create("hatch");
public static final Property<Integer> LAYERS = Property.create("layers");
public static final Property<Integer> LEVEL_CAULDRON = Property.create("level");
public static final Property<Integer> LEVEL_COMPOSTER = Property.create("level");
public static final Property<Integer> LEVEL_FLOWING = Property.create("level");
public static final Property<Integer> LEVEL_HONEY = Property.create("honey_level");
public static final Property<Integer> LEVEL = Property.create("level");
public static final Property<Integer> MOISTURE = Property.create("moisture");
public static final Property<Integer> NOTE = Property.create("note");
public static final Property<Integer> PICKLES = Property.create("pickles");
public static final Property<Integer> POWER = Property.create("power");
public static final Property<Integer> STAGE = Property.create("stage");
public static final Property<Integer> STABILITY_DISTANCE = Property.create("distance");
public static final Property<Integer> RESPAWN_ANCHOR_CHARGES = Property.create("charges");
public static final Property<Integer> ROTATION_16 = Property.create("rotation");
public static final Property<String> BED_PART = Property.create("part");
public static final Property<String> CHEST_TYPE = Property.create("type");
public static final Property<String> MODE_COMPARATOR = Property.create("mode");
public static final Property<String> DOOR_HINGE = Property.create("hinge");
public static final Property<String> NOTEBLOCK_INSTRUMENT = Property.create("instrument");
public static final Property<String> PISTON_TYPE = Property.create("type");
public static final Property<String> SLAB_TYPE = Property.create("type");
public static final Property<String> STAIRS_SHAPE = Property.create("shape");
public static final Property<String> STRUCTUREBLOCK_MODE = Property.create("mode");
public static final Property<String> BAMBOO_LEAVES = Property.create("leaves");
public static final Property<String> TILT = Property.create("tilt");
public static final Property<Direction> VERTICAL_DIRECTION = Property.create("vertical_direction");
public static final Property<String> DRIPSTONE_THICKNESS = Property.create("thickness");
public static final Property<String> SCULK_SENSOR_PHASE = Property.create("sculk_sensor_phase");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_0_OCCUPIED = Property.create("slot_0_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_1_OCCUPIED = Property.create("slot_1_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_2_OCCUPIED = Property.create("slot_2_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_3_OCCUPIED = Property.create("slot_3_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_4_OCCUPIED = Property.create("slot_4_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_5_OCCUPIED = Property.create("slot_5_occupied");
public static final Property<Integer> DUSTED = Property.create("dusted");
public static final Property<Boolean> CRACKED = Property.create("cracked");
public static final Property<Boolean> CRAFTING = Property.create("crafting");
public static final Property<String> TRIAL_SPAWNER_STATE = Property.create("trial_spawner_state");
public static final Property<String> VAULT_STATE = Property.create("vault_state");
public static final Property<Boolean> OMINOUS = Property.create("ominous");
}

View file

@ -0,0 +1,43 @@
/*
* 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;
public class Property<T extends Comparable<T>> {
private final String name;
public Property(String name) {
this.name = name;
}
@Override
public String toString() {
return getClass().getSimpleName() + "[" + name + "]";
}
public static <T extends Comparable<T>> Property<T> create(String name) {
return new Property<>(name);
}
}

View file

@ -0,0 +1,39 @@
/*
* 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.type;
public class BannerBlock extends Block {
private final int dyeColor;
public BannerBlock(String javaIdentifier, int dyeColor, Builder builder) {
super(javaIdentifier, builder);
this.dyeColor = dyeColor;
}
public int dyeColor() {
return dyeColor;
}
}

View file

@ -0,0 +1,39 @@
/*
* 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.type;
public class BedBlock extends Block {
private final int dyeColor;
public BedBlock(String javaIdentifier, int dyeColor, Builder builder) {
super(javaIdentifier, builder);
this.dyeColor = dyeColor;
}
public int dyeColor() {
return dyeColor;
}
}

View file

@ -0,0 +1,152 @@
/*
* 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.type;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
import org.geysermc.geyser.level.block.property.Property;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
import java.util.*;
import java.util.stream.Stream;
public class Block {
public static final int JAVA_AIR_ID = 0;
private final String javaIdentifier;
private int javaId = -1;
public Block(String javaIdentifier, Builder builder) {
this.javaIdentifier = Identifier.formalize(javaIdentifier).intern();
builder.build(this);
}
public String javaIdentifier() {
return javaIdentifier;
}
public int javaId() {
return javaId;
}
public void setJavaId(int javaId) {
if (this.javaId != -1) {
throw new RuntimeException("Block ID has already been set!");
}
this.javaId = javaId;
}
@Override
public String toString() {
return "Item{" +
"javaIdentifier='" + javaIdentifier + '\'' +
", javaId=" + javaId +
'}';
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
private final Map<Property<?>, List<Comparable<?>>> states = new LinkedHashMap<>();
/**
* For states that we're just tracking for mirroring Java states.
*/
public Builder enumState(Property<String> property, String... values) {
states.put(property, List.of(values));
return this;
}
@SafeVarargs
public final <T extends Enum<T>> Builder enumState(Property<T> property, T... enums) {
states.put(property, List.of(enums));
return this;
}
public Builder booleanState(Property<Boolean> property) {
states.put(property, List.of(Boolean.TRUE, Boolean.FALSE)); // Make this list a static constant if it'll survive past initialization
return this;
}
public Builder intState(Property<Integer> property, int low, int high) {
IntList list = new IntArrayList();
// There is a state for every number between the low and high.
for (int i = low; i <= high; i++) {
list.add(i);
}
states.put(property, List.copyOf(list)); // Boxing reasons for that copy I guess.
return this;
}
private void build(Block block) {
if (states.isEmpty()) {
BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size()));
} else {
// Think of this stream as another list containing, at the start, one empty list.
// It's two collections. Not a stream from the empty list.
Stream<List<Pair<Property<?>, Comparable<?>>>> stream = Stream.of(Collections.emptyList());
for (var state : this.states.entrySet()) {
// OK, so here's how I understand this works. Because this was staring at vanilla Java code trying
// to figure out exactly how it works so we don't have any discrepencies.
// For each existing pair in the list, a new list is created, adding one of the new values.
// Property up [true/false] would exist as true and false
// Both entries will get duplicated, adding down, true and false.
stream = stream.flatMap(aPreviousPropertiesList ->
// So the above is a list. It may be empty if this is the first property,
// or it may be populated if this is not the first property.
// We're about to create a new stream, each with a new list,
// for every previous property
state.getValue().stream().map(value -> {
var newProperties = new ArrayList<>(aPreviousPropertiesList);
newProperties.add(Pair.of(state.getKey(), value));
return newProperties;
}));
}
// Now we have a list of Pair<Property, Value>s. Each list is a block state!
// If we have two boolean properties: up [true/false] and down [true/false],
// We'll see [up=true,down=true], [up=false,down=true], [up=true,down=false], [up=false,down=false]
stream.forEach(properties -> {
Reference2ObjectMap<Property<?>, Comparable<?>> propertyMap = new Reference2ObjectArrayMap<>(properties.size());
for (int i = 0; i < properties.size(); i++) {
Pair<Property<?>, Comparable<?>> property = properties.get(i);
propertyMap.put(property.key(), property.value());
}
BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap));
});
}
}
private Builder() {
}
}
}

View file

@ -0,0 +1,64 @@
/*
* 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.type;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps;
import org.geysermc.geyser.level.block.property.Property;
import org.geysermc.geyser.registry.BlockRegistries;
public final class BlockState {
private final Block block;
private final int javaId;
private final Reference2ObjectMap<Property<?>, Comparable<?>> states;
BlockState(Block block, int javaId) {
this(block, javaId, Reference2ObjectMaps.emptyMap());
}
BlockState(Block block, int javaId, Reference2ObjectMap<Property<?>, Comparable<?>> states) {
this.block = block;
this.javaId = javaId;
this.states = states;
}
public <T extends Comparable<T>> T getValue(Property<T> property) {
//noinspection unchecked
return (T) states.get(property);
}
public Block block() {
return block;
}
public int javaId() {
return javaId;
}
public static BlockState of(int javaId) {
return BlockRegistries.BLOCK_STATES.get(javaId);
}
}

View file

@ -34,6 +34,8 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.loader.CollisionRegistryLoader;
import org.geysermc.geyser.registry.loader.RegistryLoaders;
import org.geysermc.geyser.registry.populator.BlockRegistryPopulator;
@ -44,8 +46,8 @@ import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.CustomSkull;
import org.geysermc.geyser.translator.collision.BlockCollision;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Set;
/**
@ -58,6 +60,14 @@ public class BlockRegistries {
*/
public static final VersionedRegistry<BlockMappings> BLOCKS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
/**
* A registry which stores Java IDs to Java {@link BlockState}s, each with their specific state differences and a link
* to the overarching block.
*/
public static final ListRegistry<BlockState> BLOCK_STATES = ListRegistry.create(RegistryLoaders.empty(ArrayList::new));
public static final ListRegistry<Block> JAVA_BLOCKS_TO_RENAME = ListRegistry.create(RegistryLoaders.empty(ArrayList::new));
/**
* A mapped registry which stores Java to Bedrock block identifiers.
*/

View file

@ -0,0 +1,103 @@
/*
* 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.registry;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.registry.loader.RegistryLoader;
import java.util.List;
public class ListRegistry<M> extends Registry<List<M>> {
/**
* Creates a new instance of this class with the given input and
* {@link RegistryLoader}. The input specified is what the registry
* loader needs to take in.
*
* @param input the input
* @param registryLoader the registry loader
*/
protected <I> ListRegistry(I input, RegistryLoader<I, List<M>> registryLoader) {
super(input, registryLoader);
}
/**
* Returns the value registered by the given index.
*
* @param index the index
* @return the value registered by the given index.
*/
@Nullable
public M get(int index) {
if (index >= this.mappings.size()) {
return null;
}
return this.mappings.get(index);
}
/**
* Returns the value registered by the given index or the default value
* specified if null.
*
* @param index the index
* @param defaultValue the default value
* @return the value registered by the given key or the default value
* specified if null.
*/
public M getOrDefault(int index, M defaultValue) {
M value = this.get(index);
if (value == null) {
return defaultValue;
}
return value;
}
/**
* Registers a new value into this registry with the given index.
*
* @param index the index
* @param value the value
* @return a new value into this registry with the given index.
*/
public M register(int index, M value) {
return this.mappings.set(index, value);
}
/**
* Creates a new array registry with the given {@link RegistryLoader}. The
* input type is not specified here, meaning the loader return type is either
* predefined, or the registry is populated at a later point.
*
* @param registryLoader the registry loader
* @param <I> the input type
* @param <M> the returned mappings type
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ListRegistry<M> create(RegistryLoader<I, List<M>> registryLoader) {
return new ListRegistry<M>(null, registryLoader);
}
}

View file

@ -582,8 +582,6 @@ public final class BlockRegistryPopulator {
}
}
BlockRegistries.CLEAN_JAVA_IDENTIFIERS.set(cleanIdentifiers.toArray(new String[0]));
BLOCKS_JSON = blocksJson;
JsonNode blockInteractionsJson;

View file

@ -1592,9 +1592,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
startGamePacket.setRewindHistorySize(0);
startGamePacket.setServerAuthoritativeBlockBreaking(false);
// Entity properties for older versions
startGamePacket.getExperiments().add(new ExperimentData("upcoming_creator_features", true));
upstream.sendPacket(startGamePacket);
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.session.cache;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
@ -92,11 +93,11 @@ public class ChunkCache {
DataPalette palette = chunk.sections()[(y - minY) >> 4];
if (palette == null) {
if (block != BlockStateValues.JAVA_AIR_ID) {
if (block != Block.JAVA_AIR_ID) {
// A previously empty chunk, which is no longer empty as a block has been added to it
palette = DataPalette.createForChunk();
// Fixes the chunk assuming that all blocks is the `block` variable we are updating. /shrug
palette.getPalette().stateToId(BlockStateValues.JAVA_AIR_ID);
palette.getPalette().stateToId(Block.JAVA_AIR_ID);
chunk.sections()[(y - minY) >> 4] = palette;
} else {
// Nothing to update
@ -109,17 +110,17 @@ public class ChunkCache {
public int getBlockAt(int x, int y, int z) {
if (!cache) {
return BlockStateValues.JAVA_AIR_ID;
return Block.JAVA_AIR_ID;
}
GeyserChunk column = this.getChunk(x >> 4, z >> 4);
if (column == null) {
return BlockStateValues.JAVA_AIR_ID;
return Block.JAVA_AIR_ID;
}
if (y < minY || ((y - minY) >> 4) > column.sections().length - 1) {
// Y likely goes above or below the height limit of this world
return BlockStateValues.JAVA_AIR_ID;
return Block.JAVA_AIR_ID;
}
DataPalette chunk = column.sections()[(y - minY) >> 4];
@ -127,7 +128,7 @@ public class ChunkCache {
return chunk.get(x & 0xF, y & 0xF, z & 0xF);
}
return BlockStateValues.JAVA_AIR_ID;
return Block.JAVA_AIR_ID;
}
public void removeChunk(int chunkX, int chunkZ) {

View file

@ -35,6 +35,7 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
@ -58,7 +59,7 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator
.putInt("z", position.getZ())
.putString("CustomName", inventory.getTitle());
// Don't reset facing property
shulkerBoxTranslator.translateTag(session, tag, null, javaBlockState);
shulkerBoxTranslator.translateTag(session, tag, null, BlockState.of(javaBlockState));
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
dataPacket.setData(tag.build());

View file

@ -36,8 +36,7 @@ import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.inventory.Container;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.DoubleChestValue;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.session.GeyserSession;
@ -72,8 +71,8 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
.putString("CustomName", inventory.getTitle())
.putString("id", "Chest");
DoubleChestValue chestValue = BlockStateValues.getDoubleChestValues().get(javaBlockId);
DoubleChestBlockEntityTranslator.translateChestValue(tag, chestValue,
BlockState blockState = BlockState.of(javaBlockId);
DoubleChestBlockEntityTranslator.translateChestValue(tag, blockState,
session.getLastInteractionBlockPosition().getX(), session.getLastInteractionBlockPosition().getZ());
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();

View file

@ -30,7 +30,8 @@ import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.item.type.BannerItem;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.BannerBlock;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -39,10 +40,9 @@ import java.util.List;
@BlockEntity(type = BlockEntityType.BANNER)
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) {
int bannerColor = BlockStateValues.getBannerColor(blockState);
if (bannerColor != -1) {
bedrockNbt.putInt("Base", 15 - bannerColor);
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) {
if (blockState.block() instanceof BannerBlock banner) {
bedrockNbt.putInt("Base", 15 - banner.dyeColor());
}
if (javaNbt == null) {

View file

@ -27,13 +27,14 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@BlockEntity(type = BlockEntityType.BEACON)
public class BeaconBlockEntityTranslator extends BlockEntityTranslator {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
int primary = javaNbt.getInt("primary");
// The effects here generally map one-to-one Java <-> Bedrock. Only the newer ones get more complicated
bedrockNbt.putInt("primary", primary == -1 ? 0 : primary);

View file

@ -27,19 +27,15 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.BedBlock;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@BlockEntity(type = BlockEntityType.BED)
public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
byte bedcolor = BlockStateValues.getBedColor(blockState);
// Just in case...
if (bedcolor == -1) {
bedcolor = 0;
}
bedrockNbt.putByte("color", bedcolor);
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
bedrockNbt.putByte("color", (byte) (blockState.block() instanceof BedBlock bed ? bed.dyeColor() : 0));
}
}

View file

@ -31,6 +31,7 @@ import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
/**
@ -50,7 +51,7 @@ public interface BedrockOnlyBlockEntity extends RequiresBlockState {
* @param blockState The Java block state.
* @param position The Bedrock block position.
*/
void updateBlock(GeyserSession session, int blockState, Vector3i position);
void updateBlock(GeyserSession session, BlockState blockState, Vector3i position);
/**
* Get the tag of the Bedrock-only block entity

View file

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -39,9 +40,9 @@ public abstract class BlockEntityTranslator {
protected BlockEntityTranslator() {
}
public abstract void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState);
public abstract void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState);
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) {
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) {
NbtMapBuilder tagBuilder = getConstantBedrockTag(type, x, y, z);
if (javaNbt != null || this instanceof RequiresBlockState) {
// Always process tags if the block state is part of the tag.

View file

@ -29,7 +29,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.item.Items;
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.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -38,7 +39,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class BrushableBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) {
return;
}
@ -70,6 +71,6 @@ public class BrushableBlockEntityTranslator extends BlockEntityTranslator implem
// controls which side the item protrudes from
bedrockNbt.putByte("brush_direction", hitDirection);
// controls how much the item protrudes
bedrockNbt.putInt("brush_count", BlockStateValues.getBrushProgress(blockState));
bedrockNbt.putInt("brush_count", blockState.getValue(Properties.DUSTED));
}
}

View file

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
@ -38,7 +39,7 @@ import java.util.List;
@BlockEntity(type = BlockEntityType.CAMPFIRE)
public class CampfireBlockEntityTranslator extends BlockEntityTranslator {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
List<NbtMap> items = javaNbt.getList("Items", NbtType.COMPOUND);
if (items != null) {
int i = 1;

View file

@ -27,7 +27,8 @@ package org.geysermc.geyser.translator.level.block.entity;
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.geyser.translator.text.MessageTranslator;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -35,12 +36,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
@BlockEntity(type = BlockEntityType.COMMAND_BLOCK)
public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null || javaNbt.size() < 5) {
return; // These values aren't here
}
// Java infers from the block state, but Bedrock needs it in the tag
bedrockNbt.putByte("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0));
bedrockNbt.putBoolean("conditionalMode", blockState.getValue(Properties.CONDITIONAL));
// Java and Bedrock values
bedrockNbt.putByte("conditionMet", javaNbt.getByte("conditionMet"));
bedrockNbt.putByte("auto", javaNbt.getByte("auto"));

View file

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -35,7 +36,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) {
return;
}

View file

@ -29,7 +29,9 @@ import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.DoubleChestValue;
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.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -45,52 +47,40 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl
}
@Override
public void updateBlock(GeyserSession session, int blockState, Vector3i position) {
public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) {
NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockEntityType.CHEST), position.getX(), position.getY(), position.getZ());
translateTag(session, tagBuilder, null, blockState);
BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position);
}
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().get(blockState);
if (chestValues != null) {
int x = (int) bedrockNbt.get("x");
int z = (int) bedrockNbt.get("z");
translateChestValue(bedrockNbt, chestValues, x, z);
}
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
int x = (int) bedrockNbt.get("x");
int z = (int) bedrockNbt.get("z");
translateChestValue(bedrockNbt, blockState, x, z);
}
/**
* Add Bedrock block entity tags to a NbtMap based on Java properties
*
* @param builder the NbtMapBuilder to apply properties to
* @param chestValues the position properties of this double chest
* @param state the BlockState of this double chest
* @param x the x position of this chest pair
* @param z the z position of this chest pair
*/
public static void translateChestValue(NbtMapBuilder builder, DoubleChestValue chestValues, int x, int z) {
public static void translateChestValue(NbtMapBuilder builder, BlockState state, int x, int z) {
// Calculate the position of the other chest based on the Java block state
if (chestValues.isFacingEast()) {
if (chestValues.isDirectionPositive()) {
// East
z = z + (chestValues.isLeft() ? 1 : -1);
} else {
// West
z = z + (chestValues.isLeft() ? -1 : 1);
}
} else {
if (chestValues.isDirectionPositive()) {
// South
x = x + (chestValues.isLeft() ? -1 : 1);
} else {
// North
x = x + (chestValues.isLeft() ? 1 : -1);
}
Direction facing = state.getValue(Properties.HORIZONTAL_FACING);
boolean isLeft = state.getValue(Properties.CHEST_TYPE).equals("left"); //TODO enum
switch (facing) {
case EAST -> z = z + (isLeft ? 1 : -1);
case WEST -> z = z + (isLeft ? -1 : 1);
case SOUTH -> x = x + (isLeft ? -1 : 1);
case NORTH -> x = x + (isLeft ? 1 : -1);
}
builder.putInt("pairx", x);
builder.putInt("pairz", z);
if (!chestValues.isLeft()) {
if (!isLeft) {
builder.putInt("pairlead", (byte) 1);
}
}

View file

@ -27,10 +27,11 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
public class EmptyBlockEntityTranslator extends BlockEntityTranslator {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
}
}

View file

@ -31,13 +31,14 @@ import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@BlockEntity(type = BlockEntityType.END_GATEWAY)
public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
bedrockNbt.putInt("Age", (int) javaNbt.getLong("Age"));
// Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist
// Linked coordinates

View file

@ -30,6 +30,7 @@ import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils;
@ -75,12 +76,12 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity {
}
@Override
public void updateBlock(GeyserSession session, int blockState, Vector3i position) {
NbtMap tag = getTag(session, blockState, position);
public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) {
NbtMap tag = getTag(session, blockState.javaId(), position);
BlockEntityUtils.updateBlockEntity(session, tag, position);
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0);
updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState));
updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState.javaId()));
updateBlockPacket.setBlockPosition(position);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);

View file

@ -29,13 +29,14 @@ 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.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@BlockEntity(type = BlockEntityType.JIGSAW)
public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) {
return;
}
@ -46,7 +47,7 @@ public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator impl
} 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) ? "aligned" : "rollable");
bedrockNbt.putString("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState.javaId()) ? "aligned" : "rollable"); // TODO
}
bedrockNbt.putString("name", javaNbt.getString("name"));
bedrockNbt.putString("target_pool", javaNbt.getString("target_pool"));

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.level.block.entity;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
import org.cloudburstmc.math.vector.Vector3d;
import org.cloudburstmc.math.vector.Vector3f;
@ -222,10 +223,10 @@ public class PistonBlockEntity {
Vector3i blockInFront = position.add(orientation.getUnitVector());
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockInFront);
if (BlockStateValues.isPistonHead(blockId)) {
ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront);
} else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == BlockStateValues.JAVA_AIR_ID) {
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
} else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == Block.JAVA_AIR_ID) {
// Spigot removes the piston head from the cache, but we need to send the block update ourselves
ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront);
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
}
}
@ -255,7 +256,7 @@ public class PistonBlockEntity {
continue;
}
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockPos);
if (blockId == BlockStateValues.JAVA_AIR_ID) {
if (blockId == Block.JAVA_AIR_ID) {
continue;
}
if (BlockStateValues.canPistonMoveBlock(blockId, action == PistonValueType.PUSHING)) {
@ -278,7 +279,7 @@ public class PistonBlockEntity {
continue;
}
int adjacentBlockId = session.getGeyser().getWorldManager().getBlockAt(session, adjacentPos);
if (adjacentBlockId != BlockStateValues.JAVA_AIR_ID && BlockStateValues.isBlockAttached(blockId, adjacentBlockId) && BlockStateValues.canPistonMoveBlock(adjacentBlockId, false)) {
if (adjacentBlockId != Block.JAVA_AIR_ID && BlockStateValues.isBlockAttached(blockId, adjacentBlockId) && BlockStateValues.canPistonMoveBlock(adjacentBlockId, false)) {
// If it is another slime/honey block we need to check its adjacent blocks
if (BlockStateValues.isBlockSticky(adjacentBlockId)) {
blocksToCheck.add(adjacentPos);
@ -322,7 +323,7 @@ public class PistonBlockEntity {
*/
private void removeBlocks() {
for (Vector3i blockPos : attachedBlocks.keySet()) {
ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockPos);
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockPos);
}
if (action != PistonValueType.PUSHING) {
removePistonHead();
@ -560,7 +561,7 @@ public class PistonBlockEntity {
if (blockPos.equals(getPistonHeadPos())) {
return BlockStateValues.getPistonHead(orientation);
} else {
return attachedBlocks.getOrDefault(blockPos, BlockStateValues.JAVA_AIR_ID);
return attachedBlocks.getOrDefault(blockPos, Block.JAVA_AIR_ID);
}
}

View file

@ -28,7 +28,8 @@ package org.geysermc.geyser.translator.level.block.entity;
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.geyser.translator.inventory.ShulkerInventoryTranslator;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -40,12 +41,7 @@ public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator imple
* where {@code tag} is passed as null.
*/
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) {
byte direction = BlockStateValues.getShulkerBoxDirection(blockState);
// Just in case...
if (direction == -1) {
direction = 1;
}
bedrockNbt.putByte("facing", direction);
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) {
bedrockNbt.putByte("facing", (byte) blockState.getValue(Properties.FACING).ordinal());
}
}

View file

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.translator.text.MessageTranslator;
@ -73,7 +74,7 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator {
}
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
bedrockNbt.putCompound("FrontText", translateSide(javaNbt.getCompound("front_text")));
bedrockNbt.putCompound("BackText", translateSide(javaNbt.getCompound("back_text")));
bedrockNbt.putBoolean("IsWaxed", javaNbt.getBoolean("is_waxed"));

View file

@ -34,6 +34,8 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
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.session.GeyserSession;
import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.skin.SkinProvider;
@ -50,16 +52,19 @@ import java.util.concurrent.ExecutionException;
public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
byte skullVariant = BlockStateValues.getSkullVariant(blockState);
float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f;
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
byte skullVariant = BlockStateValues.getSkullVariant(blockState.javaId()); // TODO
// Just in case...
if (skullVariant == -1) {
skullVariant = 0;
}
bedrockNbt.putFloat("Rotation", rotation);
Integer rotation = blockState.getValue(Properties.ROTATION_16);
if (rotation != null) {
// Could be a wall skull block
bedrockNbt.putFloat("Rotation", rotation * 22.5f);
}
bedrockNbt.putByte("SkullType", skullVariant);
if (BlockStateValues.isSkullPowered(blockState)) {
if (blockState.getValue(Properties.POWERED)) {
bedrockNbt.putBoolean("MouthMoving", true);
}
}

View file

@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -40,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class SpawnerBlockEntityTranslator extends BlockEntityTranslator {
@Override
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) {
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) {
return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState);
}
@ -70,7 +71,7 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator {
}
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
Object current;
// TODO use primitive get and put methods

View file

@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.StructureBlockUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -40,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator {
@Override
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) {
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) {
return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState);
}
@ -73,7 +74,7 @@ public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator {
}
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
if (javaNbt.size() < 5) {
return; // These values aren't here
}

View file

@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -34,7 +35,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator {
@Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) {
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) {
return;
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.bedrock;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket;
@ -48,7 +49,7 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator<BlockPic
int blockToPick = session.getGeyser().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ());
// Block is air - chunk caching is probably off
if (blockToPick == BlockStateValues.JAVA_AIR_ID) {
if (blockToPick == Block.JAVA_AIR_ID) {
// Check for an item frame since the client thinks that's a block when it's an entity in Java
ItemFrameEntity entity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition());
if (entity != null) {

View file

@ -57,6 +57,7 @@ import org.geysermc.geyser.item.type.BoatItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.item.type.SpawnEggItem;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.SkullCache;
@ -444,7 +445,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
session.getWorldCache().markPositionInSequence(packet.getBlockPosition());
// -1 means we don't know what block they're breaking
if (blockState == -1) {
blockState = BlockStateValues.JAVA_AIR_ID;
blockState = Block.JAVA_AIR_ID;
}
LevelEventPacket blockBreakPacket = new LevelEventPacket();

View file

@ -39,6 +39,7 @@ import org.geysermc.geyser.entity.type.ItemFrameEntity;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping;
@ -197,7 +198,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
}
int breakingBlock = session.getBreakingBlock();
if (breakingBlock == -1) {
breakingBlock = BlockStateValues.JAVA_AIR_ID;
breakingBlock = Block.JAVA_AIR_ID;
}
Vector3f vectorFloat = vector.toFloat();

View file

@ -33,7 +33,8 @@ import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation;
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
import org.geysermc.geyser.translator.level.block.entity.RequiresBlockState;
@ -58,11 +59,11 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(type);
// The Java block state is used in BlockEntityTranslator.translateTag() to make up for some inconsistencies
// between Java block states and Bedrock block entity data
int blockState;
BlockState blockState;
if (translator instanceof RequiresBlockState) {
blockState = session.getGeyser().getWorldManager().getBlockAt(session, packet.getPosition());
blockState = BlockRegistries.BLOCK_STATES.get(session.getGeyser().getWorldManager().getBlockAt(session, packet.getPosition()));
} else {
blockState = BlockStateValues.JAVA_AIR_ID;
blockState = BlockRegistries.BLOCK_STATES.get(0); //TODO
}
Vector3i position = packet.getPosition();
@ -71,7 +72,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
// Check for custom skulls.
boolean hasCustomHeadBlock = false;
if (session.getPreferencesCache().showCustomSkulls() && packet.getNbt() != null && packet.getNbt().containsKey("profile")) {
BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, packet.getNbt(), position, blockState);
BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, packet.getNbt(), position, blockState.javaId());
if (blockDefinition != null) {
hasCustomHeadBlock = true;
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.java.level;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket;
import org.cloudburstmc.math.vector.Vector3i;
@ -82,7 +83,7 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
if (action != PistonValueType.CANCELLED_MID_PUSH) {
Vector3i blockInFrontPos = position.add(direction.getUnitVector());
int blockInFront = session.getGeyser().getWorldManager().getBlockAt(session, blockInFrontPos);
if (blockInFront != BlockStateValues.JAVA_AIR_ID) {
if (blockInFront != Block.JAVA_AIR_ID) {
// Piston pulled something
return;
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.java.level;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
@ -58,7 +59,7 @@ public class JavaExplodeTranslator extends PacketTranslator<ClientboundExplodePa
int i = 0;
for (Vector3i position : packet.getExploded()) {
Vector3i pos = Vector3i.from(packet.getX() + position.getX(), packet.getY() + position.getY(), packet.getZ() + position.getZ());
ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, pos);
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, pos);
builder.putFloat("pos" + i + "x", pos.getX());
builder.putFloat("pos" + i + "y", pos.getY());
builder.putFloat("pos" + i + "z", pos.getZ());

View file

@ -42,6 +42,9 @@ import org.geysermc.erosion.util.LecternUtils;
import org.geysermc.geyser.entity.type.ItemFrameEntity;
import org.geysermc.geyser.level.BedrockDimension;
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.chunk.BlockStorage;
import org.geysermc.geyser.level.chunk.GeyserChunkSection;
import org.geysermc.geyser.level.chunk.bitarray.BitArray;
@ -175,7 +178,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
// Extended collision blocks
if (useExtendedCollisions) {
if (EXTENDED_COLLISIONS_STORAGE.get().get(yzx, sectionY) != 0) {
if (javaId == BlockStateValues.JAVA_AIR_ID) {
if (javaId == Block.JAVA_AIR_ID) {
section.getBlockStorageArray()[0].setFullBlock(xzy, EXTENDED_COLLISIONS_STORAGE.get().get(yzx, sectionY));
}
EXTENDED_COLLISIONS_STORAGE.get().set(yzx, 0, sectionY);
@ -238,7 +241,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
waterloggedPaletteIds.set(i);
}
if (javaId == BlockStateValues.JAVA_AIR_ID) {
if (javaId == Block.JAVA_AIR_ID) {
airPaletteId = i;
}
@ -396,9 +399,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
// Get the Java block state ID from block entity position
DataPalette section = javaChunks[(y >> 4) - yOffset];
int blockState = section.get(x, y & 0xF, z);
BlockState blockState = BlockRegistries.BLOCK_STATES.get(section.get(x, y & 0xF, z));
if (type == BlockEntityType.LECTERN && BlockStateValues.getLecternBookStates().get(blockState)) {
if (type == BlockEntityType.LECTERN && blockState.getValue(Properties.HAS_BOOK)) {
// If getLecternBookStates is false, let's just treat it like a normal block entity
// Fill in tag with a default value
NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x + chunkBlockX, y, z + chunkBlockZ, 1);
@ -419,7 +422,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
// Check for custom skulls
if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.containsKey("profile")) {
BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState);
BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState.javaId());
if (blockDefinition != null) {
int bedrockSectionY = (y >> 4) - (bedrockDimension.minY() >> 4);
int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4);

View file

@ -41,6 +41,8 @@ import org.geysermc.geyser.entity.type.ItemFrameEntity;
import org.geysermc.geyser.level.BedrockDimension;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.chunk.BlockStorage;
import org.geysermc.geyser.level.chunk.GeyserChunkSection;
import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray;
@ -50,8 +52,6 @@ import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity;
import static org.geysermc.geyser.level.block.BlockStateValues.JAVA_AIR_ID;
@UtilityClass
public class ChunkUtils {
@ -130,7 +130,7 @@ public class ChunkUtils {
// Checks for item frames so they aren't tripped up and removed
ItemFrameEntity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, position);
if (itemFrameEntity != null) {
if (blockState == JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it
if (blockState == Block.JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it
itemFrameEntity.updateBlock(true);
// Still update the chunk cache with the new block if updateBlock is called
return;
@ -180,21 +180,21 @@ public class ChunkUtils {
BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(blockState);
int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ());
BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock);
if (belowBedrockExtendedCollisionDefinition != null && blockState == BlockStateValues.JAVA_AIR_ID) {
if (belowBedrockExtendedCollisionDefinition != null && blockState == Block.JAVA_AIR_ID) {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(position);
updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
session.sendUpstreamPacket(updateBlockPacket);
} else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == BlockStateValues.JAVA_AIR_ID) {
} else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(position.add(0, 1, 0));
updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
session.sendUpstreamPacket(updateBlockPacket);
} else if (aboveBlock == BlockStateValues.JAVA_AIR_ID) {
} else if (aboveBlock == Block.JAVA_AIR_ID) {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(position.add(0, 1, 0));
@ -211,7 +211,7 @@ public class ChunkUtils {
for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityUtils.BEDROCK_ONLY_BLOCK_ENTITIES) {
if (bedrockOnlyBlockEntity.isBlock(blockState)) {
// Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks
bedrockOnlyBlockEntity.updateBlock(session, blockState, position);
bedrockOnlyBlockEntity.updateBlock(session, BlockState.of(blockState), position); //TODO blockState
break; //No block will be a part of two classes
}
}

View file

@ -34,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.SoundMapping;
@ -147,7 +148,7 @@ public final class SoundUtils {
soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12);
} else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) {
if (!soundMapping.getIdentifier().equals(":")) {
int javaId = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID);
int javaId = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(soundMapping.getIdentifier(), Block.JAVA_AIR_ID);
soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(javaId));
} else {
session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + soundMapping);

View file

@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
import org.geysermc.cumulus.form.SimpleForm;
import org.geysermc.cumulus.util.FormImage;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
@ -93,10 +94,10 @@ public class StatisticsUtils {
for (Object2IntMap.Entry<Statistic> entry : session.getStatistics().object2IntEntrySet()) {
if (entry.getKey() instanceof BreakBlockStatistic statistic) {
String identifier = BlockRegistries.CLEAN_JAVA_IDENTIFIERS.get(statistic.getId());
if (identifier != null) {
String block = identifier.replace("minecraft:", "block.minecraft.");
content.add(block + ": " + entry.getIntValue());
Block block = BlockRegistries.JAVA_BLOCKS_TO_RENAME.get(statistic.getId());
if (block != null) {
String identifier = block.javaIdentifier().replace("minecraft:", "block.minecraft.");
content.add(identifier + ": " + entry.getIntValue());
}
}
}

View file

@ -65,6 +65,7 @@ fastutil-int-byte-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-
fastutil-int-boolean-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-boolean-maps", version.ref = "fastutil" }
fastutil-object-int-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-int-maps", version.ref = "fastutil" }
fastutil-object-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-object-maps", version.ref = "fastutil" }
fastutil-reference-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-reference-object-maps", version.ref = "fastutil" }
adventure-text-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" } # Remove when we remove our Adventure bump
adventure-text-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" }
@ -142,7 +143,7 @@ blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
[bundles]
jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ]
fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps" ]
fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps", "fastutil-reference-object-maps" ]
adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ]
log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl" ]
jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ]