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! 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 ## Setting Up
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.

View file

@ -13,7 +13,7 @@
<repositories> <repositories>
<repository> <repository>
<id>papermc</id> <id>papermc</id>
<url>https://papermc.io/repo/repository/maven-public/</url> <url>https://repo.papermc.io/repository/maven-public/</url>
</repository> </repository>
<repository> <repository>
<id>viaversion-repo</id> <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 * 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) { private void workAroundWeirdBug(GeyserBootstrap bootstrap) {
MinecraftProtocol protocol = new MinecraftProtocol();
LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().getAddress(), LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().getAddress(),
bootstrap.getGeyserConfig().getRemote().getPort(), this.serverSocketAddress, bootstrap.getGeyserConfig().getRemote().getPort(), this.serverSocketAddress,
InetAddress.getLoopbackAddress().getHostAddress(), new MinecraftProtocol()); InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper());
session.connect(); session.connect();
} }

View file

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

View file

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

View file

@ -43,7 +43,7 @@ public class FloodgateKeyLoader {
if (floodgateDataFolder != null) { if (floodgateDataFolder != null) {
Path autoKey = floodgateDataFolder.resolve("key.pem"); Path autoKey = floodgateDataFolder.resolve("key.pem");
if (Files.exists(autoKey)) { if (Files.exists(autoKey)) {
logger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded")); logger.debug(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
return autoKey; return autoKey;
} else { } else {
logger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.missing_key")); logger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.missing_key"));
@ -52,7 +52,7 @@ public class FloodgateKeyLoader {
Path floodgateKey; Path floodgateKey;
if (config.getFloodgateKeyFile().equals("public-key.pem")) { 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"); floodgateKey = geyserDataFolder.resolve("key.pem");
} else { } else {
floodgateKey = geyserDataFolder.resolve(config.getFloodgateKeyFile()); 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.session.auth.AuthType;
import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.skin.FloodgateSkinUploader;
import org.geysermc.geyser.skin.SkinProvider; import org.geysermc.geyser.skin.SkinProvider;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.inventory.item.ItemTranslator; import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
@ -203,7 +204,6 @@ public class GeyserImpl implements GeyserApi {
GeyserLogger logger = bootstrap.getGeyserLogger(); GeyserLogger logger = bootstrap.getGeyserLogger();
GeyserConfiguration config = bootstrap.getGeyserConfig(); GeyserConfiguration config = bootstrap.getGeyserConfig();
logger.setDebug(config.isDebugMode());
ScoreboardUpdater.init(); 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 // Ensure that PacketLib does not create an event loop for handling packets; we'll do that ourselves
TcpSession.USE_EVENT_LOOP_FOR_PACKETS = false; 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"; String branch = "unknown";
int buildNumber = -1; int buildNumber = -1;
if (this.productionEnvironment()) { if (this.productionEnvironment()) {
@ -321,14 +309,34 @@ public class GeyserImpl implements GeyserApi {
if (shouldStartListener) { if (shouldStartListener) {
bedrockServer.bind().whenComplete((avoid, throwable) -> { bedrockServer.bind().whenComplete((avoid, throwable) -> {
if (throwable == null) { 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 { } else {
logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort()))); String address = config.getBedrock().getAddress();
throwable.printStackTrace(); 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(); }).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()) { if (config.getMetrics().isEnabled()) {
metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger("")); metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger(""));
metrics.addCustomChart(new Metrics.SingleLineChart("players", sessionManager::size)); 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.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; 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.GeyserImpl;
import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.command.CommandSender;
import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommand;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockUtils;
public class OffhandCommand extends GeyserCommand { public class OffhandCommand extends GeyserCommand {
@ -46,8 +46,8 @@ public class OffhandCommand extends GeyserCommand {
return; return;
} }
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO, ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
Direction.DOWN); Direction.DOWN, session.getNextSequence());
session.sendDownstreamPacket(releaseItemPacket); 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.configuration.GeyserConfiguration;
import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.network.MinecraftProtocol;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.CpuUtils;
import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.FileUtils;
import org.geysermc.geyser.util.WebUtils; import org.geysermc.geyser.util.WebUtils;
import org.geysermc.floodgate.util.DeviceOs; import org.geysermc.floodgate.util.DeviceOs;
@ -64,6 +65,7 @@ public class DumpInfo {
private final DumpInfo.VersionInfo versionInfo; private final DumpInfo.VersionInfo versionInfo;
private final int cpuCount; private final int cpuCount;
private final String cpuName;
private final Locale systemLocale; private final Locale systemLocale;
private final String systemEncoding; private final String systemEncoding;
private Properties gitInfo; private Properties gitInfo;
@ -80,6 +82,7 @@ public class DumpInfo {
this.versionInfo = new VersionInfo(); this.versionInfo = new VersionInfo();
this.cpuCount = Runtime.getRuntime().availableProcessors(); this.cpuCount = Runtime.getRuntime().availableProcessors();
this.cpuName = CpuUtils.tryGetProcessorName();
this.systemLocale = Locale.getDefault(); this.systemLocale = Locale.getDefault();
this.systemEncoding = System.getProperty("file.encoding"); 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; import org.geysermc.geyser.translator.text.MessageTranslator;
public final class EntityDefinitions { public final class EntityDefinitions {
public static final EntityDefinition<AllayEntity> ALLAY;
public static final EntityDefinition<AreaEffectCloudEntity> AREA_EFFECT_CLOUD; public static final EntityDefinition<AreaEffectCloudEntity> AREA_EFFECT_CLOUD;
public static final EntityDefinition<ArmorStandEntity> ARMOR_STAND; public static final EntityDefinition<ArmorStandEntity> ARMOR_STAND;
public static final EntityDefinition<TippedArrowEntity> ARROW; 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<SpiderEntity> CAVE_SPIDER;
public static final EntityDefinition<MinecartEntity> CHEST_MINECART; public static final EntityDefinition<MinecartEntity> CHEST_MINECART;
public static final EntityDefinition<ChickenEntity> CHICKEN; public static final EntityDefinition<ChickenEntity> CHICKEN;
public static final EntityDefinition<ChestBoatEntity> CHEST_BOAT;
public static final EntityDefinition<AbstractFishEntity> COD; public static final EntityDefinition<AbstractFishEntity> COD;
public static final EntityDefinition<CommandBlockMinecartEntity> COMMAND_BLOCK_MINECART; public static final EntityDefinition<CommandBlockMinecartEntity> COMMAND_BLOCK_MINECART;
public static final EntityDefinition<CowEntity> COW; 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<FireworkEntity> FIREWORK_ROCKET;
public static final EntityDefinition<FishingHookEntity> FISHING_BOBBER; public static final EntityDefinition<FishingHookEntity> FISHING_BOBBER;
public static final EntityDefinition<FoxEntity> FOX; 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<FurnaceMinecartEntity> FURNACE_MINECART; // Not present on Bedrock
public static final EntityDefinition<GhastEntity> GHAST; public static final EntityDefinition<GhastEntity> GHAST;
public static final EntityDefinition<GiantEntity> GIANT; public static final EntityDefinition<GiantEntity> GIANT;
@ -143,6 +146,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<SquidEntity> SQUID; public static final EntityDefinition<SquidEntity> SQUID;
public static final EntityDefinition<AbstractSkeletonEntity> STRAY; public static final EntityDefinition<AbstractSkeletonEntity> STRAY;
public static final EntityDefinition<StriderEntity> STRIDER; public static final EntityDefinition<StriderEntity> STRIDER;
public static final EntityDefinition<TadpoleEntity> TADPOLE;
public static final EntityDefinition<TNTEntity> TNT; public static final EntityDefinition<TNTEntity> TNT;
public static final EntityDefinition<MinecartEntity> TNT_MINECART; public static final EntityDefinition<MinecartEntity> TNT_MINECART;
public static final EntityDefinition<TraderLlamaEntity> TRADER_LLAMA; 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<VillagerEntity> VILLAGER;
public static final EntityDefinition<VindicatorEntity> VINDICATOR; public static final EntityDefinition<VindicatorEntity> VINDICATOR;
public static final EntityDefinition<AbstractMerchantEntity> WANDERING_TRADER; public static final EntityDefinition<AbstractMerchantEntity> WANDERING_TRADER;
public static final EntityDefinition<WardenEntity> WARDEN;
public static final EntityDefinition<RaidParticipantEntity> WITCH; public static final EntityDefinition<RaidParticipantEntity> WITCH;
public static final EntityDefinition<WitherEntity> WITHER; public static final EntityDefinition<WitherEntity> WITHER;
public static final EntityDefinition<AbstractSkeletonEntity> WITHER_SKELETON; public static final EntityDefinition<AbstractSkeletonEntity> WITHER_SKELETON;
@ -179,7 +184,7 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles .addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles
.addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName) .addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName)
.addTranslator(MetadataType.BOOLEAN, Entity::setDisplayNameVisible) .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.BOOLEAN, Entity::setGravity)
.addTranslator(MetadataType.POSE, (entity, entityMetadata) -> entity.setPose(entityMetadata.getValue())) .addTranslator(MetadataType.POSE, (entity, entityMetadata) -> entity.setPose(entityMetadata.getValue()))
.addTranslator(MetadataType.INT, Entity::setFreezing) .addTranslator(MetadataType.INT, Entity::setFreezing)
@ -209,6 +214,9 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight) .addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight)
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything
.build(); .build();
CHEST_BOAT = EntityDefinition.inherited(ChestBoatEntity::new, BOAT)
.type(EntityType.CHEST_BOAT)
.build();
DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase) DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase)
.type(EntityType.DRAGON_FIREBALL) .type(EntityType.DRAGON_FIREBALL)
.heightAndWidth(1.0f) .heightAndWidth(1.0f)
@ -274,6 +282,7 @@ public final class EntityDefinitions {
.build(); .build();
PAINTING = EntityDefinition.<PaintingEntity>inherited(null, entityBase) PAINTING = EntityDefinition.<PaintingEntity>inherited(null, entityBase)
.type(EntityType.PAINTING) .type(EntityType.PAINTING)
.addTranslator(MetadataType.PAINTING_VARIANT, PaintingEntity::setPaintingType)
.build(); .build();
SHULKER_BULLET = EntityDefinition.inherited(ThrowableEntity::new, entityBase) SHULKER_BULLET = EntityDefinition.inherited(ThrowableEntity::new, entityBase)
.type(EntityType.SHULKER_BULLET) .type(EntityType.SHULKER_BULLET)
@ -441,6 +450,10 @@ public final class EntityDefinitions {
// Extends mob // Extends mob
{ {
ALLAY = EntityDefinition.inherited(AllayEntity::new, mobEntityBase)
.type(EntityType.ALLAY)
.height(0.6f).width(0.35f)
.build();
BAT = EntityDefinition.inherited(BatEntity::new, mobEntityBase) BAT = EntityDefinition.inherited(BatEntity::new, mobEntityBase)
.type(EntityType.BAT) .type(EntityType.BAT)
.height(0.9f).width(0.5f) .height(0.9f).width(0.5f)
@ -550,6 +563,11 @@ public final class EntityDefinitions {
.height(0.8f).width(0.4f) .height(0.8f).width(0.4f)
.addTranslator(MetadataType.BYTE, VexEntity::setVexFlags) .addTranslator(MetadataType.BYTE, VexEntity::setVexFlags)
.build(); .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) WITHER = EntityDefinition.inherited(WitherEntity::new, mobEntityBase)
.type(EntityType.WITHER) .type(EntityType.WITHER)
.height(3.5f).width(0.9f) .height(3.5f).width(0.9f)
@ -634,6 +652,10 @@ public final class EntityDefinitions {
.type(EntityType.SALMON) .type(EntityType.SALMON)
.height(0.5f).width(0.7f) .height(0.5f).width(0.7f)
.build(); .build();
TADPOLE = EntityDefinition.inherited(TadpoleEntity::new, abstractFishEntityBase)
.type(EntityType.TADPOLE)
.height(0.3f).width(0.4f)
.build();
TROPICAL_FISH = EntityDefinition.inherited(TropicalFishEntity::new, abstractFishEntityBase) TROPICAL_FISH = EntityDefinition.inherited(TropicalFishEntity::new, abstractFishEntityBase)
.type(EntityType.TROPICAL_FISH) .type(EntityType.TROPICAL_FISH)
.heightAndWidth(0.6f) .heightAndWidth(0.6f)
@ -735,6 +757,12 @@ public final class EntityDefinitions {
.addTranslator(null) // Trusted player 1 .addTranslator(null) // Trusted player 1
.addTranslator(null) // Trusted player 2 .addTranslator(null) // Trusted player 2
.build(); .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) HOGLIN = EntityDefinition.inherited(HoglinEntity::new, ageableEntityBase)
.type(EntityType.HOGLIN) .type(EntityType.HOGLIN)
.height(1.4f).width(1.3965f) .height(1.4f).width(1.3965f)
@ -871,7 +899,7 @@ public final class EntityDefinitions {
CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase) CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase)
.type(EntityType.CAT) .type(EntityType.CAT)
.height(0.35f).width(0.3f) .height(0.35f).width(0.3f)
.addTranslator(MetadataType.INT, CatEntity::setCatVariant) .addTranslator(MetadataType.CAT_VARIANT, CatEntity::setCatVariant)
.addTranslator(MetadataType.BOOLEAN, CatEntity::setResting) .addTranslator(MetadataType.BOOLEAN, CatEntity::setResting)
.addTranslator(null) // "resting state one" //TODO .addTranslator(null) // "resting state one" //TODO
.addTranslator(MetadataType.INT, CatEntity::setCollarColor) .addTranslator(MetadataType.INT, CatEntity::setCollarColor)

View file

@ -52,4 +52,9 @@ public final class GeyserDirtyMetadata {
public boolean hasEntries() { public boolean hasEntries() {
return !metadata.isEmpty(); 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; 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.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.math.vector.Vector3i; import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
@ -50,13 +49,12 @@ public class EnderCrystalEntity extends Entity {
setFlag(EntityFlag.FIRE_IMMUNE, true); setFlag(EntityFlag.FIRE_IMMUNE, true);
} }
public void setBlockTarget(EntityMetadata<Optional<Position>, ?> entityMetadata) { public void setBlockTarget(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
// Show beam // Show beam
// Usually performed client-side on Bedrock except for Ender Dragon respawn event // 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()) { if (optionalPos.isPresent()) {
Position pos = optionalPos.get(); dirtyMetadata.put(EntityData.BLOCK_TARGET, optionalPos.get());
dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.from(pos.getX(), pos.getY(), pos.getZ()));
} else { } else {
dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.ZERO); dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.ZERO);
} }

View file

@ -94,6 +94,8 @@ public class Entity {
private float boundingBoxWidth; private float boundingBoxWidth;
@Setter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
protected String nametag = ""; protected String nametag = "";
@Setter(AccessLevel.NONE)
protected boolean silent = false;
/* Metadata end */ /* Metadata end */
protected List<Entity> passengers = Collections.emptyList(); protected List<Entity> passengers = Collections.emptyList();
@ -141,13 +143,19 @@ public class Entity {
*/ */
protected void initializeMetadata() { protected void initializeMetadata() {
dirtyMetadata.put(EntityData.SCALE, 1f); dirtyMetadata.put(EntityData.SCALE, 1f);
dirtyMetadata.put(EntityData.COLOR, 0); dirtyMetadata.put(EntityData.COLOR, (byte) 0);
dirtyMetadata.put(EntityData.MAX_AIR_SUPPLY, getMaxAir()); dirtyMetadata.put(EntityData.MAX_AIR_SUPPLY, getMaxAir());
setDimensions(Pose.STANDING); setDimensions(Pose.STANDING);
setFlag(EntityFlag.HAS_GRAVITY, true); setFlag(EntityFlag.HAS_GRAVITY, true);
setFlag(EntityFlag.HAS_COLLISION, true); setFlag(EntityFlag.HAS_COLLISION, true);
setFlag(EntityFlag.CAN_SHOW_NAME, true); setFlag(EntityFlag.CAN_SHOW_NAME, true);
setFlag(EntityFlag.CAN_CLIMB, 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() { public void spawnEntity() {
@ -351,7 +359,7 @@ public class Entity {
dirtyMetadata.put(EntityData.AIR_SUPPLY, (short) MathUtils.constrain(amount, 0, getMaxAir())); dirtyMetadata.put(EntityData.AIR_SUPPLY, (short) MathUtils.constrain(amount, 0, getMaxAir()));
} }
protected int getMaxAir() { protected short getMaxAir() {
return 300; return 300;
} }
@ -370,6 +378,10 @@ public class Entity {
dirtyMetadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0)); 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) { public void setGravity(BooleanEntityMetadata entityMetadata) {
setFlag(EntityFlag.HAS_GRAVITY, !entityMetadata.getPrimitiveValue()); 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.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -58,7 +57,7 @@ public class EvokerFangsEntity extends Entity implements Tickable {
public void setAttackStarted() { public void setAttackStarted() {
this.attackStarted = true; this.attackStarted = true;
if (!getFlag(EntityFlag.SILENT)) { if (!silent) {
// Play the chomp sound // Play the chomp sound
PlaySoundPacket packet = new PlaySoundPacket(); PlaySoundPacket packet = new PlaySoundPacket();
packet.setPosition(this.position); packet.setPosition(this.position);

View file

@ -36,8 +36,8 @@ import java.util.UUID;
public class FallingBlockEntity extends Entity { 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) { 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, 0f); super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, headYaw);
this.dirtyMetadata.put(EntityData.VARIANT, session.getBlockMappings().getBedrockBlockId(javaId)); 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.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
import lombok.Getter; import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.player.PlayerEntity; 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.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 org.geysermc.geyser.util.BlockUtils;
import java.util.UUID; import java.util.UUID;
@ -56,7 +55,7 @@ public class FishingHookEntity extends ThrowableEntity {
private final BoundingBox boundingBox; 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); 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); 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) { 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())); float volume = (float) (0.2f * Math.sqrt(0.2 * (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) + motion.getY() * motion.getY()));
if (volume > 1) { if (volume > 1) {
volume = 1; volume = 1;

View file

@ -79,8 +79,8 @@ public class ItemFrameEntity extends Entity {
*/ */
private boolean changed = true; 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) { 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, 0f); super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
NbtMapBuilder blockBuilder = NbtMap.builder() NbtMapBuilder blockBuilder = NbtMap.builder()
.putString("name", this.definition.entityType() == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame") .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.attribute.AttributeType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.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.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; 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.EntityDefinition;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractionResult;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Getter @Getter
@Setter @Setter
@ -123,12 +118,11 @@ public class LivingEntity extends Entity {
session.sendUpstreamPacket(attributesPacket); session.sendUpstreamPacket(attributesPacket);
} }
public Vector3i setBedPosition(EntityMetadata<Optional<Position>, ?> entityMetadata) { public Vector3i setBedPosition(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
Optional<Position> optionalPos = entityMetadata.getValue(); Optional<Vector3i> optionalPos = entityMetadata.getValue();
if (optionalPos.isPresent()) { if (optionalPos.isPresent()) {
Position bedPosition = optionalPos.get(); Vector3i bedPosition = optionalPos.get();
Vector3i vector = Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ()); dirtyMetadata.put(EntityData.BED_POSITION, bedPosition);
dirtyMetadata.put(EntityData.BED_POSITION, vector);
int bed = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition); int bed = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
// Bed has to be updated, or else player is floating in the air // Bed has to be updated, or else player is floating in the air
ChunkUtils.updateBlock(session, bed, bedPosition); ChunkUtils.updateBlock(session, bed, bedPosition);
@ -136,7 +130,7 @@ public class LivingEntity extends Entity {
// Has to be a byte or it does not work // Has to be a byte or it does not work
// (Bed position is what actually triggers sleep - "pose" is only optional) // (Bed position is what actually triggers sleep - "pose" is only optional)
dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 2); dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 2);
return vector; return bedPosition;
} else { } else {
// Player is no longer sleeping // Player is no longer sleeping
dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 0); dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 0);

View file

@ -25,33 +25,45 @@
package org.geysermc.geyser.entity.type; 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.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket; import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.level.PaintingType; import org.geysermc.geyser.level.PaintingType;
import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID; import java.util.UUID;
public class PaintingEntity extends Entity { public class PaintingEntity extends Entity {
private static final double OFFSET = -0.46875; private static final double OFFSET = -0.46875;
private final PaintingType paintingName; private final Direction direction;
private final int direction;
public PaintingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, PaintingType paintingName, int direction) { 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, EntityDefinitions.PAINTING, position, Vector3f.ZERO, 0f, 0f, 0f); super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
this.paintingName = paintingName;
this.direction = direction; this.direction = direction;
} }
@Override @Override
public void spawnEntity() { 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 addPaintingPacket = new AddPaintingPacket();
addPaintingPacket.setUniqueEntityId(geyserId); addPaintingPacket.setUniqueEntityId(geyserId);
addPaintingPacket.setRuntimeEntityId(geyserId); addPaintingPacket.setRuntimeEntityId(geyserId);
addPaintingPacket.setMotive(paintingName.getBedrockName()); addPaintingPacket.setMotive(type.getBedrockName());
addPaintingPacket.setPosition(fixOffset()); addPaintingPacket.setPosition(fixOffset(type));
addPaintingPacket.setDirection(direction); 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); session.sendUpstreamPacket(addPaintingPacket);
valid = true; valid = true;
@ -64,17 +76,17 @@ public class PaintingEntity extends Entity {
// Do nothing, as head look messes up paintings // Do nothing, as head look messes up paintings
} }
private Vector3f fixOffset() { private Vector3f fixOffset(PaintingType paintingName) {
Vector3f position = super.position; Vector3f position = super.position;
position = position.add(0.5, 0.5, 0.5); position = position.add(0.5, 0.5, 0.5);
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0; double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0; double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
return switch (direction) { return switch (direction) {
case 0 -> position.add(widthOffset, heightOffset, OFFSET); case SOUTH -> position.add(widthOffset, heightOffset, OFFSET);
case 1 -> position.add(-OFFSET, heightOffset, widthOffset); case WEST -> position.add(-OFFSET, heightOffset, widthOffset);
case 2 -> position.add(-widthOffset, heightOffset, -OFFSET); case NORTH -> position.add(-widthOffset, heightOffset, -OFFSET);
case 3 -> position.add(OFFSET, heightOffset, -widthOffset); case EAST -> position.add(OFFSET, heightOffset, -widthOffset);
default -> position; default -> position;
}; };
} }

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living; 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.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
@ -49,11 +50,11 @@ public class AbstractFishEntity extends WaterEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (EntityUtils.attemptToBucket(session, itemInHand)) { if (EntityUtils.attemptToBucket(session, itemInHand)) {
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else { } 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; 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.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.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.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; 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 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()); 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()); 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()); 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()); 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()); 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()); 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 negativeZToggle the flag to set true if the Z value of rotation is negative
* @param rotation the Java rotation value * @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 // Indicate that rotation should be checked
setFlag(EntityFlag.BRIBED, true); setFlag(EntityFlag.BRIBED, true);
int rotationX = MathUtils.wrapDegreesToInt(rotation.getPitch()); int rotationX = MathUtils.wrapDegreesToInt(rotation.getX());
int rotationY = MathUtils.wrapDegreesToInt(rotation.getYaw()); int rotationY = MathUtils.wrapDegreesToInt(rotation.getY());
int rotationZ = MathUtils.wrapDegreesToInt(rotation.getRoll()); int rotationZ = MathUtils.wrapDegreesToInt(rotation.getZ());
// The top bit acts like binary and determines if each rotation goes above 100 // 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 // 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); 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; 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.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
@ -47,20 +48,20 @@ public class DolphinEntity extends WaterEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) { if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) {
return InteractiveTag.FEED; return InteractiveTag.FEED;
} }
return super.testMobInteraction(itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) { if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) {
// Feed // Feed
return InteractionResult.SUCCESS; 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; 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.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -48,7 +49,7 @@ public class IronGolemEntity extends GolemEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().ironIngot()) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().ironIngot()) {
if (health < maxHealth) { if (health < maxHealth) {
// Healing the iron golem // Healing the iron golem
@ -57,6 +58,6 @@ public class IronGolemEntity extends GolemEntity {
return InteractionResult.PASS; 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); return tag != InteractiveTag.NONE ? tag : super.testInteraction(hand);
} }
} }
@ -109,7 +109,7 @@ public class MobEntity extends LivingEntity {
if (result.consumesAction()) { if (result.consumesAction()) {
return result; return result;
} else { } else {
InteractionResult mobResult = mobInteract(itemInHand); InteractionResult mobResult = mobInteract(hand, itemInHand);
return mobResult.consumesAction() ? mobResult : super.interact(hand); return mobResult.consumesAction() ? mobResult : super.interact(hand);
} }
} }
@ -137,12 +137,12 @@ public class MobEntity extends LivingEntity {
} }
@Nonnull @Nonnull
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
return InteractiveTag.NONE; return InteractiveTag.NONE;
} }
@Nonnull @Nonnull
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) {
return InteractionResult.PASS; return InteractionResult.PASS;
} }

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living; 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.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
@ -51,7 +52,7 @@ public class SnowGolemEntity extends GolemEntity {
@Nonnull @Nonnull
@Override @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)) { if (session.getItemMappings().getStoredItems().shears() == itemInHand.getJavaId() && isAlive() && !getFlag(EntityFlag.SHEARED)) {
// Shearing the snow golem // Shearing the snow golem
return InteractiveTag.SHEAR; return InteractiveTag.SHEAR;
@ -61,7 +62,7 @@ public class SnowGolemEntity extends GolemEntity {
@Nonnull @Nonnull
@Override @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)) { if (session.getItemMappings().getStoredItems().shears() == itemInHand.getJavaId() && isAlive() && !getFlag(EntityFlag.SHEARED)) {
// Shearing the snow golem // Shearing the snow golem
return InteractionResult.SUCCESS; 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; 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.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -63,16 +64,16 @@ public class AnimalEntity extends AgeableEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (canEat(itemInHand)) { if (canEat(itemInHand)) {
return InteractiveTag.FEED; return InteractiveTag.FEED;
} }
return super.testMobInteraction(itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (canEat(itemInHand)) { if (canEat(itemInHand)) {
// FEED // FEED
if (getFlag(EntityFlag.BABY)) { if (getFlag(EntityFlag.BABY)) {
@ -82,6 +83,6 @@ public class AnimalEntity extends AgeableEntity {
return InteractionResult.CONSUME; 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.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -64,7 +65,7 @@ public class AxolotlEntity extends AnimalEntity {
} }
@Override @Override
protected int getMaxAir() { protected short getMaxAir() {
return 6000; return 6000;
} }
@ -75,11 +76,11 @@ public class AxolotlEntity extends AnimalEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (EntityUtils.attemptToBucket(session, itemInHand)) { if (EntityUtils.attemptToBucket(session, itemInHand)) {
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else { } else {
return super.mobInteract(itemInHand); return super.mobInteract(hand, itemInHand);
} }
} }
} }

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal; 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.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -44,9 +45,9 @@ public class CowEntity extends AnimalEntity {
@Nonnull @Nonnull
@Override @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")) { if (getFlag(EntityFlag.BABY) || !itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) {
return super.testMobInteraction(itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
return InteractiveTag.MILK; return InteractiveTag.MILK;
@ -54,9 +55,9 @@ public class CowEntity extends AnimalEntity {
@Nonnull @Nonnull
@Override @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")) { 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); 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.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -65,12 +66,12 @@ public class GoatEntity extends AnimalEntity {
@Nonnull @Nonnull
@Override @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")) { if (!getFlag(EntityFlag.BABY) && itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) {
session.playSoundEvent(isScreamer ? SoundEvent.MILK_SCREAMER : SoundEvent.MILK, position); session.playSoundEvent(isScreamer ? SoundEvent.MILK_SCREAMER : SoundEvent.MILK, position);
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else { } else {
return super.mobInteract(itemInHand); return super.mobInteract(hand, itemInHand);
} }
} }
} }

View file

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

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living.animal; 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.metadata.type.ObjectEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
@ -52,7 +53,7 @@ public class MooshroomEntity extends AnimalEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
StoredItemMappings storedItems = session.getItemMappings().getStoredItems(); StoredItemMappings storedItems = session.getItemMappings().getStoredItems();
if (!isBaby()) { if (!isBaby()) {
if (itemInHand.getJavaId() == storedItems.bowl()) { if (itemInHand.getJavaId() == storedItems.bowl()) {
@ -63,12 +64,12 @@ public class MooshroomEntity extends AnimalEntity {
return InteractiveTag.MOOSHROOM_SHEAR; return InteractiveTag.MOOSHROOM_SHEAR;
} }
} }
return super.testMobInteraction(itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
StoredItemMappings storedItems = session.getItemMappings().getStoredItems(); StoredItemMappings storedItems = session.getItemMappings().getStoredItems();
boolean isBaby = isBaby(); boolean isBaby = isBaby();
if (!isBaby && itemInHand.getJavaId() == storedItems.bowl()) { if (!isBaby && itemInHand.getJavaId() == storedItems.bowl()) {
@ -81,6 +82,6 @@ public class MooshroomEntity extends AnimalEntity {
// ? // ?
return InteractionResult.SUCCESS; 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; 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.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
@ -50,23 +51,23 @@ public class OcelotEntity extends AnimalEntity {
@Nonnull @Nonnull
@Override @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) { if (!getFlag(EntityFlag.TRUSTING) && canEat(itemInHand) && session.getPlayerEntity().getPosition().distanceSquared(position) < 9f) {
// Attempt to feed // Attempt to feed
return InteractiveTag.FEED; return InteractiveTag.FEED;
} else { } else {
return super.testMobInteraction(itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
} }
@Nonnull @Nonnull
@Override @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) { if (!getFlag(EntityFlag.TRUSTING) && canEat(itemInHand) && session.getPlayerEntity().getPosition().distanceSquared(position) < 9f) {
// Attempt to feed // Attempt to feed
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else { } 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.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
@ -93,16 +94,16 @@ public class PandaEntity extends AnimalEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (mainGene == Gene.WORRIED && session.isThunder()) { if (mainGene == Gene.WORRIED && session.isThunder()) {
return InteractiveTag.NONE; return InteractiveTag.NONE;
} }
return super.testMobInteraction(itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (mainGene == Gene.WORRIED && session.isThunder()) { if (mainGene == Gene.WORRIED && session.isThunder()) {
// Huh! // Huh!
return InteractionResult.PASS; return InteractionResult.PASS;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -48,6 +48,6 @@ public class BasePiglinEntity extends MonsterEntity {
@Override @Override
protected boolean isShaking() { 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.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -63,23 +64,23 @@ public class CreeperEntity extends MonsterEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) {
return InteractiveTag.IGNITE_CREEPER; return InteractiveTag.IGNITE_CREEPER;
} else { } else {
return super.testMobInteraction(itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
} }
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) {
// Ignite creeper // Ignite creeper
session.playSoundEvent(SoundEvent.IGNITE, position); session.playSoundEvent(SoundEvent.IGNITE, position);
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else { } 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() { private void effectTick() {
Random random = ThreadLocalRandom.current(); 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) { if (Math.cos(wingPosition * 2f * Math.PI) <= -0.3f && Math.cos(lastWingPosition * 2f * Math.PI) >= -0.3f) {
PlaySoundPacket playSoundPacket = new PlaySoundPacket(); PlaySoundPacket playSoundPacket = new PlaySoundPacket();
playSoundPacket.setSound("mob.enderdragon.flap"); playSoundPacket.setSound("mob.enderdragon.flap");

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.entity.type.living.monster; 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.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -71,8 +72,8 @@ public class PiglinEntity extends BasePiglinEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
InteractiveTag tag = super.testMobInteraction(itemInHand); InteractiveTag tag = super.testMobInteraction(hand, itemInHand);
if (tag != InteractiveTag.NONE) { if (tag != InteractiveTag.NONE) {
return tag; return tag;
} else { } else {
@ -82,8 +83,8 @@ public class PiglinEntity extends BasePiglinEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
InteractionResult superResult = super.mobInteract(itemInHand); InteractionResult superResult = super.mobInteract(hand, itemInHand);
if (superResult.consumesAction()) { if (superResult.consumesAction()) {
return superResult; return superResult;
} else { } 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.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData; 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.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
@ -67,22 +68,22 @@ public class ZombieVillagerEntity extends ZombieEntity {
@Nonnull @Nonnull
@Override @Override
protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) {
return InteractiveTag.CURE; return InteractiveTag.CURE;
} else { } else {
return super.testMobInteraction(itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
} }
@Nonnull @Nonnull
@Override @Override
protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) {
if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) { 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 // The client doesn't know if the entity has weakness as that's not usually sent over the network
return InteractionResult.CONSUME; return InteractionResult.CONSUME;
} else { } 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.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import 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.FloatEntityMetadata;
@ -169,6 +168,12 @@ public class PlayerEntity extends LivingEntity {
} }
session.sendUpstreamPacket(movePlayerPacket); session.sendUpstreamPacket(movePlayerPacket);
if (teleported) {
// As of 1.19.0, head yaw seems to be ignored during teleports.
updateHeadLookRotation(headYaw);
}
if (leftParrot != null) { if (leftParrot != null) {
leftParrot.moveAbsolute(position, yaw, pitch, headYaw, true, teleported); 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) { public void updateRotation(float yaw, float pitch, float headYaw, boolean isOnGround) {
// the method below is called by super.updateRotation(yaw, pitch, isOnGround). moveRelative(0, 0, 0, yaw, pitch, headYaw, 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);
} }
@Override @Override
@ -265,7 +226,7 @@ public class PlayerEntity extends LivingEntity {
} }
@Override @Override
public Vector3i setBedPosition(EntityMetadata<Optional<Position>, ?> entityMetadata) { public Vector3i setBedPosition(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
return bedPosition = super.setBedPosition(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.Attribute;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType; 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.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.nukkitx.math.vector.Vector3f; 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.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.DimensionUtils;
import java.util.Collections; import javax.annotation.Nullable;
import java.util.List; import java.util.*;
import java.util.Map;
import java.util.UUID;
/** /**
* The entity class specifically for a {@link GeyserSession}'s player. * The entity class specifically for a {@link GeyserSession}'s player.
@ -75,6 +75,11 @@ public class SessionPlayerEntity extends PlayerEntity {
valid = true; valid = true;
} }
@Override
protected void setClientSideSilent() {
// Do nothing, since we want the session player to hear their own footstep sounds for example.
}
@Override @Override
public void spawnEntity() { public void spawnEntity() {
// Already logged in // Already logged in
@ -222,4 +227,14 @@ public class SessionPlayerEntity extends PlayerEntity {
this.attributes.put(type, attributeData); this.attributes.put(type, attributeData);
return 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", 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", "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", "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", "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", "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; 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.google.common.collect.ImmutableSet;
import com.nukkitx.math.vector.Vector3i; import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMap;
@ -36,9 +35,9 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Container;
import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.BlockUtils;
import java.util.Collections; import java.util.Collections;
@ -154,8 +153,7 @@ public class BlockInventoryHolder extends InventoryHolder {
} }
Vector3i holderPos = inventory.getHolderPosition(); Vector3i holderPos = inventory.getHolderPosition();
Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos.getX(), holderPos.getY(), holderPos.getZ());
int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ());
UpdateBlockPacket blockPacket = new UpdateBlockPacket(); UpdateBlockPacket blockPacket = new UpdateBlockPacket();
blockPacket.setDataLayer(0); blockPacket.setDataLayer(0);
blockPacket.setBlockPosition(holderPos); blockPacket.setBlockPosition(holderPos);

View file

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

View file

@ -60,6 +60,7 @@ public class StoredItemMappings {
private final int saddle; private final int saddle;
private final int shears; private final int shears;
private final ItemMapping shield; private final ItemMapping shield;
private final int slimeBall;
private final int waterBucket; private final int waterBucket;
private final ItemMapping wheat; private final ItemMapping wheat;
private final ItemMapping writableBook; private final ItemMapping writableBook;
@ -87,6 +88,7 @@ public class StoredItemMappings {
this.saddle = load(itemMappings, "saddle").getJavaId(); this.saddle = load(itemMappings, "saddle").getJavaId();
this.shears = load(itemMappings, "shears").getJavaId(); this.shears = load(itemMappings, "shears").getJavaId();
this.shield = load(itemMappings, "shield"); this.shield = load(itemMappings, "shield");
this.slimeBall = load(itemMappings, "slime_ball").getJavaId();
this.waterBucket = load(itemMappings, "water_bucket").getJavaId(); this.waterBucket = load(itemMappings, "water_bucket").getJavaId();
this.wheat = load(itemMappings, "wheat"); this.wheat = load(itemMappings, "wheat");
this.writableBook = load(itemMappings, "writable_book"); 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 com.github.steveice10.mc.protocol.data.game.advancement.Advancement;
import lombok.NonNull; import lombok.NonNull;
import org.geysermc.geyser.session.cache.AdvancementsCache; import org.geysermc.geyser.session.cache.AdvancementsCache;
import org.geysermc.geyser.text.ChatColor;
import java.util.List; import java.util.List;
@ -69,6 +70,14 @@ public class GeyserAdvancement {
return this.advancement.getDisplayData(); 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) { public String getRootId(AdvancementsCache advancementsCache) {
if (rootId == null) { if (rootId == null) {
if (this.advancement.getParentId() == 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.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; 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.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtMapBuilder;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; 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.GeyserSession;
import org.geysermc.geyser.session.cache.ChunkCache; import org.geysermc.geyser.session.cache.ChunkCache;
import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
import org.geysermc.geyser.level.block.BlockStateValues;
import java.util.Locale; import java.util.Locale;
@ -83,7 +82,7 @@ public class GeyserWorldManager extends WorldManager {
@Override @Override
public void setGameRule(GeyserSession session, String name, Object value) { 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)); gameruleCache.put(name, String.valueOf(value));
} }
@ -109,12 +108,12 @@ public class GeyserWorldManager extends WorldManager {
@Override @Override
public void setPlayerGameMode(GeyserSession session, GameMode gameMode) { 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 @Override
public void setDifficulty(GeyserSession session, Difficulty difficulty) { 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 @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), SKELETON("Skeleton", 4, 3),
DONKEY_KONG("DonkeyKong", 4, 3), DONKEY_KONG("DonkeyKong", 4, 3),
POINTER("Pointer", 4, 4), POINTER("Pointer", 4, 4),
PIG_SCENE("Pigscene", 4, 4), PIGSCENE("Pigscene", 4, 4),
BURNING_SKULL("BurningSkull", 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 static final PaintingType[] VALUES = values();
private String bedrockName; private final String bedrockName;
private int width; private final int width;
private int height; private final 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());
}
public static PaintingType getByName(String javaName) { public static PaintingType getByName(String javaName) {
for (PaintingType paintingName : VALUES) { for (PaintingType paintingName : VALUES) {

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.level; 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.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
import com.nukkitx.math.vector.Vector3i; import com.nukkitx.math.vector.Vector3i;
@ -41,17 +40,6 @@ import org.geysermc.geyser.session.GeyserSession;
*/ */
public abstract class WorldManager { 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 * Gets the Java block state at the specified location
* *
@ -59,7 +47,7 @@ public abstract class WorldManager {
* @param vector the position * @param vector the position
* @return the block state at the specified location * @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()); 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.MinecraftCodec;
import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec;
import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
import com.nukkitx.protocol.bedrock.v475.Bedrock_v475; import com.nukkitx.protocol.bedrock.beta.BedrockBeta;
import com.nukkitx.protocol.bedrock.v486.Bedrock_v486;
import com.nukkitx.protocol.bedrock.v503.Bedrock_v503;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; 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 * Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports. * release of the game that Geyser supports.
*/ */
public static final 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 * 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; private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC;
static { 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() SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
.minecraftVersion("1.18.30/1.18.31") .minecraftVersion("1.19.0")
.build()); .build());
} }

View file

@ -26,6 +26,7 @@
package org.geysermc.geyser.network.netty; package org.geysermc.geyser.network.netty;
import com.github.steveice10.packetlib.BuiltinFlags; 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.packet.PacketProtocol;
import com.github.steveice10.packetlib.tcp.*; import com.github.steveice10.packetlib.tcp.*;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
@ -47,15 +48,17 @@ public final class LocalSession extends TcpSession {
private final SocketAddress targetAddress; private final SocketAddress targetAddress;
private final String clientIp; 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); super(host, port, protocol);
this.targetAddress = targetAddress; this.targetAddress = targetAddress;
this.clientIp = clientIp; this.clientIp = clientIp;
this.codecHelper = codecHelper;
} }
@Override @Override
public void connect() { public void connect(boolean wait) {
if (this.disconnected) { if (this.disconnected) {
throw new IllegalStateException("Connection has already been 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 // TODO duplicate code
private void addHAProxySupport(ChannelPipeline pipeline) { private void addHAProxySupport(ChannelPipeline pipeline) {
InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); 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.entity.type.EntityType;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
import com.github.steveice10.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.level.particle.ParticleType;
import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
import com.github.steveice10.packetlib.packet.Packet; 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); 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}. * A mapped registry holding {@link SoundTranslator}s to their corresponding {@link SoundInteractionTranslator}.

View file

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

View file

@ -54,8 +54,9 @@ public class SoundRegistryLoader implements RegistryLoader<String, Map<String, S
while(soundsIterator.hasNext()) { while(soundsIterator.hasNext()) {
Map.Entry<String, JsonNode> next = soundsIterator.next(); Map.Entry<String, JsonNode> next = soundsIterator.next();
JsonNode brMap = next.getValue(); JsonNode brMap = next.getValue();
soundMappings.put(next.getKey(), new SoundMapping( String javaSound = next.getKey();
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("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("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, 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.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.nukkitx.nbt.*; import com.nukkitx.nbt.*;
import com.nukkitx.protocol.bedrock.v475.Bedrock_v475; import com.nukkitx.protocol.bedrock.beta.BedrockBeta;
import com.nukkitx.protocol.bedrock.v486.Bedrock_v486;
import com.nukkitx.protocol.bedrock.v503.Bedrock_v503;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2IntMap; 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 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> 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 { static {
ImmutableMap.Builder<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> stateMapperBuilder = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder() 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_19_0", BedrockBeta.BETA_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;
};
});
BLOCK_MAPPERS = stateMapperBuilder.build(); BLOCK_MAPPERS = stateMapperBuilder.build();
} }
@ -294,7 +250,7 @@ public class BlockRegistryPopulator {
builder.pickItem(pickItemNode.textValue().intern()); 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); builder.pistonBehavior(PistonBehavior.BLOCK);
} else { } else {
JsonNode pistonBehaviorNode = entry.getValue().get("piston_behavior"); 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.NbtMapBuilder;
import com.nukkitx.nbt.NbtType; import com.nukkitx.nbt.NbtType;
import com.nukkitx.nbt.NbtUtils; 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.SoundEvent;
import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData;
import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
import com.nukkitx.protocol.bedrock.packet.StartGamePacket; 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.Int2IntMap;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
@ -66,9 +64,7 @@ public class ItemRegistryPopulator {
public static void populate() { public static void populate() {
Map<String, PaletteVersion> paletteVersions = new Object2ObjectOpenHashMap<>(); Map<String, PaletteVersion> paletteVersions = new Object2ObjectOpenHashMap<>();
paletteVersions.put("1_18_0", new PaletteVersion(Bedrock_v475.V475_CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_19_0", new PaletteVersion(BedrockBeta.BETA_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()));
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
@ -230,18 +226,6 @@ public class ItemRegistryPopulator {
mappingItem = entry.getValue(); 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")) { if (usingFurnaceMinecart && javaIdentifier.equals("minecraft:furnace_minecart")) {
javaFurnaceMinecartId = itemIndex; javaFurnaceMinecartId = itemIndex;
itemIndex++; itemIndex++;
@ -250,6 +234,7 @@ public class ItemRegistryPopulator {
continue; continue;
} }
String bedrockIdentifier = mappingItem.getBedrockIdentifier();
int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier); int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier);
if (bedrockId == Short.MIN_VALUE) { if (bedrockId == Short.MIN_VALUE) {
throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier); 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) { public SoundMapping(String java, String bedrock, String playsound, int extraData, String identifier, boolean levelEvent) {
this.java = java; this.java = java;
this.bedrock = bedrock == null || bedrock.equalsIgnoreCase("") ? null : bedrock; this.bedrock = bedrock == null || bedrock.isEmpty() ? null : bedrock;
this.playsound = playsound == null || playsound.equalsIgnoreCase("") ? null : playsound; this.playsound = playsound == null || playsound.isEmpty() ? null : playsound;
this.extraData = extraData; this.extraData = extraData;
this.identifier = identifier == null || identifier.equalsIgnoreCase("") ? ":" : identifier; this.identifier = identifier == null || identifier.isEmpty() ? ":" : identifier;
this.levelEvent = levelEvent; 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.auth.service.MsaAuthenticationService;
import com.github.steveice10.mc.protocol.MinecraftConstants; import com.github.steveice10.mc.protocol.MinecraftConstants;
import com.github.steveice10.mc.protocol.MinecraftProtocol; 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.ProtocolState;
import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException; 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.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; 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.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.CustomStatistic;
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; 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.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.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; 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.github.steveice10.packetlib.tcp.TcpSession;
import com.nukkitx.math.GenericMath; import com.nukkitx.math.GenericMath;
import com.nukkitx.math.vector.*; import com.nukkitx.math.vector.*;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockPacket;
import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.BedrockServerSession;
import com.nukkitx.protocol.bedrock.data.*; 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 com.nukkitx.protocol.bedrock.packet.*;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.EventLoop; 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.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@ -81,6 +87,7 @@ import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.Setter; import lombok.Setter;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.common.value.qual.IntRange; import org.checkerframework.common.value.qual.IntRange;
import org.geysermc.common.PlatformType; import org.geysermc.common.PlatformType;
import org.geysermc.cumulus.form.Form; 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.PlayerInventory;
import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.CollisionManager;
import org.geysermc.geyser.network.netty.LocalSession; 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.skin.FloodgateSkinUploader;
import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.*; import org.geysermc.geyser.util.*;
@ -124,6 +133,7 @@ import java.net.ConnectException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
@ -318,12 +328,15 @@ public class GeyserSession implements GeyserConnection, CommandSender {
*/ */
@Setter @Setter
private String dimension = DimensionUtils.OVERWORLD; private String dimension = DimensionUtils.OVERWORLD;
/** @MonotonicNonNull
* Whether piglins and hoglins are safe from conversion in this dimension.
* This controls if they have the shaking effect applied in the dimension.
*/
@Setter @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 @Setter
private int breakingBlock; private int breakingBlock;
@ -480,15 +493,6 @@ public class GeyserSession implements GeyserConnection, CommandSender {
@Setter @Setter
private boolean thunder = false; 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. * 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. * 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) { if (geyser.getBootstrap().getSocketAddress() != null) {
// We're going to connect through the JVM and not through TCP // We're going to connect through the JVM and not through TCP
downstream = new LocalSession(this.remoteAddress, this.remotePort, 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 { } else {
downstream = new TcpClientSession(this.remoteAddress, this.remotePort, this.protocol); downstream = new TcpClientSession(this.remoteAddress, this.remotePort, this.protocol);
disableSrvResolving(); disableSrvResolving();
@ -1012,7 +1017,7 @@ public class GeyserSession implements GeyserConnection, CommandSender {
setDaylightCycle(true); setDaylightCycle(true);
} }
downstream.connect(); downstream.connect(false);
} }
public void disconnect(String reason) { public void disconnect(String reason) {
@ -1261,9 +1266,9 @@ public class GeyserSession implements GeyserConnection, CommandSender {
ServerboundUseItemPacket useItemPacket; ServerboundUseItemPacket useItemPacket;
if (playerInventory.getItemInHand().getJavaId() == shield.getJavaId()) { 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()) { } else if (playerInventory.getOffhand().getJavaId() == shield.getJavaId()) {
useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND); useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, getNextSequence());
} else { } else {
// No blocking // No blocking
return false; return false;
@ -1292,7 +1297,7 @@ public class GeyserSession implements GeyserConnection, CommandSender {
private boolean disableBlocking() { private boolean disableBlocking() {
if (playerEntity.getFlag(EntityFlag.BLOCKING)) { if (playerEntity.getFlag(EntityFlag.BLOCKING)) {
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM,
BlockUtils.POSITION_ZERO, Direction.DOWN); Vector3i.ZERO, Direction.DOWN, getNextSequence());
sendDownstreamPacket(releaseItemPacket); sendDownstreamPacket(releaseItemPacket);
playerEntity.setFlag(EntityFlag.BLOCKING, false); playerEntity.setFlag(EntityFlag.BLOCKING, false);
return true; return true;
@ -1358,7 +1363,21 @@ public class GeyserSession implements GeyserConnection, CommandSender {
@Override @Override
public String getLocale() { public String getLocale() {
return clientData.getLanguageCode(); 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) { public void setServerRenderDistance(int renderDistance) {
renderDistance = GenericMath.ceil(++renderDistance * MathUtils.SQRT_OF_TWO); //square to circle 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.setInventoriesServerAuthoritative(true);
startGamePacket.setServerEngine(""); // Do we want to fill this in? startGamePacket.setServerEngine(""); // Do we want to fill this in?
startGamePacket.setPlayerPropertyData(NbtMap.EMPTY);
startGamePacket.setWorldTemplateId(UUID.randomUUID());
SyncedPlayerMovementSettings settings = new SyncedPlayerMovementSettings(); SyncedPlayerMovementSettings settings = new SyncedPlayerMovementSettings();
settings.setMovementMode(AuthoritativeMovementMode.CLIENT); settings.setMovementMode(AuthoritativeMovementMode.CLIENT);
settings.setRewindHistorySize(0); settings.setRewindHistorySize(0);
@ -1653,6 +1675,10 @@ public class GeyserSession implements GeyserConnection, CommandSender {
sendDownstreamPacket(clientSettingsPacket); sendDownstreamPacket(clientSettingsPacket);
} }
public int getNextSequence() {
return 0;
}
/** /**
* Used for updating statistic values since we only get changes from the server * 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); packet.setExtraData(-1);
sendUpstreamPacket(packet); 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.text.MinecraftLocale;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -75,33 +76,20 @@ public class AdvancementsCache {
.translator(MinecraftLocale::getLocaleString, session.getLocale()) .translator(MinecraftLocale::getLocaleString, session.getLocale())
.title("gui.advancements"); .title("gui.advancements");
boolean hasAdvancements = false; List<String> rootAdvancementIds = new ArrayList<>();
for (Map.Entry<String, GeyserAdvancement> advancement : storedAdvancements.entrySet()) { for (Map.Entry<String, GeyserAdvancement> advancement : storedAdvancements.entrySet()) {
if (advancement.getValue().getParentId() == null) { // No parent means this is a root advancement 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())); builder.button(MessageTranslator.convertMessage(advancement.getValue().getDisplayData().getTitle(), session.getLocale()));
rootAdvancementIds.add(advancement.getKey());
} }
} }
if (!hasAdvancements) { if (rootAdvancementIds.isEmpty()) {
builder.content("advancements.empty"); builder.content("advancements.empty");
} }
builder.validResultHandler((response) -> { builder.validResultHandler((response) -> {
String id = ""; String id = rootAdvancementIds.get(response.clickedButtonId());
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++;
}
}
}
if (!id.equals("")) { if (!id.equals("")) {
if (id.equals(currentAdvancementCategoryId)) { if (id.equals(currentAdvancementCategoryId)) {
// The server thinks we are already on this tab // The server thinks we are already on this tab
@ -130,12 +118,16 @@ public class AdvancementsCache {
.title(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getTitle(), language)) .title(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getTitle(), language))
.content(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getDescription(), language)); .content(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getDescription(), language));
List<GeyserAdvancement> visibleAdvancements = new ArrayList<>();
if (currentAdvancementCategoryId != null) { if (currentAdvancementCategoryId != null) {
for (GeyserAdvancement advancement : storedAdvancements.values()) { 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))) { if (advancement.getParentId() != null && currentAdvancementCategoryId.equals(advancement.getRootId(this))) {
boolean color = isEarned(advancement) || !advancement.getDisplayData().isShowToast(); String color = earned ? advancement.getDisplayColor() : "";
builder.button((color ? ChatColor.DARK_GREEN : "") + MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()) + '\n'); builder.button(color + MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()) + '\n');
visibleAdvancements.add(advancement);
} }
} }
} }
@ -148,22 +140,8 @@ public class AdvancementsCache {
session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket());
}).validResultHandler((response) -> { }).validResultHandler((response) -> {
GeyserAdvancement advancement = null; if (response.getClickedButtonId() < visibleAdvancements.size()) {
int advancementIndex = 0; GeyserAdvancement advancement = visibleAdvancements.get(response.clickedButtonId());
// 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) {
buildAndShowInfoForm(advancement); buildAndShowInfoForm(advancement);
} else { } else {
buildAndShowMenuForm(); 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.session.GeyserSession;
import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.InventoryUtils;
import java.util.OptionalInt;
public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator { public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator {
public BeaconInventoryTranslator() { public BeaconInventoryTranslator() {
super(1, new BlockInventoryHolder("minecraft:beacon", com.nukkitx.protocol.bedrock.data.inventory.ContainerType.BEACON) { 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) { public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
// Input a beacon payment // Input a beacon payment
BeaconPaymentStackRequestActionData beaconPayment = (BeaconPaymentStackRequestActionData) request.getActions()[0]; 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); session.sendDownstreamPacket(packet);
return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet()));
} }
private OptionalInt toJava(int effectChoice) {
return effectChoice == -1 ? OptionalInt.empty() : OptionalInt.of(effectChoice);
}
@Override @Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.BEACON_PAYMENT) { 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.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData;
import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket;
import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket; 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.type.Entity;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.Inventory;
@ -140,10 +139,6 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
@Override @Override
public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { 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. // 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 // 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. // store a map of net ID to trade index on our end.
@ -153,12 +148,6 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
@Override @Override
public ItemStackResponsePacket.Response translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { 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 // 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 // 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. // 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.BitArrayVersion;
import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.util.JavaCodecEntry;
import org.geysermc.geyser.util.MathUtils; import org.geysermc.geyser.util.MathUtils;
// Array index formula by https://wiki.vg/Chunk_Format // Array index formula by https://wiki.vg/Chunk_Format
@ -55,27 +56,26 @@ public class BiomeTranslator {
ListTag serverBiomes = worldGen.get("value"); ListTag serverBiomes = worldGen.get("value");
session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(serverBiomes.size())); session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(serverBiomes.size()));
for (Tag tag : serverBiomes) { for (CompoundTag biomeTag : JavaCodecEntry.iterateAsTag(worldGen)) {
CompoundTag biomeTag = (CompoundTag) tag;
String javaIdentifier = ((StringTag) biomeTag.get("name")).getValue(); 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(); int javaId = ((IntTag) biomeTag.get("id")).getValue();
if (bedrockId == -1) { // TODO - the category tag no longer exists - find a better replacement option
// There is no matching Bedrock variation for this biome; let's set the closest match based on biome category // if (bedrockId == -1) {
String category = ((StringTag) ((CompoundTag) biomeTag.get("element")).get("category")).getValue(); // // There is no matching Bedrock variation for this biome; let's set the closest match based on biome category
String replacementBiome = switch (category) { // String category = ((StringTag) ((CompoundTag) biomeTag.get("element")).get("category")).getValue();
case "extreme_hills" -> "minecraft:mountains"; // String replacementBiome = switch (category) {
case "icy" -> "minecraft:ice_spikes"; // case "extreme_hills" -> "minecraft:mountains";
case "mesa" -> "minecraft:badlands"; // case "icy" -> "minecraft:ice_spikes";
case "mushroom" -> "minecraft:mushroom_fields"; // case "mesa" -> "minecraft:badlands";
case "nether" -> "minecraft:nether_wastes"; // case "mushroom" -> "minecraft:mushroom_fields";
default -> "minecraft:ocean"; // Typically ID 0 so a good default // case "nether" -> "minecraft:nether_wastes";
case "taiga", "jungle", "plains", "savanna", "the_end", "beach", "ocean", "desert", "river", "swamp" -> "minecraft:" + category; // 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); // };
} // bedrockId = Registries.BIOME_IDENTIFIERS.get().getInt(replacementBiome);
// }
// When we see the Java ID, we should instead apply the Bedrock ID // When we see the Java ID, we should instead apply the Bedrock ID
biomeTranslations.put(javaId, bedrockId); biomeTranslations.put(javaId, bedrockId);

View file

@ -40,7 +40,7 @@ public record SoundEventEventTranslator(SoundEvent soundEvent,
levelSoundEvent.setIdentifier(identifier); levelSoundEvent.setIdentifier(identifier);
levelSoundEvent.setExtraData(extraData); levelSoundEvent.setExtraData(extraData);
levelSoundEvent.setRelativeVolumeDisabled(packet.isBroadcast()); 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); levelSoundEvent.setBabySound(false);
session.sendUpstreamPacket(levelSoundEvent); session.sendUpstreamPacket(levelSoundEvent);
} }

View file

@ -25,12 +25,11 @@
package org.geysermc.geyser.translator.protocol.bedrock; 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.inventory.ServerboundSetJigsawBlockPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket; 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.nbt.NbtMap;
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; 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.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
@ -45,16 +44,8 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
String id = tag.getString("id"); String id = tag.getString("id");
if (id.equals("Sign")) { if (id.equals("Sign")) {
String text = tag.getString("Text"); 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 // Note: as of 1.18.30, only one packet is sent from Bedrock when the sign is finished.
// 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 // Previous versions did not have this behavior.
// 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
StringBuilder newMessage = new StringBuilder(); StringBuilder newMessage = new StringBuilder();
// While Bedrock's sign lines are one string, Java's is an array of each line // 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) // (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 // Put the final line on since it isn't done in the for loop
if (iterator < lines.length) lines[iterator] = newMessage.toString(); if (iterator < lines.length) lines[iterator] = newMessage.toString();
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); ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines);
session.sendDownstreamPacket(signUpdatePacket); 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")) { } else if (id.equals("JigsawBlock")) {
// Client has just sent a jigsaw block update // 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 name = tag.getString("name");
String target = tag.getString("target"); String target = tag.getString("target");
String pool = tag.getString("target_pool"); String pool = tag.getString("target_pool");

View file

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

View file

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

View file

@ -52,7 +52,7 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator<EntityP
// Get the corresponding item // Get the corresponding item
String itemName; String itemName;
switch (entity.getDefinition().entityType()) { switch (entity.getDefinition().entityType()) {
case BOAT -> { case BOAT, CHEST_BOAT -> {
// Include type of boat in the name // Include type of boat in the name
int variant = ((BoatEntity) entity).getVariant(); int variant = ((BoatEntity) entity).getVariant();
String typeOfBoat = switch (variant) { String typeOfBoat = switch (variant) {
@ -61,9 +61,10 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator<EntityP
case 3 -> "jungle"; case 3 -> "jungle";
case 4 -> "acacia"; case 4 -> "acacia";
case 5 -> "dark_oak"; case 5 -> "dark_oak";
case 6 -> "mangrove";
default -> "oak"; default -> "oak";
}; };
itemName = typeOfBoat + "_boat"; itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT);
} }
case LEASH_KNOT -> itemName = "lead"; case LEASH_KNOT -> itemName = "lead";
case CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART, TNT_MINECART -> 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; 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.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.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; 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( ServerboundPlayerActionPacket dropPacket = new ServerboundPlayerActionPacket(
dropAll ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM, dropAll ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM,
BlockUtils.POSITION_ZERO, Vector3i.ZERO,
Direction.DOWN Direction.DOWN,
session.getNextSequence()
); );
session.sendDownstreamPacket(dropPacket); session.sendDownstreamPacket(dropPacket);
@ -256,24 +256,25 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (blockState == BlockStateValues.JAVA_WATER_ID) { if (blockState == BlockStateValues.JAVA_WATER_ID) {
// Otherwise causes multiple mobs to spawn - just send a use item packet // Otherwise causes multiple mobs to spawn - just send a use item packet
// TODO when we fix mobile bucket rotation, use it for this, too // 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); session.sendDownstreamPacket(itemPacket);
break; break;
} }
} }
ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket( ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket(
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), packet.getBlockPosition(),
Direction.VALUES[packet.getBlockFace()], Direction.VALUES[packet.getBlockFace()],
Hand.MAIN_HAND, Hand.MAIN_HAND,
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(), packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
false); false,
session.getNextSequence());
session.sendDownstreamPacket(blockPacket); session.sendDownstreamPacket(blockPacket);
if (packet.getItemInHand() != null) { if (packet.getItemInHand() != null) {
// Otherwise boats will not be able to be placed in survival and buckets won't work on mobile // 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())) { 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); session.sendDownstreamPacket(itemPacket);
} else if (session.getItemMappings().getBucketIds().contains(packet.getItemInHand().getId())) { } 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 // 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 // Delay the interaction in case the client doesn't intend to actually use the bucket
// See BedrockActionTranslator.java // See BedrockActionTranslator.java
session.setBucketScheduledFuture(session.scheduleInEventLoop(() -> { session.setBucketScheduledFuture(session.scheduleInEventLoop(() -> {
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND); ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence());
session.sendDownstreamPacket(itemPacket); session.sendDownstreamPacket(itemPacket);
}, 5, TimeUnit.MILLISECONDS)); }, 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); session.sendDownstreamPacket(useItemPacket);
List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots(); 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; 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, packet.getBlockPosition(), Direction.VALUES[packet.getBlockFace()], session.getNextSequence());
ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, pos, Direction.VALUES[packet.getBlockFace()]);
session.sendDownstreamPacket(breakPacket); session.sendDownstreamPacket(breakPacket);
} }
} }
@ -426,8 +426,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
case ITEM_RELEASE: case ITEM_RELEASE:
if (packet.getActionType() == 0) { if (packet.getActionType() == 0) {
// Followed to the Minecraft Protocol specification outlined at wiki.vg // Followed to the Minecraft Protocol specification outlined at wiki.vg
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, BlockUtils.POSITION_ZERO, ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO,
Direction.DOWN); Direction.DOWN, session.getNextSequence());
session.sendDownstreamPacket(releaseItemPacket); session.sendDownstreamPacket(releaseItemPacket);
} }
break; break;

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.translator.protocol.bedrock; 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.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; 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 // Emulate an interact packet
ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket( ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket(
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), packet.getBlockPosition(),
Direction.DOWN, Direction.DOWN,
Hand.MAIN_HAND, Hand.MAIN_HAND,
0, 0, 0, // Java doesn't care about these when dealing with a lectern 0, 0, 0, // Java doesn't care about these when dealing with a lectern
false); false,
session.getNextSequence());
session.sendDownstreamPacket(blockPacket); session.sendDownstreamPacket(blockPacket);
} else { } else {
// Bedrock wants to either move a page or exit // 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 // Activate shield since we are already sneaking
// (No need to send a release item packet - Java doesn't do this when swapping items) // (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 // 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); 50, TimeUnit.MILLISECONDS);
} }

View file

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

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.translator.protocol.bedrock.entity.player; 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.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.*; import com.github.steveice10.mc.protocol.data.game.entity.player.*;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
@ -129,8 +128,8 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
session.setSprinting(false); session.setSprinting(false);
break; break;
case DROP_ITEM: case DROP_ITEM:
Position position = new Position(vector.getX(), vector.getY(), vector.getZ()); ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, position, Direction.VALUES[packet.getFace()]); vector, Direction.VALUES[packet.getFace()], session.getNextSequence());
session.sendDownstreamPacket(dropItemPacket); session.sendDownstreamPacket(dropItemPacket);
break; break;
case STOP_SLEEP: case STOP_SLEEP:
@ -163,16 +162,16 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
int blockUp = session.getGeyser().getWorldManager().getBlockAt(session, fireBlockPos); int blockUp = session.getGeyser().getWorldManager().getBlockAt(session, fireBlockPos);
String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().get(blockUp); String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().get(blockUp);
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) { if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(), ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos,
fireBlockPos.getY(), fireBlockPos.getZ()), Direction.VALUES[packet.getFace()]); Direction.VALUES[packet.getFace()], session.getNextSequence());
session.sendDownstreamPacket(startBreakingPacket); session.sendDownstreamPacket(startBreakingPacket);
if (session.getGameMode() == GameMode.CREATIVE) { if (session.getGameMode() == GameMode.CREATIVE) {
break; break;
} }
} }
position = new Position(vector.getX(), vector.getY(), vector.getZ()); ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING,
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, position, Direction.VALUES[packet.getFace()]); vector, Direction.VALUES[packet.getFace()], session.getNextSequence());
session.sendDownstreamPacket(startBreakingPacket); session.sendDownstreamPacket(startBreakingPacket);
break; break;
case CONTINUE_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, vector, Direction.DOWN, session.getNextSequence());
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, position, Direction.DOWN);
session.sendDownstreamPacket(abortBreakingPacket); session.sendDownstreamPacket(abortBreakingPacket);
LevelEventPacket stopBreak = new LevelEventPacket(); LevelEventPacket stopBreak = new LevelEventPacket();
stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK); 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.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; 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 com.nukkitx.protocol.bedrock.packet.EmotePacket;
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption; import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.BlockUtils;
@Translator(packet = EmotePacket.class) @Translator(packet = EmotePacket.class)
public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> { public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> {
@ -43,8 +43,8 @@ public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> {
public void translate(GeyserSession session, EmotePacket packet) { public void translate(GeyserSession session, EmotePacket packet) {
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) { if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) {
// Activate the workaround - we should trigger the offhand now // Activate the workaround - we should trigger the offhand now
ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO, ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
Direction.DOWN); Direction.DOWN, session.getNextSequence());
session.sendDownstreamPacket(swapHandsPacket); session.sendDownstreamPacket(swapHandsPacket);
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) { 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.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; 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.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.ServerboundInteractPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; 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.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
import com.nukkitx.protocol.bedrock.packet.InteractPacket; import com.nukkitx.protocol.bedrock.packet.InteractPacket;
@ -96,12 +96,10 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
case OPEN_INVENTORY: case OPEN_INVENTORY:
if (session.getOpenInventory() == null) { if (session.getOpenInventory() == null) {
Entity ridingEntity = session.getPlayerEntity().getVehicle(); Entity ridingEntity = session.getPlayerEntity().getVehicle();
if (ridingEntity instanceof AbstractHorseEntity) { if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) {
if (ridingEntity.getFlag(EntityFlag.TAMED)) { // This mob has an inventory of its own that we should open instead.
// We should request to open the horse inventory instead ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY);
ServerboundPlayerCommandPacket openHorseWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_HORSE_INVENTORY); session.sendDownstreamPacket(openVehicleWindowPacket);
session.sendDownstreamPacket(openHorseWindowPacket);
}
} else { } else {
session.setOpenInventory(session.getPlayerInventory()); session.setOpenInventory(session.getPlayerInventory());

View file

@ -222,7 +222,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
case BLOCK_POS -> CommandParam.BLOCK_POSITION; case BLOCK_POS -> CommandParam.BLOCK_POSITION;
case COLUMN_POS, VEC3 -> CommandParam.POSITION; case COLUMN_POS, VEC3 -> CommandParam.POSITION;
case MESSAGE -> CommandParam.MESSAGE; 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 RESOURCE_LOCATION, FUNCTION -> CommandParam.FILE_PATH;
case BOOL -> ENUM_BOOLEAN; case BOOL -> ENUM_BOOLEAN;
case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc 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. * 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 @Getter
@ -317,15 +317,21 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
Object mappedType = mapCommandType(session, paramNode); Object mappedType = mapCommandType(session, paramNode);
CommandEnumData enumData = null; CommandEnumData enumData = null;
CommandParam type = null; CommandParam type = null;
boolean optional = this.paramNode.isExecutable();
if (mappedType instanceof String[]) { if (mappedType instanceof String[]) {
enumData = new CommandEnumData(paramNode.getParser().name().toLowerCase(), (String[]) mappedType, false); enumData = new CommandEnumData(paramNode.getParser().name().toLowerCase(), (String[]) mappedType, false);
} else { } else {
type = (CommandParam) mappedType; 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: // IF enumData != null:
// In game, this will show up like <paramNode.getName(): enumData.getName()> // In game, this will show up like <paramNode.getName(): enumData.getName()>
// So if paramNode.getName() == "value" and enumData.getName() == "bool": <value: bool> // 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; 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.clientbound.ClientboundLoginPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; 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.GameRuleData;
import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.data.PlayerPermission;
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket;
import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; 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.GeyserSession;
import org.geysermc.geyser.session.auth.AuthType; 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.level.BiomeTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.JavaCodecEntry;
import org.geysermc.geyser.util.PluginMessageUtils; import org.geysermc.geyser.util.PluginMessageUtils;
import java.util.Map;
@Translator(packet = ClientboundLoginPacket.class) @Translator(packet = ClientboundLoginPacket.class)
public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> { public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> {
@Override @Override
public void translate(GeyserSession session, ClientboundLoginPacket packet) { public void translate(GeyserSession session, ClientboundLoginPacket packet) {
PlayerEntity entity = session.getPlayerEntity(); SessionPlayerEntity entity = session.getPlayerEntity();
entity.setEntityId(packet.getEntityId()); 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 // If the player is already initialized and a join game packet is sent, they
// are swapping servers // are swapping servers
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
if (session.isSpawned()) { if (session.isSpawned()) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension); String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension());
DimensionUtils.switchDimension(session, fakeDim); DimensionUtils.switchDimension(session, fakeDim);
session.getWorldCache().removeScoreboard(); session.getWorldCache().removeScoreboard();
} }
session.setWorldName(packet.getWorldName()); session.setWorldName(packet.getWorldName());
BiomeTranslator.loadServerBiomes(session, packet.getDimensionCodec()); BiomeTranslator.loadServerBiomes(session, packet.getRegistry());
session.getTagCache().clear(); session.getTagCache().clear();
session.setGameMode(packet.getGameMode()); session.setGameMode(packet.getGameMode());
String newDimension = packet.getDimension();
boolean needsSpawnPacket = !session.isSentSpawnPacket(); boolean needsSpawnPacket = !session.isSentSpawnPacket();
if (needsSpawnPacket) { if (needsSpawnPacket) {
// The player has yet to spawn so let's do that using some of the information in this Java packet // 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); session.sendUpstreamPacket(playerGameTypePacket);
} }
entity.setLastDeathPosition(packet.getLastDeathPos());
entity.updateBedrockMetadata(); entity.updateBedrockMetadata();
// Send if client should show respawn screen // Send if client should show respawn screen
@ -113,6 +146,7 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
session.sendFog("minecraft:fog_hell"); 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.attribute.GeyserAttributeType;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.session.GeyserSession; 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.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; 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.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.DimensionUtils;
@ -55,6 +55,9 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
session.setOpenInventory(null); session.setOpenInventory(null);
session.setClosingInventory(false); session.setClosingInventory(false);
entity.setLastDeathPosition(packet.getLastDeathPos());
entity.updateBedrockMetadata();
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(packet.getGamemode().ordinal()); playerGameTypePacket.setGamemode(packet.getGamemode().ordinal());
session.sendUpstreamPacket(playerGameTypePacket); session.sendUpstreamPacket(playerGameTypePacket);
@ -78,7 +81,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
session.setThunder(false); session.setThunder(false);
} }
String newDimension = DimensionUtils.getNewDimension(packet.getDimension()); String newDimension = packet.getDimension();
if (!session.getDimension().equals(newDimension) || !packet.getWorldName().equals(session.getWorldName())) { 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 // 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) if (!packet.getWorldName().equals(session.getWorldName()) && (session.getDimension().equals(newDimension)
@ -90,8 +93,9 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
} }
session.setWorldName(packet.getWorldName()); session.setWorldName(packet.getWorldName());
DimensionUtils.switchDimension(session, newDimension); 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; 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 com.nukkitx.protocol.bedrock.packet.TextPacket;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
@Translator(packet = ClientboundChatPacket.class) @Translator(packet = ClientboundSystemChatPacket.class)
public class JavaChatTranslator extends PacketTranslator<ClientboundChatPacket> { public class JavaSystemChatTranslator extends PacketTranslator<ClientboundSystemChatPacket> {
@Override @Override
public void translate(GeyserSession session, ClientboundChatPacket packet) { public void translate(GeyserSession session, ClientboundSystemChatPacket packet) {
TextPacket textPacket = new TextPacket(); TextPacket textPacket = new TextPacket();
textPacket.setPlatformChatId(""); textPacket.setPlatformChatId("");
textPacket.setSourceName(""); textPacket.setSourceName("");
textPacket.setXuid(session.getAuthData().xuid()); textPacket.setXuid(session.getAuthData().xuid());
// TODO new types
textPacket.setType(switch (packet.getType()) { textPacket.setType(switch (packet.getType()) {
case CHAT -> TextPacket.Type.CHAT; case CHAT -> TextPacket.Type.CHAT;
case SYSTEM -> TextPacket.Type.SYSTEM; case SYSTEM -> TextPacket.Type.SYSTEM;
case NOTIFICATION -> TextPacket.Type.TIP; case GAME_INFO -> TextPacket.Type.TIP;
default -> TextPacket.Type.RAW; default -> TextPacket.Type.RAW;
}); });
textPacket.setNeedsTranslation(false); textPacket.setNeedsTranslation(false);
textPacket.setMessage(MessageTranslator.convertMessage(packet.getMessage(), session.getLocale())); textPacket.setMessage(MessageTranslator.convertMessage(packet.getContent(), session.getLocale()));
session.sendUpstreamPacket(textPacket); 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.data.game.advancement.Advancement;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateAdvancementsPacket; 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.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
@ -36,7 +36,7 @@ import org.geysermc.geyser.session.cache.AdvancementsCache;
import org.geysermc.geyser.level.GeyserAdvancement; import org.geysermc.geyser.level.GeyserAdvancement;
import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.MinecraftLocale;
import java.util.Map; import java.util.Locale;
@Translator(packet = ClientboundUpdateAdvancementsPacket.class) @Translator(packet = ClientboundUpdateAdvancementsPacket.class)
public class JavaUpdateAdvancementsTranslator extends PacketTranslator<ClientboundUpdateAdvancementsPacket> { public class JavaUpdateAdvancementsTranslator extends PacketTranslator<ClientboundUpdateAdvancementsPacket> {
@ -56,48 +56,39 @@ public class JavaUpdateAdvancementsTranslator extends PacketTranslator<Clientbou
advancementsCache.getStoredAdvancementProgress().putAll(packet.getProgress()); advancementsCache.getStoredAdvancementProgress().putAll(packet.getProgress());
sendToolbarAdvancementUpdates(session, packet);
// Adds advancements to the player's stored advancements when advancements are sent // Adds advancements to the player's stored advancements when advancements are sent
for (Advancement advancement : packet.getAdvancements()) { 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); GeyserAdvancement geyserAdvancement = GeyserAdvancement.from(advancement);
advancementsCache.getStoredAdvancements().put(advancement.getId(), geyserAdvancement); advancementsCache.getStoredAdvancements().put(advancement.getId(), geyserAdvancement);
} else { } else {
advancementsCache.getStoredAdvancements().remove(advancement.getId()); advancementsCache.getStoredAdvancements().remove(advancement.getId());
} }
} }
sendAdvancementToasts(session, packet);
} }
/** /**
* Handle all advancements progress updates * Handle all advancements progress updates
*/ */
public void sendToolbarAdvancementUpdates(GeyserSession session, ClientboundUpdateAdvancementsPacket packet) { public void sendAdvancementToasts(GeyserSession session, ClientboundUpdateAdvancementsPacket packet) {
if (packet.isReset()) { if (packet.isReset()) {
// Advancements are being cleared, so they can't be granted // Advancements are being cleared, so they can't be granted
return; return;
} }
for (Map.Entry<String, Map<String, Long>> progress : packet.getProgress().entrySet()) { for (String advancementId : packet.getProgress().keySet()) {
GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(progress.getKey()); GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(advancementId);
if (advancement != null && advancement.getDisplayData() != null) { if (advancement != null && advancement.getDisplayData() != null) {
if (session.getAdvancementsCache().isEarned(advancement)) { if (advancement.getDisplayData().isShowToast() && session.getAdvancementsCache().isEarned(advancement)) {
// Java uses some pink color for toast challenge completes String frameType = advancement.getDisplayData().getFrameType().toString().toLowerCase(Locale.ROOT);
String color = advancement.getDisplayData().getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE ? String frameTitle = advancement.getDisplayColor() + MinecraftLocale.getLocaleString("advancements.toast." + frameType, session.getLocale());
"§d" : "§a";
String advancementName = MessageTranslator.convertMessage(advancement.getDisplayData().getTitle(), session.getLocale()); String advancementName = MessageTranslator.convertMessage(advancement.getDisplayData().getTitle(), session.getLocale());
// Send an action bar message stating they earned an achievement ToastRequestPacket toastRequestPacket = new ToastRequestPacket();
// Sent for instances where broadcasting advancements through chat are disabled toastRequestPacket.setTitle(frameTitle);
SetTitlePacket titlePacket = new SetTitlePacket(); toastRequestPacket.setContent(advancementName);
titlePacket.setText(color + "[" + MinecraftLocale.getLocaleString("advancements.toast." + session.sendUpstreamPacket(toastRequestPacket);
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);
} }
} }
} }

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

View file

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

View file

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

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