Merge branch 'master' of https://github.com/GeyserMC/Geyser into feature/protocol-3.0

This commit is contained in:
Camotoy 2022-12-20 19:47:45 -05:00
commit 4fe9aeca40
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
142 changed files with 2276 additions and 11909 deletions

View file

@ -111,6 +111,8 @@ public interface GeyserConfiguration {
boolean isNotifyOnNewBedrockUpdate();
String getUnusableSpaceBlock();
IMetricsInfo getMetrics();
int getPendingAuthenticationTimeout();

View file

@ -154,6 +154,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
@JsonProperty("notify-on-new-bedrock-update")
private boolean notifyOnNewBedrockUpdate = true;
@JsonProperty("unusable-space-block")
private String unusableSpaceBlock = "minecraft:barrier";
private MetricsInfo metrics = new MetricsInfo();
@JsonProperty("pending-authentication-timeout")

View file

@ -29,6 +29,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import org.geysermc.common.PlatformType;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.text.AsteriskSerializer;
import java.util.List;
@ -53,6 +54,8 @@ public class BootstrapDumpInfo {
@Getter
@AllArgsConstructor
public static class ListenerInfo {
@AsteriskSerializer.Asterisk(isIp = true)
public String ip;
public int port;
}

View file

@ -60,6 +60,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<BeeEntity> BEE;
public static final EntityDefinition<BlazeEntity> BLAZE;
public static final EntityDefinition<BoatEntity> BOAT;
public static final EntityDefinition<CamelEntity> CAMEL;
public static final EntityDefinition<CatEntity> CAT;
public static final EntityDefinition<SpiderEntity> CAVE_SPIDER;
public static final EntityDefinition<MinecartEntity> CHEST_MINECART;
@ -859,6 +860,13 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.BYTE, AbstractHorseEntity::setHorseFlags)
.addTranslator(null) // UUID of owner
.build();
CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase)
.type(EntityType.CAMEL)
.identifier("minecraft:llama") // todo 1.20
.height(2.375f).width(1.7f)
.addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing)
.addTranslator(null) // Last pose change tick
.build();
HORSE = EntityDefinition.inherited(HorseEntity::new, abstractHorseEntityBase)
.type(EntityType.HORSE)
.height(1.6f).width(1.3965f)

View file

@ -48,6 +48,8 @@ import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.EntityUtils;
@ -360,6 +362,7 @@ public class Entity {
setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire
setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
// Swimming is ignored here and instead we rely on the pose
setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);

View file

@ -31,9 +31,9 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.math.vector.Vector3f;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
import org.geysermc.floodgate.util.DeviceOs;

View file

@ -33,8 +33,8 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2019-2022 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.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID;
public class CamelEntity extends AbstractHorseEntity {
private static final float SITTING_HEIGHT_DIFFERENCE = 1.43F;
public CamelEntity(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);
}
@Override
protected void initializeMetadata() {
super.initializeMetadata();
this.dirtyMetadata.put(EntityDataTypes.VARIANT, 2); // Closest llama colour to camel
}
@Override
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
return "cactus".equals(javaIdentifierStripped);
}
@Override
protected void setDimensions(Pose pose) {
if (pose == Pose.SITTING) {
setBoundingBoxWidth(definition.height() - SITTING_HEIGHT_DIFFERENCE);
setBoundingBoxWidth(definition.width());
} else {
super.setDimensions(pose);
}
}
public void setDashing(BooleanEntityMetadata entityMetadata) {
}
}

View file

