Skip to content

Commit 181a0cb

Browse files
committed
Cache parsed item name and lore in older protocols
1 parent b367037 commit 181a0cb

File tree

5 files changed

+162
-36
lines changed

5 files changed

+162
-36
lines changed

common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsItemRewriter.java

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@
2626
import com.viaversion.nbt.tag.Tag;
2727
import com.viaversion.viabackwards.api.BackwardsProtocol;
2828
import com.viaversion.viabackwards.api.data.MappedItem;
29+
import com.viaversion.viabackwards.item.DataItemWithExtras;
2930
import com.viaversion.viaversion.api.connection.UserConnection;
3031
import com.viaversion.viaversion.api.minecraft.item.Item;
3132
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
3233
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
3334
import com.viaversion.viaversion.api.type.Type;
35+
import com.viaversion.viaversion.libs.gson.JsonElement;
36+
import java.util.List;
3437
import org.checkerframework.checker.nullness.qual.Nullable;
3538

3639
public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
@@ -52,29 +55,45 @@ public BackwardsItemRewriter(T protocol, Type<Item> itemType, Type<Item[]> itemA
5255

5356
CompoundTag display = item.tag() != null ? item.tag().getCompoundTag("display") : null;
5457
if (protocol.getComponentRewriter() != null && display != null) {
58+
final DataItemWithExtras fullItem;
59+
if (item instanceof DataItemWithExtras) {
60+
fullItem = (DataItemWithExtras) item;
61+
} else {
62+
item = fullItem = new DataItemWithExtras(item);
63+
}
64+
5565
// Handle name and lore components
56-
StringTag name = display.getStringTag("Name");
66+
final JsonElement name = fullItem.name();
5767
if (name != null) {
58-
String newValue = protocol.getComponentRewriter().processText(connection, name.getValue()).toString();
59-
if (!newValue.equals(name.getValue())) {
60-
saveStringTag(display, name, "Name");
68+
final JsonElement updatedName = name.deepCopy();
69+
protocol.getComponentRewriter().processText(connection, updatedName);
70+
if (!updatedName.equals(name)) {
71+
final StringTag rawName = fullItem.rawName();
72+
saveStringTag(display, rawName, "Name");
73+
rawName.setValue(updatedName.toString());
6174
}
62-
63-
name.setValue(newValue);
6475
}
6576

66-
ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
77+
final List<JsonElement> lore = fullItem.lore();
6778
if (lore != null) {
6879
boolean changed = false;
69-
for (StringTag loreEntry : lore) {
70-
String newValue = protocol.getComponentRewriter().processText(connection, loreEntry.getValue()).toString();
71-
if (!changed && !newValue.equals(loreEntry.getValue())) {
80+
final ListTag<StringTag> rawLore = fullItem.rawLore();
81+
for (int i = 0; i < lore.size(); i++) {
82+
final JsonElement loreEntry = lore.get(i);
83+
final JsonElement updatedLoreEntry = loreEntry.deepCopy();
84+
protocol.getComponentRewriter().processText(connection, updatedLoreEntry);
85+
if (updatedLoreEntry.equals(loreEntry)) {
86+
continue;
87+
}
88+
89+
if (!changed) {
7290
// Backup original lore before doing any modifications
7391
changed = true;
74-
saveListTag(display, lore, "Lore");
92+
saveListTag(display, rawLore, "Lore");
7593
}
7694

77-
loreEntry.setValue(newValue);
95+
final StringTag rawLoreEntry = rawLore.get(i);
96+
rawLoreEntry.setValue(updatedLoreEntry.toString());
7897
}
7998
}
8099
}

common/src/main/java/com/viaversion/viabackwards/api/rewriters/EntityRewriterBase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ public void registerEntityDataTypeHandler(
175175
filter().handler((event, data) -> {
176176
EntityDataType type = data.dataType();
177177
if (type == itemType) {
178-
protocol.getItemRewriter().handleItemToClient(event.user(), data.value());
178+
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), data.value()));
179179
} else if (type == blockStateType) {
180180
int value = data.value();
181181
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
3+
* Copyright (C) 2016-2025 ViaVersion 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 com.viaversion.viabackwards.item;
19+
20+
import com.viaversion.nbt.tag.CompoundTag;
21+
import com.viaversion.nbt.tag.ListTag;
22+
import com.viaversion.nbt.tag.StringTag;
23+
import com.viaversion.viaversion.api.minecraft.item.DataItem;
24+
import com.viaversion.viaversion.api.minecraft.item.Item;
25+
import com.viaversion.viaversion.libs.gson.JsonElement;
26+
import com.viaversion.viaversion.libs.gson.JsonParser;
27+
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
28+
import com.viaversion.viaversion.libs.gson.JsonSyntaxException;
29+
import java.util.ArrayList;
30+
import java.util.List;
31+
import org.checkerframework.checker.nullness.qual.Nullable;
32+
33+
/**
34+
* Prevent expensive parsing/toString by checking against cached JsonElement instances, used from 1.14 to 1.20.5.
35+
* <p>
36+
* When using this, be careful not to break caching by modifying the display tag directly.
37+
*/
38+
public final class DataItemWithExtras extends DataItem {
39+
40+
private JsonElement name;
41+
private List<JsonElement> lore;
42+
43+
public DataItemWithExtras(final Item from) {
44+
setIdentifier(from.identifier());
45+
setAmount(from.amount());
46+
setData(from.data());
47+
setTag(from.tag());
48+
49+
if (tag() == null) {
50+
return;
51+
}
52+
53+
final CompoundTag display = tag().getCompoundTag("display");
54+
if (display == null) {
55+
return;
56+
}
57+
58+
final StringTag name = display.getStringTag("Name");
59+
if (name != null) {
60+
this.name = parse(name.getValue());
61+
}
62+
63+
final ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
64+
if (lore != null) {
65+
this.lore = new ArrayList<>(lore.size());
66+
for (int i = 0; i < lore.size(); i++) {
67+
this.lore.add(parse(lore.get(i).getValue()));
68+
}
69+
}
70+
}
71+
72+
public @Nullable JsonElement name() {
73+
return name;
74+
}
75+
76+
public @Nullable StringTag rawName() {
77+
if (tag() == null) {
78+
return null;
79+
}
80+
final CompoundTag display = tag().getCompoundTag("display");
81+
return display != null ? display.getStringTag("Name") : null;
82+
}
83+
84+
public @Nullable List<JsonElement> lore() {
85+
return lore;
86+
}
87+
88+
public @Nullable ListTag<StringTag> rawLore() {
89+
if (tag() == null) {
90+
return null;
91+
}
92+
final CompoundTag display = tag().getCompoundTag("display");
93+
return display != null ? display.getListTag("Lore", StringTag.class) : null;
94+
}
95+
96+
private JsonElement parse(final String value) {
97+
try {
98+
return JsonParser.parseString(value);
99+
} catch (final JsonSyntaxException e) {
100+
return new JsonPrimitive(value);
101+
}
102+
}
103+
}

common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_1to1_13/rewriter/EntityPacketRewriter1_13_1.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ protected void registerRewrites() {
131131
// Rewrite items & blocks
132132
filter().handler((event, data) -> {
133133
if (data.dataType() == Types1_13.ENTITY_DATA_TYPES.itemType) {
134-
protocol.getItemRewriter().handleItemToClient(event.user(), (Item) data.getValue());
134+
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), (Item) data.getValue()));
135135
} else if (data.dataType() == Types1_13.ENTITY_DATA_TYPES.optionalBlockStateType) {
136136
// Convert to new block id
137137
int value = (int) data.getValue();

common/src/main/java/com/viaversion/viabackwards/protocol/v1_14to1_13_2/rewriter/BlockItemPacketRewriter1_14.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.viaversion.viabackwards.api.data.TranslatableMappings;
2525
import com.viaversion.viabackwards.api.rewriters.BackwardsItemRewriter;
2626
import com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter;
27+
import com.viaversion.viabackwards.item.DataItemWithExtras;
2728
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
2829
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.storage.ChunkLightStorage;
2930
import com.viaversion.viaversion.api.Via;
@@ -39,6 +40,7 @@
3940
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
4041
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_14;
4142
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
43+
import com.viaversion.viaversion.api.minecraft.item.DataItem;
4244
import com.viaversion.viaversion.api.minecraft.item.Item;
4345
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
4446
import com.viaversion.viaversion.api.type.Types;
@@ -61,7 +63,6 @@
6163
import com.viaversion.viaversion.util.Key;
6264
import com.viaversion.viaversion.util.SerializerVersion;
6365
import java.util.ArrayList;
64-
import java.util.Iterator;
6566
import java.util.List;
6667
import java.util.Set;
6768

@@ -462,31 +463,34 @@ public Item handleItemToClient(UserConnection connection, Item item) {
462463
super.handleItemToClient(connection, item);
463464

464465
// Lore now uses JSON
465-
CompoundTag tag = item.tag();
466-
CompoundTag display;
467-
if (tag != null && (display = tag.getCompoundTag("display")) != null) {
468-
ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
469-
if (lore != null) {
470-
saveListTag(display, lore, "Lore");
471-
472-
try {
473-
final Iterator<StringTag> each = lore.iterator();
474-
while (each.hasNext()) {
475-
final StringTag loreEntry = each.next();
476-
final var component = SerializerVersion.V1_12.toComponent(loreEntry.getValue());
477-
if (component == null) {
478-
each.remove();
479-
continue;
480-
}
481-
TextUtils.setTranslator(component, s -> Protocol1_12_2To1_13.MAPPINGS.getMojangTranslation().
482-
getOrDefault(s, TranslatableMappings.getTranslatableMappings("1.14").get(s)));
483-
loreEntry.setValue(component.asLegacyFormatString());
466+
final CompoundTag display = item.tag() != null ? item.tag().getCompoundTag("display") : null;
467+
if (display != null && item instanceof DataItemWithExtras fullItem && fullItem.lore() != null) {
468+
final List<JsonElement> lore = fullItem.lore();
469+
final ListTag<StringTag> loreTag = fullItem.rawLore();
470+
saveListTag(display, loreTag, "Lore");
471+
472+
try {
473+
for (int i = 0; i < lore.size(); i++) {
474+
final JsonElement loreEntry = lore.get(i);
475+
final var component = SerializerVersion.V1_12.toComponent(loreEntry);
476+
if (component == null) {
477+
lore.remove(i);
478+
loreTag.remove(i);
479+
i--;
480+
continue;
484481
}
485-
} catch (final JsonParseException e) {
486-
display.remove("Lore");
482+
483+
TextUtils.setTranslator(component, s -> Protocol1_12_2To1_13.MAPPINGS.getMojangTranslation()
484+
.getOrDefault(s, TranslatableMappings.getTranslatableMappings("1.14").get(s)));
485+
loreTag.get(i).setValue(component.asLegacyFormatString());
487486
}
487+
} catch (final JsonParseException e) {
488+
display.remove("Lore");
488489
}
489490
}
491+
if (item instanceof DataItemWithExtras) {
492+
item = new DataItem(item.identifier(), (byte) item.amount(), item.data(), item.tag()); // back to a normal DataItem
493+
}
490494

491495
enchantmentRewriter.handleToClient(item);
492496
return item;

0 commit comments

Comments
 (0)