Prepare for hashed item rewriting
This commit is contained in:
27 files changed
+452
-106
No files matched your search
@@ -22,19 +22,18 @@ dependencies {
|
||||
api(libs.gson) {
|
||||
exclude("com.google.errorprone", "error_prone_annotations")
|
||||
}
|
||||
api(libs.guava) {
|
||||
exclude("com.google.errorprone", "error_prone_annotations")
|
||||
exclude("org.jspecify", "jspecify")
|
||||
exclude("com.google.j2objc", "j2objc-annotations")
|
||||
}
|
||||
implementation(rootProject.libs.text) {
|
||||
exclude("com.google.code.gson", "gson")
|
||||
exclude("com.google.guava", "guava")
|
||||
exclude("com.viaversion", "nbt")
|
||||
}
|
||||
api(libs.snakeYaml)
|
||||
|
||||
compileOnlyApi(libs.netty)
|
||||
compileOnlyApi(libs.guava) {
|
||||
exclude("com.google.errorprone", "error_prone_annotations")
|
||||
exclude("org.jspecify", "jspecify")
|
||||
exclude("com.google.j2objc", "j2objc-annotations")
|
||||
}
|
||||
compileOnlyApi(libs.checkerQual)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.connection;
|
||||
|
||||
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
|
||||
import com.viaversion.viaversion.api.data.entity.EntityTracker;
|
||||
import com.viaversion.viaversion.api.data.item.ItemHasher;
|
||||
import com.viaversion.viaversion.api.minecraft.ClientWorld;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketTracker;
|
||||
@@ -99,6 +100,23 @@ public interface UserConnection {
|
||||
*/
|
||||
void addEntityTracker(Class<? extends Protocol> protocolClass, EntityTracker tracker);
|
||||
|
||||
/**
|
||||
* Adds an item hasher to the user connection.
|
||||
*
|
||||
* @param protocolClass protocol class
|
||||
* @param itemHasher item hasher
|
||||
*/
|
||||
void addItemHasher(Class<? extends Protocol> protocolClass, ItemHasher itemHasher);
|
||||
|
||||
/**
|
||||
* Returns the item hasher by the given protocol class if present.
|
||||
*
|
||||
* @param protocolClass protocol class
|
||||
* @param <T> item hasher type
|
||||
* @return item hasher if present
|
||||
*/
|
||||
@Nullable <T extends ItemHasher> T getItemHasher(Class<? extends Protocol> protocolClass);
|
||||
|
||||
/**
|
||||
* Returns the client world by the given protocol class if present.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
||||
* Copyright (C) 2016-2025 ViaVersion and contributors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.data.item;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Used for converting items to hashed items and caching them for later use during serverbound packets.
|
||||
* <p>
|
||||
* Most of this stays in the internal module given non-permanent, imperfect caching as well as missing converters.
|
||||
*/
|
||||
public interface ItemHasher {
|
||||
|
||||
/**
|
||||
* Returns whether this connection is currently processing a clientbound player inventory packet.
|
||||
* <p>
|
||||
* Used for checking when it is necessary to track/process item data hashes.
|
||||
*
|
||||
* @return true if processing a clientbound inventory packet, false otherwise
|
||||
*/
|
||||
boolean isProcessingClientboundInventoryPacket();
|
||||
|
||||
void setProcessingClientboundInventoryPacket(boolean processingClientboundInventoryPacket);
|
||||
|
||||
/**
|
||||
* Sets the enchantment registry for this connection.
|
||||
*
|
||||
* @param enchantments list of enchantment identifiers
|
||||
*/
|
||||
void setEnchantments(List<String> enchantments);
|
||||
}
|
||||
+4
@@ -284,6 +284,10 @@ public final class StructuredDataContainer implements Copyable {
|
||||
return data;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return data.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StructuredDataContainer{" +
|
||||
|
||||
@@ -39,4 +39,7 @@ public interface HashedItem extends ItemBase {
|
||||
Int2IntMap dataHashesById();
|
||||
|
||||
IntSet removedDataIds();
|
||||
|
||||
@Override
|
||||
HashedItem copy();
|
||||
}
|
||||
+5
@@ -79,6 +79,11 @@ public class HashedStructuredItem implements HashedItem {
|
||||
return this.removedData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashedItem copy() {
|
||||
return new HashedStructuredItem(identifier, amount, new Int2IntOpenHashMap(dataHashes), new IntOpenHashSet(removedData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
|
||||
import com.viaversion.viaversion.util.Copyable;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public interface Item extends ItemBase, Copyable {
|
||||
public interface Item extends ItemBase {
|
||||
|
||||
/**
|
||||
* Returns the item data. Always 0 for 1.13+ items.
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.api.minecraft.item;
|
||||
|
||||
import com.viaversion.viaversion.util.Copyable;
|
||||
|
||||
/**
|
||||
* @see Item
|
||||
* @see HashedItem
|
||||
*/
|
||||
public interface ItemBase {
|
||||
public interface ItemBase extends Copyable {
|
||||
|
||||
/**
|
||||
* Returns the item identifier.
|
||||
@@ -64,4 +66,7 @@ public interface ItemBase {
|
||||
default boolean isEmpty() {
|
||||
return identifier() == 0 || amount() <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
ItemBase copy();
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.google.common.base.Preconditions;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.entity.EntityTracker;
|
||||
import com.viaversion.viaversion.api.data.item.ItemHasher;
|
||||
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
|
||||
import com.viaversion.viaversion.api.protocol.packet.Direction;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketType;
|
||||
@@ -247,6 +248,10 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
|
||||
connection.addEntityTracker(this.getClass(), tracker);
|
||||
}
|
||||
|
||||
protected void addItemHasher(UserConnection connection, ItemHasher hasher) {
|
||||
connection.addItemHasher(this.getClass(), hasher);
|
||||
}
|
||||
|
||||
protected PacketTypesProvider<CU, CM, SM, SU> createPacketTypesProvider() {
|
||||
return new SimplePacketTypesProvider<>(
|
||||
packetTypeMap(unmappedClientboundPacketType, unmappedClientboundPacketType),
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
package com.viaversion.viaversion.api.rewriter;
|
||||
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.item.HashedItem;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
@@ -50,6 +51,17 @@ public interface ItemRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter<T
|
||||
@Nullable
|
||||
Item handleItemToServer(UserConnection connection, @Nullable Item item);
|
||||
|
||||
/**
|
||||
* Returns the rewritten item, which may or may not be the same given HashedItem instance.
|
||||
* <p>
|
||||
* Used starting with 1.22.
|
||||
*
|
||||
* @param connection user connection
|
||||
* @param item hashed item
|
||||
* @return rewritten hashed item
|
||||
*/
|
||||
HashedItem handleHashedItem(UserConnection connection, HashedItem item);
|
||||
|
||||
/**
|
||||
* Returns the item type of the current protocol.
|
||||
*
|
||||
|
||||
@@ -43,7 +43,6 @@ publishing {
|
||||
|
||||
fun ShadowJar.configureRelocations() {
|
||||
relocate("com.google.gson", "com.viaversion.viaversion.libs.gson")
|
||||
relocate("com.google.common", "com.viaversion.viaversion.libs.guava")
|
||||
relocate("it.unimi.dsi.fastutil", "com.viaversion.viaversion.libs.fastutil")
|
||||
relocate("net.lenni0451.mcstructs", "com.viaversion.viaversion.libs.mcstructs")
|
||||
relocate("org.yaml.snakeyaml", "com.viaversion.viaversion.libs.snakeyaml")
|
||||
|
||||
@@ -2,7 +2,6 @@ dependencies {
|
||||
api(projects.viaversionApi)
|
||||
api(rootProject.libs.bundles.mcstructs) {
|
||||
exclude("com.google.code.gson", "gson")
|
||||
exclude("com.google.guava", "guava")
|
||||
exclude("com.viaversion", "nbt")
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ public class ProtocolInfoImpl implements ProtocolInfo {
|
||||
private String username;
|
||||
private UUID uuid;
|
||||
private ProtocolPipeline pipeline;
|
||||
private boolean processingClientboundInventoryPacket;
|
||||
|
||||
@Override
|
||||
public State getClientState() {
|
||||
@@ -110,21 +109,6 @@ public class ProtocolInfoImpl implements ProtocolInfo {
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this connection is currently processing a clientbound player inventory packet.
|
||||
* <p>
|
||||
* Used for checking when it is necessary to track/process item data hashes.
|
||||
*
|
||||
* @return true if processing a clientbound inventory packet, false otherwise
|
||||
*/
|
||||
public boolean isProcessingClientboundInventoryPacket() {
|
||||
return processingClientboundInventoryPacket;
|
||||
}
|
||||
|
||||
public void setProcessingClientboundInventoryPacket(final boolean processingClientboundInventoryPacket) {
|
||||
this.processingClientboundInventoryPacket = processingClientboundInventoryPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProtocolInfo{" +
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.viaversion.viaversion.api.connection.ProtocolInfo;
|
||||
import com.viaversion.viaversion.api.connection.StorableObject;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.entity.EntityTracker;
|
||||
import com.viaversion.viaversion.api.data.item.ItemHasher;
|
||||
import com.viaversion.viaversion.api.minecraft.ClientWorld;
|
||||
import com.viaversion.viaversion.api.platform.ViaInjector;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
@@ -60,6 +61,7 @@ public class UserConnectionImpl implements UserConnection {
|
||||
private final long id = IDS.incrementAndGet();
|
||||
private final Map<Class<?>, StorableObject> storedObjects = new ConcurrentHashMap<>();
|
||||
private final Map<Class<? extends Protocol>, EntityTracker> entityTrackers = new HashMap<>();
|
||||
private final Map<Class<? extends Protocol>, ItemHasher> itemHashers = new HashMap<>();
|
||||
private final Map<Class<? extends Protocol>, ClientWorld> clientWorlds = new HashMap<>();
|
||||
private final PacketTracker packetTracker = new PacketTracker(this);
|
||||
private final Set<UUID> passthroughTokens = Collections.newSetFromMap(CacheBuilder.newBuilder()
|
||||
@@ -131,6 +133,16 @@ public class UserConnectionImpl implements UserConnection {
|
||||
entityTrackers.putIfAbsent(protocolClass, tracker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addItemHasher(final Class<? extends Protocol> protocolClass, final ItemHasher itemHasher) {
|
||||
itemHashers.putIfAbsent(protocolClass, itemHasher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable <T extends ItemHasher> T getItemHasher(Class<? extends Protocol> protocolClass) {
|
||||
return (T) itemHashers.get(protocolClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable <T extends ClientWorld> T getClientWorld(final Class<? extends Protocol> protocolClass) {
|
||||
return (T) clientWorlds.get(protocolClass);
|
||||
@@ -160,6 +172,7 @@ public class UserConnectionImpl implements UserConnection {
|
||||
}
|
||||
storedObjects.clear();
|
||||
entityTrackers.clear();
|
||||
itemHashers.clear();
|
||||
clientWorlds.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
||||
* Copyright (C) 2016-2025 ViaVersion 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 com.viaversion.viaversion.data.item;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.viaversion.nbt.tag.CompoundTag;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.data.item.ItemHasher;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
|
||||
import com.viaversion.viaversion.api.minecraft.item.HashedItem;
|
||||
import com.viaversion.viaversion.api.minecraft.item.HashedStructuredItem;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.rewriter.item.ItemDataComponentConverter;
|
||||
import com.viaversion.viaversion.rewriter.item.ItemDataComponentConverter.RegistryAccess;
|
||||
import com.viaversion.viaversion.util.SerializerVersion;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.lenni0451.mcstructs.converter.impl.v1_21_5.HashConverter_v1_21_5;
|
||||
import net.lenni0451.mcstructs.itemcomponents.ItemComponentRegistry;
|
||||
import net.lenni0451.mcstructs.itemcomponents.impl.v1_21_5.ItemComponents_v1_21_5;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ItemHasherBase implements ItemHasher {
|
||||
|
||||
public static final int UNKNOWN_HASH = Integer.MIN_VALUE;
|
||||
private final Map<Integer, HashedItem> hashes = CacheBuilder.newBuilder().concurrencyLevel(1).maximumSize(1024).<Integer, HashedItem>build().asMap();
|
||||
private final List<String> enchantments = new ArrayList<>();
|
||||
private final ItemDataComponentConverter itemComponentConverter;
|
||||
protected final UserConnection connection;
|
||||
private boolean processingClientboundInventoryPacket;
|
||||
|
||||
public ItemHasherBase(final UserConnection connection, final SerializerVersion serializerVersion, final MappingData mappingData) {
|
||||
final RegistryAccess registryAccess = RegistryAccess.of(
|
||||
this.enchantments,
|
||||
ItemComponentRegistry.V1_21_5.getRegistries(), // Unused outside of file deserialization
|
||||
mappingData
|
||||
);
|
||||
this.itemComponentConverter = new ItemDataComponentConverter(serializerVersion, registryAccess);
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnchantments(final List<String> enchantments) {
|
||||
this.enchantments.clear();
|
||||
this.enchantments.addAll(enchantments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hashed item for the given item. Not all data may be successfully hashed.
|
||||
*
|
||||
* @param item the item to hash
|
||||
* @return the hashed item
|
||||
*/
|
||||
public HashedItem toHashedItem(final Item item) {
|
||||
return toHashedItem(this.itemComponentConverter, item);
|
||||
}
|
||||
|
||||
public static HashedItem toHashedItem(final ItemDataComponentConverter converter, final Item item) {
|
||||
final HashedItem hashedItem = new HashedStructuredItem(item.identifier(), item.amount());
|
||||
for (final StructuredData<?> data : item.dataContainer().data().values()) {
|
||||
if (data.isEmpty()) {
|
||||
hashedItem.removedDataIds().add(data.id());
|
||||
continue;
|
||||
}
|
||||
|
||||
final ItemDataComponentConverter.Result<?> result = converter.viaToMcStructs(data);
|
||||
final int hash = result != null ? hash(result) : UNKNOWN_HASH;
|
||||
hashedItem.dataHashesById().put(data.id(), hash);
|
||||
}
|
||||
return hashedItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks the data for the given data container, storing the original hashes via the now transformed data hashes.
|
||||
*
|
||||
* @param customData custom_data tag
|
||||
* @param originalHashedItem the original (pre-transformed) hashed item
|
||||
*/
|
||||
public void trackOriginalHashedItem(final CompoundTag customData, final HashedItem originalHashedItem) {
|
||||
// Store them via the custom_data hash, which includes the original data hashes.
|
||||
// Not perfect (as opposed to storing it by the full hashed item), but good enough. In the rare occasion there is a collision, we ignore it without issues.
|
||||
final int customDataHash = hashTag(customData);
|
||||
this.hashes.put(customDataHash, originalHashedItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the original hashed item for a given custom_data hash.
|
||||
*
|
||||
* @param customDataHash custom_data hash
|
||||
* @param clientItem the hashed item from the client that the original should be retrieved for
|
||||
* @return the original hashed item, or null if not found
|
||||
*/
|
||||
public @Nullable HashedItem originalHashedItem(final int customDataHash, final HashedItem clientItem) {
|
||||
HashedItem originalItem = this.hashes.get(customDataHash);
|
||||
if (originalItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
originalItem = originalItem.copy();
|
||||
|
||||
// Take hashes for data we couldn't calculate the hash of from the client item, more likely than not it's the same
|
||||
for (final Int2IntMap.Entry entry : originalItem.dataHashesById().int2IntEntrySet()) {
|
||||
final int typeId = entry.getIntKey();
|
||||
if (entry.getIntValue() == UNKNOWN_HASH && clientItem.dataHashesById().containsKey(typeId)) {
|
||||
final int clientProvidedHash = clientItem.dataHashesById().get(typeId);
|
||||
originalItem.dataHashesById().put(typeId, clientProvidedHash);
|
||||
}
|
||||
}
|
||||
return originalItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessingClientboundInventoryPacket() {
|
||||
return processingClientboundInventoryPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProcessingClientboundInventoryPacket(final boolean processingClientboundInventoryPacket) {
|
||||
this.processingClientboundInventoryPacket = processingClientboundInventoryPacket;
|
||||
}
|
||||
|
||||
private static <T> int hash(final ItemDataComponentConverter.Result<T> result) {
|
||||
return result.type().getCodec().serialize(HashConverter_v1_21_5.CRC32C, result.value()).getOrThrow().asInt();
|
||||
}
|
||||
|
||||
private int hashTag(final CompoundTag tag) {
|
||||
return ItemComponents_v1_21_5.V1_21_5.CUSTOM_DATA.getCodec().serialize(HashConverter_v1_21_5.CRC32C, tag).getOrThrow().asInt();
|
||||
}
|
||||
}
|
||||
+19
@@ -17,9 +17,13 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.template;
|
||||
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.item.HashedItem;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21_5;
|
||||
import com.viaversion.viaversion.data.item.ItemHasherBase;
|
||||
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4;
|
||||
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4;
|
||||
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.RecipeDisplayRewriter1_21_5;
|
||||
@@ -77,4 +81,19 @@ final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<Clientbou
|
||||
// OR do this if serialization of recipes changed and override the relevant method
|
||||
// Add new serializers to RecipeDisplayRewriter, or extend the last one for changes
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item handleItemToClient(final UserConnection connection, final Item item) {
|
||||
if (item.isEmpty()) {
|
||||
return item;
|
||||
}
|
||||
|
||||
final ItemHasherBase itemHasher = itemHasher(connection); // get the original hashed item and store it later if there are any changes that could affect the data hashes
|
||||
final HashedItem originalHashedItem = hashItem(item, itemHasher);
|
||||
|
||||
super.handleItemToClient(connection, item);
|
||||
|
||||
storeOriginalHashedItem(item, itemHasher, originalHashedItem); // has to be called AFTER all modifications
|
||||
return item;
|
||||
}
|
||||
}
|
||||
+3
@@ -26,6 +26,7 @@ import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvide
|
||||
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
|
||||
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
|
||||
import com.viaversion.viaversion.data.item.ItemHasherBase;
|
||||
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5;
|
||||
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
|
||||
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4;
|
||||
@@ -38,6 +39,7 @@ import com.viaversion.viaversion.rewriter.ParticleRewriter;
|
||||
import com.viaversion.viaversion.rewriter.SoundRewriter;
|
||||
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
|
||||
import com.viaversion.viaversion.rewriter.TagRewriter;
|
||||
import com.viaversion.viaversion.util.SerializerVersion;
|
||||
|
||||
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
|
||||
|
||||
@@ -137,6 +139,7 @@ final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21_2,
|
||||
public void init(final UserConnection connection) {
|
||||
// Register the entity tracker - used for entity id/entity data rewriting AND for tracking world data sent to the client (then used for chunk data rewriting)
|
||||
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_4.PLAYER));
|
||||
addItemHasher(connection, new ItemHasherBase(connection, SerializerVersion.V1_21_5, MAPPINGS));
|
||||
}
|
||||
|
||||
// Overriding these four methods is important as they are relied on various rewriter classes
|
||||
|
||||
+1
-1
@@ -211,8 +211,8 @@ public final class Protocol1_21_4To1_21_5 extends AbstractProtocol<ClientboundPa
|
||||
@Override
|
||||
public void init(final UserConnection connection) {
|
||||
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_4.PLAYER));
|
||||
addItemHasher(connection, new ItemHashStorage1_21_5(MAPPINGS));
|
||||
connection.put(new MessageIndexStorage());
|
||||
connection.put(new ItemHashStorage1_21_5(connection, MAPPINGS));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-5
@@ -63,7 +63,6 @@ import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
|
||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_21_5;
|
||||
import com.viaversion.viaversion.connection.ProtocolInfoImpl;
|
||||
import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
|
||||
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;
|
||||
@@ -345,10 +344,10 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
|
||||
appendItemDataFixComponents(connection, item);
|
||||
|
||||
// Store the data components if necessary for the server, the client only sends data hashes now
|
||||
if (((ProtocolInfoImpl) connection.getProtocolInfo()).isProcessingClientboundInventoryPacket()) {
|
||||
final ItemHashStorage1_21_5 hasher = connection.get(ItemHashStorage1_21_5.class);
|
||||
final ItemHashStorage1_21_5 itemHasher = itemHasher(connection);
|
||||
if (itemHasher.isProcessingClientboundInventoryPacket()) {
|
||||
for (final StructuredData<?> data : dataContainer.data().values()) {
|
||||
hasher.trackStructuredData(data);
|
||||
itemHasher.trackStructuredData(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +494,7 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
|
||||
|
||||
private StructuredItem convertHashedItemToStructuredItem(final UserConnection connection, final HashedItem hashedItem) {
|
||||
final StructuredItem item = new StructuredItem(hashedItem.identifier(), hashedItem.amount());
|
||||
final ItemHashStorage1_21_5 hasher = connection.get(ItemHashStorage1_21_5.class);
|
||||
final ItemHashStorage1_21_5 hasher = itemHasher(connection);
|
||||
final Map<StructuredDataKey<?>, StructuredData<?>> structuredDataMap = item.dataContainer().data();
|
||||
for (final Int2IntMap.Entry hashEntry : hashedItem.dataHashesById().int2IntEntrySet()) {
|
||||
final StructuredData<?> structuredData = hasher.dataFromHash(hashEntry.getIntKey(), hashEntry.getIntValue());
|
||||
|
||||
-12
@@ -32,18 +32,14 @@ import com.viaversion.viaversion.api.type.types.version.Types1_21_5;
|
||||
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.ClientboundPackets1_21_5;
|
||||
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.storage.ItemHashStorage1_21_5;
|
||||
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.storage.MessageIndexStorage;
|
||||
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
|
||||
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
|
||||
import com.viaversion.viaversion.rewriter.EntityRewriter;
|
||||
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
|
||||
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import net.lenni0451.mcstructs.core.Identifier;
|
||||
|
||||
public final class EntityPacketRewriter1_21_5 extends EntityRewriter<ClientboundPacket1_21_2, Protocol1_21_4To1_21_5> {
|
||||
private static final int ATTACK_BLOCKED_ENTITY_EVENT = 29;
|
||||
@@ -83,14 +79,6 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
|
||||
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol) {
|
||||
@Override
|
||||
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
|
||||
if (key.equals("enchantment")) {
|
||||
final List<Identifier> identifiers = new ArrayList<>();
|
||||
for (final RegistryEntry entry : entries) {
|
||||
identifiers.add(Identifier.of(entry.key()));
|
||||
}
|
||||
connection.get(ItemHashStorage1_21_5.class).setEnchantmentRegistry(identifiers);
|
||||
}
|
||||
|
||||
if (!key.equals("wolf_variant")) {
|
||||
return super.handle(connection, key, entries);
|
||||
}
|
||||
|
||||
+20
-10
@@ -18,34 +18,34 @@
|
||||
package com.viaversion.viaversion.protocols.v1_21_4to1_21_5.storage;
|
||||
|
||||
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.data.item.ItemHasher;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
|
||||
import com.viaversion.viaversion.rewriter.item.ItemDataComponentConverter;
|
||||
import com.viaversion.viaversion.rewriter.item.ItemDataComponentConverter.RegistryAccess;
|
||||
import com.viaversion.viaversion.util.SerializerVersion;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.lenni0451.mcstructs.converter.impl.v1_21_5.HashConverter_v1_21_5;
|
||||
import net.lenni0451.mcstructs.core.Identifier;
|
||||
import net.lenni0451.mcstructs.itemcomponents.ItemComponentRegistry;
|
||||
|
||||
public class ItemHashStorage1_21_5 extends StoredObject {
|
||||
public class ItemHashStorage1_21_5 implements ItemHasher {
|
||||
|
||||
private final Map<Long, StructuredData<?>> hashToStructuredData = CacheBuilder.newBuilder().concurrencyLevel(1).maximumSize(512).<Long, StructuredData<?>>build().asMap();
|
||||
private final List<Identifier> enchantmentRegistry = new ArrayList<>();
|
||||
private final List<String> enchantmentRegistry = new ArrayList<>();
|
||||
private final ItemDataComponentConverter itemComponentConverter;
|
||||
private boolean processingClientboundInventoryPacket;
|
||||
|
||||
public ItemHashStorage1_21_5(final UserConnection connection, final MappingData mappingData) {
|
||||
super(connection);
|
||||
public ItemHashStorage1_21_5(final MappingData mappingData) {
|
||||
final RegistryAccess registryAccess = RegistryAccess.of(this.enchantmentRegistry, ItemComponentRegistry.V1_21_5.getRegistries(), mappingData);
|
||||
this.itemComponentConverter = new ItemDataComponentConverter(registryAccess);
|
||||
this.itemComponentConverter = new ItemDataComponentConverter(SerializerVersion.V1_21_5, registryAccess);
|
||||
}
|
||||
|
||||
public void setEnchantmentRegistry(final List<Identifier> enchantmentRegistry) {
|
||||
@Override
|
||||
public void setEnchantments(final List<String> enchantments) {
|
||||
this.enchantmentRegistry.clear();
|
||||
this.enchantmentRegistry.addAll(enchantmentRegistry);
|
||||
this.enchantmentRegistry.addAll(enchantments);
|
||||
}
|
||||
|
||||
public void trackStructuredData(final StructuredData<?> structuredData) {
|
||||
@@ -71,4 +71,14 @@ public class ItemHashStorage1_21_5 extends StoredObject {
|
||||
private static <T> int hash(final ItemDataComponentConverter.Result<T> result) {
|
||||
return result.type().getCodec().serialize(HashConverter_v1_21_5.CRC32C, result.value()).getOrThrow().asInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessingClientboundInventoryPacket() {
|
||||
return this.processingClientboundInventoryPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProcessingClientboundInventoryPacket(final boolean processingClientboundInventoryPacket) {
|
||||
this.processingClientboundInventoryPacket = processingClientboundInventoryPacket;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.FullMappings;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.data.Mappings;
|
||||
import com.viaversion.viaversion.api.data.item.ItemHasher;
|
||||
import com.viaversion.viaversion.api.minecraft.item.HashedItem;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
@@ -34,7 +35,7 @@ import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
|
||||
import com.viaversion.viaversion.api.rewriter.RewriterBase;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.connection.ProtocolInfoImpl;
|
||||
import com.viaversion.viaversion.data.item.ItemHasherBase;
|
||||
import com.viaversion.viaversion.util.Limit;
|
||||
import com.viaversion.viaversion.util.Rewritable;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
@@ -94,6 +95,35 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashedItem handleHashedItem(final UserConnection connection, final HashedItem item) {
|
||||
final MappingData mappingData = protocol.getMappingData();
|
||||
if (mappingData == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
final FullMappings dataComponentMappings = mappingData.getDataComponentSerializerMappings();
|
||||
if (dataComponentMappings != null) {
|
||||
updateHashedItemDataComponentIds(item, dataComponentMappings.inverse());
|
||||
|
||||
final int customDataId = dataComponentMappings.id("custom_data");
|
||||
if (item.dataHashesById().containsKey(customDataId)) {
|
||||
// Use the original hashed item if we can find it in the cache
|
||||
final int customDataHash = item.dataHashesById().get(customDataId);
|
||||
final ItemHasherBase itemHasher = itemHasher(connection);
|
||||
final HashedItem originalHashedItem = itemHasher.originalHashedItem(customDataHash, item);
|
||||
if (originalHashedItem != null) {
|
||||
return originalHashedItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mappingData.getItemMappings() != null) {
|
||||
item.setIdentifier(mappingData.getOldItemId(item.identifier()));
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public void registerSetContent(C packetType) {
|
||||
protocol.registerClientbound(packetType, wrapper -> {
|
||||
wrapper.passthrough(Types.UNSIGNED_BYTE); // Container id
|
||||
@@ -499,22 +529,31 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
|
||||
}
|
||||
|
||||
protected @Nullable Item handleItemToClientAndTrackHash(final UserConnection connection, @Nullable Item item) {
|
||||
final ProtocolInfoImpl protocolInfo = (ProtocolInfoImpl) connection.getProtocolInfo();
|
||||
protocolInfo.setProcessingClientboundInventoryPacket(true);
|
||||
final ItemHasher itemHasher = itemHasher(connection);
|
||||
if (itemHasher == null) {
|
||||
return handleItemToClient(connection, item);
|
||||
}
|
||||
|
||||
itemHasher.setProcessingClientboundInventoryPacket(true);
|
||||
try {
|
||||
return this.handleItemToClient(connection, item);
|
||||
} finally {
|
||||
protocolInfo.setProcessingClientboundInventoryPacket(false);
|
||||
itemHasher.setProcessingClientboundInventoryPacket(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void passthroughClientboundItemAndTrackHash(final PacketWrapper wrapper) {
|
||||
final ProtocolInfoImpl protocolInfo = (ProtocolInfoImpl) wrapper.user().getProtocolInfo();
|
||||
protocolInfo.setProcessingClientboundInventoryPacket(true);
|
||||
final ItemHasher itemHasher = itemHasher(wrapper.user());
|
||||
if (itemHasher == null) {
|
||||
passthroughClientboundItem(wrapper);
|
||||
return;
|
||||
}
|
||||
|
||||
itemHasher.setProcessingClientboundInventoryPacket(true);
|
||||
try {
|
||||
this.passthroughClientboundItem(wrapper);
|
||||
} finally {
|
||||
protocolInfo.setProcessingClientboundInventoryPacket(false);
|
||||
itemHasher.setProcessingClientboundInventoryPacket(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,20 +563,12 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
|
||||
}
|
||||
|
||||
protected void passthroughHashedItem(final PacketWrapper wrapper) {
|
||||
final HashedItem item = wrapper.passthrough(Types.HASHED_ITEM);
|
||||
final MappingData mappingData = protocol.getMappingData();
|
||||
if (mappingData == null) {
|
||||
return;
|
||||
}
|
||||
final HashedItem item = handleHashedItem(wrapper.user(), wrapper.read(Types.HASHED_ITEM));
|
||||
wrapper.write(Types.HASHED_ITEM, item);
|
||||
}
|
||||
|
||||
if (mappingData.getItemMappings() != null) {
|
||||
item.setIdentifier(mappingData.getOldItemId(item.identifier()));
|
||||
}
|
||||
|
||||
final FullMappings dataComponentMappings = protocol.getMappingData().getDataComponentSerializerMappings();
|
||||
if (dataComponentMappings != null) {
|
||||
updateHashedItemDataComponentIds(item, dataComponentMappings.inverse());
|
||||
}
|
||||
protected <T extends ItemHasher> @Nullable T itemHasher(final UserConnection connection) {
|
||||
return connection.getItemHasher(protocol.getClass());
|
||||
}
|
||||
|
||||
protected void updateHashedItemDataComponentIds(final HashedItem item, final FullMappings mappings) {
|
||||
@@ -549,9 +580,10 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
|
||||
continue;
|
||||
}
|
||||
|
||||
// Let's hope the hash didn't change...
|
||||
final int hash = addedData.remove(id);
|
||||
addedData.put(mappedId, hash);
|
||||
if (mappedId != -1) {
|
||||
addedData.put(mappedId, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,7 +596,9 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
|
||||
}
|
||||
|
||||
removedData.remove(id);
|
||||
removedData.add(mappedId);
|
||||
if (mappedId != -1) {
|
||||
removedData.add(mappedId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.FullMappings;
|
||||
import com.viaversion.viaversion.api.data.entity.DimensionData;
|
||||
import com.viaversion.viaversion.api.data.item.ItemHasher;
|
||||
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
@@ -60,7 +61,7 @@ public class RegistryDataRewriter {
|
||||
public RegistryEntry[] handle(final UserConnection connection, String key, RegistryEntry[] entries) {
|
||||
key = Key.stripMinecraftNamespace(key);
|
||||
if (key.equals("enchantment")) {
|
||||
updateEnchantments(entries);
|
||||
updateEnchantments(connection, entries);
|
||||
} else if (key.equals("trim_material")) {
|
||||
updateTrimMaterials(entries);
|
||||
}
|
||||
@@ -119,8 +120,10 @@ public class RegistryDataRewriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateEnchantments(final RegistryEntry[] entries) {
|
||||
public void updateEnchantments(final UserConnection connection, final RegistryEntry[] entries) {
|
||||
final List<String> identifiers = new ArrayList<>(entries.length);
|
||||
for (final RegistryEntry entry : entries) {
|
||||
identifiers.add(entry.key());
|
||||
if (entry.tag() == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -149,6 +152,11 @@ public class RegistryDataRewriter {
|
||||
|
||||
updateAttributesFields(effects);
|
||||
}
|
||||
|
||||
final ItemHasher itemHasher = connection.getItemHasher(protocol.getClass());
|
||||
if (itemHasher != null) {
|
||||
itemHasher.setEnchantments(identifiers);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTrimMaterials(final RegistryEntry[] entries) {
|
||||
|
||||
+51
-12
@@ -18,15 +18,18 @@
|
||||
package com.viaversion.viaversion.rewriter;
|
||||
|
||||
import com.viaversion.nbt.tag.CompoundTag;
|
||||
import com.viaversion.nbt.tag.IntArrayTag;
|
||||
import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.FullMappings;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.data.item.ItemHasher;
|
||||
import com.viaversion.viaversion.api.minecraft.EitherHolder;
|
||||
import com.viaversion.viaversion.api.minecraft.Holder;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
|
||||
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
|
||||
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.data.FilterableComponent;
|
||||
import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook;
|
||||
@@ -34,8 +37,9 @@ import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
|
||||
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.connection.ProtocolInfoImpl;
|
||||
import com.viaversion.viaversion.data.item.ItemHasherBase;
|
||||
import com.viaversion.viaversion.util.Rewritable;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import java.util.Map;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
@@ -76,6 +80,36 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
|
||||
return item;
|
||||
}
|
||||
|
||||
protected @Nullable HashedItem hashItem(final Item item, @Nullable final ItemHasherBase hasher) {
|
||||
// Hash the original item from open inventory data to be able to get it back out of serverbound hashed items
|
||||
return hasher == null || !hasher.isProcessingClientboundInventoryPacket() ? null : hasher.toHashedItem(item);
|
||||
}
|
||||
|
||||
protected void storeOriginalHashedItem(final Item item, final ItemHasherBase hasher, @Nullable final HashedItem originalHashedItem) {
|
||||
if (originalHashedItem == null || item.dataContainer().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the hashed data is the same, this will also prevent unnecessary backups due to missing converters
|
||||
final HashedItem hashedItem = hasher.toHashedItem(item);
|
||||
if (hashedItem.dataHashesById().equals(originalHashedItem.dataHashesById()) && hashedItem.removedDataIds().equals(originalHashedItem.removedDataIds())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Always has to be AFTER any modification - Use the custom_data hash as a key to the original hashes.
|
||||
// This is much easier/cheaper than tracking via the full hashed item, as collisions are both acceptable and still unlikely.
|
||||
final CompoundTag originalHashes = new CompoundTag();
|
||||
for (final Int2IntMap.Entry entry : originalHashedItem.dataHashesById().int2IntEntrySet()) {
|
||||
originalHashes.putInt(Integer.toString(entry.getIntKey()), entry.getIntValue());
|
||||
}
|
||||
originalHashes.put("removed", new IntArrayTag(originalHashedItem.removedDataIds().toIntArray()));
|
||||
|
||||
final CompoundTag customTag = createCustomTag(item);
|
||||
saveTag(customTag, originalHashes, "original_hashes");
|
||||
|
||||
hasher.trackOriginalHashedItem(customTag, originalHashedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item handleItemToServer(UserConnection connection, Item item) {
|
||||
if (item.isEmpty()) {
|
||||
@@ -89,7 +123,7 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
|
||||
|
||||
updateItemDataComponentTypeIds(item.dataContainer(), false);
|
||||
updateItemDataComponents(connection, item, false);
|
||||
restoreTextComponents(item);
|
||||
restoreBackupData(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -136,14 +170,18 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
|
||||
}
|
||||
}
|
||||
|
||||
final ProtocolInfoImpl protocolInfo = ((ProtocolInfoImpl) connection.getProtocolInfo());
|
||||
final boolean processingClientboundInventoryPacket = protocolInfo.isProcessingClientboundInventoryPacket();
|
||||
protocolInfo.setProcessingClientboundInventoryPacket(false); // Don't track items inside items
|
||||
final ItemHasher itemHasher = itemHasher(connection);
|
||||
final ItemHandler itemHandler = clientbound ? this::handleItemToClient : this::handleItemToServer;
|
||||
try {
|
||||
if (itemHasher != null && itemHasher.isProcessingClientboundInventoryPacket()) {
|
||||
// Don't track items inside items
|
||||
itemHasher.setProcessingClientboundInventoryPacket(false);
|
||||
try {
|
||||
updateItemDataComponents(connection, clientbound, container, itemHandler);
|
||||
} finally {
|
||||
itemHasher.setProcessingClientboundInventoryPacket(true);
|
||||
}
|
||||
} else {
|
||||
updateItemDataComponents(connection, clientbound, container, itemHandler);
|
||||
} finally {
|
||||
protocolInfo.setProcessingClientboundInventoryPacket(processingClientboundInventoryPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,30 +241,31 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreTextComponents(final Item item) {
|
||||
protected void restoreBackupData(final Item item) {
|
||||
final StructuredDataContainer data = item.dataContainer();
|
||||
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
|
||||
if (customData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
customData.remove(nbtTagName("original_hashes"));
|
||||
|
||||
// Remove custom name
|
||||
if (customData.remove(nbtTagName("added_custom_name")) != null) {
|
||||
data.remove(StructuredDataKey.CUSTOM_NAME);
|
||||
removeCustomTag(data, customData);
|
||||
} else {
|
||||
final Tag customName = removeBackupTag(customData, "custom_name");
|
||||
if (customName != null) {
|
||||
data.set(StructuredDataKey.CUSTOM_NAME, customName);
|
||||
removeCustomTag(data, customData);
|
||||
}
|
||||
|
||||
final Tag itemName = removeBackupTag(customData, "item_name");
|
||||
if (itemName != null) {
|
||||
data.set(StructuredDataKey.ITEM_NAME, itemName);
|
||||
removeCustomTag(data, customData);
|
||||
}
|
||||
}
|
||||
|
||||
removeCustomTag(data, customData);
|
||||
}
|
||||
|
||||
protected CompoundTag createCustomTag(final Item item) {
|
||||
|
||||
+12
-10
@@ -28,6 +28,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
|
||||
import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent;
|
||||
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
|
||||
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
|
||||
import com.viaversion.viaversion.util.SerializerVersion;
|
||||
import com.viaversion.viaversion.util.Unit;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
@@ -50,15 +51,16 @@ import net.lenni0451.mcstructs.itemcomponents.registry.Registry;
|
||||
import net.lenni0451.mcstructs.itemcomponents.registry.RegistryEntry;
|
||||
import net.lenni0451.mcstructs.itemcomponents.registry.RegistryTag;
|
||||
import net.lenni0451.mcstructs.text.TextComponent;
|
||||
import net.lenni0451.mcstructs.text.serializer.TextComponentCodec;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public final class ItemDataComponentConverter {
|
||||
|
||||
private final Map<StructuredDataKey<?>, Converter<?, ?>> converters = new Reference2ObjectOpenHashMap<>();
|
||||
private final SerializerVersion serializerVersion;
|
||||
private final RegistryAccess registryAccess;
|
||||
|
||||
public ItemDataComponentConverter(final RegistryAccess registryAccess) {
|
||||
public ItemDataComponentConverter(final SerializerVersion serializerVersion, final RegistryAccess registryAccess) {
|
||||
this.serializerVersion = serializerVersion;
|
||||
this.registryAccess = registryAccess;
|
||||
this.direct(StructuredDataKey.CUSTOM_DATA, ItemComponentRegistry.V1_21_5.CUSTOM_DATA);
|
||||
this.direct(StructuredDataKey.MAX_STACK_SIZE, ItemComponentRegistry.V1_21_5.MAX_STACK_SIZE);
|
||||
@@ -84,10 +86,10 @@ public final class ItemDataComponentConverter {
|
||||
booleans.add(b);
|
||||
}
|
||||
return new Result<>(ItemComponentRegistry.V1_21_5.CUSTOM_MODEL_DATA, new Types_v1_21_4.CustomModelData(
|
||||
floats,
|
||||
booleans,
|
||||
Arrays.asList(customModelData.strings()),
|
||||
intArrayToIntList(customModelData.colors())
|
||||
floats,
|
||||
booleans,
|
||||
Arrays.asList(customModelData.strings()),
|
||||
intArrayToIntList(customModelData.colors())
|
||||
));
|
||||
});
|
||||
this.notImplemented(StructuredDataKey.TOOLTIP_DISPLAY);
|
||||
@@ -287,7 +289,7 @@ public final class ItemDataComponentConverter {
|
||||
this.register(key, value -> new Result<>(result, new RegistryTag(registry, Identifier.of(value))));
|
||||
}
|
||||
|
||||
private static Converter<Tag[], List<TextComponent>> stringArrayToTextComponentArray(final ItemComponent<List<TextComponent>> itemComponent) {
|
||||
private Converter<Tag[], List<TextComponent>> stringArrayToTextComponentArray(final ItemComponent<List<TextComponent>> itemComponent) {
|
||||
return tags -> {
|
||||
final List<TextComponent> textComponents = new ArrayList<>(tags.length);
|
||||
for (final Tag tag : tags) {
|
||||
@@ -306,8 +308,8 @@ public final class ItemDataComponentConverter {
|
||||
return new Types_v1_20_5.FireworkExplosions(explosionShape, intArrayToIntList(explosion.colors()), intArrayToIntList(explosion.fadeColors()), explosion.hasTrail(), explosion.hasTwinkle());
|
||||
}
|
||||
|
||||
private static TextComponent convertTextComponent(final Tag tag) {
|
||||
return tag != null ? TextComponentCodec.V1_21_5.deserialize(tag) : null;
|
||||
private TextComponent convertTextComponent(final Tag tag) {
|
||||
return tag != null ? this.serializerVersion.toComponent(tag) : null;
|
||||
}
|
||||
|
||||
private static List<Integer> intArrayToIntList(final int[] array) {
|
||||
@@ -392,7 +394,7 @@ public final class ItemDataComponentConverter {
|
||||
|
||||
RegistryEntry getEnchantment(final int networkId);
|
||||
|
||||
static RegistryAccess of(final List<Identifier> enchantments, final Registries registries, final MappingData mappingData) {
|
||||
static RegistryAccess of(final List<String> enchantments, final Registries registries, final MappingData mappingData) {
|
||||
return new RegistryAccessImpl(enchantments, registries, mappingData);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -25,11 +25,11 @@ import net.lenni0451.mcstructs.itemcomponents.registry.Registry;
|
||||
import net.lenni0451.mcstructs.itemcomponents.registry.RegistryEntry;
|
||||
|
||||
final class RegistryAccessImpl implements ItemDataComponentConverter.RegistryAccess {
|
||||
private final List<Identifier> enchantments;
|
||||
private final List<String> enchantments;
|
||||
private final Registries registries;
|
||||
private final MappingData mappingData;
|
||||
|
||||
RegistryAccessImpl(final List<Identifier> enchantments, final Registries registries, final MappingData mappingData) {
|
||||
RegistryAccessImpl(final List<String> enchantments, final Registries registries, final MappingData mappingData) {
|
||||
this.enchantments = enchantments;
|
||||
this.registries = registries;
|
||||
this.mappingData = mappingData;
|
||||
@@ -52,6 +52,6 @@ final class RegistryAccessImpl implements ItemDataComponentConverter.RegistryAcc
|
||||
if (networkId < 0 || networkId >= this.enchantments.size()) {
|
||||
return new RegistryEntry(registry, Identifier.of("viaversion", "unknown/enchantment/" + networkId));
|
||||
}
|
||||
return new RegistryEntry(registry, this.enchantments.get(networkId));
|
||||
return new RegistryEntry(registry, Identifier.of(this.enchantments.get(networkId)));
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,13 @@ metadata.format.version = "1.1"
|
||||
[versions]
|
||||
|
||||
gson = "2.12.1"
|
||||
guava = "33.4.8-jre" # 17.0 can be assumed by platforms, but we require newer API
|
||||
fastutil = "8.5.15"
|
||||
vianbt = "5.1.0"
|
||||
mcstructs = "5-3.1.0-SNAPSHOT"
|
||||
|
||||
# Common provided
|
||||
netty = "4.0.20.Final"
|
||||
guava = "17.0"
|
||||
snakeYaml = "2.2"
|
||||
|
||||
junit = "5.11.4"
|
||||
@@ -25,7 +25,6 @@ viaProxy = "3.4.2-SNAPSHOT"
|
||||
[libraries]
|
||||
|
||||
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
|
||||
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
|
||||
fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" }
|
||||
vianbt = { group = "com.viaversion", name = "nbt", version.ref = "vianbt" }
|
||||
# Custom version that uses ViaNBT instead of its own inbuilt NBT library
|
||||
@@ -33,6 +32,7 @@ text = { group = "com.viaversion.mcstructs", name = "text", version.ref = "mcstr
|
||||
itemDataComponents = { group = "com.viaversion.mcstructs", name = "itemcomponents", version.ref = "mcstructs" }
|
||||
|
||||
netty = { group = "io.netty", name = "netty-all", version.ref = "netty" }
|
||||
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
|
||||
snakeYaml = { group = "org.yaml", name = "snakeyaml", version.ref = "snakeYaml" }
|
||||
|
||||
jupiterApi = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" }
|
||||
|
||||
Reference in new issue
Block a user