mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
It's almost done.
This commit is contained in:
parent
a439f3e3d7
commit
6c904b2378
40 changed files with 1359 additions and 1189 deletions
|
@ -258,10 +258,10 @@ public class GeyserImpl implements GeyserApi {
|
|||
VersionCheckUtils.checkForOutdatedJava(logger);
|
||||
|
||||
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());
|
||||
String oldIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getJavaIdentifier();
|
||||
String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).toString();
|
||||
if (!oldIdentifier.equals(newIdentifier)) {
|
||||
System.out.println("Check block " + oldIdentifier + " " + newIdentifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,14 +25,14 @@
|
|||
|
||||
package org.geysermc.geyser.entity.type;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.level.block.type.FurnaceBlock;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -51,7 +51,7 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
|
|||
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(hasFuel ? BlockStateValues.JAVA_FURNACE_LIT_ID : BlockStateValues.JAVA_FURNACE_ID));
|
||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(FurnaceBlock.state(hasFuel)));
|
||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type;
|
|||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.level.block.type.SpawnerBlock;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -41,7 +41,7 @@ public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
|
|||
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(BlockStateValues.JAVA_SPAWNER_ID));
|
||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(SpawnerBlock.state()));
|
||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
|
|||
placeBlockSoundPacket.setIdentifier(":");
|
||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||
session.setLastBlockPlacePosition(null);
|
||||
session.setLastBlockPlacedId(null);
|
||||
session.setLastBlockPlaced(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,8 +36,9 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.LecternContainer;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
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;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.util.BlockUtils;
|
||||
|
@ -59,12 +60,14 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
private final ContainerType containerType;
|
||||
private final Set<String> validBlocks;
|
||||
|
||||
public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) {
|
||||
public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, Block... validBlocks) {
|
||||
this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(javaBlockIdentifier);
|
||||
this.containerType = containerType;
|
||||
if (validBlocks != null) {
|
||||
Set<String> validBlocksTemp = new HashSet<>(validBlocks.length + 1);
|
||||
Collections.addAll(validBlocksTemp, validBlocks);
|
||||
for (Block block : validBlocks) {
|
||||
validBlocksTemp.add(block.javaIdentifier().toString());
|
||||
}
|
||||
validBlocksTemp.add(BlockUtils.getCleanIdentifier(javaBlockIdentifier));
|
||||
this.validBlocks = Set.copyOf(validBlocksTemp);
|
||||
} else {
|
||||
|
@ -80,14 +83,15 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
if (checkInteractionPosition(session)) {
|
||||
// Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid
|
||||
// and the bedrock block is vanilla
|
||||
int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
|
||||
if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(javaBlockId)) {
|
||||
String[] javaBlockString = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaBlockId, BlockMapping.DEFAULT).getJavaIdentifier().split("\\[");
|
||||
BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition());
|
||||
if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) {
|
||||
// TODO TODO TODO
|
||||
String[] javaBlockString = state.toString().split("\\[");
|
||||
if (isValidBlock(javaBlockString)) {
|
||||
// We can safely use this block
|
||||
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||
((Container) inventory).setUsingRealBlock(true, javaBlockString[0]);
|
||||
setCustomName(session, session.getLastInteractionBlockPosition(), inventory, javaBlockId);
|
||||
setCustomName(session, session.getLastInteractionBlockPosition(), inventory, state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -107,7 +111,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
session.sendUpstreamPacket(blockPacket);
|
||||
inventory.setHolderPosition(position);
|
||||
|
||||
setCustomName(session, position, inventory, defaultJavaBlockState);
|
||||
setCustomName(session, position, inventory, BlockState.of(defaultJavaBlockState));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -129,7 +133,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
return this.validBlocks.contains(javaBlockString[0]);
|
||||
}
|
||||
|
||||
protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, int javaBlockState) {
|
||||
protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) {
|
||||
NbtMap tag = NbtMap.builder()
|
||||
.putInt("x", position.getX())
|
||||
.putInt("y", position.getY())
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -35,6 +35,7 @@ import org.cloudburstmc.nbt.NbtMap;
|
|||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.inventory.item.BannerPattern;
|
||||
import org.geysermc.geyser.inventory.item.DyeColor;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||
|
@ -199,8 +200,8 @@ public class BannerItem extends BlockItem {
|
|||
return null;
|
||||
}
|
||||
|
||||
public BannerItem(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
public BannerItem(Builder builder, Block block, Block... otherBlocks) {
|
||||
super(builder, block, otherBlocks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,11 +25,26 @@
|
|||
|
||||
package org.geysermc.geyser.item.type;
|
||||
|
||||
/**
|
||||
* TODO needed?
|
||||
*/
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
|
||||
public class BlockItem extends Item {
|
||||
public BlockItem(String javaIdentifier, Builder builder) {
|
||||
public BlockItem(Builder builder, Block block, Block... otherBlocks) {
|
||||
super(block.javaIdentifier().value(), builder);
|
||||
|
||||
// Ensure this item can be looked up by its block(s)
|
||||
registerBlock(block, this);
|
||||
for (Block otherBlock : otherBlocks) {
|
||||
registerBlock(otherBlock, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Use this constructor if the item name is not the same as its primary block
|
||||
public BlockItem(String javaIdentifier, Builder builder, Block block, Block... otherBlocks) {
|
||||
super(javaIdentifier, builder);
|
||||
|
||||
registerBlock(block, this);
|
||||
for (Block otherBlock : otherBlocks) {
|
||||
registerBlock(otherBlock, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.item.type;
|
|||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
|
@ -38,8 +39,8 @@ import java.util.List;
|
|||
|
||||
public class DecoratedPotItem extends BlockItem {
|
||||
|
||||
public DecoratedPotItem(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
public DecoratedPotItem(Builder builder, Block block, Block... otherBlocks) {
|
||||
super(builder, block, otherBlocks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.item.Enchantment;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -49,20 +50,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen
|
|||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Item {
|
||||
/**
|
||||
* This is a map from Java-only enchantments to their translation keys so that we can
|
||||
* map these enchantments to Bedrock clients, since they don't actually exist there.
|
||||
*/
|
||||
private static final Map<Enchantment.JavaEnchantment, String> ENCHANTMENT_TRANSLATION_KEYS = Map.of(
|
||||
Enchantment.JavaEnchantment.SWEEPING_EDGE, "enchantment.minecraft.sweeping",
|
||||
Enchantment.JavaEnchantment.DENSITY, "enchantment.minecraft.density",
|
||||
Enchantment.JavaEnchantment.BREACH, "enchantment.minecraft.breach",
|
||||
Enchantment.JavaEnchantment.WIND_BURST, "enchantment.minecraft.wind_burst");
|
||||
|
||||
private static final Map<Block, Item> BLOCK_TO_ITEM = new HashMap<>();
|
||||
private final String javaIdentifier;
|
||||
private int javaId = -1;
|
||||
private final int stackSize;
|
||||
|
@ -233,6 +226,16 @@ public class Item {
|
|||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a map from Java-only enchantments to their translation keys so that we can
|
||||
* map these enchantments to Bedrock clients, since they don't actually exist there.
|
||||
*/
|
||||
private static final Map<Enchantment.JavaEnchantment, String> ENCHANTMENT_TRANSLATION_KEYS = Map.of(
|
||||
Enchantment.JavaEnchantment.SWEEPING_EDGE, "enchantment.minecraft.sweeping",
|
||||
Enchantment.JavaEnchantment.DENSITY, "enchantment.minecraft.density",
|
||||
Enchantment.JavaEnchantment.BREACH, "enchantment.minecraft.breach",
|
||||
Enchantment.JavaEnchantment.WIND_BURST, "enchantment.minecraft.wind_burst");
|
||||
|
||||
protected final @Nullable NbtMap remapEnchantment(GeyserSession session, int enchantId, int level, BedrockItemBuilder builder) {
|
||||
// TODO verify
|
||||
// TODO streamline Enchantment process
|
||||
|
@ -281,6 +284,18 @@ public class Item {
|
|||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the block associated with this item, or air if nothing
|
||||
*/
|
||||
@NonNull
|
||||
public static Item byBlock(Block block) {
|
||||
return BLOCK_TO_ITEM.getOrDefault(block, Items.AIR);
|
||||
}
|
||||
|
||||
protected static void registerBlock(Block block, Item item) {
|
||||
BLOCK_TO_ITEM.put(block, item);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.item.type;
|
|||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
import org.geysermc.geyser.text.MinecraftLocale;
|
||||
|
@ -34,9 +35,9 @@ import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
|||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
||||
public class PlayerHeadItem extends Item {
|
||||
public PlayerHeadItem(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
public class PlayerHeadItem extends BlockItem {
|
||||
public PlayerHeadItem(Builder builder, Block block, Block... otherBlocks) {
|
||||
super(builder, block, otherBlocks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.cloudburstmc.nbt.NbtMap;
|
|||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
|
@ -42,8 +43,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
public class ShulkerBoxItem extends BlockItem {
|
||||
public ShulkerBoxItem(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
public ShulkerBoxItem(Builder builder, Block block, Block... otherBlocks) {
|
||||
super(builder, block, otherBlocks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -249,25 +249,6 @@ public final class BlockStateValues {
|
|||
return ALL_CAULDRONS.contains(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return The map of all DoubleChestValues.
|
||||
*/
|
||||
public static Int2ObjectMap<DoubleChestValue> getDoubleChestValues() {
|
||||
return DOUBLE_CHEST_VALUES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Int2ObjectMap of flower pot block states to containing plant
|
||||
*
|
||||
* @return Int2ObjectMap of flower pot values
|
||||
*/
|
||||
public static Int2ObjectMap<String> getFlowerPotValues() {
|
||||
return FLOWER_POT_VALUES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a set of all forward-facing jigsaws, to use as a fallback if NBT is missing.
|
||||
*/
|
||||
|
@ -282,26 +263,6 @@ public final class BlockStateValues {
|
|||
return LECTERN_BOOK_STATES;
|
||||
}
|
||||
|
||||
/**
|
||||
* The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock.
|
||||
* This gives an integer pitch that Bedrock can use.
|
||||
*
|
||||
* @param state BlockState of the block
|
||||
* @return note block note integer or -1 if not present
|
||||
*/
|
||||
public static int getNoteblockPitch(int state) {
|
||||
return NOTEBLOCK_PITCHES.getOrDefault(state, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Int2BooleanMap showing if a piston block state is extended or not.
|
||||
*
|
||||
* @return the Int2BooleanMap of piston extensions.
|
||||
*/
|
||||
public static Int2BooleanMap getPistonValues() {
|
||||
return PISTON_VALUES;
|
||||
}
|
||||
|
||||
public static boolean isStickyPiston(int blockState) {
|
||||
return STICKY_PISTONS.contains(blockState);
|
||||
}
|
||||
|
@ -435,16 +396,6 @@ public final class BlockStateValues {
|
|||
return WATER_LEVEL.getOrDefault(state, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a block is the upper half of a door.
|
||||
*
|
||||
* @param state BlockState of the block
|
||||
* @return True if the block is the upper half of a door
|
||||
*/
|
||||
public static boolean isUpperDoor(int state) {
|
||||
return UPPER_DOORS.contains(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of water from the block state
|
||||
* This is used in FishingHookEntity to create splash sounds when the hook hits the water. In addition,
|
||||
|
|
|
@ -82,7 +82,7 @@ public final class Blocks {
|
|||
.intState(STAGE, 0, 1)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BEDROCK = register(new Block("bedrock", builder().destroyTime(-1.0f)));
|
||||
public static final Block WATER = register(new Block("water", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block WATER = register(new WaterBlock("water", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(LEVEL, 0, 15)));
|
||||
public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(LEVEL, 0, 15)));
|
||||
|
@ -379,7 +379,7 @@ public final class Blocks {
|
|||
.booleanState(UP)
|
||||
.booleanState(WEST)));
|
||||
public static final Block SOUL_FIRE = register(new Block("soul_fire", builder().pushReaction(PistonBehavior.DESTROY)));
|
||||
public static final Block SPAWNER = register(new Block("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f)));
|
||||
public static final Block SPAWNER = register(new SpawnerBlock("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f)));
|
||||
public static final Block OAK_STAIRS = register(new Block("oak_stairs", builder().destroyTime(2.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.enumState(HALF, "top", "bottom")
|
||||
|
@ -403,7 +403,7 @@ public final class Blocks {
|
|||
.intState(AGE_7, 0, 7)));
|
||||
public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f)
|
||||
.intState(MOISTURE, 0, 7)));
|
||||
public static final Block FURNACE = register(new Block("furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
public static final Block FURNACE = register(new FurnaceBlock("furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(LIT)));
|
||||
public static final Block OAK_SIGN = register(new Block("oak_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
|
@ -823,10 +823,10 @@ public final class Blocks {
|
|||
.booleanState(HAS_BOTTLE_1)
|
||||
.booleanState(HAS_BOTTLE_2)));
|
||||
public static final Block CAULDRON = register(new CauldronBlock("cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)));
|
||||
public static final Block WATER_CAULDRON = register(new Block("water_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)
|
||||
public static final Block WATER_CAULDRON = register(new CauldronBlock("water_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)
|
||||
.intState(LEVEL_CAULDRON, 1, 3)));
|
||||
public static final Block LAVA_CAULDRON = register(new Block("lava_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)));
|
||||
public static final Block POWDER_SNOW_CAULDRON = register(new Block("powder_snow_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)
|
||||
public static final Block LAVA_CAULDRON = register(new CauldronBlock("lava_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)));
|
||||
public static final Block POWDER_SNOW_CAULDRON = register(new CauldronBlock("powder_snow_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)
|
||||
.intState(LEVEL_CAULDRON, 1, 3)));
|
||||
public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK)));
|
||||
public static final Block END_PORTAL_FRAME = register(new Block("end_portal_frame", builder().destroyTime(-1.0f)
|
||||
|
@ -2179,7 +2179,7 @@ public final class Blocks {
|
|||
public static final Block BEEHIVE = register(new Block("beehive", builder().setBlockEntity().destroyTime(0.6f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.intState(LEVEL_HONEY, 0, 5)));
|
||||
public static final Block HONEY_BLOCK = register(new Block("honey_block", builder()));
|
||||
public static final Block HONEY_BLOCK = register(new HoneyBlock("honey_block", builder()));
|
||||
public static final Block HONEYCOMB_BLOCK = register(new Block("honeycomb_block", builder().destroyTime(0.6f)));
|
||||
public static final Block NETHERITE_BLOCK = register(new Block("netherite_block", builder().requiresCorrectToolForDrops().destroyTime(50.0f)));
|
||||
public static final Block ANCIENT_DEBRIS = register(new Block("ancient_debris", builder().requiresCorrectToolForDrops().destroyTime(30.0f)));
|
||||
|
|
|
@ -32,6 +32,10 @@ public class Property<T extends Comparable<T>> {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[" + name + "]";
|
||||
|
|
|
@ -25,21 +25,24 @@
|
|||
|
||||
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 it.unimi.dsi.fastutil.objects.Reference2ObjectMaps;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.level.block.property.Properties;
|
||||
import org.geysermc.geyser.level.block.property.Property;
|
||||
import org.geysermc.geyser.level.physics.PistonBehavior;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
|
||||
import org.intellij.lang.annotations.Subst;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -47,20 +50,21 @@ import java.util.stream.Stream;
|
|||
public class Block {
|
||||
public static final int JAVA_AIR_ID = 0;
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final Key javaIdentifier;
|
||||
private final boolean requiresCorrectToolForDrops;
|
||||
private final boolean hasBlockEntity;
|
||||
private final float destroyTime;
|
||||
private final @NonNull PistonBehavior pushReaction;
|
||||
protected Item item = null;
|
||||
private int javaId = -1;
|
||||
|
||||
public Block(String javaIdentifier, Builder builder) {
|
||||
this.javaIdentifier = Identifier.formalize(javaIdentifier).intern();
|
||||
public Block(@Subst("empty") String javaIdentifier, Builder builder) {
|
||||
this.javaIdentifier = Key.key(javaIdentifier);
|
||||
this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops;
|
||||
this.hasBlockEntity = builder.hasBlockEntity;
|
||||
this.destroyTime = builder.destroyTime;
|
||||
this.pushReaction = builder.pushReaction;
|
||||
builder.build(this);
|
||||
processStates(builder.build(this));
|
||||
}
|
||||
|
||||
public void updateBlock(GeyserSession session, BlockState state, Vector3i position) {
|
||||
|
@ -114,7 +118,8 @@ public class Block {
|
|||
UpdateBlockPacket waterPacket = new UpdateBlockPacket();
|
||||
waterPacket.setDataLayer(1);
|
||||
waterPacket.setBlockPosition(position);
|
||||
if (BlockRegistries.WATERLOGGED.get().get(state.javaId())) {
|
||||
Boolean waterlogged = state.getValue(Properties.WATERLOGGED);
|
||||
if (waterlogged == Boolean.TRUE) {
|
||||
waterPacket.setDefinition(session.getBlockMappings().getBedrockWater());
|
||||
} else {
|
||||
waterPacket.setDefinition(session.getBlockMappings().getBedrockAir());
|
||||
|
@ -129,7 +134,21 @@ public class Block {
|
|||
}
|
||||
}
|
||||
|
||||
public String javaIdentifier() {
|
||||
public Item asItem() {
|
||||
if (this.item == null) {
|
||||
return this.item = Item.byBlock(this);
|
||||
}
|
||||
return this.item;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of BlockStates is created pertaining to this block. Do we need any of them? If so, override this method.
|
||||
*/
|
||||
protected void processStates(List<BlockState> states) {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Key javaIdentifier() {
|
||||
return javaIdentifier;
|
||||
}
|
||||
|
||||
|
@ -163,7 +182,7 @@ public class Block {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Item{" +
|
||||
return "Block{" +
|
||||
"javaIdentifier='" + javaIdentifier + '\'' +
|
||||
", javaId=" + javaId +
|
||||
'}';
|
||||
|
@ -229,14 +248,27 @@ public class Block {
|
|||
return this;
|
||||
}
|
||||
|
||||
private void build(Block block) {
|
||||
private List<BlockState> build(Block block) {
|
||||
if (states.isEmpty()) {
|
||||
BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size()));
|
||||
BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size());
|
||||
BlockRegistries.BLOCK_STATES.get().add(state);
|
||||
return List.of(state);
|
||||
} else if (states.size() == 1) {
|
||||
// We can optimize because we don't need to worry about combinations
|
||||
Map.Entry<Property<?>, List<Comparable<?>>> property = this.states.entrySet().stream().findFirst().orElseThrow();
|
||||
List<BlockState> states = new ArrayList<>(property.getValue().size());
|
||||
property.getValue().forEach(value -> {
|
||||
Reference2ObjectMap<Property<?>, Comparable<?>> propertyMap = Reference2ObjectMaps.singleton(property.getKey(), value);
|
||||
BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap);
|
||||
BlockRegistries.BLOCK_STATES.get().add(state);
|
||||
states.add(state);
|
||||
});
|
||||
return states;
|
||||
} 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()) {
|
||||
Stream<List<Comparable<?>>> stream = Stream.of(Collections.emptyList());
|
||||
for (var values : this.states.values()) {
|
||||
// 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.
|
||||
|
@ -247,24 +279,29 @@ public class Block {
|
|||
// 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 -> {
|
||||
values.stream().map(value -> {
|
||||
var newProperties = new ArrayList<>(aPreviousPropertiesList);
|
||||
newProperties.add(Pair.of(state.getKey(), value));
|
||||
newProperties.add(value);
|
||||
return newProperties;
|
||||
}));
|
||||
}
|
||||
|
||||
List<BlockState> states = new ArrayList<>();
|
||||
// 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));
|
||||
List<List<Comparable<?>>> result = stream.toList();
|
||||
// Ensure each block state shares the same key array. Creating a keySet here shouldn't be an issue since
|
||||
// this states map should be removed after build.
|
||||
Property<?>[] keys = this.states.keySet().toArray(new Property<?>[0]);
|
||||
result.forEach(properties -> {
|
||||
Comparable<?>[] values = properties.toArray(new Comparable<?>[0]);
|
||||
Reference2ObjectMap<Property<?>, Comparable<?>> propertyMap = new Reference2ObjectArrayMap<>(keys, values);
|
||||
BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap);
|
||||
BlockRegistries.BLOCK_STATES.get().add(state);
|
||||
states.add(state);
|
||||
});
|
||||
return states;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps;
|
|||
import org.geysermc.geyser.level.block.property.Property;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public final class BlockState {
|
||||
private final Block block;
|
||||
private final int javaId;
|
||||
|
@ -62,12 +64,25 @@ public final class BlockState {
|
|||
return this.block == block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.states.isEmpty()) {
|
||||
return this.block.javaIdentifier().toString();
|
||||
}
|
||||
return this.block.javaIdentifier().toString() + "[" + paramsToString() + "]";
|
||||
}
|
||||
|
||||
private String paramsToString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
var it = this.states.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
var entry = it.next();
|
||||
builder.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
builder.append(entry.getKey().name())
|
||||
.append("=")
|
||||
.append(entry.getValue().toString().toLowerCase(Locale.ROOT)); // lowercase covers enums
|
||||
if (it.hasNext()) {
|
||||
builder.append(",");
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public class FlowerPotBlock extends Block implements BedrockChunkWantsBlockEntit
|
|||
if (this.flower != Blocks.AIR) {
|
||||
// Get the Bedrock CompoundTag of the block.
|
||||
// This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states.
|
||||
NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(this.flower.javaIdentifier());
|
||||
NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(this.flower.javaIdentifier().asString());
|
||||
if (plant != null) {
|
||||
tagBuilder.putCompound("PlantBlock", plant.toBuilder().build());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 org.geysermc.geyser.level.block.property.Properties;
|
||||
import org.geysermc.geyser.level.physics.Direction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FurnaceBlock extends Block {
|
||||
private static BlockState LIT;
|
||||
private static BlockState UNLIT;
|
||||
|
||||
public FurnaceBlock(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processStates(List<BlockState> states) {
|
||||
LIT = states.stream()
|
||||
.filter(state -> state.getValue(Properties.HORIZONTAL_FACING) == Direction.NORTH
|
||||
&& state.getValue(Properties.LIT))
|
||||
.findFirst().orElseThrow();
|
||||
UNLIT = states.stream()
|
||||
.filter(state -> state.getValue(Properties.HORIZONTAL_FACING) == Direction.NORTH
|
||||
&& !state.getValue(Properties.LIT))
|
||||
.findFirst().orElseThrow();
|
||||
}
|
||||
|
||||
public static BlockState state(boolean lit) {
|
||||
return lit ? LIT : UNLIT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
public class HoneyBlock extends Block {
|
||||
private static BlockState STATE;
|
||||
|
||||
public HoneyBlock(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processStates(List<BlockState> states) {
|
||||
STATE = states.get(0);
|
||||
}
|
||||
|
||||
public static BlockState state() {
|
||||
return STATE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
public class SpawnerBlock extends Block {
|
||||
private static BlockState STATE;
|
||||
|
||||
public SpawnerBlock(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processStates(List<BlockState> states) {
|
||||
STATE = states.get(0);
|
||||
}
|
||||
|
||||
public static BlockState state() {
|
||||
return STATE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
public class WaterBlock extends Block {
|
||||
private static BlockState LEVEL_0;
|
||||
|
||||
public WaterBlock(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processStates(List<BlockState> states) {
|
||||
super.processStates(states);
|
||||
}
|
||||
}
|
|
@ -147,6 +147,7 @@ public class BlockRegistries {
|
|||
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION);
|
||||
BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK);
|
||||
BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.POST_INIT);
|
||||
System.out.println("Block registries loaded");
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
|
|
|
@ -204,5 +204,6 @@ public final class Registries {
|
|||
biomesNbt.put(key, value.build());
|
||||
}
|
||||
BIOMES_NBT.set(biomesNbt.build());
|
||||
System.out.println("Registries loaded");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
|
|||
}
|
||||
|
||||
private @Nullable BlockCollision instantiateCollision(BlockState state, Map<Class<?>, CollisionInfo> annotationMap, int collisionIndex, List<BoundingBox[]> collisionList) {
|
||||
String blockName = state.block().javaIdentifier().substring("minecraft:".length());
|
||||
String blockName = state.block().javaIdentifier().value();
|
||||
|
||||
for (Map.Entry<Class<?>, CollisionInfo> collisionRemappers : annotationMap.entrySet()) {
|
||||
Class<?> type = collisionRemappers.getKey();
|
||||
|
|
|
@ -50,10 +50,12 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
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.item.type.Item;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.level.physics.PistonBehavior;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||
import org.geysermc.geyser.registry.type.BlockMappings;
|
||||
import org.geysermc.geyser.registry.type.GeyserBedrockBlock;
|
||||
|
@ -391,7 +393,7 @@ public final class BlockRegistryPopulator {
|
|||
throw new AssertionError("Unable to load Java block mappings", e);
|
||||
}
|
||||
|
||||
JAVA_BLOCKS_SIZE = blocksJson.size();
|
||||
JAVA_BLOCKS_SIZE = BlockRegistries.BLOCK_STATES.get().size();
|
||||
|
||||
if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) {
|
||||
MIN_CUSTOM_RUNTIME_ID = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet().stream().min(Comparator.comparing(JavaBlockState::javaId)).orElseThrow().javaId();
|
||||
|
@ -409,12 +411,6 @@ public final class BlockRegistryPopulator {
|
|||
Deque<String> cleanIdentifiers = new ArrayDeque<>();
|
||||
|
||||
int javaRuntimeId = -1;
|
||||
int furnaceRuntimeId = -1;
|
||||
int furnaceLitRuntimeId = -1;
|
||||
int honeyBlockRuntimeId = -1;
|
||||
int slimeBlockRuntimeId = -1;
|
||||
int spawnerRuntimeId = -1;
|
||||
int uniqueJavaId = -1;
|
||||
int waterRuntimeId = -1;
|
||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocksJson.fields();
|
||||
while (blocksIterator.hasNext()) {
|
||||
|
@ -422,7 +418,6 @@ public final class BlockRegistryPopulator {
|
|||
Map.Entry<String, JsonNode> entry = blocksIterator.next();
|
||||
String javaId = entry.getKey();
|
||||
|
||||
// TODO fix this, (no block should have a null hardness)
|
||||
BlockMapping.BlockMappingBuilder builder = BlockMapping.builder();
|
||||
|
||||
JsonNode pickItemNode = entry.getValue().get("pick_item");
|
||||
|
@ -443,7 +438,6 @@ public final class BlockRegistryPopulator {
|
|||
String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
|
||||
|
||||
if (!cleanJavaIdentifier.equals(cleanIdentifiers.peekLast())) {
|
||||
uniqueJavaId++;
|
||||
cleanIdentifiers.add(cleanJavaIdentifier.intern());
|
||||
}
|
||||
|
||||
|
@ -456,50 +450,11 @@ public final class BlockRegistryPopulator {
|
|||
// 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 (javaId.startsWith("minecraft:furnace[facing=north")) {
|
||||
if (javaId.contains("lit=true")) {
|
||||
furnaceLitRuntimeId = javaRuntimeId;
|
||||
} else {
|
||||
furnaceRuntimeId = javaRuntimeId;
|
||||
}
|
||||
|
||||
} else if (javaId.startsWith("minecraft:spawner")) {
|
||||
spawnerRuntimeId = javaRuntimeId;
|
||||
|
||||
} else if ("minecraft:water[level=0]".equals(javaId)) {
|
||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
||||
waterRuntimeId = javaRuntimeId;
|
||||
} else if (javaId.equals("minecraft:honey_block")) {
|
||||
honeyBlockRuntimeId = javaRuntimeId;
|
||||
} else if (javaId.equals("minecraft:slime_block")) {
|
||||
slimeBlockRuntimeId = javaRuntimeId;
|
||||
}
|
||||
}
|
||||
|
||||
if (furnaceRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find furnace in palette");
|
||||
}
|
||||
BlockStateValues.JAVA_FURNACE_ID = furnaceRuntimeId;
|
||||
|
||||
if (furnaceLitRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find lit furnace in palette");
|
||||
}
|
||||
BlockStateValues.JAVA_FURNACE_LIT_ID = furnaceLitRuntimeId;
|
||||
|
||||
if (honeyBlockRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find honey block in palette");
|
||||
}
|
||||
BlockStateValues.JAVA_HONEY_BLOCK_ID = honeyBlockRuntimeId;
|
||||
|
||||
if (slimeBlockRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find slime block in palette");
|
||||
}
|
||||
BlockStateValues.JAVA_SLIME_BLOCK_ID = slimeBlockRuntimeId;
|
||||
|
||||
if (spawnerRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find spawner in palette");
|
||||
}
|
||||
BlockStateValues.JAVA_SPAWNER_ID = spawnerRuntimeId;
|
||||
|
||||
if (waterRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find Java water in palette");
|
||||
}
|
||||
|
@ -534,12 +489,20 @@ public final class BlockRegistryPopulator {
|
|||
builder.setBlockEntity();
|
||||
}
|
||||
String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier());
|
||||
Block block = new Block(cleanJavaIdentifier, builder);
|
||||
String pickItem = javaBlockState.pickItem();
|
||||
Block block = new Block(cleanJavaIdentifier, builder) {
|
||||
@Override
|
||||
public Item asItem() {
|
||||
if (this.item == null) {
|
||||
return Registries.JAVA_ITEM_IDENTIFIERS.get(pickItem);
|
||||
}
|
||||
return this.item;
|
||||
}
|
||||
};
|
||||
|
||||
String bedrockIdentifier = customBlockState.block().identifier();
|
||||
|
||||
if (!cleanJavaIdentifier.equals(cleanIdentifiers.peekLast())) {
|
||||
uniqueJavaId++;
|
||||
cleanIdentifiers.add(cleanJavaIdentifier.intern());
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ package org.geysermc.geyser.registry.type;
|
|||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.util.BlockUtils;
|
||||
|
||||
@Builder
|
||||
@Value
|
||||
|
@ -37,42 +36,8 @@ public class BlockMapping {
|
|||
|
||||
String javaIdentifier;
|
||||
|
||||
boolean canBreakWithHand;
|
||||
@Nullable String pickItem;
|
||||
|
||||
boolean isBlockEntity;
|
||||
boolean isNonVanilla;
|
||||
|
||||
/**
|
||||
* @return the identifier without the additional block states
|
||||
*/
|
||||
public String getCleanJavaIdentifier() {
|
||||
return BlockUtils.getCleanIdentifier(javaIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the corresponding Java identifier for this item
|
||||
*/
|
||||
public String getItemIdentifier() {
|
||||
if (pickItem != null && !pickItem.equals("minecraft:air")) {
|
||||
// Spawners can have air as their pick item which we are not interested in.
|
||||
return pickItem;
|
||||
}
|
||||
|
||||
return getCleanJavaIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item a Java client would receive when pressing
|
||||
* the Pick Block key on a specific Java block state.
|
||||
*
|
||||
* @return The Java identifier of the item
|
||||
*/
|
||||
public String getPickItem() {
|
||||
if (pickItem != null) {
|
||||
return pickItem;
|
||||
}
|
||||
|
||||
return getCleanJavaIdentifier();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ import org.geysermc.geyser.inventory.PlayerInventory;
|
|||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.BlockItem;
|
||||
import org.geysermc.geyser.level.JavaDimension;
|
||||
import org.geysermc.geyser.level.WorldManager;
|
||||
import org.geysermc.geyser.level.physics.CollisionManager;
|
||||
|
@ -349,7 +350,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
private Vector3i lastBlockPlacePosition;
|
||||
|
||||
@Setter
|
||||
private String lastBlockPlacedId;
|
||||
private BlockItem lastBlockPlaced;
|
||||
|
||||
@Setter
|
||||
private boolean interacting;
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.geysermc.geyser.inventory.Inventory;
|
|||
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
|
||||
import org.geysermc.geyser.inventory.holder.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
/**
|
||||
|
@ -44,10 +45,10 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran
|
|||
* @param javaBlockIdentifier a Java block identifier that is used as a temporary block
|
||||
* @param containerType the container type of this inventory
|
||||
* @param updater updater
|
||||
* @param additionalValidBlocks any other block identifiers that can safely use this inventory without a fake block
|
||||
* @param additionalValidBlocks any other blocks that can safely use this inventory without a fake block
|
||||
*/
|
||||
public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater,
|
||||
String... additionalValidBlocks) {
|
||||
Block... additionalValidBlocks) {
|
||||
super(size);
|
||||
this.holder = new BlockInventoryHolder(javaBlockIdentifier, containerType, additionalValidBlocks);
|
||||
this.updater = updater;
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
|||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.updater.AnvilInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
|
@ -45,7 +46,7 @@ import java.util.Objects;
|
|||
public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public AnvilInventoryTranslator() {
|
||||
super(3, "minecraft:anvil[facing=north]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE,
|
||||
"minecraft:chipped_anvil", "minecraft:damaged_anvil");
|
||||
Blocks.CHIPPED_ANVIL, Blocks.DAMAGED_ANVIL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.geysermc.geyser.inventory.Generic3X3Container;
|
|||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
|
@ -41,7 +42,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
|||
public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public Generic3X3InventoryTranslator() {
|
||||
super(9, "minecraft:dispenser[facing=north,triggered=false]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE,
|
||||
"minecraft:dropper");
|
||||
Blocks.DROPPER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,14 +52,14 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, int javaBlockState) {
|
||||
protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) {
|
||||
NbtMapBuilder tag = NbtMap.builder()
|
||||
.putInt("x", position.getX())
|
||||
.putInt("y", position.getY())
|
||||
.putInt("z", position.getZ())
|
||||
.putString("CustomName", inventory.getTitle());
|
||||
// Don't reset facing property
|
||||
shulkerBoxTranslator.translateTag(session, tag, null, BlockState.of(javaBlockState));
|
||||
shulkerBoxTranslator.translateTag(session, tag, null, javaBlockState);
|
||||
|
||||
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag.build());
|
||||
|
|
|
@ -29,15 +29,17 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
|||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
|
||||
import org.geysermc.geyser.inventory.holder.InventoryHolder;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
private final InventoryHolder holder;
|
||||
|
||||
// TODO add barrel???
|
||||
public SingleChestInventoryTranslator(int size) {
|
||||
super(size, 27);
|
||||
this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER,
|
||||
"minecraft:ender_chest", "minecraft:trapped_chest") {
|
||||
Blocks.ENDER_CHEST, Blocks.TRAPPED_CHEST) {
|
||||
@Override
|
||||
protected boolean isValidBlock(String[] javaBlockString) {
|
||||
if (javaBlockString[0].equals("minecraft:ender_chest")) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.objects.*;
|
|||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.level.block.type.BlockState;
|
||||
import org.geysermc.geyser.level.block.type.HoneyBlock;
|
||||
import org.geysermc.geyser.level.block.type.PistonBlock;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
|
||||
import org.cloudburstmc.math.vector.Vector3d;
|
||||
|
@ -98,7 +99,7 @@ public class PistonBlockEntity {
|
|||
|
||||
static {
|
||||
// Create a ~1 x ~0.5 x ~1 bounding box above the honey block
|
||||
BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(BlockStateValues.JAVA_HONEY_BLOCK_ID);
|
||||
BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(HoneyBlock.state().javaId());
|
||||
if (blockCollision == null) {
|
||||
throw new RuntimeException("Failed to find honey block collision");
|
||||
}
|
||||
|
@ -622,11 +623,11 @@ public class PistonBlockEntity {
|
|||
}
|
||||
placedFinalBlocks = true;
|
||||
Vector3i movement = getMovement();
|
||||
attachedBlocks.forEach((blockPos, javaId) -> {
|
||||
attachedBlocks.forEach((blockPos, state) -> {
|
||||
blockPos = blockPos.add(movement);
|
||||
// Don't place blocks that collide with the player
|
||||
if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) {
|
||||
ChunkUtils.updateBlock(session, javaId, blockPos);
|
||||
ChunkUtils.updateBlock(session, state, blockPos);
|
||||
}
|
||||
});
|
||||
if (action == PistonValueType.PUSHING) {
|
||||
|
|
|
@ -29,11 +29,10 @@ import org.cloudburstmc.math.vector.Vector3i;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.level.block.type.BannerBlock;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
@ -46,10 +45,10 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator<BlockPic
|
|||
@Override
|
||||
public void translate(GeyserSession session, BlockPickRequestPacket packet) {
|
||||
Vector3i vector = packet.getBlockPosition();
|
||||
int blockToPick = session.getGeyser().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ());
|
||||
Block blockToPick = session.getGeyser().getWorldManager().blockAt(session, vector.getX(), vector.getY(), vector.getZ()).block();
|
||||
|
||||
// Block is air - chunk caching is probably off
|
||||
if (blockToPick == Block.JAVA_AIR_ID) {
|
||||
if (blockToPick == Blocks.AIR) {
|
||||
// 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) {
|
||||
|
@ -59,35 +58,31 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator<BlockPic
|
|||
InventoryUtils.findOrCreateItem(session, entity.getHeldItem());
|
||||
} else {
|
||||
// Grab the frame as the item
|
||||
InventoryUtils.findOrCreateItem(session, entity.getDefinition() == EntityDefinitions.GLOW_ITEM_FRAME ? "minecraft:glow_item_frame" : "minecraft:item_frame");
|
||||
InventoryUtils.findOrCreateItem(session, entity.getDefinition() == EntityDefinitions.GLOW_ITEM_FRAME ? Items.GLOW_ITEM_FRAME : Items.ITEM_FRAME);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BlockMapping blockMapping = BlockRegistries.JAVA_BLOCKS.getOrDefault(blockToPick, BlockMapping.DEFAULT);
|
||||
boolean addExtraData = packet.isAddUserData() && blockMapping.isBlockEntity(); // Holding down CTRL
|
||||
if (BlockStateValues.getBannerColor(blockToPick) != -1 || addExtraData) { //TODO
|
||||
boolean addExtraData = packet.isAddUserData() && blockToPick.hasBlockEntity(); // Holding down CTRL
|
||||
if (blockToPick instanceof BannerBlock || addExtraData) { //TODO
|
||||
session.getGeyser().getWorldManager().getPickItemComponents(session, vector.getX(), vector.getY(), vector.getZ(), addExtraData)
|
||||
.whenComplete((components, ex) -> session.ensureInEventLoop(() -> {
|
||||
if (components == null) {
|
||||
pickItem(session, blockMapping);
|
||||
pickItem(session, blockToPick);
|
||||
return;
|
||||
}
|
||||
|
||||
// I don't really like this... I'd rather get an ID from the block mapping I think
|
||||
ItemMapping mapping = session.getItemMappings().getMapping(blockMapping.getPickItem());
|
||||
|
||||
ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), 1, components);
|
||||
ItemStack itemStack = new ItemStack(blockToPick.asItem().javaId(), 1, components);
|
||||
InventoryUtils.findOrCreateItem(session, itemStack);
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
pickItem(session, blockMapping);
|
||||
pickItem(session, blockToPick);
|
||||
}
|
||||
|
||||
private void pickItem(GeyserSession session, BlockMapping blockToPick) {
|
||||
InventoryUtils.findOrCreateItem(session, blockToPick.getPickItem());
|
||||
private void pickItem(GeyserSession session, Block block) {
|
||||
InventoryUtils.findOrCreateItem(session, block.asItem());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -355,9 +355,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
}
|
||||
}
|
||||
}
|
||||
if (item instanceof BlockItem) {
|
||||
if (item instanceof BlockItem blockItem) {
|
||||
session.setLastBlockPlacePosition(blockPos);
|
||||
session.setLastBlockPlacedId(item.javaIdentifier());
|
||||
session.setLastBlockPlaced(blockItem);
|
||||
}
|
||||
session.setInteracting(true);
|
||||
}
|
||||
|
@ -420,7 +420,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
int blockState = session.getGameMode() == GameMode.CREATIVE ?
|
||||
session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition()) : session.getBreakingBlock();
|
||||
|
||||
session.setLastBlockPlacedId(null);
|
||||
session.setLastBlockPlaced(null);
|
||||
session.setLastBlockPlacePosition(null);
|
||||
|
||||
// Same deal with vanilla block placing as above.
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.java.level;
|
||||
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.level.block.type.BlockState;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockUpdatePacket;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||
|
@ -66,14 +68,14 @@ public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlock
|
|||
// We need to check if the identifier is the same, else a packet with the sound of what the
|
||||
// player has in their hand is played, despite if the block is being placed or not
|
||||
boolean contains = false;
|
||||
String identifier = BlockRegistries.JAVA_BLOCKS.get(packet.getEntry().getBlock()).getItemIdentifier();
|
||||
if (identifier.equals(session.getLastBlockPlacedId())) {
|
||||
Item item = BlockState.of(packet.getEntry().getBlock()).block().asItem();
|
||||
if (item == session.getLastBlockPlaced()) {
|
||||
contains = true;
|
||||
}
|
||||
|
||||
if (!contains) {
|
||||
session.setLastBlockPlacePosition(null);
|
||||
session.setLastBlockPlacedId(null);
|
||||
session.setLastBlockPlaced(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -86,7 +88,7 @@ public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlock
|
|||
placeBlockSoundPacket.setIdentifier(":");
|
||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||
session.setLastBlockPlacePosition(null);
|
||||
session.setLastBlockPlacedId(null);
|
||||
session.setLastBlockPlaced(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -166,11 +166,13 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
|||
GeyserChunkSection section = new GeyserChunkSection(session.getBlockMappings().getBedrockAir().getRuntimeId(), subChunkIndex);
|
||||
for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) {
|
||||
int javaId = javaData.get(yzx);
|
||||
BlockState state = BlockState.of(javaId);
|
||||
int bedrockId = session.getBlockMappings().getBedrockBlockId(javaId);
|
||||
int xzy = indexYZXtoXZY(yzx);
|
||||
section.getBlockStorageArray()[0].setFullBlock(xzy, bedrockId);
|
||||
|
||||
if (BlockRegistries.WATERLOGGED.get().get(javaId)) {
|
||||
Boolean waterlogged = state.getValue(Properties.WATERLOGGED); // TODO performance check
|
||||
if (waterlogged == Boolean.TRUE) {
|
||||
section.getBlockStorageArray()[1].setFullBlock(xzy, session.getBlockMappings().getBedrockWater().getRuntimeId());
|
||||
}
|
||||
|
||||
|
@ -192,7 +194,6 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
|||
}
|
||||
}
|
||||
|
||||
BlockState state = BlockState.of(javaId);
|
||||
// Check if block is piston or flower to see if we'll need to create additional block entities, as they're only block entities in Bedrock
|
||||
if (state.block() instanceof BedrockChunkWantsBlockEntityTag blockEntity) {
|
||||
bedrockBlockEntities.add(blockEntity.createTag(session,
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
|||
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.level.BedrockDimension;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
|
@ -300,6 +301,11 @@ public class InventoryUtils {
|
|||
}
|
||||
}
|
||||
|
||||
// Please remove!!!
|
||||
public static void findOrCreateItem(GeyserSession session, String itemName) {
|
||||
findOrCreateItem(session, Registries.JAVA_ITEM_IDENTIFIERS.getOrDefault(itemName, Items.AIR));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find the specified item name in the session's inventory.
|
||||
* If it is found and in the hotbar, set the user's held item to that slot.
|
||||
|
@ -309,13 +315,13 @@ public class InventoryUtils {
|
|||
* <p>
|
||||
* This attempts to mimic Java Edition behavior as best as it can.
|
||||
* @param session the Bedrock client's session
|
||||
* @param itemName the Java identifier of the item to search/select
|
||||
* @param item the Java item to search/select for
|
||||
*/
|
||||
public static void findOrCreateItem(GeyserSession session, String itemName) {
|
||||
public static void findOrCreateItem(GeyserSession session, Item item) {
|
||||
// Get the inventory to choose a slot to pick
|
||||
PlayerInventory inventory = session.getPlayerInventory();
|
||||
|
||||
if (itemName.equals("minecraft:air")) {
|
||||
if (item == Items.AIR) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -326,7 +332,7 @@ public class InventoryUtils {
|
|||
continue;
|
||||
}
|
||||
// If this isn't the item we're looking for
|
||||
if (!geyserItem.asItem().javaIdentifier().equals(itemName)) {
|
||||
if (!geyserItem.asItem().equals(item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -342,7 +348,7 @@ public class InventoryUtils {
|
|||
continue;
|
||||
}
|
||||
// If this isn't the item we're looking for
|
||||
if (!geyserItem.asItem().javaIdentifier().equals(itemName)) {
|
||||
if (!geyserItem.asItem().equals(item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -355,17 +361,13 @@ public class InventoryUtils {
|
|||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
int slot = findEmptyHotbarSlot(inventory);
|
||||
|
||||
ItemMapping mapping = session.getItemMappings().getMapping(itemName); // TODO
|
||||
if (mapping != null) {
|
||||
ItemMapping mapping = session.getItemMappings().getMapping(item);
|
||||
ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket((short)slot,
|
||||
new ItemStack(mapping.getJavaItem().javaId()));
|
||||
if ((slot - 36) != inventory.getHeldItemSlot()) {
|
||||
setHotbarItem(session, slot);
|
||||
}
|
||||
session.sendDownstreamGamePacket(actionPacket);
|
||||
} else {
|
||||
session.getGeyser().getLogger().debug("Cannot find item for block " + itemName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ public class StatisticsUtils {
|
|||
if (entry.getKey() instanceof BreakBlockStatistic statistic) {
|
||||
Block block = BlockRegistries.JAVA_BLOCKS_TO_RENAME.get(statistic.getId());
|
||||
if (block != null) {
|
||||
String identifier = block.javaIdentifier().replace("minecraft:", "block.minecraft.");
|
||||
String identifier = "block.minecraft." + block.javaIdentifier().value();
|
||||
content.add(identifier + ": " + entry.getIntValue());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue