Skip to content
This repository was archived by the owner on Jun 30, 2024. It is now read-only.

Commit 8ac0f62

Browse files
committed
- setting functions to not exist now works correctly
- copy to clipboard on defined functions - added sgn function - added a terrible factorial - fixed a bug with negative signs not working - reworked the math engine logic - changed `random()` and `rand()` to be `rand` and `random` - added constants
1 parent da22d42 commit 8ac0f62

13 files changed

+379
-349
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ org.gradle.jvmargs=-Xmx1G
88
loader_version=0.14.23
99

1010
# Mod Properties
11-
mod_version = 3.0.20
11+
mod_version = 3.0.21
1212
maven_group = ca.rttv
1313
archives_base_name = chatcalc

src/main/java/ca/rttv/chatcalc/CallableFunction.java

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,80 @@
11
package ca.rttv.chatcalc;
22

3+
import com.mojang.datafixers.util.Either;
34
import net.fabricmc.loader.api.FabricLoader;
45
import net.minecraft.client.MinecraftClient;
56
import net.minecraft.client.gui.widget.TextFieldWidget;
7+
import net.minecraft.text.ClickEvent;
8+
import net.minecraft.text.HoverEvent;
9+
import net.minecraft.text.MutableText;
610
import net.minecraft.text.Text;
711
import org.jetbrains.annotations.Contract;
12+
import org.jetbrains.annotations.NotNull;
813

914
import java.util.Optional;
1015
import java.util.regex.Pattern;
11-
import java.util.stream.Collectors;
1216

