Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.netty.channel.EventLoop;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
Expand Down Expand Up @@ -526,19 +527,26 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
/**
* Stores all Java recipes by ID, and matches them to all possible Bedrock recipe identifiers.
*/
private final Int2ObjectMap<List<String>> javaToBedrockRecipeIds;
private final Int2ObjectMap<List<String>> javaToBedrockRecipeIds = new Int2ObjectOpenHashMap<>();

private final Int2ObjectMap<GeyserRecipe> craftingRecipes;
private final Int2ObjectMap<GeyserRecipe> craftingRecipes = new Int2ObjectOpenHashMap<>();
@Setter
private Pair<CraftingRecipeData, GeyserRecipe> lastCreatedRecipe = null; // TODO try to prevent sending duplicate recipes
private final AtomicInteger lastRecipeNetId;

/**
* Used to minimize the amount of recipes sent to the client, as the packet is quite heavy
* when sent in rapid succession
*/
@Setter
private boolean cleanRecipesRequired = true;

/**
* Saves a list of all stonecutter recipes, for use in a stonecutter inventory.
* The key is the Bedrock recipe net ID; the values are their respective output and button ID.
*/
@Setter
private Int2ObjectMap<GeyserStonecutterData> stonecutterRecipes;
private Int2ObjectMap<GeyserStonecutterData> stonecutterRecipes = Int2ObjectMaps.emptyMap();
private final List<GeyserSmithingRecipe> smithingRecipes = new ArrayList<>();

/**
Expand Down Expand Up @@ -856,8 +864,6 @@ public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSessio

this.playerInventoryHolder = new InventoryHolder<>(this, new PlayerInventory(this), InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR);
this.inventoryHolder = null;
this.craftingRecipes = new Int2ObjectOpenHashMap<>();
this.javaToBedrockRecipeIds = new Int2ObjectOpenHashMap<>();
this.lastRecipeNetId = new AtomicInteger(InventoryUtils.LAST_RECIPE_NET_ID + 1);

this.spawned = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

package org.geysermc.geyser.translator.protocol.java;

import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket;
import org.geysermc.geyser.registry.Registries;
Expand Down Expand Up @@ -63,19 +64,18 @@ public void translate(GeyserSession session, ClientboundFinishConfigurationPacke
craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(session.getUpstream().getProtocolVersion()));
if (session.isSentSpawnPacket()) {
session.getUpstream().sendPacket(craftingDataPacket);
// TODO proper fix to check if we've been online - in online mode (with auth screen),
// recipes are not yet known
if (session.getStonecutterRecipes() != null) {
session.getLastRecipeNetId().set(InventoryUtils.LAST_RECIPE_NET_ID + 1);
session.getCraftingRecipes().clear();
session.getJavaToBedrockRecipeIds().clear();
session.getSmithingRecipes().clear();
session.getStonecutterRecipes().clear();
}
session.getLastRecipeNetId().set(InventoryUtils.LAST_RECIPE_NET_ID + 1);
session.getCraftingRecipes().clear();
session.getJavaToBedrockRecipeIds().clear();
session.getSmithingRecipes().clear();
session.setStonecutterRecipes(Int2ObjectMaps.emptyMap());
} else {
session.getUpstream().queuePostStartGamePacket(craftingDataPacket);
}

// We can avoid re-sending potion mixes / crafting recipes again in the JavaUpdateRecipesTranslator
session.setCleanRecipesRequired(false);

// while ClientboundLoginPacket holds the level, it doesn't hold the scoreboard.
// The ClientboundStartConfigurationPacket indirectly removes the old scoreboard,
// and this packet indirectly creates the new one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,24 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
public void translate(GeyserSession session, ClientboundUpdateRecipesPacket packet) {
int netId = session.getLastRecipeNetId().get();
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
craftingDataPacket.setCleanRecipes(true);
craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES);
craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(session.getUpstream().getProtocolVersion()));
for (GeyserRecipe recipe : session.getCraftingRecipes().values()) {
craftingDataPacket.getCraftingData().addAll(recipe.asRecipeData(session));
}
for (GeyserSmithingRecipe recipe : session.getSmithingRecipes()) {
craftingDataPacket.getCraftingData().addAll(recipe.asRecipeData(session));
// See JavaFinishConfigurationTranslator - avoid re-sending base recipe data in quick succession
if (session.isCleanRecipesRequired()) {
craftingDataPacket.setCleanRecipes(true);
craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES);
craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(session.getUpstream().getProtocolVersion()));

for (GeyserRecipe recipe : session.getCraftingRecipes().values()) {
craftingDataPacket.getCraftingData().addAll(recipe.asRecipeData(session));
}
for (GeyserSmithingRecipe recipe : session.getSmithingRecipes()) {
craftingDataPacket.getCraftingData().addAll(recipe.asRecipeData(session));
}
}

// As we now populate recipes that can differ,
// we need to ensure the next crafting packet resets the client's known recipes
session.setCleanRecipesRequired(true);

boolean oldSmithingTable;
int[] smithingBase = packet.getItemSets().get(SMITHING_BASE);
int[] smithingTemplate = packet.getItemSets().get(SMITHING_TEMPLATE);
Expand Down
Loading