Skip to content

Commit 56e1d32

Browse files
committed
Implement equippable item data hashing
1 parent d4aa5a2 commit 56e1d32

File tree

12 files changed

+165
-5
lines changed

12 files changed

+165
-5
lines changed

api/src/main/java/com/viaversion/viaversion/api/data/MappingData.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,18 @@ public interface MappingData {
165165
@Nullable FullMappings getRecipeSerializerMappings();
166166

167167
@Nullable FullMappings getDataComponentSerializerMappings();
168+
169+
default @Nullable FullMappings getFullMappings(final MappingType mappingType) {
170+
return switch (mappingType) {
171+
case SOUND -> getFullSoundMappings();
172+
case ENTITY -> getEntityMappings();
173+
};
174+
}
175+
176+
/**
177+
* Type of mappings. Currently only relevant for ops writing of generic holder classes and expanded when needed.
178+
*/
179+
enum MappingType {
180+
SOUND, ENTITY
181+
}
168182
}

api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSet.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ static HolderSet of(final int[] ids) {
5050
}
5151

5252
/**
53-
* Gets the tag key.
53+
* Gets the tag key, not including '#'.
5454
*
55-
* @return the tag key
55+
* @return the tag key without a '#'
5656
* @see #hasTagKey()
5757
*/
5858
String tagKey();

api/src/main/java/com/viaversion/viaversion/api/minecraft/codec/CodecContext.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ interface RegistryAccess {
4949

5050
Key blockEntity(int id);
5151

52+
Key sound(int id);
53+
54+
Key key(MappingData.MappingType mappingType, int id);
55+
56+
int id(MappingData.MappingType mappingType, String identifier);
57+
5258
static RegistryAccess of(final List<String> enchantments, final MappingData mappingData) {
5359
return new RegistryAccessImpl(enchantments, mappingData);
5460
}

api/src/main/java/com/viaversion/viaversion/api/minecraft/codec/RegistryAccessImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,22 @@ public Key blockEntity(final int id) {
7676
return key(mappingData.getBlockEntityMappings(), id);
7777
}
7878

79+
@Override
80+
public Key sound(final int id) {
81+
return key(mappingData.getFullSoundMappings(), id);
82+
}
83+
84+
@Override
85+
public Key key(final MappingData.MappingType mappingType, final int id) {
86+
return key(mappingData.getFullMappings(mappingType), id);
87+
}
88+
89+
@Override
90+
public int id(final MappingData.MappingType mappingType, final String identifier) {
91+
final FullMappings mappings = mappingData.getFullMappings(mappingType);
92+
return mapped ? mappings.mappedId(identifier) : mappings.id(identifier);
93+
}
94+
7995
private Key key(final FullMappings mappings, final int id) {
8096
final String identifier = mapped ? mappings.mappedIdentifier(id) : mappings.identifier(id);
8197
return key(identifier, id);

api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/EnumTypes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public final class EnumTypes {
4444
public static final EnumType HORSE_VARIANT = new EnumType(Fallback.WRAP, "white", "creamy", "chestnut", "brown", "black", "gray", "dark_brown");
4545
public static final EnumType LLAMA_VARIANT = new EnumType(Fallback.CLAMP, "creamy", "white", "brown", "gray");
4646
public static final EnumType AXOLOTL_VARIANT = new EnumType("lucy", "wild", "gold", "cyan", "blue");
47+
public static final EnumType EQUIPMENT_SLOT = new EnumType("mainhand", "feet", "legs", "chest", "head", "offhand", "body", "saddle");
4748
// Enums with non-ordinal ids
4849
public static final FakeEnumType RABBIT_VARIANT = new FakeEnumType(List.of("brown", "white", "black", "white_splotched", "gold", "salt"), of(99, "evil"));
4950
// Pretty much enums, but with a resource location

api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Equippable.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@
2323
package com.viaversion.viaversion.api.minecraft.item.data;
2424

2525
import com.viaversion.viaversion.api.connection.UserConnection;
26+
import com.viaversion.viaversion.api.data.MappingData;
2627
import com.viaversion.viaversion.api.minecraft.Holder;
2728
import com.viaversion.viaversion.api.minecraft.HolderSet;
2829
import com.viaversion.viaversion.api.minecraft.SoundEvent;
30+
import com.viaversion.viaversion.api.minecraft.codec.Ops;
2931
import com.viaversion.viaversion.api.protocol.Protocol;
3032
import com.viaversion.viaversion.api.type.Type;
3133
import com.viaversion.viaversion.api.type.Types;
34+
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
35+
import com.viaversion.viaversion.util.Key;
3236
import com.viaversion.viaversion.util.Rewritable;
3337
import io.netty.buffer.ByteBuf;
3438
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -101,6 +105,21 @@ public void write(final ByteBuf buffer, final Equippable value) {
101105
buffer.writeBoolean(value.damageOnHurt());
102106
buffer.writeBoolean(value.equipOnInteract());
103107
}
108+
109+
@Override
110+
public void write(final Ops ops, final Equippable value) {
111+
final Holder<SoundEvent> defaultEquipSound = Holder.of(ops.context().registryAccess().id(MappingData.MappingType.SOUND, "item.armor.equip_generic"));
112+
ops.writeMap(map -> map
113+
.write("slot", EnumTypes.EQUIPMENT_SLOT, value.equipmentSlot)
114+
.writeOptional("equip_sound", Types.SOUND_EVENT, value.soundEvent, defaultEquipSound)
115+
.writeOptional("asset_id", Types.RESOURCE_LOCATION, value.model != null ? Key.of(value.model) : null)
116+
.writeOptional("camera_overlay", Types.RESOURCE_LOCATION, value.cameraOverlay != null ? Key.of(value.cameraOverlay) : null)
117+
.writeOptional("allowed_entities", new HolderSetType(MappingData.MappingType.ENTITY), value.allowedEntities)
118+
.writeOptional("dispensable", Types.BOOLEAN, value.dispensable, true)
119+
.writeOptional("swappable", Types.BOOLEAN, value.swappable, true)
120+
.writeOptional("damage_on_hurt", Types.BOOLEAN, value.damageOnHurt, true)
121+
.writeOptional("equip_on_interact", Types.BOOLEAN, value.equipOnInteract, false));
122+
}
104123
};
105124
public static final Type<Equippable> TYPE1_21_6 = new Type<>(Equippable.class) {
106125
@Override
@@ -133,6 +152,24 @@ public void write(final ByteBuf buffer, final Equippable value) {
133152
buffer.writeBoolean(value.canBeSheared());
134153
Types.SOUND_EVENT.write(buffer, value.shearingSound());
135154
}
155+
156+
@Override
157+
public void write(final Ops ops, final Equippable value) {
158+
final Holder<SoundEvent> defaultSound = Holder.of(ops.context().registryAccess().id(MappingData.MappingType.SOUND, "item.armor.equip_generic"));
159+
final Holder<SoundEvent> defaultShearingSound = Holder.of(ops.context().registryAccess().id(MappingData.MappingType.SOUND, "item.shears.snip"));
160+
ops.writeMap(map -> map
161+
.write("slot", EnumTypes.EQUIPMENT_SLOT, value.equipmentSlot)
162+
.writeOptional("equip_sound", Types.SOUND_EVENT, value.soundEvent, defaultSound)
163+
.writeOptional("asset_id", Types.RESOURCE_LOCATION, value.model != null ? Key.of(value.model) : null)
164+
.writeOptional("camera_overlay", Types.RESOURCE_LOCATION, value.cameraOverlay != null ? Key.of(value.cameraOverlay) : null)
165+
.writeOptional("allowed_entities", new HolderSetType(MappingData.MappingType.ENTITY), value.allowedEntities)
166+
.writeOptional("dispensable", Types.BOOLEAN, value.dispensable, true)
167+
.writeOptional("swappable", Types.BOOLEAN, value.swappable, true)
168+
.writeOptional("damage_on_hurt", Types.BOOLEAN, value.damageOnHurt, true)
169+
.writeOptional("equip_on_interact", Types.BOOLEAN, value.equipOnInteract, false)
170+
.writeOptional("can_be_sheared", Types.BOOLEAN, value.canBeSheared, false)
171+
.writeOptional("shearing_sound", Types.SOUND_EVENT, value.shearingSound, defaultShearingSound));
172+
}
136173
};
137174

138175
@Override

api/src/main/java/com/viaversion/viaversion/api/type/types/misc/HolderSetType.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,27 @@
2222
*/
2323
package com.viaversion.viaversion.api.type.types.misc;
2424

25+
import com.google.common.base.Preconditions;
26+
import com.viaversion.viaversion.api.data.MappingDataBase;
2527
import com.viaversion.viaversion.api.minecraft.HolderSet;
28+
import com.viaversion.viaversion.api.minecraft.codec.Ops;
2629
import com.viaversion.viaversion.api.type.OptionalType;
2730
import com.viaversion.viaversion.api.type.Type;
2831
import com.viaversion.viaversion.api.type.Types;
32+
import com.viaversion.viaversion.util.Key;
2933
import io.netty.buffer.ByteBuf;
3034

3135
public class HolderSetType extends Type<HolderSet> {
3236

37+
private final MappingDataBase.MappingType mappingType;
38+
3339
public HolderSetType() {
40+
this(null);
41+
}
42+
43+
public HolderSetType(final MappingDataBase.MappingType mappingType) {
3444
super(HolderSet.class);
45+
this.mappingType = mappingType;
3546
}
3647

3748
@Override
@@ -63,6 +74,28 @@ public void write(final ByteBuf buffer, final HolderSet object) {
6374
}
6475
}
6576

77+
@Override
78+
public void write(final Ops ops, final HolderSet value) {
79+
if (value.hasTagKey()) {
80+
ops.write(Types.STRING, "#" + Key.namespaced(value.tagKey()));
81+
} else {
82+
Preconditions.checkArgument(mappingType != null, "Cannot write HolderSet with direct ids without a mapping type");
83+
if (value.ids().length == 1) {
84+
// Single entries are inlined
85+
final Key key = ops.context().registryAccess().key(mappingType, value.ids()[0]);
86+
ops.write(Types.RESOURCE_LOCATION, key);
87+
return;
88+
}
89+
90+
ops.writeList(list -> {
91+
for (final int id : value.ids()) {
92+
final Key key = ops.context().registryAccess().key(mappingType, id);
93+
list.write(Types.RESOURCE_LOCATION, key);
94+
}
95+
});
96+
}
97+
}
98+
6699
public static final class OptionalHolderSetType extends OptionalType<HolderSet> {
67100

68101
public OptionalHolderSetType() {

api/src/main/java/com/viaversion/viaversion/api/type/types/misc/HolderType.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,27 @@
2222
*/
2323
package com.viaversion.viaversion.api.type.types.misc;
2424

25+
import com.google.common.base.Preconditions;
26+
import com.viaversion.viaversion.api.data.MappingData;
2527
import com.viaversion.viaversion.api.minecraft.Holder;
28+
import com.viaversion.viaversion.api.minecraft.codec.Ops;
2629
import com.viaversion.viaversion.api.type.Type;
2730
import com.viaversion.viaversion.api.type.Types;
31+
import com.viaversion.viaversion.util.Key;
2832
import io.netty.buffer.ByteBuf;
2933
import org.checkerframework.checker.nullness.qual.Nullable;
3034

3135
public abstract class HolderType<T> extends Type<Holder<T>> {
3236

37+
private final MappingData.MappingType mappingType;
38+
3339
protected HolderType() {
40+
this(null);
41+
}
42+
43+
protected HolderType(final MappingData.MappingType mappingType) {
3444
super(Holder.class);
45+
this.mappingType = mappingType;
3546
}
3647

3748
@Override
@@ -57,6 +68,24 @@ public void write(final ByteBuf buffer, final Holder<T> object) {
5768

5869
public abstract void writeDirect(final ByteBuf buffer, final T object);
5970

71+
@Override
72+
public void write(final Ops ops, final Holder<T> value) {
73+
if (value.hasId()) {
74+
ops.write(Types.RESOURCE_LOCATION, identifier(ops, value.id()));
75+
} else {
76+
writeDirect(ops, value.value());
77+
}
78+
}
79+
80+
protected Key identifier(final Ops ops, final int id) {
81+
Preconditions.checkArgument(mappingType != null, "Mapping type is not defined for this HolderType");
82+
return ops.context().registryAccess().key(mappingType, id);
83+
}
84+
85+
public void writeDirect(final Ops ops, final T object) {
86+
throw new UnsupportedOperationException("Write operation not supported for type: " + getTypeName());
87+
}
88+
6089
public abstract static class OptionalHolderType<T> extends HolderType<T> {
6190
private final HolderType<T> type;
6291

api/src/main/java/com/viaversion/viaversion/api/type/types/misc/SoundEventType.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@
2222
*/
2323
package com.viaversion.viaversion.api.type.types.misc;
2424

25+
import com.viaversion.viaversion.api.data.MappingData;
2526
import com.viaversion.viaversion.api.minecraft.SoundEvent;
27+
import com.viaversion.viaversion.api.minecraft.codec.Ops;
2628
import com.viaversion.viaversion.api.type.Types;
29+
import com.viaversion.viaversion.util.Key;
2730
import io.netty.buffer.ByteBuf;
2831

2932
public final class SoundEventType extends HolderType<SoundEvent> {
3033

34+
public SoundEventType() {
35+
super(MappingData.MappingType.SOUND);
36+
}
37+
3138
@Override
3239
public SoundEvent readDirect(final ByteBuf buffer) {
3340
final String resourceLocation = Types.STRING.read(buffer);
@@ -41,6 +48,13 @@ public void writeDirect(final ByteBuf buffer, final SoundEvent value) {
4148
Types.OPTIONAL_FLOAT.write(buffer, value.fixedRange());
4249
}
4350

51+
@Override
52+
public void writeDirect(final Ops ops, final SoundEvent object) {
53+
ops.writeMap(map -> map
54+
.write("sound_id", Types.RESOURCE_LOCATION, Key.of(object.identifier()))
55+
.writeOptional("range", Types.FLOAT, object.fixedRange()));
56+
}
57+
4458
public static final class OptionalSoundEventType extends OptionalHolderType<SoundEvent> {
4559

4660
public OptionalSoundEventType() {

api/src/main/java/com/viaversion/viaversion/util/Key.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public static String stripMinecraftNamespace(final String identifier) {
124124
}
125125

126126
public static boolean equals(final String firstIdentifier, final String secondIdentifier) {
127-
return of(firstIdentifier).equals(of(secondIdentifier));
127+
return firstIdentifier != null && secondIdentifier != null && of(firstIdentifier).equals(of(secondIdentifier));
128128
}
129129

130130
public static String namespaced(final String identifier) {

0 commit comments

Comments
 (0)