1317
public class ChatCalc {
14-
public static final Pattern NUMBER = Pattern.compile("[-+]?\\d+(\\.\\d+)?");
18+
public static final Pattern NUMBER = Pattern.compile("[-+]?(\\d,?)+(\\.\\d+)?");
19+
public static final Pattern FUNCTION = Pattern.compile("[a-zA-Z]+\\(([a-zA-Z]+,)*?([a-zA-Z]+)\\)");
20+
public static final Pattern CONSTANT = Pattern.compile("[a-zA-Z]+");
1521
public static final String SEPARATOR = ";";
1622
public static final char SEPARATOR_CHAR = ';';
1723

1824
@Contract(value = "_->_", mutates = "param1")
19-
public static boolean tryParse(TextFieldWidget field) {
25+
public static boolean tryParse(@NotNull TextFieldWidget field) {
2026
final MinecraftClient client = MinecraftClient.getInstance();
2127
String originalText = field.getText();
2228
int cursor = field.getCursor();
23-
String text = ChatHelper.getWord(originalText, cursor);
29+
String text = ChatHelper.getSection(originalText, cursor);
2430
{
2531
String[] split = text.split("=");
2632
if (split.length == 2) {
2733
if (Config.JSON.has(split[0])) {
2834
Config.JSON.addProperty(split[0], split[1]);
2935
Config.refreshJson();
30-
return ChatHelper.replaceWord(field, "");
36+
return ChatHelper.replaceSection(field, "");
3137
} else {
32-
Optional<CallableFunction> func = CallableFunction.fromString(text);
33-
if (func.isPresent()) {
34-
if (func.get().rest().isEmpty()) {
35-
if (Config.FUNCTIONS.containsKey(func.get().name())) {
36-
Config.FUNCTIONS.remove(func.get().name());
37-
} else {
38-
return false;
39-
}
40-
} else {
41-
Config.FUNCTIONS.put(func.get().name(), func.get());
38+
Optional<Either<CustomFunction, CustomConstant>> either = parseDeclaration(text);
39+
if (either.isPresent()) {
40+
Optional<CustomFunction> left = either.get().left();
41+
Optional<CustomConstant> right = either.get().right();
42+
if (left.isPresent()) {
43+
Config.FUNCTIONS.put(left.get().name(), left.get());
44+
Config.refreshJson();
45+
return ChatHelper.replaceSection(field, "");
46+
} else if (right.isPresent()) {
47+
Config.CONSTANTS.put(right.get().name(), right.get());
48+
Config.refreshJson();
49+
return ChatHelper.replaceSection(field, "");
4250
}
43-
Config.refreshJson();
44-
return ChatHelper.replaceWord(field, "");
4551
}
4652
}
4753
} else if (split.length == 1) {
4854
if (Config.JSON.has(split[0])) {
49-
return ChatHelper.replaceWord(field, Config.JSON.get(split[0]).getAsString());
55+
return ChatHelper.replaceSection(field, Config.JSON.get(split[0]).getAsString());
5056
} else if (!split[0].isEmpty() && Config.JSON.has(split[0].substring(0, split[0].length() - 1)) && split[0].endsWith("?") && client.player != null) {
5157
client.player.sendMessage(Text.translatable("chatcalc." + split[0].substring(0, split[0].length() - 1) + ".description"));
5258
return false;
59+
} else {
60+
Optional<Either<CustomFunction, CustomConstant>> either = parseDeclaration(text);
61+
if (either.isPresent()) {
62+
Optional<CustomFunction> left = either.get().left();
63+
Optional<CustomConstant> right = either.get().right();
64+
if (left.isPresent()) {
65+
if (Config.FUNCTIONS.containsKey(left.get().name())) {
66+
Config.FUNCTIONS.remove(left.get().name());
67+
Config.refreshJson();
68+
return ChatHelper.replaceSection(field, "");
69+
}
70+
} else if (right.isPresent()) {
71+
if (Config.CONSTANTS.containsKey(right.get().name())) {
72+
Config.CONSTANTS.remove(right.get().name());
73+
Config.refreshJson();
74+
return ChatHelper.replaceSection(field, "");
75+
}
76+
}
77+
}
5378
}
5479
}
5580
}
@@ -61,7 +86,10 @@ public static boolean tryParse(TextFieldWidget field) {
6186
Testcases.test(Testcases.TESTCASES);
6287
return false;
6388
} else if (text.equals("functions?")) {
64-
client.player.sendMessage(Text.literal("Currently defined custom functions are:\n" + Config.FUNCTIONS.values().stream().map(CallableFunction::toString).collect(Collectors.joining("\n"))));
89+
client.player.sendMessage(Config.FUNCTIONS.values().stream().map(CustomFunction::toString).map(str -> Text.literal(str).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, str)).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Click to copy to clipboard"))))).collect(() -> Text.literal("Currently defined custom functions are:"), (a, b) -> a.append(Text.literal("\n").append(b)), MutableText::append));
90+
return false;
91+
} else if (text.equals("constants?")) {
92+
client.player.sendMessage(Config.CONSTANTS.values().stream().map(CustomConstant::toString).map(str -> Text.literal(str).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, str)).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Click to copy to clipboard"))))).collect(() -> Text.literal("Currently defined custom constants are:"), (a, b) -> a.append(Text.literal("\n").append(b)), MutableText::append));
6593
return false;
6694
} else if (NUMBER.matcher(text).matches()) {
6795
return false;
@@ -85,10 +113,14 @@ public static boolean tryParse(TextFieldWidget field) {
85113
}
86114
Config.saveToChatHud(originalText);
87115
Config.saveToClipboard(originalText);
88-
return add ? ChatHelper.addWordAfterIndex(field, solution) : ChatHelper.replaceWord(field, solution);
116+
return add ? ChatHelper.addSectionAfterIndex(field, solution) : ChatHelper.replaceSection(field, solution);
89117
} catch (Throwable t) {
90118
return false;
91119
}
92120
}
93121
}
122+
123+
private static Optional<Either<CustomFunction, CustomConstant>> parseDeclaration(String text) {
124+
return CustomFunction.fromString(text).map(Either::<CustomFunction, CustomConstant>left).or(() -> CustomConstant.fromString(text).map(Either::<CustomFunction, CustomConstant>right));
125+
}
94126
}

src/main/java/ca/rttv/chatcalc/ChatHelper.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
import net.minecraft.client.gui.widget.TextFieldWidget;
44

55
public class ChatHelper {
6-
public static String getWord(String input, int cursor) {
7-
return input.substring(ChatHelper.getStartOfWord(input, cursor), ChatHelper.getEndOfWord(input, cursor));
6+
public static String getSection(String input, int cursor) {
7+
return input.substring(ChatHelper.getStartOfSection(input, cursor), ChatHelper.getEndOfSection(input, cursor));
88
}
99

10-
public static boolean replaceWord(TextFieldWidget field, String replacement) {
10+
public static boolean replaceSection(TextFieldWidget field, String replacement) {
1111
String input = field.getText();
1212
int cursor = field.getCursor();
13-
int start = ChatHelper.getStartOfWord(input, cursor);
14-
int end = ChatHelper.getEndOfWord(input, cursor);
13+
int start = ChatHelper.getStartOfSection(input, cursor);
14+
int end = ChatHelper.getEndOfSection(input, cursor);
1515
String output = input.substring(0, start) + replacement + input.substring(end);
1616
if (output.length() > 256 || input.substring(start, end).equals(replacement)) {
1717
return false;
@@ -20,9 +20,9 @@ public static boolean replaceWord(TextFieldWidget field, String replacement) {
2020
return true;
2121
}
2222

23-
public static boolean addWordAfterIndex(TextFieldWidget field, String word) {
23+
public static boolean addSectionAfterIndex(TextFieldWidget field, String word) {
2424
String input = field.getText();
25-
int index = ChatHelper.getEndOfWord(input, field.getCursor());
25+
int index = ChatHelper.getEndOfSection(input, field.getCursor());
2626
String output = input.substring(0, index) + word + input.substring(index);
2727
if (output.length() > 256) {
2828
return false;
@@ -31,7 +31,7 @@ public static boolean addWordAfterIndex(TextFieldWidget field, String word) {
3131
return true;
3232
}
3333

34-
public static int getStartOfWord(String input, int cursor) {
34+
public static int getStartOfSection(String input, int cursor) {
3535
if (cursor == 0) {
3636
return 0;
3737
}
@@ -46,7 +46,7 @@ public static int getStartOfWord(String input, int cursor) {
4646
return 0;
4747
}
4848

49-
public static int getEndOfWord(String input, int cursor) {
49+
public static int getEndOfSection(String input, int cursor) {
5050
if (cursor == input.length() - 1) {
5151
return cursor;
5252
}

src/main/java/ca/rttv/chatcalc/Config.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public class Config {
1414
public static final JsonObject JSON;
1515
public static final Gson GSON;
1616
public static final File CONFIG_FILE;
17-
public static final Map<String, CallableFunction> FUNCTIONS;
17+
public static final Map<String, CustomFunction> FUNCTIONS;
18+
public static final Map<String, CustomConstant> CONSTANTS;
1819
public static final ImmutableMap<String, String> DEFAULTS;
1920

2021
static {
@@ -44,6 +45,7 @@ public class Config {
4445
} catch (IOException ignored) {}
4546
}
4647
FUNCTIONS = new HashMap<>();
48+
CONSTANTS = new HashMap<>();
4749
if (CONFIG_FILE.exists() && CONFIG_FILE.isFile() && CONFIG_FILE.canRead()) {
4850
readJson();
4951
}
@@ -77,8 +79,10 @@ public static void refreshJson() {
7779
try {
7880
FileWriter writer = new FileWriter(CONFIG_FILE);
7981
JSON.add("functions", FUNCTIONS.values().stream().map(Object::toString).collect(JsonArray::new, JsonArray::add, JsonArray::addAll));
82+
JSON.add("constants", CONSTANTS.values().stream().map(Object::toString).collect(JsonArray::new, JsonArray::add, JsonArray::addAll));
8083
writer.write(GSON.toJson(JSON));
8184
JSON.remove("functions");
85+
JSON.remove("constants");
8286
writer.close();
8387
} catch (Exception ignored) { }
8488
}
@@ -97,10 +101,17 @@ public static void readJson() {
97101
if (json.obj.get("functions") instanceof JsonArray array) {
98102
array.forEach(e -> {
99103
if (e instanceof JsonPrimitive primitive && primitive.isString()) {
100-
CallableFunction.fromString(e.getAsString()).ifPresent(func -> FUNCTIONS.put(func.name(), func));
104+
CustomFunction.fromString(e.getAsString()).ifPresent(func -> FUNCTIONS.put(func.name(), func));
101105
}
102106
});
103107
}
108+
if (json.obj.get("constants") instanceof JsonArray array) {
109+
for (JsonElement e : array) {
110+
if (e instanceof JsonPrimitive primitive && primitive.isString()) {
111+
CustomConstant.fromString(e.getAsString()).ifPresent(constant -> CONSTANTS.put(constant.name(), constant));
112+
}
113+
}
114+
}
104115
} catch (Exception ignored) { }
105116
}
106117

@@ -114,12 +125,12 @@ public static void saveToChatHud(String input) {
114125
}
115126

116127
public static double func(String name, double... values) {
117-
CallableFunction func = FUNCTIONS.get(name);
128+
CustomFunction func = FUNCTIONS.get(name);
118129
if (func != null) {
119130
if (values.length != func.params().length) {
120131
throw new IllegalArgumentException("Invalid amount of arguments for custom function");
121132
}
122-
String input = func.rest();
133+
String input = func.eval();
123134
FunctionParameter[] parameters = new FunctionParameter[values.length];
124135
for (int i = 0; i < parameters.length; i++) {
125136
parameters[i] = new FunctionParameter(func.params()[i], values[i]);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package ca.rttv.chatcalc;
2+
3+
import java.util.Optional;
4+
5+
public record CustomConstant(String name, String eval) {
6+
7+
public static Optional<CustomConstant> fromString(String text) {
8+
int equalsIdx = text.indexOf('=');
9+
if (equalsIdx == -1) {
10+
return Optional.empty();
11+
}
12+
13+
String lhs = text.substring(0, equalsIdx);
14+
String rhs = text.substring(equalsIdx + 1);
15+
16+
if (!ChatCalc.CONSTANT.matcher(lhs).matches()) {
17+
return Optional.empty();
18+
}
19+
20+
return Optional.of(new CustomConstant(lhs, rhs));
21+
}
22+
23+
public double value() {
24+
return Config.makeEngine().eval(eval, new FunctionParameter[0]);
25+
}
26+
27+
@Override
28+
public String toString() {
29+
return name + "=" + eval;
30+
}
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package ca.rttv.chatcalc;
2+
3+
import java.util.Optional;
4+
5+
public record CustomFunction(String name, String eval, String[] params) {
6+
public static Optional<CustomFunction> fromString(String text) {
7+
int equalsIdx = text.indexOf('=');
8+
if (equalsIdx == -1) {
9+
return Optional.empty();
10+
}
11+
String lhs = text.substring(0, equalsIdx);
12+
String rhs = text.substring(equalsIdx + 1);
13+
if (!ChatCalc.FUNCTION.matcher(lhs).matches()) {
14+
return Optional.empty();
15+
}
16+
int functionNameEnd = lhs.indexOf('(');
17+
String functionName = lhs.substring(0, functionNameEnd);
18+
int paramsEnd = lhs.substring(functionNameEnd).indexOf(')') + functionNameEnd;
19+
String[] params = lhs.substring(functionNameEnd + 1, paramsEnd).split(ChatCalc.SEPARATOR);
20+
return Optional.of(new CustomFunction(functionName, rhs, params));
21+
}
22+
23+
@Override
24+
public String toString() {
25+
return name + '(' + String.join(ChatCalc.SEPARATOR, params) + ")=" + eval;
26+
}
27+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package ca.rttv.chatcalc;
2+
3+
import net.minecraft.client.MinecraftClient;
4+
import net.minecraft.util.math.MathHelper;
5+
6+
import java.util.LinkedHashSet;
7+
import java.util.function.DoubleSupplier;
8+
9+
public class MathematicalConstant {
10+
public static final LinkedHashSet<MathematicalConstant> CONSTANTS = new LinkedHashSet<>();
11+
12+
static {
13+
CONSTANTS.add(new MathematicalConstant("random", Math::random));
14+
CONSTANTS.add(new MathematicalConstant("rand", Math::random));
15+
CONSTANTS.add(new MathematicalConstant("rad", () -> Config.radians() ? 1.0 : 57.29577951308232));
16+
CONSTANTS.add(new MathematicalConstant("deg", () -> Config.radians() ? 0.017453292519943295 : 1.0));
17+
CONSTANTS.add(new MathematicalConstant("yaw", () -> Config.convertFromDegrees(MathHelper.wrapDegrees(MinecraftClient.getInstance().player.getYaw()))));
18+
CONSTANTS.add(new MathematicalConstant("pitch", () -> Config.convertFromDegrees(MathHelper.wrapDegrees(MinecraftClient.getInstance().player.getPitch()))));
19+
CONSTANTS.add(new MathematicalConstant("pi", () -> Math.PI));
20+
CONSTANTS.add(new MathematicalConstant("tau", () -> 2.0d * Math.PI));
21+
CONSTANTS.add(new MathematicalConstant("e", () -> Math.E));
22+
CONSTANTS.add(new MathematicalConstant("phi", () -> 1.6180339887498948482));
23+
CONSTANTS.add(new MathematicalConstant("x", () -> MinecraftClient.getInstance().player.getPos().x));
24+
CONSTANTS.add(new MathematicalConstant("y", () -> MinecraftClient.getInstance().player.getPos().y));
25+
CONSTANTS.add(new MathematicalConstant("z", () -> MinecraftClient.getInstance().player.getPos().z));
26+
}
27+
28+
private final String name;
29+
private final DoubleSupplier value;
30+
31+
public MathematicalConstant(String name, DoubleSupplier value) {
32+
this.name = name;
33+
this.value = value;
34+
}
35+
36+
public String name() {
37+
return name;
38+
}
39+
40+
public double value() {
41+
return value.getAsDouble();
42+
}
43+
}

0 commit comments

Comments
 (0)