Skip to content

Commit d6bae47

Browse files
committed
Fix command parsing in tellraw functions in 1.21.5+
* Switches to the Gson library for JSON serialization * Improves exception handling, fixing core errors * Uses /execute instead of sudo() for ptellraw
1 parent 025a2d1 commit d6bae47

File tree

2 files changed

+63
-26
lines changed

2 files changed

+63
-26
lines changed

src/main/java/com/laytonsmith/core/functions/Echoes.java

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.laytonsmith.core.functions;
22

3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import com.google.gson.JsonIOException;
36
import com.laytonsmith.PureUtilities.Common.StreamUtils;
47
import com.laytonsmith.PureUtilities.Common.StringUtils;
58
import com.laytonsmith.PureUtilities.TermColors;
@@ -27,6 +30,7 @@
2730
import com.laytonsmith.core.environments.GlobalEnv;
2831
import com.laytonsmith.core.exceptions.CRE.CRECastException;
2932
import com.laytonsmith.core.exceptions.CRE.CREFormatException;
33+
import com.laytonsmith.core.exceptions.CRE.CREIOException;
3034
import com.laytonsmith.core.exceptions.CRE.CREInsufficientArgumentsException;
3135
import com.laytonsmith.core.exceptions.CRE.CRELengthException;
3236
import com.laytonsmith.core.exceptions.CRE.CREPlayerOfflineException;
@@ -183,7 +187,7 @@ public static class tellraw extends AbstractFunction {
183187

184188
@Override
185189
public Class<? extends CREThrowable>[] thrown() {
186-
return new Class[]{CRECastException.class};
190+
return new Class[]{CRECastException.class, CREFormatException.class, CREIOException.class};
187191
}
188192

189193
@Override
@@ -200,13 +204,24 @@ public Boolean runAsync() {
200204
public Mixed exec(Target t, Environment environment, Mixed... args) throws ConfigRuntimeException {
201205
String selector = "@a";
202206
String json;
203-
if(args.length == 1) {
204-
json = new DataTransformations.json_encode().exec(t, environment, args[0]).val();
205-
} else {
206-
selector = ArgumentValidation.getString(args[0], t);
207-
json = new DataTransformations.json_encode().exec(t, environment, args[1]).val();
207+
try {
208+
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
209+
if(args.length == 1) {
210+
json = gson.toJson(Construct.GetPOJO(args[0]));
211+
} else {
212+
selector = ArgumentValidation.getString(args[0], t);
213+
json = gson.toJson(Construct.GetPOJO(args[1]));
214+
}
215+
} catch(ClassCastException ex) {
216+
throw new CRECastException(ex.getMessage(), t);
217+
} catch(JsonIOException ex) {
218+
throw new CREIOException(ex.getMessage(), t);
219+
}
220+
try {
221+
Static.getServer().runasConsole("minecraft:tellraw " + selector + " " + json);
222+
} catch(Exception ex) {
223+
throw new CREFormatException(ex.getMessage(), t, ex.getCause());
208224
}
209-
Static.getServer().runasConsole("minecraft:tellraw " + selector + " " + json);
210225
return CVoid.VOID;
211226
}
212227

@@ -226,11 +241,12 @@ public String docs() {
226241
+ " this simply passes the input to the command. The raw is passed in as an array and json encoded."
227242
+ " No validation is done on the input, so the command may fail."
228243
+ " Do not use double quotes (smart string) when providing the selector."
229-
+ " If not provided, the selector defaults to @a. See {{function|ptellraw}} if you need player"
230-
+ " context. ---- The specification of the array may change from version to version of Minecraft,"
231-
+ " but is documented here https://minecraft.gamepedia.com/Commands#Raw_JSON_text."
232-
+ " This function is simply written in terms of json_encode and runas, and is otherwise equivalent"
233-
+ " to runas('~console', '/minecraft:tellraw ' . @selector . ' ' . json_encode(@raw))";
244+
+ " If not provided, the selector defaults to @a. See {{function|ptellraw}} if you need the @s"
245+
+ " selector with player context. ---- The specification of the array may change from version to"
246+
+ " version of Minecraft, but is documented here: https://minecraft.wiki/w/Text_component_format."
247+
+ " This function is roughly equivalent to"
248+
+ " runas('~console', '/tellraw '.@selector.' '.json_encode(@raw))"
249+
+ " but uses the Gson serializer instead.";
234250
}
235251

236252
@Override

src/main/java/com/laytonsmith/core/functions/PlayerManagement.java

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.laytonsmith.core.functions;
22

3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import com.google.gson.JsonIOException;
36
import com.laytonsmith.PureUtilities.Common.StringUtils;
47
import com.laytonsmith.PureUtilities.Vector3D;
58
import com.laytonsmith.PureUtilities.Version;
@@ -63,6 +66,7 @@
6366
import com.laytonsmith.core.exceptions.CRE.CREBadEntityException;
6467
import com.laytonsmith.core.exceptions.CRE.CRECastException;
6568
import com.laytonsmith.core.exceptions.CRE.CREFormatException;
69+
import com.laytonsmith.core.exceptions.CRE.CREIOException;
6670
import com.laytonsmith.core.exceptions.CRE.CREIllegalArgumentException;
6771
import com.laytonsmith.core.exceptions.CRE.CREInsufficientArgumentsException;
6872
import com.laytonsmith.core.exceptions.CRE.CREInvalidWorldException;
@@ -6187,7 +6191,8 @@ public static class ptellraw extends AbstractFunction {
61876191

61886192
@Override
61896193
public Class<? extends CREThrowable>[] thrown() {
6190-
return new Class[]{CRECastException.class};
6194+
return new Class[]{CRECastException.class, CREFormatException.class, CREIOException.class,
6195+
CREPlayerOfflineException.class};
61916196
}
61926197

61936198
@Override
@@ -6202,15 +6207,31 @@ public Boolean runAsync() {
62026207

62036208
@Override
62046209
public Mixed exec(Target t, Environment environment, Mixed... args) throws ConfigRuntimeException {
6210+
MCPlayer p = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
6211+
if(p == null) {
6212+
throw new CREPlayerOfflineException("ptellraw() requires player context. Consider tellraw().", t);
6213+
}
62056214
String selector = "@s";
62066215
String json;
6207-
if(args.length == 1) {
6208-
json = new DataTransformations.json_encode().exec(t, environment, args[0]).val();
6209-
} else {
6210-
selector = ArgumentValidation.getString(args[0], t);
6211-
json = new DataTransformations.json_encode().exec(t, environment, args[1]).val();
6216+
try {
6217+
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
6218+
if(args.length == 1) {
6219+
json = gson.toJson(Construct.GetPOJO(args[0]));
6220+
} else {
6221+
selector = ArgumentValidation.getString(args[0], t);
6222+
json = gson.toJson(Construct.GetPOJO(args[1]));
6223+
}
6224+
} catch(ClassCastException ex) {
6225+
throw new CRECastException(ex.getMessage(), t);
6226+
} catch(JsonIOException ex) {
6227+
throw new CREIOException(ex.getMessage(), t);
6228+
}
6229+
try {
6230+
Static.getServer().runasConsole("minecraft:execute as " + p.getName() + " at @s"
6231+
+ " run minecraft:tellraw " + selector + " " + json);
6232+
} catch(Exception ex) {
6233+
throw new CREFormatException(ex.getMessage(), t, ex.getCause());
62126234
}
6213-
new Meta.sudo().exec(t, environment, new CString("/minecraft:tellraw " + selector + " " + json, t));
62146235
return CVoid.VOID;
62156236
}
62166237

@@ -6230,11 +6251,12 @@ public String docs() {
62306251
+ " this simply passes the input to the command. The raw is passed in as a normal"
62316252
+ " (possibly associative) array, and json encoded. No validation is done on the input,"
62326253
+ " so the command may fail. If not provided, the selector defaults to @s. Do not use double quotes"
6233-
+ " (smart string) when providing the selector. See {{function|tellraw}} if you don't need player"
6234-
+ " context. ---- The specification of the array may change from version to version of Minecraft,"
6235-
+ " but is documented here https://minecraft.gamepedia.com/Commands#Raw_JSON_text."
6236-
+ " This function is simply written in terms of json_encode and sudo, and is otherwise equivalent"
6237-
+ " to sudo('/minecraft:tellraw ' . @selector . ' ' . json_encode(@raw))";
6254+
+ " (smart string) when providing the selector. See {{function|tellraw}} if you don't need the @s"
6255+
+ " selector with player context. ---- The specification of the array may change from version to"
6256+
+ " version of Minecraft, but is documented here: https://minecraft.wiki/w/Text_component_format."
6257+
+ " This function is roughly equivalent to"
6258+
+ " runas('~console', '/execute as '.player().' at @s tellraw '.@selector.' '.json_encode(@raw))"
6259+
+ " but uses the Gson serializer instead.";
62386260
}
62396261

62406262
@Override
@@ -6251,8 +6273,7 @@ public ExampleScript[] examples() throws ConfigCompileException {
62516273
new ExampleScript("Advanced usage with embedded selectors.",
62526274
"ptellraw('@a', array(\n"
62536275
+ "\tarray('selector': '@s'), // prints current player\n"
6254-
+ "\tarray('text': ': Hello '),\n"
6255-
+ "\tarray('selector': '@p') // prints receiving player\n"
6276+
+ "\tarray('text': ': Hello World!')\n"
62566277
+ "));",
62576278
"<<Would output a message from the current player to all players.>>"),
62586279
new ExampleScript("Complex object",

0 commit comments

Comments
 (0)