@ -25,16 +25,19 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.OptionalIntMetadataType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import java.util.OptionalInt;
import java.util.UUID;
public class EndermanEntity extends MonsterEntity {
@ -43,8 +46,15 @@ public class EndermanEntity extends MonsterEntity {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
public void setCarriedBlock(IntEntityMetadata entityMetadata) {
dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getBedrockBlock(entityMetadata.getPrimitiveValue()));
public void setCarriedBlock(EntityMetadata<OptionalInt, OptionalIntMetadataType> entityMetadata) {
BlockDefinition bedrockBlockId;
if (entityMetadata.getValue().isPresent()) {
bedrockBlockId = session.getBlockMappings().getBedrockBlock(entityMetadata.getValue().getAsInt());
} else {
bedrockBlockId = session.getBlockMappings().getBedrockAir();
}
dirtyMetadata.put(EntityDataTypes.CARRY_BLOCK_STATE, bedrockBlockId);
}
/**

View file

@ -30,13 +30,13 @@ import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeTyp
import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import lombok.Getter;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
@ -47,7 +47,6 @@ import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* The entity class specifically for a {@link GeyserSession}'s player.
@ -120,6 +119,16 @@ public class SessionPlayerEntity extends PlayerEntity {
refreshSpeed = true;
}
/**
* Since 1.19.40, the client must be re-informed of its bounding box on respawn
* See https://github.com/GeyserMC/Geyser/issues/3370
*/
public void updateBoundingBox() {
dirtyMetadata.put(EntityDataTypes.HEIGHT, getBoundingBoxHeight());
dirtyMetadata.put(EntityDataTypes.WIDTH, getBoundingBoxWidth());
updateBedrockMetadata();
}
@Override
public boolean setBoundingBoxHeight(float height) {
if (super.setBoundingBoxHeight(height)) {

View file

@ -76,7 +76,7 @@ public class AnvilContainer extends Container {
String originalName = ItemUtils.getCustomName(getInput().getNbt());
String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.locale());
String plainNewName = MessageTranslator.convertToPlainText(rename, session.locale());
String plainNewName = MessageTranslator.convertToPlainText(rename);
if (!plainOriginalName.equals(plainNewName)) {
// Strip out formatting since Java Edition does not allow it
correctRename = plainNewName;

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.inventory;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMap;
import lombok.Getter;
import lombok.Setter;

View file

@ -30,10 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.inventory.ContainerActionType
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import com.github.steveice10.mc.protocol.data.game.inventory.MoveToHotbarAction;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.ints.*;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.SlotType;
@ -124,12 +121,14 @@ public final class ClickPlan {
}
ItemStack clickedItemStack;
if (!planIter.hasNext() && refresh) {
clickedItemStack = InventoryUtils.REFRESH_ITEM;
if (emulatePost1_16Logic) {
// The action must be simulated first as Java expects the new contents of the cursor (as of 1.18.1)
clickedItemStack = simulatedCursor.getItemStack();
} else {
if (emulatePost1_16Logic) {
// The action must be simulated first as Java expects the new contents of the cursor (as of 1.18.1)
clickedItemStack = simulatedCursor.getItemStack();
if (!planIter.hasNext() && refresh) {
// Doesn't have the intended effect with state IDs since this won't cause a complete window refresh
// (It will eventually once state IDs desync, but this causes more problems than not)
clickedItemStack = InventoryUtils.REFRESH_ITEM;
} else {
if (action.click.actionType == ContainerActionType.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) {
clickedItemStack = null;

View file

@ -25,9 +25,8 @@
package org.geysermc.geyser.inventory.holder;
import com.google.common.collect.ImmutableSet;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket;
@ -39,6 +38,7 @@ import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.geyser.util.InventoryUtils;
import java.util.Collections;
import java.util.HashSet;
@ -63,14 +63,14 @@ public class BlockInventoryHolder extends InventoryHolder {
Set<String> validBlocksTemp = new HashSet<>(validBlocks.length + 1);
Collections.addAll(validBlocksTemp, validBlocks);
validBlocksTemp.add(BlockUtils.getCleanIdentifier(javaBlockIdentifier));
this.validBlocks = ImmutableSet.copyOf(validBlocksTemp);
this.validBlocks = Set.copyOf(validBlocksTemp);
} else {
this.validBlocks = Collections.singleton(BlockUtils.getCleanIdentifier(javaBlockIdentifier));
}
}
@Override
public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
public boolean prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
// Check to see if there is an existing block we can use that the player just selected.
// First, verify that the player's position has not changed, so we don't try to select a block wildly out of range.
// (This could be a virtual inventory that the player is opening)
@ -83,13 +83,16 @@ public class BlockInventoryHolder extends InventoryHolder {
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
((Container) inventory).setUsingRealBlock(true, javaBlockString[0]);
setCustomName(session, session.getLastInteractionBlockPosition(), inventory, javaBlockId);
return;
return true;
}
}
// Otherwise, time to conjure up a fake block!
Vector3i position = session.getPlayerEntity().getPosition().toInt();
position = position.add(Vector3i.UP);
Vector3i position = InventoryUtils.findAvailableWorldSpace(session);
if (position == null) {
return false;
}
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(position);
@ -99,6 +102,8 @@ public class BlockInventoryHolder extends InventoryHolder {
inventory.setHolderPosition(position);
setCustomName(session, position, inventory, defaultJavaBlockState);
return true;
}
/**

View file

@ -30,7 +30,7 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
public abstract class InventoryHolder {
public abstract void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory);
public abstract boolean prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory);
public abstract void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory);
public abstract void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory);
}

View file

@ -31,8 +31,8 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;

View file

@ -25,8 +25,8 @@
package org.geysermc.geyser.item.components;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import java.util.ArrayList;
import java.util.List;

View file

@ -25,7 +25,7 @@
package org.geysermc.geyser.item.components;
import com.nukkitx.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMap;
import java.util.Locale;

View file

@ -32,43 +32,41 @@ import lombok.Getter;
* It is used to construct the list for the settings menu
*/
public enum GameRule {
ANNOUNCEADVANCEMENTS("announceAdvancements", Boolean.class, true), // JE only
COMMANDBLOCKOUTPUT("commandBlockOutput", Boolean.class, true),
DISABLEELYTRAMOVEMENTCHECK("disableElytraMovementCheck", Boolean.class, false), // JE only
DISABLERAIDS("disableRaids", Boolean.class, false), // JE only
DODAYLIGHTCYCLE("doDaylightCycle", Boolean.class, true),
DOENTITYDROPS("doEntityDrops", Boolean.class, true),
DOFIRETICK("doFireTick", Boolean.class, true),
DOIMMEDIATERESPAWN("doImmediateRespawn", Boolean.class, false),
DOINSOMNIA("doInsomnia", Boolean.class, true),
DOLIMITEDCRAFTING("doLimitedCrafting", Boolean.class, false), // JE only
DOMOBLOOT("doMobLoot", Boolean.class, true),
DOMOBSPAWNING("doMobSpawning", Boolean.class, true),
DOPATROLSPAWNING("doPatrolSpawning", Boolean.class, true), // JE only
DOTILEDROPS("doTileDrops", Boolean.class, true),
DOTRADERSPAWNING("doTraderSpawning", Boolean.class, true), // JE only
DOWEATHERCYCLE("doWeatherCycle", Boolean.class, true),
DROWNINGDAMAGE("drowningDamage", Boolean.class, true),
FALLDAMAGE("fallDamage", Boolean.class, true),
FIREDAMAGE("fireDamage", Boolean.class, true),
FREEZEDAMAGE("freezeDamage", Boolean.class, true),
FORGIVEDEADPLAYERS("forgiveDeadPlayers", Boolean.class, true), // JE only
KEEPINVENTORY("keepInventory", Boolean.class, false),
LOGADMINCOMMANDS("logAdminCommands", Boolean.class, true), // JE only
MAXCOMMANDCHAINLENGTH("maxCommandChainLength", Integer.class, 65536),
MAXENTITYCRAMMING("maxEntityCramming", Integer.class, 24), // JE only
MOBGRIEFING("mobGriefing", Boolean.class, true),
NATURALREGENERATION("naturalRegeneration", Boolean.class, true),
PLAYERSSLEEPINGPERCENTAGE("playersSleepingPercentage", Integer.class, 100), // JE only
RANDOMTICKSPEED("randomTickSpeed", Integer.class, 3),
REDUCEDDEBUGINFO("reducedDebugInfo", Boolean.class, false), // JE only
SENDCOMMANDFEEDBACK("sendCommandFeedback", Boolean.class, true),
SHOWDEATHMESSAGES("showDeathMessages", Boolean.class, true),
SPAWNRADIUS("spawnRadius", Integer.class, 10),
SPECTATORSGENERATECHUNKS("spectatorsGenerateChunks", Boolean.class, true), // JE only
UNIVERSALANGER("universalAnger", Boolean.class, false), // JE only
UNKNOWN("unknown", Object.class);
ANNOUNCEADVANCEMENTS("announceAdvancements", true), // JE only
COMMANDBLOCKOUTPUT("commandBlockOutput", true),
DISABLEELYTRAMOVEMENTCHECK("disableElytraMovementCheck", false), // JE only
DISABLERAIDS("disableRaids", false), // JE only
DODAYLIGHTCYCLE("doDaylightCycle", true),
DOENTITYDROPS("doEntityDrops", true),
DOFIRETICK("doFireTick", true),
DOIMMEDIATERESPAWN("doImmediateRespawn", false),
DOINSOMNIA("doInsomnia", true),
DOLIMITEDCRAFTING("doLimitedCrafting", false), // JE only
DOMOBLOOT("doMobLoot", true),
DOMOBSPAWNING("doMobSpawning", true),
DOPATROLSPAWNING("doPatrolSpawning", true), // JE only
DOTILEDROPS("doTileDrops", true),
DOTRADERSPAWNING("doTraderSpawning", true), // JE only
DOWEATHERCYCLE("doWeatherCycle", true),
DROWNINGDAMAGE("drowningDamage", true),
FALLDAMAGE("fallDamage", true),
FIREDAMAGE("fireDamage", true),
FREEZEDAMAGE("freezeDamage", true),
FORGIVEDEADPLAYERS("forgiveDeadPlayers", true), // JE only
KEEPINVENTORY("keepInventory", false),
LOGADMINCOMMANDS("logAdminCommands", true), // JE only
MAXCOMMANDCHAINLENGTH("maxCommandChainLength", 65536),
MAXENTITYCRAMMING("maxEntityCramming", 24), // JE only
MOBGRIEFING("mobGriefing", true),
NATURALREGENERATION("naturalRegeneration", true),
PLAYERSSLEEPINGPERCENTAGE("playersSleepingPercentage", 100), // JE only
RANDOMTICKSPEED("randomTickSpeed", 3),
REDUCEDDEBUGINFO("reducedDebugInfo", false), // JE only
SENDCOMMANDFEEDBACK("sendCommandFeedback", true),
SHOWDEATHMESSAGES("showDeathMessages", true),
SPAWNRADIUS("spawnRadius", 10),
SPECTATORSGENERATECHUNKS("spectatorsGenerateChunks", true), // JE only
UNIVERSALANGER("universalAnger", false); // JE only
public static final GameRule[] VALUES = values();
@ -78,48 +76,25 @@ public enum GameRule {
@Getter
private final Class<?> type;
@Getter
private final Object defaultValue;
private final int defaultValue;
GameRule(String javaID, Class<?> type) {
this(javaID, type, null);
GameRule(String javaID, boolean defaultValue) {
this.javaID = javaID;
this.type = Boolean.class;
this.defaultValue = defaultValue ? 1 : 0;
}
GameRule(String javaID, Class<?> type, Object defaultValue) {
GameRule(String javaID, int defaultValue) {
this.javaID = javaID;
this.type = type;
this.type = Integer.class;
this.defaultValue = defaultValue;
}
/**
* Convert a string to an object of the correct type for the current gamerule
*
* @param value The string value to convert
* @return The converted and formatted value
*/
public Object convertValue(String value) {
if (type.equals(Boolean.class)) {
return Boolean.parseBoolean(value);
} else if (type.equals(Integer.class)) {
return Integer.parseInt(value);
}
return null;
public boolean getDefaultBooleanValue() {
return defaultValue != 0;
}
/**
* Fetch a game rule by the given Java ID
*
* @param id The ID of the gamerule
* @return A {@link GameRule} object representing the requested ID or {@link GameRule#UNKNOWN}
*/
public static GameRule fromJavaID(String id) {
for (GameRule gamerule : VALUES) {
if (gamerule.javaID.equals(id)) {
return gamerule;
}
}
return UNKNOWN;
public int getDefaultIntValue() {
return defaultValue;
}
}

View file

@ -25,10 +25,8 @@
package org.geysermc.geyser.level;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.geyser.level.block.BlockStateValues;
@ -36,11 +34,8 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.ChunkCache;
import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
import java.util.Locale;
public class GeyserWorldManager extends WorldManager {
private static final Object2ObjectMap<String, String> gameruleCache = new Object2ObjectOpenHashMap<>();
private final Object2ObjectMap<String, String> gameruleCache = new Object2ObjectOpenHashMap<>();
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
@ -82,18 +77,18 @@ public class GeyserWorldManager extends WorldManager {
@Override
public void setGameRule(GeyserSession session, String name, Object value) {
session.sendCommand("gamerule " + name + " " + value);
super.setGameRule(session, name, value);
gameruleCache.put(name, String.valueOf(value));
}
@Override
public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
String value = gameruleCache.get(gameRule.getJavaID());
if (value != null) {
return Boolean.parseBoolean(value);
}
return gameRule.getDefaultValue() != null ? (Boolean) gameRule.getDefaultValue() : false;
return gameRule.getDefaultBooleanValue();
}
@Override
@ -103,17 +98,7 @@ public class GeyserWorldManager extends WorldManager {
return Integer.parseInt(value);
}
return gameRule.getDefaultValue() != null ? (int) gameRule.getDefaultValue() : 0;
}
@Override
public void setPlayerGameMode(GeyserSession session, GameMode gameMode) {
session.sendCommand("gamemode " + gameMode.name().toLowerCase(Locale.ROOT));
}
@Override
public void setDifficulty(GeyserSession session, Difficulty difficulty) {
session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT));
return gameRule.getDefaultIntValue();
}
@Override

View file

@ -28,9 +28,12 @@ package org.geysermc.geyser.level;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMap;
import org.geysermc.geyser.session.GeyserSession;
import javax.annotation.Nullable;
import java.util.Locale;
/**
* Class that manages or retrieves various information
* from the world. Everything in this class should be
@ -105,7 +108,9 @@ public abstract class WorldManager {
* @param name The gamerule to change
* @param value The new value for the gamerule
*/
public abstract void setGameRule(GeyserSession session, String name, Object value);
public void setGameRule(GeyserSession session, String name, Object value) {
session.sendCommand("gamerule " + name + " " + value);
}
/**
* Gets a gamerule value as a boolean
@ -114,7 +119,7 @@ public abstract class WorldManager {
* @param gameRule The gamerule to fetch the value of
* @return The boolean representation of the value
*/
public abstract Boolean getGameRuleBool(GeyserSession session, GameRule gameRule);
public abstract boolean getGameRuleBool(GeyserSession session, GameRule gameRule);
/**
* Get a gamerule value as an integer
@ -131,7 +136,9 @@ public abstract class WorldManager {
* @param session The session of the player to change the game mode of
* @param gameMode The game mode to change the player to
*/
public abstract void setPlayerGameMode(GeyserSession session, GameMode gameMode);
public void setPlayerGameMode(GeyserSession session, GameMode gameMode) {
session.sendCommand("gamemode " + gameMode.name().toLowerCase(Locale.ROOT));
}
/**
* Change the difficulty of the Java server
@ -139,7 +146,9 @@ public abstract class WorldManager {
* @param session The session of the user that requested the change
* @param difficulty The difficulty to change to
*/
public abstract void setDifficulty(GeyserSession session, Difficulty difficulty);
public void setDifficulty(GeyserSession session, Difficulty difficulty) {
session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT));
}
/**
* Checks if the given session's player has a permission
@ -149,4 +158,12 @@ public abstract class WorldManager {
* @return True if the player has the requested permission, false if not
*/
public abstract boolean hasPermission(GeyserSession session, String permission);
/**
* Returns a list of biome identifiers available on the server.
*/
@Nullable
public String[] getBiomeIdentifiers(boolean withTags) {
return null;
}
}

View file

@ -28,12 +28,11 @@ package org.geysermc.geyser.network;
import com.github.steveice10.mc.protocol.codec.MinecraftCodec;
import com.github.steveice10.mc.protocol.codec.PacketCodec;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.v527.Bedrock_v527;
import org.cloudburstmc.protocol.bedrock.codec.v534.Bedrock_v534;
import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544;
import org.cloudburstmc.protocol.bedrock.codec.v545.Bedrock_v545;
import org.cloudburstmc.protocol.bedrock.codec.v554.Bedrock_v554;
import org.cloudburstmc.protocol.bedrock.codec.v557.Bedrock_v557;
import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.geysermc.geyser.session.GeyserSession;
@ -49,7 +48,7 @@ public final class GameProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports.
*/
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v557.CODEC;
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v560.CODEC;
/**
* A list of all supported Bedrock versions that can join Geyser
*/
@ -62,12 +61,6 @@ public final class GameProtocol {
private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC;
static {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v527.CODEC.toBuilder()
.minecraftVersion("1.19.0/1.19.2")
.build());
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v534.CODEC.toBuilder()
.minecraftVersion("1.19.10/1.19.11")
.build());
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.CODEC);
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.CODEC.toBuilder()
.minecraftVersion("1.19.21/1.19.22")
@ -75,7 +68,12 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.CODEC.toBuilder()
.minecraftVersion("1.19.30/1.19.31")
.build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.CODEC.toBuilder()
.minecraftVersion("1.19.40/1.19.41")
.build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
.minecraftVersion("1.19.50/1.19.51")
.build());
}
/**
@ -94,11 +92,11 @@ public final class GameProtocol {
/* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */
public static boolean supports1_19_10(GeyserSession session) {
return session.getUpstream().getProtocolVersion() >= Bedrock_v534.CODEC.getProtocolVersion();
public static boolean supports1_19_30(GeyserSession session) {
return session.getUpstream().getProtocolVersion() >= Bedrock_v554.CODEC.getProtocolVersion();
}
public static boolean supports1_19_30(GeyserSession session) {
public static boolean supports1_19_50(GeyserSession session) {
return session.getUpstream().getProtocolVersion() >= Bedrock_v554.CODEC.getProtocolVersion();
}
@ -117,7 +115,7 @@ public final class GameProtocol {
* @return the supported Minecraft: Java Edition version names
*/
public static List<String> getJavaVersions() {
return List.of(DEFAULT_JAVA_CODEC.getMinecraftVersion(), "1.19.2");
return List.of(DEFAULT_JAVA_CODEC.getMinecraftVersion());
}
/**

View file

@ -61,9 +61,13 @@ import org.geysermc.geyser.util.MathUtils;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayDeque;
import java.util.Deque;
public class UpstreamPacketHandler extends LoggingPacketHandler {
private Deque<String> packsToSent = new ArrayDeque<>();
public UpstreamPacketHandler(GeyserImpl geyser, GeyserSession session) {
super(geyser, session);
}
@ -186,24 +190,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
break;
case SEND_PACKS:
for(String id : packet.getPackIds()) {
ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket();
String[] packID = id.split("_");
ResourcePack pack = ResourcePack.PACKS.get(packID[0]);
ResourcePackManifest.Header header = pack.getManifest().getHeader();
data.setPackId(header.getUuid());
int chunkCount = (int) Math.ceil((int) pack.getFile().length() / (double) ResourcePack.CHUNK_SIZE);
data.setChunkCount(chunkCount);
data.setCompressedPackSize(pack.getFile().length());
data.setMaxChunkSize(ResourcePack.CHUNK_SIZE);
data.setHash(pack.getSha256());
data.setPackVersion(packID[1]);
data.setPremium(false);
data.setType(ResourcePackType.RESOURCES);
session.sendUpstreamPacket(data);
}
packsToSent.addAll(packet.getPackIds());
sendPackDataInfo(packsToSent.pop());
break;
case HAVE_ALL_PACKS:
@ -296,7 +284,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
data.setPackId(packet.getPackId());
int offset = packet.getChunkIndex() * ResourcePack.CHUNK_SIZE;
byte[] packData = new byte[(int) MathUtils.constrain(pack.getFile().length() - offset, 0, ResourcePack.CHUNK_SIZE)];
long remainingSize = pack.getFile().length() - offset;
byte[] packData = new byte[(int) MathUtils.constrain(remainingSize, 0, ResourcePack.CHUNK_SIZE)];
try (InputStream inputStream = new FileInputStream(pack.getFile())) {
inputStream.skip(offset);
@ -308,6 +297,31 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
data.setData(Unpooled.wrappedBuffer(packData));
session.sendUpstreamPacket(data);
// Check if it is the last chunk and send next pack in queue when available.
if (remainingSize <= ResourcePack.CHUNK_SIZE && !packsToSent.isEmpty()) {
sendPackDataInfo(packsToSent.pop());
}
return PacketSignal.HANDLED;
}
private void sendPackDataInfo(String id) {
ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket();
String[] packID = id.split("_");
ResourcePack pack = ResourcePack.PACKS.get(packID[0]);
ResourcePackManifest.Header header = pack.getManifest().getHeader();
data.setPackId(header.getUuid());
int chunkCount = (int) Math.ceil((int) pack.getFile().length() / (double) ResourcePack.CHUNK_SIZE);
data.setChunkCount(chunkCount);
data.setCompressedPackSize(pack.getFile().length());
data.setMaxChunkSize(ResourcePack.CHUNK_SIZE);
data.setHash(pack.getSha256());
data.setPackVersion(packID[1]);
data.setPremium(false);
data.setType(ResourcePackType.RESOURCES);
session.sendUpstreamPacket(data);
}
}

View file

@ -41,9 +41,6 @@ import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.cloudburstmc.netty.channel.raknet.RakChannelFactory;
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPingEncoder;
import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPongDecoder;
import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPongEncoder;
import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerOfflineHandler;
import org.cloudburstmc.protocol.bedrock.BedrockPong;
import org.geysermc.geyser.GeyserImpl;
@ -57,7 +54,6 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Random;
import java.util.function.Function;
public final class GeyserServer {
@ -158,13 +154,9 @@ public final class GeyserServer {
pong.subMotd(config.getBedrock().secondaryMotd());
}
if (config.isPassthroughPlayerCounts() && pingInfo != null) {
pong.playerCount(pingInfo.getPlayers().getOnline());
pong.maximumPlayerCount(pingInfo.getPlayers().getMax());
} else {
pong.playerCount(geyser.getSessionManager().getSessions().size());
pong.maximumPlayerCount(config.getMaxPlayers());
}
// https://github.com/GeyserMC/Geyser/issues/3388
pong.motd(pong.motd().replace(';', ':'));
pong.subMotd(pong.subMotd().replace(';', ':'));
// Fallbacks to prevent errors and allow Bedrock to see the server
if (pong.motd() == null || pong.motd().isBlank()) {
@ -193,6 +185,14 @@ public final class GeyserServer {
}
}
if (config.isPassthroughPlayerCounts() && pingInfo != null) {
pong.playerCount(pingInfo.getPlayers().getOnline());
pong.maximumPlayerCount(pingInfo.getPlayers().getMax());
} else {
pong.playerCount(geyser.getSessionManager().getSessions().size());
pong.maximumPlayerCount(config.getMaxPlayers());
}
//Bedrock will not even attempt a connection if the client thinks the server is full
//so we have to fake it not being full
if (pong.playerCount() >= pong.maximumPlayerCount()) {

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.ping;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.nukkitx.nbt.util.VarInts;
import org.cloudburstmc.nbt.util.VarInts;
import io.netty.handler.codec.haproxy.HAProxyCommand;
import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol;
import io.netty.util.NetUtil;

View file

@ -31,15 +31,15 @@ import com.github.steveice10.mc.protocol.data.game.level.event.LevelEvent;
import com.github.steveice10.mc.protocol.data.game.level.particle.ParticleType;
import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
import com.github.steveice10.packetlib.packet.Packet;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.inventory.CraftingData;
import org.cloudburstmc.protocol.bedrock.data.inventory.PotionMixData;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.CraftingData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData;
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment;
@ -181,12 +181,15 @@ public final class Registries {
POTION_MIXES = SimpleRegistry.create(PotionMixRegistryLoader::new);
ENCHANTMENTS = SimpleMappedRegistry.create("mappings/enchantments.json", EnchantmentRegistryLoader::new);
// TEMPORARY FIX TO MAKE OLD BIOMES NBT WORK WITH 1.19.30
// Remove unneeded client generation data from NbtMapBuilder
NbtMapBuilder biomesNbt = NbtMap.builder();
for (Map.Entry<String, Object> entry : BIOMES_NBT.get().entrySet()) {
String key = entry.getKey();
NbtMapBuilder value = ((NbtMap) entry.getValue()).toBuilder();
value.put("name_hash", key);
value.remove("minecraft:consolidated_features");
value.remove("minecraft:multinoise_generation_rules");
value.remove("minecraft:surface_material_adjustments");
value.remove( "minecraft:surface_parameters");
biomesNbt.put(key, value.build());
}
BIOMES_NBT.set(biomesNbt.build());

View file

@ -25,9 +25,9 @@
package org.geysermc.geyser.registry.loader;
import com.nukkitx.nbt.NBTInputStream;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtUtils;
import org.cloudburstmc.nbt.NBTInputStream;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtUtils;
import org.geysermc.geyser.GeyserImpl;
/**

View file

@ -25,7 +25,7 @@
package org.geysermc.geyser.registry.loader;
import org.cloudburstmc.protocol.bedrock.data.inventory.PotionMixData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData;
import org.geysermc.geyser.inventory.item.Potion;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.Registries;

View file

@ -28,24 +28,16 @@ package org.geysermc.geyser.registry.populator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.ImmutableMap;
import com.nukkitx.nbt.NBTInputStream;
import com.nukkitx.nbt.NbtList;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIntPair;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import org.cloudburstmc.protocol.bedrock.codec.v527.Bedrock_v527;
import it.unimi.dsi.fastutil.objects.*;
import org.cloudburstmc.nbt.*;
import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544;
import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleBlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleDefinitionRegistry;
import org.cloudburstmc.protocol.common.DefinitionRegistry;
import org.cloudburstmc.protocol.common.SimpleDefinitionRegistry;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.physics.PistonBehavior;
@ -56,12 +48,7 @@ import org.geysermc.geyser.util.BlockUtils;
import java.io.DataInputStream;
import java.io.InputStream;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.function.BiFunction;
import java.util.zip.GZIPInputStream;
@ -84,13 +71,9 @@ public final class BlockRegistryPopulator {
private static void registerBedrockBlocks() {
BiFunction<String, NbtMapBuilder, String> emptyMapper = (bedrockIdentifier, statesBuilder) -> null;
ImmutableMap<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> blockMappers = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder()
.put(ObjectIntPair.of("1_19_0", Bedrock_v527.CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> {
if (bedrockIdentifier.equals("minecraft:muddy_mangrove_roots")) {
statesBuilder.remove("pillar_axis");
}
return null;
})
.put(ObjectIntPair.of("1_19_20", Bedrock_v544.CODEC.getProtocolVersion()), emptyMapper).build();
.put(ObjectIntPair.of("1_19_20", Bedrock_v544.CODEC.getProtocolVersion()), emptyMapper)
.put(ObjectIntPair.of("1_19_50", Bedrock_v560.CODEC.getProtocolVersion()), emptyMapper)
.build();
for (Map.Entry<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> palette : blockMappers.entrySet()) {
NbtList<NbtMap> blocksTag;
@ -129,7 +112,7 @@ public final class BlockRegistryPopulator {
BiFunction<String, NbtMapBuilder, String> stateMapper = blockMappers.getOrDefault(palette.getKey(), emptyMapper);
BlockDefinition[] javaToBedrockBlocks = new BlockDefinition[BLOCKS_JSON.size()];
DefinitionRegistry.Builder<BlockDefinition> registry = SimpleDefinitionRegistry.builder();
SimpleDefinitionRegistry.Builder<BlockDefinition> registry = SimpleDefinitionRegistry.builder();
Map<String, NbtMap> flowerPotBlocks = new Object2ObjectOpenHashMap<>();
Map<NbtMap, BlockDefinition> itemFrames = new Object2ObjectOpenHashMap<>();

View file

@ -26,8 +26,8 @@
package org.geysermc.geyser.registry.populator;
import com.fasterxml.jackson.databind.JsonNode;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtUtils;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtUtils;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.GeyserBootstrap;

View file

@ -26,9 +26,9 @@
package org.geysermc.geyser.registry.populator;
import com.google.common.collect.Multimap;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
@ -174,6 +174,33 @@ public class CustomItemRegistryPopulator {
computeArmorProperties(mapping.getArmorType(), mapping.getProtectionValue(), componentBuilder);
}
if (mapping.getFirstBlockRuntimeId() != null) {
computeBlockItemProperties(mapping.getBedrockIdentifier(), componentBuilder);
}
if (mapping.isEdible()) {
computeConsumableProperties(itemProperties, componentBuilder, 1, false);
}
if (mapping.isEntityPlacer()) {
computeEntityPlacerProperties(componentBuilder);
}
switch (mapping.getBedrockIdentifier()) {
case "minecraft:fire_charge", "minecraft:flint_and_steel" -> {
computeBlockItemProperties("minecraft:fire", componentBuilder);
}
case "minecraft:bow", "minecraft:crossbow", "minecraft:trident" -> {
computeChargeableProperties(itemProperties, componentBuilder);
}
case "minecraft:honey_bottle", "minecraft:milk_bucket", "minecraft:potion" -> {
computeConsumableProperties(itemProperties, componentBuilder, 2, true);
}
case "minecraft:experience_bottle", "minecraft:egg", "minecraft:ender_pearl", "minecraft:ender_eye", "minecraft:lingering_potion", "minecraft:snowball", "minecraft:splash_potion" -> {
computeThrowableProperties(componentBuilder);
}
}
computeRenderOffsets(false, customItemData, componentBuilder);
componentBuilder.putCompound("item_properties", itemProperties.build());
@ -310,6 +337,48 @@ public class CustomItemRegistryPopulator {
}
}
private static void computeBlockItemProperties(String blockItem, NbtMapBuilder componentBuilder) {
// carved pumpkin should be able to be worn and for that we would need to add wearable and armor with protection 0 here
// however this would have the side effect of preventing carved pumpkins from working as an attachable on the RP side outside the head slot
// it also causes the item to glitch when right clicked to "equip" so this should only be added here later if these issues can be overcome
// all block items registered should be given this component to prevent double placement
componentBuilder.putCompound("minecraft:block_placer", NbtMap.builder().putString("block", blockItem).build());
}
private static void computeChargeableProperties(NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder) {
// setting high use_duration prevents the consume animation from playing
itemProperties.putInt("use_duration", Integer.MAX_VALUE);
// display item as tool (mainly for crossbow and bow)
itemProperties.putBoolean("hand_equipped", true);
// ensure client moves at slow speed while charging (note: this was calculated by hand as the movement modifer value does not seem to scale linearly)
componentBuilder.putCompound("minecraft:chargeable", NbtMap.builder().putFloat("movement_modifier", 0.35F).build());
}
private static void computeConsumableProperties(NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder, int useAnimation, boolean canAlwaysEat) {
// this is the duration of the use animation in ticks; note that in behavior packs this is set as a float in seconds, but over the network it is an int in ticks
itemProperties.putInt("use_duration", 32);
// this dictates that the item will use the eat or drink animation (in the first person) and play eat or drink sounds
// note that in behavior packs this is set as the string "eat" or "drink", but over the network it as an int, with these values being 1 and 2 respectively
itemProperties.putInt("use_animation", useAnimation);
// this component is required to allow the eat animation to play
componentBuilder.putCompound("minecraft:food", NbtMap.builder().putBoolean("can_always_eat", canAlwaysEat).build());
}
private static void computeEntityPlacerProperties(NbtMapBuilder componentBuilder) {
// all items registered that place entities should be given this component to prevent double placement
// it is okay that the entity here does not match the actual one since we control what entity actually spawns
componentBuilder.putCompound("minecraft:entity_placer", NbtMap.builder().putString("entity", "minecraft:minecart").build());
}
private static void computeThrowableProperties(NbtMapBuilder componentBuilder) {
// allows item to be thrown when holding down right click (individual presses are required w/o this component)
componentBuilder.putCompound("minecraft:throwable", NbtMap.builder().putBoolean("do_swing_animation", true).build());
// this must be set to something for the swing animation to play
// it is okay that the projectile here does not match the actual one since we control what entity actually spawns
componentBuilder.putCompound("minecraft:projectile", NbtMap.builder().putString("projectile_entity", "minecraft:snowball").build());
}
private static void computeRenderOffsets(boolean isHat, CustomItemData customItemData, NbtMapBuilder componentBuilder) {
if (isHat) {
componentBuilder.remove("minecraft:render_offsets");

View file

@ -28,30 +28,19 @@ package org.geysermc.geyser.registry.populator;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import org.cloudburstmc.protocol.bedrock.codec.v527.Bedrock_v527;
import org.cloudburstmc.protocol.bedrock.codec.v534.Bedrock_v534;
import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.objects.*;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544;
import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleDefinitionRegistry;
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.common.DefinitionRegistry;
import org.cloudburstmc.protocol.common.SimpleDefinitionRegistry;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.item.custom.CustomItemData;
@ -61,23 +50,12 @@ import org.geysermc.geyser.inventory.item.StoredItemMappings;
import org.geysermc.geyser.item.GeyserCustomMappingData;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.GeyserMappingItem;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.registry.type.NonVanillaItemRegistration;
import org.geysermc.geyser.registry.type.PaletteItem;
import org.geysermc.geyser.registry.type.*;
import org.geysermc.geyser.util.ItemUtils;
import org.geysermc.geyser.util.collection.FixedInt2IntMap;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
@ -90,10 +68,8 @@ public class ItemRegistryPopulator {
public static void populate() {
Map<String, PaletteVersion> paletteVersions = new Object2ObjectOpenHashMap<>();
paletteVersions.put("1_19_0", new PaletteVersion(Bedrock_v527.CODEC.getProtocolVersion(),
Collections.singletonMap("minecraft:trader_llama_spawn_egg", "minecraft:llama_spawn_egg")));
paletteVersions.put("1_19_10", new PaletteVersion(Bedrock_v534.CODEC.getProtocolVersion(), Collections.emptyMap()));
paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.CODEC.getProtocolVersion(), Collections.emptyMap()));
paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.CODEC.getProtocolVersion(), Collections.emptyMap()));
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
@ -147,7 +123,7 @@ public class ItemRegistryPopulator {
int nextFreeBedrockId = 0;
List<ComponentItemData> componentItemData = new ObjectArrayList<>();
DefinitionRegistry.Builder<ItemDefinition> registry = SimpleDefinitionRegistry.builder();
SimpleDefinitionRegistry.Builder<ItemDefinition> registry = SimpleDefinitionRegistry.builder();
Map<String, ItemDefinition> definitions = new Object2ObjectLinkedOpenHashMap<>();
for (PaletteItem entry : itemEntries) {

View file

@ -29,13 +29,13 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.cloudburstmc.protocol.bedrock.data.inventory.CraftingData;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtUtils;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.CraftingData;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
@ -50,15 +50,7 @@ import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID;
@ -90,8 +82,6 @@ public class RecipeRegistryPopulator {
Collections.singletonList(CraftingData.fromMulti(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), ++LAST_RECIPE_NET_ID)));
craftingData.put(RecipeType.CRAFTING_SPECIAL_MAPCLONING,
Collections.singletonList(CraftingData.fromMulti(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), ++LAST_RECIPE_NET_ID)));
craftingData.put(RecipeType.CRAFTING_SPECIAL_BANNERADDPATTERN,
Collections.singletonList(CraftingData.fromMulti(UUID.fromString("b5c5d105-75a2-4076-af2b-923ea2bf4bf0"), ++LAST_RECIPE_NET_ID)));
// https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/inventory/MultiRecipe.php

View file

@ -25,14 +25,11 @@
package org.geysermc.geyser.registry.type;
import com.nukkitx.nbt.NbtList;
import com.nukkitx.nbt.NbtMap;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import lombok.Builder;
import lombok.Value;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.common.DefinitionRegistry;
import java.util.Map;
@ -78,6 +75,6 @@ public class BlockMappings {
}
public boolean isItemFrame(BlockDefinition definition) {
return this.itemFrames.containsKey(definition.getState());
return this.itemFrames.containsKey(definition.getRuntimeId());
}
}

View file

@ -48,4 +48,6 @@ public class GeyserMappingItem {
@JsonProperty("repair_materials") List<String> repairMaterials;
@JsonProperty("has_suspicious_stew_effect") boolean hasSuspiciousStewEffect = false;
@JsonProperty("dye_color") int dyeColor = -1;
@JsonProperty("is_edible") boolean edible = false;
@JsonProperty("is_entity_placer") boolean entityPlacer = false;
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.session;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsException;
import com.github.steveice10.mc.auth.exception.request.RequestException;
@ -58,19 +57,13 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket;
import com.github.steveice10.packetlib.BuiltinFlags;
import com.github.steveice10.packetlib.Session;
import com.github.steveice10.packetlib.event.session.ConnectedEvent;
import com.github.steveice10.packetlib.event.session.DisconnectedEvent;
import com.github.steveice10.packetlib.event.session.PacketErrorEvent;
import com.github.steveice10.packetlib.event.session.PacketSendingEvent;
import com.github.steveice10.packetlib.event.session.SessionAdapter;
import com.github.steveice10.packetlib.event.session.*;
import com.github.steveice10.packetlib.packet.Packet;
import com.github.steveice10.packetlib.tcp.TcpClientSession;
import com.github.steveice10.packetlib.tcp.TcpSession;
import com.nimbusds.jwt.SignedJWT;
import com.nukkitx.nbt.NbtMap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import it.unimi.dsi.fastutil.bytes.ByteArrays;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@ -89,23 +82,10 @@ import lombok.experimental.Accessors;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.common.value.qual.IntRange;
import org.cloudburstmc.math.GenericMath;
import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.math.vector.Vector2i;
import org.cloudburstmc.math.vector.Vector3d;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.math.vector.*;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.BedrockServerSession;
import org.cloudburstmc.protocol.bedrock.data.Ability;
import org.cloudburstmc.protocol.bedrock.data.AbilityLayer;
import org.cloudburstmc.protocol.bedrock.data.AdventureSetting;
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.data.AuthoritativeMovementMode;
import org.cloudburstmc.protocol.bedrock.data.ChatRestrictionLevel;
import org.cloudburstmc.protocol.bedrock.data.GamePublishSetting;
import org.cloudburstmc.protocol.bedrock.data.GameRuleData;
import org.cloudburstmc.protocol.bedrock.data.GameType;
import org.cloudburstmc.protocol.bedrock.data.PlayerPermission;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.*;
import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.*;
@ -137,7 +117,6 @@ import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.level.physics.CollisionManager;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.network.netty.LocalSession;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.BlockMappings;
@ -145,20 +124,7 @@ import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.auth.AuthData;
import org.geysermc.geyser.session.auth.BedrockClientData;
import org.geysermc.geyser.session.cache.AdvancementsCache;
import org.geysermc.geyser.session.cache.BookEditCache;
import org.geysermc.geyser.session.cache.ChunkCache;
import org.geysermc.geyser.session.cache.EntityCache;
import org.geysermc.geyser.session.cache.EntityEffectCache;
import org.geysermc.geyser.session.cache.FormCache;
import org.geysermc.geyser.session.cache.LodestoneCache;
import org.geysermc.geyser.session.cache.PistonCache;
import org.geysermc.geyser.session.cache.PreferencesCache;
import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.session.cache.TagCache;
import org.geysermc.geyser.session.cache.TeleportCache;
import org.geysermc.geyser.session.cache.WorldBorder;
import org.geysermc.geyser.session.cache.WorldCache;
import org.geysermc.geyser.session.cache.*;
import org.geysermc.geyser.skin.FloodgateSkinUploader;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
@ -174,14 +140,7 @@ import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@ -336,6 +295,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
*/
@Setter
private String worldName = null;
/**
* As of Java 1.19.3, the client only uses these for commands.
*/
@Setter
private String[] levels;
private boolean sneaking;
@ -656,6 +620,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
creativePacket.setContents(this.itemMappings.getCreativeItems());
upstream.sendPacket(creativePacket);
// Potion mixes are registered by default, as they are needed to be able to put ingredients into the brewing stand.
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
craftingDataPacket.setCleanRecipes(true);
craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.get());
upstream.sendPacket(craftingDataPacket);
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
upstream.sendPacket(playStatusPacket);
@ -1389,14 +1359,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
* Sends a chat message to the Java server.
*/
public void sendChat(String message) {
sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, ByteArrays.EMPTY_ARRAY, false, Collections.emptyList(), null));
sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, null, 0, new BitSet()));
}
/**
* Sends a command to the Java server.
*/
public void sendCommand(String command) {
sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), false, Collections.emptyList(), null));
sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet()));
}
public void setServerRenderDistance(int renderDistance) {
@ -1454,7 +1424,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
startGamePacket.setRotation(Vector2f.from(1, 1));
startGamePacket.setSeed(-1L);
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(dimension));
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(chunkCache.getBedrockDimension()));
startGamePacket.setGeneratorId(1);
startGamePacket.setLevelGameType(GameType.SURVIVAL);
startGamePacket.setDifficulty(1);
@ -1655,76 +1625,40 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
boolean spectator = gameMode == GameMode.SPECTATOR;
boolean worldImmutable = gameMode == GameMode.ADVENTURE || spectator;
if (GameProtocol.supports1_19_10(this)) {
UpdateAdventureSettingsPacket adventureSettingsPacket = new UpdateAdventureSettingsPacket();
adventureSettingsPacket.setNoMvP(false);
adventureSettingsPacket.setNoPvM(false);
adventureSettingsPacket.setImmutableWorld(worldImmutable);
adventureSettingsPacket.setShowNameTags(false);
adventureSettingsPacket.setAutoJump(true);
sendUpstreamPacket(adventureSettingsPacket);
UpdateAdventureSettingsPacket adventureSettingsPacket = new UpdateAdventureSettingsPacket();
adventureSettingsPacket.setNoMvP(false);
adventureSettingsPacket.setNoPvM(false);
adventureSettingsPacket.setImmutableWorld(worldImmutable);
adventureSettingsPacket.setShowNameTags(false);
adventureSettingsPacket.setAutoJump(true);
sendUpstreamPacket(adventureSettingsPacket);
UpdateAbilitiesPacket updateAbilitiesPacket = new UpdateAbilitiesPacket();
updateAbilitiesPacket.setUniqueEntityId(bedrockId);
updateAbilitiesPacket.setCommandPermission(commandPermission);
updateAbilitiesPacket.setPlayerPermission(playerPermission);
UpdateAbilitiesPacket updateAbilitiesPacket = new UpdateAbilitiesPacket();
updateAbilitiesPacket.setUniqueEntityId(bedrockId);
updateAbilitiesPacket.setCommandPermission(commandPermission);
updateAbilitiesPacket.setPlayerPermission(playerPermission);
AbilityLayer abilityLayer = new AbilityLayer();
Set<Ability> abilities = abilityLayer.getAbilityValues();
if (canFly || spectator) {
abilities.add(Ability.MAY_FLY);
}
// Default stuff we have to fill in
abilities.add(Ability.BUILD);
abilities.add(Ability.MINE);
// Needed so you can drop items
abilities.add(Ability.DOORS_AND_SWITCHES);
if (gameMode == GameMode.CREATIVE) {
// Needed so the client doesn't attempt to take away items
abilities.add(Ability.INSTABUILD);
}
if (commandPermission == CommandPermission.GAME_DIRECTORS) {
// Fixes a bug? since 1.19.11 where the player can change their gamemode in Bedrock settings and
// a packet is not sent to the server.
// https://github.com/GeyserMC/Geyser/issues/3191
abilities.add(Ability.OPERATOR_COMMANDS);
}
if (flying || spectator) {
if (spectator && !flying) {
// We're "flying locked" in this gamemode
flying = true;
ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true);
sendDownstreamPacket(abilitiesPacket);
}
abilities.add(Ability.FLYING);
}
if (spectator) {
abilities.add(Ability.NO_CLIP);
}
abilityLayer.setLayerType(AbilityLayer.Type.BASE);
abilityLayer.setFlySpeed(flySpeed);
// https://github.com/GeyserMC/Geyser/issues/3139 as of 1.19.10
abilityLayer.setWalkSpeed(walkSpeed == 0f ? 0.01f : walkSpeed);
Collections.addAll(abilityLayer.getAbilitiesSet(), USED_ABILITIES);
updateAbilitiesPacket.getAbilityLayers().add(abilityLayer);
sendUpstreamPacket(updateAbilitiesPacket);
return;
AbilityLayer abilityLayer = new AbilityLayer();
Set<Ability> abilities = abilityLayer.getAbilityValues();
if (canFly || spectator) {
abilities.add(Ability.MAY_FLY);
}
AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket();
adventureSettingsPacket.setUniqueEntityId(bedrockId);
adventureSettingsPacket.setCommandPermission(commandPermission);
adventureSettingsPacket.setPlayerPermission(playerPermission);
// Default stuff we have to fill in
abilities.add(Ability.BUILD);
abilities.add(Ability.MINE);
// Needed so you can drop items
abilities.add(Ability.DOORS_AND_SWITCHES);
if (gameMode == GameMode.CREATIVE) {
// Needed so the client doesn't attempt to take away items
abilities.add(Ability.INSTABUILD);
}
Set<AdventureSetting> flags = adventureSettingsPacket.getSettings();
if (canFly || spectator) {
flags.add(AdventureSetting.MAY_FLY);
if (commandPermission == CommandPermission.GAME_DIRECTORS) {
// Fixes a bug? since 1.19.11 where the player can change their gamemode in Bedrock settings and
// a packet is not sent to the server.
// https://github.com/GeyserMC/Geyser/issues/3191
abilities.add(Ability.OPERATOR_COMMANDS);
}
if (flying || spectator) {
@ -1734,20 +1668,21 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true);
sendDownstreamPacket(abilitiesPacket);
}
flags.add(AdventureSetting.FLYING);
}
if (worldImmutable) {
flags.add(AdventureSetting.WORLD_IMMUTABLE);
abilities.add(Ability.FLYING);
}
if (spectator) {
flags.add(AdventureSetting.NO_CLIP);
abilities.add(Ability.NO_CLIP);
}
flags.add(AdventureSetting.AUTO_JUMP);
abilityLayer.setLayerType(AbilityLayer.Type.BASE);
abilityLayer.setFlySpeed(flySpeed);
// https://github.com/GeyserMC/Geyser/issues/3139 as of 1.19.10
abilityLayer.setWalkSpeed(walkSpeed == 0f ? 0.01f : walkSpeed);
Collections.addAll(abilityLayer.getAbilitiesSet(), USED_ABILITIES);
sendUpstreamPacket(adventureSettingsPacket);
updateAbilitiesPacket.getAbilityLayers().add(abilityLayer);
sendUpstreamPacket(updateAbilitiesPacket);
}
private int getRenderDistance() {

View file

@ -43,6 +43,8 @@ import java.util.Optional;
public class AsteriskSerializer extends StdSerializer<Object> implements ContextualSerializer {
public static final String[] NON_SENSITIVE_ADDRESSES = {"", "0.0.0.0", "localhost", "127.0.0.1", "auto", "unknown"};
public static boolean showSensitive = false;
@Target({ElementType.FIELD})
@ -91,11 +93,11 @@ public class AsteriskSerializer extends StdSerializer<Object> implements Context
}
private boolean isSensitiveIp(String ip) {
if (ip.equalsIgnoreCase("localhost") || ip.equalsIgnoreCase("auto")) {
// `auto` should not be shown unless there is an obscure issue with setting the localhost address
return false;
for (String address : NON_SENSITIVE_ADDRESSES) {
if (address.equalsIgnoreCase(ip)) {
return false;
}
}
return !ip.isEmpty() && !ip.equals("0.0.0.0") && !ip.equals("127.0.0.1");
return true;
}
}

View file

@ -25,7 +25,7 @@
package org.geysermc.geyser.text;
import com.github.steveice10.mc.protocol.data.game.BuiltinChatType;
import com.github.steveice10.mc.protocol.data.game.chat.BuiltinChatType;
import org.cloudburstmc.protocol.bedrock.packet.TextPacket;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;

View file

@ -65,8 +65,8 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran
}
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
holder.prepareInventory(this, session, inventory);
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
return holder.prepareInventory(this, session, inventory);
}
@Override

View file

@ -27,12 +27,12 @@ package org.geysermc.geyser.translator.inventory;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeOptionalStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftRecipeOptionalAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
import org.geysermc.geyser.inventory.AnvilContainer;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory;
@ -49,27 +49,29 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
}
@Override
protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) {
return action.getType() == StackRequestActionType.CRAFT_RECIPE_OPTIONAL;
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
return action.getType() == ItemStackRequestActionType.CRAFT_RECIPE_OPTIONAL;
}
@Override
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
// Guarded by shouldHandleRequestFirst check
CraftRecipeOptionalStackRequestActionData data = (CraftRecipeOptionalStackRequestActionData) request.getActions()[0];
CraftRecipeOptionalAction data = (CraftRecipeOptionalAction) request.getActions()[0];
AnvilContainer container = (AnvilContainer) inventory;
// Required as of 1.18.30 - FilterTextPackets no longer appear to be sent
String name = request.getFilterStrings()[data.getFilteredStringIndex()];
if (!Objects.equals(name, container.getNewName())) {
container.checkForRename(session, name);
if (request.getFilterStrings().length != 0) {
// Required as of 1.18.30 - FilterTextPackets no longer appear to be sent
String name = request.getFilterStrings()[data.getFilteredStringIndex()];
if (!Objects.equals(name, container.getNewName())) { // TODO is this still necessary after pre-1.19.50 support is dropped?
container.checkForRename(session, name);
}
}
return super.translateRequest(session, inventory, request);
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
return switch (slotInfoData.getContainer()) {
case ANVIL_INPUT -> 0;
case ANVIL_MATERIAL -> 1;

View file

@ -27,12 +27,8 @@ package org.geysermc.geyser.translator.inventory;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Container;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.SlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.session.GeyserSession;
public abstract class BaseInventoryTranslator extends InventoryTranslator {
@ -46,7 +42,7 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator {
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
int slotnum = slotInfoData.getSlot();
switch (slotInfoData.getContainer()) {
case HOTBAR_AND_INVENTORY:

View file

@ -27,17 +27,17 @@ package org.geysermc.geyser.translator.inventory;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetBeaconPacket;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import it.unimi.dsi.fastutil.ints.IntSets;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.BeaconPaymentStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.BeaconPaymentAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.geysermc.geyser.inventory.BeaconContainer;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
@ -105,14 +105,14 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
}
@Override
protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) {
return action.getType() == StackRequestActionType.BEACON_PAYMENT;
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
return action.getType() == ItemStackRequestActionType.BEACON_PAYMENT;
}
@Override
public ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
// Input a beacon payment
BeaconPaymentStackRequestActionData beaconPayment = (BeaconPaymentStackRequestActionData) request.getActions()[0];
BeaconPaymentAction beaconPayment = (BeaconPaymentAction) request.getActions()[0];
ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(toJava(beaconPayment.getPrimaryEffect()), toJava(beaconPayment.getSecondaryEffect()));
session.sendDownstreamPacket(packet);
return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet()));
@ -123,7 +123,7 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.BEACON_PAYMENT) {
return 0;
}

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.inventory;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.packet.ContainerSetDataPacket;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory;
@ -68,7 +68,7 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.BREWING_INPUT) {
// Ingredient
return 3;

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.inventory;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.session.GeyserSession;
@ -53,7 +53,7 @@ public class CartographyInventoryTranslator extends AbstractBlockInventoryTransl
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
return switch (slotInfoData.getContainer()) {
case CARTOGRAPHY_INPUT -> 0;
case CARTOGRAPHY_ADDITIONAL -> 1;

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.inventory;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
@ -62,7 +62,7 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.CRAFTING_INPUT) {
// Java goes from 1 - 9, left to right then up to down
// Bedrock is the same, but it starts from 32.

View file

@ -30,18 +30,14 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.Ser
import it.unimi.dsi.fastutil.ints.IntSets;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftRecipeAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.packet.PlayerEnchantOptionsPacket;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.EnchantingContainer;
import org.geysermc.geyser.inventory.GeyserEnchantOption;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.item.Enchantment;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.session.GeyserSession;
@ -107,14 +103,14 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
}
@Override
protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) {
return action.getType() == StackRequestActionType.CRAFT_RECIPE;
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
return action.getType() == ItemStackRequestActionType.CRAFT_RECIPE;
}
@Override
public ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
// Client has requested an item to be enchanted
CraftRecipeStackRequestActionData craftRecipeData = (CraftRecipeStackRequestActionData) request.getActions()[0];
CraftRecipeAction craftRecipeData = (CraftRecipeAction) request.getActions()[0];
EnchantingContainer enchantingInventory = (EnchantingContainer) inventory;
int javaSlot = -1;
for (int i = 0; i < enchantingInventory.getEnchantOptions().length; i++) {
@ -137,7 +133,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.ENCHANTING_INPUT) {
return 0;
}

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.inventory;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
@ -37,7 +37,7 @@ public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTransla
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
return switch (slotInfoData.getContainer()) {
case GRINDSTONE_INPUT -> 0;
case GRINDSTONE_ADDITIONAL -> 1;

View file

@ -30,18 +30,18 @@ import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerEntry;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemEntry;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.ResponseStatus;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.*;
import org.cloudburstmc.protocol.bedrock.packet.ItemStackResponsePacket;
import it.unimi.dsi.fastutil.ints.*;
import lombok.AllArgsConstructor;
import org.checkerframework.checker.nullness.qual.Nullable;
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.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.*;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseContainer;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseSlot;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseStatus;
import org.cloudburstmc.protocol.bedrock.packet.ItemStackResponsePacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.click.Click;
@ -105,13 +105,13 @@ public abstract class InventoryTranslator {
public final int size;
public abstract void prepareInventory(GeyserSession session, Inventory inventory);
public abstract boolean prepareInventory(GeyserSession session, Inventory inventory);
public abstract void openInventory(GeyserSession session, Inventory inventory);
public abstract void closeInventory(GeyserSession session, Inventory inventory);
public abstract void updateProperty(GeyserSession session, Inventory inventory, int key, int value);
public abstract void updateInventory(GeyserSession session, Inventory inventory);
public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot);
public abstract int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData);
public abstract int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData);
public abstract int javaSlotToBedrock(int javaSlot);
public abstract BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot);
public abstract SlotType getSlotType(int javaSlot);
@ -141,12 +141,12 @@ public abstract class InventoryTranslator {
* Should be overrided if this request matches a certain criteria and shouldn't be treated normally.
* E.G. anvil renaming or enchanting
*/
protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) {
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
return false;
}
/**
* If {@link #shouldHandleRequestFirst(StackRequestActionData, Inventory)} returns true, this will be called
* If {@link #shouldHandleRequestFirst(ItemStackRequestAction, Inventory)} returns true, this will be called
*/
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
return rejectRequest(request);
@ -158,7 +158,7 @@ public abstract class InventoryTranslator {
for (ItemStackRequest request : requests) {
ItemStackResponse response;
if (request.getActions().length > 0) {
StackRequestActionData firstAction = request.getActions()[0];
ItemStackRequestAction firstAction = request.getActions()[0];
if (shouldHandleRequestFirst(firstAction, inventory)) {
// Some special request that shouldn't be processed normally
response = translateSpecialRequest(session, inventory, request);
@ -176,7 +176,7 @@ public abstract class InventoryTranslator {
response = rejectRequest(request);
}
if (response.getResult() != ResponseStatus.OK) {
if (response.getResult() != ItemStackResponseStatus.OK) {
// Sync our copy of the inventory with Bedrock's to prevent desyncs
refresh = true;
}
@ -197,12 +197,12 @@ public abstract class InventoryTranslator {
public ItemStackResponse translateRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
ClickPlan plan = new ClickPlan(session, this, inventory);
IntSet affectedSlots = new IntOpenHashSet();
for (StackRequestActionData action : request.getActions()) {
for (ItemStackRequestAction action : request.getActions()) {
GeyserItemStack cursor = session.getPlayerInventory().getCursor();
switch (action.getType()) {
case TAKE:
case PLACE: {
TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action;
TransferItemStackRequestAction transferAction = (TransferItemStackRequestAction) action;
if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) {
if (session.getGeyser().getConfig().isDebugMode()) {
session.getGeyser().getLogger().error("DEBUG: About to reject TAKE/PLACE request made by " + session.bedrockUsername());
@ -290,9 +290,9 @@ public abstract class InventoryTranslator {
break;
}
case SWAP: {
SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action;
StackRequestSlotInfoData source = swapAction.getSource();
StackRequestSlotInfoData destination = swapAction.getDestination();
SwapAction swapAction = (SwapAction) action;
ItemStackRequestSlotData source = swapAction.getSource();
ItemStackRequestSlotData destination = swapAction.getDestination();
if (!(checkNetId(session, inventory, source) && checkNetId(session, inventory, destination))) {
if (session.getGeyser().getConfig().isDebugMode()) {
@ -352,7 +352,7 @@ public abstract class InventoryTranslator {
break;
}
case DROP: {
DropStackRequestActionData dropAction = (DropStackRequestActionData) action;
DropAction dropAction = (DropAction) action;
if (!checkNetId(session, inventory, dropAction.getSource()))
return rejectRequest(request);
@ -381,7 +381,7 @@ public abstract class InventoryTranslator {
case CONSUME: { // Tends to be called for UI inventories
if (inventory instanceof CartographyContainer) {
// TODO add this for more inventories? Only seems to glitch out the cartography table, though.
ConsumeStackRequestActionData consumeData = (ConsumeStackRequestActionData) action;
ConsumeAction consumeData = (ConsumeAction) action;
int sourceSlot = bedrockSlotToJava(consumeData.getSource());
if ((sourceSlot == 0 && inventory.getItem(1).isEmpty()) || (sourceSlot == 1 && inventory.getItem(0).isEmpty())) {
@ -436,7 +436,7 @@ public abstract class InventoryTranslator {
ClickPlan plan = new ClickPlan(session, this, inventory);
// Track all the crafting table slots to report back the contents of the slots after crafting
IntSet affectedSlots = new IntOpenHashSet();
for (StackRequestActionData action : request.getActions()) {
for (ItemStackRequestAction action : request.getActions()) {
switch (action.getType()) {
case CRAFT_RECIPE: {
if (craftState != CraftState.START) {
@ -446,7 +446,7 @@ public abstract class InventoryTranslator {
break;
}
case CRAFT_RESULTS_DEPRECATED: {
CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action;
CraftResultsDeprecatedAction deprecatedCraftAction = (CraftResultsDeprecatedAction) action;
if (craftState != CraftState.RECIPE_ID) {
return rejectRequest(request);
}
@ -467,12 +467,12 @@ public abstract class InventoryTranslator {
return rejectRequest(request);
}
craftState = CraftState.INGREDIENTS;
affectedSlots.add(bedrockSlotToJava(((ConsumeStackRequestActionData) action).getSource()));
affectedSlots.add(bedrockSlotToJava(((ConsumeAction) action).getSource()));
break;
}
case TAKE:
case PLACE: {
TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action;
TransferItemStackRequestAction transferAction = (TransferItemStackRequestAction) action;
if (craftState != CraftState.INGREDIENTS && craftState != CraftState.TRANSFER) {
return rejectRequest(request);
}
@ -556,10 +556,10 @@ public abstract class InventoryTranslator {
ClickPlan plan = new ClickPlan(session, this, inventory);
requestLoop:
for (StackRequestActionData action : request.getActions()) {
for (ItemStackRequestAction action : request.getActions()) {
switch (action.getType()) {
case CRAFT_RECIPE_AUTO: {
AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action;
AutoCraftRecipeAction autoCraftAction = (AutoCraftRecipeAction) action;
// TODO autoCraftAction#getTimesCrafted 1.17.10 ???
if (craftState != CraftState.START) {
return rejectRequest(request);
@ -601,7 +601,7 @@ public abstract class InventoryTranslator {
break;
}
case CRAFT_RESULTS_DEPRECATED: {
CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action;
CraftResultsDeprecatedAction deprecatedCraftAction = (CraftResultsDeprecatedAction) action;
if (craftState != CraftState.RECIPE_ID) {
return rejectRequest(request);
}
@ -618,7 +618,7 @@ public abstract class InventoryTranslator {
break;
}
case CONSUME: {
ConsumeStackRequestActionData consumeAction = (ConsumeStackRequestActionData) action;
ConsumeAction consumeAction = (ConsumeAction) action;
if (craftState != CraftState.DEPRECATED && craftState != CraftState.INGREDIENTS) {
return rejectRequest(request);
}
@ -647,7 +647,7 @@ public abstract class InventoryTranslator {
}
case TAKE:
case PLACE: {
TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action;
TransferItemStackRequestAction transferAction = (TransferItemStackRequestAction) action;
if (craftState != CraftState.INGREDIENTS && craftState != CraftState.TRANSFER) {
return rejectRequest(request);
}
@ -754,8 +754,8 @@ public abstract class InventoryTranslator {
}
}
protected static ItemStackResponse acceptRequest(ItemStackRequest request, List<ContainerEntry> containerEntries) {
return new ItemStackResponse(ResponseStatus.OK, request.getRequestId(), containerEntries);
protected static ItemStackResponse acceptRequest(ItemStackRequest request, List<ItemStackResponseContainer> containerEntries) {
return new ItemStackResponse(ItemStackResponseStatus.OK, request.getRequestId(), containerEntries);
}
/**
@ -775,20 +775,20 @@ public abstract class InventoryTranslator {
if (throwError && GeyserImpl.getInstance().getConfig().isDebugMode()) {
new Throwable("DEBUGGING: ItemStackRequest rejected " + request.toString()).printStackTrace();
}
return new ItemStackResponse(ResponseStatus.ERROR, request.getRequestId(), Collections.emptyList());
return new ItemStackResponse(ItemStackResponseStatus.ERROR, request.getRequestId(), Collections.emptyList());
}
/**
* Print out the contents of an ItemStackRequest, should the net ID check fail.
*/
protected void dumpStackRequestDetails(GeyserSession session, Inventory inventory, StackRequestSlotInfoData source, StackRequestSlotInfoData destination) {
protected void dumpStackRequestDetails(GeyserSession session, Inventory inventory, ItemStackRequestSlotData source, ItemStackRequestSlotData destination) {
session.getGeyser().getLogger().error("Source: " + source.toString() + " Result: " + checkNetId(session, inventory, source));
session.getGeyser().getLogger().error("Destination: " + destination.toString() + " Result: " + checkNetId(session, inventory, destination));
session.getGeyser().getLogger().error("Geyser's record of source slot: " + inventory.getItem(bedrockSlotToJava(source)));
session.getGeyser().getLogger().error("Geyser's record of destination slot: " + inventory.getItem(bedrockSlotToJava(destination)));
}
public boolean checkNetId(GeyserSession session, Inventory inventory, StackRequestSlotInfoData slotInfoData) {
public boolean checkNetId(GeyserSession session, Inventory inventory, ItemStackRequestSlotData slotInfoData) {
int netId = slotInfoData.getStackNetworkId();
// "In my testing, sometimes the client thinks the netId of an item in the crafting grid is 1, even though we never said it was.
// I think it only happens when we manually set the grid but that was my quick fix"
@ -846,30 +846,30 @@ public abstract class InventoryTranslator {
return -1;
}
protected final List<ContainerEntry> makeContainerEntries(GeyserSession session, Inventory inventory, IntSet affectedSlots) {
Map<ContainerSlotType, List<ItemEntry>> containerMap = new HashMap<>();
protected final List<ItemStackResponseContainer> makeContainerEntries(GeyserSession session, Inventory inventory, IntSet affectedSlots) {
Map<ContainerSlotType, List<ItemStackResponseSlot>> containerMap = new HashMap<>();
// Manually call iterator to prevent Integer boxing
IntIterator it = affectedSlots.iterator();
while (it.hasNext()) {
int slot = it.nextInt();
BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot);
List<ItemEntry> list = containerMap.computeIfAbsent(bedrockSlot.container(), k -> new ArrayList<>());
List<ItemStackResponseSlot> list = containerMap.computeIfAbsent(bedrockSlot.container(), k -> new ArrayList<>());
list.add(makeItemEntry(session, bedrockSlot.slot(), inventory.getItem(slot)));
}
List<ContainerEntry> containerEntries = new ArrayList<>();
for (Map.Entry<ContainerSlotType, List<ItemEntry>> entry : containerMap.entrySet()) {
containerEntries.add(new ContainerEntry(entry.getKey(), entry.getValue()));
List<ItemStackResponseContainer> containerEntries = new ArrayList<>();
for (Map.Entry<ContainerSlotType, List<ItemStackResponseSlot>> entry : containerMap.entrySet()) {
containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue()));
}
ItemEntry cursorEntry = makeItemEntry(session, 0, session.getPlayerInventory().getCursor());
containerEntries.add(new ContainerEntry(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry)));
ItemStackResponseSlot cursorEntry = makeItemEntry(session, 0, session.getPlayerInventory().getCursor());
containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry)));
return containerEntries;
}
private static ItemEntry makeItemEntry(GeyserSession session, int bedrockSlot, GeyserItemStack itemStack) {
ItemEntry itemEntry;
private static ItemStackResponseSlot makeItemEntry(GeyserSession session, int bedrockSlot, GeyserItemStack itemStack) {
ItemStackResponseSlot itemEntry;
if (!itemStack.isEmpty()) {
// As of 1.16.210: Bedrock needs confirmation on what the current item durability is.
// If 0 is sent, then Bedrock thinks the item is not damaged
@ -881,14 +881,14 @@ public abstract class InventoryTranslator {
}
}
itemEntry = new ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), "", durability);
itemEntry = new ItemStackResponseSlot((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), "", durability);
} else {
itemEntry = new ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0, "", 0);
itemEntry = new ItemStackResponseSlot((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0, "", 0);
}
return itemEntry;
}
protected static boolean isCursor(StackRequestSlotInfoData slotInfoData) {
protected static boolean isCursor(ItemStackRequestSlotData slotInfoData) {
return slotInfoData.getContainer() == ContainerSlotType.CURSOR;
}

View file

@ -31,9 +31,9 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.Ser
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
@ -55,7 +55,8 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator {
}
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
return true;
}
@Override

View file

@ -28,19 +28,19 @@ package org.geysermc.geyser.translator.inventory;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtType;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.CraftLoomStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.CraftResultsDeprecatedStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftLoomAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftResultsDeprecatedAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
@ -117,19 +117,19 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
}
@Override
protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) {
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
// If the LOOM_MATERIAL slot is not empty, we are crafting a pattern that does not come from an item
return action.getType() == StackRequestActionType.CRAFT_LOOM && inventory.getItem(2).isEmpty();
return action.getType() == ItemStackRequestActionType.CRAFT_LOOM && inventory.getItem(2).isEmpty();
}
@Override
public ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
StackRequestActionData headerData = request.getActions()[0];
StackRequestActionData data = request.getActions()[1];
if (!(headerData instanceof CraftLoomStackRequestActionData)) {
ItemStackRequestAction headerData = request.getActions()[0];
ItemStackRequestAction data = request.getActions()[1];
if (!(headerData instanceof CraftLoomAction)) {
return rejectRequest(request);
}
if (!(data instanceof CraftResultsDeprecatedStackRequestActionData craftData)) {
if (!(data instanceof CraftResultsDeprecatedAction craftData)) {
return rejectRequest(request);
}
@ -137,7 +137,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
List<NbtMap> newBlockEntityTag = craftData.getResultItems()[0].getTag().getList("Patterns", NbtType.COMPOUND);
// Get the pattern that the Bedrock client requests - the last pattern in the Patterns list
NbtMap pattern = newBlockEntityTag.get(newBlockEntityTag.size() - 1);
String bedrockPattern = ((CraftLoomStackRequestActionData) headerData).getPatternId();
String bedrockPattern = ((CraftLoomAction) headerData).getPatternId();
// Get the Java index of this pattern
int index = PATTERN_TO_INDEX.getOrDefault(bedrockPattern, -1);
@ -181,7 +181,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
return switch (slotInfoData.getContainer()) {
case LOOM_INPUT -> 0;
case LOOM_DYE -> 1;

View file

@ -31,19 +31,15 @@ import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.AutoCraftRecipeStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.AutoCraftRecipeAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftRecipeAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.MerchantContainer;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.updater.InventoryUpdater;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.session.GeyserSession;
@ -80,7 +76,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
return switch (slotInfoData.getContainer()) {
case TRADE2_INGREDIENT1 -> 0;
case TRADE2_INGREDIENT2 -> 1;
@ -98,7 +94,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
}
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
MerchantContainer merchantInventory = (MerchantContainer) inventory;
if (merchantInventory.getVillager() == null) {
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
@ -121,6 +117,8 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
merchantInventory.setVillager(villager);
}
return true;
}
@Override
@ -142,7 +140,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
// Behavior as of 1.18.10.
// We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to
// store a map of net ID to trade index on our end.
int tradeChoice = ((CraftRecipeStackRequestActionData) request.getActions()[0]).getRecipeNetworkId() - 1;
int tradeChoice = ((CraftRecipeAction) request.getActions()[0]).getRecipeNetworkId() - 1;
return handleTrade(session, inventory, request, tradeChoice);
}
@ -151,7 +149,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
// 1.18.10 update - seems impossible to call without consoles/controller input
// We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to
// store a map of net ID to trade index on our end.
int tradeChoice = ((AutoCraftRecipeStackRequestActionData) request.getActions()[0]).getRecipeNetworkId() - 1;
int tradeChoice = ((AutoCraftRecipeAction) request.getActions()[0]).getRecipeNetworkId() - 1;
return handleTrade(session, inventory, request, tradeChoice);
}

View file

@ -36,22 +36,13 @@ import it.unimi.dsi.fastutil.ints.IntSet;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.CraftCreativeStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.DestroyStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.DropStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.SwapStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.TransferStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.*;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.FakeHeadProvider;
import org.geysermc.geyser.text.GeyserLocale;
@ -174,7 +165,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
int slotnum = slotInfoData.getSlot();
switch (slotInfoData.getContainer()) {
case HOTBAR_AND_INVENTORY:
@ -246,10 +237,10 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
PlayerInventory playerInv = session.getPlayerInventory();
IntSet affectedSlots = new IntOpenHashSet();
for (StackRequestActionData action : request.getActions()) {
for (ItemStackRequestAction action : request.getActions()) {
switch (action.getType()) {
case TAKE, PLACE -> {
TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action;
TransferItemStackRequestAction transferAction = (TransferItemStackRequestAction ) action;
if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) {
return rejectRequest(request);
}
@ -296,7 +287,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
}
}
case SWAP -> {
SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action;
SwapAction swapAction = (SwapAction) action;
if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) {
return rejectRequest(request);
}
@ -336,7 +327,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
}
}
case DROP -> {
DropStackRequestActionData dropAction = (DropStackRequestActionData) action;
DropAction dropAction = (DropAction) action;
if (!checkNetId(session, inventory, dropAction.getSource())) {
return rejectRequest(request);
}
@ -364,7 +355,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
}
case DESTROY -> {
// Only called when a creative client wants to destroy an item... I think - Camotoy
DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action;
DestroyAction destroyAction = (DestroyAction) action;
if (!checkNetId(session, inventory, destroyAction.getSource())) {
return rejectRequest(request);
}
@ -403,10 +394,10 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
ItemStack javaCreativeItem = null;
IntSet affectedSlots = new IntOpenHashSet();
CraftState craftState = CraftState.START;
for (StackRequestActionData action : request.getActions()) {
for (ItemStackRequestAction action : request.getActions()) {
switch (action.getType()) {
case CRAFT_CREATIVE: {
CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action;
CraftCreativeAction creativeAction = (CraftCreativeAction) action;
if (craftState != CraftState.START) {
return rejectRequest(request);
}
@ -430,7 +421,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
break;
}
case DESTROY: {
DestroyStackRequestActionData destroyAction = (DestroyStackRequestActionData) action;
DestroyAction destroyAction = (DestroyAction) action;
if (craftState != CraftState.DEPRECATED) {
return rejectRequest(request);
}
@ -442,7 +433,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
}
case TAKE:
case PLACE: {
TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action;
TransferItemStackRequestAction transferAction = (TransferItemStackRequestAction) action;
if (!(craftState == CraftState.DEPRECATED || craftState == CraftState.TRANSFER)) {
return rejectRequest(request);
}
@ -480,7 +471,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
return rejectRequest(request);
}
DropStackRequestActionData dropAction = (DropStackRequestActionData) action;
DropAction dropAction = (DropAction) action;
if (dropAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT || dropAction.getSource().getSlot() != 50) {
return rejectRequest(request);
}
@ -517,7 +508,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
session.sendDownstreamPacket(creativePacket);
}
private static boolean isCraftingGrid(StackRequestSlotInfoData slotInfoData) {
private static boolean isCraftingGrid(ItemStackRequestSlotData slotInfoData) {
return slotInfoData.getContainer() == ContainerSlotType.CRAFTING_INPUT;
}
@ -527,7 +518,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
}
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
return true;
}
@Override

View file

@ -27,8 +27,8 @@ package org.geysermc.geyser.translator.inventory;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.inventory;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
@ -37,7 +37,7 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
return switch (slotInfoData.getContainer()) {
case SMITHING_TABLE_INPUT -> 0;
case SMITHING_TABLE_MATERIAL -> 1;

View file

@ -29,18 +29,13 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemStackResponse;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.SlotType;
import org.geysermc.geyser.inventory.StonecutterContainer;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftRecipeAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestActionType;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
import org.geysermc.geyser.inventory.*;
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.session.GeyserSession;
@ -51,14 +46,14 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl
}
@Override
protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) {
return action.getType() == StackRequestActionType.CRAFT_RECIPE;
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
return action.getType() == ItemStackRequestActionType.CRAFT_RECIPE;
}
@Override
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
// Guarded by shouldHandleRequestFirst
CraftRecipeStackRequestActionData data = (CraftRecipeStackRequestActionData) request.getActions()[0];
CraftRecipeAction data = (CraftRecipeAction) request.getActions()[0];
// Look up all possible options of cutting from this ID
GeyserStonecutterData craftingData = session.getStonecutterRecipes().get(data.getRecipeNetworkId());
@ -86,7 +81,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
return switch (slotInfoData.getContainer()) {
case STONECUTTER_INPUT -> 0;
case STONECUTTER_RESULT, CREATIVE_OUTPUT -> 1;

View file

@ -26,8 +26,8 @@
package org.geysermc.geyser.translator.inventory.chest;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
@ -41,6 +41,7 @@ import org.geysermc.geyser.level.block.DoubleChestValue;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.level.block.entity.DoubleChestBlockEntityTranslator;
import org.geysermc.geyser.util.InventoryUtils;
public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
private final int defaultJavaBlockState;
@ -51,7 +52,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
}
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
// See BlockInventoryHolder - same concept there except we're also dealing with a specific block state
if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) {
int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
@ -77,11 +78,16 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
dataPacket.setData(tag.build());
dataPacket.setBlockPosition(session.getLastInteractionBlockPosition());
session.sendUpstreamPacket(dataPacket);
return;
return true;
}
}
Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP);
Vector3i position = InventoryUtils.findAvailableWorldSpace(session);
if (position == null) {
return false;
}
Vector3i pairPosition = position.add(Vector3i.UNIT_X);
BlockDefinition definition = session.getBlockMappings().getBedrockBlock(defaultJavaBlockState);
@ -126,6 +132,8 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
session.sendUpstreamPacket(dataPacket);
inventory.setHolderPosition(position);
return true;
}
@Override

View file

@ -52,8 +52,8 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
}
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
holder.prepareInventory(this, session, inventory);
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
return holder.prepareInventory(this, session, inventory);
}
@Override

View file

@ -40,7 +40,8 @@ public abstract class AbstractHorseInventoryTranslator extends BaseInventoryTran
}
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
return true;
}
@Override

View file

@ -28,7 +28,7 @@ package org.geysermc.geyser.translator.inventory.horse;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory;
@ -52,7 +52,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.HORSE_EQUIP) {
return this.equipSlot;
}

View file

@ -26,7 +26,7 @@
package org.geysermc.geyser.translator.inventory.horse;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
import org.cloudburstmc.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
import org.geysermc.geyser.inventory.BedrockContainerSlot;
public class HorseInventoryTranslator extends AbstractHorseInventoryTranslator {
@ -35,7 +35,7 @@ public class HorseInventoryTranslator extends AbstractHorseInventoryTranslator {
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.HORSE_EQUIP) {
return slotInfoData.getSlot();
}

View file

@ -39,10 +39,10 @@ import com.github.steveice10.opennbt.tag.builtin.LongTag;
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtList;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.kyori.adventure.text.Component;
@ -380,7 +380,7 @@ public abstract class ItemTranslator {
if (tag instanceof LongArrayTag) {
//Long array tag does not exist in BE
//LongArrayTag longArrayTag = (LongArrayTag) tag;
//return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
//return new org.cloudburstmc.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
return null;
}

View file

@ -26,9 +26,9 @@
package org.geysermc.geyser.translator.inventory.item.nbt;
import com.github.steveice10.opennbt.tag.builtin.*;
import com.nukkitx.nbt.NbtList;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.ItemMapping;

View file

@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
@BlockEntity(type = BlockEntityType.BEACON)
public class BeaconBlockEntityTranslator extends BlockEntityTranslator {

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
@BlockEntity(type = BlockEntityType.BED)

View file

@ -26,9 +26,9 @@
package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtList;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.session.GeyserSession;

View file

@ -28,8 +28,8 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.util.BlockEntityUtils;
/**

View file

@ -29,8 +29,8 @@ import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.ItemMapping;

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.*;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.translator.text.MessageTranslator;

View file

@ -28,7 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.DoubleChestValue;
import org.geysermc.geyser.session.GeyserSession;

View file

@ -26,7 +26,7 @@
package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
public class EmptyBlockEntityTranslator extends BlockEntityTranslator {
@Override

View file

@ -30,9 +30,9 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.LongTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtList;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;

View file

@ -26,8 +26,8 @@
package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.session.GeyserSession;

View file

@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
@BlockEntity(type = BlockEntityType.JIGSAW)

View file

@ -29,8 +29,8 @@ import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValue
import org.cloudburstmc.math.vector.Vector3d;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;

View file

@ -26,7 +26,7 @@
package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMap;
import org.geysermc.geyser.level.block.BlockStateValues;
/**

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.translator.inventory.ShulkerInventoryTranslator;

View file

@ -28,11 +28,11 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.SignUtils;
@BlockEntity(type = BlockEntityType.SIGN)
@BlockEntity(type = {BlockEntityType.SIGN, BlockEntityType.HANGING_SIGN})
public class SignBlockEntityTranslator extends BlockEntityTranslator {
/**
* Maps a color stored in a sign's Color tag to its ARGB value.
@ -88,6 +88,7 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator {
signWidth += SignUtils.getCharacterWidth(c);
}
// todo 1.20: update for hanging signs (smaller width). Currently OK because bedrock sees hanging signs as normal signs
if (signWidth <= SignUtils.BEDROCK_CHARACTER_WIDTH_MAX) {
finalSignLine.append(c);
} else {

View file

@ -30,7 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinProvider;

View file

@ -27,8 +27,9 @@ package org.geysermc.geyser.translator.level.block.entity;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.registry.Registries;
@ -68,16 +69,18 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator {
CompoundTag spawnData = tag.get("SpawnData");
if (spawnData != null) {
String entityID = (String) ((CompoundTag) spawnData.get("entity"))
.get("id")
.getValue();
builder.put("EntityIdentifier", entityID);
StringTag idTag = ((CompoundTag) spawnData.get("entity")).get("id");
if (idTag != null) {
// As of 1.19.3, spawners can be empty
String entityId = idTag.getValue();
builder.put("EntityIdentifier", entityId);
EntityDefinition<?> definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityID);
if (definition != null) {
builder.put("DisplayEntityWidth", definition.width());
builder.put("DisplayEntityHeight", definition.height());
builder.put("DisplayEntityScale", 1.0f);
EntityDefinition<?> definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityId);
if (definition != null) {
builder.put("DisplayEntityWidth", definition.width());
builder.put("DisplayEntityHeight", definition.height());
builder.put("DisplayEntityScale", 1.0f);
}
}
}

View file

@ -28,7 +28,7 @@ package org.geysermc.geyser.translator.protocol.bedrock;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetJigsawBlockPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket;
import org.cloudburstmc.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
@ -57,6 +57,10 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
// This converts the message into the array'd message Java wants
for (char character : text.toCharArray()) {
widthCount += SignUtils.getCharacterWidth(character);
// todo 1.20: update for hanging signs (smaller width). Currently bedrock thinks hanging signs are normal,
// so it thinks hanging signs have more width than they actually do. Seems like JE just truncates it.
// If we get a return in Bedrock, or go over the character width max, that signals to use the next line.
if (character == '\n' || widthCount > SignUtils.JAVA_CHARACTER_WIDTH_MAX) {
// We need to apply some more logic if we went over the character width max

View file

@ -29,6 +29,7 @@ import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket;
import org.geysermc.common.PlatformType;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.translator.text.MessageTranslator;
@ -38,16 +39,14 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
@Override
public void translate(GeyserSession session, CommandRequestPacket packet) {
String command = packet.getCommand().replace("/", "");
String command = MessageTranslator.convertToPlainText(packet.getCommand());
if (!(session.getGeyser().getPlatformType() == PlatformType.STANDALONE
&& GeyserImpl.getInstance().commandManager().runCommand(session, command))) {
String message = packet.getCommand().trim();
if (MessageTranslator.isTooLong(message, session)) {
&& GeyserImpl.getInstance().commandManager().runCommand(session, command.substring(1)))) {
if (MessageTranslator.isTooLong(command, session)) {
return;
}
session.sendCommand(message.substring(1));
session.sendCommand(command.substring(1));
}
}
}

View file

@ -32,12 +32,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.*;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@ -47,10 +42,10 @@ import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.InventoryActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.InventorySource;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.LegacySetItemSlotData;
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryActionData;
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventorySource;
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.LegacySetItemSlotData;
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
import org.cloudburstmc.protocol.bedrock.packet.InventoryTransactionPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
@ -64,7 +59,6 @@ import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.click.Click;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
@ -73,11 +67,7 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.geyser.util.CooldownUtils;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InventoryUtils;
import org.geysermc.geyser.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -478,10 +468,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
InteractAction.ATTACK, session.isSneaking());
session.sendDownstreamPacket(attackPacket);
if (GameProtocol.supports1_19_10(session)) {
// Since 1.19.10, LevelSoundEventPackets are no longer sent by the client when attacking entities
CooldownUtils.sendCooldown(session);
}
// Since 1.19.10, LevelSoundEventPackets are no longer sent by the client when attacking entities
CooldownUtils.sendCooldown(session);
}
}
break;

View file

@ -25,9 +25,9 @@
package org.geysermc.geyser.translator.protocol.bedrock;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.packet.PositionTrackingDBClientRequestPacket;
import org.cloudburstmc.protocol.bedrock.packet.PositionTrackingDBServerBroadcastPacket;
import org.geysermc.geyser.session.GeyserSession;

View file

@ -37,21 +37,7 @@ public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
@Override
public void translate(GeyserSession session, TextPacket packet) {
String message = packet.getMessage();
// The order here is important - strip out illegal characters first, then check if it's blank
// (in case the message is blank after removing)
if (message.indexOf(ChatColor.ESCAPE) != -1) {
// Filter out all escape characters - Java doesn't let you type these
StringBuilder builder = new StringBuilder();
for (int i = 0; i < message.length(); i++) {
char c = message.charAt(i);
if (c != ChatColor.ESCAPE) {
builder.append(c);
}
}
message = builder.toString();
}
String message = MessageTranslator.convertToPlainText(packet.getMessage());
if (message.isBlank()) {
// Java Edition (as of 1.17.1) just doesn't pass on these messages, so... we won't either!

View file

@ -83,6 +83,9 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
attributesPacket.setRuntimeEntityId(entity.getGeyserId());
attributesPacket.getAttributes().addAll(entity.getAttributes().values());
session.sendUpstreamPacket(attributesPacket);
// Bounding box must be sent after a player dies and respawns since 1.19.40
entity.updateBoundingBox();
break;
case START_SWIMMING:
if (!entity.getFlag(EntityFlag.SWIMMING)) {

View file

@ -45,6 +45,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
import lombok.Getter;
import lombok.ToString;
import net.kyori.adventure.text.format.NamedTextColor;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.event.downstream.ServerDefineCommandsEvent;
import org.geysermc.geyser.command.GeyserCommandManager;
@ -138,7 +139,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
// Get and update the commandArgs list with the found arguments
if (node.getChildIndices().length >= 1) {
for (int childIndex : node.getChildIndices()) {
commandArgs.computeIfAbsent(nodeIndex, ArrayList::new).add(nodes[childIndex]);
commandArgs.computeIfAbsent(nodeIndex, ($) -> new ArrayList<>()).add(nodes[childIndex]);
}
}
@ -205,7 +206,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
if (commandNode.getChildIndices().length >= 1) {
// Create the root param node and build all the children
ParamInfo rootParam = new ParamInfo(commandNode, null);
rootParam.buildChildren(session, allNodes);
rootParam.buildChildren(new CommandBuilderContext(session), allNodes);
List<CommandParamData[]> treeData = rootParam.getTree();
@ -218,11 +219,11 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
/**
* Convert Java edition command types to Bedrock edition
*
* @param session the session
* @param context the session's command context
* @param node Command type to convert
* @return Bedrock parameter data type
*/
private static Object mapCommandType(GeyserSession session, CommandNode node) {
private static Object mapCommandType(CommandBuilderContext context, CommandNode node) {
CommandParser parser = node.getParser();
if (parser == null) {
return CommandParam.STRING;
@ -239,21 +240,24 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
case RESOURCE_LOCATION, FUNCTION -> CommandParam.FILE_PATH;
case BOOL -> ENUM_BOOLEAN;
case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc
case BLOCK_STATE -> BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.get().keySet().toArray(new String[0]);
case ITEM_STACK -> session.getItemMappings().getItemNames();
case ITEM_ENCHANTMENT -> Enchantment.JavaEnchantment.ALL_JAVA_IDENTIFIERS;
case ENTITY_SUMMON -> Registries.JAVA_ENTITY_IDENTIFIERS.get().keySet().toArray(new String[0]);
case BLOCK_STATE -> context.getBlockStates();
case ITEM_STACK -> context.session.getItemMappings().getItemNames();
case COLOR -> VALID_COLORS;
case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS;
case MOB_EFFECT -> ALL_EFFECT_IDENTIFIERS;
case RESOURCE, RESOURCE_OR_TAG -> {
String resource = ((ResourceProperties) node.getProperties()).getRegistryKey();
if (resource.equals("minecraft:attribute")) {
yield ATTRIBUTES;
} else {
yield CommandParam.STRING;
}
}
case RESOURCE -> handleResource(context, ((ResourceProperties) node.getProperties()).getRegistryKey(), false);
case RESOURCE_OR_TAG -> handleResource(context, ((ResourceProperties) node.getProperties()).getRegistryKey(), true);
case DIMENSION -> context.session.getLevels();
default -> CommandParam.STRING;
};
}
private static Object handleResource(CommandBuilderContext context, String resource, boolean tags) {
return switch (resource) {
case "minecraft:attribute" -> ATTRIBUTES;
case "minecraft:enchantment" -> Enchantment.JavaEnchantment.ALL_JAVA_IDENTIFIERS;
case "minecraft:entity_type" -> context.getEntityTypes();
case "minecraft:mob_effect" -> ALL_EFFECT_IDENTIFIERS;
case "minecraft:worldgen/biome" -> tags ? context.getBiomesWithTags() : context.getBiomes();
default -> CommandParam.STRING;
};
}
@ -261,7 +265,55 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
/**
* Stores the command description and parameter data for best optimizing the Bedrock commands packet.
*/
private static record BedrockCommandInfo(String name, String description, CommandParamData[][] paramData) implements ServerDefineCommandsEvent.CommandInfo {
private record BedrockCommandInfo(String name, String description, CommandParamData[][] paramData) implements ServerDefineCommandsEvent.CommandInfo {
}
/**
* Stores command completions so we don't have to rebuild the same values multiple times.
*/
@MonotonicNonNull
private static class CommandBuilderContext {
private final GeyserSession session;
private Object biomesWithTags;
private Object biomesNoTags;
private String[] blockStates;
private String[] entityTypes;
CommandBuilderContext(GeyserSession session) {
this.session = session;
}
private Object getBiomes() {
if (biomesNoTags != null) {
return biomesNoTags;
}
String[] identifiers = session.getGeyser().getWorldManager().getBiomeIdentifiers(false);
return (biomesNoTags = identifiers != null ? identifiers : CommandParam.STRING);
}
private Object getBiomesWithTags() {
if (biomesWithTags != null) {
return biomesWithTags;
}
String[] identifiers = session.getGeyser().getWorldManager().getBiomeIdentifiers(true);
return (biomesWithTags = identifiers != null ? identifiers : CommandParam.STRING);
}
private String[] getBlockStates() {
if (blockStates != null) {
return blockStates;
}
return (blockStates = BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.get().keySet().toArray(new String[0]));
}
private String[] getEntityTypes() {
if (entityTypes != null) {
return entityTypes;
}
return (entityTypes = Registries.JAVA_ENTITY_IDENTIFIERS.get().keySet().toArray(new String[0]));
}
}
@Getter
@ -286,10 +338,10 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
/**
* Build the array of all the child parameters (recursive)
*
* @param session the session
* @param context the session's command builder context
* @param allNodes Every command node
*/
public void buildChildren(GeyserSession session, CommandNode[] allNodes) {
public void buildChildren(CommandBuilderContext context, CommandNode[] allNodes) {
for (int paramID : paramNode.getChildIndices()) {
CommandNode paramNode = allNodes[paramID];
@ -343,7 +395,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
}
} else {
// Put the non-enum param into the list
Object mappedType = mapCommandType(session, paramNode);
Object mappedType = mapCommandType(context, paramNode);
CommandEnumData enumData = null;
CommandParam type = null;
boolean optional = this.paramNode.isExecutable();
@ -353,7 +405,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
map.put(s, Set.of());
}
enumData = new CommandEnumData(paramNode.getParser().name().toLowerCase(Locale.ROOT), map, false);
enumData = new CommandEnumData(getEnumDataName(paramNode).toLowerCase(Locale.ROOT), map, false);
} else {
type = (CommandParam) mappedType;
// Bedrock throws a fit if an optional message comes after a string or target
@ -377,10 +429,25 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
// Recursively build all child options
for (ParamInfo child : children) {
child.buildChildren(session, allNodes);
child.buildChildren(context, allNodes);
}
}
/**
* Mitigates https://github.com/GeyserMC/Geyser/issues/3411. Not a perfect solution.
*/
private static String getEnumDataName(CommandNode node) {
if (node.getProperties() instanceof ResourceProperties properties) {
String registryKey = properties.getRegistryKey();
int identifierSplit = registryKey.indexOf(':');
if (identifierSplit != -1) {
return registryKey.substring(identifierSplit);
}
return registryKey;
}
return node.getParser().name();
}
/**
* Comparing CommandNode type a and b, determine if they are in the same overload.
* <p>

View file

@ -23,27 +23,19 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.protocol.java.level;
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundCustomSoundPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDisguisedChatPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.SoundUtils;
import org.geysermc.geyser.translator.text.MessageTranslator;
@Translator(packet = ClientboundCustomSoundPacket.class)
public class JavaCustomSoundTranslator extends PacketTranslator<ClientboundCustomSoundPacket> {
@Translator(packet = ClientboundDisguisedChatPacket.class)
public class JavaDisguisedChatTranslator extends PacketTranslator<ClientboundDisguisedChatPacket> {
@Override
public void translate(GeyserSession session, ClientboundCustomSoundPacket packet) {
PlaySoundPacket playSoundPacket = new PlaySoundPacket();
playSoundPacket.setSound(SoundUtils.translatePlaySound(packet.getSound()));
playSoundPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()));
playSoundPacket.setVolume(packet.getVolume());
playSoundPacket.setPitch(packet.getPitch());
session.sendUpstreamPacket(playSoundPacket);
public void translate(GeyserSession session, ClientboundDisguisedChatPacket packet) {
MessageTranslator.handleChatPacket(session, packet.getMessage(), packet.getChatType(), packet.getTargetName(), packet.getName());
}
}

View file

@ -87,6 +87,7 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
session.getWorldCache().removeScoreboard();
}
session.setWorldName(packet.getWorldName());
session.setLevels(packet.getWorldNames());
BiomeTranslator.loadServerBiomes(session, packet.getRegistry());
session.getTagCache().clear();
@ -99,16 +100,11 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
if (needsSpawnPacket) {
// The player has yet to spawn so let's do that using some of the information in this Java packet
session.setDimension(newDimension);
session.setDimensionType(dimensions.get(newDimension));
ChunkUtils.loadDimension(session);
DimensionUtils.setBedrockDimension(session, newDimension);
session.connect();
// It is now safe to send these packets
session.getUpstream().sendPostStartGamePackets();
} else if (!session.isSpawned()) {
// Called for online mode, being presented with a GUI before logging ing
session.setDimensionType(dimensions.get(newDimension));
ChunkUtils.loadDimension(session);
}
AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket();
@ -151,5 +147,7 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
// If the player is spawning into the "fake" nether, send them some fog
session.sendFog("minecraft:fog_hell");
}
ChunkUtils.loadDimension(session);
}
}

View file

@ -26,57 +26,18 @@
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerChatPacket;
import org.cloudburstmc.protocol.bedrock.packet.TextPacket;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Translator(packet = ClientboundPlayerChatPacket.class)
public class JavaPlayerChatTranslator extends PacketTranslator<ClientboundPlayerChatPacket> {
@Override
public void translate(GeyserSession session, ClientboundPlayerChatPacket packet) {
TextPacket textPacket = new TextPacket();
textPacket.setPlatformChatId("");
textPacket.setSourceName("");
textPacket.setXuid(session.getAuthData().xuid());
textPacket.setType(TextPacket.Type.CHAT);
textPacket.setNeedsTranslation(false);
Component message = packet.getUnsignedContent() == null ? packet.getMessageDecorated() : packet.getUnsignedContent();
TextDecoration decoration = session.getChatTypes().get(packet.getChatType());
if (decoration != null) {
// As of 1.19 - do this to apply all the styling for signed messages
// Though, Bedrock cannot care about the signed stuff.
TranslatableComponent.Builder withDecoration = Component.translatable()
.key(decoration.translationKey())
.style(decoration.style());
Set<TextDecoration.Parameter> parameters = decoration.parameters();
List<Component> args = new ArrayList<>(3);
if (parameters.contains(TextDecoration.Parameter.TARGET)) {
args.add(packet.getTargetName());
}
if (parameters.contains(TextDecoration.Parameter.SENDER)) {
args.add(packet.getName());
}
if (parameters.contains(TextDecoration.Parameter.CONTENT)) {
args.add(message);
}
withDecoration.args(args);
textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.locale()));
} else {
textPacket.setMessage(MessageTranslator.convertMessage(message, session.locale()));
}
session.sendUpstreamPacket(textPacket);
Component message = packet.getUnsignedContent() == null ? Component.text(packet.getContent()) : packet.getUnsignedContent();
MessageTranslator.handleChatPacket(session, message, packet.getChatType(), packet.getTargetName(), packet.getName());
}
}

View file

@ -28,7 +28,6 @@ package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRespawnPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.LevelEventType;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
@ -37,6 +36,7 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils;
@Translator(packet = ClientboundRespawnPacket.class)
@ -83,16 +83,15 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
String newDimension = packet.getDimension();
if (!session.getDimension().equals(newDimension) || !packet.getWorldName().equals(session.getWorldName())) {
// Switching to a new world (based off the world name change); send a fake dimension change
if (!packet.getWorldName().equals(session.getWorldName()) && (session.getDimension().equals(newDimension)
// Ensure that the player never ever dimension switches to the same dimension - BAD
// Can likely be removed if the Above Bedrock Nether Building option can be removed
|| DimensionUtils.javaToBedrock(session.getDimension()) == DimensionUtils.javaToBedrock(newDimension))) {
// Switching to a new world (based off the world name change or new dimension); send a fake dimension change
if (DimensionUtils.javaToBedrock(session.getDimension()) == DimensionUtils.javaToBedrock(newDimension)) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension);
DimensionUtils.switchDimension(session, fakeDim);
}
session.setWorldName(packet.getWorldName());
DimensionUtils.switchDimension(session, newDimension);
ChunkUtils.loadDimension(session);
}
}
}

View file

@ -34,16 +34,12 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeDa
import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingRecipeData;
import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.ints.*;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.CraftingData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.CraftingData;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
@ -59,16 +55,7 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.InventoryUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID;

View file

@ -40,6 +40,6 @@ public class JavaSoundEntityTranslator extends PacketTranslator<ClientboundSound
if (entity == null) {
return;
}
SoundUtils.playBuiltinSound(session, packet.getSound(), entity.getPosition(), packet.getVolume(), packet.getPitch());
SoundUtils.playSound(session, packet.getSound(), entity.getPosition(), packet.getVolume(), packet.getPitch());
}
}

View file

@ -39,7 +39,7 @@ public class JavaPlayerCombatKillTranslator extends PacketTranslator<Clientbound
@Override
public void translate(GeyserSession session, ClientboundPlayerCombatKillPacket packet) {
if (packet.getPlayerId() == session.getPlayerEntity().getEntityId() && GameProtocol.supports1_19_10(session)) {
if (packet.getPlayerId() == session.getPlayerEntity().getEntityId()) {
Component deathMessage = packet.getMessage();
// TODO - could inject score in, but as of 1.19.10 newlines don't center and start at the left of the first text
DeathInfoPacket deathInfoPacket = new DeathInfoPacket();

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019-2022 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.translator.protocol.java.entity.player;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoRemovePacket;
import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import java.util.UUID;
@Translator(packet = ClientboundPlayerInfoRemovePacket.class)
public class JavaPlayerInfoRemoveTranslator extends PacketTranslator<ClientboundPlayerInfoRemovePacket> {
@Override
public void translate(GeyserSession session, ClientboundPlayerInfoRemovePacket packet) {
PlayerListPacket translate = new PlayerListPacket();
translate.setAction(PlayerListPacket.Action.REMOVE);
for (UUID id : packet.getProfileIds()) {
// As the player entity is no longer present, we can remove the entry
PlayerEntity entity = session.getEntityCache().removePlayerEntity(id);
if (entity != null) {
// Just remove the entity's player list status
// Don't despawn the entity - the Java server will also take care of that.
entity.setPlayerList(false);
}
if (entity == session.getPlayerEntity()) {
// If removing ourself we use our AuthData UUID
translate.getEntries().add(new PlayerListPacket.Entry(session.getAuthData().uuid()));
} else {
translate.getEntries().add(new PlayerListPacket.Entry(id));
}
}
session.sendUpstreamPacket(translate);
}
}

View file

@ -1,125 +0,0 @@
/*
* Copyright (c) 2019-2022 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.translator.protocol.java.entity.player;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@Translator(packet = ClientboundPlayerInfoPacket.class)
public class JavaPlayerInfoTranslator extends PacketTranslator<ClientboundPlayerInfoPacket> {
@Override
public void translate(GeyserSession session, ClientboundPlayerInfoPacket packet) {
if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER)
return;
PlayerListPacket translate = new PlayerListPacket();
translate.setAction(packet.getAction() == PlayerListEntryAction.ADD_PLAYER ? PlayerListPacket.Action.ADD : PlayerListPacket.Action.REMOVE);
for (PlayerListEntry entry : packet.getEntries()) {
switch (packet.getAction()) {
case ADD_PLAYER -> {
GameProfile profile = entry.getProfile();
PlayerEntity playerEntity;
boolean self = profile.getId().equals(session.getPlayerEntity().getUuid());
if (self) {
// Entity is ourself
playerEntity = session.getPlayerEntity();
} else {
playerEntity = session.getEntityCache().getPlayerEntity(profile.getId());
}
GameProfile.Property textures = profile.getProperty("textures");
String texturesProperty = textures == null ? null : textures.getValue();
if (playerEntity == null) {
// It's a new player
playerEntity = new PlayerEntity(
session,
-1,
session.getEntityCache().getNextEntityId().incrementAndGet(),
profile.getId(),
Vector3f.ZERO,
Vector3f.ZERO,
0, 0, 0,
profile.getName(),
texturesProperty
);
session.getEntityCache().addPlayerEntity(playerEntity);
} else {
playerEntity.setUsername(profile.getName());
playerEntity.setTexturesProperty(texturesProperty);
}
playerEntity.setPlayerList(true);
// We'll send our own PlayerListEntry in requestAndHandleSkinAndCape
// But we need to send other player's entries so they show up in the player list
// without processing their skin information - that'll be processed when they spawn in
if (self) {
SkinManager.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape ->
GeyserImpl.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data for " + session.getClientData().getUsername()));
} else {
playerEntity.setValid(true);
PlayerListPacket.Entry playerListEntry = SkinManager.buildCachedEntry(session, playerEntity);
translate.getEntries().add(playerListEntry);
}
}
case REMOVE_PLAYER -> {
// As the player entity is no longer present, we can remove the entry
PlayerEntity entity = session.getEntityCache().removePlayerEntity(entry.getProfile().getId());
if (entity != null) {
// Just remove the entity's player list status
// Don't despawn the entity - the Java server will also take care of that.
entity.setPlayerList(false);
}
if (entity == session.getPlayerEntity()) {
// If removing ourself we use our AuthData UUID
translate.getEntries().add(new PlayerListPacket.Entry(session.getAuthData().uuid()));
} else {
translate.getEntries().add(new PlayerListPacket.Entry(entry.getProfile().getId()));
}
}
}
}
if (!translate.getEntries().isEmpty()) {
session.sendUpstreamPacket(translate);
}
}
}

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2019-2022 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.translator.protocol.java.entity.player;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@Translator(packet = ClientboundPlayerInfoUpdatePacket.class)
public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<ClientboundPlayerInfoUpdatePacket> {
@Override
public void translate(GeyserSession session, ClientboundPlayerInfoUpdatePacket packet) {
if (!packet.getActions().contains(PlayerListEntryAction.ADD_PLAYER)) {
return;
}
PlayerListPacket translate = new PlayerListPacket();
translate.setAction(PlayerListPacket.Action.ADD);
for (PlayerListEntry entry : packet.getEntries()) {
GameProfile profile = entry.getProfile();
PlayerEntity playerEntity;
boolean self = profile.getId().equals(session.getPlayerEntity().getUuid());
if (self) {
// Entity is ourself
playerEntity = session.getPlayerEntity();
} else {
playerEntity = session.getEntityCache().getPlayerEntity(profile.getId());
}
GameProfile.Property textures = profile.getProperty("textures");
String texturesProperty = textures == null ? null : textures.getValue();
if (playerEntity == null) {
// It's a new player
playerEntity = new PlayerEntity(
session,
-1,
session.getEntityCache().getNextEntityId().incrementAndGet(),
profile.getId(),
Vector3f.ZERO,
Vector3f.ZERO,
0, 0, 0,
profile.getName(),
texturesProperty
);
session.getEntityCache().addPlayerEntity(playerEntity);
} else {
playerEntity.setUsername(profile.getName());
playerEntity.setTexturesProperty(texturesProperty);
}
playerEntity.setPlayerList(true);
// We'll send our own PlayerListEntry in requestAndHandleSkinAndCape
// But we need to send other player's entries so they show up in the player list
// without processing their skin information - that'll be processed when they spawn in
if (self) {
SkinManager.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape ->
GeyserImpl.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data for " + session.getClientData().getUsername()));
} else {
playerEntity.setValid(true);
PlayerListPacket.Entry playerListEntry = SkinManager.buildCachedEntry(session, playerEntity);
translate.getEntries().add(playerListEntry);
}
}
if (!translate.getEntries().isEmpty()) {
session.sendUpstreamPacket(translate);
}
}
}

View file

@ -31,6 +31,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.InventoryUtils;
@ -46,7 +47,7 @@ public class JavaContainerSetContentTranslator extends PacketTranslator<Clientbo
int inventorySize = inventory.getSize();
for (int i = 0; i < packet.getItems().length; i++) {
if (i > inventorySize) {
if (i >= inventorySize) {
GeyserImpl geyser = session.getGeyser();
geyser.getLogger().warning("ClientboundContainerSetContentPacket sent to " + session.bedrockUsername()
+ " that exceeds inventory size!");
@ -54,10 +55,7 @@ public class JavaContainerSetContentTranslator extends PacketTranslator<Clientbo
geyser.getLogger().debug(packet);
geyser.getLogger().debug(inventory);
}
InventoryTranslator translator = session.getInventoryTranslator();
if (translator != null) {
translator.updateInventory(session, inventory);
}
updateInventory(session, inventory, packet.getContainerId());
// 1.18.1 behavior: the previous items will be correctly set, but the state ID and carried item will not
// as this produces a stack trace on the client.
// If Java processes this correctly in the future, we can revert this behavior
@ -68,10 +66,7 @@ public class JavaContainerSetContentTranslator extends PacketTranslator<Clientbo
inventory.setItem(i, newItem, session);
}
InventoryTranslator translator = session.getInventoryTranslator();
if (translator != null) {
translator.updateInventory(session, inventory);
}
updateInventory(session, inventory, packet.getContainerId());
int stateId = packet.getStateId();
session.setEmulatePost1_16Logic(stateId > 0 || stateId != inventory.getStateId());
@ -80,4 +75,14 @@ public class JavaContainerSetContentTranslator extends PacketTranslator<Clientbo
session.getPlayerInventory().setCursor(GeyserItemStack.from(packet.getCarriedItem()), session);
InventoryUtils.updateCursor(session);
}
private void updateInventory(GeyserSession session, Inventory inventory, int containerId) {
InventoryTranslator translator = session.getInventoryTranslator();
if (containerId == 0 && !(translator instanceof PlayerInventoryTranslator)) {
// In rare cases, the window ID can still be 0 but Java treats it as valid
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateInventory(session, inventory);
} else if (translator != null) {
translator.updateInventory(session, inventory);
}
}
}

View file

@ -29,8 +29,8 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetSlotPacket;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.data.inventory.CraftingData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.CraftingData;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;

View file

@ -26,9 +26,9 @@
package org.geysermc.geyser.translator.protocol.java.inventory;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundHorseScreenOpenPacket;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.UpdateEquipPacket;
import org.geysermc.geyser.entity.type.Entity;

Some files were not shown because too many files have changed in this diff Show more