Skip to content

Commit 50b1907

Browse files
committed
Implemented item component hashing to fix inventory issues with 1.21.5 clients on <=1.21.4 servers
1 parent c54c432 commit 50b1907

File tree

7 files changed

+728
-0
lines changed

7 files changed

+728
-0
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ dependencies {
9898
include("net.raphimc.netminecraft:all:3.1.0") {
9999
exclude group: "com.google.code.gson", module: "gson"
100100
}
101+
include "net.lenni0451.mcstructs:itemcomponents:3.0.0"
101102
include("net.raphimc:MinecraftAuth:4.1.1") {
102103
exclude group: "com.google.code.gson", module: "gson"
103104
exclude group: "org.slf4j", module: "slf4j-api"
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
3+
* Copyright (C) 2021-2025 RK_01/RaphiMC and contributors
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package net.raphimc.viaproxy.injection.mixins;
20+
21+
import com.viaversion.viaversion.api.connection.UserConnection;
22+
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
23+
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
24+
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
25+
import com.viaversion.viaversion.api.minecraft.item.HashedItem;
26+
import com.viaversion.viaversion.api.minecraft.item.Item;
27+
import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
28+
import com.viaversion.viaversion.api.type.Types;
29+
import com.viaversion.viaversion.api.type.types.version.Types1_21_5;
30+
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
31+
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
32+
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
33+
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.packet.ServerboundPacket1_21_5;
34+
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.BlockItemPacketRewriter1_21_5;
35+
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
36+
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
37+
import com.viaversion.viaversion.util.Key;
38+
import net.lenni0451.mcstructs.core.Identifier;
39+
import net.raphimc.viaproxy.protocoltranslator.viaproxy.item_component_hasher.ItemComponentHashStorage;
40+
import org.spongepowered.asm.mixin.Mixin;
41+
import org.spongepowered.asm.mixin.Unique;
42+
import org.spongepowered.asm.mixin.injection.At;
43+
import org.spongepowered.asm.mixin.injection.Inject;
44+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
45+
46+
import java.util.ArrayList;
47+
import java.util.List;
48+
import java.util.Map;
49+
50+
@Mixin(value = BlockItemPacketRewriter1_21_5.class, remap = false)
51+
public abstract class MixinBlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<ClientboundPacket1_21_2, ServerboundPacket1_21_5, Protocol1_21_4To1_21_5> {
52+
53+
@Unique
54+
private static final boolean DEBUG = false;
55+
56+
public MixinBlockItemPacketRewriter1_21_5() {
57+
super(null, null, null, null, null);
58+
}
59+
60+
@Inject(method = "registerPackets", at = @At("RETURN"))
61+
private void appendPacketHandlers() {
62+
this.protocol.appendClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, wrapper -> {
63+
wrapper.resetReader();
64+
final String key = Key.namespaced(wrapper.passthrough(Types.STRING)); // key
65+
final RegistryEntry[] entries = wrapper.passthrough(Types.REGISTRY_ENTRY_ARRAY); // entries
66+
67+
final ItemComponentHashStorage itemComponentHasher = wrapper.user().get(ItemComponentHashStorage.class);
68+
if (key.equals("minecraft:enchantment")) {
69+
final List<Identifier> identifiers = new ArrayList<>();
70+
for (RegistryEntry entry : entries) {
71+
identifiers.add(Identifier.of(entry.key()));
72+
}
73+
itemComponentHasher.setEnchantmentRegistry(identifiers);
74+
}
75+
});
76+
}
77+
78+
@Inject(method = "handleItemToClient", at = @At("RETURN"))
79+
private void trackItemHashes(UserConnection connection, Item item, CallbackInfoReturnable<Item> cir) {
80+
final ItemComponentHashStorage itemComponentHasher = connection.get(ItemComponentHashStorage.class);
81+
for (StructuredData<?> structuredData : item.dataContainer().data().values()) {
82+
itemComponentHasher.trackStructuredData(structuredData);
83+
}
84+
}
85+
86+
@Inject(method = "convertHashedItemToStructuredItem", at = @At("RETURN"))
87+
private void addMoreDataToStructuredItem(UserConnection connection, HashedItem hashedItem, CallbackInfoReturnable<StructuredItem> cir) {
88+
final ItemComponentHashStorage itemComponentHasher = connection.get(ItemComponentHashStorage.class);
89+
final Map<StructuredDataKey<?>, StructuredData<?>> structuredDataMap = cir.getReturnValue().dataContainer().data();
90+
for (Int2IntMap.Entry hashEntry : hashedItem.dataHashesById().int2IntEntrySet()) {
91+
final StructuredData<?> structuredData = itemComponentHasher.getStructuredData(hashEntry.getIntKey(), hashEntry.getIntValue());
92+
if (structuredData != null) {
93+
structuredDataMap.put(structuredData.key(), structuredData);
94+
} else if (DEBUG) {
95+
this.protocol.getLogger().warning("Failed to find structured data for hash: " + hashEntry.getIntValue() + " with id: " + hashEntry.getIntKey());
96+
}
97+
}
98+
for (int dataId : hashedItem.removedDataIds()) {
99+
final StructuredDataKey<?> structuredDataKey = Types1_21_5.STRUCTURED_DATA.key(dataId);
100+
structuredDataMap.put(structuredDataKey, StructuredData.empty(structuredDataKey, dataId));
101+
}
102+
}
103+
104+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
3+
* Copyright (C) 2021-2025 RK_01/RaphiMC and contributors
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package net.raphimc.viaproxy.injection.mixins;
19+
20+
import com.viaversion.viaversion.api.connection.UserConnection;
21+
import com.viaversion.viaversion.api.data.MappingData;
22+
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
23+
import net.raphimc.viaproxy.protocoltranslator.viaproxy.item_component_hasher.ItemComponentHashStorage;
24+
import org.spongepowered.asm.mixin.Mixin;
25+
import org.spongepowered.asm.mixin.Shadow;
26+
import org.spongepowered.asm.mixin.injection.At;
27+
import org.spongepowered.asm.mixin.injection.Inject;
28+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
29+
30+
@Mixin(Protocol1_21_4To1_21_5.class)
31+
public abstract class MixinProtocol1_21_4To1_21_5 {
32+
33+
@Shadow
34+
public abstract MappingData getMappingData();
35+
36+
@Inject(method = "init", at = @At("RETURN"))
37+
private void addItemComponentHashStorage(UserConnection connection, CallbackInfo ci) {
38+
connection.put(new ItemComponentHashStorage(connection, this.getMappingData()));
39+
}
40+
41+
}

0 commit comments

Comments
 (0)