Skip to content

Commit

Permalink
Fix some item interactions (#3083)
Browse files Browse the repository at this point in the history
* Remove Bedrock only banner patterns from the creative inventory

* Add sound for tadpole bucket

* Fix lily pad and frogspawn placing on mobile/single stacks

* Workaround? Fix? for bucket usage on mobile

* Simplify math and update position+rotation whenever ServerboundUseItemPacket is sent

* Rotate the player back after using an item and fix glass bottles

* ITEM_USE actionType 1 does not need the rotation fix

Increase delay for look back

* Add some checks

* Prevent buckets and spawn eggs from being unintentionally placed when interacting with special blocks

As of 1.19 Bedrock no longer sends a PlayerActionPacket with action=BLOCK_INTERACT. Bedrock now sends action=ITEM_USE_ON_START before and action=ITEM_USE_ON_STOP after using an item on a block. However, this is not useful as it is sent for all block interactions.

* Fix inventory transactions being rejected after restoreCorrectBlock

The held item's netId is always 0 in the InventoryTransactionPacket.

* Touch ups

* Fix lookAt for different poses and sneaking + cauldron + bucket interactions

Fix boat items being desynced when placing them very close to collision
Fix bottles being desynced when tapping above water

Resend the held item if we do encounter a desync

* Avoid getting blockstate twice and fix comment

* Use generated interaction data

* Fix glass bottles being double filled and phantom water bottles/water buckets

* Don't update the entire inventory on useItem

* Use Geyser's inventory copy for check

* Use ItemTranslator#getBedrockItemMapping to avoid NBT translation

* mappings

Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com>
  • Loading branch information
davchoo and Camotoy authored Jun 24, 2022
1 parent 6032733 commit 9ea2204
Show file tree
Hide file tree
Showing 13 changed files with 239 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,20 @@ public class StoredItemMappings {
private final ItemMapping banner;
private final ItemMapping barrier;
private final int bowl;
private final int bucket;
private final int chest;
private final ItemMapping compass;
private final ItemMapping crossbow;
private final ItemMapping enchantedBook;
private final ItemMapping fishingRod;
private final int flintAndSteel;
private final int frogspawn;
private final int glassBottle;
private final int goldenApple;
private final int goldIngot;
private final int ironIngot;
private final int lead;
private final int lilyPad;
private final ItemMapping milkBucket;
private final int nameTag;
private final ItemMapping powderSnowBucket;
Expand All @@ -70,16 +74,20 @@ public StoredItemMappings(Map<String, ItemMapping> itemMappings) {
this.banner = load(itemMappings, "white_banner"); // As of 1.17.10, all banners have the same Bedrock ID
this.barrier = load(itemMappings, "barrier");
this.bowl = load(itemMappings, "bowl").getJavaId();
this.bucket = load(itemMappings, "bucket").getBedrockId();
this.chest = load(itemMappings, "chest").getJavaId();
this.compass = load(itemMappings, "compass");
this.crossbow = load(itemMappings, "crossbow");
this.enchantedBook = load(itemMappings, "enchanted_book");
this.fishingRod = load(itemMappings, "fishing_rod");
this.flintAndSteel = load(itemMappings, "flint_and_steel").getJavaId();
this.frogspawn = load(itemMappings, "frogspawn").getBedrockId();
this.glassBottle = load(itemMappings, "glass_bottle").getBedrockId();
this.goldenApple = load(itemMappings, "golden_apple").getJavaId();
this.goldIngot = load(itemMappings, "gold_ingot").getJavaId();
this.ironIngot = load(itemMappings, "iron_ingot").getJavaId();
this.lead = load(itemMappings, "lead").getJavaId();
this.lilyPad = load(itemMappings, "lily_pad").getBedrockId();
this.milkBucket = load(itemMappings, "milk_bucket");
this.nameTag = load(itemMappings, "name_tag").getJavaId();
this.powderSnowBucket = load(itemMappings, "powder_snow_bucket");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
* Used for block entities if the Java block state contains Bedrock block information.
*/
public final class BlockStateValues {
private static final IntSet ALL_CAULDRONS = new IntOpenHashSet();
private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap();
private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap();
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
Expand Down Expand Up @@ -193,6 +194,9 @@ public static void storeBlockStateValues(String javaId, int javaBlockState, Json
return;
}

if (javaId.contains("cauldron")) {
ALL_CAULDRONS.add(javaBlockState);
}
if (javaId.contains("_cauldron") && !javaId.contains("water_")) {
NON_WATER_CAULDRONS.add(javaBlockState);
}
Expand Down Expand Up @@ -225,10 +229,19 @@ public static byte getBedColor(int state) {
*
* @return if this Java block state is a non-empty non-water cauldron
*/
public static boolean isCauldron(int state) {
public static boolean isNonWaterCauldron(int state) {
return NON_WATER_CAULDRONS.contains(state);
}

/**
* When using a bucket on a cauldron sending a ServerboundUseItemPacket can result in the liquid being placed.
*
* @return if this Java block state is a cauldron
*/
public static boolean isCauldron(int state) {
return ALL_CAULDRONS.contains(state);
}

/**
* The block state in Java and Bedrock both contain the conditional bit, however command block block entity tags
* in Bedrock need the conditional information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ public class BlockRegistries {
*/
public static final SimpleRegistry<IntSet> WATERLOGGED = SimpleRegistry.create(RegistryLoaders.empty(IntOpenHashSet::new));

/**
* A registry containing all blockstates which are always interactive.
*/
public static final SimpleRegistry<IntSet> INTERACTIVE = SimpleRegistry.create(RegistryLoaders.empty(IntOpenHashSet::new));

/**
* A registry containing all blockstates which are interactive if the player has the may build permission.
*/
public static final SimpleRegistry<IntSet> INTERACTIVE_MAY_BUILD = SimpleRegistry.create(RegistryLoaders.empty(IntOpenHashSet::new));

static {
BlockRegistryPopulator.populate();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package org.geysermc.geyser.registry.populator;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.ImmutableMap;
import com.nukkitx.nbt.*;
import com.nukkitx.protocol.bedrock.v527.Bedrock_v527;
Expand Down Expand Up @@ -355,6 +356,24 @@ private static void registerJavaBlocks() {
BlockRegistries.CLEAN_JAVA_IDENTIFIERS.set(cleanIdentifiers.toArray(new String[0]));

BLOCKS_JSON = blocksJson;

JsonNode blockInteractionsJson;
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("mappings/interactions.json")) {
blockInteractionsJson = GeyserImpl.JSON_MAPPER.readTree(stream);
} catch (Exception e) {
throw new AssertionError("Unable to load Java block interaction mappings", e);
}

BlockRegistries.INTERACTIVE.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("always_consumes")));
BlockRegistries.INTERACTIVE_MAY_BUILD.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("requires_may_build")));
}

private static IntSet toBlockStateSet(ArrayNode node) {
IntSet blockStateSet = new IntOpenHashSet(node.size());
for (JsonNode javaIdentifier : node) {
blockStateSet.add(BlockRegistries.JAVA_IDENTIFIERS.get().getInt(javaIdentifier.textValue()));
}
return blockStateSet;
}

private static NbtMap buildBedrockState(JsonNode node, int blockStateVersion, BiFunction<String, NbtMapBuilder, String> statesMapper) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ public static void populate() {
} else if (identifier.equals("minecraft:empty_map") && damage == 2) {
// Bedrock-only as its own item
continue;
} else if (identifier.equals("minecraft:bordure_indented_banner_pattern") || identifier.equals("minecraft:field_masoned_banner_pattern")) {
// Bedrock-only banner patterns
continue;
}
StartGamePacket.ItemEntry entry = entries.get(identifier);
int id = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,11 +433,10 @@ public class GeyserSession implements GeyserConnection, CommandSender {
private long lastInteractionTime;

/**
* Stores a future interaction to place a bucket. Will be cancelled if the client instead intended to
* interact with a block.
* Stores whether the player intended to place a bucket.
*/
@Setter
private ScheduledFuture<?> bucketScheduledFuture;
private boolean placedBucket;

/**
* Used to send a movement packet every three seconds if the player hasn't moved. Prevents timeouts when AFK in certain instances.
Expand Down Expand Up @@ -524,6 +523,12 @@ public class GeyserSession implements GeyserConnection, CommandSender {
*/
private ScheduledFuture<?> tickThread = null;

/**
* Used to return the player to their original rotation after using an item in BedrockInventoryTransactionTranslator
*/
@Setter
private ScheduledFuture<?> lookBackScheduledFuture = null;

private MinecraftProtocol protocol;

public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop eventLoop) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static NbtMap getTag(GeyserSession session, Vector3i position, int blockState) {
return FlowerPotBlockEntityTranslator.getTag(session, blockState, position);
} else if (PistonBlockEntityTranslator.isBlock(blockState)) {
return PistonBlockEntityTranslator.getTag(blockState, position);
} else if (BlockStateValues.isCauldron(blockState)) {
} else if (BlockStateValues.isNonWaterCauldron(blockState)) {
// As of 1.18.30: this is required to make rendering not look weird on chunk load (lava and snow cauldrons look dim)
return NbtMap.builder()
.putString("id", "Cauldron")
Expand Down
Loading

0 comments on commit 9ea2204

Please sign in to comment.