Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-27 08:30:12 +01:00
Better multi-item recipe support for 1.21.1
Dieser Commit ist enthalten in:
Ursprung
6983095d36
Commit
881b8e9b90
@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.Pair;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.RecipeUnlockingRequirement;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.RecipeUnlockingRequirement;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData;
|
||||||
@ -72,6 +73,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.WithRem
|
|||||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipeBookAddPacket;
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipeBookAddPacket;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -202,11 +204,39 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator<ClientboundRec
|
|||||||
if (composite.contents().size() == 1) {
|
if (composite.contents().size() == 1) {
|
||||||
return translateToInput(session, composite.contents().get(0));
|
return translateToInput(session, composite.contents().get(0));
|
||||||
}
|
}
|
||||||
return composite.contents().stream()
|
|
||||||
.map(subDisplay -> translateToInput(session, subDisplay))
|
// Try and see if the contents match a tag.
|
||||||
.filter(Objects::nonNull)
|
// ViaVersion maps pre-1.21.2 ingredient lists to CompositeSlotDisplays.
|
||||||
.flatMap(List::stream)
|
int[] items = new int[composite.contents().size()];
|
||||||
.toList();
|
List<SlotDisplay> contents = composite.contents();
|
||||||
|
for (int i = 0; i < contents.size(); i++) {
|
||||||
|
SlotDisplay subDisplay = contents.get(i);
|
||||||
|
int id;
|
||||||
|
if (subDisplay instanceof ItemSlotDisplay item) {
|
||||||
|
id = item.item();
|
||||||
|
} else if (!(subDisplay instanceof ItemStackSlotDisplay itemStackSlotDisplay)) {
|
||||||
|
id = -1;
|
||||||
|
} else if (itemStackSlotDisplay.itemStack().getAmount() == 1
|
||||||
|
&& itemStackSlotDisplay.itemStack().getDataComponents() == null) {
|
||||||
|
id = itemStackSlotDisplay.itemStack().getId();
|
||||||
|
} else {
|
||||||
|
id = -1;
|
||||||
|
}
|
||||||
|
if (id == -1) {
|
||||||
|
// We couldn't guarantee a "normal" item from this stack.
|
||||||
|
return fallbackCompositeMapping(session, composite);
|
||||||
|
}
|
||||||
|
items[i] = id;
|
||||||
|
}
|
||||||
|
// For searching in the tag map.
|
||||||
|
Arrays.sort(items);
|
||||||
|
|
||||||
|
List<ItemDescriptorWithCount> tagDescriptor = lookupBedrockTag(session, items);
|
||||||
|
if (tagDescriptor != null) {
|
||||||
|
return tagDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackCompositeMapping(session, composite);
|
||||||
}
|
}
|
||||||
if (slotDisplay instanceof WithRemainderSlotDisplay remainder) {
|
if (slotDisplay instanceof WithRemainderSlotDisplay remainder) {
|
||||||
// Don't need to worry about what will stay in the crafting table after crafting for the purposes of sending recipes to Bedrock
|
// Don't need to worry about what will stay in the crafting table after crafting for the purposes of sending recipes to Bedrock
|
||||||
@ -230,12 +260,9 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator<ClientboundRec
|
|||||||
// Cache is implemented as, presumably, an item tag will be used multiple times in succession
|
// Cache is implemented as, presumably, an item tag will be used multiple times in succession
|
||||||
// (E.G. a chest with planks tags)
|
// (E.G. a chest with planks tags)
|
||||||
return TAG_TO_ITEM_DESCRIPTOR_CACHE.get().computeIfAbsent(items, key -> {
|
return TAG_TO_ITEM_DESCRIPTOR_CACHE.get().computeIfAbsent(items, key -> {
|
||||||
var bedrockTags = Registries.TAGS.forVersion(session.getUpstream().getProtocolVersion());
|
List<ItemDescriptorWithCount> tagDescriptor = lookupBedrockTag(session, key);
|
||||||
String bedrockTag = bedrockTags.get(key);
|
if (tagDescriptor != null) {
|
||||||
if (bedrockTag != null) {
|
return tagDescriptor;
|
||||||
return Collections.singletonList(
|
|
||||||
new ItemDescriptorWithCount(new ItemTagDescriptor(bedrockTag), 1)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the future, we can probably search through and use subsets of tags as well.
|
// In the future, we can probably search through and use subsets of tags as well.
|
||||||
@ -278,6 +305,33 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator<ClientboundRec
|
|||||||
return new ItemDescriptorWithCount(new DefaultDescriptor(mapping.getBedrockDefinition(), mapping.getBedrockData()), 1); // Need to check count
|
return new ItemDescriptorWithCount(new DefaultDescriptor(mapping.getBedrockDefinition(), mapping.getBedrockData()), 1); // Need to check count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if this list of items matches with one of this Bedrock version's tags.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private List<ItemDescriptorWithCount> lookupBedrockTag(GeyserSession session, int[] items) {
|
||||||
|
var bedrockTags = Registries.TAGS.forVersion(session.getUpstream().getProtocolVersion());
|
||||||
|
String bedrockTag = bedrockTags.get(items);
|
||||||
|
if (bedrockTag != null) {
|
||||||
|
return Collections.singletonList(
|
||||||
|
new ItemDescriptorWithCount(new ItemTagDescriptor(bedrockTag), 1)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts CompositeSlotDisplay contents to a list of basic ItemDescriptorWithCounts.
|
||||||
|
*/
|
||||||
|
private List<ItemDescriptorWithCount> fallbackCompositeMapping(GeyserSession session, CompositeSlotDisplay composite) {
|
||||||
|
return composite.contents().stream()
|
||||||
|
.map(subDisplay -> translateToInput(session, subDisplay))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
private Pair<List<List<ItemDescriptorWithCount>>, ItemData> combinations(GeyserSession session, RecipeDisplay display, List<SlotDisplay> ingredients) {
|
private Pair<List<List<ItemDescriptorWithCount>>, ItemData> combinations(GeyserSession session, RecipeDisplay display, List<SlotDisplay> ingredients) {
|
||||||
Pair<Item, ItemData> pair = translateToOutput(session, display.result());
|
Pair<Item, ItemData> pair = translateToOutput(session, display.result());
|
||||||
if (pair == null || !pair.right().isValid()) {
|
if (pair == null || !pair.right().isValid()) {
|
||||||
@ -327,6 +381,7 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator<ClientboundRec
|
|||||||
return Pair.of(Lists.cartesianProduct(inputs), output);
|
return Pair.of(Lists.cartesianProduct(inputs), output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO:
|
||||||
return Pair.of(
|
return Pair.of(
|
||||||
Collections.singletonList(inputs.stream().map(descriptors -> descriptors.get(0)).toList()),
|
Collections.singletonList(inputs.stream().map(descriptors -> descriptors.get(0)).toList()),
|
||||||
output
|
output
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren