Skip to content

Commit ce4d616

Browse files
wizjanydordsor21
authored andcommitted
Update click and hover text component serialization for 1.21.5. (#2757)
Hacky workaround by overwriting the text3 StyleSerializer class with our own modified copy. Note that the hover events "show_entity" and "show_item" aren't supported as they no longer take a rendered component, but just the NBT structure. Behavior remains unchanged if 1.21.4- is detected. Fixes #2756.
1 parent 365ce9b commit ce4d616

1 file changed

Lines changed: 207 additions & 0 deletions

File tree

  • worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/text/serializer/gson
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* This file is part of text, licensed under the MIT License.
3+
*
4+
* Copyright (c) 2017-2020 KyoriPowered
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.sk89q.worldedit.util.formatting.text.serializer.gson;
26+
27+
import com.google.gson.JsonDeserializationContext;
28+
import com.google.gson.JsonDeserializer;
29+
import com.google.gson.JsonElement;
30+
import com.google.gson.JsonObject;
31+
import com.google.gson.JsonParseException;
32+
import com.google.gson.JsonPrimitive;
33+
import com.google.gson.JsonSerializationContext;
34+
import com.google.gson.JsonSerializer;
35+
import com.sk89q.worldedit.WorldEdit;
36+
import com.sk89q.worldedit.extension.platform.Capability;
37+
import com.sk89q.worldedit.internal.Constants;
38+
import com.sk89q.worldedit.util.formatting.text.Component;
39+
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
40+
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
41+
import com.sk89q.worldedit.util.formatting.text.format.Style;
42+
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
43+
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
44+
45+
import java.lang.reflect.Type;
46+
47+
// This class was copied and manually "relocated" from text3 to update the click/hover events for 1.21.5.
48+
public class StyleSerializer implements JsonDeserializer<Style>, JsonSerializer<Style> {
49+
public static final StyleSerializer INSTANCE = new StyleSerializer();
50+
51+
private static final TextDecoration[] DECORATIONS = TextDecoration.values();
52+
53+
static final boolean PRE_1215;
54+
static final String COLOR = "color";
55+
static final String INSERTION = "insertion";
56+
static final String CLICK_EVENT;
57+
static final String CLICK_EVENT_ACTION = "action";
58+
static final String CLICK_EVENT_VALUE = "value";
59+
static final String CLICK_EVENT_URL = "url";
60+
static final String CLICK_EVENT_COMMAND = "command";
61+
static final String CLICK_EVENT_PAGE = "page";
62+
static final String HOVER_EVENT;
63+
static final String HOVER_EVENT_ACTION = "action";
64+
static final String HOVER_EVENT_VALUE = "value";
65+
66+
static {
67+
boolean tmp = false;
68+
try {
69+
tmp = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.USER_COMMANDS)
70+
.getDataVersion() < Constants.DATA_VERSION_MC_1_21_5;
71+
} catch (Exception ignored) {
72+
}
73+
PRE_1215 = tmp;
74+
CLICK_EVENT = PRE_1215 ? "clickEvent" : "click_event";
75+
HOVER_EVENT = PRE_1215 ? "hoverEvent" : "hover_event";
76+
}
77+
78+
@Override
79+
public Style deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException {
80+
final JsonObject object = json.getAsJsonObject();
81+
return this.deserialize(object, context);
82+
}
83+
84+
private Style deserialize(final JsonObject json, final JsonDeserializationContext context) throws JsonParseException {
85+
final Style.Builder style = Style.builder();
86+
87+
if (json.has(COLOR)) {
88+
final TextColorWrapper color = context.deserialize(json.get(COLOR), TextColorWrapper.class);
89+
if (color.color != null) {
90+
style.color(color.color);
91+
} else if (color.decoration != null) {
92+
// I know. Setting a decoration from the color is weird. This is, unfortunately, something we need to support.
93+
style.decoration(color.decoration, true);
94+
}
95+
}
96+
97+
for (int i = 0, length = DECORATIONS.length; i < length; i++) {
98+
final TextDecoration decoration = DECORATIONS[i];
99+
final String name = TextDecoration.NAMES.name(decoration);
100+
if (json.has(name)) {
101+
style.decoration(decoration, json.get(name).getAsBoolean());
102+
}
103+
}
104+
105+
if (json.has(INSERTION)) {
106+
style.insertion(json.get(INSERTION).getAsString());
107+
}
108+
109+
if (json.has(CLICK_EVENT)) {
110+
final JsonObject clickEvent = json.getAsJsonObject(CLICK_EVENT);
111+
if (clickEvent != null) {
112+
final /* @Nullable */ JsonPrimitive rawAction = clickEvent.getAsJsonPrimitive(CLICK_EVENT_ACTION);
113+
final ClickEvent./*@Nullable*/ Action action = rawAction == null ? null : context.deserialize(rawAction, ClickEvent.Action.class);
114+
if (action != null && action.readable()) {
115+
final /* @Nullable */ JsonPrimitive rawValue = clickEvent.getAsJsonPrimitive(clickActionToKey(action));
116+
final /* @Nullable */ String value = rawValue == null ? null : rawValue.getAsString();
117+
if (value != null) {
118+
style.clickEvent(ClickEvent.of(action, value));
119+
}
120+
}
121+
}
122+
}
123+
124+
if (json.has(HOVER_EVENT)) {
125+
final JsonObject hoverEvent = json.getAsJsonObject(HOVER_EVENT);
126+
if (hoverEvent != null) {
127+
final /* @Nullable */ JsonPrimitive rawAction = hoverEvent.getAsJsonPrimitive(HOVER_EVENT_ACTION);
128+
final HoverEvent./*@Nullable*/ Action action = rawAction == null ? null : context.deserialize(rawAction, HoverEvent.Action.class);
129+
if (action != null && action.readable()) {
130+
if (!PRE_1215 && action != HoverEvent.Action.SHOW_TEXT) {
131+
// entity/item are technically readable but text3 can't deserialize the NBT contents
132+
throw new IllegalArgumentException("Don't know how to serialize " + hoverEvent);
133+
}
134+
final /* @Nullable */ JsonElement rawValue = hoverEvent.get(HOVER_EVENT_VALUE);
135+
final /* @Nullable */ Component value = rawValue == null ? null : context.deserialize(rawValue, Component.class);
136+
if (value != null) {
137+
style.hoverEvent(HoverEvent.of(action, value));
138+
}
139+
}
140+
}
141+
}
142+
143+
return style.build();
144+
}
145+
146+
@Override
147+
public JsonElement serialize(final Style src, final Type typeOfSrc, final JsonSerializationContext context) {
148+
final JsonObject json = new JsonObject();
149+
150+
final /* @Nullable */ TextColor color = src.color();
151+
if (color != null) {
152+
json.add(COLOR, context.serialize(color));
153+
}
154+
155+
for (int i = 0, length = DECORATIONS.length; i < length; i++) {
156+
final TextDecoration decoration = DECORATIONS[i];
157+
final TextDecoration.State state = src.decoration(decoration);
158+
if (state != TextDecoration.State.NOT_SET) {
159+
final String name = TextDecoration.NAMES.name(decoration);
160+
json.addProperty(name, state == TextDecoration.State.TRUE);
161+
}
162+
}
163+
164+
final /* @Nullable */ String insertion = src.insertion();
165+
if (insertion != null) {
166+
json.add(INSERTION, context.serialize(insertion));
167+
}
168+
169+
final /* @Nullable */ ClickEvent clickEvent = src.clickEvent();
170+
if (clickEvent != null) {
171+
final JsonObject eventJson = new JsonObject();
172+
eventJson.add(CLICK_EVENT_ACTION, context.serialize(clickEvent.action()));
173+
if (!PRE_1215 && clickEvent.action() == ClickEvent.Action.CHANGE_PAGE) {
174+
eventJson.addProperty(CLICK_EVENT_PAGE, Integer.valueOf(clickEvent.value()));
175+
} else {
176+
eventJson.addProperty(clickActionToKey(clickEvent.action()), clickEvent.value());
177+
}
178+
json.add(CLICK_EVENT, eventJson);
179+
}
180+
181+
final /* @Nullable */ HoverEvent hoverEvent = src.hoverEvent();
182+
if (hoverEvent != null) {
183+
if (!PRE_1215 && hoverEvent.action() != HoverEvent.Action.SHOW_TEXT) {
184+
throw new IllegalArgumentException("Don't know how to serialize " + hoverEvent);
185+
}
186+
final JsonObject eventJson = new JsonObject();
187+
eventJson.add(HOVER_EVENT_ACTION, context.serialize(hoverEvent.action()));
188+
eventJson.add(HOVER_EVENT_VALUE, context.serialize(hoverEvent.value()));
189+
json.add(HOVER_EVENT, eventJson);
190+
}
191+
192+
return json;
193+
}
194+
195+
private static String clickActionToKey(ClickEvent.Action action) {
196+
if (PRE_1215) {
197+
return CLICK_EVENT_VALUE;
198+
}
199+
return switch (action) {
200+
case OPEN_URL -> CLICK_EVENT_URL;
201+
case CHANGE_PAGE -> CLICK_EVENT_PAGE;
202+
case RUN_COMMAND, SUGGEST_COMMAND -> CLICK_EVENT_COMMAND;
203+
case COPY_TO_CLIPBOARD -> CLICK_EVENT_VALUE;
204+
default -> throw new IllegalArgumentException("Can't convert action " + action + " to serialization key.");
205+
};
206+
}
207+
}

0 commit comments

Comments
 (0)