3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-11-20 06:50:09 +01:00

Merge remote-tracking branch 'upstream/dev' into client-vehicle

Dieser Commit ist enthalten in:
AJ Ferguson 2024-05-23 02:59:16 -04:00
Commit 32d587a65a
65 geänderte Dateien mit 1350 neuen und 1092 gelöschten Zeilen

Datei anzeigen

@ -41,6 +41,7 @@ import org.bukkit.event.block.BlockPistonRetractEvent;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
@ -120,7 +121,7 @@ public class GeyserPistonListener implements Listener {
int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock()); int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock());
// event.getDirection() is unreliable // event.getDirection() is unreliable
Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId); Direction orientation = BlockState.of(pistonBlockId).getValue(Properties.FACING);
session.executeInEventLoop(() -> { session.executeInEventLoop(() -> {
PistonCache pistonCache = session.getPistonCache(); PistonCache pistonCache = session.getPistonCache();

Datei anzeigen

@ -42,7 +42,6 @@ import org.geysermc.erosion.bukkit.SchedulerUtils;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.GameRule;
import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
@ -88,7 +87,7 @@ public class GeyserSpigotWorldManager extends WorldManager {
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString())); Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID);
} }
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); // TODO could just make this a BlockState lookup?
} }
@Override @Override

Datei anzeigen

@ -235,7 +235,7 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.BOOLEAN, .addTranslator(MetadataType.BOOLEAN,
(enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal (enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal
.build(); .build();
EXPERIENCE_ORB = EntityDefinition.<ExpOrbEntity>inherited(null, entityBase) EXPERIENCE_ORB = EntityDefinition.inherited(ExpOrbEntity::new, entityBase)
.type(EntityType.EXPERIENCE_ORB) .type(EntityType.EXPERIENCE_ORB)
.identifier("minecraft:xp_orb") .identifier("minecraft:xp_orb")
.build(); .build();
@ -297,6 +297,7 @@ public final class EntityDefinitions {
TNT = EntityDefinition.inherited(TNTEntity::new, entityBase) TNT = EntityDefinition.inherited(TNTEntity::new, entityBase)
.type(EntityType.TNT) .type(EntityType.TNT)
.heightAndWidth(0.98f) .heightAndWidth(0.98f)
.offset(0.49f)
.addTranslator(MetadataType.INT, TNTEntity::setFuseLength) .addTranslator(MetadataType.INT, TNTEntity::setFuseLength)
.build(); .build();

Datei anzeigen

@ -60,6 +60,9 @@ import java.util.*;
@Getter @Getter
@Setter @Setter
public class Entity implements GeyserEntity { public class Entity implements GeyserEntity {
private static final boolean PRINT_ENTITY_SPAWN_DEBUG = Boolean.parseBoolean(System.getProperty("Geyser.PrintEntitySpawnDebug", "false"));
protected final GeyserSession session; protected final GeyserSession session;
protected int entityId; protected int entityId;
@ -182,7 +185,7 @@ public class Entity implements GeyserEntity {
flagsDirty = false; flagsDirty = false;
if (session.getGeyser().getConfig().isDebugMode()) { if (session.getGeyser().getConfig().isDebugMode() && PRINT_ENTITY_SPAWN_DEBUG) {
EntityType type = definition.entityType(); EntityType type = definition.entityType();
String name = type != null ? type.name() : getClass().getSimpleName(); String name = type != null ? type.name() : getClass().getSimpleName();
session.getGeyser().getLogger().debug("Spawned entity " + name + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")"); session.getGeyser().getLogger().debug("Spawned entity " + name + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");

Datei anzeigen

@ -27,11 +27,18 @@ package org.geysermc.geyser.entity.type;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID;
public class ExpOrbEntity extends Entity { public class ExpOrbEntity extends Entity {
public ExpOrbEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> entityDefinition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
this(session, 1, entityId, geyserId, position);
}
public ExpOrbEntity(GeyserSession session, int amount, int entityId, long geyserId, Vector3f position) { public ExpOrbEntity(GeyserSession session, int amount, int entityId, long geyserId, Vector3f position) {
super(session, entityId, geyserId, null, EntityDefinitions.EXPERIENCE_ORB, position, Vector3f.ZERO, 0, 0, 0); super(session, entityId, geyserId, null, EntityDefinitions.EXPERIENCE_ORB, position, Vector3f.ZERO, 0, 0, 0);

Datei anzeigen

@ -28,7 +28,9 @@ package org.geysermc.geyser.entity.type;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.block.type.FurnaceBlock; import org.geysermc.geyser.level.block.Blocks;
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.GeyserSession;
import org.geysermc.geyser.util.InteractionResult; 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.metadata.type.BooleanEntityMetadata;
@ -51,7 +53,8 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
@Override @Override
public void updateDefaultBlockMetadata() { public void updateDefaultBlockMetadata() {
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(FurnaceBlock.state(hasFuel))); BlockState furnace = Blocks.FURNACE.defaultBlockState().withValue(Properties.LIT, hasFuel);
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(furnace));
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6); dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
} }

Datei anzeigen

@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.block.type.SpawnerBlock; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID; import java.util.UUID;
@ -41,7 +41,7 @@ public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
@Override @Override
public void updateDefaultBlockMetadata() { public void updateDefaultBlockMetadata() {
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(SpawnerBlock.state())); dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(Blocks.SPAWNER.defaultBlockState()));
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6); dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
} }
} }

Datei anzeigen

@ -39,7 +39,17 @@ public class TNTEntity extends Entity implements Tickable {
private int currentTick; private int currentTick;
public TNTEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { public TNTEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); super(session, entityId, geyserId, uuid, definition, position.add(0, definition.offset(), 0), motion, yaw, pitch, headYaw);
}
@Override
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
super.moveRelative(relX, relY + definition.offset(), relZ, yaw, pitch, isOnGround);
}
@Override
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
super.moveAbsolute(position.add(Vector3f.from(0, definition.offset(), 0)), yaw, pitch, headYaw, isOnGround, teleported);
} }
public void setFuseLength(IntEntityMetadata entityMetadata) { public void setFuseLength(IntEntityMetadata entityMetadata) {

Datei anzeigen

@ -41,6 +41,7 @@ import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.*; import org.cloudburstmc.protocol.bedrock.packet.*;
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
@ -166,6 +167,31 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
session.sendUpstreamPacket(addPlayerPacket); session.sendUpstreamPacket(addPlayerPacket);
} }
@Override
public void despawnEntity() {
super.despawnEntity();
// Since we re-use player entities: Clear flags, held item, etc
this.resetMetadata();
this.hand = ItemData.AIR;
this.offhand = ItemData.AIR;
this.boots = ItemData.AIR;
this.leggings = ItemData.AIR;
this.chestplate = ItemData.AIR;
this.helmet = ItemData.AIR;
}
public void resetMetadata() {
// Reset all metadata to their default values
// This is used when a player respawns
this.flags.clear();
this.initializeMetadata();
// Explicitly reset all metadata not handled by initializeMetadata
setParrot(null, true);
setParrot(null, false);
}
public void sendPlayer() { public void sendPlayer() {
if (session.getEntityCache().getPlayerEntity(uuid) == null) if (session.getEntityCache().getPlayerEntity(uuid) == null)
return; return;

Datei anzeigen

@ -33,7 +33,6 @@ import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
@ -62,10 +61,6 @@ public class SessionPlayerEntity extends PlayerEntity {
*/ */
@Getter @Getter
protected final Map<GeyserAttributeType, AttributeData> attributes = new Object2ObjectOpenHashMap<>(); protected final Map<GeyserAttributeType, AttributeData> attributes = new Object2ObjectOpenHashMap<>();
/**
* Whether to check for updated speed after all entity metadata has been processed
*/
private boolean refreshSpeed = false;
/** /**
* Used in PlayerInputTranslator for movement checks. * Used in PlayerInputTranslator for movement checks.
*/ */
@ -134,9 +129,7 @@ public class SessionPlayerEntity extends PlayerEntity {
// TODO: proper fix, BDS somehow does it? https://paste.gg/p/anonymous/3adfb7612f1540be80fa03a2281f93dc (BDS 1.20.13) // TODO: proper fix, BDS somehow does it? https://paste.gg/p/anonymous/3adfb7612f1540be80fa03a2281f93dc (BDS 1.20.13)
if (!this.session.getGameMode().equals(GameMode.SPECTATOR)) { if (!this.session.getGameMode().equals(GameMode.SPECTATOR)) {
super.setFlags(entityMetadata); super.setFlags(entityMetadata);
session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING));
} }
refreshSpeed = true;
} }
/** /**
@ -164,7 +157,6 @@ public class SessionPlayerEntity extends PlayerEntity {
public void setPose(Pose pose) { public void setPose(Pose pose) {
super.setPose(pose); super.setPose(pose);
session.setPose(pose); session.setPose(pose);
refreshSpeed = true;
} }
public float getMaxHealth() { public float getMaxHealth() {
@ -213,21 +205,6 @@ public class SessionPlayerEntity extends PlayerEntity {
} }
} }
@Override
public void updateBedrockMetadata() {
super.updateBedrockMetadata();
if (refreshSpeed) {
AttributeData speedAttribute = session.adjustSpeed();
if (speedAttribute != null) {
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
attributesPacket.setRuntimeEntityId(geyserId);
attributesPacket.setAttributes(Collections.singletonList(speedAttribute));
session.sendUpstreamPacket(attributesPacket);
}
refreshSpeed = false;
}
}
@Override @Override
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) { protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) { if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) {
@ -240,17 +217,6 @@ public class SessionPlayerEntity extends PlayerEntity {
@Override @Override
protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) { protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) {
AttributeData attributeData = super.calculateAttribute(javaAttribute, type); AttributeData attributeData = super.calculateAttribute(javaAttribute, type);
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_MOVEMENT_SPEED) {
session.setOriginalSpeedAttribute(attributeData.getValue());
AttributeData speedAttribute = session.adjustSpeed();
if (speedAttribute != null) {
// Overwrite the attribute with our own
this.attributes.put(type, speedAttribute);
return speedAttribute;
}
}
this.attributes.put(type, attributeData); this.attributes.put(type, attributeData);
return attributeData; return attributeData;
} }
@ -278,19 +244,13 @@ public class SessionPlayerEntity extends PlayerEntity {
super.setAbsorptionHearts(entityMetadata); super.setAbsorptionHearts(entityMetadata);
} }
@Override
public void resetMetadata() { public void resetMetadata() {
// Reset all metadata to their default values super.resetMetadata();
// This is used when a player respawns
this.flags.clear();
this.initializeMetadata();
// Reset air // Reset air
this.resetAir(); this.resetAir();
// Explicitly reset all metadata not handled by initializeMetadata
setParrot(null, true);
setParrot(null, false);
// Absorption is metadata in java edition // Absorption is metadata in java edition
attributes.remove(GeyserAttributeType.ABSORPTION); attributes.remove(GeyserAttributeType.ABSORPTION);
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();

Datei anzeigen

@ -44,6 +44,7 @@ import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket;
import org.geysermc.erosion.packet.backendbound.BackendboundPacket; import org.geysermc.erosion.packet.backendbound.BackendboundPacket;
import org.geysermc.erosion.packet.geyserbound.*; import org.geysermc.erosion.packet.geyserbound.*;
import org.geysermc.geyser.level.block.BlockStateValues; 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.Block;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
@ -148,7 +149,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
@Override @Override
public void handlePistonEvent(GeyserboundPistonEventPacket packet) { public void handlePistonEvent(GeyserboundPistonEventPacket packet) {
Direction orientation = BlockStateValues.getPistonOrientation(packet.getBlockId()); Direction orientation = BlockState.of(packet.getBlockId()).getValue(Properties.FACING);
Vector3i position = packet.getPos(); Vector3i position = packet.getPos();
boolean isExtend = packet.isExtend(); boolean isExtend = packet.isExtend();

Datei anzeigen

@ -41,7 +41,6 @@ import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.InventoryUtils;
import java.util.Collections; import java.util.Collections;
@ -56,22 +55,24 @@ public class BlockInventoryHolder extends InventoryHolder {
/** /**
* The default Java block ID to translate as a fake block * The default Java block ID to translate as a fake block
*/ */
private final int defaultJavaBlockState; private final BlockState defaultJavaBlockState;
private final ContainerType containerType; private final ContainerType containerType;
private final Set<String> validBlocks; private final Set<Block> validBlocks;
public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, Block... validBlocks) { public BlockInventoryHolder(Block defaultJavaBlock, ContainerType containerType, Block... validBlocks) {
this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(javaBlockIdentifier); this(defaultJavaBlock.defaultBlockState(), containerType, validBlocks);
}
public BlockInventoryHolder(BlockState defaultJavaBlockState, ContainerType containerType, Block... validBlocks) {
this.defaultJavaBlockState = defaultJavaBlockState;
this.containerType = containerType; this.containerType = containerType;
if (validBlocks != null) { if (validBlocks != null) {
Set<String> validBlocksTemp = new HashSet<>(validBlocks.length + 1); Set<Block> validBlocksTemp = new HashSet<>(validBlocks.length + 1);
for (Block block : validBlocks) { Collections.addAll(validBlocksTemp, validBlocks);
validBlocksTemp.add(block.javaIdentifier().toString()); validBlocksTemp.add(defaultJavaBlockState.block());
}
validBlocksTemp.add(BlockUtils.getCleanIdentifier(javaBlockIdentifier));
this.validBlocks = Set.copyOf(validBlocksTemp); this.validBlocks = Set.copyOf(validBlocksTemp);
} else { } else {
this.validBlocks = Collections.singleton(BlockUtils.getCleanIdentifier(javaBlockIdentifier)); this.validBlocks = Collections.singleton(defaultJavaBlockState.block());
} }
} }
@ -85,9 +86,7 @@ public class BlockInventoryHolder extends InventoryHolder {
// and the bedrock block is vanilla // and the bedrock block is vanilla
BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition()); BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition());
if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) { if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) {
// TODO TODO TODO if (isValidBlock(state)) {
String[] javaBlockString = state.toString().split("\\[");
if (isValidBlock(javaBlockString)) {
// We can safely use this block // We can safely use this block
inventory.setHolderPosition(session.getLastInteractionBlockPosition()); inventory.setHolderPosition(session.getLastInteractionBlockPosition());
((Container) inventory).setUsingRealBlock(true, state.block()); ((Container) inventory).setUsingRealBlock(true, state.block());
@ -111,7 +110,7 @@ public class BlockInventoryHolder extends InventoryHolder {
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
inventory.setHolderPosition(position); inventory.setHolderPosition(position);
setCustomName(session, position, inventory, BlockState.of(defaultJavaBlockState)); setCustomName(session, position, inventory, defaultJavaBlockState);
return true; return true;
} }
@ -129,8 +128,8 @@ public class BlockInventoryHolder extends InventoryHolder {
/** /**
* @return true if this Java block ID can be used for player inventory. * @return true if this Java block ID can be used for player inventory.
*/ */
protected boolean isValidBlock(String[] javaBlockString) { protected boolean isValidBlock(BlockState blockState) {
return this.validBlocks.contains(javaBlockString[0]); return this.validBlocks.contains(blockState.block());
} }
protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) { protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) {

Datei anzeigen

@ -25,116 +25,19 @@
package org.geysermc.geyser.level.block; package org.geysermc.geyser.level.block;
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.property.Properties; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.block.type.PistonBlock; import org.geysermc.geyser.level.block.type.PistonBlock;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.level.physics.PistonBehavior;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import java.util.Locale;
/** /**
* Used for block entities if the Java block state contains Bedrock block information. * Used for block entities if the Java block state contains Bedrock block information.
*/ */
public final class BlockStateValues { public final class BlockStateValues {
private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet();
private static final IntSet STICKY_PISTONS = new IntOpenHashSet();
private static final Object2IntMap<Direction> PISTON_HEADS = new Object2IntOpenHashMap<>();
private static final Int2ObjectMap<Direction> PISTON_ORIENTATION = new Int2ObjectOpenHashMap<>();
private static final IntSet ALL_PISTON_HEADS = new IntOpenHashSet();
private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap();
private static final Int2IntMap LAVA_LEVEL = new Int2IntOpenHashMap();
public static int JAVA_WATER_ID;
public static final int NUM_FLUID_LEVELS = 9; public static final int NUM_FLUID_LEVELS = 9;
/**
* Determines if the block state contains Bedrock block information
*
* @param javaId The Java Identifier of the block
* @param javaBlockState the Java Block State of the block
*/
public static void storeBlockStateValues(String javaId, int javaBlockState) {
if (javaId.contains("piston[")) { // minecraft:moving_piston, minecraft:sticky_piston, minecraft:piston
if (javaId.contains("sticky")) {
STICKY_PISTONS.add(javaBlockState);
}
PISTON_ORIENTATION.put(javaBlockState, getBlockDirection(javaId));
return;
} else if (javaId.startsWith("minecraft:piston_head")) {
ALL_PISTON_HEADS.add(javaBlockState);
if (javaId.contains("short=false")) {
PISTON_HEADS.put(getBlockDirection(javaId), javaBlockState);
}
return;
}
if (javaId.startsWith("minecraft:water") && !javaId.contains("cauldron")) {
String strLevel = javaId.substring(javaId.lastIndexOf("level=") + 6, javaId.length() - 1);
int level = Integer.parseInt(strLevel);
WATER_LEVEL.put(javaBlockState, level);
return;
}
if (javaId.startsWith("minecraft:lava") && !javaId.contains("cauldron")) {
String strLevel = javaId.substring(javaId.lastIndexOf("level=") + 6, javaId.length() - 1);
int level = Integer.parseInt(strLevel);
LAVA_LEVEL.put(javaBlockState, level);
return;
}
if (javaId.startsWith("minecraft:jigsaw[orientation=")) {
String blockStateData = javaId.substring(javaId.indexOf("orientation=") + "orientation=".length(), javaId.lastIndexOf('_'));
Direction direction = Direction.valueOf(blockStateData.toUpperCase(Locale.ROOT));
if (direction.isHorizontal()) {
HORIZONTAL_FACING_JIGSAWS.add(javaBlockState);
}
}
}
/**
* @return a set of all forward-facing jigsaws, to use as a fallback if NBT is missing.
*/
public static IntSet getHorizontalFacingJigsaws() {
return HORIZONTAL_FACING_JIGSAWS;
}
public static boolean isStickyPiston(int blockState) {
return STICKY_PISTONS.contains(blockState);
}
public static boolean isPistonHead(int state) {
return ALL_PISTON_HEADS.contains(state);
}
/**
* Get the Java Block State for a piston head for a specific direction
* This is used in PistonBlockEntity to get the BlockCollision for the piston head.
*
* @param direction Direction the piston head points in
* @return Block state for the piston head
*/
public static int getPistonHead(Direction direction) {
return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID);
}
/**
* This is used in GeyserPistonEvents.java and accepts minecraft:piston,
* minecraft:sticky_piston, and minecraft:moving_piston.
*
* @param state The block state of the piston base
* @return The direction in which the piston faces
*/
public static Direction getPistonOrientation(int state) {
return PISTON_ORIENTATION.get(state);
}
/** /**
* Checks if a block sticks to other blocks * Checks if a block sticks to other blocks
* (Slime and honey blocks) * (Slime and honey blocks)
@ -203,11 +106,12 @@ public final class BlockStateValues {
* @return The type of fluid * @return The type of fluid
*/ */
public static Fluid getFluid(int state) { public static Fluid getFluid(int state) {
if (WATER_LEVEL.containsKey(state) || BlockRegistries.WATERLOGGED.get().get(state)) { BlockState blockState = BlockState.of(state);
if (blockState.is(Blocks.WATER) || BlockRegistries.WATERLOGGED.get().get(state)) {
return Fluid.WATER; return Fluid.WATER;
} }
if (LAVA_LEVEL.containsKey(state)) { if (blockState.is(Blocks.LAVA)) {
return Fluid.LAVA; return Fluid.LAVA;
} }
@ -221,7 +125,11 @@ public final class BlockStateValues {
* @return The water level or -1 if the block isn't water * @return The water level or -1 if the block isn't water
*/ */
public static int getWaterLevel(int state) { public static int getWaterLevel(int state) {
return WATER_LEVEL.getOrDefault(state, -1); BlockState blockState = BlockState.of(state);
if (!blockState.is(Blocks.WATER)) {
return -1;
}
return blockState.getValue(Properties.LEVEL);
} }
/** /**
@ -255,7 +163,11 @@ public final class BlockStateValues {
* @return The lava level or -1 if the block isn't lava * @return The lava level or -1 if the block isn't lava
*/ */
public static int getLavaLevel(int state) { public static int getLavaLevel(int state) {
return LAVA_LEVEL.getOrDefault(state, -1); BlockState blockState = BlockState.of(state);
if (!blockState.is(Blocks.LAVA)) {
return -1;
}
return blockState.getValue(Properties.LEVEL);
} }
/** /**
@ -298,23 +210,6 @@ public final class BlockStateValues {
return 0.6f; return 0.6f;
} }
private static Direction getBlockDirection(String javaId) {
if (javaId.contains("down")) {
return Direction.DOWN;
} else if (javaId.contains("up")) {
return Direction.UP;
} else if (javaId.contains("south")) {
return Direction.SOUTH;
} else if (javaId.contains("west")) {
return Direction.WEST;
} else if (javaId.contains("north")) {
return Direction.NORTH;
} else if (javaId.contains("east")) {
return Direction.EAST;
}
throw new IllegalStateException();
}
private BlockStateValues() { private BlockStateValues() {
} }
} }

Datei anzeigen

@ -0,0 +1,63 @@
/*
* 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 java.util.List;
/**
* Represents enums we don't need classes for in Geyser.
*/
public final class BasicEnumProperty extends Property<String> {
private final List<String> values;
private BasicEnumProperty(String name, List<String> values) {
super(name);
this.values = values;
}
@Override
public int valuesCount() {
return this.values.size();
}
@Override
public int indexOf(String value) {
int index = this.values.indexOf(value);
if (index == -1) {
throw new IllegalStateException("Property " + this + " does not have value " + value);
}
return index;
}
@SuppressWarnings("unchecked")
public <T> T values() {
return (T) this.values;
}
public static BasicEnumProperty create(String name, String... values) {
return new BasicEnumProperty(name, List.of(values));
}
}

Datei anzeigen

@ -0,0 +1,46 @@
/*
* 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 final class BooleanProperty extends Property<Boolean> {
private BooleanProperty(String name) {
super(name);
}
@Override
public int valuesCount() {
return 2;
}
@Override
public int indexOf(Boolean value) {
return value ? 0 : 1;
}
public static BooleanProperty create(String name) {
return new BooleanProperty(name);
}
}

Datei anzeigen

@ -0,0 +1,59 @@
/*
* 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 it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
public final class EnumProperty<T extends Enum<T>> extends Property<T> {
private final IntList ordinalValues;
/**
* @param values all possible values of this enum.
*/
private EnumProperty(String name, T[] values) {
super(name);
this.ordinalValues = new IntArrayList(values.length);
for (T anEnum : values) {
this.ordinalValues.add(anEnum.ordinal());
}
}
@Override
public int valuesCount() {
return this.ordinalValues.size();
}
@Override
public int indexOf(T value) {
return this.ordinalValues.indexOf(value.ordinal());
}
@SafeVarargs
public static <T extends Enum<T>> EnumProperty<T> create(String name, T... values) {
return new EnumProperty<>(name, values);
}
}

Datei anzeigen

@ -0,0 +1,55 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.level.block.property;
import org.geysermc.geyser.level.physics.Direction;
public enum FrontAndTop {
DOWN_EAST(Direction.DOWN),
DOWN_NORTH(Direction.DOWN),
DOWN_SOUTH(Direction.DOWN),
DOWN_WEST(Direction.DOWN),
UP_EAST(Direction.UP),
UP_NORTH(Direction.UP),
UP_SOUTH(Direction.UP),
UP_WEST(Direction.UP),
WEST_UP(Direction.WEST),
EAST_UP(Direction.EAST),
NORTH_UP(Direction.NORTH),
SOUTH_UP(Direction.SOUTH);
private final boolean horizontal;
FrontAndTop(Direction front) {
this.horizontal = front.isHorizontal();
}
public boolean isHorizontal() {
return horizontal;
}
public static final FrontAndTop[] VALUES = values();
}

Datei anzeigen

@ -0,0 +1,59 @@
/*
* 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 final class IntegerProperty extends Property<Integer> {
private final int offset;
private final int valuesCount;
private IntegerProperty(String name, int low, int high) {
super(name);
this.offset = low;
this.valuesCount = high - low;
}
@Override
public int valuesCount() {
return this.valuesCount;
}
@Override
public int indexOf(Integer value) {
return value - this.offset;
}
public int low() {
return this.offset;
}
public int high() {
return this.offset + this.valuesCount;
}
public static IntegerProperty create(String name, int low, int high) {
return new IntegerProperty(name, low, high);
}
}

Datei anzeigen

@ -29,118 +29,118 @@ import org.geysermc.geyser.level.physics.Axis;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
public final class Properties { public final class Properties {
public static final Property<Boolean> ATTACHED = Property.create("attached"); public static final BooleanProperty ATTACHED = BooleanProperty.create("attached");
public static final Property<Boolean> BOTTOM = Property.create("bottom"); public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom");
public static final Property<Boolean> CONDITIONAL = Property.create("conditional"); public static final BooleanProperty CONDITIONAL = BooleanProperty.create("conditional");
public static final Property<Boolean> DISARMED = Property.create("disarmed"); public static final BooleanProperty DISARMED = BooleanProperty.create("disarmed");
public static final Property<Boolean> DRAG = Property.create("drag"); public static final BooleanProperty DRAG = BooleanProperty.create("drag");
public static final Property<Boolean> ENABLED = Property.create("enabled"); public static final BooleanProperty ENABLED = BooleanProperty.create("enabled");
public static final Property<Boolean> EXTENDED = Property.create("extended"); public static final BooleanProperty EXTENDED = BooleanProperty.create("extended");
public static final Property<Boolean> EYE = Property.create("eye"); public static final BooleanProperty EYE = BooleanProperty.create("eye");
public static final Property<Boolean> FALLING = Property.create("falling"); public static final BooleanProperty FALLING = BooleanProperty.create("falling");
public static final Property<Boolean> HANGING = Property.create("hanging"); public static final BooleanProperty HANGING = BooleanProperty.create("hanging");
public static final Property<Boolean> HAS_BOTTLE_0 = Property.create("has_bottle_0"); public static final BooleanProperty HAS_BOTTLE_0 = BooleanProperty.create("has_bottle_0");
public static final Property<Boolean> HAS_BOTTLE_1 = Property.create("has_bottle_1"); public static final BooleanProperty HAS_BOTTLE_1 = BooleanProperty.create("has_bottle_1");
public static final Property<Boolean> HAS_BOTTLE_2 = Property.create("has_bottle_2"); public static final BooleanProperty HAS_BOTTLE_2 = BooleanProperty.create("has_bottle_2");
public static final Property<Boolean> HAS_RECORD = Property.create("has_record"); public static final BooleanProperty HAS_RECORD = BooleanProperty.create("has_record");
public static final Property<Boolean> HAS_BOOK = Property.create("has_book"); public static final BooleanProperty HAS_BOOK = BooleanProperty.create("has_book");
public static final Property<Boolean> INVERTED = Property.create("inverted"); public static final BooleanProperty INVERTED = BooleanProperty.create("inverted");
public static final Property<Boolean> IN_WALL = Property.create("in_wall"); public static final BooleanProperty IN_WALL = BooleanProperty.create("in_wall");
public static final Property<Boolean> LIT = Property.create("lit"); public static final BooleanProperty LIT = BooleanProperty.create("lit");
public static final Property<Boolean> LOCKED = Property.create("locked"); public static final BooleanProperty LOCKED = BooleanProperty.create("locked");
public static final Property<Boolean> OCCUPIED = Property.create("occupied"); public static final BooleanProperty OCCUPIED = BooleanProperty.create("occupied");
public static final Property<Boolean> OPEN = Property.create("open"); public static final BooleanProperty OPEN = BooleanProperty.create("open");
public static final Property<Boolean> PERSISTENT = Property.create("persistent"); public static final BooleanProperty PERSISTENT = BooleanProperty.create("persistent");
public static final Property<Boolean> POWERED = Property.create("powered"); public static final BooleanProperty POWERED = BooleanProperty.create("powered");
public static final Property<Boolean> SHORT = Property.create("short"); public static final BooleanProperty SHORT = BooleanProperty.create("short");
public static final Property<Boolean> SIGNAL_FIRE = Property.create("signal_fire"); public static final BooleanProperty SIGNAL_FIRE = BooleanProperty.create("signal_fire");
public static final Property<Boolean> SNOWY = Property.create("snowy"); public static final BooleanProperty SNOWY = BooleanProperty.create("snowy");
public static final Property<Boolean> TRIGGERED = Property.create("triggered"); public static final BooleanProperty TRIGGERED = BooleanProperty.create("triggered");
public static final Property<Boolean> UNSTABLE = Property.create("unstable"); public static final BooleanProperty UNSTABLE = BooleanProperty.create("unstable");
public static final Property<Boolean> WATERLOGGED = Property.create("waterlogged"); public static final BooleanProperty WATERLOGGED = BooleanProperty.create("waterlogged");
public static final Property<Boolean> BERRIES = Property.create("berries"); public static final BooleanProperty BERRIES = BooleanProperty.create("berries");
public static final Property<Boolean> BLOOM = Property.create("bloom"); public static final BooleanProperty BLOOM = BooleanProperty.create("bloom");
public static final Property<Boolean> SHRIEKING = Property.create("shrieking"); public static final BooleanProperty SHRIEKING = BooleanProperty.create("shrieking");
public static final Property<Boolean> CAN_SUMMON = Property.create("can_summon"); public static final BooleanProperty CAN_SUMMON = BooleanProperty.create("can_summon");
public static final Property<Axis> HORIZONTAL_AXIS = Property.create("axis"); public static final EnumProperty<Axis> HORIZONTAL_AXIS = EnumProperty.create("axis", Axis.X, Axis.Z);
public static final Property<Axis> AXIS = Property.create("axis"); public static final EnumProperty<Axis> AXIS = EnumProperty.create("axis", Axis.VALUES);
public static final Property<Boolean> UP = Property.create("up"); public static final BooleanProperty UP = BooleanProperty.create("up");
public static final Property<Boolean> DOWN = Property.create("down"); public static final BooleanProperty DOWN = BooleanProperty.create("down");
public static final Property<Boolean> NORTH = Property.create("north"); public static final BooleanProperty NORTH = BooleanProperty.create("north");
public static final Property<Boolean> EAST = Property.create("east"); public static final BooleanProperty EAST = BooleanProperty.create("east");
public static final Property<Boolean> SOUTH = Property.create("south"); public static final BooleanProperty SOUTH = BooleanProperty.create("south");
public static final Property<Boolean> WEST = Property.create("west"); public static final BooleanProperty WEST = BooleanProperty.create("west");
public static final Property<Direction> FACING = Property.create("facing"); public static final EnumProperty<Direction> FACING = EnumProperty.create("facing", Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN);
public static final Property<Direction> FACING_HOPPER = Property.create("facing"); public static final EnumProperty<Direction> FACING_HOPPER = EnumProperty.create("facing", Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST);
public static final Property<Direction> HORIZONTAL_FACING = Property.create("facing"); public static final EnumProperty<Direction> HORIZONTAL_FACING = EnumProperty.create("facing", Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST);
public static final Property<Integer> FLOWER_AMOUNT = Property.create("flower_amount"); public static final IntegerProperty FLOWER_AMOUNT = IntegerProperty.create("flower_amount", 1, 4);
public static final Property<String> ORIENTATION = Property.create("orientation"); public static final EnumProperty<FrontAndTop> ORIENTATION = EnumProperty.create("orientation", FrontAndTop.VALUES);
public static final Property<String> ATTACH_FACE = Property.create("face"); public static final BasicEnumProperty ATTACH_FACE = BasicEnumProperty.create("face", "floor", "wall", "ceiling");
public static final Property<String> BELL_ATTACHMENT = Property.create("attachment"); public static final BasicEnumProperty BELL_ATTACHMENT = BasicEnumProperty.create("attachment", "floor", "ceiling", "single_wall", "double_wall");
public static final Property<String> EAST_WALL = Property.create("east"); public static final BasicEnumProperty EAST_WALL = BasicEnumProperty.create("east", "none", "low", "tall");
public static final Property<String> NORTH_WALL = Property.create("north"); public static final BasicEnumProperty NORTH_WALL = BasicEnumProperty.create("north", "none", "low", "tall");
public static final Property<String> SOUTH_WALL = Property.create("south"); public static final BasicEnumProperty SOUTH_WALL = BasicEnumProperty.create("south", "none", "low", "tall");
public static final Property<String> WEST_WALL = Property.create("west"); public static final BasicEnumProperty WEST_WALL = BasicEnumProperty.create("west", "none", "low", "tall");
public static final Property<String> EAST_REDSTONE = Property.create("east"); public static final BasicEnumProperty EAST_REDSTONE = BasicEnumProperty.create("east", "up", "side", "none");
public static final Property<String> NORTH_REDSTONE = Property.create("north"); public static final BasicEnumProperty NORTH_REDSTONE = BasicEnumProperty.create("north", "up", "side", "none");
public static final Property<String> SOUTH_REDSTONE = Property.create("south"); public static final BasicEnumProperty SOUTH_REDSTONE = BasicEnumProperty.create("south", "up", "side", "none");
public static final Property<String> WEST_REDSTONE = Property.create("west"); public static final BasicEnumProperty WEST_REDSTONE = BasicEnumProperty.create("west", "up", "side", "none");
public static final Property<String> DOUBLE_BLOCK_HALF = Property.create("half"); public static final BasicEnumProperty DOUBLE_BLOCK_HALF = BasicEnumProperty.create("half", "upper", "lower");
public static final Property<String> HALF = Property.create("half"); public static final BasicEnumProperty HALF = BasicEnumProperty.create("half", "top", "bottom");
public static final Property<String> RAIL_SHAPE = Property.create("shape"); public static final BasicEnumProperty RAIL_SHAPE = BasicEnumProperty.create("shape", "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south", "south_east", "south_west", "north_west", "north_east");
public static final Property<String> RAIL_SHAPE_STRAIGHT = Property.create("shape"); public static final BasicEnumProperty RAIL_SHAPE_STRAIGHT = BasicEnumProperty.create("shape", "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south");
public static final Property<Integer> AGE_1 = Property.create("age"); public static final IntegerProperty AGE_1 = IntegerProperty.create("age", 0, 1);
public static final Property<Integer> AGE_2 = Property.create("age"); public static final IntegerProperty AGE_2 = IntegerProperty.create("age", 0, 2);
public static final Property<Integer> AGE_3 = Property.create("age"); public static final IntegerProperty AGE_3 = IntegerProperty.create("age", 0, 3);
public static final Property<Integer> AGE_4 = Property.create("age"); public static final IntegerProperty AGE_4 = IntegerProperty.create("age", 0, 4);
public static final Property<Integer> AGE_5 = Property.create("age"); public static final IntegerProperty AGE_5 = IntegerProperty.create("age", 0, 5);
public static final Property<Integer> AGE_7 = Property.create("age"); public static final IntegerProperty AGE_7 = IntegerProperty.create("age", 0, 7);
public static final Property<Integer> AGE_15 = Property.create("age"); public static final IntegerProperty AGE_15 = IntegerProperty.create("age", 0, 15);
public static final Property<Integer> AGE_25 = Property.create("age"); public static final IntegerProperty AGE_25 = IntegerProperty.create("age", 0, 25);
public static final Property<Integer> BITES = Property.create("bites"); public static final IntegerProperty BITES = IntegerProperty.create("bites", 0, 6);
public static final Property<Integer> CANDLES = Property.create("candles"); public static final IntegerProperty CANDLES = IntegerProperty.create("candles", 1, 4);
public static final Property<Integer> DELAY = Property.create("delay"); public static final IntegerProperty DELAY = IntegerProperty.create("delay", 1, 4);
public static final Property<Integer> DISTANCE = Property.create("distance"); public static final IntegerProperty DISTANCE = IntegerProperty.create("distance", 1, 7);
public static final Property<Integer> EGGS = Property.create("eggs"); public static final IntegerProperty EGGS = IntegerProperty.create("eggs", 1, 4);
public static final Property<Integer> HATCH = Property.create("hatch"); public static final IntegerProperty HATCH = IntegerProperty.create("hatch", 0, 2);
public static final Property<Integer> LAYERS = Property.create("layers"); public static final IntegerProperty LAYERS = IntegerProperty.create("layers", 1, 8);
public static final Property<Integer> LEVEL_CAULDRON = Property.create("level"); public static final IntegerProperty LEVEL_CAULDRON = IntegerProperty.create("level", 1, 3);
public static final Property<Integer> LEVEL_COMPOSTER = Property.create("level"); public static final IntegerProperty LEVEL_COMPOSTER = IntegerProperty.create("level", 0, 8);
public static final Property<Integer> LEVEL_FLOWING = Property.create("level"); public static final IntegerProperty LEVEL_FLOWING = IntegerProperty.create("level", 1, 8);
public static final Property<Integer> LEVEL_HONEY = Property.create("honey_level"); public static final IntegerProperty LEVEL_HONEY = IntegerProperty.create("honey_level", 0, 5);
public static final Property<Integer> LEVEL = Property.create("level"); public static final IntegerProperty LEVEL = IntegerProperty.create("level", 0, 15);
public static final Property<Integer> MOISTURE = Property.create("moisture"); public static final IntegerProperty MOISTURE = IntegerProperty.create("moisture", 0, 7);
public static final Property<Integer> NOTE = Property.create("note"); public static final IntegerProperty NOTE = IntegerProperty.create("note", 0, 24);
public static final Property<Integer> PICKLES = Property.create("pickles"); public static final IntegerProperty PICKLES = IntegerProperty.create("pickles", 1, 4);
public static final Property<Integer> POWER = Property.create("power"); public static final IntegerProperty POWER = IntegerProperty.create("power", 0, 15);
public static final Property<Integer> STAGE = Property.create("stage"); public static final IntegerProperty STAGE = IntegerProperty.create("stage", 0, 1);
public static final Property<Integer> STABILITY_DISTANCE = Property.create("distance"); public static final IntegerProperty STABILITY_DISTANCE = IntegerProperty.create("distance", 0, 7);
public static final Property<Integer> RESPAWN_ANCHOR_CHARGES = Property.create("charges"); public static final IntegerProperty RESPAWN_ANCHOR_CHARGES = IntegerProperty.create("charges", 0, 4);
public static final Property<Integer> ROTATION_16 = Property.create("rotation"); public static final IntegerProperty ROTATION_16 = IntegerProperty.create("rotation", 0, 15);
public static final Property<String> BED_PART = Property.create("part"); public static final BasicEnumProperty BED_PART = BasicEnumProperty.create("part", "head", "foot");
public static final Property<ChestType> CHEST_TYPE = Property.create("type"); public static final EnumProperty<ChestType> CHEST_TYPE = EnumProperty.create("type", ChestType.VALUES);
public static final Property<String> MODE_COMPARATOR = Property.create("mode"); public static final BasicEnumProperty MODE_COMPARATOR = BasicEnumProperty.create("mode", "compare", "subtract");
public static final Property<String> DOOR_HINGE = Property.create("hinge"); public static final BasicEnumProperty DOOR_HINGE = BasicEnumProperty.create("hinge", "left", "right");
public static final Property<String> NOTEBLOCK_INSTRUMENT = Property.create("instrument"); public static final BasicEnumProperty NOTEBLOCK_INSTRUMENT = BasicEnumProperty.create("instrument", "harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling", "zombie", "skeleton", "creeper", "dragon", "wither_skeleton", "piglin", "custom_head");
public static final Property<String> PISTON_TYPE = Property.create("type"); public static final BasicEnumProperty PISTON_TYPE = BasicEnumProperty.create("type", "normal", "sticky");
public static final Property<String> SLAB_TYPE = Property.create("type"); public static final BasicEnumProperty SLAB_TYPE = BasicEnumProperty.create("type", "top", "bottom", "double");
public static final Property<String> STAIRS_SHAPE = Property.create("shape"); public static final BasicEnumProperty STAIRS_SHAPE = BasicEnumProperty.create("shape", "straight", "inner_left", "inner_right", "outer_left", "outer_right");
public static final Property<String> STRUCTUREBLOCK_MODE = Property.create("mode"); public static final BasicEnumProperty STRUCTUREBLOCK_MODE = BasicEnumProperty.create("mode", "save", "load", "corner", "data");
public static final Property<String> BAMBOO_LEAVES = Property.create("leaves"); public static final BasicEnumProperty BAMBOO_LEAVES = BasicEnumProperty.create("leaves", "none", "small", "large");
public static final Property<String> TILT = Property.create("tilt"); public static final BasicEnumProperty TILT = BasicEnumProperty.create("tilt", "none", "unstable", "partial", "full");
public static final Property<Direction> VERTICAL_DIRECTION = Property.create("vertical_direction"); public static final EnumProperty<Direction> VERTICAL_DIRECTION = EnumProperty.create("vertical_direction", Direction.UP, Direction.DOWN);
public static final Property<String> DRIPSTONE_THICKNESS = Property.create("thickness"); public static final BasicEnumProperty DRIPSTONE_THICKNESS = BasicEnumProperty.create("thickness", "tip_merge", "tip", "frustum", "middle", "base");
public static final Property<String> SCULK_SENSOR_PHASE = Property.create("sculk_sensor_phase"); public static final BasicEnumProperty SCULK_SENSOR_PHASE = BasicEnumProperty.create("sculk_sensor_phase", "inactive", "active", "cooldown");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_0_OCCUPIED = Property.create("slot_0_occupied"); public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_0_OCCUPIED = BooleanProperty.create("slot_0_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_1_OCCUPIED = Property.create("slot_1_occupied"); public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_1_OCCUPIED = BooleanProperty.create("slot_1_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_2_OCCUPIED = Property.create("slot_2_occupied"); public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_2_OCCUPIED = BooleanProperty.create("slot_2_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_3_OCCUPIED = Property.create("slot_3_occupied"); public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_3_OCCUPIED = BooleanProperty.create("slot_3_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_4_OCCUPIED = Property.create("slot_4_occupied"); public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_4_OCCUPIED = BooleanProperty.create("slot_4_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_5_OCCUPIED = Property.create("slot_5_occupied"); public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_5_OCCUPIED = BooleanProperty.create("slot_5_occupied");
public static final Property<Integer> DUSTED = Property.create("dusted"); public static final IntegerProperty DUSTED = IntegerProperty.create("dusted", 0, 3);
public static final Property<Boolean> CRACKED = Property.create("cracked"); public static final BooleanProperty CRACKED = BooleanProperty.create("cracked");
public static final Property<Boolean> CRAFTING = Property.create("crafting"); public static final BooleanProperty CRAFTING = BooleanProperty.create("crafting");
public static final Property<String> TRIAL_SPAWNER_STATE = Property.create("trial_spawner_state"); public static final BasicEnumProperty TRIAL_SPAWNER_STATE = BasicEnumProperty.create("trial_spawner_state", "inactive", "waiting_for_players", "active", "waiting_for_reward_ejection", "ejecting_reward", "cooldown");
public static final Property<String> VAULT_STATE = Property.create("vault_state"); public static final BasicEnumProperty VAULT_STATE = BasicEnumProperty.create("vault_state", "inactive", "active", "unlocking", "ejecting");
public static final Property<Boolean> OMINOUS = Property.create("ominous"); public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous");
} }

Datei anzeigen

@ -25,10 +25,10 @@
package org.geysermc.geyser.level.block.property; package org.geysermc.geyser.level.block.property;
public class Property<T extends Comparable<T>> { public abstract class Property<T extends Comparable<T>> {
private final String name; private final String name;
public Property(String name) { protected Property(String name) {
this.name = name; this.name = name;
} }
@ -36,12 +36,12 @@ public class Property<T extends Comparable<T>> {
return name; return name;
} }
public abstract int valuesCount();
public abstract int indexOf(T value);
@Override @Override
public String toString() { public String toString() {
return getClass().getSimpleName() + "[" + name + "]"; return getClass().getSimpleName() + "[" + name + "]";
} }
public static <T extends Comparable<T>> Property<T> create(String name) {
return new Property<>(name);
}
} }

Datei anzeigen

@ -27,9 +27,6 @@ package org.geysermc.geyser.level.block.type;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; 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 net.kyori.adventure.key.Key;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
@ -37,6 +34,8 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.BasicEnumProperty;
import org.geysermc.geyser.level.block.property.IntegerProperty;
import org.geysermc.geyser.level.block.property.Property; import org.geysermc.geyser.level.block.property.Property;
import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.level.physics.PistonBehavior;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
@ -67,6 +66,12 @@ public class Block {
protected Item item = null; protected Item item = null;
private int javaId = -1; private int javaId = -1;
/**
* Used for switching a given block state to different states.
*/
private final Property<?>[] propertyKeys;
private final BlockState defaultState;
public Block(@Subst("empty") String javaIdentifier, Builder builder) { public Block(@Subst("empty") String javaIdentifier, Builder builder) {
this.javaIdentifier = Key.key(javaIdentifier); this.javaIdentifier = Key.key(javaIdentifier);
this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops; this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops;
@ -74,7 +79,10 @@ public class Block {
this.destroyTime = builder.destroyTime; this.destroyTime = builder.destroyTime;
this.pushReaction = builder.pushReaction; this.pushReaction = builder.pushReaction;
this.pickItem = builder.pickItem; this.pickItem = builder.pickItem;
processStates(builder.build(this));
BlockState firstState = builder.build(this).get(0);
this.propertyKeys = builder.propertyKeys; // Ensure this is not null before iterating over states
this.defaultState = setDefaultState(firstState);
} }
public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { public void updateBlock(GeyserSession session, BlockState state, Vector3i position) {
@ -167,9 +175,11 @@ public class Block {
} }
/** /**
* A list of BlockStates is created pertaining to this block. Do we need any of them? If so, override this method. * Should only be ran on block creation. Can be overridden.
* @param firstState the first state created from this block
*/ */
protected void processStates(List<BlockState> states) { protected BlockState setDefaultState(BlockState firstState) {
return firstState;
} }
@NonNull @NonNull
@ -194,6 +204,10 @@ public class Block {
return this.pushReaction; return this.pushReaction;
} }
public BlockState defaultBlockState() {
return this.defaultState;
}
public int javaId() { public int javaId() {
return javaId; return javaId;
} }
@ -213,6 +227,10 @@ public class Block {
'}'; '}';
} }
Property<?>[] propertyKeys() {
return propertyKeys;
}
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
} }
@ -225,11 +243,14 @@ public class Block {
private float destroyTime; private float destroyTime;
private Supplier<Item> pickItem; private Supplier<Item> pickItem;
// We'll use this field after building
private Property<?>[] propertyKeys;
/** /**
* For states that we're just tracking for mirroring Java states. * For states that we're just tracking for mirroring Java states.
*/ */
public Builder enumState(Property<String> property, String... values) { public Builder enumState(BasicEnumProperty property) {
states.put(property, List.of(values)); states.put(property, property.values());
return this; return this;
} }
@ -244,7 +265,9 @@ public class Block {
return this; return this;
} }
public Builder intState(Property<Integer> property, int low, int high) { public Builder intState(IntegerProperty property) {
int low = property.low();
int high = property.high();
IntList list = new IntArrayList(); IntList list = new IntArrayList();
// There is a state for every number between the low and high. // There is a state for every number between the low and high.
for (int i = low; i <= high; i++) { for (int i = low; i <= high; i++) {
@ -283,17 +306,18 @@ public class Block {
if (states.isEmpty()) { if (states.isEmpty()) {
BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size()); BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size());
BlockRegistries.BLOCK_STATES.get().add(state); BlockRegistries.BLOCK_STATES.get().add(state);
propertyKeys = null;
return List.of(state); return List.of(state);
} else if (states.size() == 1) { } else if (states.size() == 1) {
// We can optimize because we don't need to worry about combinations // We can optimize because we don't need to worry about combinations
Map.Entry<Property<?>, List<Comparable<?>>> property = this.states.entrySet().stream().findFirst().orElseThrow(); Map.Entry<Property<?>, List<Comparable<?>>> property = this.states.entrySet().stream().findFirst().orElseThrow();
List<BlockState> states = new ArrayList<>(property.getValue().size()); List<BlockState> states = new ArrayList<>(property.getValue().size());
property.getValue().forEach(value -> { property.getValue().forEach(value -> {
Reference2ObjectMap<Property<?>, Comparable<?>> propertyMap = Reference2ObjectMaps.singleton(property.getKey(), value); BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), new Comparable[] {value});
BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap);
BlockRegistries.BLOCK_STATES.get().add(state); BlockRegistries.BLOCK_STATES.get().add(state);
states.add(state); states.add(state);
}); });
this.propertyKeys = new Property[]{property.getKey()};
return states; return states;
} else { } else {
// Think of this stream as another list containing, at the start, one empty list. // Think of this stream as another list containing, at the start, one empty list.
@ -327,11 +351,11 @@ public class Block {
Property<?>[] keys = this.states.keySet().toArray(new Property<?>[0]); Property<?>[] keys = this.states.keySet().toArray(new Property<?>[0]);
result.forEach(properties -> { result.forEach(properties -> {
Comparable<?>[] values = properties.toArray(new Comparable<?>[0]); 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(), values);
BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap);
BlockRegistries.BLOCK_STATES.get().add(state); BlockRegistries.BLOCK_STATES.get().add(state);
states.add(state); states.add(state);
}); });
this.propertyKeys = keys;
return states; return states;
} }
} }

Datei anzeigen

@ -25,8 +25,7 @@
package org.geysermc.geyser.level.block.type; package org.geysermc.geyser.level.block.type;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; import org.checkerframework.checker.nullness.qual.Nullable;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps;
import org.geysermc.geyser.level.block.property.Property; import org.geysermc.geyser.level.block.property.Property;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
@ -35,13 +34,18 @@ import java.util.Locale;
public final class BlockState { public final class BlockState {
private final Block block; private final Block block;
private final int javaId; private final int javaId;
private final Reference2ObjectMap<Property<?>, Comparable<?>> states; /**
* The values of each property of this block state. These should be treated as keys to {@link Block#propertyKeys()}
* Of note - the comparable part probably doesn't do anything because we occasionally use strings in place of enums.
* Will be null if there's only one block state for a block.
*/
private final Comparable<?>[] states;
public BlockState(Block block, int javaId) { public BlockState(Block block, int javaId) {
this(block, javaId, Reference2ObjectMaps.emptyMap()); this(block, javaId, null);
} }
BlockState(Block block, int javaId, Reference2ObjectMap<Property<?>, Comparable<?>> states) { BlockState(Block block, int javaId, Comparable<?>[] states) {
this.block = block; this.block = block;
this.javaId = javaId; this.javaId = javaId;
this.states = states; this.states = states;
@ -49,23 +53,97 @@ public final class BlockState {
public <T extends Comparable<T>> T getValue(Property<T> property) { public <T extends Comparable<T>> T getValue(Property<T> property) {
//noinspection unchecked //noinspection unchecked
return (T) states.get(property); return (T) get(property);
} }
public boolean getValue(Property<Boolean> property, boolean def) { public boolean getValue(Property<Boolean> property, boolean def) {
var value = states.get(property); var value = get(property);
if (value == null) { if (value == null) {
return def; return def;
} }
return (Boolean) value; return (Boolean) value;
} }
@Nullable
private Comparable<?> get(Property<?> property) {
Property<?>[] keys = this.block.propertyKeys();
if (keys == null) {
return null;
}
// We're copying the behavior Reference2ObjectArrayMap uses
for (int i = keys.length; i-- != 0;) {
if (keys[i] == property) {
return this.states[i];
}
}
return null;
}
/**
* @return the {@link BlockState} instance with the given value.
*/
public <T extends Comparable<T>> BlockState withValue(Property<T> property, T value) {
Property<?>[] keys = this.block.propertyKeys();
if (keys == null) {
throw new IllegalStateException(this + " does not have any different states!");
}
T currentValue = getValue(property);
if (currentValue == null) {
throw new IllegalArgumentException("This BlockState does not have the property " + property);
}
if (currentValue.equals(value)) {
// No action required. This block state is the state we're looking for.
return this;
}
// Diff is how much we will have to traverse as a sort of offset
// Block states are calculated in a predictable structure:
// minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=none]
// minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=low]
// minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=tall]
// minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=false,west=none]
// minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=false,west=low]
// minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=false,west=tall]
// minecraft:cobblestone_wall[east=none,north=none,south=none,up=false,waterlogged=true,west=none]
// The last value goes through all its iterations, then the next state goes through all its iterations.
// West goes none -> low -> tall, then waterlogged is toggled as west cycles again.
// Then when waterlogged goes through all its properties, up is toggled, and west goes through again
// If we want to find the "up" property in order, then we need to find how many iterations each property
// after it goes in. West goes for 3, waterlogged goes for 2. Adding those together, we find that we need to
// add five to get to the next toggle of the up property
int diff = 0;
for (int i = keys.length - 1; i >= 0; i--) {
if (keys[i] != property) {
diff += keys[i].valuesCount();
} else {
break;
}
}
// How many times do we have to jump by diff? This depends on how far away each value is from each other.
// piston_head[facing=north] might be right next to piston_head[facing=south], which just one diff'd hop.
// But piston_head[facing=west] is further away, requiring more hops.
int thatOffset = property.indexOf(value);
int thisOffset = property.indexOf(currentValue);
if (diff == 0) {
// This can happen if the property is at the tail end of the block and there are no other properties to look through
// If we have minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=none]
// And want minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=low]
// The above for loop will always stop at the first break because the last property has already been found
diff = 1;
}
return BlockState.of(this.javaId + ((thatOffset - thisOffset) * diff));
}
public Block block() { public Block block() {
return block; return this.block;
} }
public int javaId() { public int javaId() {
return javaId; return this.javaId;
} }
public boolean is(Block block) { public boolean is(Block block) {
@ -74,7 +152,7 @@ public final class BlockState {
@Override @Override
public String toString() { public String toString() {
if (this.states.isEmpty()) { if (this.states == null) {
return this.block.javaIdentifier().toString(); return this.block.javaIdentifier().toString();
} }
return this.block.javaIdentifier().toString() + "[" + paramsToString() + "]"; return this.block.javaIdentifier().toString() + "[" + paramsToString() + "]";
@ -82,14 +160,15 @@ public final class BlockState {
private String paramsToString() { private String paramsToString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
var it = this.states.entrySet().iterator(); Property<?>[] propertyKeys = this.block.propertyKeys();
while (it.hasNext()) { if (propertyKeys != null) {
var entry = it.next(); for (int i = 0; i < propertyKeys.length; i++) {
builder.append(entry.getKey().name()) builder.append(propertyKeys[i].name())
.append("=") .append("=")
.append(entry.getValue().toString().toLowerCase(Locale.ROOT)); // lowercase covers enums .append(this.states[i].toString().toLowerCase(Locale.ROOT)); // lowercase covers enums
if (it.hasNext()) { if (i < propertyKeys.length - 1) {
builder.append(","); builder.append(",");
}
} }
} }
return builder.toString(); return builder.toString();

Datei anzeigen

@ -28,29 +28,14 @@ package org.geysermc.geyser.level.block.type;
import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
import java.util.List;
public class FurnaceBlock extends Block { public class FurnaceBlock extends Block {
private static BlockState LIT;
private static BlockState UNLIT;
public FurnaceBlock(String javaIdentifier, Builder builder) { public FurnaceBlock(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder); super(javaIdentifier, builder);
} }
@Override @Override
protected void processStates(List<BlockState> states) { protected BlockState setDefaultState(BlockState firstState) {
LIT = states.stream() // Both furnace minecart states look north.
.filter(state -> state.getValue(Properties.HORIZONTAL_FACING) == Direction.NORTH return firstState.withValue(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;
} }
} }

Datei anzeigen

@ -25,21 +25,8 @@
package org.geysermc.geyser.level.block.type; package org.geysermc.geyser.level.block.type;
import java.util.List;
public class HoneyBlock extends Block { public class HoneyBlock extends Block {
private static BlockState STATE;
public HoneyBlock(String javaIdentifier, Builder builder) { public HoneyBlock(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder); super(javaIdentifier, builder);
} }
@Override
protected void processStates(List<BlockState> states) {
STATE = states.get(0);
}
public static BlockState state() {
return STATE;
}
} }

Datei anzeigen

@ -25,21 +25,8 @@
package org.geysermc.geyser.level.block.type; package org.geysermc.geyser.level.block.type;
import java.util.List;
public class SpawnerBlock extends Block { public class SpawnerBlock extends Block {
private static BlockState STATE;
public SpawnerBlock(String javaIdentifier, Builder builder) { public SpawnerBlock(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder); super(javaIdentifier, builder);
} }
@Override
protected void processStates(List<BlockState> states) {
STATE = states.get(0);
}
public static BlockState state() {
return STATE;
}
} }

Datei anzeigen

@ -25,17 +25,8 @@
package org.geysermc.geyser.level.block.type; package org.geysermc.geyser.level.block.type;
import java.util.List;
public class WaterBlock extends Block { public class WaterBlock extends Block {
private static BlockState LEVEL_0;
public WaterBlock(String javaIdentifier, Builder builder) { public WaterBlock(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder); super(javaIdentifier, builder);
} }
@Override
protected void processStates(List<BlockState> states) {
super.processStates(states);
}
} }

Datei anzeigen

@ -39,6 +39,9 @@ import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.session.cache.PistonCache;
import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.translator.collision.BlockCollision;
@ -436,7 +439,8 @@ public class CollisionManager {
* @return if the player is currently in a water block * @return if the player is currently in a water block
*/ */
public boolean isPlayerInWater() { public boolean isPlayerInWater() {
return session.getGeyser().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockStateValues.JAVA_WATER_ID; BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getPlayerEntity().getPosition().toInt());
return state.is(Blocks.WATER) && state.getValue(Properties.LEVEL) == 0;
} }
public boolean isWaterInEyes() { public boolean isWaterInEyes() {

Datei anzeigen

@ -28,10 +28,13 @@ package org.geysermc.geyser.registry;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.registry.loader.RegistryLoader; import org.geysermc.geyser.registry.loader.RegistryLoader;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ListRegistry<M> extends Registry<List<M>> { public class ListRegistry<M> extends Registry<List<M>> {
private boolean frozen = false;
/** /**
* Creates a new instance of this class with the given input and * Creates a new instance of this class with the given input and
* {@link RegistryLoader}. The input specified is what the registry * {@link RegistryLoader}. The input specified is what the registry
@ -85,9 +88,24 @@ public class ListRegistry<M> extends Registry<List<M>> {
* @return a new value into this registry with the given index. * @return a new value into this registry with the given index.
*/ */
public M register(int index, M value) { public M register(int index, M value) {
if (this.frozen) {
throw new IllegalStateException("Registry should not be modified after frozen!");
}
return this.mappings.set(index, value); return this.mappings.set(index, value);
} }
/**
* Mark this registry as unsuitable for new additions. The backing list will then be optimized for storage.
*/
public void freeze() {
if (!this.frozen) {
this.frozen = true;
if (this.mappings instanceof ArrayList<M> arrayList) {
arrayList.trimToSize();
}
}
}
/** /**
* Creates a new array registry with the given {@link RegistryLoader}. The * Creates a new array registry with the given {@link RegistryLoader}. The
* input type is not specified here, meaning the loader return type is either * input type is not specified here, meaning the loader return type is either

Datei anzeigen

@ -77,7 +77,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
} }
List<BlockState> blockStates = BlockRegistries.BLOCK_STATES.get(); List<BlockState> blockStates = BlockRegistries.BLOCK_STATES.get();
List<BlockCollision> collisions = new ObjectArrayList<>(blockStates.size()); var collisions = new ObjectArrayList<BlockCollision>(blockStates.size());
// Map of unique collisions to its instance // Map of unique collisions to its instance
Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>(); Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>();
@ -102,6 +102,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
collisions.add(newCollision); collisions.add(newCollision);
} }
collisions.trim();
return collisions; return collisions;
} }

Datei anzeigen

@ -50,7 +50,6 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.Block;
@ -433,32 +432,13 @@ public final class BlockRegistryPopulator {
} }
int javaRuntimeId = -1; int javaRuntimeId = -1;
int waterRuntimeId = -1;
for (BlockState javaBlockState : BlockRegistries.BLOCK_STATES.get()) { for (BlockState javaBlockState : BlockRegistries.BLOCK_STATES.get()) {
javaRuntimeId++; javaRuntimeId++;
String javaId = javaBlockState.toString().intern(); String javaId = javaBlockState.toString().intern();
BlockStateValues.storeBlockStateValues(javaId, javaRuntimeId);
//String cleanJavaIdentifier = javaBlockState.block().javaIdentifier().toString();
//String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId); BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId);
// Keeping this here since this is currently unchanged between versions
// It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions
//BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern());
if ("minecraft:water[level=0]".equals(javaId)) {
waterRuntimeId = javaRuntimeId;
}
} }
if (waterRuntimeId == -1) {
throw new AssertionError("Unable to find Java water in palette");
}
BlockStateValues.JAVA_WATER_ID = waterRuntimeId;
if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) { if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) {
IntSet usedNonVanillaRuntimeIDs = new IntOpenHashSet(); IntSet usedNonVanillaRuntimeIDs = new IntOpenHashSet();
@ -467,8 +447,6 @@ public final class BlockRegistryPopulator {
throw new RuntimeException("Duplicate runtime ID " + javaBlockState.javaId() + " for non vanilla Java block state " + javaBlockState.identifier()); throw new RuntimeException("Duplicate runtime ID " + javaBlockState.javaId() + " for non vanilla Java block state " + javaBlockState.identifier());
} }
CustomBlockState customBlockState = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().get(javaBlockState);
String javaId = javaBlockState.identifier(); String javaId = javaBlockState.identifier();
int stateRuntimeId = javaBlockState.javaId(); int stateRuntimeId = javaBlockState.javaId();
String pistonBehavior = javaBlockState.pistonBehavior(); String pistonBehavior = javaBlockState.pistonBehavior();
@ -517,6 +495,8 @@ public final class BlockRegistryPopulator {
BlockRegistries.INTERACTIVE.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("always_consumes"))); BlockRegistries.INTERACTIVE.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("always_consumes")));
BlockRegistries.INTERACTIVE_MAY_BUILD.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("requires_may_build"))); BlockRegistries.INTERACTIVE_MAY_BUILD.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("requires_may_build")));
BlockRegistries.BLOCK_STATES.freeze();
} }
private static BitSet toBlockStateSet(ArrayNode node) { private static BitSet toBlockStateSet(ArrayNode node) {

Datei anzeigen

@ -90,6 +90,10 @@ public class BlockMappings implements DefinitionRegistry<GeyserBedrockBlock> {
return this.getBedrockBlock(javaState.javaId()); return this.getBedrockBlock(javaState.javaId());
} }
public GeyserBedrockBlock getVanillaBedrockBlock(BlockState javaState) {
return getVanillaBedrockBlock(javaState.javaId());
}
public GeyserBedrockBlock getVanillaBedrockBlock(int javaState) { public GeyserBedrockBlock getVanillaBedrockBlock(int javaState) {
if (javaState < 0 || javaState >= this.javaToVanillaBedrockBlocks.length) { if (javaState < 0 || javaState >= this.javaToVanillaBedrockBlocks.length) {
return bedrockAir; return bedrockAir;

Datei anzeigen

@ -318,22 +318,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
@Setter @Setter
private boolean sprinting; private boolean sprinting;
/**
* Whether the player is swimming in water.
* Used to update speed when crawling.
*/
@Setter
private boolean swimmingInWater;
/**
* Tracks the original speed attribute.
* <p>
* We need to do this in order to emulate speeds when sneaking under 1.5-blocks-tall areas if the player isn't sneaking,
* and when crawling.
*/
@Setter
private float originalSpeedAttribute;
/** /**
* The dimension of the player. * The dimension of the player.
* As all entities are in the same world, this can be safely applied to all other entities. * As all entities are in the same world, this can be safely applied to all other entities.
@ -913,6 +897,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
this.downstream.getSession().setFlag(BuiltinFlags.ATTEMPT_SRV_RESOLVE, resolveSrv); this.downstream.getSession().setFlag(BuiltinFlags.ATTEMPT_SRV_RESOLVE, resolveSrv);
} }
// Disable automatic creation of a new TcpClientSession when transferring - we don't use that functionality.
this.downstream.getSession().setFlag(MinecraftConstants.FOLLOW_TRANSFERS, false);
if (geyser.getConfig().getRemote().isUseProxyProtocol()) { if (geyser.getConfig().getRemote().isUseProxyProtocol()) {
downstream.setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true); downstream.setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true);
downstream.setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress()); downstream.setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress());
@ -1304,21 +1291,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
this.sneaking = sneaking; this.sneaking = sneaking;
// Update pose and bounding box on our end // Update pose and bounding box on our end
AttributeData speedAttribute; if (!flying) {
if (!sneaking && (speedAttribute = adjustSpeed()) != null) { // The pose and bounding box should not be updated if the player is flying
// Update attributes since we're still "sneaking" under a 1.5-block-tall area setSneakingPose(sneaking);
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
attributesPacket.setRuntimeEntityId(playerEntity.getGeyserId());
attributesPacket.setAttributes(Collections.singletonList(speedAttribute));
sendUpstreamPacket(attributesPacket);
// the server *should* update our pose once it has returned to normal
} else {
if (!flying) {
// The pose and bounding box should not be updated if the player is flying
setSneakingPose(sneaking);
}
collisionManager.updateScaffoldingFlags(false);
} }
collisionManager.updateScaffoldingFlags(false);
playerEntity.updateBedrockMetadata(); playerEntity.updateBedrockMetadata();
@ -1361,30 +1338,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
} }
} }
/**
* Adjusts speed if the player is crawling.
*
* @return not null if attributes should be updated.
*/
public @Nullable AttributeData adjustSpeed() {
AttributeData currentPlayerSpeed = playerEntity.getAttributes().get(GeyserAttributeType.MOVEMENT_SPEED);
if (currentPlayerSpeed != null) {
if ((pose.equals(Pose.SNEAKING) && !sneaking && collisionManager.mustPlayerSneakHere()) ||
(!swimmingInWater && playerEntity.getFlag(EntityFlag.SWIMMING) && !collisionManager.isPlayerInWater())) {
// Either of those conditions means that Bedrock goes zoom when they shouldn't be
AttributeData speedAttribute = GeyserAttributeType.MOVEMENT_SPEED.getAttribute(originalSpeedAttribute / 3.32f);
playerEntity.getAttributes().put(GeyserAttributeType.MOVEMENT_SPEED, speedAttribute);
return speedAttribute;
} else if (originalSpeedAttribute != currentPlayerSpeed.getValue()) {
// Speed has reset to normal
AttributeData speedAttribute = GeyserAttributeType.MOVEMENT_SPEED.getAttribute(originalSpeedAttribute);
playerEntity.getAttributes().put(GeyserAttributeType.MOVEMENT_SPEED, speedAttribute);
return speedAttribute;
}
}
return null;
}
/** /**
* Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display * Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display
* blocking and sends a packet to the Java server. * blocking and sends a packet to the Java server.

Datei anzeigen

@ -91,15 +91,11 @@ public class AdvancementsCache {
builder.validResultHandler((response) -> { builder.validResultHandler((response) -> {
String id = rootAdvancementIds.get(response.clickedButtonId()); String id = rootAdvancementIds.get(response.clickedButtonId());
if (!id.equals("")) { if (!id.equals("")) {
if (id.equals(currentAdvancementCategoryId)) { // Send a packet indicating that we are opening this particular advancement window
// The server thinks we are already on this tab ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id);
buildAndShowListForm(); session.sendDownstreamGamePacket(packet);
} else { currentAdvancementCategoryId = id;
// Send a packet indicating that we intend to open this particular advancement window buildAndShowListForm();
ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id);
session.sendDownstreamGamePacket(packet);
// Wait for a response there
}
} }
}); });
@ -190,6 +186,10 @@ public class AdvancementsCache {
.content(content) .content(content)
.button(GeyserLocale.getPlayerLocaleString("gui.back", language)) .button(GeyserLocale.getPlayerLocaleString("gui.back", language))
.validResultHandler((response) -> buildAndShowListForm()) .validResultHandler((response) -> buildAndShowListForm())
.closedResultHandler(() -> {
// Indicate that we have closed the current advancement tab
session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket());
})
); );
} }

Datei anzeigen

@ -28,7 +28,6 @@ package org.geysermc.geyser.session.cache;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.LodestoneTracker; import org.geysermc.mcprotocollib.protocol.data.game.item.component.LodestoneTracker;
@ -53,11 +52,13 @@ public final class LodestoneCache {
private int id = 1; private int id = 1;
public void cacheInventoryItem(GeyserItemStack itemStack, LodestoneTracker tracker) { public void cacheInventoryItem(GeyserItemStack itemStack, LodestoneTracker tracker) {
GlobalPos position = tracker.getPos(); if (!tracker.isTracked()) {
return;
}
GlobalPos position = tracker.getPos();
if (position == null) { if (position == null) {
GeyserImpl.getInstance().getLogger().error("Position is null. Find out why."); // As of 1.20.6, position can still be null even if tracking is enabled.
Thread.dumpStack();
return; return;
} }
int x = position.getX(); int x = position.getX();
@ -84,13 +85,16 @@ public final class LodestoneCache {
} }
public int store(LodestoneTracker tracker) { public int store(LodestoneTracker tracker) {
GlobalPos position = tracker.getPos(); if (!tracker.isTracked()) {
// No coordinates; nothing to convert
if (position == null) { return 0;
GeyserImpl.getInstance().getLogger().error("Position is null. Find out why.");
Thread.dumpStack();
return -1;
} }
GlobalPos position = tracker.getPos();
if (position == null) {
return 0;
}
int x = position.getX(); int x = position.getX();
int y = position.getY(); int y = position.getY();
int z = position.getZ(); int z = position.getZ();

Datei anzeigen

@ -63,6 +63,13 @@ public class MinecraftTranslationRegistry extends TranslatableComponentRenderer<
} }
} }
// replace single quote instances which get lost in MessageFormat otherwise
localeString = localeString.replace("'", "''");
// Wrap all curly brackets with single quote inserts - fixes https://github.com/GeyserMC/Geyser/issues/4662
localeString = localeString.replace("{", "'{")
.replace("}", "'}");
// Replace the `%s` with numbered inserts `{0}` // Replace the `%s` with numbered inserts `{0}`
Pattern p = stringReplacement; Pattern p = stringReplacement;
Matcher m = p.matcher(localeString); Matcher m = p.matcher(localeString);
@ -83,8 +90,7 @@ public class MinecraftTranslationRegistry extends TranslatableComponentRenderer<
} }
m.appendTail(sb); m.appendTail(sb);
// replace single quote instances which get lost in MessageFormat otherwise
// Locale shouldn't need to be specific - dates for example will not be handled // Locale shouldn't need to be specific - dates for example will not be handled
return new MessageFormat(sb.toString().replace("'", "''"), Locale.ROOT); return new MessageFormat(sb.toString(), Locale.ROOT);
} }
} }

Datei anzeigen

@ -31,6 +31,7 @@ import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
import org.geysermc.geyser.inventory.holder.InventoryHolder; import org.geysermc.geyser.inventory.holder.InventoryHolder;
import org.geysermc.geyser.inventory.updater.InventoryUpdater; import org.geysermc.geyser.inventory.updater.InventoryUpdater;
import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
/** /**
@ -40,17 +41,25 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran
private final InventoryHolder holder; private final InventoryHolder holder;
private final InventoryUpdater updater; private final InventoryUpdater updater;
/**
* @param javaBlock a Java block that is used as a temporary block
*/
public AbstractBlockInventoryTranslator(int size, Block javaBlock, ContainerType containerType, InventoryUpdater updater,
Block... additionalValidBlocks) {
this(size, javaBlock.defaultBlockState(), containerType, updater, additionalValidBlocks);
}
/** /**
* @param size the amount of slots that the inventory adds alongside the base inventory slots * @param size the amount of slots that the inventory adds alongside the base inventory slots
* @param javaBlockIdentifier a Java block identifier that is used as a temporary block * @param javaBlockState a Java block state that is used as a temporary block
* @param containerType the container type of this inventory * @param containerType the container type of this inventory
* @param updater updater * @param updater updater
* @param additionalValidBlocks any other blocks 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, public AbstractBlockInventoryTranslator(int size, BlockState javaBlockState, ContainerType containerType, InventoryUpdater updater,
Block... additionalValidBlocks) { Block... additionalValidBlocks) {
super(size); super(size);
this.holder = new BlockInventoryHolder(javaBlockIdentifier, containerType, additionalValidBlocks); this.holder = new BlockInventoryHolder(javaBlockState, containerType, additionalValidBlocks);
this.updater = updater; this.updater = updater;
} }

Datei anzeigen

@ -45,7 +45,7 @@ import java.util.Objects;
public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
public AnvilInventoryTranslator() { public AnvilInventoryTranslator() {
super(3, "minecraft:anvil[facing=north]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE, super(3, Blocks.ANVIL, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE,
Blocks.CHIPPED_ANVIL, Blocks.DAMAGED_ANVIL); Blocks.CHIPPED_ANVIL, Blocks.DAMAGED_ANVIL);
} }

Datei anzeigen

@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.inventory;
import it.unimi.dsi.fastutil.ints.IntSets; import it.unimi.dsi.fastutil.ints.IntSets;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
@ -43,7 +42,9 @@ import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.InventoryUtils;
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetBeaconPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetBeaconPacket;
@ -52,7 +53,7 @@ import java.util.OptionalInt;
public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator { public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator {
public BeaconInventoryTranslator() { public BeaconInventoryTranslator() {
super(1, new BlockInventoryHolder("minecraft:beacon", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.BEACON) { super(1, new BlockInventoryHolder(Blocks.BEACON, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.BEACON) {
@Override @Override
protected boolean checkInteractionPosition(GeyserSession session) { protected boolean checkInteractionPosition(GeyserSession session) {
// Since we can't fall back to a virtual inventory, let's make opening one easier // Since we can't fall back to a virtual inventory, let's make opening one easier
@ -89,12 +90,8 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
// Send a block entity data packet update to the fake beacon inventory // Send a block entity data packet update to the fake beacon inventory
Vector3i position = inventory.getHolderPosition(); Vector3i position = inventory.getHolderPosition();
NbtMapBuilder builder = NbtMap.builder() NbtMapBuilder builder = BlockEntityTranslator.getConstantBedrockTag("Beacon", position)
.putInt("x", position.getX())
.putInt("y", position.getY())
.putInt("z", position.getZ())
.putString("CustomName", inventory.getTitle()) .putString("CustomName", inventory.getTitle())
.putString("id", "Beacon")
.putInt("primary", beaconContainer.getPrimaryId()) .putInt("primary", beaconContainer.getPrimaryId())
.putInt("secondary", beaconContainer.getSecondaryId()); .putInt("secondary", beaconContainer.getSecondaryId());

Datei anzeigen

@ -32,11 +32,16 @@ import org.cloudburstmc.protocol.bedrock.packet.ContainerSetDataPacket;
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator { public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator {
public BrewingInventoryTranslator() { public BrewingInventoryTranslator() {
super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND, ContainerInventoryUpdater.INSTANCE); super(5, Blocks.BREWING_STAND.defaultBlockState()
.withValue(Properties.HAS_BOTTLE_0, false)
.withValue(Properties.HAS_BOTTLE_1, false)
.withValue(Properties.HAS_BOTTLE_2, false), ContainerType.BREWING_STAND, ContainerInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -30,12 +30,13 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemSt
import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
public class CartographyInventoryTranslator extends AbstractBlockInventoryTranslator { public class CartographyInventoryTranslator extends AbstractBlockInventoryTranslator {
public CartographyInventoryTranslator() { public CartographyInventoryTranslator() {
super(3, "minecraft:cartography_table", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CARTOGRAPHY, UIInventoryUpdater.INSTANCE); super(3, Blocks.CARTOGRAPHY_TABLE, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CARTOGRAPHY, UIInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -31,6 +31,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.updater.CrafterInventoryUpdater; import org.geysermc.geyser.inventory.updater.CrafterInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
@ -53,7 +54,7 @@ public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator
private static final int TRIGGERED = 1; // triggered value private static final int TRIGGERED = 1; // triggered value
public CrafterInventoryTranslator() { public CrafterInventoryTranslator() {
super(10, "minecraft:crafter", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CRAFTER, CrafterInventoryUpdater.INSTANCE); super(10, Blocks.CRAFTER, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CRAFTER, CrafterInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -31,10 +31,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemSt
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslator { public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslator {
public CraftingInventoryTranslator() { public CraftingInventoryTranslator() {
super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, UIInventoryUpdater.INSTANCE); super(10, Blocks.CRAFTING_TABLE, ContainerType.WORKBENCH, UIInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -38,6 +38,7 @@ import org.cloudburstmc.protocol.bedrock.packet.PlayerEnchantOptionsPacket;
import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.inventory.item.Enchantment;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket;
@ -47,7 +48,7 @@ import java.util.Locale;
public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator { public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator {
public EnchantingInventoryTranslator() { public EnchantingInventoryTranslator() {
super(2, "minecraft:enchanting_table", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ENCHANTMENT, UIInventoryUpdater.INSTANCE); super(2, Blocks.ENCHANTING_TABLE, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ENCHANTMENT, UIInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -41,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
*/ */
public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator { public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator {
public Generic3X3InventoryTranslator() { public Generic3X3InventoryTranslator() {
super(9, "minecraft:dispenser[facing=north,triggered=false]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE, super(9, Blocks.DISPENSER, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE,
Blocks.DROPPER); Blocks.DROPPER);
} }

Datei anzeigen

@ -30,10 +30,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTranslator { public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTranslator {
public GrindstoneInventoryTranslator() { public GrindstoneInventoryTranslator() {
super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, UIInventoryUpdater.INSTANCE); super(3, Blocks.GRINDSTONE, ContainerType.GRINDSTONE, UIInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -29,13 +29,14 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
/** /**
* Implemented on top of any block that does not have special properties implemented * Implemented on top of any block that does not have special properties implemented
*/ */
public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator { public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator {
public HopperInventoryTranslator() { public HopperInventoryTranslator() {
super(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, ContainerInventoryUpdater.INSTANCE); super(5, Blocks.HOPPER, ContainerType.HOPPER, ContainerInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -34,6 +34,7 @@ import org.geysermc.erosion.util.LecternUtils;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
@ -56,7 +57,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator
private boolean initialized = false; private boolean initialized = false;
public LecternInventoryTranslator() { public LecternInventoryTranslator() {
super(1, "minecraft:lectern[facing=north,has_book=true,powered=true]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.LECTERN , ContainerInventoryUpdater.INSTANCE); super(1, Blocks.LECTERN, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.LECTERN , ContainerInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -45,6 +45,7 @@ import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.item.type.BannerItem; import org.geysermc.geyser.item.type.BannerItem;
import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.item.type.DyeItem;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
@ -101,7 +102,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
} }
public LoomInventoryTranslator() { public LoomInventoryTranslator() {
super(4, "minecraft:loom[facing=north]", ContainerType.LOOM, UIInventoryUpdater.INSTANCE); super(4, Blocks.LOOM, ContainerType.LOOM, UIInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -37,6 +37,7 @@ import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.InventoryUtils;
@ -53,7 +54,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator
private static final IntFunction<ItemData> UPGRADE_TEMPLATE = InventoryUtils.getUpgradeTemplate(); private static final IntFunction<ItemData> UPGRADE_TEMPLATE = InventoryUtils.getUpgradeTemplate();
private OldSmithingTableTranslator() { private OldSmithingTableTranslator() {
super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); super(3, Blocks.SMITHING_TABLE, ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -35,7 +35,10 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
@ -43,12 +46,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator { public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator {
public ShulkerInventoryTranslator() { public ShulkerInventoryTranslator() {
super(27, new BlockInventoryHolder("minecraft:shulker_box[facing=north]", ContainerType.CONTAINER) { // Ensure that the shulker box default state won't be trying to open in a state facing the player
super(27, new BlockInventoryHolder(Blocks.SHULKER_BOX.defaultBlockState().withValue(Properties.FACING, Direction.NORTH), ContainerType.CONTAINER) {
private final BlockEntityTranslator shulkerBoxTranslator = Registries.BLOCK_ENTITIES.get(BlockEntityType.SHULKER_BOX); private final BlockEntityTranslator shulkerBoxTranslator = Registries.BLOCK_ENTITIES.get(BlockEntityType.SHULKER_BOX);
@Override @Override
protected boolean isValidBlock(String[] javaBlockString) { protected boolean isValidBlock(BlockState blockState) {
return javaBlockString[0].contains("shulker_box"); return blockState.block().javaIdentifier().value().contains("shulker_box"); // TODO ew
} }
@Override @Override

Datei anzeigen

@ -30,10 +30,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator { public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator {
public SmithingInventoryTranslator() { public SmithingInventoryTranslator() {
super(4, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); super(4, Blocks.SMITHING_TABLE, ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemS
import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
@ -42,7 +43,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S
public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator { public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator {
public StonecutterInventoryTranslator() { public StonecutterInventoryTranslator() {
super(2, "minecraft:stonecutter[facing=north]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.STONECUTTER, UIInventoryUpdater.INSTANCE); super(2, Blocks.STONECUTTER, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.STONECUTTER, UIInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -40,6 +40,7 @@ import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.ChestType; import org.geysermc.geyser.level.block.property.ChestType;
import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
@ -51,7 +52,10 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
public DoubleChestInventoryTranslator(int size) { public DoubleChestInventoryTranslator(int size) {
super(size, 54); super(size, 54);
this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt("minecraft:chest[facing=north,type=single,waterlogged=false]"); this.defaultJavaBlockState = Blocks.CHEST.defaultBlockState()
.withValue(Properties.HORIZONTAL_FACING, Direction.NORTH)
.withValue(Properties.CHEST_TYPE, ChestType.SINGLE)
.javaId();
} }
@Override @Override
@ -96,11 +100,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
session.sendUpstreamPacket(blockPacket); session.sendUpstreamPacket(blockPacket);
NbtMap tag = NbtMap.builder() NbtMap tag = BlockEntityTranslator.getConstantBedrockTag("Chest", position)
.putString("id", "Chest")
.putInt("x", position.getX())
.putInt("y", position.getY())
.putInt("z", position.getZ())
.putInt("pairx", pairPosition.getX()) .putInt("pairx", pairPosition.getX())
.putInt("pairz", pairPosition.getZ()) .putInt("pairz", pairPosition.getZ())
.putString("CustomName", inventory.getTitle()).build(); .putString("CustomName", inventory.getTitle()).build();

Datei anzeigen

@ -30,6 +30,9 @@ import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
import org.geysermc.geyser.inventory.holder.InventoryHolder; import org.geysermc.geyser.inventory.holder.InventoryHolder;
import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.ChestType;
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.GeyserSession;
public class SingleChestInventoryTranslator extends ChestInventoryTranslator { public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
@ -38,17 +41,17 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
// TODO add barrel??? // TODO add barrel???
public SingleChestInventoryTranslator(int size) { public SingleChestInventoryTranslator(int size) {
super(size, 27); super(size, 27);
this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, this.holder = new BlockInventoryHolder(Blocks.CHEST.defaultBlockState().withValue(Properties.CHEST_TYPE, ChestType.SINGLE), ContainerType.CONTAINER,
Blocks.ENDER_CHEST, Blocks.TRAPPED_CHEST) { Blocks.ENDER_CHEST, Blocks.TRAPPED_CHEST) {
@Override @Override
protected boolean isValidBlock(String[] javaBlockString) { protected boolean isValidBlock(BlockState blockState) {
if (javaBlockString[0].equals("minecraft:ender_chest")) { if (blockState.is(Blocks.ENDER_CHEST)) {
// Can't have double ender chests // Can't have double ender chests
return true; return true;
} }
// Add provision to ensure this isn't a double chest // Add provision to ensure this isn't a double chest
return super.isValidBlock(javaBlockString) && (javaBlockString.length > 1 && javaBlockString[1].contains("type=single")); return super.isValidBlock(blockState) && blockState.getValue(Properties.CHEST_TYPE) == ChestType.SINGLE;
} }
}; };
} }

Datei anzeigen

@ -32,12 +32,14 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.AbstractBlockInventoryTranslator; import org.geysermc.geyser.translator.inventory.AbstractBlockInventoryTranslator;
public abstract class AbstractFurnaceInventoryTranslator extends AbstractBlockInventoryTranslator { public abstract class AbstractFurnaceInventoryTranslator extends AbstractBlockInventoryTranslator {
AbstractFurnaceInventoryTranslator(String javaBlockIdentifier, ContainerType containerType) { AbstractFurnaceInventoryTranslator(Block javaBlock, ContainerType containerType) {
super(3, javaBlockIdentifier, containerType, ContainerInventoryUpdater.INSTANCE); super(3, javaBlock.defaultBlockState().withValue(Properties.LIT, false), containerType, ContainerInventoryUpdater.INSTANCE);
} }
@Override @Override

Datei anzeigen

@ -28,10 +28,11 @@ package org.geysermc.geyser.translator.inventory.furnace;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.level.block.Blocks;
public class BlastFurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator { public class BlastFurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator {
public BlastFurnaceInventoryTranslator() { public BlastFurnaceInventoryTranslator() {
super("minecraft:blast_furnace[facing=north,lit=false]", ContainerType.BLAST_FURNACE); super(Blocks.BLAST_FURNACE, ContainerType.BLAST_FURNACE);
} }
@Override @Override

Datei anzeigen

@ -28,10 +28,11 @@ package org.geysermc.geyser.translator.inventory.furnace;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.level.block.Blocks;
public class FurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator { public class FurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator {
public FurnaceInventoryTranslator() { public FurnaceInventoryTranslator() {
super("minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE); super(Blocks.FURNACE, ContainerType.FURNACE);
} }
@Override @Override

Datei anzeigen

@ -28,10 +28,11 @@ package org.geysermc.geyser.translator.inventory.furnace;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.level.block.Blocks;
public class SmokerInventoryTranslator extends AbstractFurnaceInventoryTranslator { public class SmokerInventoryTranslator extends AbstractFurnaceInventoryTranslator {
public SmokerInventoryTranslator() { public SmokerInventoryTranslator() {
super("minecraft:smoker[facing=north,lit=false]", ContainerType.SMOKER); super(Blocks.SMOKER, ContainerType.SMOKER);
} }
@Override @Override

Datei anzeigen

@ -28,7 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; 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.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -47,7 +47,7 @@ public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator impl
} else { } else {
// Tag is not present in at least 1.14.4 Paper // 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 // Minecraft 1.18.1 deliberately has a fallback here, but not for any other value
bedrockNbt.putString("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState.javaId()) ? "aligned" : "rollable"); // TODO bedrockNbt.putString("joint", blockState.getValue(Properties.ORIENTATION).isHorizontal() ? "aligned" : "rollable");
} }
bedrockNbt.putString("name", javaNbt.getString("name")); bedrockNbt.putString("name", javaNbt.getString("name"));
bedrockNbt.putString("target_pool", javaNbt.getString("target_pool")); bedrockNbt.putString("target_pool", javaNbt.getString("target_pool"));

Datei anzeigen

@ -26,22 +26,24 @@
package org.geysermc.geyser.translator.level.block.entity; package org.geysermc.geyser.translator.level.block.entity;
import it.unimi.dsi.fastutil.ints.IntArrays; import it.unimi.dsi.fastutil.ints.IntArrays;
import it.unimi.dsi.fastutil.objects.*; import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import org.geysermc.geyser.level.block.Blocks; import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import org.geysermc.geyser.level.block.type.Block; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.geyser.level.block.type.BlockState; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import org.geysermc.geyser.level.block.type.HoneyBlock; import lombok.Getter;
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; import org.cloudburstmc.math.vector.Vector3d;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import lombok.Getter;
import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.block.type.PistonBlock;
import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Axis;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.CollisionManager;
@ -53,6 +55,7 @@ import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map; import java.util.Map;
@ -99,7 +102,7 @@ public class PistonBlockEntity {
static { static {
// Create a ~1 x ~0.5 x ~1 bounding box above the honey block // Create a ~1 x ~0.5 x ~1 bounding box above the honey block
BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(HoneyBlock.state().javaId()); BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(Blocks.HONEY_BLOCK.defaultBlockState().javaId());
if (blockCollision == null) { if (blockCollision == null) {
throw new RuntimeException("Failed to find honey block collision"); throw new RuntimeException("Failed to find honey block collision");
} }
@ -224,10 +227,10 @@ public class PistonBlockEntity {
private void removePistonHead() { private void removePistonHead() {
Vector3i blockInFront = position.add(orientation.getUnitVector()); Vector3i blockInFront = position.add(orientation.getUnitVector());
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockInFront); BlockState state = session.getGeyser().getWorldManager().blockAt(session, blockInFront);
if (BlockStateValues.isPistonHead(blockId)) { if (state.is(Blocks.PISTON_HEAD)) {
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront); ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
} else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == Block.JAVA_AIR_ID) { } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && state.is(Blocks.AIR)) {
// Spigot removes the piston head from the cache, but we need to send the block update ourselves // Spigot removes the piston head from the cache, but we need to send the block update ourselves
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront); ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
} }
@ -353,7 +356,9 @@ public class PistonBlockEntity {
playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() - shrink.getZ()); playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() - shrink.getZ());
// Resolve collision with the piston head // Resolve collision with the piston head
BlockState pistonHeadId = BlockState.of(BlockStateValues.getPistonHead(orientation)); BlockState pistonHeadId = Blocks.PISTON_HEAD.defaultBlockState()
.withValue(Properties.SHORT, false)
.withValue(Properties.FACING, orientation);
pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox); pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox);
// Resolve collision with any attached moving blocks, but skip slime blocks // Resolve collision with any attached moving blocks, but skip slime blocks
@ -562,9 +567,11 @@ public class PistonBlockEntity {
private BlockState getAttachedBlockId(Vector3i blockPos) { private BlockState getAttachedBlockId(Vector3i blockPos) {
if (blockPos.equals(getPistonHeadPos())) { if (blockPos.equals(getPistonHeadPos())) {
return BlockState.of(BlockStateValues.getPistonHead(orientation)); return Blocks.PISTON_HEAD.defaultBlockState()
.withValue(Properties.SHORT, false)
.withValue(Properties.FACING, orientation);
} else { } else {
return attachedBlocks.getOrDefault(blockPos, BlockState.of(Block.JAVA_AIR_ID)); //FIXME return attachedBlocks.getOrDefault(blockPos, Blocks.AIR.defaultBlockState());
} }
} }
@ -633,7 +640,9 @@ public class PistonBlockEntity {
if (action == PistonValueType.PUSHING) { if (action == PistonValueType.PUSHING) {
Vector3i pistonHeadPos = getPistonHeadPos().add(movement); Vector3i pistonHeadPos = getPistonHeadPos().add(movement);
if (!SOLID_BOUNDING_BOX.checkIntersection(pistonHeadPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { if (!SOLID_BOUNDING_BOX.checkIntersection(pistonHeadPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) {
ChunkUtils.updateBlock(session, BlockStateValues.getPistonHead(orientation), pistonHeadPos); ChunkUtils.updateBlock(session, Blocks.PISTON_HEAD.defaultBlockState()
.withValue(Properties.SHORT, false)
.withValue(Properties.FACING, orientation), pistonHeadPos);
} }
} }
} }

Datei anzeigen

@ -56,8 +56,8 @@ import org.geysermc.geyser.item.type.BlockItem;
import org.geysermc.geyser.item.type.BoatItem; import org.geysermc.geyser.item.type.BoatItem;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.item.type.SpawnEggItem; import org.geysermc.geyser.item.type.SpawnEggItem;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.block.type.CauldronBlock; import org.geysermc.geyser.level.block.type.CauldronBlock;
@ -295,10 +295,10 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
*/ */
if (packet.getItemInHand() != null && session.getItemMappings().getMapping(packet.getItemInHand()).getJavaItem() instanceof SpawnEggItem) { if (packet.getItemInHand() != null && session.getItemMappings().getMapping(packet.getItemInHand()).getJavaItem() instanceof SpawnEggItem) {
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition()); BlockState blockState = session.getGeyser().getWorldManager().blockAt(session, packet.getBlockPosition());
if (blockState == BlockStateValues.JAVA_WATER_ID) { if (blockState.is(Blocks.WATER) && blockState.getValue(Properties.LEVEL) == 0) {
// Otherwise causes multiple mobs to spawn - just send a use item packet // Otherwise causes multiple mobs to spawn - just send a use item packet
useItem(session, packet, blockState); useItem(session, packet, blockState.javaId());
break; break;
} }
} }

Datei anzeigen

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.google.common.base.Suppliers;
import org.geysermc.mcprotocollib.protocol.data.game.command.CommandNode; import org.geysermc.mcprotocollib.protocol.data.game.command.CommandNode;
import org.geysermc.mcprotocollib.protocol.data.game.command.CommandParser; import org.geysermc.mcprotocollib.protocol.data.game.command.CommandParser;
import org.geysermc.mcprotocollib.protocol.data.game.command.properties.ResourceProperties; import org.geysermc.mcprotocollib.protocol.data.game.command.properties.ResourceProperties;
@ -54,12 +55,16 @@ import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.EntityUtils;
import java.util.*; import java.util.*;
import java.util.function.Supplier;
@SuppressWarnings("removal") // We know. This is our doing. @SuppressWarnings("removal") // We know. This is our doing.
@Translator(packet = ClientboundCommandsPacket.class) @Translator(packet = ClientboundCommandsPacket.class)
public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommandsPacket> { public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommandsPacket> {
private static final String[] ALL_BLOCK_NAMES = BlockRegistries.JAVA_BLOCKS.get().stream().map(block -> block.javaIdentifier().toString()).toArray(String[]::new); /**
* Wait until the registries load before getting all the block names.
*/
private static final Supplier<String[]> ALL_BLOCK_NAMES = Suppliers.memoize(() -> BlockRegistries.JAVA_BLOCKS.get().stream().map(block -> block.javaIdentifier().toString()).toArray(String[]::new));
private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers(); private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers();
private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(AttributeType::getIdentifier).toList().toArray(new String[0]); private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(AttributeType::getIdentifier).toList().toArray(new String[0]);
private static final String[] ENUM_BOOLEAN = {"true", "false"}; private static final String[] ENUM_BOOLEAN = {"true", "false"};
@ -247,7 +252,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
case RESOURCE_LOCATION, FUNCTION -> CommandParam.FILE_PATH; case RESOURCE_LOCATION, FUNCTION -> CommandParam.FILE_PATH;
case BOOL -> ENUM_BOOLEAN; case BOOL -> ENUM_BOOLEAN;
case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc
case BLOCK_STATE -> ALL_BLOCK_NAMES; case BLOCK_STATE -> ALL_BLOCK_NAMES.get();
case ITEM_STACK -> context.getItemNames(); case ITEM_STACK -> context.getItemNames();
case COLOR -> VALID_COLORS; case COLOR -> VALID_COLORS;
case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS; case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS;

Datei anzeigen

@ -31,7 +31,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.BlockEventPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEventPacket;
import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
@ -78,8 +78,8 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
// Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1 // Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1
// See https://github.com/PaperMC/Paper/blob/6fa1983e9ce177a4a412d5b950fd978620174777/patches/server/0304-Fire-BlockPistonRetractEvent-for-all-empty-pistons.patch // See https://github.com/PaperMC/Paper/blob/6fa1983e9ce177a4a412d5b950fd978620174777/patches/server/0304-Fire-BlockPistonRetractEvent-for-all-empty-pistons.patch
if (action == PistonValueType.PULLING || action == PistonValueType.CANCELLED_MID_PUSH) { if (action == PistonValueType.PULLING || action == PistonValueType.CANCELLED_MID_PUSH) {
int pistonBlock = session.getGeyser().getWorldManager().getBlockAt(session, position); BlockState pistonBlock = session.getGeyser().getWorldManager().blockAt(session, position);
if (!BlockStateValues.isStickyPiston(pistonBlock)) { if (!pistonBlock.is(Blocks.STICKY_PISTON)) {
return; return;
} }
if (action != PistonValueType.CANCELLED_MID_PUSH) { if (action != PistonValueType.CANCELLED_MID_PUSH) {
@ -97,8 +97,8 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
} }
} else { } else {
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> { PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> {
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, position); BlockState state = session.getGeyser().getWorldManager().blockAt(session, position);
boolean sticky = BlockStateValues.isStickyPiston(blockId); boolean sticky = state.is(Blocks.STICKY_PISTON);
boolean extended = action != PistonValueType.PUSHING; boolean extended = action != PistonValueType.PUSHING;
return new PistonBlockEntity(session, pos, direction, sticky, extended); return new PistonBlockEntity(session, pos, direction, sticky, extended);
}); });

Datei anzeigen

@ -65,7 +65,6 @@ 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-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-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-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-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" } adventure-text-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" }
@ -143,7 +142,7 @@ blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
[bundles] [bundles]
jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ] 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-reference-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" ]
adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ] adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ]
log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl" ] log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl" ]
jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ] jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ]