mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Fix smithing tables on pre-1.20 servers (#4056)
This commit is contained in:
parent
a99d2bcca8
commit
706d1b9627
7 changed files with 252 additions and 26 deletions
|
@ -45,11 +45,12 @@ public class StoredItemMappings {
|
||||||
private final ItemMapping barrier;
|
private final ItemMapping barrier;
|
||||||
private final ItemMapping compass;
|
private final ItemMapping compass;
|
||||||
private final ItemMapping crossbow;
|
private final ItemMapping crossbow;
|
||||||
|
private final ItemMapping egg;
|
||||||
private final ItemMapping glassBottle;
|
private final ItemMapping glassBottle;
|
||||||
private final ItemMapping milkBucket;
|
private final ItemMapping milkBucket;
|
||||||
private final ItemMapping powderSnowBucket;
|
private final ItemMapping powderSnowBucket;
|
||||||
private final ItemMapping egg;
|
|
||||||
private final ItemMapping shield;
|
private final ItemMapping shield;
|
||||||
|
private final ItemMapping upgradeTemplate;
|
||||||
private final ItemMapping wheat;
|
private final ItemMapping wheat;
|
||||||
private final ItemMapping writableBook;
|
private final ItemMapping writableBook;
|
||||||
|
|
||||||
|
@ -59,11 +60,12 @@ public class StoredItemMappings {
|
||||||
this.barrier = load(itemMappings, Items.BARRIER);
|
this.barrier = load(itemMappings, Items.BARRIER);
|
||||||
this.compass = load(itemMappings, Items.COMPASS);
|
this.compass = load(itemMappings, Items.COMPASS);
|
||||||
this.crossbow = load(itemMappings, Items.CROSSBOW);
|
this.crossbow = load(itemMappings, Items.CROSSBOW);
|
||||||
|
this.egg = load(itemMappings, Items.EGG);
|
||||||
this.glassBottle = load(itemMappings, Items.GLASS_BOTTLE);
|
this.glassBottle = load(itemMappings, Items.GLASS_BOTTLE);
|
||||||
this.milkBucket = load(itemMappings, Items.MILK_BUCKET);
|
this.milkBucket = load(itemMappings, Items.MILK_BUCKET);
|
||||||
this.powderSnowBucket = load(itemMappings, Items.POWDER_SNOW_BUCKET);
|
this.powderSnowBucket = load(itemMappings, Items.POWDER_SNOW_BUCKET);
|
||||||
this.egg = load(itemMappings, Items.EGG);
|
|
||||||
this.shield = load(itemMappings, Items.SHIELD);
|
this.shield = load(itemMappings, Items.SHIELD);
|
||||||
|
this.upgradeTemplate = load(itemMappings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE);
|
||||||
this.wheat = load(itemMappings, Items.WHEAT);
|
this.wheat = load(itemMappings, Items.WHEAT);
|
||||||
this.writableBook = load(itemMappings, Items.WRITABLE_BOOK);
|
this.writableBook = load(itemMappings, Items.WRITABLE_BOOK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
|
@ -39,7 +41,6 @@ import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.item.type.Item;
|
import org.geysermc.geyser.item.type.Item;
|
||||||
import org.geysermc.geyser.item.type.PotionItem;
|
import org.geysermc.geyser.item.type.PotionItem;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -77,7 +78,7 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
|
||||||
* @param itemStack the itemstack
|
* @param itemStack the itemstack
|
||||||
* @return an item entry from the given java edition identifier
|
* @return an item entry from the given java edition identifier
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@NonNull
|
||||||
public ItemMapping getMapping(ItemStack itemStack) {
|
public ItemMapping getMapping(ItemStack itemStack) {
|
||||||
return this.getMapping(itemStack.getId());
|
return this.getMapping(itemStack.getId());
|
||||||
}
|
}
|
||||||
|
@ -89,11 +90,12 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
|
||||||
* @param javaId the id
|
* @param javaId the id
|
||||||
* @return an item entry from the given java edition identifier
|
* @return an item entry from the given java edition identifier
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@NonNull
|
||||||
public ItemMapping getMapping(int javaId) {
|
public ItemMapping getMapping(int javaId) {
|
||||||
return javaId >= 0 && javaId < this.items.length ? this.items[javaId] : ItemMapping.AIR;
|
return javaId >= 0 && javaId < this.items.length ? this.items[javaId] : ItemMapping.AIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public ItemMapping getMapping(Item javaItem) {
|
public ItemMapping getMapping(Item javaItem) {
|
||||||
return getMapping(javaItem.javaIdentifier());
|
return getMapping(javaItem.javaIdentifier());
|
||||||
}
|
}
|
||||||
|
@ -105,6 +107,7 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
|
||||||
* @param javaIdentifier the block state identifier
|
* @param javaIdentifier the block state identifier
|
||||||
* @return an item entry from the given java edition identifier
|
* @return an item entry from the given java edition identifier
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
public ItemMapping getMapping(String javaIdentifier) {
|
public ItemMapping getMapping(String javaIdentifier) {
|
||||||
return this.cachedJavaMappings.computeIfAbsent(javaIdentifier, key -> {
|
return this.cachedJavaMappings.computeIfAbsent(javaIdentifier, key -> {
|
||||||
for (ItemMapping mapping : this.items) {
|
for (ItemMapping mapping : this.items) {
|
||||||
|
@ -122,6 +125,7 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
|
||||||
* @param data the item data
|
* @param data the item data
|
||||||
* @return an item entry from the given item data
|
* @return an item entry from the given item data
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
public ItemMapping getMapping(ItemData data) {
|
public ItemMapping getMapping(ItemData data) {
|
||||||
ItemDefinition definition = data.getDefinition();
|
ItemDefinition definition = data.getDefinition();
|
||||||
if (ItemDefinition.AIR.equals(definition)) {
|
if (ItemDefinition.AIR.equals(definition)) {
|
||||||
|
@ -158,11 +162,22 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
|
||||||
return ItemMapping.AIR;
|
return ItemMapping.AIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public ItemDefinition getDefinition(int bedrockId) {
|
public ItemDefinition getDefinition(int bedrockId) {
|
||||||
return this.itemDefinitions.get(bedrockId);
|
return this.itemDefinitions.get(bedrockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ItemDefinition getDefinition(String bedrockIdentifier) {
|
||||||
|
for (ItemDefinition itemDefinition : this.itemDefinitions.values()) {
|
||||||
|
if (itemDefinition.getIdentifier().equals(bedrockIdentifier)) {
|
||||||
|
return itemDefinition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRegistered(ItemDefinition definition) {
|
public boolean isRegistered(ItemDefinition definition) {
|
||||||
return getDefinition(definition.getRuntimeId()) == definition;
|
return getDefinition(definition.getRuntimeId()) == definition;
|
||||||
|
|
|
@ -425,6 +425,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
@Setter
|
@Setter
|
||||||
private boolean emulatePost1_18Logic = true;
|
private boolean emulatePost1_18Logic = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to emulate pre-1.20 smithing table behavior.
|
||||||
|
* Adapts ViaVersion's furnace UI to one Bedrock can use.
|
||||||
|
* See {@link org.geysermc.geyser.translator.inventory.OldSmithingTableTranslator}.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private boolean oldSmithingTable = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current attack speed of the player. Used for sending proper cooldown timings.
|
* The current attack speed of the player. Used for sending proper cooldown timings.
|
||||||
* Setting a default fixes cooldowns not showing up on a fresh world.
|
* Setting a default fixes cooldowns not showing up on a fresh world.
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.translator.inventory;
|
||||||
|
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.DropAction;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.PlaceAction;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.SwapAction;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.TakeAction;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||||
|
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||||
|
import org.geysermc.geyser.inventory.Inventory;
|
||||||
|
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.util.InventoryUtils;
|
||||||
|
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translator for smithing tables for pre-1.20 servers.
|
||||||
|
* This adapts ViaVersion's furnace ui to the 1.20+ smithing table; with the addition of a fake smithing template so Bedrock clients can use it.
|
||||||
|
*/
|
||||||
|
public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator {
|
||||||
|
|
||||||
|
public static final OldSmithingTableTranslator INSTANCE = new OldSmithingTableTranslator();
|
||||||
|
|
||||||
|
private static final IntFunction<ItemData> UPGRADE_TEMPLATE = InventoryUtils.getUpgradeTemplate();
|
||||||
|
|
||||||
|
private OldSmithingTableTranslator() {
|
||||||
|
super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
|
||||||
|
return switch (slotInfoData.getContainer()) {
|
||||||
|
case SMITHING_TABLE_INPUT -> 0;
|
||||||
|
case SMITHING_TABLE_MATERIAL -> 1;
|
||||||
|
case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> 2;
|
||||||
|
default -> super.bedrockSlotToJava(slotInfoData);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||||
|
return switch (slot) {
|
||||||
|
case 0 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51);
|
||||||
|
case 1 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52);
|
||||||
|
case 2 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50);
|
||||||
|
default -> super.javaSlotToBedrockContainer(slot);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int javaSlotToBedrock(int slot) {
|
||||||
|
return switch (slot) {
|
||||||
|
case 0 -> 51;
|
||||||
|
case 1 -> 52;
|
||||||
|
case 2 -> 50;
|
||||||
|
default -> super.javaSlotToBedrock(slot);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||||
|
for (var action: request.getActions()) {
|
||||||
|
switch (action.getType()) {
|
||||||
|
case DROP -> {
|
||||||
|
if (isInvalidAction(((DropAction) action).getSource())) {
|
||||||
|
return rejectRequest(request, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case TAKE -> {
|
||||||
|
if (isInvalidAction(((TakeAction) action).getSource()) ||
|
||||||
|
isInvalidAction(((TakeAction) action).getDestination())) {
|
||||||
|
return rejectRequest(request, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SWAP -> {
|
||||||
|
if (isInvalidAction(((SwapAction) action).getSource()) ||
|
||||||
|
isInvalidAction(((SwapAction) action).getDestination())) {
|
||||||
|
return rejectRequest(request, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PLACE -> {
|
||||||
|
if (isInvalidAction(((PlaceAction) action).getSource()) ||
|
||||||
|
isInvalidAction(((PlaceAction) action).getDestination())) {
|
||||||
|
return rejectRequest(request, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Allow everything else that doesn't involve the fake template
|
||||||
|
return super.translateRequest(session, inventory, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInvalidAction(ItemStackRequestSlotData slotData) {
|
||||||
|
return slotData.getContainer().equals(ContainerSlotType.SMITHING_TABLE_TEMPLATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||||
|
super.openInventory(session, inventory);
|
||||||
|
|
||||||
|
// pre-1.20 server has no concept of templates, but we are working with a 1.20 client
|
||||||
|
// put a fake netherite upgrade template in the template slot otherwise the client doesn't recognize a valid recipe
|
||||||
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
|
slotPacket.setContainerId(ContainerId.UI);
|
||||||
|
slotPacket.setSlot(53);
|
||||||
|
slotPacket.setItem(UPGRADE_TEMPLATE.apply(session.getUpstream().getProtocolVersion()));
|
||||||
|
session.sendUpstreamPacket(slotPacket);
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,6 +46,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescri
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
|
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
|
||||||
|
@ -81,11 +82,24 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
||||||
MultiRecipeData.of(UUID.fromString("602234e4-cac1-4353-8bb7-b1ebff70024b"), ++LAST_RECIPE_NET_ID) // Map locking
|
MultiRecipeData.of(UUID.fromString("602234e4-cac1-4353-8bb7-b1ebff70024b"), ++LAST_RECIPE_NET_ID) // Map locking
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static final List<String> NETHERITE_UPGRADES = List.of(
|
||||||
|
"minecraft:netherite_sword",
|
||||||
|
"minecraft:netherite_shovel",
|
||||||
|
"minecraft:netherite_pickaxe",
|
||||||
|
"minecraft:netherite_axe",
|
||||||
|
"minecraft:netherite_hoe",
|
||||||
|
"minecraft:netherite_helmet",
|
||||||
|
"minecraft:netherite_chestplate",
|
||||||
|
"minecraft:netherite_leggings",
|
||||||
|
"minecraft:netherite_boots"
|
||||||
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundUpdateRecipesPacket packet) {
|
public void translate(GeyserSession session, ClientboundUpdateRecipesPacket packet) {
|
||||||
Map<RecipeType, List<RecipeData>> recipeTypes = Registries.CRAFTING_DATA.forVersion(session.getUpstream().getProtocolVersion());
|
Map<RecipeType, List<RecipeData>> recipeTypes = Registries.CRAFTING_DATA.forVersion(session.getUpstream().getProtocolVersion());
|
||||||
// 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 sendTrimRecipes = false;
|
||||||
|
|
||||||
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<>();
|
||||||
|
@ -168,6 +182,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
||||||
|
|
||||||
}
|
}
|
||||||
case SMITHING_TRIM -> {
|
case SMITHING_TRIM -> {
|
||||||
|
sendTrimRecipes = true;
|
||||||
// ignored currently - see below
|
// ignored currently - see below
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
|
@ -214,8 +229,10 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: if the server/viaversion doesn't send trim recipes then we shouldn't either.
|
session.getLastRecipeNetId().set(netId);
|
||||||
|
|
||||||
|
// Only send smithing trim recipes if Java/ViaVersion sends them.
|
||||||
|
if (sendTrimRecipes) {
|
||||||
// BDS sends armor trim templates and materials before the CraftingDataPacket
|
// BDS sends armor trim templates and materials before the CraftingDataPacket
|
||||||
TrimDataPacket trimDataPacket = new TrimDataPacket();
|
TrimDataPacket trimDataPacket = new TrimDataPacket();
|
||||||
trimDataPacket.getPatterns().addAll(TrimRecipe.PATTERNS);
|
trimDataPacket.getPatterns().addAll(TrimRecipe.PATTERNS);
|
||||||
|
@ -225,12 +242,15 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
||||||
// Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the
|
// Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the
|
||||||
// approach of using many default-descriptors (which we do for smithing_transform)
|
// approach of using many default-descriptors (which we do for smithing_transform)
|
||||||
craftingDataPacket.getCraftingData().add(SmithingTrimRecipeData.of(TrimRecipe.ID,
|
craftingDataPacket.getCraftingData().add(SmithingTrimRecipeData.of(TrimRecipe.ID,
|
||||||
TrimRecipe.BASE, TrimRecipe.ADDITION, TrimRecipe.TEMPLATE, "smithing_table", netId++));
|
TrimRecipe.BASE, TrimRecipe.ADDITION, TrimRecipe.TEMPLATE, "smithing_table", session.getLastRecipeNetId().getAndIncrement()));
|
||||||
|
} else {
|
||||||
|
// manually add recipes for the upgrade template (workaround), since Java pre-1.20 doesn't
|
||||||
|
craftingDataPacket.getCraftingData().addAll(getSmithingTransformRecipes(session));
|
||||||
|
}
|
||||||
|
session.setOldSmithingTable(!sendTrimRecipes);
|
||||||
session.sendUpstreamPacket(craftingDataPacket);
|
session.sendUpstreamPacket(craftingDataPacket);
|
||||||
session.setCraftingRecipes(recipeMap);
|
session.setCraftingRecipes(recipeMap);
|
||||||
session.setStonecutterRecipes(stonecutterRecipeMap);
|
session.setStonecutterRecipes(stonecutterRecipeMap);
|
||||||
session.getLastRecipeNetId().set(netId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: rewrite
|
//TODO: rewrite
|
||||||
|
@ -323,4 +343,29 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
||||||
ItemDefinition id;
|
ItemDefinition id;
|
||||||
int count;
|
int count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<RecipeData> getSmithingTransformRecipes(GeyserSession session) {
|
||||||
|
List<RecipeData> recipes = new ArrayList<>();
|
||||||
|
ItemMapping template = session.getItemMappings().getStoredItems().upgradeTemplate();
|
||||||
|
|
||||||
|
for (String identifier : NETHERITE_UPGRADES) {
|
||||||
|
recipes.add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(identifier + "_smithing",
|
||||||
|
getDescriptorFromId(session, template.getBedrockIdentifier()),
|
||||||
|
getDescriptorFromId(session, identifier.replace("netherite", "diamond")),
|
||||||
|
getDescriptorFromId(session, "minecraft:netherite_ingot"),
|
||||||
|
ItemData.builder().definition(Objects.requireNonNull(session.getItemMappings().getDefinition(identifier))).count(1).build(),
|
||||||
|
"smithing_table",
|
||||||
|
session.getLastRecipeNetId().getAndIncrement()));
|
||||||
|
}
|
||||||
|
return recipes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemDescriptorWithCount getDescriptorFromId(GeyserSession session, String bedrockId) {
|
||||||
|
ItemDefinition bedrockDefinition = session.getItemMappings().getDefinition(bedrockId);
|
||||||
|
if (bedrockDefinition != null) {
|
||||||
|
return ItemDescriptorWithCount.fromItem(ItemData.builder().definition(bedrockDefinition).count(1).build());
|
||||||
|
}
|
||||||
|
GeyserImpl.getInstance().getLogger().debug("Unable to find item with identifier " + bedrockId);
|
||||||
|
return ItemDescriptorWithCount.EMPTY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,14 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundOpenScreenPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundOpenScreenPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
import org.geysermc.geyser.inventory.Inventory;
|
import org.geysermc.geyser.inventory.Inventory;
|
||||||
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.translator.inventory.OldSmithingTableTranslator;
|
||||||
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;
|
||||||
|
@ -38,6 +41,8 @@ import org.geysermc.geyser.util.InventoryUtils;
|
||||||
@Translator(packet = ClientboundOpenScreenPacket.class)
|
@Translator(packet = ClientboundOpenScreenPacket.class)
|
||||||
public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenScreenPacket> {
|
public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenScreenPacket> {
|
||||||
|
|
||||||
|
private static final Component SMITHING_TABLE_COMPONENT = Component.translatable("container.upgrade");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundOpenScreenPacket packet) {
|
public void translate(GeyserSession session, ClientboundOpenScreenPacket packet) {
|
||||||
if (packet.getContainerId() == 0) {
|
if (packet.getContainerId() == 0) {
|
||||||
|
@ -46,6 +51,12 @@ public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenSc
|
||||||
|
|
||||||
InventoryTranslator newTranslator = InventoryTranslator.inventoryTranslator(packet.getType());
|
InventoryTranslator newTranslator = InventoryTranslator.inventoryTranslator(packet.getType());
|
||||||
Inventory openInventory = session.getOpenInventory();
|
Inventory openInventory = session.getOpenInventory();
|
||||||
|
|
||||||
|
// Hack: ViaVersion translates the old (pre 1.20) smithing table to a furnace (does not work for Bedrock). We can detect this and translate it back to a smithing table.
|
||||||
|
if (session.isOldSmithingTable() && packet.getType() == ContainerType.FURNACE && packet.getTitle().equals(SMITHING_TABLE_COMPONENT)) {
|
||||||
|
newTranslator = OldSmithingTableTranslator.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
// No translator exists for this window type. Close all windows and return.
|
// No translator exists for this window type. Close all windows and return.
|
||||||
if (newTranslator == null) {
|
if (newTranslator == null) {
|
||||||
if (openInventory != null) {
|
if (openInventory != null) {
|
||||||
|
|
|
@ -208,15 +208,7 @@ public class InventoryUtils {
|
||||||
|
|
||||||
private static ItemDefinition getUnusableSpaceBlockDefinition(int protocolVersion) {
|
private static ItemDefinition getUnusableSpaceBlockDefinition(int protocolVersion) {
|
||||||
String unusableSpaceBlock = GeyserImpl.getInstance().getConfig().getUnusableSpaceBlock();
|
String unusableSpaceBlock = GeyserImpl.getInstance().getConfig().getUnusableSpaceBlock();
|
||||||
ItemDefinition itemDefinition = null;
|
ItemDefinition itemDefinition = Registries.ITEMS.forVersion(protocolVersion).getDefinition(unusableSpaceBlock);
|
||||||
|
|
||||||
// looping through all the items to find the one with the specified Bedrock identifier
|
|
||||||
for (ItemDefinition definition : Registries.ITEMS.forVersion(protocolVersion).getItemDefinitions().values()) {
|
|
||||||
if (definition.getIdentifier().equals(unusableSpaceBlock)) {
|
|
||||||
itemDefinition = definition;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemDefinition == null) {
|
if (itemDefinition == null) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Invalid value " + unusableSpaceBlock + ". Resorting to barrier block.");
|
GeyserImpl.getInstance().getLogger().error("Invalid value " + unusableSpaceBlock + ". Resorting to barrier block.");
|
||||||
|
@ -226,6 +218,12 @@ public class InventoryUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IntFunction<ItemData> getUpgradeTemplate() {
|
||||||
|
return protocolVersion -> ItemData.builder()
|
||||||
|
.definition(Registries.ITEMS.forVersion(protocolVersion).getStoredItems().upgradeTemplate().getBedrockDefinition())
|
||||||
|
.count(1).build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link #findOrCreateItem(GeyserSession, String)}. This is for finding a specified {@link ItemStack}.
|
* See {@link #findOrCreateItem(GeyserSession, String)}. This is for finding a specified {@link ItemStack}.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue