Merge remote-tracking branch 'origin/feature/1.19-bedrock' into feature/cumulus-1.1

# Conflicts:
#	core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java
This commit is contained in:
Tim203 2022-06-07 00:14:43 +02:00
commit 5fe24ac867
No known key found for this signature in database
GPG key ID: 064EE9F5BF7C3EE8
138 changed files with 3101 additions and 21100 deletions

View file

@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
### Currently supporting Minecraft Bedrock 1.18.0 - 1.18.31 and Minecraft Java 1.18.2.
### Currently supporting Minecraft Bedrock 1.19 and Minecraft Java 1.19.0.
## Setting Up
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.

View file

@ -13,7 +13,7 @@
<repositories>
<repository>
<id>papermc</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>viaversion-repo</id>

View file

@ -169,9 +169,10 @@ public class GeyserSpigotInjector extends GeyserInjector {
* For the future, if someone wants to properly fix this - as of December 28, 2021, it happens on 1.16.5/1.17.1/1.18.1 EXCEPT Spigot 1.16.5
*/
private void workAroundWeirdBug(GeyserBootstrap bootstrap) {
MinecraftProtocol protocol = new MinecraftProtocol();
LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().getAddress(),
bootstrap.getGeyserConfig().getRemote().getPort(), this.serverSocketAddress,
InetAddress.getLoopbackAddress().getHostAddress(), new MinecraftProtocol());
InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper());
session.connect();
}

View file

@ -209,6 +209,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
return;
}
}
geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
// Allow libraries like Protocol to have their debug information passthrough

View file

@ -72,7 +72,7 @@
<groupId>com.nukkitx</groupId>
<artifactId>nbt</artifactId>
<!-- Used for key/value interning -->
<version>2.1.0</version>
<version>2.2.1</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -120,8 +120,8 @@
</dependency>
<dependency>
<groupId>com.github.CloudburstMC.Protocol</groupId>
<artifactId>bedrock-v503</artifactId>
<version>297567d</version>
<artifactId>bedrock-beta</artifactId>
<version>be0cc73</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@ -153,9 +153,9 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.GeyserMC</groupId>
<artifactId>MCProtocolLib</artifactId>
<version>0771504</version>
<groupId>com.github.steveice10</groupId>
<artifactId>mcprotocollib</artifactId>
<version>1.19-SNAPSHOT</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@ -171,7 +171,7 @@
<dependency>
<groupId>com.github.steveice10</groupId>
<artifactId>packetlib</artifactId>
<version>2.1-SNAPSHOT</version>
<version>3.0</version>
<scope>compile</scope>
<exclusions>
<exclusion>

View file

@ -43,7 +43,7 @@ public class FloodgateKeyLoader {
if (floodgateDataFolder != null) {
Path autoKey = floodgateDataFolder.resolve("key.pem");
if (Files.exists(autoKey)) {
logger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
logger.debug(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
return autoKey;
} else {
logger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.missing_key"));
@ -52,7 +52,7 @@ public class FloodgateKeyLoader {
Path floodgateKey;
if (config.getFloodgateKeyFile().equals("public-key.pem")) {
logger.info("Floodgate 2.0 doesn't use a public/private key system anymore. We'll search for key.pem instead");
logger.debug("Floodgate 2.0 doesn't use a public/private key system anymore. We'll search for key.pem instead");
floodgateKey = geyserDataFolder.resolve("key.pem");
} else {
floodgateKey = geyserDataFolder.resolve(config.getFloodgateKeyFile());

View file

@ -66,6 +66,7 @@ import org.geysermc.geyser.session.SessionManager;
import org.geysermc.geyser.session.auth.AuthType;
import org.geysermc.geyser.skin.FloodgateSkinUploader;
import org.geysermc.geyser.skin.SkinProvider;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
@ -203,7 +204,6 @@ public class GeyserImpl implements GeyserApi {
GeyserLogger logger = bootstrap.getGeyserLogger();
GeyserConfiguration config = bootstrap.getGeyserConfig();
logger.setDebug(config.isDebugMode());
ScoreboardUpdater.init();
@ -249,18 +249,6 @@ public class GeyserImpl implements GeyserApi {
// Ensure that PacketLib does not create an event loop for handling packets; we'll do that ourselves
TcpSession.USE_EVENT_LOOP_FOR_PACKETS = false;
if (config.getRemote().getAuthType() == AuthType.FLOODGATE) {
try {
Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath());
cipher = new AesCipher(new Base64Topping());
cipher.init(key);
logger.info(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key"));
skinUploader = new FloodgateSkinUploader(this).start();
} catch (Exception exception) {
logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception);
}
}
String branch = "unknown";
int buildNumber = -1;
if (this.productionEnvironment()) {
@ -321,14 +309,34 @@ public class GeyserImpl implements GeyserApi {
if (shouldStartListener) {
bedrockServer.bind().whenComplete((avoid, throwable) -> {
if (throwable == null) {
logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort())));
logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(),
String.valueOf(config.getBedrock().getPort())));
} else {
logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort())));
throwable.printStackTrace();
String address = config.getBedrock().getAddress();
int port = config.getBedrock().getPort();
logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port)));
if (!"0.0.0.0".equals(address)) {
logger.info(ChatColor.GREEN + "Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0");
logger.info(ChatColor.GREEN + "Then, restart this server.");
}
}
}).join();
}
if (config.getRemote().getAuthType() == AuthType.FLOODGATE) {
try {
Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath());
cipher = new AesCipher(new Base64Topping());
cipher.init(key);
logger.debug(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key"));
// Note: this is positioned after the bind so the skin uploader doesn't try to run if Geyser fails
// to load successfully. Spigot complains about class loader if the plugin is disabled.
skinUploader = new FloodgateSkinUploader(this).start();
} catch (Exception exception) {
logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception);
}
}
if (config.getMetrics().isEnabled()) {
metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger(""));
metrics.addCustomChart(new Metrics.SingleLineChart("players", sessionManager::size));

View file

@ -28,11 +28,11 @@ package org.geysermc.geyser.command.defaults;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import com.nukkitx.math.vector.Vector3i;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.CommandSender;
import org.geysermc.geyser.command.GeyserCommand;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockUtils;
public class OffhandCommand extends GeyserCommand {
@ -46,8 +46,8 @@ public class OffhandCommand extends GeyserCommand {
return;
}
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO,
Direction.DOWN);
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
Direction.DOWN, session.getNextSequence());
session.sendDownstreamPacket(releaseItemPacket);
}

View file

@ -40,6 +40,7 @@ import org.geysermc.geyser.text.AsteriskSerializer;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.network.MinecraftProtocol;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.CpuUtils;
import org.geysermc.geyser.util.FileUtils;
import org.geysermc.geyser.util.WebUtils;
import org.geysermc.floodgate.util.DeviceOs;
@ -64,6 +65,7 @@ public class DumpInfo {
private final DumpInfo.VersionInfo versionInfo;
private final int cpuCount;
private final String cpuName;
private final Locale systemLocale;
private final String systemEncoding;
private Properties gitInfo;
@ -80,6 +82,7 @@ public class DumpInfo {
this.versionInfo = new VersionInfo();
this.cpuCount = Runtime.getRuntime().availableProcessors();
this.cpuName = CpuUtils.tryGetProcessorName();
this.systemLocale = Locale.getDefault();
this.systemEncoding = System.getProperty("file.encoding");

View file

@ -51,6 +51,7 @@ import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.translator.text.MessageTranslator;
public final class EntityDefinitions {
public static final EntityDefinition<AllayEntity> ALLAY;
public static final EntityDefinition<AreaEffectCloudEntity> AREA_EFFECT_CLOUD;
public static final EntityDefinition<ArmorStandEntity> ARMOR_STAND;
public static final EntityDefinition<TippedArrowEntity> ARROW;
@ -63,6 +64,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<SpiderEntity> CAVE_SPIDER;
public static final EntityDefinition<MinecartEntity> CHEST_MINECART;
public static final EntityDefinition<ChickenEntity> CHICKEN;
public static final EntityDefinition<ChestBoatEntity> CHEST_BOAT;
public static final EntityDefinition<AbstractFishEntity> COD;
public static final EntityDefinition<CommandBlockMinecartEntity> COMMAND_BLOCK_MINECART;
public static final EntityDefinition<CowEntity> COW;
@ -88,6 +90,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<FireworkEntity> FIREWORK_ROCKET;
public static final EntityDefinition<FishingHookEntity> FISHING_BOBBER;
public static final EntityDefinition<FoxEntity> FOX;
public static final EntityDefinition<FrogEntity> FROG;
public static final EntityDefinition<FurnaceMinecartEntity> FURNACE_MINECART; // Not present on Bedrock
public static final EntityDefinition<GhastEntity> GHAST;
public static final EntityDefinition<GiantEntity> GIANT;
@ -143,6 +146,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<SquidEntity> SQUID;
public static final EntityDefinition<AbstractSkeletonEntity> STRAY;
public static final EntityDefinition<StriderEntity> STRIDER;
public static final EntityDefinition<TadpoleEntity> TADPOLE;
public static final EntityDefinition<TNTEntity> TNT;
public static final EntityDefinition<MinecartEntity> TNT_MINECART;
public static final EntityDefinition<TraderLlamaEntity> TRADER_LLAMA;
@ -153,6 +157,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<VillagerEntity> VILLAGER;
public static final EntityDefinition<VindicatorEntity> VINDICATOR;
public static final EntityDefinition<AbstractMerchantEntity> WANDERING_TRADER;
public static final EntityDefinition<WardenEntity> WARDEN;
public static final EntityDefinition<RaidParticipantEntity> WITCH;
public static final EntityDefinition<WitherEntity> WITHER;
public static final EntityDefinition<AbstractSkeletonEntity> WITHER_SKELETON;
@ -179,7 +184,7 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles
.addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName)
.addTranslator(MetadataType.BOOLEAN, Entity::setDisplayNameVisible)
.addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.SILENT, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
.addTranslator(MetadataType.BOOLEAN, Entity::setSilent)
.addTranslator(MetadataType.BOOLEAN, Entity::setGravity)
.addTranslator(MetadataType.POSE, (entity, entityMetadata) -> entity.setPose(entityMetadata.getValue()))
.addTranslator(MetadataType.INT, Entity::setFreezing)
@ -209,6 +214,9 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight)
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything
.build();
CHEST_BOAT = EntityDefinition.inherited(ChestBoatEntity::new, BOAT)
.type(EntityType.CHEST_BOAT)
.build();
DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase)
.type(EntityType.DRAGON_FIREBALL)
.heightAndWidth(1.0f)
@ -274,6 +282,7 @@ public final class EntityDefinitions {
.build();
PAINTING = EntityDefinition.<PaintingEntity>inherited(null, entityBase)
.type(EntityType.PAINTING)
.addTranslator(MetadataType.PAINTING_VARIANT, PaintingEntity::setPaintingType)
.build();
SHULKER_BULLET = EntityDefinition.inherited(ThrowableEntity::new, entityBase)
.type(EntityType.SHULKER_BULLET)
@ -441,6 +450,10 @@ public final class EntityDefinitions {
// Extends mob
{
ALLAY = EntityDefinition.inherited(AllayEntity::new, mobEntityBase)
.type(EntityType.ALLAY)
.height(0.6f).width(0.35f)
.build();
BAT = EntityDefinition.inherited(BatEntity::new, mobEntityBase)
.type(EntityType.BAT)
.height(0.9f).width(0.5f)
@ -550,6 +563,11 @@ public final class EntityDefinitions {
.height(0.8f).width(0.4f)
.addTranslator(MetadataType.BYTE, VexEntity::setVexFlags)
.build();
WARDEN = EntityDefinition.inherited(WardenEntity::new, mobEntityBase)
.type(EntityType.WARDEN)
.height(2.9f).width(0.9f)
.addTranslator(MetadataType.INT, WardenEntity::setAngerLevel)
.build();
WITHER = EntityDefinition.inherited(WitherEntity::new, mobEntityBase)
.type(EntityType.WITHER)
.height(3.5f).width(0.9f)
@ -634,6 +652,10 @@ public final class EntityDefinitions {
.type(EntityType.SALMON)
.height(0.5f).width(0.7f)
.build();
TADPOLE = EntityDefinition.inherited(TadpoleEntity::new, abstractFishEntityBase)
.type(EntityType.TADPOLE)
.height(0.3f).width(0.4f)
.build();
TROPICAL_FISH = EntityDefinition.inherited(TropicalFishEntity::new, abstractFishEntityBase)
.type(EntityType.TROPICAL_FISH)
.heightAndWidth(0.6f)
@ -735,6 +757,12 @@ public final class EntityDefinitions {
.addTranslator(null) // Trusted player 1
.addTranslator(null) // Trusted player 2
.build();
FROG = EntityDefinition.inherited(FrogEntity::new, ageableEntityBase)
.type(EntityType.FROG)
.heightAndWidth(0.5f)
.addTranslator(MetadataType.FROG_VARIANT, FrogEntity::setFrogVariant)
.addTranslator(MetadataType.OPTIONAL_VARINT, FrogEntity::setTongueTarget)
.build();
HOGLIN = EntityDefinition.inherited(HoglinEntity::new, ageableEntityBase)
.type(EntityType.HOGLIN)
.height(1.4f).width(1.3965f)
@ -871,7 +899,7 @@ public final class EntityDefinitions {
CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase)
.type(EntityType.CAT)
.height(0.35f).width(0.3f)
.addTranslator(MetadataType.INT, CatEntity::setCatVariant)
.addTranslator(MetadataType.CAT_VARIANT, CatEntity::setCatVariant)
.addTranslator(MetadataType.BOOLEAN, CatEntity::setResting)
.addTranslator(null) // "resting state one" //TODO
.addTranslator(MetadataType.INT, CatEntity::setCollarColor)

View file

@ -52,4 +52,9 @@ public final class GeyserDirtyMetadata {
public boolean hasEntries() {
return !metadata.isEmpty();
}
@Override
public String toString() {
return metadata.toString();
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import java.util.UUID;
public class ChestBoatEntity extends BoatEntity {
public ChestBoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
@Override
protected InteractiveTag testInteraction(Hand hand) {
return passengers.isEmpty() && !session.isSneaking() ? super.testInteraction(hand) : InteractiveTag.OPEN_CONTAINER;
}
@Override
public InteractionResult interact(Hand hand) {
return passengers.isEmpty() && !session.isSneaking() ? super.interact(hand) : InteractionResult.SUCCESS;
}
}

View file

@ -26,7 +26,6 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
@ -50,13 +49,12 @@ public class EnderCrystalEntity extends Entity {
setFlag(EntityFlag.FIRE_IMMUNE, true);
}
public void setBlockTarget(EntityMetadata<Optional<Position>, ?> entityMetadata) {
public void setBlockTarget(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
// Show beam
// Usually performed client-side on Bedrock except for Ender Dragon respawn event
Optional<Position> optionalPos = entityMetadata.getValue();
Optional<Vector3i> optionalPos = entityMetadata.getValue();
if (optionalPos.isPresent()) {
Position pos = optionalPos.get();
dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.from(pos.getX(), pos.getY(), pos.getZ()));
dirtyMetadata.put(EntityData.BLOCK_TARGET, optionalPos.get());
} else {
dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.ZERO);
}

View file

@ -94,6 +94,8 @@ public class Entity {
private float boundingBoxWidth;
@Setter(AccessLevel.NONE)
protected String nametag = "";
@Setter(AccessLevel.NONE)
protected boolean silent = false;
/* Metadata end */
protected List<Entity> passengers = Collections.emptyList();
@ -141,13 +143,19 @@ public class Entity {
*/
protected void initializeMetadata() {
dirtyMetadata.put(EntityData.SCALE, 1f);
dirtyMetadata.put(EntityData.COLOR, 0);
dirtyMetadata.put(EntityData.COLOR, (byte) 0);
dirtyMetadata.put(EntityData.MAX_AIR_SUPPLY, getMaxAir());
setDimensions(Pose.STANDING);
setFlag(EntityFlag.HAS_GRAVITY, true);
setFlag(EntityFlag.HAS_COLLISION, true);
setFlag(EntityFlag.CAN_SHOW_NAME, true);
setFlag(EntityFlag.CAN_CLIMB, true);
// Let the Java server (or us) supply all sounds for an entity
setClientSideSilent();
}
protected void setClientSideSilent() {
setFlag(EntityFlag.SILENT, true);
}
public void spawnEntity() {
@ -351,7 +359,7 @@ public class Entity {
dirtyMetadata.put(EntityData.AIR_SUPPLY, (short) MathUtils.constrain(amount, 0, getMaxAir()));
}
protected int getMaxAir() {
protected short getMaxAir() {
return 300;
}
@ -370,6 +378,10 @@ public class Entity {
dirtyMetadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0));
}
public final void setSilent(BooleanEntityMetadata entityMetadata) {
silent = entityMetadata.getPrimitiveValue();
}
public void setGravity(BooleanEntityMetadata entityMetadata) {
setFlag(EntityFlag.HAS_GRAVITY, !entityMetadata.getPrimitiveValue());
}

View file

@ -27,7 +27,6 @@ package org.geysermc.geyser.entity.type;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
@ -58,7 +57,7 @@ public class EvokerFangsEntity extends Entity implements Tickable {
public void setAttackStarted() {
this.attackStarted = true;
if (!getFlag(EntityFlag.SILENT)) {
if (!silent) {
// Play the chomp sound
PlaySoundPacket packet = new PlaySoundPacket();
packet.setPosition(this.position);

View file

@ -36,8 +36,8 @@ import java.util.UUID;
public class FallingBlockEntity extends Entity {
public FallingBlockEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, int javaId) {
super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, 0f);
public FallingBlockEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, int javaId) {
super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, headYaw);
this.dirtyMetadata.put(EntityData.VARIANT, session.getBlockMappings().getBedrockBlockId(javaId));
}

View file

@ -28,17 +28,16 @@ package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.level.block.BlockPositionIterator;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.util.BlockUtils;
import java.util.UUID;
@ -56,7 +55,7 @@ public class FishingHookEntity extends ThrowableEntity {
private final BoundingBox boundingBox;
public FishingHookEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, PlayerEntity owner) {
public FishingHookEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, PlayerEntity owner) {
super(session, entityId, geyserId, uuid, EntityDefinitions.FISHING_BOBBER, position, motion, yaw, pitch, 0f);
this.boundingBox = new BoundingBox(0.125, 0.125, 0.125, 0.25, 0.25, 0.25);
@ -129,7 +128,7 @@ public class FishingHookEntity extends ThrowableEntity {
}
private void sendSplashSound(GeyserSession session) {
if (!getFlag(EntityFlag.SILENT)) {
if (!silent) {
float volume = (float) (0.2f * Math.sqrt(0.2 * (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) + motion.getY() * motion.getY()));
if (volume > 1) {
volume = 1;

View file

@ -79,8 +79,8 @@ public class ItemFrameEntity extends Entity {
*/
private boolean changed = true;
public ItemFrameEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, Direction direction) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, 0f);
public ItemFrameEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, Direction direction) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
NbtMapBuilder blockBuilder = NbtMap.builder()
.putString("name", this.definition.entityType() == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame")

View file

@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
@ -52,17 +51,13 @@ import lombok.Setter;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.InteractionResult;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
@Getter
@Setter
@ -123,12 +118,11 @@ public class LivingEntity extends Entity {
session.sendUpstreamPacket(attributesPacket);
}
public Vector3i setBedPosition(EntityMetadata<Optional<Position>, ?> entityMetadata) {
Optional<Position> optionalPos = entityMetadata.getValue();
public Vector3i setBedPosition(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
Optional<Vector3i> optionalPos = entityMetadata.getValue();
if (optionalPos.isPresent()) {
Position bedPosition = optionalPos.get();
Vector3i vector = Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ());
dirtyMetadata.put(EntityData.BED_POSITION, vector);
Vector3i bedPosition = optionalPos.get();
dirtyMetadata.put(EntityData.BED_POSITION, bedPosition);
int bed = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
// Bed has to be updated, or else player is floating in the air
ChunkUtils.updateBlock(session, bed, bedPosition);
@ -136,7 +130,7 @@ public class LivingEntity extends Entity {
// Has to be a byte or it does not work
// (Bed position is what actually triggers sleep - "pose" is only optional)
dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 2);
return vector;
return bedPosition;
} else {
// Player is no longer sleeping
dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 0);

View file

@ -25,33 +25,45 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.PaintingType;
import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID;
public class PaintingEntity extends Entity {
private static final double OFFSET = -0.46875;
private final PaintingType paintingName;
private final int direction;
private final Direction direction;
public PaintingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, PaintingType paintingName, int direction) {
super(session, entityId, geyserId, uuid, EntityDefinitions.PAINTING, position, Vector3f.ZERO, 0f, 0f, 0f);
this.paintingName = paintingName;
public PaintingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, Direction direction) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
this.direction = direction;
}
@Override
public void spawnEntity() {
// Wait until we get the metadata needed
}
public void setPaintingType(ObjectEntityMetadata<com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType> entityMetadata) {
PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue());
AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
addPaintingPacket.setUniqueEntityId(geyserId);
addPaintingPacket.setRuntimeEntityId(geyserId);
addPaintingPacket.setMotive(paintingName.getBedrockName());
addPaintingPacket.setPosition(fixOffset());
addPaintingPacket.setDirection(direction);
addPaintingPacket.setMotive(type.getBedrockName());
addPaintingPacket.setPosition(fixOffset(type));
addPaintingPacket.setDirection(switch (direction) {
//TODO this doesn't seem right. Why did it work fine before?
case SOUTH -> 0;
case WEST -> 1;
case NORTH -> 2;
case EAST -> 3;
default -> 0;
});
session.sendUpstreamPacket(addPaintingPacket);
valid = true;
@ -64,17 +76,17 @@ public class PaintingEntity extends Entity {
// Do nothing, as head look messes up paintings
}
private Vector3f fixOffset() {
private Vector3f fixOffset(PaintingType paintingName) {
Vector3f position = super.position;
position = position.add(0.5, 0.5, 0.5);
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
return switch (direction) {
case 0 -> position.add(widthOffset, heightOffset, OFFSET);
case 1 -> position.add(-OFFSET, heightOffset, widthOffset);
case 2 -> position.add(-widthOffset, heightOffset, -OFFSET);
case 3 -> position.add(OFFSET, heightOffset, -widthOffset);
case SOUTH -> position.add(widthOffset, heightOffset, OFFSET);
case WEST -> position.add(-OFFSET, heightOffset, widthOffset);
case NORTH -> position.add(-widthOffset, heightOffset, -OFFSET);
case EAST -> position.add(OFFSET, heightOffset, -widthOffset);
default -> position;
};
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
@ -49,11 +50,11 @@ public class AbstractFishEntity extends WaterEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (EntityUtils.attemptToBucket(session, itemInHand)) {
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import javax.annotation.Nonnull;
import java.util.UUID;
public class AllayEntity extends MobEntity {
public AllayEntity(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);
}
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!this.hand.isValid() && !itemInHand.isEmpty()) {
return InteractiveTag.GIVE_ITEM_TO_ALLAY;
} else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) {
// Seems like there isn't a good tag for this yet
return InteractiveTag.GIVE_ITEM_TO_ALLAY;
} else {
return super.testMobInteraction(hand, itemInHand);
}
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!this.hand.isValid() && !itemInHand.isEmpty()) {
//TODO play sound?
return InteractionResult.SUCCESS;
} else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) {
//TOCHECK also play sound here?
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(hand, itemInHand);
}
}
}

View file

@ -26,9 +26,7 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Rotation;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
@ -165,27 +163,27 @@ public class ArmorStandEntity extends LivingEntity {
setFlag(EntityFlag.ADMIRING, (xd & 0x08) == 0x08); // Has no baseplate
}
public void setHeadRotation(EntityMetadata<Rotation, ?> entityMetadata) {
public void setHeadRotation(EntityMetadata<Vector3f, ?> entityMetadata) {
onRotationUpdate(EntityData.MARK_VARIANT, EntityFlag.INTERESTED, EntityFlag.CHARGED, EntityFlag.POWERED, entityMetadata.getValue());
}
public void setBodyRotation(EntityMetadata<Rotation, ?> entityMetadata) {
public void setBodyRotation(EntityMetadata<Vector3f, ?> entityMetadata) {
onRotationUpdate(EntityData.VARIANT, EntityFlag.IN_LOVE, EntityFlag.CELEBRATING, EntityFlag.CELEBRATING_SPECIAL, entityMetadata.getValue());
}
public void setLeftArmRotation(EntityMetadata<Rotation, ?> entityMetadata) {
public void setLeftArmRotation(EntityMetadata<Vector3f, ?> entityMetadata) {
onRotationUpdate(EntityData.TRADE_TIER, EntityFlag.CHARGING, EntityFlag.CRITICAL, EntityFlag.DANCING, entityMetadata.getValue());
}
public void setRightArmRotation(EntityMetadata<Rotation, ?> entityMetadata) {
public void setRightArmRotation(EntityMetadata<Vector3f, ?> entityMetadata) {
onRotationUpdate(EntityData.MAX_TRADE_TIER, EntityFlag.ELDER, EntityFlag.EMOTING, EntityFlag.IDLING, entityMetadata.getValue());
}
public void setLeftLegRotation(EntityMetadata<Rotation, ?> entityMetadata) {
public void setLeftLegRotation(EntityMetadata<Vector3f, ?> entityMetadata) {
onRotationUpdate(EntityData.SKIN_ID, EntityFlag.IS_ILLAGER_CAPTAIN, EntityFlag.IS_IN_UI, EntityFlag.LINGERING, entityMetadata.getValue());
}
public void setRightLegRotation(EntityMetadata<Rotation, ?> entityMetadata) {
public void setRightLegRotation(EntityMetadata<Vector3f, ?> entityMetadata) {
onRotationUpdate(EntityData.HURT_DIRECTION, EntityFlag.IS_PREGNANT, EntityFlag.SHEARED, EntityFlag.STALKING, entityMetadata.getValue());
}
@ -200,13 +198,13 @@ public class ArmorStandEntity extends LivingEntity {
* @param negativeZToggle the flag to set true if the Z value of rotation is negative
* @param rotation the Java rotation value
*/
private void onRotationUpdate(EntityData dataLeech, EntityFlag negativeXToggle, EntityFlag negativeYToggle, EntityFlag negativeZToggle, Rotation rotation) {
private void onRotationUpdate(EntityData dataLeech, EntityFlag negativeXToggle, EntityFlag negativeYToggle, EntityFlag negativeZToggle, Vector3f rotation) {
// Indicate that rotation should be checked
setFlag(EntityFlag.BRIBED, true);
int rotationX = MathUtils.wrapDegreesToInt(rotation.getPitch());
int rotationY = MathUtils.wrapDegreesToInt(rotation.getYaw());
int rotationZ = MathUtils.wrapDegreesToInt(rotation.getRoll());
int rotationX = MathUtils.wrapDegreesToInt(rotation.getX());
int rotationY = MathUtils.wrapDegreesToInt(rotation.getY());
int rotationZ = MathUtils.wrapDegreesToInt(rotation.getZ());
// The top bit acts like binary and determines if each rotation goes above 100
// We don't do this for the negative values out of concerns of the number being too big
int topBit = (Math.abs(rotationX) >= 100 ? 4 : 0) + (Math.abs(rotationY) >= 100 ? 2 : 0) + (Math.abs(rotationZ) >= 100 ? 1 : 0);

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
@ -47,20 +48,20 @@ public class DolphinEntity extends WaterEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) {
return InteractiveTag.FEED;
}
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) {
// Feed
return InteractionResult.SUCCESS;
}
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -48,7 +49,7 @@ public class IronGolemEntity extends GolemEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().ironIngot()) {
if (health < maxHealth) {
// Healing the iron golem
@ -57,6 +58,6 @@ public class IronGolemEntity extends GolemEntity {
return InteractionResult.PASS;
}
}
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}

View file

@ -90,7 +90,7 @@ public class MobEntity extends LivingEntity {
}
}
InteractiveTag tag = testMobInteraction(itemStack);
InteractiveTag tag = testMobInteraction(hand, itemStack);
return tag != InteractiveTag.NONE ? tag : super.testInteraction(hand);
}
}
@ -109,7 +109,7 @@ public class MobEntity extends LivingEntity {
if (result.consumesAction()) {
return result;
} else {
InteractionResult mobResult = mobInteract(itemInHand);
InteractionResult mobResult = mobInteract(hand, itemInHand);
return mobResult.consumesAction() ? mobResult : super.interact(hand);
}
}
@ -137,12 +137,12 @@ public class MobEntity extends LivingEntity {
}
@Nonnull
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
return InteractiveTag.NONE;
}
@Nonnull
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
return InteractionResult.PASS;
}

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
@ -51,7 +52,7 @@ public class SnowGolemEntity extends GolemEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (session.getItemMappings().getStoredItems().shears() == itemInHand.getJavaId() && isAlive() && !getFlag(EntityFlag.SHEARED)) {
// Shearing the snow golem
return InteractiveTag.SHEAR;
@ -61,7 +62,7 @@ public class SnowGolemEntity extends GolemEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (session.getItemMappings().getStoredItems().shears() == itemInHand.getJavaId() && isAlive() && !getFlag(EntityFlag.SHEARED)) {
// Shearing the snow golem
return InteractionResult.SUCCESS;

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import javax.annotation.Nonnull;
import java.util.UUID;
public class TadpoleEntity extends AbstractFishEntity {
public TadpoleEntity(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);
}
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (isFood(itemInHand)) {
return InteractiveTag.FEED;
}
return super.testMobInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (isFood(itemInHand)) {
//TODO particles
return InteractionResult.SUCCESS;
}
return super.mobInteract(hand, itemInHand);
}
private boolean isFood(GeyserItemStack itemStack) {
return itemStack.getJavaId() == session.getItemMappings().getStoredItems().slimeBall();
}
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -63,16 +64,16 @@ public class AnimalEntity extends AgeableEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (canEat(itemInHand)) {
return InteractiveTag.FEED;
}
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (canEat(itemInHand)) {
// FEED
if (getFlag(EntityFlag.BABY)) {
@ -82,6 +83,6 @@ public class AnimalEntity extends AgeableEntity {
return InteractionResult.CONSUME;
}
}
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}

View file

@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -64,7 +65,7 @@ public class AxolotlEntity extends AnimalEntity {
}
@Override
protected int getMaxAir() {
protected short getMaxAir() {
return 6000;
}
@ -75,11 +76,11 @@ public class AxolotlEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (EntityUtils.attemptToBucket(session, itemInHand)) {
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -44,9 +45,9 @@ public class CowEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (getFlag(EntityFlag.BABY) || !itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) {
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
return InteractiveTag.MILK;
@ -54,9 +55,9 @@ public class CowEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (getFlag(EntityFlag.BABY) || !itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
session.playSoundEvent(SoundEvent.MILK, position);

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import java.util.OptionalInt;
import java.util.UUID;
public class FrogEntity extends AnimalEntity {
public FrogEntity(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) {
setFlag(EntityFlag.JUMP_GOAL_JUMP, pose == Pose.LONG_JUMPING);
setFlag(EntityFlag.CROAKING, pose == Pose.CROAKING);
setFlag(EntityFlag.EAT_MOB, pose == Pose.USING_TONGUE);
super.setPose(pose);
}
public void setFrogVariant(IntEntityMetadata entityMetadata) {
int variant = entityMetadata.getPrimitiveValue();
dirtyMetadata.put(EntityData.VARIANT, switch (variant) {
case 1 -> 2; // White
case 2 -> 1; // Green
default -> variant;
});
}
public void setTongueTarget(ObjectEntityMetadata<OptionalInt> entityMetadata) {
OptionalInt entityId = entityMetadata.getValue();
if (entityId.isPresent()) {
Entity entity = session.getEntityCache().getEntityByJavaId(entityId.getAsInt());
if (entity != null) {
dirtyMetadata.put(EntityData.TARGET_EID, entity.getGeyserId());
}
} else {
dirtyMetadata.put(EntityData.TARGET_EID, 0L);
}
}
@Override
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
return mapping.getJavaId() == session.getItemMappings().getStoredItems().slimeBall();
}
}

View file

@ -27,6 +27,7 @@ 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.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -65,12 +66,12 @@ public class GoatEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!getFlag(EntityFlag.BABY) && itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) {
session.playSoundEvent(isScreamer ? SoundEvent.MILK_SCREAMER : SoundEvent.MILK, position);
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}
}

View file

@ -49,7 +49,7 @@ public class HoglinEntity extends AnimalEntity {
@Override
protected boolean isShaking() {
return (!isImmuneToZombification && !session.isDimensionPiglinSafe()) || super.isShaking();
return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking();
}
@Override

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import org.geysermc.geyser.entity.EntityDefinition;
@ -52,7 +53,7 @@ public class MooshroomEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
StoredItemMappings storedItems = session.getItemMappings().getStoredItems();
if (!isBaby()) {
if (itemInHand.getJavaId() == storedItems.bowl()) {
@ -63,12 +64,12 @@ public class MooshroomEntity extends AnimalEntity {
return InteractiveTag.MOOSHROOM_SHEAR;
}
}
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
StoredItemMappings storedItems = session.getItemMappings().getStoredItems();
boolean isBaby = isBaby();
if (!isBaby && itemInHand.getJavaId() == storedItems.bowl()) {
@ -81,6 +82,6 @@ public class MooshroomEntity extends AnimalEntity {
// ?
return InteractionResult.SUCCESS;
}
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
@ -50,23 +51,23 @@ public class OcelotEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!getFlag(EntityFlag.TRUSTING) && canEat(itemInHand) && session.getPlayerEntity().getPosition().distanceSquared(position) < 9f) {
// Attempt to feed
return InteractiveTag.FEED;
} else {
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!getFlag(EntityFlag.TRUSTING) && canEat(itemInHand) && session.getPlayerEntity().getPosition().distanceSquared(position) < 9f) {
// Attempt to feed
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}
}

View file

@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
@ -93,16 +94,16 @@ public class PandaEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (mainGene == Gene.WORRIED && session.isThunder()) {
return InteractiveTag.NONE;
}
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (mainGene == Gene.WORRIED && session.isThunder()) {
// Huh!
return InteractionResult.PASS;

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
@ -51,12 +52,12 @@ public class PigEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) {
// Mount
return InteractiveTag.MOUNT;
} else {
InteractiveTag superTag = super.testMobInteraction(itemInHand);
InteractiveTag superTag = super.testMobInteraction(hand, itemInHand);
if (superTag != InteractiveTag.NONE) {
return superTag;
} else {
@ -68,12 +69,12 @@ public class PigEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) {
// Mount
return InteractionResult.SUCCESS;
} else {
InteractionResult superResult = super.mobInteract(itemInHand);
InteractionResult superResult = super.mobInteract(hand, itemInHand);
if (superResult.consumesAction()) {
return superResult;
} else {

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -55,11 +56,11 @@ public class SheepEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().shears()) {
return InteractiveTag.SHEAR;
} else {
InteractiveTag tag = super.testMobInteraction(itemInHand);
InteractiveTag tag = super.testMobInteraction(hand, itemInHand);
if (tag != InteractiveTag.NONE) {
return tag;
} else {
@ -74,11 +75,11 @@ public class SheepEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().shears()) {
return InteractionResult.CONSUME;
} else {
InteractionResult superResult = super.mobInteract(itemInHand);
InteractionResult superResult = super.mobInteract(hand, itemInHand);
if (superResult.consumesAction()) {
return superResult;
} else {

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.type.Entity;
@ -98,12 +99,12 @@ public class StriderEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) {
// Mount Strider
return InteractiveTag.RIDE_STRIDER;
} else {
InteractiveTag tag = super.testMobInteraction(itemInHand);
InteractiveTag tag = super.testMobInteraction(hand, itemInHand);
if (tag != InteractiveTag.NONE) {
return tag;
} else {
@ -115,12 +116,12 @@ public class StriderEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) {
// Mount Strider
return InteractionResult.SUCCESS;
} else {
InteractionResult superResult = super.mobInteract(itemInHand);
InteractionResult superResult = super.mobInteract(hand, itemInHand);
if (superResult.consumesAction()) {
return superResult;
} else {

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.google.common.collect.ImmutableSet;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
@ -129,12 +130,12 @@ public class AbstractHorseEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
return testHorseInteraction(itemInHand);
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
return testHorseInteraction(hand, itemInHand);
}
@Nonnull
protected final InteractiveTag testHorseInteraction(@Nonnull GeyserItemStack itemInHand) {
protected final InteractiveTag testHorseInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
boolean isBaby = isBaby();
if (!isBaby) {
if (getFlag(EntityFlag.TAMED) && session.isSneaking()) {
@ -142,7 +143,7 @@ public class AbstractHorseEntity extends AnimalEntity {
}
if (!passengers.isEmpty()) {
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
}
@ -171,7 +172,7 @@ public class AbstractHorseEntity extends AnimalEntity {
}
if (isBaby) {
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
} else {
return InteractiveTag.MOUNT;
}
@ -179,12 +180,12 @@ public class AbstractHorseEntity extends AnimalEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
return mobHorseInteract(itemInHand);
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
return mobHorseInteract(hand, itemInHand);
}
@Nonnull
protected final InteractionResult mobHorseInteract(@Nonnull GeyserItemStack itemInHand) {
protected final InteractionResult mobHorseInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
boolean isBaby = isBaby();
if (!isBaby) {
if (getFlag(EntityFlag.TAMED) && session.isSneaking()) {
@ -193,7 +194,7 @@ public class AbstractHorseEntity extends AnimalEntity {
}
if (!passengers.isEmpty()) {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}
@ -227,7 +228,7 @@ public class AbstractHorseEntity extends AnimalEntity {
}
if (isBaby) {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
} else {
// Attempt to mount
// TODO client-set flags sitting standing?
@ -249,15 +250,15 @@ public class AbstractHorseEntity extends AnimalEntity {
/* Just a place to stuff common code for the undead variants without having duplicate code */
protected final InteractiveTag testUndeadHorseInteraction(@Nonnull GeyserItemStack itemInHand) {
protected final InteractiveTag testUndeadHorseInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!getFlag(EntityFlag.TAMED)) {
return InteractiveTag.NONE;
} else if (isBaby()) {
return testHorseInteraction(itemInHand);
return testHorseInteraction(hand, itemInHand);
} else if (session.isSneaking()) {
return InteractiveTag.OPEN_CONTAINER;
} else if (!passengers.isEmpty()) {
return testHorseInteraction(itemInHand);
return testHorseInteraction(hand, itemInHand);
} else {
if (session.getItemMappings().getStoredItems().saddle() == itemInHand.getJavaId()) {
return InteractiveTag.OPEN_CONTAINER;
@ -271,16 +272,16 @@ public class AbstractHorseEntity extends AnimalEntity {
}
}
protected final InteractionResult undeadHorseInteract(@Nonnull GeyserItemStack itemInHand) {
protected final InteractionResult undeadHorseInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!getFlag(EntityFlag.TAMED)) {
return InteractionResult.PASS;
} else if (isBaby()) {
return mobHorseInteract(itemInHand);
return mobHorseInteract(hand, itemInHand);
} else if (session.isSneaking()) {
// Opens inventory
return InteractionResult.SUCCESS;
} else if (!passengers.isEmpty()) {
return mobHorseInteract(itemInHand);
return mobHorseInteract(hand, itemInHand);
} else {
// The client tests for saddle but it doesn't matter for us at this point.
return InteractionResult.SUCCESS;

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
@ -42,13 +43,13 @@ public class SkeletonHorseEntity extends AbstractHorseEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
return testUndeadHorseInteraction(itemInHand);
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
return testUndeadHorseInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
return undeadHorseInteract(itemInHand);
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
return undeadHorseInteract(hand, itemInHand);
}
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
@ -42,13 +43,13 @@ public class ZombieHorseEntity extends AbstractHorseEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
return testUndeadHorseInteraction(itemInHand);
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
return testUndeadHorseInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
return undeadHorseInteract(itemInHand);
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
return undeadHorseInteract(hand, itemInHand);
}
}

View file

@ -28,6 +28,7 @@ package org.geysermc.geyser.entity.type.living.animal.tameable;
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 com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -105,7 +106,7 @@ public class CatEntity extends TameableEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
boolean tamed = getFlag(EntityFlag.TAMED);
if (tamed && ownerBedrockId == session.getPlayerEntity().getGeyserId()) {
// Toggle sitting
@ -117,7 +118,7 @@ public class CatEntity extends TameableEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
boolean tamed = getFlag(EntityFlag.TAMED);
if (tamed && ownerBedrockId == session.getPlayerEntity().getGeyserId()) {
return InteractionResult.SUCCESS;

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
@ -58,7 +59,7 @@ public class ParrotEntity extends TameableEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
String javaIdentifierStripped = itemInHand.getMapping(session).getJavaIdentifier().replace("minecraft:", "");
boolean tame = getFlag(EntityFlag.TAMED);
if (!tame && isTameFood(javaIdentifierStripped)) {
@ -69,12 +70,12 @@ public class ParrotEntity extends TameableEntity {
// Sitting/standing
return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
}
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
String javaIdentifierStripped = itemInHand.getMapping(session).getJavaIdentifier().replace("minecraft:", "");
boolean tame = getFlag(EntityFlag.TAMED);
if (!tame && isTameFood(javaIdentifierStripped)) {
@ -85,6 +86,6 @@ public class ParrotEntity extends TameableEntity {
// Sitting/standing
return InteractionResult.SUCCESS;
}
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}

View file

@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type.living.animal.tameable;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.google.common.collect.ImmutableSet;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
@ -103,7 +104,7 @@ public class WolfEntity extends TameableEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (getFlag(EntityFlag.ANGRY)) {
return InteractiveTag.NONE;
}
@ -122,12 +123,12 @@ public class WolfEntity extends TameableEntity {
return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
}
}
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (ownerBedrockId == session.getPlayerEntity().getGeyserId() || getFlag(EntityFlag.TAMED)
|| itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bone") && !getFlag(EntityFlag.ANGRY)) {
// Sitting toggle or feeding; not angry

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.merchant;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
@ -51,7 +52,7 @@ public class AbstractMerchantEntity extends AgeableEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
String javaIdentifier = itemInHand.getMapping(session).getJavaIdentifier();
if (!javaIdentifier.equals("minecraft:villager_spawn_egg")
&& (definition != EntityDefinitions.VILLAGER || !getFlag(EntityFlag.SLEEPING) && ((VillagerEntity) this).isCanTradeWith())) {
@ -60,12 +61,12 @@ public class AbstractMerchantEntity extends AgeableEntity {
return InteractiveTag.TRADE;
}
}
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
String javaIdentifier = itemInHand.getMapping(session).getJavaIdentifier();
if (!javaIdentifier.equals("minecraft:villager_spawn_egg")
&& (definition != EntityDefinitions.VILLAGER || !getFlag(EntityFlag.SLEEPING))
@ -73,7 +74,7 @@ public class AbstractMerchantEntity extends AgeableEntity {
// Trading time
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}
}

View file

@ -26,7 +26,6 @@
package org.geysermc.geyser.entity.type.living.merchant;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.math.vector.Vector3i;
@ -103,7 +102,7 @@ public class VillagerEntity extends AbstractMerchantEntity {
}
@Override
public Vector3i setBedPosition(EntityMetadata<Optional<Position>, ?> entityMetadata) {
public Vector3i setBedPosition(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
return bedPosition = super.setBedPosition(entityMetadata);
}

View file

@ -48,6 +48,6 @@ public class BasePiglinEntity extends MonsterEntity {
@Override
protected boolean isShaking() {
return (!isImmuneToZombification && !session.isDimensionPiglinSafe()) || super.isShaking();
return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking();
}
}

View file

@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -63,23 +64,23 @@ public class CreeperEntity extends MonsterEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) {
return InteractiveTag.IGNITE_CREEPER;
} else {
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) {
// Ignite creeper
session.playSoundEvent(SoundEvent.IGNITE, position);
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}
}

View file

@ -213,7 +213,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable {
*/
private void effectTick() {
Random random = ThreadLocalRandom.current();
if (!getFlag(EntityFlag.SILENT)) {
if (!silent) {
if (Math.cos(wingPosition * 2f * Math.PI) <= -0.3f && Math.cos(lastWingPosition * 2f * Math.PI) >= -0.3f) {
PlaySoundPacket playSoundPacket = new PlaySoundPacket();
playSoundPacket.setSound("mob.enderdragon.flap");

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -71,8 +72,8 @@ public class PiglinEntity extends BasePiglinEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
InteractiveTag tag = super.testMobInteraction(itemInHand);
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
InteractiveTag tag = super.testMobInteraction(hand, itemInHand);
if (tag != InteractiveTag.NONE) {
return tag;
} else {
@ -82,8 +83,8 @@ public class PiglinEntity extends BasePiglinEntity {
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
InteractionResult superResult = super.mobInteract(itemInHand);
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
InteractionResult superResult = super.mobInteract(hand, itemInHand);
if (superResult.consumesAction()) {
return superResult;
} else {

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.nukkitx.math.GenericMath;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Tickable;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.MathUtils;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
public class WardenEntity extends MonsterEntity implements Tickable {
private int heartBeatDelay;
private int tickCount;
private int sonicBoomTickDuration;
public WardenEntity(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) {
setFlag(EntityFlag.DIGGING, pose == Pose.DIGGING);
setFlag(EntityFlag.EMERGING, pose == Pose.EMERGING);
setFlag(EntityFlag.ROARING, pose == Pose.ROARING);
setFlag(EntityFlag.SNIFFING, pose == Pose.SNIFFING);
super.setPose(pose);
}
public void setAngerLevel(IntEntityMetadata entityMetadata) {
float anger = (float) entityMetadata.getPrimitiveValue() / 80f;
heartBeatDelay = 40 - GenericMath.floor(MathUtils.clamp(anger, 0.0F, 1.0F) * 30F);
dirtyMetadata.put(EntityData.HEARTBEAT_INTERVAL_TICKS, heartBeatDelay);
}
@Override
public void tick() {
if (++tickCount % heartBeatDelay == 0 && !silent) {
// We have to do these calculations because they're clientside on Java Edition but we mute entities
// to prevent hearing their step sounds
ThreadLocalRandom random = ThreadLocalRandom.current();
PlaySoundPacket packet = new PlaySoundPacket();
packet.setSound("mob.warden.heartbeat");
packet.setPosition(position);
packet.setPitch((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f);
packet.setVolume(1.0f);
session.sendUpstreamPacket(packet);
}
if (sonicBoomTickDuration > 0) {
sonicBoomTickDuration--;
if (sonicBoomTickDuration == 0) {
setFlag(EntityFlag.SONIC_BOOM, false);
updateBedrockMetadata();
}
}
}
public void onSonicBoom() {
setFlag(EntityFlag.SONIC_BOOM, true);
updateBedrockMetadata();
sonicBoomTickDuration = 3 * 20;
}
}

View file

@ -28,6 +28,7 @@ package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -67,22 +68,22 @@ public class ZombieVillagerEntity extends ZombieEntity {
@Nonnull
@Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) {
protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) {
return InteractiveTag.CURE;
} else {
return super.testMobInteraction(itemInHand);
return super.testMobInteraction(hand, itemInHand);
}
}
@Nonnull
@Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) {
protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) {
// The client doesn't know if the entity has weakness as that's not usually sent over the network
return InteractionResult.CONSUME;
} else {
return super.mobInteract(itemInHand);
return super.mobInteract(hand, itemInHand);
}
}
}

View file

@ -27,7 +27,6 @@ package org.geysermc.geyser.entity.type.player;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
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 com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
@ -169,6 +168,12 @@ public class PlayerEntity extends LivingEntity {
}
session.sendUpstreamPacket(movePlayerPacket);
if (teleported) {
// As of 1.19.0, head yaw seems to be ignored during teleports.
updateHeadLookRotation(headYaw);
}
if (leftParrot != null) {
leftParrot.moveAbsolute(position, yaw, pitch, headYaw, true, teleported);
}
@ -211,52 +216,8 @@ public class PlayerEntity extends LivingEntity {
}
}
@Override
public void updateHeadLookRotation(float headYaw) {
moveRelative(0, 0, 0, getYaw(), getPitch(), headYaw, isOnGround());
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(geyserId);
movePlayerPacket.setPosition(position);
movePlayerPacket.setRotation(getBedrockRotation());
movePlayerPacket.setMode(MovePlayerPacket.Mode.HEAD_ROTATION);
session.sendUpstreamPacket(movePlayerPacket);
}
@Override
public void updatePositionAndRotation(double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) {
moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround);
if (leftParrot != null) {
leftParrot.moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround);
}
if (rightParrot != null) {
rightParrot.moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround);
}
}
public void updateRotation(float yaw, float pitch, float headYaw, boolean isOnGround) {
// the method below is called by super.updateRotation(yaw, pitch, isOnGround).
// but we have to be able to set the headYaw, so we call the method below directly.
super.moveRelative(0, 0, 0, yaw, pitch, headYaw, isOnGround);
// Both packets need to be sent or else player head rotation isn't correctly updated
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(geyserId);
movePlayerPacket.setPosition(position);
movePlayerPacket.setRotation(getBedrockRotation());
movePlayerPacket.setOnGround(isOnGround);
movePlayerPacket.setMode(MovePlayerPacket.Mode.HEAD_ROTATION);
session.sendUpstreamPacket(movePlayerPacket);
if (leftParrot != null) {
leftParrot.updateRotation(yaw, pitch, isOnGround);
}
if (rightParrot != null) {
rightParrot.updateRotation(yaw, pitch, isOnGround);
}
}
@Override
public void updateRotation(float yaw, float pitch, boolean isOnGround) {
updateRotation(yaw, pitch, getHeadYaw(), isOnGround);
moveRelative(0, 0, 0, yaw, pitch, headYaw, isOnGround);
}
@Override
@ -265,7 +226,7 @@ public class PlayerEntity extends LivingEntity {
}
@Override
public Vector3i setBedPosition(EntityMetadata<Optional<Position>, ?> entityMetadata) {
public Vector3i setBedPosition(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
return bedPosition = super.setBedPosition(entityMetadata);
}

View file

@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type.player;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.nukkitx.math.vector.Vector3f;
@ -40,11 +41,10 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.DimensionUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import java.util.*;
/**
* The entity class specifically for a {@link GeyserSession}'s player.
@ -75,6 +75,11 @@ public class SessionPlayerEntity extends PlayerEntity {
valid = true;
}
@Override
protected void setClientSideSilent() {
// Do nothing, since we want the session player to hear their own footstep sounds for example.
}
@Override
public void spawnEntity() {
// Already logged in
@ -222,4 +227,14 @@ public class SessionPlayerEntity extends PlayerEntity {
this.attributes.put(type, attributeData);
return attributeData;
}
public void setLastDeathPosition(@Nullable GlobalPos pos) {
if (pos != null) {
dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_POS, pos.getPosition());
dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension()));
dirtyMetadata.put(EntityData.PLAYER_HAS_DIED, (byte) 1);
} else {
dirtyMetadata.put(EntityData.PLAYER_HAS_DIED, (byte) 0);
}
}
}

View file

@ -46,7 +46,7 @@ public class GeyserEnchantOption {
*/
private static final List<String> ENCHANT_NAMES = Arrays.asList("tougher armor", "lukeeey", "fall better",
"explode less", "camo toy", "breathe better", "rtm five one six", "armor stab", "water walk", "you are elsa",
"tim two zero three", "fast walk nether", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned",
"tim two zero three", "fast walk nether", "davchoo", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned",
"more items thx", "long sword reach", "fast tool", "give me block", "less breaky break", "cube craft",
"strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", "come here fish", "i like this",
"stabby stab", "supreme mortal", "avatar i guess", "more arrows", "fly finder seventeen", "in and out",

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.inventory.holder;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.google.common.collect.ImmutableSet;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
@ -36,9 +35,9 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.inventory.Container;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.util.BlockUtils;
import java.util.Collections;
@ -154,8 +153,7 @@ public class BlockInventoryHolder extends InventoryHolder {
}
Vector3i holderPos = inventory.getHolderPosition();
Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ());
int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ());
int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos.getX(), holderPos.getY(), holderPos.getZ());
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(holderPos);

View file

@ -67,7 +67,8 @@ public enum Enchantment {
MULTISHOT,
PIERCING,
QUICK_CHARGE,
SOUL_SPEED;
SOUL_SPEED,
SWIFT_SNEAK;
private static final Enchantment[] VALUES = values();
@ -109,6 +110,7 @@ public enum Enchantment {
FROST_WALKER,
BINDING_CURSE,
SOUL_SPEED,
SWIFT_SNEAK,
SHARPNESS,
SMITE,
BANE_OF_ARTHROPODS,

View file

@ -60,6 +60,7 @@ public class StoredItemMappings {
private final int saddle;
private final int shears;
private final ItemMapping shield;
private final int slimeBall;
private final int waterBucket;
private final ItemMapping wheat;
private final ItemMapping writableBook;
@ -87,6 +88,7 @@ public class StoredItemMappings {
this.saddle = load(itemMappings, "saddle").getJavaId();
this.shears = load(itemMappings, "shears").getJavaId();
this.shield = load(itemMappings, "shield");
this.slimeBall = load(itemMappings, "slime_ball").getJavaId();
this.waterBucket = load(itemMappings, "water_bucket").getJavaId();
this.wheat = load(itemMappings, "wheat");
this.writableBook = load(itemMappings, "writable_book");

View file

@ -28,6 +28,7 @@ package org.geysermc.geyser.level;
import com.github.steveice10.mc.protocol.data.game.advancement.Advancement;
import lombok.NonNull;
import org.geysermc.geyser.session.cache.AdvancementsCache;
import org.geysermc.geyser.text.ChatColor;
import java.util.List;
@ -69,6 +70,14 @@ public class GeyserAdvancement {
return this.advancement.getDisplayData();
}
/**
* @return Purple for challenges and green for normal advancements
*/
public String getDisplayColor() {
Advancement.DisplayData displayData = getDisplayData();
return displayData != null && displayData.getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE ? ChatColor.LIGHT_PURPLE : ChatColor.GREEN;
}
public String getRootId(AdvancementsCache advancementsCache) {
if (rootId == null) {
if (this.advancement.getParentId() == null) {

View file

@ -27,15 +27,14 @@ package org.geysermc.geyser.level;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.ChunkCache;
import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
import org.geysermc.geyser.level.block.BlockStateValues;
import java.util.Locale;
@ -83,7 +82,7 @@ public class GeyserWorldManager extends WorldManager {
@Override
public void setGameRule(GeyserSession session, String name, Object value) {
session.sendDownstreamPacket(new ServerboundChatPacket("/gamerule " + name + " " + value));
session.sendCommand("gamerule " + name + " " + value);
gameruleCache.put(name, String.valueOf(value));
}
@ -109,12 +108,12 @@ public class GeyserWorldManager extends WorldManager {
@Override
public void setPlayerGameMode(GeyserSession session, GameMode gameMode) {
session.sendDownstreamPacket(new ServerboundChatPacket("/gamemode " + gameMode.name().toLowerCase(Locale.ROOT)));
session.sendCommand("gamemode " + gameMode.name().toLowerCase(Locale.ROOT));
}
@Override
public void setDifficulty(GeyserSession session, Difficulty difficulty) {
session.sendDownstreamPacket(new ServerboundChatPacket("/difficulty " + difficulty.name().toLowerCase(Locale.ROOT)));
session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT));
}
@Override

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.level;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import org.geysermc.geyser.util.JavaCodecEntry;
import java.util.Map;
/**
* Represents the information we store from the current Java dimension
* @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension.
* This controls if they have the shaking effect applied in the dimension.
*/
public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale) {
public static void load(CompoundTag tag, Map<String, JavaDimension> map) {
for (CompoundTag dimension : JavaCodecEntry.iterateAsTag(tag.get("minecraft:dimension_type"))) {
CompoundTag elements = dimension.get("element");
int minY = ((IntTag) elements.get("min_y")).getValue();
int maxY = ((IntTag) elements.get("height")).getValue();
// Logical height can be ignored probably - seems to be for artificial limits like the Nether.
// Set if piglins/hoglins should shake
boolean piglinSafe = ((Number) elements.get("piglin_safe").getValue()).byteValue() != (byte) 0;
// Load world coordinate scale for the world border
double coordinateScale = ((Number) elements.get("coordinate_scale").getValue()).doubleValue();
map.put((String) dimension.get("name").getValue(), new JavaDimension(minY, maxY, piglinSafe, coordinateScale));
}
}
}

View file

@ -56,17 +56,17 @@ public enum PaintingType {
SKELETON("Skeleton", 4, 3),
DONKEY_KONG("DonkeyKong", 4, 3),
POINTER("Pointer", 4, 4),
PIG_SCENE("Pigscene", 4, 4),
BURNING_SKULL("BurningSkull", 4, 4);
PIGSCENE("Pigscene", 4, 4),
BURNING_SKULL("BurningSkull", 4, 4),
EARTH("Earth", 2, 2),
WIND("Wind", 2, 2),
WATER("Water", 2, 2),
FIRE("Fire", 2, 2);
private static final PaintingType[] VALUES = values();
private String bedrockName;
private int width;
private int height;
public com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType toJavaType() {
return com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType.valueOf(name());
}
private final String bedrockName;
private final int width;
private final int height;
public static PaintingType getByName(String javaName) {
for (PaintingType paintingName : VALUES) {

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.level;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
import com.nukkitx.math.vector.Vector3i;
@ -41,17 +40,6 @@ import org.geysermc.geyser.session.GeyserSession;
*/
public abstract class WorldManager {
/**
* Gets the Java block state at the specified location
*
* @param session the session
* @param position the position
* @return the block state at the specified location
*/
public int getBlockAt(GeyserSession session, Position position) {
return this.getBlockAt(session, position.getX(), position.getY(), position.getZ());
}
/**
* Gets the Java block state at the specified location
*
@ -59,7 +47,7 @@ public abstract class WorldManager {
* @param vector the position
* @return the block state at the specified location
*/
public int getBlockAt(GeyserSession session, Vector3i vector) {
public final int getBlockAt(GeyserSession session, Vector3i vector) {
return this.getBlockAt(session, vector.getX(), vector.getY(), vector.getZ());
}

View file

@ -28,9 +28,7 @@ package org.geysermc.geyser.network;
import com.github.steveice10.mc.protocol.codec.MinecraftCodec;
import com.github.steveice10.mc.protocol.codec.PacketCodec;
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
import com.nukkitx.protocol.bedrock.v475.Bedrock_v475;
import com.nukkitx.protocol.bedrock.v486.Bedrock_v486;
import com.nukkitx.protocol.bedrock.v503.Bedrock_v503;
import com.nukkitx.protocol.bedrock.beta.BedrockBeta;
import java.util.ArrayList;
import java.util.Collections;
@ -45,7 +43,7 @@ public final class MinecraftProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports.
*/
public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v503.V503_CODEC;
public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = BedrockBeta.BETA_CODEC;
/**
* A list of all supported Bedrock versions that can join Geyser
*/
@ -58,12 +56,8 @@ public final class MinecraftProtocol {
private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC;
static {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v475.V475_CODEC.toBuilder().minecraftVersion("1.18.0/1.18.1/1.18.2").build());
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v486.V486_CODEC.toBuilder()
.minecraftVersion("1.18.10/1.18.12") // 1.18.11 is also supported, but was only on Switch and since that auto-updates it's not needed
.build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
.minecraftVersion("1.18.30/1.18.31")
.minecraftVersion("1.19.0")
.build());
}

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.network.netty;
import com.github.steveice10.packetlib.BuiltinFlags;
import com.github.steveice10.packetlib.codec.PacketCodecHelper;
import com.github.steveice10.packetlib.packet.PacketProtocol;
import com.github.steveice10.packetlib.tcp.*;
import io.netty.bootstrap.Bootstrap;
@ -47,15 +48,17 @@ public final class LocalSession extends TcpSession {
private final SocketAddress targetAddress;
private final String clientIp;
private final PacketCodecHelper codecHelper;
public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol) {
public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, PacketCodecHelper codecHelper) {
super(host, port, protocol);
this.targetAddress = targetAddress;
this.clientIp = clientIp;
this.codecHelper = codecHelper;
}
@Override
public void connect() {
public void connect(boolean wait) {
if (this.disconnected) {
throw new IllegalStateException("Connection has already been disconnected.");
}
@ -102,6 +105,11 @@ public final class LocalSession extends TcpSession {
}
}
@Override
public PacketCodecHelper getCodecHelper() {
return this.codecHelper;
}
// TODO duplicate code
private void addHAProxySupport(ChannelPipeline pipeline) {
InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS);

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.registry;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.mc.protocol.data.game.level.event.SoundEvent;
import com.github.steveice10.mc.protocol.data.game.level.event.LevelEvent;
import com.github.steveice10.mc.protocol.data.game.level.particle.ParticleType;
import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
import com.github.steveice10.packetlib.packet.Packet;
@ -155,9 +155,9 @@ public final class Registries {
public static final SimpleMappedRegistry<String, SoundMapping> SOUNDS = SimpleMappedRegistry.create("mappings/sounds.json", SoundRegistryLoader::new);
/**
* A mapped registry holding {@link SoundEvent}s to their corresponding {@link LevelEventTranslator}.
* A mapped registry holding {@link LevelEvent}s to their corresponding {@link LevelEventTranslator}.
*/
public static final SimpleMappedRegistry<SoundEvent, LevelEventTranslator> SOUND_EVENTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new);
public static final SimpleMappedRegistry<LevelEvent, LevelEventTranslator> SOUND_LEVEL_EVENTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new);
/**
* A mapped registry holding {@link SoundTranslator}s to their corresponding {@link SoundInteractionTranslator}.

View file

@ -26,7 +26,7 @@
package org.geysermc.geyser.registry.loader;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.steveice10.mc.protocol.data.game.level.event.SoundEvent;
import com.github.steveice10.mc.protocol.data.game.level.event.LevelEvent;
import com.nukkitx.protocol.bedrock.data.LevelEventType;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.geyser.GeyserImpl;
@ -41,37 +41,37 @@ import java.util.Map;
/**
* Loads sound effects from the given resource path.
*/
public class SoundEventsRegistryLoader extends EffectRegistryLoader<Map<SoundEvent, LevelEventTranslator>> {
public class SoundEventsRegistryLoader extends EffectRegistryLoader<Map<LevelEvent, LevelEventTranslator>> {
@Override
public Map<SoundEvent, LevelEventTranslator> load(String input) {
public Map<LevelEvent, LevelEventTranslator> load(String input) {
this.loadFile(input);
Iterator<Map.Entry<String, JsonNode>> effectsIterator = this.get(input).fields();
Map<SoundEvent, LevelEventTranslator> soundEffects = new Object2ObjectOpenHashMap<>();
Map<LevelEvent, LevelEventTranslator> soundEffects = new Object2ObjectOpenHashMap<>();
while (effectsIterator.hasNext()) {
Map.Entry<String, JsonNode> entry = effectsIterator.next();
JsonNode node = entry.getValue();
try {
String type = node.get("type").asText();
SoundEvent javaEffect = null;
LevelEvent javaEffect = null;
LevelEventTranslator transformer = null;
switch (type) {
case "soundLevel" -> {
javaEffect = SoundEvent.valueOf(entry.getKey());
javaEffect = LevelEvent.valueOf(entry.getKey());
LevelEventType levelEventType = LevelEventType.valueOf(node.get("name").asText());
int data = node.has("data") ? node.get("data").intValue() : 0;
transformer = new SoundLevelEventTranslator(levelEventType, data);
}
case "soundEvent" -> {
javaEffect = SoundEvent.valueOf(entry.getKey());
javaEffect = LevelEvent.valueOf(entry.getKey());
com.nukkitx.protocol.bedrock.data.SoundEvent soundEvent = com.nukkitx.protocol.bedrock.data.SoundEvent.valueOf(node.get("name").asText());
String identifier = node.has("identifier") ? node.get("identifier").asText() : "";
int extraData = node.has("extraData") ? node.get("extraData").intValue() : -1;
transformer = new SoundEventEventTranslator(soundEvent, identifier, extraData);
}
case "playSound" -> {
javaEffect = SoundEvent.valueOf(entry.getKey());
javaEffect = LevelEvent.valueOf(entry.getKey());
String name = node.get("name").asText();
float volume = node.has("volume") ? node.get("volume").floatValue() : 1.0f;
boolean pitchSub = node.has("pitch_sub") && node.get("pitch_sub").booleanValue();
@ -85,7 +85,7 @@ public class SoundEventsRegistryLoader extends EffectRegistryLoader<Map<SoundEve
soundEffects.put(javaEffect, transformer);
}
} catch (Exception e) {
GeyserImpl.getInstance().getLogger().warning("Failed to map sound effect " + entry.getKey() + " : " + e.toString());
GeyserImpl.getInstance().getLogger().warning("Failed to map sound effect " + entry.getKey() + " : " + e);
}
}
return soundEffects;

View file

@ -54,8 +54,9 @@ public class SoundRegistryLoader implements RegistryLoader<String, Map<String, S
while(soundsIterator.hasNext()) {
Map.Entry<String, JsonNode> next = soundsIterator.next();
JsonNode brMap = next.getValue();
soundMappings.put(next.getKey(), new SoundMapping(
next.getKey(),
String javaSound = next.getKey();
soundMappings.put(javaSound, new SoundMapping(
javaSound,
brMap.has("bedrock_mapping") && brMap.get("bedrock_mapping").isTextual() ? brMap.get("bedrock_mapping").asText() : null,
brMap.has("playsound_mapping") && brMap.get("playsound_mapping").isTextual() ? brMap.get("playsound_mapping").asText() : null,
brMap.has("extra_data") && brMap.get("extra_data").isInt() ? brMap.get("extra_data").asInt() : -1,

View file

@ -28,9 +28,7 @@ package org.geysermc.geyser.registry.populator;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.ImmutableMap;
import com.nukkitx.nbt.*;
import com.nukkitx.protocol.bedrock.v475.Bedrock_v475;
import com.nukkitx.protocol.bedrock.v486.Bedrock_v486;
import com.nukkitx.protocol.bedrock.v503.Bedrock_v503;
import com.nukkitx.protocol.bedrock.beta.BedrockBeta;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
@ -61,51 +59,9 @@ public class BlockRegistryPopulator {
private static final ImmutableMap<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> BLOCK_MAPPERS;
private static final BiFunction<String, NbtMapBuilder, String> EMPTY_MAPPER = (bedrockIdentifier, statesBuilder) -> null;
private static final BiFunction<String, NbtMapBuilder, String> V486_MAPPER = (bedrockIdentifier, statesBuilder) -> {
statesBuilder.remove("no_drop_bit"); // Used in skulls
if (bedrockIdentifier.equals("minecraft:glow_lichen")) {
// Moved around north, south, west
int bits = (int) statesBuilder.get("multi_face_direction_bits");
boolean north = (bits & (1 << 2)) != 0;
boolean south = (bits & (1 << 3)) != 0;
boolean west = (bits & (1 << 4)) != 0;
if (north) {
bits |= 1 << 4;
} else {
bits &= ~(1 << 4);
}
if (south) {
bits |= 1 << 2;
} else {
bits &= ~(1 << 2);
}
if (west) {
bits |= 1 << 3;
} else {
bits &= ~(1 << 3);
}
statesBuilder.put("multi_face_direction_bits", bits);
}
return null;
};
static {
ImmutableMap.Builder<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> stateMapperBuilder = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder()
.put(ObjectIntPair.of("1_18_0", Bedrock_v475.V475_CODEC.getProtocolVersion()), EMPTY_MAPPER)
.put(ObjectIntPair.of("1_18_10", Bedrock_v486.V486_CODEC.getProtocolVersion()), V486_MAPPER)
.put(ObjectIntPair.of("1_18_30", Bedrock_v503.V503_CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> {
// Apply these fixes too
V486_MAPPER.apply(bedrockIdentifier, statesBuilder);
return switch (bedrockIdentifier) {
case "minecraft:pistonArmCollision" -> "minecraft:piston_arm_collision";
case "minecraft:stickyPistonArmCollision" -> "minecraft:sticky_piston_arm_collision";
case "minecraft:movingBlock" -> "minecraft:moving_block";
case "minecraft:tripWire" -> "minecraft:trip_wire";
case "minecraft:seaLantern" -> "minecraft:sea_lantern";
case "minecraft:concretePowder" -> "minecraft:concrete_powder";
default -> null;
};
});
.put(ObjectIntPair.of("1_19_0", BedrockBeta.BETA_CODEC.getProtocolVersion()), EMPTY_MAPPER);
BLOCK_MAPPERS = stateMapperBuilder.build();
}
@ -294,7 +250,7 @@ public class BlockRegistryPopulator {
builder.pickItem(pickItemNode.textValue().intern());
}
if (javaId.equals("minecraft:obsidian") || javaId.equals("minecraft:crying_obsidian") || javaId.startsWith("minecraft:respawn_anchor")) {
if (javaId.equals("minecraft:obsidian") || javaId.equals("minecraft:crying_obsidian") || javaId.startsWith("minecraft:respawn_anchor") || javaId.startsWith("minecraft:reinforced_deepslate")) {
builder.pistonBehavior(PistonBehavior.BLOCK);
} else {
JsonNode pistonBehaviorNode = entry.getValue().get("piston_behavior");

View file

@ -31,13 +31,11 @@ import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import com.nukkitx.nbt.NbtUtils;
import com.nukkitx.protocol.bedrock.beta.BedrockBeta;
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData;
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
import com.nukkitx.protocol.bedrock.v475.Bedrock_v475;
import com.nukkitx.protocol.bedrock.v486.Bedrock_v486;
import com.nukkitx.protocol.bedrock.v503.Bedrock_v503;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
@ -66,9 +64,7 @@ public class ItemRegistryPopulator {
public static void populate() {
Map<String, PaletteVersion> paletteVersions = new Object2ObjectOpenHashMap<>();
paletteVersions.put("1_18_0", new PaletteVersion(Bedrock_v475.V475_CODEC.getProtocolVersion(), Collections.emptyMap()));
paletteVersions.put("1_18_10", new PaletteVersion(Bedrock_v486.V486_CODEC.getProtocolVersion(), Collections.emptyMap()));
paletteVersions.put("1_18_30", new PaletteVersion(Bedrock_v503.V503_CODEC.getProtocolVersion(), Collections.emptyMap()));
paletteVersions.put("1_19_0", new PaletteVersion(BedrockBeta.BETA_CODEC.getProtocolVersion(), Collections.emptyMap()));
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
@ -230,18 +226,6 @@ public class ItemRegistryPopulator {
mappingItem = entry.getValue();
}
String bedrockIdentifier;
if (javaIdentifier.equals("minecraft:globe_banner_pattern") && palette.getValue().protocolVersion() < Bedrock_v486.V486_CODEC.getProtocolVersion()) {
bedrockIdentifier = "minecraft:banner_pattern";
} else {
bedrockIdentifier = mappingItem.getBedrockIdentifier();
if (palette.getValue().protocolVersion() >= Bedrock_v503.V503_CODEC.getProtocolVersion()) {
if (bedrockIdentifier.equals("minecraft:sealantern")) {
bedrockIdentifier = "minecraft:sea_lantern";
}
}
}
if (usingFurnaceMinecart && javaIdentifier.equals("minecraft:furnace_minecart")) {
javaFurnaceMinecartId = itemIndex;
itemIndex++;
@ -250,6 +234,7 @@ public class ItemRegistryPopulator {
continue;
}
String bedrockIdentifier = mappingItem.getBedrockIdentifier();
int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier);
if (bedrockId == Short.MIN_VALUE) {
throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier);

View file

@ -38,10 +38,10 @@ public class SoundMapping {
public SoundMapping(String java, String bedrock, String playsound, int extraData, String identifier, boolean levelEvent) {
this.java = java;
this.bedrock = bedrock == null || bedrock.equalsIgnoreCase("") ? null : bedrock;
this.playsound = playsound == null || playsound.equalsIgnoreCase("") ? null : playsound;
this.bedrock = bedrock == null || bedrock.isEmpty() ? null : bedrock;
this.playsound = playsound == null || playsound.isEmpty() ? null : playsound;
this.extraData = extraData;
this.identifier = identifier == null || identifier.equalsIgnoreCase("") ? ":" : identifier;
this.identifier = identifier == null || identifier.isEmpty() ? ":" : identifier;
this.levelEvent = levelEvent;
}
}

View file

@ -34,8 +34,10 @@ import com.github.steveice10.mc.auth.service.MojangAuthenticationService;
import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import com.github.steveice10.mc.protocol.MinecraftProtocol;
import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper;
import com.github.steveice10.mc.protocol.data.ProtocolState;
import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException;
import com.github.steveice10.mc.protocol.data.game.MessageType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
@ -47,6 +49,8 @@ import com.github.steveice10.mc.protocol.data.game.setting.SkinPart;
import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic;
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
@ -61,6 +65,7 @@ import com.github.steveice10.packetlib.tcp.TcpClientSession;
import com.github.steveice10.packetlib.tcp.TcpSession;
import com.nukkitx.math.GenericMath;
import com.nukkitx.math.vector.*;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.protocol.bedrock.BedrockPacket;
import com.nukkitx.protocol.bedrock.BedrockServerSession;
import com.nukkitx.protocol.bedrock.data.*;
@ -69,6 +74,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.*;
import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import it.unimi.dsi.fastutil.bytes.ByteArrays;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@ -81,6 +87,7 @@ import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.common.value.qual.IntRange;
import org.geysermc.common.PlatformType;
import org.geysermc.cumulus.form.Form;
@ -101,6 +108,7 @@ import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.level.physics.CollisionManager;
import org.geysermc.geyser.network.netty.LocalSession;
@ -115,6 +123,7 @@ import org.geysermc.geyser.session.cache.*;
import org.geysermc.geyser.skin.FloodgateSkinUploader;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.*;
@ -124,6 +133,7 @@ import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledFuture;
@ -318,12 +328,15 @@ public class GeyserSession implements GeyserConnection, CommandSender {
*/
@Setter
private String dimension = DimensionUtils.OVERWORLD;
/**
* Whether piglins and hoglins are safe from conversion in this dimension.
* This controls if they have the shaking effect applied in the dimension.
*/
@MonotonicNonNull
@Setter
private boolean dimensionPiglinSafe;
private JavaDimension dimensionType = null;
/**
* All dimensions that the client could possibly connect to.
*/
private final Map<String, JavaDimension> dimensions = new Object2ObjectOpenHashMap<>(3);
private final Map<MessageType, TextDecoration> chatTypes = new EnumMap<>(MessageType.class);
@Setter
private int breakingBlock;
@ -480,15 +493,6 @@ public class GeyserSession implements GeyserConnection, CommandSender {
@Setter
private boolean thunder = false;
/**
* Stores the last text inputted into a sign.
* <p>
* Bedrock sends packets every time you update the sign, Java only wants the final packet.
* Until we determine that the user has finished editing, we save the sign's current status.
*/
@Setter
private String lastSignMessage;
/**
* Stores a map of all statistics sent from the server.
* The server only sends new statistics back to us, so in order to show all statistics we need to cache existing ones.
@ -840,7 +844,8 @@ public class GeyserSession implements GeyserConnection, CommandSender {
if (geyser.getBootstrap().getSocketAddress() != null) {
// We're going to connect through the JVM and not through TCP
downstream = new LocalSession(this.remoteAddress, this.remotePort,
geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), this.protocol);
geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(),
this.protocol, this.protocol.createHelper());
} else {
downstream = new TcpClientSession(this.remoteAddress, this.remotePort, this.protocol);
disableSrvResolving();
@ -1012,7 +1017,7 @@ public class GeyserSession implements GeyserConnection, CommandSender {
setDaylightCycle(true);
}
downstream.connect();
downstream.connect(false);
}
public void disconnect(String reason) {
@ -1261,9 +1266,9 @@ public class GeyserSession implements GeyserConnection, CommandSender {
ServerboundUseItemPacket useItemPacket;
if (playerInventory.getItemInHand().getJavaId() == shield.getJavaId()) {
useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND);
useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, getNextSequence());
} else if (playerInventory.getOffhand().getJavaId() == shield.getJavaId()) {
useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND);
useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, getNextSequence());
} else {
// No blocking
return false;
@ -1292,7 +1297,7 @@ public class GeyserSession implements GeyserConnection, CommandSender {
private boolean disableBlocking() {
if (playerEntity.getFlag(EntityFlag.BLOCKING)) {
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM,
BlockUtils.POSITION_ZERO, Direction.DOWN);
Vector3i.ZERO, Direction.DOWN, getNextSequence());
sendDownstreamPacket(releaseItemPacket);
playerEntity.setFlag(EntityFlag.BLOCKING, false);
return true;
@ -1358,7 +1363,21 @@ public class GeyserSession implements GeyserConnection, CommandSender {
@Override
public String getLocale() {
return clientData.getLanguageCode();
}
}
/**
* Sends a chat message to the Java server.
*/
public void sendChat(String message) {
sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, ByteArrays.EMPTY_ARRAY, false));
}
/**
* Sends a command to the Java server.
*/
public void sendCommand(String command) {
sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyMap(), false));
}
public void setServerRenderDistance(int renderDistance) {
renderDistance = GenericMath.ceil(++renderDistance * MathUtils.SQRT_OF_TWO); //square to circle
@ -1452,6 +1471,9 @@ public class GeyserSession implements GeyserConnection, CommandSender {
startGamePacket.setInventoriesServerAuthoritative(true);
startGamePacket.setServerEngine(""); // Do we want to fill this in?
startGamePacket.setPlayerPropertyData(NbtMap.EMPTY);
startGamePacket.setWorldTemplateId(UUID.randomUUID());
SyncedPlayerMovementSettings settings = new SyncedPlayerMovementSettings();
settings.setMovementMode(AuthoritativeMovementMode.CLIENT);
settings.setRewindHistorySize(0);
@ -1653,6 +1675,10 @@ public class GeyserSession implements GeyserConnection, CommandSender {
sendDownstreamPacket(clientSettingsPacket);
}
public int getNextSequence() {
return 0;
}
/**
* Used for updating statistic values since we only get changes from the server
*
@ -1729,4 +1755,8 @@ public class GeyserSession implements GeyserConnection, CommandSender {
packet.setExtraData(-1);
sendUpstreamPacket(packet);
}
public MinecraftCodecHelper getCodecHelper() {
return (MinecraftCodecHelper) this.downstream.getCodecHelper();
}
}

View file

@ -37,6 +37,7 @@ import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.text.MessageTranslator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -75,33 +76,20 @@ public class AdvancementsCache {
.translator(MinecraftLocale::getLocaleString, session.getLocale())
.title("gui.advancements");
boolean hasAdvancements = false;
List<String> rootAdvancementIds = new ArrayList<>();
for (Map.Entry<String, GeyserAdvancement> advancement : storedAdvancements.entrySet()) {
if (advancement.getValue().getParentId() == null) { // No parent means this is a root advancement
hasAdvancements = true;
builder.button(MessageTranslator.convertMessage(advancement.getValue().getDisplayData().getTitle(), session.getLocale()));
rootAdvancementIds.add(advancement.getKey());
}
}
if (!hasAdvancements) {
if (rootAdvancementIds.isEmpty()) {
builder.content("advancements.empty");
}
builder.validResultHandler((response) -> {
String id = "";
int advancementIndex = 0;
for (Map.Entry<String, GeyserAdvancement> advancement : storedAdvancements.entrySet()) {
if (advancement.getValue().getParentId() == null) { // Root advancement
if (advancementIndex == response.clickedButtonId()) {
id = advancement.getKey();
break;
} else {
advancementIndex++;
}
}
}
String id = rootAdvancementIds.get(response.clickedButtonId());
if (!id.equals("")) {
if (id.equals(currentAdvancementCategoryId)) {
// The server thinks we are already on this tab
@ -130,12 +118,16 @@ public class AdvancementsCache {
.title(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getTitle(), language))
.content(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getDescription(), language));
List<GeyserAdvancement> visibleAdvancements = new ArrayList<>();
if (currentAdvancementCategoryId != null) {
for (GeyserAdvancement advancement : storedAdvancements.values()) {
if (advancement != null) {
boolean earned = isEarned(advancement);
if (earned || !advancement.getDisplayData().isHidden()) {
if (advancement.getParentId() != null && currentAdvancementCategoryId.equals(advancement.getRootId(this))) {
boolean color = isEarned(advancement) || !advancement.getDisplayData().isShowToast();
builder.button((color ? ChatColor.DARK_GREEN : "") + MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()) + '\n');
String color = earned ? advancement.getDisplayColor() : "";
builder.button(color + MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()) + '\n');
visibleAdvancements.add(advancement);
}
}
}
@ -148,22 +140,8 @@ public class AdvancementsCache {
session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket());
}).validResultHandler((response) -> {
GeyserAdvancement advancement = null;
int advancementIndex = 0;
// Loop around to find the advancement that the client pressed
for (GeyserAdvancement advancementEntry : storedAdvancements.values()) {
if (advancementEntry.getParentId() != null &&
currentAdvancementCategoryId.equals(advancementEntry.getRootId(this))) {
if (advancementIndex == response.clickedButtonId()) {
advancement = advancementEntry;
break;
} else {
advancementIndex++;
}
}
}
if (advancement != null) {
if (response.getClickedButtonId() < visibleAdvancements.size()) {
GeyserAdvancement advancement = visibleAdvancements.get(response.clickedButtonId());
buildAndShowInfoForm(advancement);
} else {
buildAndShowMenuForm();

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.text;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Set;
public final class TextDecoration {
private final String translationKey;
private final Style style;
private final Set<Parameter> parameters;
public TextDecoration(CompoundTag tag) {
translationKey = (String) tag.get("translation_key").getValue();
CompoundTag styleTag = tag.get("style");
Style.Builder builder = Style.style();
StringTag color = styleTag.get("color");
if (color != null) {
builder.color(NamedTextColor.NAMES.value(color.getValue()));
}
//TODO implement the rest
Tag italic = styleTag.get("italic");
if (italic != null && ((Number) italic.getValue()).byteValue() == (byte) 1) {
builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC);
}
style = builder.build();
this.parameters = EnumSet.noneOf(Parameter.class);
ListTag parameters = tag.get("parameters");
for (Tag parameter : parameters) {
this.parameters.add(Parameter.valueOf(((String) parameter.getValue()).toUpperCase(Locale.ROOT)));
}
}
public String translationKey() {
return translationKey;
}
public Style style() {
return style;
}
public Set<Parameter> parameters() {
return parameters;
}
@Override
public String toString() {
return "TextDecoration{" +
"translationKey='" + translationKey + '\'' +
", style=" + style +
", parameters=" + parameters +
'}';
}
public enum Parameter {
CONTENT,
SENDER,
TEAM_NAME
}
}

View file

@ -48,6 +48,8 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InventoryUtils;
import java.util.OptionalInt;
public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator {
public BeaconInventoryTranslator() {
super(1, new BlockInventoryHolder("minecraft:beacon", com.nukkitx.protocol.bedrock.data.inventory.ContainerType.BEACON) {
@ -111,11 +113,15 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
// Input a beacon payment
BeaconPaymentStackRequestActionData beaconPayment = (BeaconPaymentStackRequestActionData) request.getActions()[0];
ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(beaconPayment.getPrimaryEffect(), beaconPayment.getSecondaryEffect());
ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(toJava(beaconPayment.getPrimaryEffect()), toJava(beaconPayment.getSecondaryEffect()));
session.sendDownstreamPacket(packet);
return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet()));
}
private OptionalInt toJava(int effectChoice) {
return effectChoice == -1 ? OptionalInt.empty() : OptionalInt.of(effectChoice);
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.BEACON_PAYMENT) {

View file

@ -37,7 +37,6 @@ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.AutoCraft
import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData;
import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket;
import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
import com.nukkitx.protocol.bedrock.v486.Bedrock_v486;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.inventory.Inventory;
@ -140,10 +139,6 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
@Override
public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
if (session.getUpstream().getProtocolVersion() < Bedrock_v486.V486_CODEC.getProtocolVersion()) {
return super.translateCraftingRequest(session, inventory, request);
}
// Behavior as of 1.18.10.
// We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to
// store a map of net ID to trade index on our end.
@ -153,12 +148,6 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
@Override
public ItemStackResponsePacket.Response translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
if (session.getUpstream().getProtocolVersion() < Bedrock_v486.V486_CODEC.getProtocolVersion()) {
// We're not crafting here
// Called at least by consoles when pressing a trade option button
return translateRequest(session, inventory, request);
}
// 1.18.10 update - seems impossible to call without consoles/controller input
// We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to
// store a map of net ID to trade index on our end.

View file

@ -42,6 +42,7 @@ import org.geysermc.geyser.level.chunk.bitarray.BitArray;
import org.geysermc.geyser.level.chunk.bitarray.BitArrayVersion;
import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.util.JavaCodecEntry;
import org.geysermc.geyser.util.MathUtils;
// Array index formula by https://wiki.vg/Chunk_Format
@ -55,27 +56,26 @@ public class BiomeTranslator {
ListTag serverBiomes = worldGen.get("value");
session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(serverBiomes.size()));
for (Tag tag : serverBiomes) {
CompoundTag biomeTag = (CompoundTag) tag;
for (CompoundTag biomeTag : JavaCodecEntry.iterateAsTag(worldGen)) {
String javaIdentifier = ((StringTag) biomeTag.get("name")).getValue();
int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, -1);
int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0);
int javaId = ((IntTag) biomeTag.get("id")).getValue();
if (bedrockId == -1) {
// There is no matching Bedrock variation for this biome; let's set the closest match based on biome category
String category = ((StringTag) ((CompoundTag) biomeTag.get("element")).get("category")).getValue();
String replacementBiome = switch (category) {
case "extreme_hills" -> "minecraft:mountains";
case "icy" -> "minecraft:ice_spikes";
case "mesa" -> "minecraft:badlands";
case "mushroom" -> "minecraft:mushroom_fields";
case "nether" -> "minecraft:nether_wastes";
default -> "minecraft:ocean"; // Typically ID 0 so a good default
case "taiga", "jungle", "plains", "savanna", "the_end", "beach", "ocean", "desert", "river", "swamp" -> "minecraft:" + category;
};
bedrockId = Registries.BIOME_IDENTIFIERS.get().getInt(replacementBiome);
}
// TODO - the category tag no longer exists - find a better replacement option
// if (bedrockId == -1) {
// // There is no matching Bedrock variation for this biome; let's set the closest match based on biome category
// String category = ((StringTag) ((CompoundTag) biomeTag.get("element")).get("category")).getValue();
// String replacementBiome = switch (category) {
// case "extreme_hills" -> "minecraft:mountains";
// case "icy" -> "minecraft:ice_spikes";
// case "mesa" -> "minecraft:badlands";
// case "mushroom" -> "minecraft:mushroom_fields";
// case "nether" -> "minecraft:nether_wastes";
// default -> "minecraft:ocean"; // Typically ID 0 so a good default
// case "taiga", "jungle", "plains", "savanna", "the_end", "beach", "ocean", "desert", "river", "swamp" -> "minecraft:" + category;
// };
// bedrockId = Registries.BIOME_IDENTIFIERS.get().getInt(replacementBiome);
// }
// When we see the Java ID, we should instead apply the Bedrock ID
biomeTranslations.put(javaId, bedrockId);

View file

@ -40,7 +40,7 @@ public record SoundEventEventTranslator(SoundEvent soundEvent,
levelSoundEvent.setIdentifier(identifier);
levelSoundEvent.setExtraData(extraData);
levelSoundEvent.setRelativeVolumeDisabled(packet.isBroadcast());
levelSoundEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f));
levelSoundEvent.setPosition(Vector3f.from(packet.getPosition().getX() + 0.5f, packet.getPosition().getY() + 0.5f, packet.getPosition().getZ() + 0.5f));
levelSoundEvent.setBabySound(false);
session.sendUpstreamPacket(levelSoundEvent);
}

View file

@ -25,12 +25,11 @@
package org.geysermc.geyser.translator.protocol.bedrock;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetJigsawBlockPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
import com.nukkitx.protocol.bedrock.v503.Bedrock_v503;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@ -45,16 +44,8 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
String id = tag.getString("id");
if (id.equals("Sign")) {
String text = tag.getString("Text");
// This is the reason why this all works - Bedrock sends packets every time you update the sign, Java only wants the final packet
// But Bedrock sends one final packet when you're done editing the sign, which should be equal to the last message since there's no edits
// So if the latest update does not match the last cached update then it's still being edited
// TODO check 1.19:
// Bedrock only sends one packet as of 1.18.30. I (Camotoy) am suspicious this is a bug, but if it's permanent then we don't need the lastSignMessage variable.
if (session.getUpstream().getProtocolVersion() < Bedrock_v503.V503_CODEC.getProtocolVersion() && !text.equals(session.getLastSignMessage())) {
session.setLastSignMessage(text);
return;
}
// Otherwise the two messages are identical and we can get to work deconstructing
// 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.
StringBuilder newMessage = new StringBuilder();
// While Bedrock's sign lines are one string, Java's is an array of each line
// (Initialized all with empty strings because it complains about null)
@ -109,16 +100,13 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
}
// Put the final line on since it isn't done in the for loop
if (iterator < lines.length) lines[iterator] = newMessage.toString();
Position pos = new Position(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);
session.sendDownstreamPacket(signUpdatePacket);
// We set the sign text cached in the session to null to indicate there is no work-in-progress sign
session.setLastSignMessage(null);
} else if (id.equals("JigsawBlock")) {
// Client has just sent a jigsaw block update
Position pos = new Position(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
String name = tag.getString("name");
String target = tag.getString("target");
String pool = tag.getString("target_pool");

View file

@ -25,10 +25,9 @@
package org.geysermc.geyser.translator.protocol.bedrock;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.level.block.CommandBlockMode;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCommandMinecartPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCommandBlockPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCommandMinecartPacket;
import com.nukkitx.protocol.bedrock.packet.CommandBlockUpdatePacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
@ -53,8 +52,7 @@ public class BedrockCommandBlockUpdateTranslator extends PacketTranslator<Comman
boolean isConditional = packet.isConditional();
boolean automatic = !packet.isRedstoneMode(); // Automatic = Always Active option in Java
ServerboundSetCommandBlockPacket commandBlockPacket = new ServerboundSetCommandBlockPacket(
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()),
command, mode, outputTracked, isConditional, automatic);
packet.getBlockPosition(), command, mode, outputTracked, isConditional, automatic);
session.sendDownstreamPacket(commandBlockPacket);
} else {
ServerboundSetCommandMinecartPacket commandMinecartPacket = new ServerboundSetCommandMinecartPacket(

View file

@ -25,15 +25,13 @@
package org.geysermc.geyser.translator.protocol.bedrock;
import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket;
import org.geysermc.common.PlatformType;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.CommandManager;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket;
import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket;
import org.geysermc.geyser.translator.text.MessageTranslator;
@Translator(packet = CommandRequestPacket.class)
@ -52,8 +50,7 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
return;
}
ServerboundChatPacket chatPacket = new ServerboundChatPacket(message);
session.sendDownstreamPacket(chatPacket);
session.sendCommand(message.substring(1));
}
}
}

View file

@ -52,7 +52,7 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator<EntityP
// Get the corresponding item
String itemName;
switch (entity.getDefinition().entityType()) {
case BOAT -> {
case BOAT, CHEST_BOAT -> {
// Include type of boat in the name
int variant = ((BoatEntity) entity).getVariant();
String typeOfBoat = switch (variant) {
@ -61,9 +61,10 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator<EntityP
case 3 -> "jungle";
case 4 -> "acacia";
case 5 -> "dark_oak";
case 6 -> "mangrove";
default -> "oak";
};
itemName = typeOfBoat + "_boat";
itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT);
}
case LEASH_KNOT -> itemName = "lead";
case CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART, TNT_MINECART ->

View file

@ -26,7 +26,6 @@
package org.geysermc.geyser.translator.protocol.bedrock;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
@ -121,8 +120,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
ServerboundPlayerActionPacket dropPacket = new ServerboundPlayerActionPacket(
dropAll ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM,
BlockUtils.POSITION_ZERO,
Direction.DOWN
Vector3i.ZERO,
Direction.DOWN,
session.getNextSequence()
);
session.sendDownstreamPacket(dropPacket);
@ -256,24 +256,25 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (blockState == BlockStateValues.JAVA_WATER_ID) {
// Otherwise causes multiple mobs to spawn - just send a use item packet
// TODO when we fix mobile bucket rotation, use it for this, too
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND);
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence());
session.sendDownstreamPacket(itemPacket);
break;
}
}
ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket(
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()),
packet.getBlockPosition(),
Direction.VALUES[packet.getBlockFace()],
Hand.MAIN_HAND,
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
false);
false,
session.getNextSequence());
session.sendDownstreamPacket(blockPacket);
if (packet.getItemInHand() != null) {
// Otherwise boats will not be able to be placed in survival and buckets won't work on mobile
if (session.getItemMappings().getBoatIds().contains(packet.getItemInHand().getId())) {
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND);
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence());
session.sendDownstreamPacket(itemPacket);
} else if (session.getItemMappings().getBucketIds().contains(packet.getItemInHand().getId())) {
// Let the server decide if the bucket item should change, not the client, and revert the changes the client made
@ -290,7 +291,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
// Delay the interaction in case the client doesn't intend to actually use the bucket
// See BedrockActionTranslator.java
session.setBucketScheduledFuture(session.scheduleInEventLoop(() -> {
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND);
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence());
session.sendDownstreamPacket(itemPacket);
}, 5, TimeUnit.MILLISECONDS));
}
@ -336,7 +337,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
}
}
ServerboundUseItemPacket useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND);
ServerboundUseItemPacket useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence());
session.sendDownstreamPacket(useItemPacket);
List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots();
@ -417,8 +418,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
}
PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING;
Position pos = new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, pos, Direction.VALUES[packet.getBlockFace()]);
ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, packet.getBlockPosition(), Direction.VALUES[packet.getBlockFace()], session.getNextSequence());
session.sendDownstreamPacket(breakPacket);
}
}
@ -426,8 +426,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
case ITEM_RELEASE:
if (packet.getActionType() == 0) {
// Followed to the Minecraft Protocol specification outlined at wiki.vg
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, BlockUtils.POSITION_ZERO,
Direction.DOWN);
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO,
Direction.DOWN, session.getNextSequence());
session.sendDownstreamPacket(releaseItemPacket);
}
break;

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.translator.protocol.bedrock;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket;
@ -53,11 +52,12 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda
// Emulate an interact packet
ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket(
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()),
packet.getBlockPosition(),
Direction.DOWN,
Hand.MAIN_HAND,
0, 0, 0, // Java doesn't care about these when dealing with a lectern
false);
false,
session.getNextSequence());
session.sendDownstreamPacket(blockPacket);
} else {
// Bedrock wants to either move a page or exit

View file

@ -65,7 +65,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
// Activate shield since we are already sneaking
// (No need to send a release item packet - Java doesn't do this when swapping items)
// Required to do it a tick later or else it doesn't register
session.scheduleInEventLoop(() -> session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND)),
session.scheduleInEventLoop(() -> session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence())),
50, TimeUnit.MILLISECONDS);
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.translator.protocol.bedrock;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket;
import com.nukkitx.protocol.bedrock.packet.TextPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
@ -63,7 +62,6 @@ public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
return;
}
ServerboundChatPacket chatPacket = new ServerboundChatPacket(message);
session.sendDownstreamPacket(chatPacket);
session.sendChat(message);
}
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.*;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
@ -129,8 +128,8 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
session.setSprinting(false);
break;
case DROP_ITEM:
Position position = new Position(vector.getX(), vector.getY(), vector.getZ());
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, position, Direction.VALUES[packet.getFace()]);
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
vector, Direction.VALUES[packet.getFace()], session.getNextSequence());
session.sendDownstreamPacket(dropItemPacket);
break;
case STOP_SLEEP:
@ -163,16 +162,16 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
int blockUp = session.getGeyser().getWorldManager().getBlockAt(session, fireBlockPos);
String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().get(blockUp);
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(),
fireBlockPos.getY(), fireBlockPos.getZ()), Direction.VALUES[packet.getFace()]);
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos,
Direction.VALUES[packet.getFace()], session.getNextSequence());
session.sendDownstreamPacket(startBreakingPacket);
if (session.getGameMode() == GameMode.CREATIVE) {
break;
}
}
position = new Position(vector.getX(), vector.getY(), vector.getZ());
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, position, Direction.VALUES[packet.getFace()]);
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING,
vector, Direction.VALUES[packet.getFace()], session.getNextSequence());
session.sendDownstreamPacket(startBreakingPacket);
break;
case CONTINUE_BREAK:
@ -207,8 +206,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
}
}
position = new Position(vector.getX(), vector.getY(), vector.getZ());
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, position, Direction.DOWN);
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, session.getNextSequence());
session.sendDownstreamPacket(abortBreakingPacket);
LevelEventPacket stopBreak = new LevelEventPacket();
stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK);

View file

@ -28,13 +28,13 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.protocol.bedrock.packet.EmotePacket;
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.BlockUtils;
@Translator(packet = EmotePacket.class)
public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> {
@ -43,8 +43,8 @@ public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> {
public void translate(GeyserSession session, EmotePacket packet) {
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) {
// Activate the workaround - we should trigger the offhand now
ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO,
Direction.DOWN);
ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
Direction.DOWN, session.getNextSequence());
session.sendDownstreamPacket(swapHandsPacket);
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {

View file

@ -28,10 +28,10 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
@ -96,12 +96,10 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
case OPEN_INVENTORY:
if (session.getOpenInventory() == null) {
Entity ridingEntity = session.getPlayerEntity().getVehicle();
if (ridingEntity instanceof AbstractHorseEntity) {
if (ridingEntity.getFlag(EntityFlag.TAMED)) {
// We should request to open the horse inventory instead
ServerboundPlayerCommandPacket openHorseWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_HORSE_INVENTORY);
session.sendDownstreamPacket(openHorseWindowPacket);
}
if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) {
// This mob has an inventory of its own that we should open instead.
ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY);
session.sendDownstreamPacket(openVehicleWindowPacket);
} else {
session.setOpenInventory(session.getPlayerInventory());

View file

@ -222,7 +222,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
case BLOCK_POS -> CommandParam.BLOCK_POSITION;
case COLUMN_POS, VEC3 -> CommandParam.POSITION;
case MESSAGE -> CommandParam.MESSAGE;
case NBT, NBT_COMPOUND_TAG, NBT_TAG, NBT_PATH -> CommandParam.JSON;
case NBT_COMPOUND_TAG, NBT_TAG, NBT_PATH -> CommandParam.JSON; //TODO NBT was removed
case RESOURCE_LOCATION, FUNCTION -> CommandParam.FILE_PATH;
case BOOL -> ENUM_BOOLEAN;
case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc
@ -248,7 +248,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
/**
* Stores the command description and parameter data for best optimizing the Bedrock commands packet.
*/
private static record BedrockCommandInfo(String description, CommandParamData[][] paramData) {
private record BedrockCommandInfo(String description, CommandParamData[][] paramData) {
}
@Getter
@ -317,15 +317,21 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
Object mappedType = mapCommandType(session, paramNode);
CommandEnumData enumData = null;
CommandParam type = null;
boolean optional = this.paramNode.isExecutable();
if (mappedType instanceof String[]) {
enumData = new CommandEnumData(paramNode.getParser().name().toLowerCase(), (String[]) mappedType, false);
} else {
type = (CommandParam) mappedType;
// Bedrock throws a fit if an optional message comes after a string or target
// Example vanilla commands: ban-ip, ban, and kick
if (optional && type == CommandParam.MESSAGE && (paramData.getType() == CommandParam.STRING || paramData.getType() == CommandParam.TARGET)) {
optional = false;
}
}
// IF enumData != null:
// In game, this will show up like <paramNode.getName(): enumData.getName()>
// So if paramNode.getName() == "value" and enumData.getName() == "bool": <value: bool>
children.add(new ParamInfo(paramNode, new CommandParamData(paramNode.getName(), this.paramNode.isExecutable(), enumData, type, null, Collections.emptyList())));
children.add(new ParamInfo(paramNode, new CommandParamData(paramNode.getName(), optional, enumData, type, null, Collections.emptyList())));
}
}

View file

@ -25,48 +25,79 @@
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.data.game.MessageType;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.nukkitx.protocol.bedrock.data.GameRuleData;
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket;
import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
import org.geysermc.floodgate.pluginmessage.PluginMessageChannels;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.auth.AuthType;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.level.BiomeTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.JavaCodecEntry;
import org.geysermc.geyser.util.PluginMessageUtils;
import java.util.Map;
@Translator(packet = ClientboundLoginPacket.class)
public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> {
@Override
public void translate(GeyserSession session, ClientboundLoginPacket packet) {
PlayerEntity entity = session.getPlayerEntity();
SessionPlayerEntity entity = session.getPlayerEntity();
entity.setEntityId(packet.getEntityId());
Map<String, JavaDimension> dimensions = session.getDimensions();
dimensions.clear();
JavaDimension.load(packet.getRegistry(), dimensions);
Map<MessageType, TextDecoration> chatTypes = session.getChatTypes();
chatTypes.clear();
for (CompoundTag tag : JavaCodecEntry.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) {
int id = ((IntTag) tag.get("id")).getValue();
CompoundTag element = tag.get("element");
CompoundTag chat = element.get("chat");
if (chat == null) {
continue;
}
CompoundTag decoration = chat.get("decoration");
if (decoration == null) {
continue;
}
MessageType type = MessageType.from(id);
chatTypes.put(type, new TextDecoration(decoration));
}
// If the player is already initialized and a join game packet is sent, they
// are swapping servers
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
if (session.isSpawned()) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension);
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension());
DimensionUtils.switchDimension(session, fakeDim);
session.getWorldCache().removeScoreboard();
}
session.setWorldName(packet.getWorldName());
BiomeTranslator.loadServerBiomes(session, packet.getDimensionCodec());
BiomeTranslator.loadServerBiomes(session, packet.getRegistry());
session.getTagCache().clear();
session.setGameMode(packet.getGameMode());
String newDimension = packet.getDimension();
boolean needsSpawnPacket = !session.isSentSpawnPacket();
if (needsSpawnPacket) {
// The player has yet to spawn so let's do that using some of the information in this Java packet
@ -85,6 +116,8 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
session.sendUpstreamPacket(playerGameTypePacket);
}
entity.setLastDeathPosition(packet.getLastDeathPos());
entity.updateBedrockMetadata();
// Send if client should show respawn screen
@ -113,6 +146,7 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
session.sendFog("minecraft:fog_hell");
}
ChunkUtils.loadDimensionTag(session, packet.getDimension());
session.setDimensionType(dimensions.get(newDimension));
ChunkUtils.loadDimension(session);
}
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerChatPacket;
import com.nukkitx.protocol.bedrock.packet.TextPacket;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Translator(packet = ClientboundPlayerChatPacket.class)
public class JavaPlayerChatTranslator extends PacketTranslator<ClientboundPlayerChatPacket> {
@Override
public void translate(GeyserSession session, ClientboundPlayerChatPacket packet) {
TextPacket textPacket = new TextPacket();
textPacket.setPlatformChatId("");
textPacket.setSourceName("");
textPacket.setXuid(session.getAuthData().xuid());
// TODO new types
textPacket.setType(switch (packet.getType()) {
case CHAT -> TextPacket.Type.CHAT;
case SYSTEM -> TextPacket.Type.SYSTEM;
case GAME_INFO -> TextPacket.Type.TIP;
default -> TextPacket.Type.RAW;
});
textPacket.setNeedsTranslation(false);
Component message = packet.getUnsignedContent() == null ? packet.getSignedContent() : packet.getUnsignedContent();
TextDecoration decoration = session.getChatTypes().get(packet.getType());
if (decoration != null) {
// As of 1.19 - do this to apply all the styling for signed messages
// Though, Bedrock cannot care about the signed stuff.
TranslatableComponent.Builder withDecoration = Component.translatable()
.key(decoration.translationKey())
.style(decoration.style());
Set<TextDecoration.Parameter> parameters = decoration.parameters();
List<Component> args = new ArrayList<>(3);
if (parameters.contains(TextDecoration.Parameter.TEAM_NAME)) {
args.add(packet.getSenderTeamName());
}
if (parameters.contains(TextDecoration.Parameter.SENDER)) {
args.add(packet.getSenderName());
}
if (parameters.contains(TextDecoration.Parameter.CONTENT)) {
args.add(message);
}
withDecoration.args(args);
textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.getLocale()));
} else {
textPacket.setMessage(MessageTranslator.convertMessage(message, session.getLocale()));
}
session.sendUpstreamPacket(textPacket);
}
}

View file

@ -33,9 +33,9 @@ import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils;
@ -55,6 +55,9 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
session.setOpenInventory(null);
session.setClosingInventory(false);
entity.setLastDeathPosition(packet.getLastDeathPos());
entity.updateBedrockMetadata();
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(packet.getGamemode().ordinal());
session.sendUpstreamPacket(playerGameTypePacket);
@ -78,7 +81,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
session.setThunder(false);
}
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
String newDimension = packet.getDimension();
if (!session.getDimension().equals(newDimension) || !packet.getWorldName().equals(session.getWorldName())) {
// Switching to a new world (based off the world name change); send a fake dimension change
if (!packet.getWorldName().equals(session.getWorldName()) && (session.getDimension().equals(newDimension)
@ -90,8 +93,9 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
}
session.setWorldName(packet.getWorldName());
DimensionUtils.switchDimension(session, newDimension);
}
ChunkUtils.loadDimensionTag(session, packet.getDimension());
session.setDimensionType(session.getDimensions().get(newDimension));
ChunkUtils.loadDimension(session);
}
}
}

View file

@ -25,31 +25,32 @@
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundChatPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundSystemChatPacket;
import com.nukkitx.protocol.bedrock.packet.TextPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.translator.text.MessageTranslator;
@Translator(packet = ClientboundChatPacket.class)
public class JavaChatTranslator extends PacketTranslator<ClientboundChatPacket> {
@Translator(packet = ClientboundSystemChatPacket.class)
public class JavaSystemChatTranslator extends PacketTranslator<ClientboundSystemChatPacket> {
@Override
public void translate(GeyserSession session, ClientboundChatPacket packet) {
public void translate(GeyserSession session, ClientboundSystemChatPacket packet) {
TextPacket textPacket = new TextPacket();
textPacket.setPlatformChatId("");
textPacket.setSourceName("");
textPacket.setXuid(session.getAuthData().xuid());
// TODO new types
textPacket.setType(switch (packet.getType()) {
case CHAT -> TextPacket.Type.CHAT;
case SYSTEM -> TextPacket.Type.SYSTEM;
case NOTIFICATION -> TextPacket.Type.TIP;
case GAME_INFO -> TextPacket.Type.TIP;
default -> TextPacket.Type.RAW;
});
textPacket.setNeedsTranslation(false);
textPacket.setMessage(MessageTranslator.convertMessage(packet.getMessage(), session.getLocale()));
textPacket.setMessage(MessageTranslator.convertMessage(packet.getContent(), session.getLocale()));
session.sendUpstreamPacket(textPacket);
}

View file

@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.data.game.advancement.Advancement;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateAdvancementsPacket;
import com.nukkitx.protocol.bedrock.packet.SetTitlePacket;
import com.nukkitx.protocol.bedrock.packet.ToastRequestPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@ -36,7 +36,7 @@ import org.geysermc.geyser.session.cache.AdvancementsCache;
import org.geysermc.geyser.level.GeyserAdvancement;
import org.geysermc.geyser.text.MinecraftLocale;
import java.util.Map;
import java.util.Locale;
@Translator(packet = ClientboundUpdateAdvancementsPacket.class)
public class JavaUpdateAdvancementsTranslator extends PacketTranslator<ClientboundUpdateAdvancementsPacket> {
@ -56,48 +56,39 @@ public class JavaUpdateAdvancementsTranslator extends PacketTranslator<Clientbou
advancementsCache.getStoredAdvancementProgress().putAll(packet.getProgress());
sendToolbarAdvancementUpdates(session, packet);
// Adds advancements to the player's stored advancements when advancements are sent
for (Advancement advancement : packet.getAdvancements()) {
if (advancement.getDisplayData() != null && !advancement.getDisplayData().isHidden()) {
if (advancement.getDisplayData() != null && (!advancement.getDisplayData().isHidden() || advancement.getDisplayData().isShowToast())) {
GeyserAdvancement geyserAdvancement = GeyserAdvancement.from(advancement);
advancementsCache.getStoredAdvancements().put(advancement.getId(), geyserAdvancement);
} else {
advancementsCache.getStoredAdvancements().remove(advancement.getId());
}
}
sendAdvancementToasts(session, packet);
}
/**
* Handle all advancements progress updates
*/
public void sendToolbarAdvancementUpdates(GeyserSession session, ClientboundUpdateAdvancementsPacket packet) {
public void sendAdvancementToasts(GeyserSession session, ClientboundUpdateAdvancementsPacket packet) {
if (packet.isReset()) {
// Advancements are being cleared, so they can't be granted
return;
}
for (Map.Entry<String, Map<String, Long>> progress : packet.getProgress().entrySet()) {
GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(progress.getKey());
for (String advancementId : packet.getProgress().keySet()) {
GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(advancementId);
if (advancement != null && advancement.getDisplayData() != null) {
if (session.getAdvancementsCache().isEarned(advancement)) {
// Java uses some pink color for toast challenge completes
String color = advancement.getDisplayData().getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE ?
"§d" : "§a";
if (advancement.getDisplayData().isShowToast() && session.getAdvancementsCache().isEarned(advancement)) {
String frameType = advancement.getDisplayData().getFrameType().toString().toLowerCase(Locale.ROOT);
String frameTitle = advancement.getDisplayColor() + MinecraftLocale.getLocaleString("advancements.toast." + frameType, session.getLocale());
String advancementName = MessageTranslator.convertMessage(advancement.getDisplayData().getTitle(), session.getLocale());
// Send an action bar message stating they earned an achievement
// Sent for instances where broadcasting advancements through chat are disabled
SetTitlePacket titlePacket = new SetTitlePacket();
titlePacket.setText(color + "[" + MinecraftLocale.getLocaleString("advancements.toast." +
advancement.getDisplayData().getFrameType().toString().toLowerCase(), session.getLocale()) + "]§f " + advancementName);
titlePacket.setType(SetTitlePacket.Type.ACTIONBAR);
titlePacket.setFadeOutTime(3);
titlePacket.setFadeInTime(3);
titlePacket.setStayTime(3);
titlePacket.setXuid("");
titlePacket.setPlatformOnlineId("");
session.sendUpstreamPacket(titlePacket);
ToastRequestPacket toastRequestPacket = new ToastRequestPacket();
toastRequestPacket.setTitle(frameTitle);
toastRequestPacket.setContent(advancementName);
session.sendUpstreamPacket(toastRequestPacket);
}
}
}

View file

@ -38,7 +38,6 @@ import com.nukkitx.nbt.NbtMap;
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket;
import com.nukkitx.protocol.bedrock.v486.Bedrock_v486;
import it.unimi.dsi.fastutil.ints.*;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
@ -82,8 +81,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
// Get the last known network ID (first used for the pregenerated recipes) and increment from there.
int netId = InventoryUtils.LAST_RECIPE_NET_ID + 1;
boolean applySmithingRecipes = session.getUpstream().getProtocolVersion() >= Bedrock_v486.V486_CODEC.getProtocolVersion();
Int2ObjectMap<GeyserRecipe> recipeMap = new Int2ObjectOpenHashMap<>(Registries.RECIPES.forVersion(session.getUpstream().getProtocolVersion()));
Int2ObjectMap<List<StoneCuttingRecipeData>> unsortedStonecutterData = new Int2ObjectOpenHashMap<>();
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
@ -138,10 +135,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
}
case SMITHING -> {
// Required to translate these as of 1.18.10, or else they cannot be crafted
if (!applySmithingRecipes) {
continue;
}
SmithingRecipeData recipeData = (SmithingRecipeData) recipe.getData();
ItemData output = ItemTranslator.translateToBedrock(session, recipeData.getResult());
for (ItemStack base : recipeData.getBase().getOptions()) {

View file

@ -26,7 +26,6 @@
package org.geysermc.geyser.translator.protocol.java.entity;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.LevelEventType;
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
@ -38,11 +37,11 @@ import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.EvokerFangsEntity;
import org.geysermc.geyser.entity.type.FishingHookEntity;
import org.geysermc.geyser.entity.type.LivingEntity;
import org.geysermc.geyser.entity.type.living.monster.WardenEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
@Translator(packet = ClientboundEntityEventPacket.class)
@ -56,7 +55,7 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
EntityEventPacket entityEventPacket = new EntityEventPacket();
entityEventPacket.setRuntimeEntityId(entity.getGeyserId());
switch (packet.getStatus()) {
switch (packet.getEvent()) {
case PLAYER_ENABLE_REDUCED_DEBUG:
session.setReducedDebugInfo(true);
return;
@ -180,8 +179,9 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
case IRON_GOLEM_EMPTY_HAND:
entityEventPacket.setType(EntityEventType.GOLEM_FLOWER_WITHDRAW);
break;
case IRON_GOLEM_ATTACK:
if (entity.getDefinition() == EntityDefinitions.IRON_GOLEM || entity.getDefinition() == EntityDefinitions.EVOKER_FANGS) {
case ATTACK:
if (entity.getDefinition() == EntityDefinitions.IRON_GOLEM || entity.getDefinition() == EntityDefinitions.EVOKER_FANGS
|| entity.getDefinition() == EntityDefinitions.WARDEN) {
entityEventPacket.setType(EntityEventType.ATTACK_START);
if (entity.getDefinition() == EntityDefinitions.EVOKER_FANGS) {
((EvokerFangsEntity) entity).setAttackStarted();
@ -236,28 +236,19 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
break;
case MAKE_POOF_PARTICLES:
if (entity instanceof LivingEntity) {
// Not ideal, but...
// LevelEventType.PARTICLE_DEATH_SMOKE doesn't work (as of 1.18.2 Bedrock)
// EntityEventType.DEATH_SMOKE_CLOUD also plays the entity death noise
// Bedrock sends the particles through EntityEventType.DEATH, but Java despawns the entity
// prematurely so they don't show up.
Vector3f position = entity.getPosition();
float baseX = position.getX();
float baseY = position.getY();
float baseZ = position.getZ();
float height = entity.getBoundingBoxHeight();
float width = entity.getBoundingBoxWidth();
Random random = ThreadLocalRandom.current();
for (int i = 0; i < 20; i++) {
// Reconstruct the Java Edition (1.18.1) logic, but in floats
float x = baseX + width * (2.0f * random.nextFloat() - 1f);
float y = baseY + height * random.nextFloat();
float z = baseZ + width * (2.0f * random.nextFloat() - 1f);
LevelEventPacket levelEventPacket = new LevelEventPacket();
levelEventPacket.setPosition(Vector3f.from(x, y, z));
levelEventPacket.setType(LevelEventType.PARTICLE_EXPLODE);
session.sendUpstreamPacket(levelEventPacket);
}
// Note that this event usually makes noise, but because we set all entities as silent on the
// client end this isn't an issue.
entityEventPacket.setType(EntityEventType.DEATH_SMOKE_CLOUD);
}
break;
case WARDEN_RECEIVE_SIGNAL:
if (entity.getDefinition() == EntityDefinitions.WARDEN) {
entityEventPacket.setType(EntityEventType.VIBRATION_DETECTED);
}
break;
case WARDEN_SONIC_BOOM:
if (entity instanceof WardenEntity wardenEntity) {
wardenEntity.onSonicBoom();
}
break;
}

View file

@ -23,27 +23,23 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.protocol.java.entity.spawn;
package org.geysermc.geyser.translator.protocol.java.entity;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddPaintingPacket;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.geyser.entity.type.PaintingEntity;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundSoundEntityPacket;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.level.PaintingType;
@Translator(packet = ClientboundAddPaintingPacket.class)
public class JavaAddPaintingTranslator extends PacketTranslator<ClientboundAddPaintingPacket> {
import org.geysermc.geyser.util.SoundUtils;
@Translator(packet = ClientboundSoundEntityPacket.class)
public class JavaSoundEntityTranslator extends PacketTranslator<ClientboundSoundEntityPacket> {
@Override
public void translate(GeyserSession session, ClientboundAddPaintingPacket packet) {
Vector3f position = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ());
PaintingEntity entity = new PaintingEntity(session, packet.getEntityId(),
session.getEntityCache().getNextEntityId().incrementAndGet(), packet.getUuid(),
position, PaintingType.getByPaintingType(packet.getPaintingType()), packet.getDirection().getHorizontalIndex());
session.getEntityCache().spawnEntity(entity);
public void translate(GeyserSession session, ClientboundSoundEntityPacket packet) {
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
if (entity == null) {
return;
}
SoundUtils.playBuiltinSound(session, packet.getSound(), entity.getPosition(), packet.getVolume(), packet.getPitch());
}
}

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