Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-20 06:50:09 +01:00
Merge pull request #3817 from GeyserMC/feature/1.20
Dieser Commit ist enthalten in:
Commit
b78ca431b6
@ -6,7 +6,7 @@ plugins {
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "org.geysermc.geyser"
|
group = "org.geysermc.geyser"
|
||||||
version = "2.1.0-SNAPSHOT"
|
version = "2.1.1-SNAPSHOT"
|
||||||
description = "Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers."
|
description = "Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers."
|
||||||
|
|
||||||
tasks.withType<JavaCompile> {
|
tasks.withType<JavaCompile> {
|
||||||
|
@ -133,6 +133,7 @@ public final class EntityDefinitions {
|
|||||||
public static final EntityDefinition<AbstractFishEntity> SALMON;
|
public static final EntityDefinition<AbstractFishEntity> SALMON;
|
||||||
public static final EntityDefinition<SheepEntity> SHEEP;
|
public static final EntityDefinition<SheepEntity> SHEEP;
|
||||||
public static final EntityDefinition<ShulkerEntity> SHULKER;
|
public static final EntityDefinition<ShulkerEntity> SHULKER;
|
||||||
|
public static final EntityDefinition<SnifferEntity> SNIFFER;
|
||||||
public static final EntityDefinition<ThrowableEntity> SHULKER_BULLET;
|
public static final EntityDefinition<ThrowableEntity> SHULKER_BULLET;
|
||||||
public static final EntityDefinition<MonsterEntity> SILVERFISH;
|
public static final EntityDefinition<MonsterEntity> SILVERFISH;
|
||||||
public static final EntityDefinition<SkeletonEntity> SKELETON;
|
public static final EntityDefinition<SkeletonEntity> SKELETON;
|
||||||
@ -235,7 +236,7 @@ public final class EntityDefinitions {
|
|||||||
.type(EntityType.EXPERIENCE_ORB)
|
.type(EntityType.EXPERIENCE_ORB)
|
||||||
.identifier("minecraft:xp_orb")
|
.identifier("minecraft:xp_orb")
|
||||||
.build();
|
.build();
|
||||||
EVOKER_FANGS = EntityDefinition.builder(EvokerFangsEntity::new) // No entity metadata to listen to as of 1.18.1
|
EVOKER_FANGS = EntityDefinition.inherited(EvokerFangsEntity::new, entityBase)
|
||||||
.type(EntityType.EVOKER_FANGS)
|
.type(EntityType.EVOKER_FANGS)
|
||||||
.height(0.8f).width(0.5f)
|
.height(0.8f).width(0.5f)
|
||||||
.identifier("minecraft:evocation_fang")
|
.identifier("minecraft:evocation_fang")
|
||||||
@ -842,6 +843,12 @@ public final class EntityDefinitions {
|
|||||||
.height(1.3f).width(0.9f)
|
.height(1.3f).width(0.9f)
|
||||||
.addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags)
|
.addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags)
|
||||||
.build();
|
.build();
|
||||||
|
SNIFFER = EntityDefinition.inherited(SnifferEntity::new, ageableEntityBase)
|
||||||
|
.type(EntityType.SNIFFER)
|
||||||
|
.height(1.75f).width(1.9f)
|
||||||
|
.addTranslator(MetadataType.SNIFFER_STATE, SnifferEntity::setSnifferState)
|
||||||
|
.addTranslator(null) // Integer, drop seed at tick
|
||||||
|
.build();
|
||||||
STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase)
|
STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase)
|
||||||
.type(EntityType.STRIDER)
|
.type(EntityType.STRIDER)
|
||||||
.height(1.7f).width(0.9f)
|
.height(1.7f).width(0.9f)
|
||||||
@ -884,7 +891,6 @@ public final class EntityDefinitions {
|
|||||||
.build();
|
.build();
|
||||||
CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase)
|
CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase)
|
||||||
.type(EntityType.CAMEL)
|
.type(EntityType.CAMEL)
|
||||||
.identifier("minecraft:llama") // todo 1.20
|
|
||||||
.height(2.375f).width(1.7f)
|
.height(2.375f).width(1.7f)
|
||||||
.addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing)
|
.addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing)
|
||||||
.addTranslator(null) // Last pose change tick
|
.addTranslator(null) // Last pose change tick
|
||||||
|
@ -35,7 +35,7 @@ import org.cloudburstmc.math.vector.Vector3f;
|
|||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
|
@ -41,7 +41,7 @@ import lombok.Setter;
|
|||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||||
|
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 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;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.SnifferState;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||||
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||||
|
import org.geysermc.geyser.entity.type.Tickable;
|
||||||
|
import org.geysermc.geyser.item.type.Item;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SnifferEntity extends AnimalEntity implements Tickable {
|
||||||
|
private static final float DIGGING_HEIGHT = EntityDefinitions.SNIFFER.height() - 0.4f;
|
||||||
|
private static final int DIG_END = 120;
|
||||||
|
private static final int DIG_START = DIG_END - 34;
|
||||||
|
|
||||||
|
private Pose pose = Pose.STANDING; // Needed to call setDimensions for DIGGING state
|
||||||
|
private int digTicks;
|
||||||
|
|
||||||
|
public SnifferEntity(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
|
||||||
|
public void setPose(Pose pose) {
|
||||||
|
this.pose = pose;
|
||||||
|
super.setPose(pose);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setDimensions(Pose pose) {
|
||||||
|
if (getFlag(EntityFlag.DIGGING)) {
|
||||||
|
setBoundingBoxHeight(DIGGING_HEIGHT);
|
||||||
|
setBoundingBoxWidth(definition.width());
|
||||||
|
} else {
|
||||||
|
super.setDimensions(pose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canEat(Item item) {
|
||||||
|
return session.getTagCache().isSnifferFood(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSnifferState(ObjectEntityMetadata<SnifferState> entityMetadata) {
|
||||||
|
SnifferState snifferState = entityMetadata.getValue();
|
||||||
|
|
||||||
|
// SnifferState.SCENTING and SnifferState.IDLING not used in bedrock
|
||||||
|
// The bedrock client does the scenting animation and sound on its own
|
||||||
|
setFlag(EntityFlag.FEELING_HAPPY, snifferState == SnifferState.FEELING_HAPPY);
|
||||||
|
setFlag(EntityFlag.SCENTING, snifferState == SnifferState.SNIFFING); // SnifferState.SNIFFING -> EntityFlag.SCENTING
|
||||||
|
setFlag(EntityFlag.SEARCHING, snifferState == SnifferState.SEARCHING);
|
||||||
|
setFlag(EntityFlag.DIGGING, snifferState == SnifferState.DIGGING);
|
||||||
|
setFlag(EntityFlag.RISING, snifferState == SnifferState.RISING);
|
||||||
|
|
||||||
|
setDimensions(pose);
|
||||||
|
|
||||||
|
if (getFlag(EntityFlag.DIGGING)) {
|
||||||
|
digTicks = DIG_END;
|
||||||
|
} else {
|
||||||
|
// Handles situations where the DIGGING state is exited earlier than expected,
|
||||||
|
// such as hitting the sniffer or joining the game while it is digging
|
||||||
|
digTicks = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
// The java client renders digging particles on its own, but bedrock does not
|
||||||
|
if (digTicks > 0 && --digTicks < DIG_START && digTicks % 5 == 0) {
|
||||||
|
Vector3f rot = Vector3f.createDirectionDeg(0, -getYaw()).mul(2.25f);
|
||||||
|
Vector3f pos = getPosition().add(rot).up(0.2f).floor(); // Handle non-full blocks
|
||||||
|
int blockId = session.getBlockMappings().getBedrockBlockId(session.getGeyser().getWorldManager().getBlockAt(session, pos.toInt().down()));
|
||||||
|
|
||||||
|
LevelEventPacket levelEventPacket = new LevelEventPacket();
|
||||||
|
levelEventPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK_NO_SOUND);
|
||||||
|
levelEventPacket.setPosition(pos);
|
||||||
|
levelEventPacket.setData(blockId);
|
||||||
|
session.sendUpstreamPacket(levelEventPacket);
|
||||||
|
|
||||||
|
if (digTicks % 10 == 0) {
|
||||||
|
LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket();
|
||||||
|
levelSoundEventPacket.setSound(SoundEvent.HIT);
|
||||||
|
levelSoundEventPacket.setPosition(pos);
|
||||||
|
levelSoundEventPacket.setExtraData(blockId);
|
||||||
|
levelSoundEventPacket.setIdentifier(":");
|
||||||
|
session.sendUpstreamPacket(levelSoundEventPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,8 +27,13 @@ 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.Pose;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.item.type.Item;
|
import org.geysermc.geyser.item.type.Item;
|
||||||
@ -42,12 +47,46 @@ public class CamelEntity extends AbstractHorseEntity {
|
|||||||
|
|
||||||
public CamelEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
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);
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
|
||||||
|
dirtyMetadata.put(EntityDataTypes.CONTAINER_TYPE, (byte) ContainerType.HORSE.getId());
|
||||||
|
|
||||||
|
// Always tamed, but not indicated in horse flags
|
||||||
|
setFlag(EntityFlag.TAMED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setHorseFlags(ByteEntityMetadata entityMetadata) {
|
||||||
protected void initializeMetadata() {
|
byte xd = entityMetadata.getPrimitiveValue();
|
||||||
super.initializeMetadata();
|
boolean saddled = (xd & 0x04) == 0x04;
|
||||||
this.dirtyMetadata.put(EntityDataTypes.VARIANT, 2); // Closest llama colour to camel
|
setFlag(EntityFlag.SADDLED, saddled);
|
||||||
|
setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
|
||||||
|
setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
|
||||||
|
|
||||||
|
// HorseFlags
|
||||||
|
// Bred 0x10
|
||||||
|
// Eating 0x20
|
||||||
|
// Open mouth 0x80
|
||||||
|
int horseFlags = 0x0;
|
||||||
|
horseFlags = (xd & 0x40) == 0x40 ? horseFlags | 0x80 : horseFlags;
|
||||||
|
|
||||||
|
// Only set eating when we don't have mouth open so a player interaction doesn't trigger the eating animation
|
||||||
|
horseFlags = (xd & 0x10) == 0x10 && (xd & 0x40) != 0x40 ? horseFlags | 0x20 : horseFlags;
|
||||||
|
|
||||||
|
// Set the flags into the horse flags
|
||||||
|
dirtyMetadata.put(EntityDataTypes.HORSE_FLAGS, horseFlags);
|
||||||
|
|
||||||
|
// Send the eating particles
|
||||||
|
// We use the wheat metadata as static particles since Java
|
||||||
|
// doesn't send over what item was used to feed the horse
|
||||||
|
if ((xd & 0x40) == 0x40) {
|
||||||
|
EntityEventPacket entityEventPacket = new EntityEventPacket();
|
||||||
|
entityEventPacket.setRuntimeEntityId(geyserId);
|
||||||
|
entityEventPacket.setType(EntityEventType.EATING_ITEM);
|
||||||
|
entityEventPacket.setData(session.getItemMappings().getStoredItems().wheat().getBedrockDefinition().getRuntimeId() << 16);
|
||||||
|
session.sendUpstreamPacket(entityEventPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows the dash meter
|
||||||
|
setFlag(EntityFlag.CAN_DASH, saddled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -55,6 +94,12 @@ public class CamelEntity extends AbstractHorseEntity {
|
|||||||
return item == Items.CACTUS;
|
return item == Items.CACTUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPose(Pose pose) {
|
||||||
|
setFlag(EntityFlag.SITTING, pose == Pose.SITTING);
|
||||||
|
super.setPose(pose);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDimensions(Pose pose) {
|
protected void setDimensions(Pose pose) {
|
||||||
if (pose == Pose.SITTING) {
|
if (pose == Pose.SITTING) {
|
||||||
|
@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanE
|
|||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||||
|
@ -33,7 +33,7 @@ import org.cloudburstmc.math.vector.Vector3i;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 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.inventory.recipe;
|
||||||
|
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescriptor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hardcoded recipe information about armor trims until further improvements can be made. This information was scraped
|
||||||
|
* from BDS 1.19.81 with a world with the next_major_update and sniffer features enabled, using ProxyPass.
|
||||||
|
*/
|
||||||
|
public class TrimRecipe {
|
||||||
|
|
||||||
|
// For TrimDataPacket, which BDS sends just before the CraftingDataPacket
|
||||||
|
public static final List<TrimPattern> PATTERNS;
|
||||||
|
public static final List<TrimMaterial> MATERIALS;
|
||||||
|
|
||||||
|
// For CraftingDataPacket
|
||||||
|
public static final String ID = "minecraft:smithing_armor_trim";
|
||||||
|
public static final ItemDescriptorWithCount BASE = tagDescriptor("minecraft:trimmable_armors");
|
||||||
|
public static final ItemDescriptorWithCount ADDITION = tagDescriptor("minecraft:trim_materials");
|
||||||
|
public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates");
|
||||||
|
|
||||||
|
static {
|
||||||
|
List<TrimPattern> patterns = new ArrayList<>(16);
|
||||||
|
patterns.add(new TrimPattern("minecraft:ward_armor_trim_smithing_template", "ward"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:sentry_armor_trim_smithing_template", "sentry"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:snout_armor_trim_smithing_template", "snout"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:dune_armor_trim_smithing_template", "dune"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:spire_armor_trim_smithing_template", "spire"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:tide_armor_trim_smithing_template", "tide"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:wild_armor_trim_smithing_template", "wild"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:rib_armor_trim_smithing_template", "rib"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:coast_armor_trim_smithing_template", "coast"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:shaper_armor_trim_smithing_template", "shaper"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:eye_armor_trim_smithing_template", "eye"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:vex_armor_trim_smithing_template", "vex"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:silence_armor_trim_smithing_template", "silence"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:wayfinder_armor_trim_smithing_template", "wayfinder"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:raiser_armor_trim_smithing_template", "raiser"));
|
||||||
|
patterns.add(new TrimPattern("minecraft:host_armor_trim_smithing_template", "host"));
|
||||||
|
PATTERNS = Collections.unmodifiableList(patterns);
|
||||||
|
|
||||||
|
List<TrimMaterial> materials = new ArrayList<>(10);
|
||||||
|
materials.add(new TrimMaterial("quartz", "§h", "minecraft:quartz"));
|
||||||
|
materials.add(new TrimMaterial("iron", "§i", "minecraft:iron_ingot"));
|
||||||
|
materials.add(new TrimMaterial("netherite", "§j", "minecraft:netherite_ingot"));
|
||||||
|
materials.add(new TrimMaterial("redstone", "§m", "minecraft:redstone"));
|
||||||
|
materials.add(new TrimMaterial("copper", "§n", "minecraft:copper_ingot"));
|
||||||
|
materials.add(new TrimMaterial("gold", "§p", "minecraft:gold_ingot"));
|
||||||
|
materials.add(new TrimMaterial("emerald", "§q", "minecraft:emerald"));
|
||||||
|
materials.add(new TrimMaterial("diamond", "§s", "minecraft:diamond"));
|
||||||
|
materials.add(new TrimMaterial("lapis", "§t", "minecraft:lapis_lazuli"));
|
||||||
|
materials.add(new TrimMaterial("amethyst", "§u", "minecraft:amethyst_shard"));
|
||||||
|
MATERIALS = Collections.unmodifiableList(materials);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrimRecipe() {
|
||||||
|
//no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ItemDescriptorWithCount tagDescriptor(String tag) {
|
||||||
|
return new ItemDescriptorWithCount(new ItemTagDescriptor(tag), 1);
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.item;
|
package org.geysermc.geyser.item;
|
||||||
|
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket;
|
import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket;
|
||||||
|
|
||||||
|
@ -84,6 +84,7 @@ public final class Items {
|
|||||||
public static final Item BEDROCK = register(new BlockItem("bedrock", builder()));
|
public static final Item BEDROCK = register(new BlockItem("bedrock", builder()));
|
||||||
public static final Item SAND = register(new BlockItem("sand", builder()));
|
public static final Item SAND = register(new BlockItem("sand", builder()));
|
||||||
public static final Item SUSPICIOUS_SAND = register(new BlockItem("suspicious_sand", builder()));
|
public static final Item SUSPICIOUS_SAND = register(new BlockItem("suspicious_sand", builder()));
|
||||||
|
public static final Item SUSPICIOUS_GRAVEL = register(new BlockItem("suspicious_gravel", builder()));
|
||||||
public static final Item RED_SAND = register(new BlockItem("red_sand", builder()));
|
public static final Item RED_SAND = register(new BlockItem("red_sand", builder()));
|
||||||
public static final Item GRAVEL = register(new BlockItem("gravel", builder()));
|
public static final Item GRAVEL = register(new BlockItem("gravel", builder()));
|
||||||
public static final Item COAL_ORE = register(new BlockItem("coal_ore", builder()));
|
public static final Item COAL_ORE = register(new BlockItem("coal_ore", builder()));
|
||||||
@ -247,6 +248,7 @@ public final class Items {
|
|||||||
public static final Item LILY_OF_THE_VALLEY = register(new FlowerItem("lily_of_the_valley", builder()));
|
public static final Item LILY_OF_THE_VALLEY = register(new FlowerItem("lily_of_the_valley", builder()));
|
||||||
public static final Item WITHER_ROSE = register(new FlowerItem("wither_rose", builder()));
|
public static final Item WITHER_ROSE = register(new FlowerItem("wither_rose", builder()));
|
||||||
public static final Item TORCHFLOWER = register(new FlowerItem("torchflower", builder()));
|
public static final Item TORCHFLOWER = register(new FlowerItem("torchflower", builder()));
|
||||||
|
public static final Item PITCHER_PLANT = register(new BlockItem("pitcher_plant", builder()));
|
||||||
public static final Item SPORE_BLOSSOM = register(new BlockItem("spore_blossom", builder()));
|
public static final Item SPORE_BLOSSOM = register(new BlockItem("spore_blossom", builder()));
|
||||||
public static final Item BROWN_MUSHROOM = register(new BlockItem("brown_mushroom", builder()));
|
public static final Item BROWN_MUSHROOM = register(new BlockItem("brown_mushroom", builder()));
|
||||||
public static final Item RED_MUSHROOM = register(new BlockItem("red_mushroom", builder()));
|
public static final Item RED_MUSHROOM = register(new BlockItem("red_mushroom", builder()));
|
||||||
@ -602,6 +604,7 @@ public final class Items {
|
|||||||
public static final Item RED_CONCRETE_POWDER = register(new BlockItem("red_concrete_powder", builder()));
|
public static final Item RED_CONCRETE_POWDER = register(new BlockItem("red_concrete_powder", builder()));
|
||||||
public static final Item BLACK_CONCRETE_POWDER = register(new BlockItem("black_concrete_powder", builder()));
|
public static final Item BLACK_CONCRETE_POWDER = register(new BlockItem("black_concrete_powder", builder()));
|
||||||
public static final Item TURTLE_EGG = register(new BlockItem("turtle_egg", builder()));
|
public static final Item TURTLE_EGG = register(new BlockItem("turtle_egg", builder()));
|
||||||
|
public static final Item SNIFFER_EGG = register(new BlockItem("sniffer_egg", builder()));
|
||||||
public static final Item DEAD_TUBE_CORAL_BLOCK = register(new BlockItem("dead_tube_coral_block", builder()));
|
public static final Item DEAD_TUBE_CORAL_BLOCK = register(new BlockItem("dead_tube_coral_block", builder()));
|
||||||
public static final Item DEAD_BRAIN_CORAL_BLOCK = register(new BlockItem("dead_brain_coral_block", builder()));
|
public static final Item DEAD_BRAIN_CORAL_BLOCK = register(new BlockItem("dead_brain_coral_block", builder()));
|
||||||
public static final Item DEAD_BUBBLE_CORAL_BLOCK = register(new BlockItem("dead_bubble_coral_block", builder()));
|
public static final Item DEAD_BUBBLE_CORAL_BLOCK = register(new BlockItem("dead_bubble_coral_block", builder()));
|
||||||
@ -689,6 +692,7 @@ public final class Items {
|
|||||||
public static final Item LIGHTNING_ROD = register(new BlockItem("lightning_rod", builder()));
|
public static final Item LIGHTNING_ROD = register(new BlockItem("lightning_rod", builder()));
|
||||||
public static final Item DAYLIGHT_DETECTOR = register(new BlockItem("daylight_detector", builder()));
|
public static final Item DAYLIGHT_DETECTOR = register(new BlockItem("daylight_detector", builder()));
|
||||||
public static final Item SCULK_SENSOR = register(new BlockItem("sculk_sensor", builder()));
|
public static final Item SCULK_SENSOR = register(new BlockItem("sculk_sensor", builder()));
|
||||||
|
public static final Item CALIBRATED_SCULK_SENSOR = register(new BlockItem("calibrated_sculk_sensor", builder()));
|
||||||
public static final Item TRIPWIRE_HOOK = register(new BlockItem("tripwire_hook", builder()));
|
public static final Item TRIPWIRE_HOOK = register(new BlockItem("tripwire_hook", builder()));
|
||||||
public static final Item TRAPPED_CHEST = register(new BlockItem("trapped_chest", builder()));
|
public static final Item TRAPPED_CHEST = register(new BlockItem("trapped_chest", builder()));
|
||||||
public static final Item TNT = register(new BlockItem("tnt", builder()));
|
public static final Item TNT = register(new BlockItem("tnt", builder()));
|
||||||
@ -1141,6 +1145,7 @@ public final class Items {
|
|||||||
public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder()));
|
public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder()));
|
||||||
public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder()));
|
public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder()));
|
||||||
public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder()));
|
public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder()));
|
||||||
|
public static final Item PITCHER_POD = register(new BlockItem("pitcher_pod", builder()));
|
||||||
public static final Item BEETROOT = register(new Item("beetroot", builder()));
|
public static final Item BEETROOT = register(new Item("beetroot", builder()));
|
||||||
public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder()));
|
public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder()));
|
||||||
public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1)));
|
public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1)));
|
||||||
@ -1168,6 +1173,7 @@ public final class Items {
|
|||||||
public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1)));
|
public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1)));
|
||||||
public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1)));
|
public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1)));
|
||||||
public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1)));
|
public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1)));
|
||||||
|
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1)));
|
||||||
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1)));
|
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1)));
|
||||||
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1)));
|
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1)));
|
||||||
public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder()));
|
public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder()));
|
||||||
@ -1262,10 +1268,31 @@ public final class Items {
|
|||||||
public static final Item SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("snout_armor_trim_smithing_template", builder()));
|
public static final Item SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("snout_armor_trim_smithing_template", builder()));
|
||||||
public static final Item RIB_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("rib_armor_trim_smithing_template", builder()));
|
public static final Item RIB_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("rib_armor_trim_smithing_template", builder()));
|
||||||
public static final Item SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("spire_armor_trim_smithing_template", builder()));
|
public static final Item SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("spire_armor_trim_smithing_template", builder()));
|
||||||
public static final Item POTTERY_SHARD_ARCHER = register(new Item("pottery_shard_archer", builder()));
|
public static final Item WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("wayfinder_armor_trim_smithing_template", builder()));
|
||||||
public static final Item POTTERY_SHARD_PRIZE = register(new Item("pottery_shard_prize", builder()));
|
public static final Item SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("shaper_armor_trim_smithing_template", builder()));
|
||||||
public static final Item POTTERY_SHARD_ARMS_UP = register(new Item("pottery_shard_arms_up", builder()));
|
public static final Item SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("silence_armor_trim_smithing_template", builder()));
|
||||||
public static final Item POTTERY_SHARD_SKULL = register(new Item("pottery_shard_skull", builder()));
|
public static final Item RAISER_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("raiser_armor_trim_smithing_template", builder()));
|
||||||
|
public static final Item HOST_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("host_armor_trim_smithing_template", builder()));
|
||||||
|
public static final Item ANGLER_POTTERY_SHERD = register(new Item("angler_pottery_sherd", builder()));
|
||||||
|
public static final Item ARCHER_POTTERY_SHERD = register(new Item("archer_pottery_sherd", builder()));
|
||||||
|
public static final Item ARMS_UP_POTTERY_SHERD = register(new Item("arms_up_pottery_sherd", builder()));
|
||||||
|
public static final Item BLADE_POTTERY_SHERD = register(new Item("blade_pottery_sherd", builder()));
|
||||||
|
public static final Item BREWER_POTTERY_SHERD = register(new Item("brewer_pottery_sherd", builder()));
|
||||||
|
public static final Item BURN_POTTERY_SHERD = register(new Item("burn_pottery_sherd", builder()));
|
||||||
|
public static final Item DANGER_POTTERY_SHERD = register(new Item("danger_pottery_sherd", builder()));
|
||||||
|
public static final Item EXPLORER_POTTERY_SHERD = register(new Item("explorer_pottery_sherd", builder()));
|
||||||
|
public static final Item FRIEND_POTTERY_SHERD = register(new Item("friend_pottery_sherd", builder()));
|
||||||
|
public static final Item HEART_POTTERY_SHERD = register(new Item("heart_pottery_sherd", builder()));
|
||||||
|
public static final Item HEARTBREAK_POTTERY_SHERD = register(new Item("heartbreak_pottery_sherd", builder()));
|
||||||
|
public static final Item HOWL_POTTERY_SHERD = register(new Item("howl_pottery_sherd", builder()));
|
||||||
|
public static final Item MINER_POTTERY_SHERD = register(new Item("miner_pottery_sherd", builder()));
|
||||||
|
public static final Item MOURNER_POTTERY_SHERD = register(new Item("mourner_pottery_sherd", builder()));
|
||||||
|
public static final Item PLENTY_POTTERY_SHERD = register(new Item("plenty_pottery_sherd", builder()));
|
||||||
|
public static final Item PRIZE_POTTERY_SHERD = register(new Item("prize_pottery_sherd", builder()));
|
||||||
|
public static final Item SHEAF_POTTERY_SHERD = register(new Item("sheaf_pottery_sherd", builder()));
|
||||||
|
public static final Item SHELTER_POTTERY_SHERD = register(new Item("shelter_pottery_sherd", builder()));
|
||||||
|
public static final Item SKULL_POTTERY_SHERD = register(new Item("skull_pottery_sherd", builder()));
|
||||||
|
public static final Item SNORT_POTTERY_SHERD = register(new Item("snort_pottery_sherd", builder()));
|
||||||
|
|
||||||
private static <T extends Item> T register(T item) {
|
private static <T extends Item> T register(T item) {
|
||||||
return register(item, Registries.JAVA_ITEMS.get().size());
|
return register(item, Registries.JAVA_ITEMS.get().size());
|
||||||
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.item.type;
|
|||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.inventory.item.Potion;
|
import org.geysermc.geyser.inventory.item.Potion;
|
||||||
|
@ -25,13 +25,40 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.item.type;
|
package org.geysermc.geyser.item.type;
|
||||||
|
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.item.components.ToolTier;
|
import org.geysermc.geyser.item.components.ToolTier;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
public class ShieldItem extends Item {
|
public class ShieldItem extends Item {
|
||||||
public ShieldItem(String javaIdentifier, Builder builder) {
|
public ShieldItem(String javaIdentifier, Builder builder) {
|
||||||
super(javaIdentifier, builder);
|
super(javaIdentifier, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) {
|
||||||
|
super.translateNbtToBedrock(session, tag);
|
||||||
|
|
||||||
|
if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) {
|
||||||
|
if (blockEntityTag.get("Patterns") instanceof ListTag patterns) {
|
||||||
|
for (Tag pattern : patterns) {
|
||||||
|
if (((CompoundTag) pattern).get("Color") instanceof IntTag color) {
|
||||||
|
color.setValue(15 - color.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Bedrock looks for patterns at the root
|
||||||
|
tag.put(patterns);
|
||||||
|
}
|
||||||
|
if (blockEntityTag.get("Base") instanceof IntTag base) {
|
||||||
|
base.setValue(15 - base.getValue());
|
||||||
|
tag.put(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidRepairItem(Item other) {
|
public boolean isValidRepairItem(Item other) {
|
||||||
// Java Edition 1.19.3 checks the tag, but TODO check to see if we want it or are simulating what Bedrock is doing
|
// Java Edition 1.19.3 checks the tag, but TODO check to see if we want it or are simulating what Bedrock is doing
|
||||||
|
@ -45,6 +45,7 @@ import java.util.Locale;
|
|||||||
*/
|
*/
|
||||||
public final class BlockStateValues {
|
public final class BlockStateValues {
|
||||||
private static final IntSet ALL_CAULDRONS = new IntOpenHashSet();
|
private static final IntSet ALL_CAULDRONS = new IntOpenHashSet();
|
||||||
|
private static final IntSet HANGING_SIGNS = new IntOpenHashSet();
|
||||||
private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap();
|
private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap();
|
||||||
private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap();
|
private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap();
|
||||||
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
|
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
|
||||||
@ -86,6 +87,12 @@ public final class BlockStateValues {
|
|||||||
* @param blockData JsonNode of info about the block from blocks.json
|
* @param blockData JsonNode of info about the block from blocks.json
|
||||||
*/
|
*/
|
||||||
public static void storeBlockStateValues(String javaId, int javaBlockState, JsonNode blockData) {
|
public static void storeBlockStateValues(String javaId, int javaBlockState, JsonNode blockData) {
|
||||||
|
if (javaId.contains("_hanging_sign")) {
|
||||||
|
// covers hanging_sign and wall_hanging_sign
|
||||||
|
HANGING_SIGNS.add(javaBlockState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
JsonNode bannerColor = blockData.get("banner_color");
|
JsonNode bannerColor = blockData.get("banner_color");
|
||||||
if (bannerColor != null) {
|
if (bannerColor != null) {
|
||||||
BANNER_COLORS.put(javaBlockState, (byte) bannerColor.intValue());
|
BANNER_COLORS.put(javaBlockState, (byte) bannerColor.intValue());
|
||||||
@ -203,6 +210,17 @@ public final class BlockStateValues {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hanging signs have a different maximum text width than "normal" signs. As a result, when the client
|
||||||
|
* updates the text of a sign without indication of the sign type, we must determine it.
|
||||||
|
*
|
||||||
|
* @param state BlockState of the block
|
||||||
|
* @return true if the sign is any hanging variant
|
||||||
|
*/
|
||||||
|
public static boolean isHangingSign(int state) {
|
||||||
|
return HANGING_SIGNS.contains(state);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Banner colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
|
* Banner colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
|
||||||
* This gives an integer color that Bedrock can use.
|
* This gives an integer color that Bedrock can use.
|
||||||
|
@ -28,12 +28,8 @@ package org.geysermc.geyser.network;
|
|||||||
import com.github.steveice10.mc.protocol.codec.MinecraftCodec;
|
import com.github.steveice10.mc.protocol.codec.MinecraftCodec;
|
||||||
import com.github.steveice10.mc.protocol.codec.PacketCodec;
|
import com.github.steveice10.mc.protocol.codec.PacketCodec;
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v557.Bedrock_v557;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v568.Bedrock_v568;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
|
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
|
||||||
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
|
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
@ -49,9 +45,8 @@ public final class GameProtocol {
|
|||||||
* Default Bedrock codec that should act as a fallback. Should represent the latest available
|
* Default Bedrock codec that should act as a fallback. Should represent the latest available
|
||||||
* release of the game that Geyser supports.
|
* release of the game that Geyser supports.
|
||||||
*/
|
*/
|
||||||
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v582.CODEC.toBuilder()
|
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v589.CODEC;
|
||||||
.minecraftVersion("1.19.81")
|
|
||||||
.build();
|
|
||||||
/**
|
/**
|
||||||
* A list of all supported Bedrock versions that can join Geyser
|
* A list of all supported Bedrock versions that can join Geyser
|
||||||
*/
|
*/
|
||||||
@ -64,20 +59,10 @@ public final class GameProtocol {
|
|||||||
private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC;
|
private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.CODEC.toBuilder()
|
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v582.CODEC.toBuilder()
|
||||||
.minecraftVersion("1.19.40/1.19.41")
|
|
||||||
.build());
|
|
||||||
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v560.CODEC.toBuilder()
|
|
||||||
.minecraftVersion("1.19.50/1.19.51")
|
|
||||||
.build());
|
|
||||||
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.CODEC);
|
|
||||||
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v568.CODEC);
|
|
||||||
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v575.CODEC.toBuilder()
|
|
||||||
.minecraftVersion("1.19.70/1.19.71/1.19.73")
|
|
||||||
.build());
|
|
||||||
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
|
|
||||||
.minecraftVersion("1.19.80/1.19.81")
|
.minecraftVersion("1.19.80/1.19.81")
|
||||||
.build());
|
.build());
|
||||||
|
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,16 +81,8 @@ public final class GameProtocol {
|
|||||||
|
|
||||||
/* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */
|
/* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */
|
||||||
|
|
||||||
public static boolean supports1_19_50(GeyserSession session) {
|
public static boolean isPre1_20(GeyserSession session) {
|
||||||
return session.getUpstream().getProtocolVersion() >= Bedrock_v560.CODEC.getProtocolVersion();
|
return session.getUpstream().getProtocolVersion() < Bedrock_v589.CODEC.getProtocolVersion();
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean supports1_19_60(GeyserSession session) {
|
|
||||||
return session.getUpstream().getProtocolVersion() >= Bedrock_v567.CODEC.getProtocolVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean supports1_19_80(GeyserSession session) {
|
|
||||||
return session.getUpstream().getProtocolVersion() >= Bedrock_v582.CODEC.getProtocolVersion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,11 +47,6 @@ public class GeyserServerInitializer extends BedrockServerInitializer {
|
|||||||
this.geyser = geyser;
|
this.geyser = geyser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void postInitChannel(Channel channel) throws Exception {
|
|
||||||
super.postInitChannel(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initSession(@Nonnull BedrockServerSession bedrockServerSession) {
|
public void initSession(@Nonnull BedrockServerSession bedrockServerSession) {
|
||||||
try {
|
try {
|
||||||
|
@ -28,8 +28,6 @@ package org.geysermc.geyser.network;
|
|||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons;
|
import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons;
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v568.Bedrock_v568;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.data.ExperimentData;
|
import org.cloudburstmc.protocol.bedrock.data.ExperimentData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;
|
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.ResourcePackType;
|
import org.cloudburstmc.protocol.bedrock.data.ResourcePackType;
|
||||||
@ -173,11 +171,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||||||
return PacketSignal.HANDLED;
|
return PacketSignal.HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack for... whatever this is
|
|
||||||
if (loginPacket.getProtocolVersion() == Bedrock_v567.CODEC.getProtocolVersion() && !session.getClientData().getGameVersion().equals("1.19.60")) {
|
|
||||||
session.getUpstream().getSession().setCodec(Bedrock_v568.CODEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayStatusPacket playStatus = new PlayStatusPacket();
|
PlayStatusPacket playStatus = new PlayStatusPacket();
|
||||||
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
|
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
|
||||||
session.sendUpstreamPacket(playStatus);
|
session.sendUpstreamPacket(playStatus);
|
||||||
@ -232,6 +225,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||||||
stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true));
|
stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GameProtocol.isPre1_20(session)) {
|
||||||
|
stackPacket.getExperiments().add(new ExperimentData("next_major_update", true));
|
||||||
|
stackPacket.getExperiments().add(new ExperimentData("sniffer", true));
|
||||||
|
}
|
||||||
|
|
||||||
session.sendUpstreamPacket(stackPacket);
|
session.sendUpstreamPacket(stackPacket);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -32,12 +32,9 @@ import com.google.common.collect.Interner;
|
|||||||
import com.google.common.collect.Interners;
|
import com.google.common.collect.Interners;
|
||||||
import it.unimi.dsi.fastutil.objects.*;
|
import it.unimi.dsi.fastutil.objects.*;
|
||||||
import org.cloudburstmc.nbt.*;
|
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.codec.v567.Bedrock_v567;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
|
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
import org.geysermc.geyser.level.physics.PistonBehavior;
|
import org.geysermc.geyser.level.physics.PistonBehavior;
|
||||||
@ -70,41 +67,54 @@ public final class BlockRegistryPopulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void registerBedrockBlocks() {
|
private static void registerBedrockBlocks() {
|
||||||
BiFunction<String, NbtMapBuilder, String> woolMapper = (bedrockIdentifier, statesBuilder) -> {
|
BiFunction<String, NbtMapBuilder, String> emptyMapper = (bedrockIdentifier, statesBuilder) -> null;
|
||||||
if (bedrockIdentifier.equals("minecraft:wool")) {
|
|
||||||
String color = (String) statesBuilder.remove("color");
|
// We are using mappings that directly support 1.20, so this maps it back to 1.19.80
|
||||||
if ("silver".equals(color)) {
|
BiFunction<String, NbtMapBuilder, String> legacyMapper = (bedrockIdentifier, statesBuilder) -> {
|
||||||
color = "light_gray";
|
if (bedrockIdentifier.endsWith("pumpkin")) {
|
||||||
|
String direction = statesBuilder.remove("minecraft:cardinal_direction").toString();
|
||||||
|
statesBuilder.putInt("direction", switch (direction) {
|
||||||
|
case "north" -> 2;
|
||||||
|
case "east" -> 3;
|
||||||
|
case "west" -> 1;
|
||||||
|
default -> 0; // south
|
||||||
|
});
|
||||||
|
} else if (bedrockIdentifier.endsWith("carpet") && !bedrockIdentifier.startsWith("minecraft:moss")) {
|
||||||
|
String color = bedrockIdentifier.replace("minecraft:", "").replace("_carpet", "");
|
||||||
|
if (color.equals("light_gray")) {
|
||||||
|
color = "silver";
|
||||||
}
|
}
|
||||||
return "minecraft:" + color + "_wool";
|
statesBuilder.putString("color", color);
|
||||||
|
return "minecraft:carpet";
|
||||||
|
} else if (bedrockIdentifier.equals("minecraft:sniffer_egg")) {
|
||||||
|
statesBuilder.remove("cracked_state");
|
||||||
|
return "minecraft:dragon_egg";
|
||||||
|
} else if (bedrockIdentifier.endsWith("coral")) {
|
||||||
|
statesBuilder.putString("coral_color", "blue"); // all blue
|
||||||
|
statesBuilder.putBoolean("dead_bit", bedrockIdentifier.startsWith("minecraft:dead"));
|
||||||
|
return "minecraft:coral";
|
||||||
|
} else if (bedrockIdentifier.endsWith("sculk_sensor")) {
|
||||||
|
int phase = (int) statesBuilder.remove("sculk_sensor_phase");
|
||||||
|
statesBuilder.putBoolean("powered_bit", phase != 0);
|
||||||
|
} else if (bedrockIdentifier.endsWith("pitcher_plant")) {
|
||||||
|
statesBuilder.putString("double_plant_type", "sunflower");
|
||||||
|
return "minecraft:double_plant";
|
||||||
|
} else if (bedrockIdentifier.endsWith("pitcher_crop")) {
|
||||||
|
statesBuilder.remove("growth");
|
||||||
|
if (((byte) statesBuilder.remove("upper_block_bit")) == 1){
|
||||||
|
statesBuilder.putString("flower_type", "orchid");
|
||||||
|
return "minecraft:red_flower"; // top
|
||||||
|
}
|
||||||
|
statesBuilder.putBoolean("update_bit", false);
|
||||||
|
return "minecraft:flower_pot"; // bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
BiFunction<String, NbtMapBuilder, String> emptyMapper = (bedrockIdentifier, statesBuilder) -> null;
|
|
||||||
ImmutableMap<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> blockMappers = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder()
|
ImmutableMap<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> blockMappers = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder()
|
||||||
.put(ObjectIntPair.of("1_19_20", Bedrock_v544.CODEC.getProtocolVersion()), emptyMapper)
|
.put(ObjectIntPair.of("1_19_80", Bedrock_v582.CODEC.getProtocolVersion()), legacyMapper)
|
||||||
.put(ObjectIntPair.of("1_19_50", Bedrock_v560.CODEC.getProtocolVersion()), emptyMapper)
|
.put(ObjectIntPair.of("1_20_0", Bedrock_v589.CODEC.getProtocolVersion()), emptyMapper)
|
||||||
.put(ObjectIntPair.of("1_19_60", Bedrock_v567.CODEC.getProtocolVersion()), emptyMapper)
|
|
||||||
.put(ObjectIntPair.of("1_19_70", Bedrock_v575.CODEC.getProtocolVersion()), woolMapper)
|
|
||||||
.put(ObjectIntPair.of("1_19_80", Bedrock_v582.CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> {
|
|
||||||
String identifier = woolMapper.apply(bedrockIdentifier, statesBuilder);
|
|
||||||
if (identifier != null) {
|
|
||||||
return identifier;
|
|
||||||
}
|
|
||||||
switch (bedrockIdentifier) {
|
|
||||||
case "minecraft:log", "minecraft:log2" -> {
|
|
||||||
String woodType = (String) statesBuilder.remove(bedrockIdentifier.equals("minecraft:log") ? "old_log_type" : "new_log_type");
|
|
||||||
return "minecraft:" + woodType + "_log";
|
|
||||||
}
|
|
||||||
case "minecraft:fence" -> {
|
|
||||||
String woodType = (String) statesBuilder.remove("wood_type");
|
|
||||||
return "minecraft:" + woodType + "_fence";
|
|
||||||
}
|
|
||||||
default -> {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// We can keep this strong as nothing should be garbage collected
|
// We can keep this strong as nothing should be garbage collected
|
||||||
@ -167,8 +177,8 @@ public final class BlockRegistryPopulator {
|
|||||||
|
|
||||||
GeyserBedrockBlock bedrockDefinition = blockStateOrderedMap.get(buildBedrockState(entry.getValue(), stateVersion, stateMapper));
|
GeyserBedrockBlock bedrockDefinition = blockStateOrderedMap.get(buildBedrockState(entry.getValue(), stateVersion, stateMapper));
|
||||||
if (bedrockDefinition == null) {
|
if (bedrockDefinition == null) {
|
||||||
throw new RuntimeException("Unable to find " + javaId + " Bedrock BlockDefinition! Built NBT tag: \n" +
|
throw new RuntimeException("Unable to find " + javaId + " Bedrock BlockDefinition on version "
|
||||||
buildBedrockState(entry.getValue(), stateVersion, stateMapper));
|
+ palette.getKey().key() + "! Built NBT tag: \n" + buildBedrockState(entry.getValue(), stateVersion, stateMapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (javaId) {
|
switch (javaId) {
|
||||||
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.registry.populator;
|
|||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtUtils;
|
import org.cloudburstmc.nbt.NbtUtils;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
@ -30,8 +30,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
import org.cloudburstmc.nbt.NbtType;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.item.custom.CustomItemData;
|
import org.geysermc.geyser.api.item.custom.CustomItemData;
|
||||||
|
@ -34,17 +34,15 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import it.unimi.dsi.fastutil.objects.*;
|
import it.unimi.dsi.fastutil.objects.*;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
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.codec.v567.Bedrock_v567;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
|
import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.codec.v589.Bedrock_v589;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||||
@ -70,22 +68,40 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
*/
|
*/
|
||||||
public class ItemRegistryPopulator {
|
public class ItemRegistryPopulator {
|
||||||
|
|
||||||
record PaletteVersion(int protocolVersion, Map<Item, String> additionalTranslatedItems) {
|
record PaletteVersion(int protocolVersion, Map<Item, String> javaOnlyItems, Remapper remapper) {
|
||||||
|
|
||||||
|
public PaletteVersion(int protocolVersion) {
|
||||||
|
this(protocolVersion, Collections.emptyMap(), (item, mapping) -> mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface Remapper {
|
||||||
|
@NonNull
|
||||||
|
GeyserMappingItem remap(Item item, GeyserMappingItem mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void populate() {
|
public static void populate() {
|
||||||
Map<Item, String> manualFallback = new HashMap<>();
|
Map<Item, String> legacyJavaOnly = new HashMap<>();
|
||||||
manualFallback.put(Items.ENDER_DRAGON_SPAWN_EGG, "minecraft:enderman_spawn_egg");
|
legacyJavaOnly.put(Items.MUSIC_DISC_RELIC, "minecraft:music_disc_wait");
|
||||||
manualFallback.put(Items.WITHER_SPAWN_EGG, "minecraft:wither_skeleton_spawn_egg");
|
legacyJavaOnly.put(Items.PITCHER_PLANT, "minecraft:chorus_flower");
|
||||||
manualFallback.put(Items.SNOW_GOLEM_SPAWN_EGG, "minecraft:polar_bear_spawn_egg");
|
legacyJavaOnly.put(Items.PITCHER_POD, "minecraft:beetroot");
|
||||||
manualFallback.put(Items.IRON_GOLEM_SPAWN_EGG, "minecraft:villager_spawn_egg");
|
legacyJavaOnly.put(Items.SNIFFER_EGG, "minecraft:sniffer_spawn_egg"); // the BlockItem of the sniffer egg block
|
||||||
|
|
||||||
Map<String, PaletteVersion> paletteVersions = new Object2ObjectOpenHashMap<>();
|
Map<String, PaletteVersion> paletteVersions = new Object2ObjectOpenHashMap<>();
|
||||||
paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.CODEC.getProtocolVersion(), manualFallback));
|
paletteVersions.put("1_19_80", new PaletteVersion(Bedrock_v582.CODEC.getProtocolVersion(), legacyJavaOnly, (item, mapping) -> {
|
||||||
paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.CODEC.getProtocolVersion(), manualFallback));
|
String id = item.javaIdentifier();
|
||||||
paletteVersions.put("1_19_60", new PaletteVersion(Bedrock_v567.CODEC.getProtocolVersion(), Collections.emptyMap()));
|
if (id.endsWith("pottery_sherd")) {
|
||||||
paletteVersions.put("1_19_70", new PaletteVersion(Bedrock_v575.CODEC.getProtocolVersion(), Collections.emptyMap()));
|
return mapping.withBedrockIdentifier(id.replace("sherd", "shard"));
|
||||||
paletteVersions.put("1_19_80", new PaletteVersion(Bedrock_v582.CODEC.getProtocolVersion(), Collections.emptyMap()));
|
} else if (id.endsWith("carpet") && !id.startsWith("minecraft:moss")) {
|
||||||
|
return mapping.withBedrockIdentifier("minecraft:carpet");
|
||||||
|
} else if (id.endsWith("coral")) {
|
||||||
|
return mapping.withBedrockIdentifier("minecraft:coral");
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapping;
|
||||||
|
}));
|
||||||
|
paletteVersions.put("1_20_0", new PaletteVersion(Bedrock_v589.CODEC.getProtocolVersion()));
|
||||||
|
|
||||||
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
|
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
|
||||||
|
|
||||||
@ -182,17 +198,11 @@ public class ItemRegistryPopulator {
|
|||||||
Set<Item> javaOnlyItems = new ObjectOpenHashSet<>();
|
Set<Item> javaOnlyItems = new ObjectOpenHashSet<>();
|
||||||
Collections.addAll(javaOnlyItems, Items.SPECTRAL_ARROW, Items.DEBUG_STICK,
|
Collections.addAll(javaOnlyItems, Items.SPECTRAL_ARROW, Items.DEBUG_STICK,
|
||||||
Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW, Items.BUNDLE);
|
Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW, Items.BUNDLE);
|
||||||
// these spawn eggs exist in 1.19.60+;
|
|
||||||
if (palette.getValue().protocolVersion() < Bedrock_v567.CODEC.getProtocolVersion()) {
|
|
||||||
Collections.addAll(javaOnlyItems, Items.IRON_GOLEM_SPAWN_EGG, Items.SNOW_GOLEM_SPAWN_EGG,
|
|
||||||
Items.WITHER_SPAWN_EGG, Items.ENDER_DRAGON_SPAWN_EGG);
|
|
||||||
}
|
|
||||||
javaOnlyItems.add(Items.DECORATED_POT);
|
|
||||||
if (!customItemsAllowed) {
|
if (!customItemsAllowed) {
|
||||||
javaOnlyItems.add(Items.FURNACE_MINECART);
|
javaOnlyItems.add(Items.FURNACE_MINECART);
|
||||||
}
|
}
|
||||||
// Java-only items for this version
|
// Java-only items for this version
|
||||||
javaOnlyItems.addAll(palette.getValue().additionalTranslatedItems().keySet());
|
javaOnlyItems.addAll(palette.getValue().javaOnlyItems().keySet());
|
||||||
|
|
||||||
Int2ObjectMap<String> customIdMappings = new Int2ObjectOpenHashMap<>();
|
Int2ObjectMap<String> customIdMappings = new Int2ObjectOpenHashMap<>();
|
||||||
Set<String> registeredItemNames = new ObjectOpenHashSet<>(); // This is used to check for duplicate item names
|
Set<String> registeredItemNames = new ObjectOpenHashSet<>(); // This is used to check for duplicate item names
|
||||||
@ -203,12 +213,12 @@ public class ItemRegistryPopulator {
|
|||||||
throw new RuntimeException("Extra item in mappings? " + entry.getKey());
|
throw new RuntimeException("Extra item in mappings? " + entry.getKey());
|
||||||
}
|
}
|
||||||
GeyserMappingItem mappingItem;
|
GeyserMappingItem mappingItem;
|
||||||
String replacementItem = palette.getValue().additionalTranslatedItems().get(javaItem);
|
String replacementItem = palette.getValue().javaOnlyItems().get(javaItem);
|
||||||
if (replacementItem != null) {
|
if (replacementItem != null) {
|
||||||
mappingItem = items.get(replacementItem);
|
mappingItem = items.get(replacementItem); // java only item, a java id fallback has been provided
|
||||||
} else {
|
} else {
|
||||||
// This items has a mapping specifically for this version of the game
|
// check if any mapping changes need to be made on this version
|
||||||
mappingItem = entry.getValue();
|
mappingItem = palette.getValue().remapper().remap(javaItem, entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customItemsAllowed && javaItem == Items.FURNACE_MINECART) {
|
if (customItemsAllowed && javaItem == Items.FURNACE_MINECART) {
|
||||||
@ -217,26 +227,10 @@ public class ItemRegistryPopulator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String bedrockIdentifier;
|
String bedrockIdentifier = mappingItem.getBedrockIdentifier();
|
||||||
// 1.19.70+
|
|
||||||
if (palette.getValue().protocolVersion() >= Bedrock_v575.CODEC.getProtocolVersion() && mappingItem.getBedrockIdentifier().equals("minecraft:wool")) {
|
|
||||||
bedrockIdentifier = javaItem.javaIdentifier();
|
|
||||||
} else {
|
|
||||||
bedrockIdentifier = mappingItem.getBedrockIdentifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
//1.19.80+
|
|
||||||
if (palette.getValue().protocolVersion >= Bedrock_v582.CODEC.getProtocolVersion()) {
|
|
||||||
if (mappingItem.getBedrockIdentifier().equals("minecraft:log") ||
|
|
||||||
mappingItem.getBedrockIdentifier().equals("minecraft:log2") ||
|
|
||||||
mappingItem.getBedrockIdentifier().equals("minecraft:fence")) {
|
|
||||||
bedrockIdentifier = javaItem.javaIdentifier();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemDefinition definition = definitions.get(bedrockIdentifier);
|
ItemDefinition definition = definitions.get(bedrockIdentifier);
|
||||||
if (definition == null) {
|
if (definition == null) {
|
||||||
throw new RuntimeException("Missing Bedrock ItemDefinition in mappings: " + bedrockIdentifier);
|
throw new RuntimeException("Missing Bedrock ItemDefinition in version " + palette.getKey() + " for mapping: " + mappingItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDefinition bedrockBlock = null;
|
BlockDefinition bedrockBlock = null;
|
||||||
@ -430,7 +424,7 @@ public class ItemRegistryPopulator {
|
|||||||
} else if (javaItem.javaIdentifier().startsWith("minecraft:music_disc_")) {
|
} else if (javaItem.javaIdentifier().startsWith("minecraft:music_disc_")) {
|
||||||
// The Java record level event uses the item ID as the "key" to play the record
|
// The Java record level event uses the item ID as the "key" to play the record
|
||||||
Registries.RECORDS.register(javaItem.javaId(), SoundEvent.valueOf("RECORD_" +
|
Registries.RECORDS.register(javaItem.javaId(), SoundEvent.valueOf("RECORD_" +
|
||||||
javaItem.javaIdentifier().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH)));
|
mapping.getBedrockIdentifier().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH)));
|
||||||
}
|
}
|
||||||
|
|
||||||
mappings.add(mapping);
|
mappings.add(mapping);
|
||||||
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.registry.type;
|
|||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.common.DefinitionRegistry;
|
import org.cloudburstmc.protocol.common.DefinitionRegistry;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
package org.geysermc.geyser.registry.type;
|
package org.geysermc.geyser.registry.type;
|
||||||
|
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
|
|
||||||
public class GeyserBedrockBlock implements BlockDefinition {
|
public class GeyserBedrockBlock implements BlockDefinition {
|
||||||
private final int runtimeId;
|
private final int runtimeId;
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.registry.type;
|
package org.geysermc.geyser.registry.type;
|
||||||
|
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.geysermc.geyser.item.type.Item;
|
import org.geysermc.geyser.item.type.Item;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,12 +26,22 @@
|
|||||||
package org.geysermc.geyser.registry.type;
|
package org.geysermc.geyser.registry.type;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Data;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.With;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents Geyser's own serialized item information before being processed per-version
|
* Represents Geyser's own serialized item information before being processed per-version
|
||||||
*/
|
*/
|
||||||
@Data
|
@ToString
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@Getter
|
||||||
|
@With
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
public class GeyserMappingItem {
|
public class GeyserMappingItem {
|
||||||
@JsonProperty("bedrock_identifier") String bedrockIdentifier;
|
@JsonProperty("bedrock_identifier") String bedrockIdentifier;
|
||||||
@JsonProperty("bedrock_data") int bedrockData;
|
@JsonProperty("bedrock_data") int bedrockData;
|
||||||
|
@ -30,8 +30,8 @@ import lombok.Builder;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.item.type.Item;
|
import org.geysermc.geyser.item.type.Item;
|
||||||
|
@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.common.DefinitionRegistry;
|
import org.cloudburstmc.protocol.common.DefinitionRegistry;
|
||||||
|
@ -124,6 +124,7 @@ import org.geysermc.geyser.item.Items;
|
|||||||
import org.geysermc.geyser.level.JavaDimension;
|
import org.geysermc.geyser.level.JavaDimension;
|
||||||
import org.geysermc.geyser.level.WorldManager;
|
import org.geysermc.geyser.level.WorldManager;
|
||||||
import org.geysermc.geyser.level.physics.CollisionManager;
|
import org.geysermc.geyser.level.physics.CollisionManager;
|
||||||
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
import org.geysermc.geyser.network.netty.LocalSession;
|
import org.geysermc.geyser.network.netty.LocalSession;
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.registry.type.BlockMappings;
|
import org.geysermc.geyser.registry.type.BlockMappings;
|
||||||
@ -1540,6 +1541,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
startGamePacket.setRewindHistorySize(0);
|
startGamePacket.setRewindHistorySize(0);
|
||||||
startGamePacket.setServerAuthoritativeBlockBreaking(false);
|
startGamePacket.setServerAuthoritativeBlockBreaking(false);
|
||||||
|
|
||||||
|
if (GameProtocol.isPre1_20(this)) {
|
||||||
|
startGamePacket.getExperiments().add(new ExperimentData("next_major_update", true));
|
||||||
|
startGamePacket.getExperiments().add(new ExperimentData("sniffer", true));
|
||||||
|
}
|
||||||
|
|
||||||
upstream.sendPacket(startGamePacket);
|
upstream.sendPacket(startGamePacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ public class TagCache {
|
|||||||
private IntList foxFood;
|
private IntList foxFood;
|
||||||
private IntList piglinLoved;
|
private IntList piglinLoved;
|
||||||
private IntList smallFlowers;
|
private IntList smallFlowers;
|
||||||
|
private IntList snifferFood;
|
||||||
|
|
||||||
public TagCache() {
|
public TagCache() {
|
||||||
// Ensure all lists are non-null
|
// Ensure all lists are non-null
|
||||||
@ -101,6 +102,7 @@ public class TagCache {
|
|||||||
this.foxFood = IntList.of(itemTags.get("minecraft:fox_food"));
|
this.foxFood = IntList.of(itemTags.get("minecraft:fox_food"));
|
||||||
this.piglinLoved = IntList.of(itemTags.get("minecraft:piglin_loved"));
|
this.piglinLoved = IntList.of(itemTags.get("minecraft:piglin_loved"));
|
||||||
this.smallFlowers = IntList.of(itemTags.get("minecraft:small_flowers"));
|
this.smallFlowers = IntList.of(itemTags.get("minecraft:small_flowers"));
|
||||||
|
this.snifferFood = load(itemTags.get("minecraft:sniffer_food"));
|
||||||
|
|
||||||
// Hack btw
|
// Hack btw
|
||||||
boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1;
|
boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1;
|
||||||
@ -137,6 +139,7 @@ public class TagCache {
|
|||||||
this.foxFood = IntLists.emptyList();
|
this.foxFood = IntLists.emptyList();
|
||||||
this.piglinLoved = IntLists.emptyList();
|
this.piglinLoved = IntLists.emptyList();
|
||||||
this.smallFlowers = IntLists.emptyList();
|
this.smallFlowers = IntLists.emptyList();
|
||||||
|
this.snifferFood = IntLists.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAxolotlTemptItem(Item item) {
|
public boolean isAxolotlTemptItem(Item item) {
|
||||||
@ -167,6 +170,10 @@ public class TagCache {
|
|||||||
return smallFlowers.contains(itemStack.getJavaId());
|
return smallFlowers.contains(itemStack.getJavaId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSnifferFood(Item item) {
|
||||||
|
return snifferFood.contains(item.javaId());
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAxeEffective(BlockMapping blockMapping) {
|
public boolean isAxeEffective(BlockMapping blockMapping) {
|
||||||
return axeEffective.contains(blockMapping.getJavaBlockId());
|
return axeEffective.contains(blockMapping.getJavaBlockId());
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,10 @@ public final class WorldCache {
|
|||||||
private int currentSequence;
|
private int currentSequence;
|
||||||
private final Object2IntMap<Vector3i> unverifiedPredictions = new Object2IntOpenHashMap<>(1);
|
private final Object2IntMap<Vector3i> unverifiedPredictions = new Object2IntOpenHashMap<>(1);
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private boolean editingSignOnFront;
|
||||||
|
|
||||||
public WorldCache(GeyserSession session) {
|
public WorldCache(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.scoreboard = new Scoreboard(session);
|
this.scoreboard = new Scoreboard(session);
|
||||||
|
@ -94,7 +94,7 @@ public abstract class InventoryTranslator {
|
|||||||
put(ContainerType.LOOM, new LoomInventoryTranslator());
|
put(ContainerType.LOOM, new LoomInventoryTranslator());
|
||||||
put(ContainerType.MERCHANT, new MerchantInventoryTranslator());
|
put(ContainerType.MERCHANT, new MerchantInventoryTranslator());
|
||||||
put(ContainerType.SHULKER_BOX, new ShulkerInventoryTranslator());
|
put(ContainerType.SHULKER_BOX, new ShulkerInventoryTranslator());
|
||||||
put(ContainerType.LEGACY_SMITHING, new SmithingInventoryTranslator());
|
put(ContainerType.SMITHING, new SmithingInventoryTranslator());
|
||||||
put(ContainerType.STONECUTTER, new StonecutterInventoryTranslator());
|
put(ContainerType.STONECUTTER, new StonecutterInventoryTranslator());
|
||||||
|
|
||||||
/* Lectern */
|
/* Lectern */
|
||||||
|
@ -33,15 +33,16 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
|||||||
|
|
||||||
public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator {
|
public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||||
public SmithingInventoryTranslator() {
|
public SmithingInventoryTranslator() {
|
||||||
super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE);
|
super(4, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
|
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
|
||||||
return switch (slotInfoData.getContainer()) {
|
return switch (slotInfoData.getContainer()) {
|
||||||
case SMITHING_TABLE_INPUT -> 0;
|
case SMITHING_TABLE_TEMPLATE -> 0;
|
||||||
case SMITHING_TABLE_MATERIAL -> 1;
|
case SMITHING_TABLE_INPUT -> 1;
|
||||||
case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> 2;
|
case SMITHING_TABLE_MATERIAL -> 2;
|
||||||
|
case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> 3;
|
||||||
default -> super.bedrockSlotToJava(slotInfoData);
|
default -> super.bedrockSlotToJava(slotInfoData);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -49,9 +50,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
|
|||||||
@Override
|
@Override
|
||||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||||
return switch (slot) {
|
return switch (slot) {
|
||||||
case 0 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51);
|
case 0 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_TEMPLATE, 53);
|
||||||
case 1 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52);
|
case 1 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51);
|
||||||
case 2 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50);
|
case 2 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52);
|
||||||
|
case 3 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50);
|
||||||
default -> super.javaSlotToBedrockContainer(slot);
|
default -> super.javaSlotToBedrockContainer(slot);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -59,9 +61,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
|
|||||||
@Override
|
@Override
|
||||||
public int javaSlotToBedrock(int slot) {
|
public int javaSlotToBedrock(int slot) {
|
||||||
return switch (slot) {
|
return switch (slot) {
|
||||||
case 0 -> 51;
|
case 0 -> 53;
|
||||||
case 1 -> 52;
|
case 1 -> 51;
|
||||||
case 2 -> 50;
|
case 2 -> 52;
|
||||||
|
case 3 -> 50;
|
||||||
default -> super.javaSlotToBedrock(slot);
|
default -> super.javaSlotToBedrock(slot);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.translator.inventory.chest;
|
|||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket;
|
import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket;
|
||||||
|
@ -30,7 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
|||||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
||||||
import org.geysermc.geyser.api.util.TriState;
|
import org.geysermc.geyser.api.util.TriState;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
|
@ -37,7 +37,7 @@ import org.cloudburstmc.nbt.NbtList;
|
|||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
import org.cloudburstmc.nbt.NbtType;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 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.level.block.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
|
||||||
|
import org.geysermc.geyser.util.SignUtils;
|
||||||
|
|
||||||
|
@BlockEntity(type = BlockEntityType.HANGING_SIGN)
|
||||||
|
public class HangingSignBlockEntityTranslator extends SignBlockEntityTranslator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int signWidthMax() {
|
||||||
|
return SignUtils.HANGING_SIGN_WIDTH_MAX; // Smaller than that for BlockEntityType.SIGN
|
||||||
|
}
|
||||||
|
}
|
@ -42,7 +42,6 @@ import org.geysermc.geyser.level.physics.Axis;
|
|||||||
import org.geysermc.geyser.level.physics.BoundingBox;
|
import org.geysermc.geyser.level.physics.BoundingBox;
|
||||||
import org.geysermc.geyser.level.physics.CollisionManager;
|
import org.geysermc.geyser.level.physics.CollisionManager;
|
||||||
import org.geysermc.geyser.level.physics.Direction;
|
import org.geysermc.geyser.level.physics.Direction;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.session.cache.PistonCache;
|
import org.geysermc.geyser.session.cache.PistonCache;
|
||||||
@ -622,10 +621,6 @@ public class PistonBlockEntity {
|
|||||||
Vector3i movement = getMovement();
|
Vector3i movement = getMovement();
|
||||||
attachedBlocks.forEach((blockPos, javaId) -> {
|
attachedBlocks.forEach((blockPos, javaId) -> {
|
||||||
blockPos = blockPos.add(movement);
|
blockPos = blockPos.add(movement);
|
||||||
if (!GameProtocol.supports1_19_50(session)) {
|
|
||||||
// Send a final block entity packet to detach blocks for clients older than 1.19.50
|
|
||||||
BlockEntityUtils.updateBlockEntity(session, buildMovingBlockTag(blockPos, javaId, Direction.DOWN.getUnitVector()), blockPos);
|
|
||||||
}
|
|
||||||
// Don't place blocks that collide with the player
|
// Don't place blocks that collide with the player
|
||||||
if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) {
|
if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) {
|
||||||
ChunkUtils.updateBlock(session, javaId, blockPos);
|
ChunkUtils.updateBlock(session, javaId, blockPos);
|
||||||
|
@ -27,12 +27,15 @@ package org.geysermc.geyser.translator.level.block.entity;
|
|||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
|
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.CompoundTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||||
import org.geysermc.geyser.util.SignUtils;
|
import org.geysermc.geyser.util.SignUtils;
|
||||||
|
|
||||||
@BlockEntity(type = {BlockEntityType.SIGN, BlockEntityType.HANGING_SIGN})
|
@BlockEntity(type = BlockEntityType.SIGN)
|
||||||
public class SignBlockEntityTranslator extends BlockEntityTranslator {
|
public class SignBlockEntityTranslator extends BlockEntityTranslator {
|
||||||
/**
|
/**
|
||||||
* Maps a color stored in a sign's Color tag to its ARGB value.
|
* Maps a color stored in a sign's Color tag to its ARGB value.
|
||||||
@ -64,54 +67,80 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator {
|
|||||||
return dyeColor | (255 << 24);
|
return dyeColor | (255 << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int signWidthMax() {
|
||||||
|
return SignUtils.SIGN_WIDTH_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||||
StringBuilder signText = new StringBuilder();
|
builder.putCompound("FrontText", translateSide(tag.get("front_text")));
|
||||||
for (int i = 0; i < 4; i++) {
|
builder.putCompound("BackText", translateSide(tag.get("back_text")));
|
||||||
int currentLine = i + 1;
|
var waxed = tag.get("is_waxed");
|
||||||
String signLine = getOrDefault(tag.getValue().get("Text" + currentLine), "");
|
builder.putBoolean("IsWaxed", waxed != null && waxed.getValue() instanceof Number number && number.byteValue() != 0);
|
||||||
signLine = MessageTranslator.convertMessageLenient(signLine);
|
}
|
||||||
|
|
||||||
// Check the character width on the sign to ensure there is no overflow that is usually hidden
|
private NbtMap translateSide(Tag tag) {
|
||||||
// to Java Edition clients but will appear to Bedrock clients
|
if (!(tag instanceof CompoundTag signData)) {
|
||||||
int signWidth = 0;
|
return NbtMap.EMPTY;
|
||||||
StringBuilder finalSignLine = new StringBuilder();
|
}
|
||||||
boolean previousCharacterWasFormatting = false; // Color changes do not count for maximum width
|
NbtMapBuilder builder = NbtMap.builder();
|
||||||
for (char c : signLine.toCharArray()) {
|
|
||||||
if (c == '\u00a7') {
|
StringBuilder signText = new StringBuilder();
|
||||||
// Don't count this character
|
Tag messages = signData.get("messages");
|
||||||
previousCharacterWasFormatting = true;
|
if (messages instanceof ListTag listTag) {
|
||||||
} else if (previousCharacterWasFormatting) {
|
var it = listTag.iterator();
|
||||||
// Don't count this character either
|
while (it.hasNext()) {
|
||||||
previousCharacterWasFormatting = false;
|
String signLine = (String) it.next().getValue();
|
||||||
} else {
|
signLine = MessageTranslator.convertMessageLenient(signLine);
|
||||||
signWidth += SignUtils.getCharacterWidth(c);
|
|
||||||
|
// Check the character width on the sign to ensure there is no overflow that is usually hidden
|
||||||
|
// to Java Edition clients but will appear to Bedrock clients
|
||||||
|
int signWidth = 0;
|
||||||
|
StringBuilder finalSignLine = new StringBuilder();
|
||||||
|
boolean previousCharacterWasFormatting = false; // Color changes do not count for maximum width
|
||||||
|
for (char c : signLine.toCharArray()) {
|
||||||
|
if (c == ChatColor.ESCAPE) {
|
||||||
|
// Don't count this character
|
||||||
|
previousCharacterWasFormatting = true;
|
||||||
|
} else if (previousCharacterWasFormatting) {
|
||||||
|
// Don't count this character either
|
||||||
|
previousCharacterWasFormatting = false;
|
||||||
|
} else {
|
||||||
|
signWidth += SignUtils.getCharacterWidth(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signWidth <= signWidthMax()) {
|
||||||
|
finalSignLine.append(c);
|
||||||
|
} else {
|
||||||
|
// Adding the character would make Bedrock move to the next line - Java doesn't do that, so we do not want to
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo 1.20: update for hanging signs (smaller width). Currently OK because bedrock sees hanging signs as normal signs
|
signText.append(finalSignLine);
|
||||||
if (signWidth <= SignUtils.BEDROCK_CHARACTER_WIDTH_MAX) {
|
if (it.hasNext()) {
|
||||||
finalSignLine.append(c);
|
signText.append("\n");
|
||||||
} else {
|
|
||||||
// Adding the character would make Bedrock move to the next line - Java doesn't do that, so we do not want to
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
signText.append(finalSignLine);
|
// Trim extra newlines - this makes editing difficult if preserved because the cursor starts at the bottom,
|
||||||
signText.append("\n");
|
// Which can easily go over the screen
|
||||||
|
while (!signText.isEmpty() && signText.charAt(signText.length() - 1) == '\n') {
|
||||||
|
signText.deleteCharAt(signText.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.putString("Text", signText.toString());
|
builder.putString("Text", signText.toString());
|
||||||
|
|
||||||
// Java Edition 1.14 added the ability to change the text color of the whole sign using dye
|
// Java Edition 1.14 added the ability to change the text color of the whole sign using dye
|
||||||
Tag color = tag.get("Color");
|
Tag color = signData.get("Color");
|
||||||
if (color != null) {
|
if (color != null) {
|
||||||
builder.putInt("SignTextColor", getBedrockSignColor(color.getValue().toString()));
|
builder.putInt("SignTextColor", getBedrockSignColor(color.getValue().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Glowing text
|
// Glowing text
|
||||||
boolean isGlowing = getOrDefault(tag.getValue().get("GlowingText"), (byte) 0) != (byte) 0;
|
boolean isGlowing = getOrDefault(signData.get("GlowingText"), (byte) 0) != (byte) 0;
|
||||||
builder.putBoolean("IgnoreLighting", isGlowing);
|
builder.putBoolean("IgnoreLighting", isGlowing);
|
||||||
builder.putBoolean("TextIgnoreLegacyBugResolved", isGlowing); // ??? required
|
return builder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.Serverb
|
|||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
import org.geysermc.geyser.translator.protocol.Translator;
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
@ -45,15 +44,11 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
|
|||||||
NbtMap tag = packet.getData();
|
NbtMap tag = packet.getData();
|
||||||
String id = tag.getString("id");
|
String id = tag.getString("id");
|
||||||
if (id.equals("Sign")) {
|
if (id.equals("Sign")) {
|
||||||
String text;
|
// Hanging signs are narrower
|
||||||
if (GameProtocol.supports1_19_80(session)) {
|
int widthMax = SignUtils.getSignWidthMax(session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition()));
|
||||||
// The other side is called... you guessed it... BackText
|
|
||||||
text = tag.getCompound("FrontText")
|
String text = MessageTranslator.convertToPlainText(
|
||||||
.getString("Text");
|
tag.getCompound(session.getWorldCache().isEditingSignOnFront() ? "FrontText" : "BackText").getString("Text"));
|
||||||
} else {
|
|
||||||
text = tag.getString("Text");
|
|
||||||
}
|
|
||||||
text = MessageTranslator.convertToPlainText(text);
|
|
||||||
// Note: as of 1.18.30, only one packet is sent from Bedrock when the sign is finished.
|
// Note: as of 1.18.30, only one packet is sent from Bedrock when the sign is finished.
|
||||||
// Previous versions did not have this behavior.
|
// Previous versions did not have this behavior.
|
||||||
StringBuilder newMessage = new StringBuilder();
|
StringBuilder newMessage = new StringBuilder();
|
||||||
@ -68,13 +63,10 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
|
|||||||
for (char character : text.toCharArray()) {
|
for (char character : text.toCharArray()) {
|
||||||
widthCount += SignUtils.getCharacterWidth(character);
|
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 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) {
|
if (character == '\n' || widthCount > widthMax) {
|
||||||
// We need to apply some more logic if we went over the character width max
|
// We need to apply some more logic if we went over the character width max
|
||||||
boolean wentOverMax = widthCount > SignUtils.JAVA_CHARACTER_WIDTH_MAX && character != '\n';
|
boolean wentOverMax = widthCount > widthMax && character != '\n';
|
||||||
widthCount = 0;
|
widthCount = 0;
|
||||||
// Saves if we're moving a word to the next line
|
// Saves if we're moving a word to the next line
|
||||||
String word = null;
|
String word = null;
|
||||||
@ -115,7 +107,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
|
|||||||
// Put the final line on since it isn't done in the for loop
|
// Put the final line on since it isn't done in the for loop
|
||||||
if (iterator < lines.length) lines[iterator] = newMessage.toString();
|
if (iterator < lines.length) lines[iterator] = newMessage.toString();
|
||||||
Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
|
Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
|
||||||
ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines);
|
ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines, session.getWorldCache().isEditingSignOnFront());
|
||||||
session.sendDownstreamPacket(signUpdatePacket);
|
session.sendDownstreamPacket(signUpdatePacket);
|
||||||
|
|
||||||
} else if (id.equals("JigsawBlock")) {
|
} else if (id.equals("JigsawBlock")) {
|
||||||
|
@ -39,7 +39,7 @@ import org.cloudburstmc.math.vector.Vector3d;
|
|||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
|
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryActionData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryActionData;
|
||||||
|
@ -29,27 +29,28 @@ 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.Ingredient;
|
||||||
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
|
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
|
||||||
import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
|
import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
|
||||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.LegacyUpgradeRecipeData;
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData;
|
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData;
|
||||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData;
|
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingTransformRecipeData;
|
||||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData;
|
import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket;
|
||||||
import it.unimi.dsi.fastutil.ints.*;
|
import it.unimi.dsi.fastutil.ints.*;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.MultiRecipeData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.MultiRecipeData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTrimRecipeData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
|
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
|
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
import org.geysermc.geyser.inventory.recipe.TrimRecipe;
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
@ -145,28 +146,29 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||||||
data.add(stoneCuttingData);
|
data.add(stoneCuttingData);
|
||||||
// Save for processing after all recipes have been received
|
// Save for processing after all recipes have been received
|
||||||
}
|
}
|
||||||
case SMITHING -> {
|
case SMITHING_TRANSFORM -> {
|
||||||
// Required to translate these as of 1.18.10, or else they cannot be crafted
|
SmithingTransformRecipeData data = (SmithingTransformRecipeData) recipe.getData();
|
||||||
LegacyUpgradeRecipeData recipeData = (LegacyUpgradeRecipeData) recipe.getData();
|
ItemData output = ItemTranslator.translateToBedrock(session, data.getResult());
|
||||||
ItemData output = ItemTranslator.translateToBedrock(session, recipeData.getResult());
|
|
||||||
for (ItemStack base : recipeData.getBase().getOptions()) {
|
|
||||||
ItemDescriptorWithCount bedrockBase = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, base));
|
|
||||||
|
|
||||||
for (ItemStack addition : recipeData.getAddition().getOptions()) {
|
for (ItemStack template : data.getTemplate().getOptions()) {
|
||||||
ItemDescriptorWithCount bedrockAddition = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, addition));
|
ItemDescriptorWithCount bedrockTemplate = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, template));
|
||||||
|
|
||||||
|
for (ItemStack base : data.getBase().getOptions()) {
|
||||||
|
ItemDescriptorWithCount bedrockBase = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, base));
|
||||||
|
|
||||||
|
for (ItemStack addition : data.getAddition().getOptions()) {
|
||||||
|
ItemDescriptorWithCount bedrockAddition = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, addition));
|
||||||
|
|
||||||
if (GameProtocol.supports1_19_60(session)) {
|
|
||||||
// Note: vanilla inputs use aux value of Short.MAX_VALUE
|
// Note: vanilla inputs use aux value of Short.MAX_VALUE
|
||||||
craftingDataPacket.getCraftingData().add(SmithingTransformRecipeData.of(recipe.getIdentifier(),
|
craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(recipe.getIdentifier(),
|
||||||
ItemDescriptorWithCount.EMPTY, bedrockBase, bedrockAddition, output, "smithing_table", netId++));
|
bedrockTemplate, bedrockBase, bedrockAddition, output, "smithing_table", netId++));
|
||||||
} else {
|
|
||||||
UUID uuid = UUID.randomUUID();
|
|
||||||
craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shapeless(uuid.toString(),
|
|
||||||
List.of(bedrockBase, bedrockAddition),
|
|
||||||
Collections.singletonList(output), uuid, "smithing_table", 2, netId++));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
case SMITHING_TRIM -> {
|
||||||
|
// ignored currently - see below
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
List<RecipeData> craftingData = recipeTypes.get(recipe.getType());
|
List<RecipeData> craftingData = recipeTypes.get(recipe.getType());
|
||||||
@ -212,6 +214,19 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: if the server/viaversion doesn't send trim recipes then we shouldn't either.
|
||||||
|
|
||||||
|
// BDS sends armor trim templates and materials before the CraftingDataPacket
|
||||||
|
TrimDataPacket trimDataPacket = new TrimDataPacket();
|
||||||
|
trimDataPacket.getPatterns().addAll(TrimRecipe.PATTERNS);
|
||||||
|
trimDataPacket.getMaterials().addAll(TrimRecipe.MATERIALS);
|
||||||
|
session.sendUpstreamPacket(trimDataPacket);
|
||||||
|
|
||||||
|
// Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the
|
||||||
|
// approach of using many default-descriptors (which we do for smithing_transform)
|
||||||
|
craftingDataPacket.getCraftingData().add(SmithingTrimRecipeData.of(TrimRecipe.ID,
|
||||||
|
TrimRecipe.BASE, TrimRecipe.ADDITION, TrimRecipe.TEMPLATE, "smithing_table", netId++));
|
||||||
|
|
||||||
session.sendUpstreamPacket(craftingDataPacket);
|
session.sendUpstreamPacket(craftingDataPacket);
|
||||||
session.setCraftingRecipes(recipeMap);
|
session.setCraftingRecipes(recipeMap);
|
||||||
session.setStonecutterRecipes(stonecutterRecipeMap);
|
session.setStonecutterRecipes(stonecutterRecipeMap);
|
||||||
|
@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtType;
|
|||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateEquipPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateEquipPacket;
|
||||||
import org.geysermc.geyser.entity.type.Entity;
|
import org.geysermc.geyser.entity.type.Entity;
|
||||||
|
import org.geysermc.geyser.entity.type.living.animal.horse.CamelEntity;
|
||||||
import org.geysermc.geyser.entity.type.living.animal.horse.ChestedHorseEntity;
|
import org.geysermc.geyser.entity.type.living.animal.horse.ChestedHorseEntity;
|
||||||
import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
|
import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
|
||||||
import org.geysermc.geyser.inventory.Container;
|
import org.geysermc.geyser.inventory.Container;
|
||||||
@ -118,6 +119,10 @@ public class JavaHorseScreenOpenTranslator extends PacketTranslator<ClientboundH
|
|||||||
} else if (entity instanceof ChestedHorseEntity) {
|
} else if (entity instanceof ChestedHorseEntity) {
|
||||||
inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots());
|
inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots());
|
||||||
slots.add(SADDLE_SLOT);
|
slots.add(SADDLE_SLOT);
|
||||||
|
} else if (entity instanceof CamelEntity) {
|
||||||
|
// The camel has an invisible armor slot and needs special handling, same as the donkey
|
||||||
|
inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots());
|
||||||
|
slots.add(SADDLE_SLOT);
|
||||||
} else {
|
} else {
|
||||||
inventoryTranslator = new HorseInventoryTranslator(packet.getNumberOfSlots());
|
inventoryTranslator = new HorseInventoryTranslator(packet.getNumberOfSlots());
|
||||||
slots.add(SADDLE_SLOT);
|
slots.add(SADDLE_SLOT);
|
||||||
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.protocol.java.level;
|
|||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundOpenSignEditorPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundOpenSignEditorPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.OpenSignPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.OpenSignPacket;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
import org.geysermc.geyser.translator.protocol.Translator;
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
@ -37,11 +36,11 @@ public class JavaOpenSignEditorTranslator extends PacketTranslator<ClientboundOp
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundOpenSignEditorPacket packet) {
|
public void translate(GeyserSession session, ClientboundOpenSignEditorPacket packet) {
|
||||||
if (GameProtocol.supports1_19_80(session)) {
|
OpenSignPacket openSignPacket = new OpenSignPacket();
|
||||||
OpenSignPacket openSignPacket = new OpenSignPacket();
|
openSignPacket.setPosition(packet.getPosition());
|
||||||
openSignPacket.setPosition(packet.getPosition());
|
openSignPacket.setFrontSide(packet.isFrontText());
|
||||||
openSignPacket.setFrontSide(true); // Will be remedied in 1.20
|
session.sendUpstreamPacket(openSignPacket);
|
||||||
session.sendUpstreamPacket(openSignPacket);
|
|
||||||
}
|
session.getWorldCache().setEditingSignOnFront(packet.isFrontText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import lombok.experimental.UtilityClass;
|
|||||||
import org.cloudburstmc.math.GenericMath;
|
import org.cloudburstmc.math.GenericMath;
|
||||||
import org.cloudburstmc.math.vector.Vector2i;
|
import org.cloudburstmc.math.vector.Vector2i;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
|
import org.cloudburstmc.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
|
@ -36,7 +36,6 @@ import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket;
|
|||||||
import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket;
|
||||||
import org.geysermc.geyser.entity.type.Entity;
|
import org.geysermc.geyser.entity.type.Entity;
|
||||||
import org.geysermc.geyser.level.BedrockDimension;
|
import org.geysermc.geyser.level.BedrockDimension;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -122,18 +121,16 @@ public class DimensionUtils {
|
|||||||
stopSoundPacket.setSoundName("");
|
stopSoundPacket.setSoundName("");
|
||||||
session.sendUpstreamPacket(stopSoundPacket);
|
session.sendUpstreamPacket(stopSoundPacket);
|
||||||
|
|
||||||
// Kind of silly but Bedrock 1.19.50 requires an acknowledgement after the
|
// Kind of silly but Bedrock 1.19.50 and later requires an acknowledgement after the
|
||||||
// initial chunks are sent, prior to the client acknowledgement
|
// initial chunks are sent, prior to the client acknowledgement
|
||||||
if (GameProtocol.supports1_19_50(session)) {
|
// Note: send this before chunks are sent. Fixed https://github.com/GeyserMC/Geyser/issues/3421
|
||||||
// Note: send this before chunks are sent. Fixed https://github.com/GeyserMC/Geyser/issues/3421
|
PlayerActionPacket ackPacket = new PlayerActionPacket();
|
||||||
PlayerActionPacket ackPacket = new PlayerActionPacket();
|
ackPacket.setRuntimeEntityId(player.getGeyserId());
|
||||||
ackPacket.setRuntimeEntityId(player.getGeyserId());
|
ackPacket.setAction(PlayerActionType.DIMENSION_CHANGE_SUCCESS);
|
||||||
ackPacket.setAction(PlayerActionType.DIMENSION_CHANGE_SUCCESS);
|
ackPacket.setBlockPosition(Vector3i.ZERO);
|
||||||
ackPacket.setBlockPosition(Vector3i.ZERO);
|
ackPacket.setResultPosition(Vector3i.ZERO);
|
||||||
ackPacket.setResultPosition(Vector3i.ZERO);
|
ackPacket.setFace(0);
|
||||||
ackPacket.setFace(0);
|
session.sendUpstreamPacket(ackPacket);
|
||||||
session.sendUpstreamPacket(ackPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - fix this hack of a fix by sending the final dimension switching logic after sections have been sent.
|
// TODO - fix this hack of a fix by sending the final dimension switching logic after sections have been sent.
|
||||||
// The client wants sections sent to it before it can successfully respawn.
|
// The client wants sections sent to it before it can successfully respawn.
|
||||||
|
@ -35,7 +35,7 @@ import org.cloudburstmc.math.vector.Vector3i;
|
|||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
import org.cloudburstmc.nbt.NbtType;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||||
|
@ -57,9 +57,11 @@ import javax.crypto.SecretKey;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.interfaces.ECPublicKey;
|
import java.security.interfaces.ECPublicKey;
|
||||||
import java.security.spec.ECGenParameterSpec;
|
import java.security.spec.ECGenParameterSpec;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -70,6 +72,18 @@ public class LoginEncryptionUtils {
|
|||||||
|
|
||||||
private static boolean HAS_SENT_ENCRYPTION_MESSAGE = false;
|
private static boolean HAS_SENT_ENCRYPTION_MESSAGE = false;
|
||||||
|
|
||||||
|
private static final ECPublicKey MOJANG_PUBLIC_KEY_OLD;
|
||||||
|
private static final ECPublicKey MOJANG_PUBLIC_KEY;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
MOJANG_PUBLIC_KEY_OLD = EncryptionUtils.generateKey("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V");
|
||||||
|
MOJANG_PUBLIC_KEY = EncryptionUtils.generateKey("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAECRXueJeTDqNRRgJi/vlRufByu/2G0i2Ebt6YMar5QX/R0DIIyrJMcUpruK4QveTfJSTp3Shlq4Gk34cD/4GUWwkv0DVuzeuB+tXija7HBxii03NHDbPAD0AKnLr2wdAp");
|
||||||
|
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||||
|
throw new AssertionError("Unable to initialize required encryption", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean validateChainData(List<SignedJWT> chain) throws Exception {
|
private static boolean validateChainData(List<SignedJWT> chain) throws Exception {
|
||||||
if (chain.size() != 3) {
|
if (chain.size() != 3) {
|
||||||
return false;
|
return false;
|
||||||
@ -105,7 +119,7 @@ public class LoginEncryptionUtils {
|
|||||||
return !iterator.hasNext();
|
return !iterator.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastKey.equals(EncryptionUtils.getMojangPublicKey())) {
|
if (verifyMojangPublicKey(lastKey)) {
|
||||||
mojangSigned = true;
|
mojangSigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +134,10 @@ public class LoginEncryptionUtils {
|
|||||||
return mojangSigned;
|
return mojangSigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean verifyMojangPublicKey(ECPublicKey key) {
|
||||||
|
return MOJANG_PUBLIC_KEY.equals(key) || MOJANG_PUBLIC_KEY_OLD.equals(key);
|
||||||
|
}
|
||||||
|
|
||||||
public static void encryptPlayerConnection(GeyserSession session, LoginPacket loginPacket) {
|
public static void encryptPlayerConnection(GeyserSession session, LoginPacket loginPacket) {
|
||||||
encryptConnectionWithCert(session, loginPacket.getExtra().getParsedString(), loginPacket.getChain());
|
encryptConnectionWithCert(session, loginPacket.getExtra().getParsedString(), loginPacket.getChain());
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.util;
|
package org.geysermc.geyser.util;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides utilities for interacting with signs. Mainly, it deals with the widths of each character.
|
* Provides utilities for interacting with signs. Mainly, it deals with the widths of each character.
|
||||||
* Since Bedrock auto-wraps signs and Java does not, we have to take this into account when translating signs.
|
* Since Bedrock auto-wraps signs and Java does not, we have to take this into account when translating signs.
|
||||||
@ -33,14 +35,15 @@ public class SignUtils {
|
|||||||
|
|
||||||
// TODO: If we send the Java font via resource pack, does width change?
|
// TODO: If we send the Java font via resource pack, does width change?
|
||||||
/**
|
/**
|
||||||
* The maximum character width that a sign can hold in Bedrock
|
* The maximum character width that a non-hanging sign can hold in both Java and Bedrock
|
||||||
*/
|
*/
|
||||||
public static final int BEDROCK_CHARACTER_WIDTH_MAX = 88;
|
public static final int SIGN_WIDTH_MAX = 90;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum character width that a sign can hold in Java
|
* The maximum character width that a hanging sign can hold in both Java and Bedrock. Hanging signs are narrower.
|
||||||
*/
|
*/
|
||||||
public static final int JAVA_CHARACTER_WIDTH_MAX = 90;
|
public static final int HANGING_SIGN_WIDTH_MAX = 60;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Minecraft width of a character
|
* Gets the Minecraft width of a character
|
||||||
@ -58,4 +61,10 @@ public class SignUtils {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getSignWidthMax(int javaBlockState) {
|
||||||
|
if (BlockStateValues.isHangingSign(javaBlockState)) {
|
||||||
|
return HANGING_SIGN_WIDTH_MAX;
|
||||||
|
}
|
||||||
|
return SIGN_WIDTH_MAX;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
BIN
core/src/main/resources/bedrock/block_palette.1_20_0.nbt
Normale Datei
BIN
core/src/main/resources/bedrock/block_palette.1_20_0.nbt
Normale Datei
Binäre Datei nicht angezeigt.
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
6580
core/src/main/resources/bedrock/creative_items.1_20_0.json
Normale Datei
6580
core/src/main/resources/bedrock/creative_items.1_20_0.json
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Binäre Datei nicht angezeigt.
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
5186
core/src/main/resources/bedrock/runtime_item_states.1_20_0.json
Normale Datei
5186
core/src/main/resources/bedrock/runtime_item_states.1_20_0.json
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -1 +1 @@
|
|||||||
Subproject commit 56c3eee7a5241b5609d1936f2a11b05dd1a3d568
|
Subproject commit f69b4db9a6f0e8fff8b29564195c76074210b924
|
@ -30,8 +30,8 @@ package org.geysermc.geyser.translator.inventory.item;
|
|||||||
//import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
//import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||||
//import it.unimi.dsi.fastutil.Pair;
|
//import it.unimi.dsi.fastutil.Pair;
|
||||||
//import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
//import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||||
//import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
//import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
//import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleItemDefinition;
|
//import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
|
||||||
//import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
//import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
||||||
//import org.geysermc.geyser.api.util.TriState;
|
//import org.geysermc.geyser.api.util.TriState;
|
||||||
//import org.geysermc.geyser.item.GeyserCustomItemOptions;
|
//import org.geysermc.geyser.item.GeyserCustomItemOptions;
|
||||||
|
@ -5,7 +5,7 @@ org.gradle.caching=true
|
|||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|
||||||
group=org.geysermc
|
group=org.geysermc
|
||||||
version=2.1.0-SNAPSHOT
|
version=2.1.1-SNAPSHOT
|
||||||
|
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
@ -9,11 +9,11 @@ netty = "4.1.80.Final"
|
|||||||
guava = "29.0-jre"
|
guava = "29.0-jre"
|
||||||
gson = "2.3.1" # Provided by Spigot 1.8.8
|
gson = "2.3.1" # Provided by Spigot 1.8.8
|
||||||
websocket = "1.5.1"
|
websocket = "1.5.1"
|
||||||
protocol = "3.0.0.Beta1-20230507.200054-78"
|
protocol = "3.0.0.Beta1-20230604.143616-86"
|
||||||
protocol-connection = "3.0.0.Beta1-20230507.200054-77"
|
protocol-connection = "3.0.0.Beta1-20230604.143616-85"
|
||||||
raknet = "1.0.0.CR1-20230430.211932-7"
|
raknet = "1.0.0.CR1-20230430.211932-7"
|
||||||
mcauthlib = "d9d773e"
|
mcauthlib = "d9d773e"
|
||||||
mcprotocollib = "1.19.4-2-20230503.145414-3"
|
mcprotocollib = "1.20-1-20230607.135651-6" # Temporary hack - needs to be updated to release once publishing is fixed
|
||||||
adventure = "4.14.0-20230424.215040-7"
|
adventure = "4.14.0-20230424.215040-7"
|
||||||
adventure-platform = "4.1.2"
|
adventure-platform = "4.1.2"
|
||||||
junit = "5.9.2"
|
junit = "5.9.2"
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren