mirror of
https://github.com/ViaVersion/ViaProxy.git
synced 2025-04-22 11:03:26 -04:00
Implemented item component hashing to fix inventory issues with 1.21.5 clients on <=1.21.4 servers
This commit is contained in:
parent
c54c4327f3
commit
50b1907ca6
7 changed files with 728 additions and 0 deletions
build.gradle
src/main/java/net/raphimc/viaproxy
injection/mixins
protocoltranslator/viaproxy/item_component_hasher
|
@ -98,6 +98,7 @@ dependencies {
|
|||
include("net.raphimc.netminecraft:all:3.1.0") {
|
||||
exclude group: "com.google.code.gson", module: "gson"
|
||||
}
|
||||
include "net.lenni0451.mcstructs:itemcomponents:3.0.0"
|
||||
include("net.raphimc:MinecraftAuth:4.1.1") {
|
||||
exclude group: "com.google.code.gson", module: "gson"
|
||||
exclude group: "org.slf4j", module: "slf4j-api"
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2021-2025 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.raphimc.viaproxy.injection.mixins;
|
||||
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
|
||||
import com.viaversion.viaversion.api.minecraft.item.HashedItem;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21_5;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
|
||||
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
|
||||
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
|
||||
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ServerboundPacket1_21_5;
|
||||
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.BlockItemPacketRewriter1_21_5;
|
||||
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
|
||||
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
import net.lenni0451.mcstructs.core.Identifier;
|
||||
import net.raphimc.viaproxy.protocoltranslator.viaproxy.item_component_hasher.ItemComponentHashStorage;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(value = BlockItemPacketRewriter1_21_5.class, remap = false)
|
||||
public abstract class MixinBlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<ClientboundPacket1_21_2, ServerboundPacket1_21_5, Protocol1_21_4To1_21_5> {
|
||||
|
||||
@Unique
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
public MixinBlockItemPacketRewriter1_21_5() {
|
||||
super(null, null, null, null, null);
|
||||
}
|
||||
|
||||
@Inject(method = "registerPackets", at = @At("RETURN"))
|
||||
private void appendPacketHandlers() {
|
||||
this.protocol.appendClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, wrapper -> {
|
||||
wrapper.resetReader();
|
||||
final String key = Key.namespaced(wrapper.passthrough(Types.STRING)); // key
|
||||
final RegistryEntry[] entries = wrapper.passthrough(Types.REGISTRY_ENTRY_ARRAY); // entries
|
||||
|
||||
final ItemComponentHashStorage itemComponentHasher = wrapper.user().get(ItemComponentHashStorage.class);
|
||||
if (key.equals("minecraft:enchantment")) {
|
||||
final List<Identifier> identifiers = new ArrayList<>();
|
||||
for (RegistryEntry entry : entries) {
|
||||
identifiers.add(Identifier.of(entry.key()));
|
||||
}
|
||||
itemComponentHasher.setEnchantmentRegistry(identifiers);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "handleItemToClient", at = @At("RETURN"))
|
||||
private void trackItemHashes(UserConnection connection, Item item, CallbackInfoReturnable<Item> cir) {
|
||||
final ItemComponentHashStorage itemComponentHasher = connection.get(ItemComponentHashStorage.class);
|
||||
for (StructuredData<?> structuredData : item.dataContainer().data().values()) {
|
||||
itemComponentHasher.trackStructuredData(structuredData);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "convertHashedItemToStructuredItem", at = @At("RETURN"))
|
||||
private void addMoreDataToStructuredItem(UserConnection connection, HashedItem hashedItem, CallbackInfoReturnable<StructuredItem> cir) {
|
||||
final ItemComponentHashStorage itemComponentHasher = connection.get(ItemComponentHashStorage.class);
|
||||
final Map<StructuredDataKey<?>, StructuredData<?>> structuredDataMap = cir.getReturnValue().dataContainer().data();
|
||||
for (Int2IntMap.Entry hashEntry : hashedItem.dataHashesById().int2IntEntrySet()) {
|
||||
final StructuredData<?> structuredData = itemComponentHasher.getStructuredData(hashEntry.getIntKey(), hashEntry.getIntValue());
|
||||
if (structuredData != null) {
|
||||
structuredDataMap.put(structuredData.key(), structuredData);
|
||||
} else if (DEBUG) {
|
||||
this.protocol.getLogger().warning("Failed to find structured data for hash: " + hashEntry.getIntValue() + " with id: " + hashEntry.getIntKey());
|
||||
}
|
||||
}
|
||||
for (int dataId : hashedItem.removedDataIds()) {
|
||||
final StructuredDataKey<?> structuredDataKey = Types1_21_5.STRUCTURED_DATA.key(dataId);
|
||||
structuredDataMap.put(structuredDataKey, StructuredData.empty(structuredDataKey, dataId));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2021-2025 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.injection.mixins;
|
||||
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
|
||||
import net.raphimc.viaproxy.protocoltranslator.viaproxy.item_component_hasher.ItemComponentHashStorage;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Protocol1_21_4To1_21_5.class)
|
||||
public abstract class MixinProtocol1_21_4To1_21_5 {
|
||||
|
||||
@Shadow
|
||||
public abstract MappingData getMappingData();
|
||||
|
||||
@Inject(method = "init", at = @At("RETURN"))
|
||||
private void addItemComponentHashStorage(UserConnection connection, CallbackInfo ci) {
|
||||
connection.put(new ItemComponentHashStorage(connection, this.getMappingData()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2021-2025 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.protocoltranslator.viaproxy.item_component_hasher;
|
||||
|
||||
import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.api.minecraft.GameProfile;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.minecraft.item.data.*;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
|
||||
import com.viaversion.viaversion.libs.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import net.lenni0451.mcstructs.converter.impl.v1_21_5.NbtConverter_v1_21_5;
|
||||
import net.lenni0451.mcstructs.core.Identifier;
|
||||
import net.lenni0451.mcstructs.itemcomponents.ItemComponent;
|
||||
import net.lenni0451.mcstructs.itemcomponents.ItemComponentMap;
|
||||
import net.lenni0451.mcstructs.itemcomponents.ItemComponentRegistry;
|
||||
import net.lenni0451.mcstructs.itemcomponents.impl.v1_20_5.Types_v1_20_5;
|
||||
import net.lenni0451.mcstructs.itemcomponents.impl.v1_21_2.Types_v1_21_2;
|
||||
import net.lenni0451.mcstructs.itemcomponents.impl.v1_21_4.Types_v1_21_4;
|
||||
import net.lenni0451.mcstructs.itemcomponents.impl.v1_21_5.Types_v1_21_5;
|
||||
import net.lenni0451.mcstructs.nbt.tags.CompoundTag;
|
||||
import net.lenni0451.mcstructs.text.TextComponent;
|
||||
import net.lenni0451.mcstructs.text.serializer.TextComponentCodec;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ItemComponentConverter {
|
||||
|
||||
private static final Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> NOT_IMPLEMENTED = structuredData -> null;
|
||||
|
||||
private static Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> passthroughValueFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> new Pair<>(itemComponent, structuredData.value());
|
||||
}
|
||||
|
||||
private static Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> noValueFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> new Pair<>(itemComponent, null);
|
||||
}
|
||||
|
||||
private static Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> convertNbtFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> new Pair<>(itemComponent, NbtConverter.viaToMcStructs((Tag) structuredData.value()));
|
||||
}
|
||||
|
||||
private static Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> convertTextComponentFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> new Pair<>(itemComponent, convertTextComponent((Tag) structuredData.value()));
|
||||
}
|
||||
|
||||
private static Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> convertTextComponentArrayFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> {
|
||||
final Tag[] tags = (Tag[]) structuredData.value();
|
||||
final List<TextComponent> textComponents = new ArrayList<>(tags.length);
|
||||
for (Tag tag : tags) {
|
||||
textComponents.add(convertTextComponent(tag));
|
||||
}
|
||||
return new Pair<>(itemComponent, textComponents);
|
||||
};
|
||||
}
|
||||
|
||||
private static Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> stringToIdentifierFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> new Pair<>(itemComponent, Identifier.of((String) structuredData.value()));
|
||||
}
|
||||
|
||||
private static <T extends Enum<?>> Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> intToEnumFunction(final ItemComponent<T> itemComponent, final Class<T> enumClass) {
|
||||
final Enum<?>[] enumConstants = enumClass.getEnumConstants();
|
||||
return structuredData -> new Pair<>(itemComponent, enumConstants[(Integer) structuredData.value()]);
|
||||
}
|
||||
|
||||
private static Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> passthroughNbtCodec(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> new Pair<>(itemComponent, itemComponent.getCodec().deserialize(NbtConverter_v1_21_5.INSTANCE, NbtConverter.viaToMcStructs((Tag) structuredData.value())).getOrThrow());
|
||||
}
|
||||
|
||||
private static Types_v1_20_5.FireworkExplosions convertFireworkExplosion(final FireworkExplosion viaFireworkExplosion) {
|
||||
final Types_v1_20_5.FireworkExplosions.ExplosionShape explosionShape = Types_v1_20_5.FireworkExplosions.ExplosionShape.values()[viaFireworkExplosion.shape()];
|
||||
return new Types_v1_20_5.FireworkExplosions(explosionShape, intArrayToIntList(viaFireworkExplosion.colors()), intArrayToIntList(viaFireworkExplosion.fadeColors()), viaFireworkExplosion.hasTrail(), viaFireworkExplosion.hasTwinkle());
|
||||
}
|
||||
|
||||
private static TextComponent convertTextComponent(final Tag tag) {
|
||||
if (tag != null) {
|
||||
return TextComponentCodec.V1_21_5.deserialize(NbtConverter.viaToMcStructs(tag));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Integer> intArrayToIntList(final int[] array) {
|
||||
final List<Integer> list = new ArrayList<>(array.length);
|
||||
for (int i : array) {
|
||||
list.add(i);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private final RegistryAccess registryAccess;
|
||||
private final Map<StructuredDataKey<?>, Function<StructuredData<?>, Pair<ItemComponent<?>, Object>>> conversionFunctions = new Reference2ObjectOpenHashMap<>();
|
||||
|
||||
public ItemComponentConverter(final RegistryAccess registryAccess) {
|
||||
this.registryAccess = registryAccess;
|
||||
this.conversionFunctions.put(StructuredDataKey.CUSTOM_DATA, convertNbtFunction(ItemComponentRegistry.V1_21_5.CUSTOM_DATA));
|
||||
this.conversionFunctions.put(StructuredDataKey.MAX_STACK_SIZE, passthroughValueFunction(ItemComponentRegistry.V1_21_5.MAX_STACK_SIZE));
|
||||
this.conversionFunctions.put(StructuredDataKey.MAX_DAMAGE, passthroughValueFunction(ItemComponentRegistry.V1_21_5.MAX_DAMAGE));
|
||||
this.conversionFunctions.put(StructuredDataKey.DAMAGE, passthroughValueFunction(ItemComponentRegistry.V1_21_5.DAMAGE));
|
||||
this.conversionFunctions.put(StructuredDataKey.UNBREAKABLE1_21_5, noValueFunction(ItemComponentRegistry.V1_21_5.UNBREAKABLE));
|
||||
this.conversionFunctions.put(StructuredDataKey.CUSTOM_NAME, convertTextComponentFunction(ItemComponentRegistry.V1_21_5.CUSTOM_NAME));
|
||||
this.conversionFunctions.put(StructuredDataKey.ITEM_NAME, convertTextComponentFunction(ItemComponentRegistry.V1_21_5.ITEM_NAME));
|
||||
this.conversionFunctions.put(StructuredDataKey.ITEM_MODEL, stringToIdentifierFunction(ItemComponentRegistry.V1_21_5.ITEM_MODEL));
|
||||
this.conversionFunctions.put(StructuredDataKey.LORE, convertTextComponentArrayFunction(ItemComponentRegistry.V1_21_5.LORE));
|
||||
this.conversionFunctions.put(StructuredDataKey.RARITY, intToEnumFunction(ItemComponentRegistry.V1_21_5.RARITY, Types_v1_20_5.Rarity.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.ENCHANTMENTS1_21_5, this.convertEnchantmentsFunction(ItemComponentRegistry.V1_21_5.ENCHANTMENTS));
|
||||
this.conversionFunctions.put(StructuredDataKey.CAN_PLACE_ON1_21_5, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.CAN_BREAK1_21_5, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.ATTRIBUTE_MODIFIERS1_21_5, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4, structuredData -> {
|
||||
final CustomModelData1_21_4 viaCustomModelData = (CustomModelData1_21_4) structuredData.value();
|
||||
final List<Float> floats = new ArrayList<>(viaCustomModelData.floats().length);
|
||||
for (float f : viaCustomModelData.floats()) {
|
||||
floats.add(f);
|
||||
}
|
||||
final List<Boolean> booleans = new ArrayList<>(viaCustomModelData.booleans().length);
|
||||
for (boolean b : viaCustomModelData.booleans()) {
|
||||
booleans.add(b);
|
||||
}
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.CUSTOM_MODEL_DATA, new Types_v1_21_4.CustomModelData(floats, booleans, Arrays.asList(viaCustomModelData.strings()), intArrayToIntList(viaCustomModelData.colors())));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.TOOLTIP_DISPLAY, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.REPAIR_COST, passthroughValueFunction(ItemComponentRegistry.V1_21_5.REPAIR_COST));
|
||||
this.conversionFunctions.put(StructuredDataKey.CREATIVE_SLOT_LOCK, noValueFunction(ItemComponentRegistry.V1_21_5.CREATIVE_SLOT_LOCK));
|
||||
this.conversionFunctions.put(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, passthroughValueFunction(ItemComponentRegistry.V1_21_5.ENCHANTMENT_GLINT_OVERRIDE));
|
||||
this.conversionFunctions.put(StructuredDataKey.INTANGIBLE_PROJECTILE, noValueFunction(ItemComponentRegistry.V1_21_5.INTANGIBLE_PROJECTILE));
|
||||
this.conversionFunctions.put(StructuredDataKey.FOOD1_21_2, structuredData -> {
|
||||
final FoodProperties1_21_2 viaFoodProperties = (FoodProperties1_21_2) structuredData.value();
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.FOOD, new Types_v1_21_2.Food(viaFoodProperties.nutrition(), viaFoodProperties.saturationModifier(), viaFoodProperties.canAlwaysEat()));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.CONSUMABLE1_21_2, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.USE_REMAINDER1_21_5, this.convertItemFunction(ItemComponentRegistry.V1_21_5.USE_REMAINDER));
|
||||
this.conversionFunctions.put(StructuredDataKey.USE_COOLDOWN, structuredData -> {
|
||||
final UseCooldown viaUseCooldown = (UseCooldown) structuredData.value();
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.USE_COOLDOWN, new Types_v1_21_2.UseCooldown(viaUseCooldown.seconds(), Identifier.of(viaUseCooldown.cooldownGroup())));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.DAMAGE_RESISTANT, structuredData -> {
|
||||
final DamageResistant viaDamageResistant = (DamageResistant) structuredData.value();
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.DAMAGE_RESISTANT, new Types_v1_21_2.DamageResistant(Identifier.of(viaDamageResistant.typesTagKey())));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.TOOL1_21_5, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.WEAPON, structuredData -> {
|
||||
final Weapon viaWeapon = (Weapon) structuredData.value();
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.WEAPON, new Types_v1_21_5.Weapon(viaWeapon.itemDamagePerAttack(), viaWeapon.disableBlockingForSeconds()));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.ENCHANTABLE, structuredData -> {
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.ENCHANTABLE, new Types_v1_21_2.Enchantable((int) structuredData.value()));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.EQUIPPABLE1_21_5, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.REPAIRABLE, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.GLIDER, noValueFunction(ItemComponentRegistry.V1_21_5.GLIDER));
|
||||
this.conversionFunctions.put(StructuredDataKey.TOOLTIP_STYLE, stringToIdentifierFunction(ItemComponentRegistry.V1_21_5.TOOLTIP_STYLE));
|
||||
this.conversionFunctions.put(StructuredDataKey.DEATH_PROTECTION, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.BLOCKS_ATTACKS, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.STORED_ENCHANTMENTS1_21_5, this.convertEnchantmentsFunction(ItemComponentRegistry.V1_21_5.STORED_ENCHANTMENTS));
|
||||
this.conversionFunctions.put(StructuredDataKey.DYED_COLOR1_21_5, structuredData -> {
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.DYED_COLOR, ((DyedColor) structuredData.value()).rgb());
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.MAP_COLOR, passthroughValueFunction(ItemComponentRegistry.V1_21_5.MAP_COLOR));
|
||||
this.conversionFunctions.put(StructuredDataKey.MAP_ID, passthroughValueFunction(ItemComponentRegistry.V1_21_5.MAP_ID));
|
||||
this.conversionFunctions.put(StructuredDataKey.MAP_DECORATIONS, passthroughNbtCodec(ItemComponentRegistry.V1_21_5.MAP_DECORATIONS));
|
||||
this.conversionFunctions.put(StructuredDataKey.MAP_POST_PROCESSING, intToEnumFunction(ItemComponentRegistry.V1_21_5.MAP_POST_PROCESSING, Types_v1_20_5.MapPostProcessing.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.CHARGED_PROJECTILES1_21_5, convertItemArrayFunction(ItemComponentRegistry.V1_21_5.CHARGED_PROJECTILES));
|
||||
this.conversionFunctions.put(StructuredDataKey.BUNDLE_CONTENTS1_21_5, convertItemArrayFunction(ItemComponentRegistry.V1_21_5.BUNDLE_CONTENTS));
|
||||
this.conversionFunctions.put(StructuredDataKey.POTION_CONTENTS1_21_2, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.POTION_DURATION_SCALE, passthroughValueFunction(ItemComponentRegistry.V1_21_5.POTION_DURATION_SCALE));
|
||||
this.conversionFunctions.put(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.WRITABLE_BOOK_CONTENT, structuredData -> {
|
||||
final FilterableString[] viaPages = (FilterableString[]) structuredData.value();
|
||||
final List<Types_v1_20_5.RawFilteredPair<String>> pages = new ArrayList<>(viaPages.length);
|
||||
for (FilterableString viaPage : viaPages) {
|
||||
pages.add(new Types_v1_20_5.RawFilteredPair<>(viaPage.raw(), viaPage.filtered()));
|
||||
}
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.WRITABLE_BOOK_CONTENT, new Types_v1_20_5.WritableBook(pages));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.WRITTEN_BOOK_CONTENT, structuredData -> {
|
||||
final WrittenBook viaWrittenBook = (WrittenBook) structuredData.value();
|
||||
final Types_v1_20_5.RawFilteredPair<String> title = new Types_v1_20_5.RawFilteredPair<>(viaWrittenBook.title().raw(), viaWrittenBook.title().filtered());
|
||||
final List<Types_v1_20_5.RawFilteredPair<TextComponent>> pages = new ArrayList<>(viaWrittenBook.pages().length);
|
||||
for (FilterableComponent viaPage : viaWrittenBook.pages()) {
|
||||
pages.add(new Types_v1_20_5.RawFilteredPair<>(convertTextComponent(viaPage.raw()), convertTextComponent(viaPage.filtered())));
|
||||
}
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.WRITTEN_BOOK_CONTENT, new Types_v1_20_5.WrittenBook(title, viaWrittenBook.author(), viaWrittenBook.generation(), pages, viaWrittenBook.resolved()));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.TRIM1_21_5, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.DEBUG_STICK_STATE, passthroughNbtCodec(ItemComponentRegistry.V1_21_5.DEBUG_STICK_STATE));
|
||||
this.conversionFunctions.put(StructuredDataKey.ENTITY_DATA, convertNbtFunction(ItemComponentRegistry.V1_21_5.ENTITY_DATA));
|
||||
this.conversionFunctions.put(StructuredDataKey.BUCKET_ENTITY_DATA, convertNbtFunction(ItemComponentRegistry.V1_21_5.BUCKET_ENTITY_DATA));
|
||||
this.conversionFunctions.put(StructuredDataKey.BLOCK_ENTITY_DATA, convertNbtFunction(ItemComponentRegistry.V1_21_5.BLOCK_ENTITY_DATA));
|
||||
this.conversionFunctions.put(StructuredDataKey.INSTRUMENT1_21_5, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.PROVIDES_TRIM_MATERIAL, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, passthroughValueFunction(ItemComponentRegistry.V1_21_5.OMINOUS_BOTTLE_AMPLIFIER));
|
||||
this.conversionFunctions.put(StructuredDataKey.JUKEBOX_PLAYABLE1_21_5, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.PROVIDES_BANNER_PATTERNS, stringToIdentifierFunction(ItemComponentRegistry.V1_21_5.PROVIDES_BANNER_PATTERNS));
|
||||
this.conversionFunctions.put(StructuredDataKey.RECIPES, passthroughNbtCodec(ItemComponentRegistry.V1_21_5.RECIPES));
|
||||
this.conversionFunctions.put(StructuredDataKey.LODESTONE_TRACKER, structuredData -> {
|
||||
final LodestoneTracker viaLodestoneTracker = (LodestoneTracker) structuredData.value();
|
||||
final Types_v1_20_5.LodestoneTracker.GlobalPos targetGlobalPos;
|
||||
if (viaLodestoneTracker.position() != null) {
|
||||
final Types_v1_20_5.BlockPos targetPos = new Types_v1_20_5.BlockPos(viaLodestoneTracker.position().x(), viaLodestoneTracker.position().y(), viaLodestoneTracker.position().z());
|
||||
targetGlobalPos = new Types_v1_20_5.LodestoneTracker.GlobalPos(Identifier.of(viaLodestoneTracker.position().dimension()), targetPos);
|
||||
} else {
|
||||
targetGlobalPos = null;
|
||||
}
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.LODESTONE_TRACKER, new Types_v1_20_5.LodestoneTracker(targetGlobalPos, viaLodestoneTracker.tracked()));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.FIREWORK_EXPLOSION, structuredData -> {
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.FIREWORK_EXPLOSION, convertFireworkExplosion((FireworkExplosion) structuredData.value()));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.FIREWORKS, structuredData -> {
|
||||
final Fireworks viaFireworks = (Fireworks) structuredData.value();
|
||||
final List<Types_v1_20_5.FireworkExplosions> explosions = new ArrayList<>(viaFireworks.explosions().length);
|
||||
for (FireworkExplosion viaFireworkExplosion : viaFireworks.explosions()) {
|
||||
explosions.add(convertFireworkExplosion(viaFireworkExplosion));
|
||||
}
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.FIREWORKS, new Types_v1_20_5.Fireworks(viaFireworks.flightDuration(), explosions));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.PROFILE, structuredData -> {
|
||||
final GameProfile viaProfile = (GameProfile) structuredData.value();
|
||||
final Map<String, List<Types_v1_20_5.GameProfile.Property>> properties = new HashMap<>();
|
||||
for (GameProfile.Property viaProperty : viaProfile.properties()) {
|
||||
final List<Types_v1_20_5.GameProfile.Property> propertyList = properties.computeIfAbsent(viaProperty.name(), k -> new ArrayList<>());
|
||||
propertyList.add(new Types_v1_20_5.GameProfile.Property(viaProperty.name(), viaProperty.value(), viaProperty.signature()));
|
||||
}
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.PROFILE, new Types_v1_20_5.GameProfile(viaProfile.name(), viaProfile.id(), properties));
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.NOTE_BLOCK_SOUND, stringToIdentifierFunction(ItemComponentRegistry.V1_21_5.NOTE_BLOCK_SOUND));
|
||||
this.conversionFunctions.put(StructuredDataKey.BANNER_PATTERNS, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.BASE_COLOR, intToEnumFunction(ItemComponentRegistry.V1_21_5.BASE_COLOR, Types_v1_20_5.DyeColor.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.POT_DECORATIONS, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.CONTAINER1_21_5, structuredData -> {
|
||||
final Item[] items = (Item[]) structuredData.value();
|
||||
final List<Types_v1_20_5.ContainerSlot> slots = new ArrayList<>();
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
final Item item = items[i];
|
||||
if (!item.isEmpty()) {
|
||||
slots.add(new Types_v1_20_5.ContainerSlot(i, this.convertItemStack(item)));
|
||||
}
|
||||
}
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.CONTAINER, slots);
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.BLOCK_STATE, structuredData -> {
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.BLOCK_STATE, ((BlockStateProperties) structuredData.value()).properties());
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.BEES, structuredData -> {
|
||||
final Bee[] viaBees = (Bee[]) structuredData.value();
|
||||
final List<Types_v1_20_5.BeeData> beeData = new ArrayList<>();
|
||||
for (Bee viaBee : viaBees) {
|
||||
beeData.add(new Types_v1_20_5.BeeData((CompoundTag) NbtConverter.viaToMcStructs(viaBee.entityData()), viaBee.ticksInHive(), viaBee.minTicksInHive()));
|
||||
}
|
||||
return new Pair<>(ItemComponentRegistry.V1_21_5.BEES, beeData);
|
||||
});
|
||||
this.conversionFunctions.put(StructuredDataKey.LOCK, passthroughNbtCodec(ItemComponentRegistry.V1_21_5.LOCK));
|
||||
this.conversionFunctions.put(StructuredDataKey.CONTAINER_LOOT, passthroughNbtCodec(ItemComponentRegistry.V1_21_5.CONTAINER_LOOT));
|
||||
this.conversionFunctions.put(StructuredDataKey.BREAK_SOUND, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.VILLAGER_VARIANT, intToEnumFunction(ItemComponentRegistry.V1_21_5.VILLAGER_VARIANT, Types_v1_21_5.VillagerVariant.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.WOLF_VARIANT, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.WOLF_SOUND_VARIANT, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.WOLF_COLLAR, intToEnumFunction(ItemComponentRegistry.V1_21_5.WOLF_COLLAR, Types_v1_20_5.DyeColor.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.FOX_VARIANT, intToEnumFunction(ItemComponentRegistry.V1_21_5.FOX_VARIANT, Types_v1_21_5.FoxVariant.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.SALMON_SIZE, intToEnumFunction(ItemComponentRegistry.V1_21_5.SALMON_SIZE, Types_v1_21_5.SalmonSize.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.PARROT_VARIANT, intToEnumFunction(ItemComponentRegistry.V1_21_5.PARROT_VARIANT, Types_v1_21_5.ParrotVariant.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.TROPICAL_FISH_PATTERN, intToEnumFunction(ItemComponentRegistry.V1_21_5.TROPICAL_FISH_PATTERN, Types_v1_21_5.TropicalFishPattern.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.TROPICAL_FISH_BASE_COLOR, intToEnumFunction(ItemComponentRegistry.V1_21_5.TROPICAL_FISH_BASE_COLOR, Types_v1_20_5.DyeColor.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.TROPICAL_FISH_PATTERN_COLOR, intToEnumFunction(ItemComponentRegistry.V1_21_5.TROPICAL_FISH_PATTERN_COLOR, Types_v1_20_5.DyeColor.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.MOOSHROOM_VARIANT, intToEnumFunction(ItemComponentRegistry.V1_21_5.MOOSHROOM_VARIANT, Types_v1_21_5.MooshroomVariant.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.RABBIT_VARIANT, intToEnumFunction(ItemComponentRegistry.V1_21_5.RABBIT_VARIANT, Types_v1_21_5.RabbitVariant.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.PIG_VARIANT, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.COW_VARIANT, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.CHICKEN_VARIANT, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.FROG_VARIANT, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.HORSE_VARIANT, intToEnumFunction(ItemComponentRegistry.V1_21_5.HORSE_VARIANT, Types_v1_21_5.HorseVariant.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.PAINTING_VARIANT, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.LLAMA_VARIANT, intToEnumFunction(ItemComponentRegistry.V1_21_5.LLAMA_VARIANT, Types_v1_21_5.LlamaVariant.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.AXOLOTL_VARIANT, intToEnumFunction(ItemComponentRegistry.V1_21_5.AXOLOTL_VARIANT, Types_v1_21_5.AxolotlVariant.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.CAT_VARIANT, NOT_IMPLEMENTED);
|
||||
this.conversionFunctions.put(StructuredDataKey.CAT_COLLAR, intToEnumFunction(ItemComponentRegistry.V1_21_5.CAT_COLLAR, Types_v1_20_5.DyeColor.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.SHEEP_COLOR, intToEnumFunction(ItemComponentRegistry.V1_21_5.SHEEP_COLOR, Types_v1_20_5.DyeColor.class));
|
||||
this.conversionFunctions.put(StructuredDataKey.SHULKER_COLOR, intToEnumFunction(ItemComponentRegistry.V1_21_5.SHULKER_COLOR, Types_v1_20_5.DyeColor.class));
|
||||
}
|
||||
|
||||
public Pair<ItemComponent<?>, Object> viaToMcStructs(final StructuredData<?> structuredData) {
|
||||
final Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> conversionFunction = this.conversionFunctions.get(structuredData.key());
|
||||
if (conversionFunction == null) {
|
||||
throw new UnsupportedOperationException("Unsupported structured data key: " + structuredData.key());
|
||||
}
|
||||
return conversionFunction.apply(structuredData);
|
||||
}
|
||||
|
||||
private Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> convertItemFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> new Pair<>(itemComponent, this.convertItemStack((Item) structuredData.value()));
|
||||
}
|
||||
|
||||
private Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> convertItemArrayFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> {
|
||||
final Item[] items = (Item[]) structuredData.value();
|
||||
final List<Types_v1_20_5.ItemStack> itemStacks = new ArrayList<>(items.length);
|
||||
for (Item item : items) {
|
||||
itemStacks.add(this.convertItemStack(item));
|
||||
}
|
||||
return new Pair<>(itemComponent, itemStacks);
|
||||
};
|
||||
}
|
||||
|
||||
private Function<StructuredData<?>, Pair<ItemComponent<?>, Object>> convertEnchantmentsFunction(final ItemComponent<?> itemComponent) {
|
||||
return structuredData -> {
|
||||
final Enchantments viaEnchantments = (Enchantments) structuredData.value();
|
||||
final Map<Identifier, Integer> enchantments = new HashMap<>();
|
||||
for (Int2IntMap.Entry entry : viaEnchantments.enchantments().int2IntEntrySet()) {
|
||||
enchantments.put(this.registryAccess.getEnchantment(entry.getIntKey()), entry.getIntValue());
|
||||
}
|
||||
return new Pair<>(itemComponent, enchantments);
|
||||
};
|
||||
}
|
||||
|
||||
private Types_v1_20_5.ItemStack convertItemStack(final Item item) {
|
||||
final Types_v1_20_5.ItemStack itemStack = new Types_v1_20_5.ItemStack(this.registryAccess.getItem(item.identifier()), item.amount(), new ItemComponentMap(ItemComponentRegistry.V1_21_5));
|
||||
final ItemComponentMap itemComponentMap = itemStack.getComponents();
|
||||
|
||||
for (StructuredData<?> structuredData : item.dataContainer().data().values()) {
|
||||
if (structuredData.isPresent()) {
|
||||
final Pair<ItemComponent<?>, Object> itemComponent = viaToMcStructs(structuredData);
|
||||
if (itemComponent != null) {
|
||||
itemComponentMap.set(itemComponent.key(), cast(itemComponent.value()));
|
||||
}
|
||||
} else {
|
||||
itemComponentMap.markForRemoval(ItemComponentRegistry.V1_21_5.getComponentList().getById(structuredData.id()).get());
|
||||
}
|
||||
}
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
private static <T> T cast(final Object o) {
|
||||
return (T) o;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2021-2025 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.protocoltranslator.viaproxy.item_component_hasher;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.viaversion.viaversion.api.connection.StoredObject;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import net.lenni0451.mcstructs.converter.impl.v1_21_5.HashConverter_v1_21_5;
|
||||
import net.lenni0451.mcstructs.core.Identifier;
|
||||
import net.lenni0451.mcstructs.itemcomponents.ItemComponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ItemComponentHashStorage extends StoredObject {
|
||||
|
||||
private final Map<Long, StructuredData<?>> hashToStructuredData = CacheBuilder.newBuilder().concurrencyLevel(1).maximumSize(256).<Long, StructuredData<?>>build().asMap();
|
||||
private final List<Identifier> enchantmentRegistry = new ArrayList<>();
|
||||
private final ItemComponentConverter itemComponentConverter;
|
||||
|
||||
public ItemComponentHashStorage(final UserConnection user, final MappingData mappingData) {
|
||||
super(user);
|
||||
this.itemComponentConverter = new ItemComponentConverter(new RegistryAccess() {
|
||||
@Override
|
||||
public Identifier getItem(final int networkId) {
|
||||
final String identifier = mappingData.getFullItemMappings().mappedIdentifier(networkId);
|
||||
if (identifier != null) {
|
||||
return Identifier.of(identifier);
|
||||
} else {
|
||||
return Identifier.of("viaproxy", "unknown/item/" + networkId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getEnchantment(final int networkId) {
|
||||
if (networkId >= 0 && networkId < ItemComponentHashStorage.this.enchantmentRegistry.size()) {
|
||||
return ItemComponentHashStorage.this.enchantmentRegistry.get(networkId);
|
||||
} else {
|
||||
return Identifier.of("viaproxy", "unknown/enchantment/" + networkId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setEnchantmentRegistry(final List<Identifier> enchantmentRegistry) {
|
||||
this.enchantmentRegistry.clear();
|
||||
this.enchantmentRegistry.addAll(enchantmentRegistry);
|
||||
}
|
||||
|
||||
public void trackStructuredData(final StructuredData<?> structuredData) {
|
||||
if (structuredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Pair<ItemComponent<?>, Object> itemComponent = this.itemComponentConverter.viaToMcStructs(structuredData);
|
||||
if (itemComponent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int hash = itemComponent.key().getCodec().serialize(HashConverter_v1_21_5.CRC32C, cast(itemComponent.value())).getOrThrow().asInt();
|
||||
final long key = (long) structuredData.id() << 32 | hash;
|
||||
if (!this.hashToStructuredData.containsKey(key)) {
|
||||
this.hashToStructuredData.put(key, structuredData.copy());
|
||||
}
|
||||
}
|
||||
|
||||
public StructuredData<?> getStructuredData(final int componentId, final int hash) {
|
||||
final long key = (long) componentId << 32 | hash;
|
||||
if (this.hashToStructuredData.containsKey(key)) {
|
||||
return this.hashToStructuredData.get(key).copy();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T cast(final Object o) {
|
||||
return (T) o;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2021-2025 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.protocoltranslator.viaproxy.item_component_hasher;
|
||||
|
||||
import com.viaversion.nbt.tag.*;
|
||||
import net.lenni0451.mcstructs.nbt.NbtTag;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class NbtConverter {
|
||||
|
||||
public static Tag mcStructsToVia(final NbtTag tag) {
|
||||
if (tag == null) return null;
|
||||
return switch (tag.getNbtType()) {
|
||||
case END -> throw new UnsupportedOperationException();
|
||||
case BYTE -> new ByteTag(tag.asByteTag().getValue());
|
||||
case SHORT -> new ShortTag(tag.asShortTag().getValue());
|
||||
case INT -> new IntTag(tag.asIntTag().getValue());
|
||||
case LONG -> new LongTag(tag.asLongTag().getValue());
|
||||
case FLOAT -> new FloatTag(tag.asFloatTag().getValue());
|
||||
case DOUBLE -> new DoubleTag(tag.asDoubleTag().getValue());
|
||||
case BYTE_ARRAY -> new ByteArrayTag(tag.asByteArrayTag().getValue());
|
||||
case STRING -> new StringTag(tag.asStringTag().getValue());
|
||||
case LIST -> {
|
||||
final ListTag<? super Tag> listTag = new ListTag<>(Collections.emptyList());
|
||||
for (NbtTag subTag : tag.asListTag()) {
|
||||
listTag.add(mcStructsToVia(subTag));
|
||||
}
|
||||
yield listTag;
|
||||
}
|
||||
case COMPOUND -> {
|
||||
final CompoundTag compoundTag = new CompoundTag();
|
||||
for (Map.Entry<String, NbtTag> entry : tag.asCompoundTag()) {
|
||||
compoundTag.put(entry.getKey(), mcStructsToVia(entry.getValue()));
|
||||
}
|
||||
yield compoundTag;
|
||||
}
|
||||
case INT_ARRAY -> new IntArrayTag(tag.asIntArrayTag().getValue());
|
||||
case LONG_ARRAY -> new LongArrayTag(tag.asLongArrayTag().getValue());
|
||||
};
|
||||
}
|
||||
|
||||
public static NbtTag viaToMcStructs(final Tag tag) {
|
||||
if (tag == null) return null;
|
||||
if (tag instanceof ByteTag byteTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.ByteTag(byteTag.asByte());
|
||||
} else if (tag instanceof ShortTag shortTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.ShortTag(shortTag.asShort());
|
||||
} else if (tag instanceof IntTag intTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.IntTag(intTag.asInt());
|
||||
} else if (tag instanceof LongTag longTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.LongTag(longTag.asLong());
|
||||
} else if (tag instanceof FloatTag floatTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.FloatTag(floatTag.asFloat());
|
||||
} else if (tag instanceof DoubleTag doubleTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.DoubleTag(doubleTag.asDouble());
|
||||
} else if (tag instanceof ByteArrayTag byteArrayTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.ByteArrayTag(byteArrayTag.getValue());
|
||||
} else if (tag instanceof StringTag stringTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.StringTag(stringTag.getValue());
|
||||
} else if (tag instanceof ListTag<?> listTag) {
|
||||
final net.lenni0451.mcstructs.nbt.tags.ListTag<NbtTag> mcListTag = new net.lenni0451.mcstructs.nbt.tags.ListTag<>();
|
||||
for (Tag subTag : listTag) {
|
||||
mcListTag.add(viaToMcStructs(subTag));
|
||||
}
|
||||
return mcListTag;
|
||||
} else if (tag instanceof CompoundTag compoundTag) {
|
||||
final net.lenni0451.mcstructs.nbt.tags.CompoundTag mcCompoundTag = new net.lenni0451.mcstructs.nbt.tags.CompoundTag();
|
||||
for (Map.Entry<String, Tag> entry : compoundTag.entrySet()) {
|
||||
mcCompoundTag.add(entry.getKey(), viaToMcStructs(entry.getValue()));
|
||||
}
|
||||
return mcCompoundTag;
|
||||
} else if (tag instanceof IntArrayTag intArrayTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.IntArrayTag(intArrayTag.getValue());
|
||||
} else if (tag instanceof LongArrayTag longArrayTag) {
|
||||
return new net.lenni0451.mcstructs.nbt.tags.LongArrayTag(longArrayTag.getValue());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unknown tag type: " + tag.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2021-2025 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.protocoltranslator.viaproxy.item_component_hasher;
|
||||
|
||||
import net.lenni0451.mcstructs.core.Identifier;
|
||||
|
||||
public interface RegistryAccess {
|
||||
|
||||
Identifier getItem(final int networkId);
|
||||
|
||||
Identifier getEnchantment(final int networkId);
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue