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

Commit

Permalink
- setting functions to not exist now works correctly
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
RealRTTV committed Dec 2, 2023
1 parent da22d42 commit 8ac0f62
Show file tree
Hide file tree
Showing 13 changed files with 379 additions and 349 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ org.gradle.jvmargs=-Xmx1G
loader_version=0.14.23

# Mod Properties
mod_version = 3.0.20
mod_version = 3.0.21
maven_group = ca.rttv
archives_base_name = chatcalc
30 changes: 0 additions & 30 deletions src/main/java/ca/rttv/chatcalc/CallableFunction.java

This file was deleted.

72 changes: 52 additions & 20 deletions src/main/java/ca/rttv/chatcalc/ChatCalc.java
Original file line number Diff line number Diff line change
@@ -1,55 +1,80 @@
package ca.rttv.chatcalc;

import com.mojang.datafixers.util.Either;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.HoverEvent;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

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

@Contract(value = "_->_", mutates = "param1")
public static boolean tryParse(TextFieldWidget field) {
public static boolean tryParse(@NotNull TextFieldWidget field) {
final MinecraftClient client = MinecraftClient.getInstance();
String originalText = field.getText();
int cursor = field.getCursor();
String text = ChatHelper.getWord(originalText, cursor);
String text = ChatHelper.getSection(originalText, cursor);
{
String[] split = text.split("=");
if (split.length == 2) {
if (Config.JSON.has(split[0])) {
Config.JSON.addProperty(split[0], split[1]);
Config.refreshJson();
return ChatHelper.replaceWord(field, "");
return ChatHelper.replaceSection(field, "");
} else {
Optional<CallableFunction> func = CallableFunction.fromString(text);
if (func.isPresent()) {
if (func.get().rest().isEmpty()) {
if (Config.FUNCTIONS.containsKey(func.get().name())) {
Config.FUNCTIONS.remove(func.get().name());
} else {
return false;
}
} else {
Config.FUNCTIONS.put(func.get().name(), func.get());
Optional<Either<CustomFunction, CustomConstant>> either = parseDeclaration(text);
if (either.isPresent()) {
Optional<CustomFunction> left = either.get().left();
Optional<CustomConstant> right = either.get().right();
if (left.isPresent()) {
Config.FUNCTIONS.put(left.get().name(), left.get());
Config.refreshJson();
return ChatHelper.replaceSection(field, "");
} else if (right.isPresent()) {
Config.CONSTANTS.put(right.get().name(), right.get());
Config.refreshJson();
return ChatHelper.replaceSection(field, "");
}
Config.refreshJson();
return ChatHelper.replaceWord(field, "");
}
}
} else if (split.length == 1) {
if (Config.JSON.has(split[0])) {
return ChatHelper.replaceWord(field, Config.JSON.get(split[0]).getAsString());
return ChatHelper.replaceSection(field, Config.JSON.get(split[0]).getAsString());
} else if (!split[0].isEmpty() && Config.JSON.has(split[0].substring(0, split[0].length() - 1)) && split[0].endsWith("?") && client.player != null) {
client.player.sendMessage(Text.translatable("chatcalc." + split[0].substring(0, split[0].length() - 1) + ".description"));
return false;
} else {
Optional<Either<CustomFunction, CustomConstant>> either = parseDeclaration(text);
if (either.isPresent()) {
Optional<CustomFunction> left = either.get().left();
Optional<CustomConstant> right = either.get().right();
if (left.isPresent()) {
if (Config.FUNCTIONS.containsKey(left.get().name())) {
Config.FUNCTIONS.remove(left.get().name());
Config.refreshJson();
return ChatHelper.replaceSection(field, "");
}
} else if (right.isPresent()) {
if (Config.CONSTANTS.containsKey(right.get().name())) {
Config.CONSTANTS.remove(right.get().name());
Config.refreshJson();
return ChatHelper.replaceSection(field, "");
}
}
}
}
}
}
Expand All @@ -61,7 +86,10 @@ public static boolean tryParse(TextFieldWidget field) {
Testcases.test(Testcases.TESTCASES);
return false;
} else if (text.equals("functions?")) {
client.player.sendMessage(Text.literal("Currently defined custom functions are:\n" + Config.FUNCTIONS.values().stream().map(CallableFunction::toString).collect(Collectors.joining("\n"))));
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));
return false;
} else if (text.equals("constants?")) {
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));
return false;
} else if (NUMBER.matcher(text).matches()) {
return false;
Expand All @@ -85,10 +113,14 @@ public static boolean tryParse(TextFieldWidget field) {
}
Config.saveToChatHud(originalText);
Config.saveToClipboard(originalText);
return add ? ChatHelper.addWordAfterIndex(field, solution) : ChatHelper.replaceWord(field, solution);
return add ? ChatHelper.addSectionAfterIndex(field, solution) : ChatHelper.replaceSection(field, solution);
} catch (Throwable t) {
return false;
}
}
}

private static Optional<Either<CustomFunction, CustomConstant>> parseDeclaration(String text) {
return CustomFunction.fromString(text).map(Either::<CustomFunction, CustomConstant>left).or(() -> CustomConstant.fromString(text).map(Either::<CustomFunction, CustomConstant>right));
}
}
18 changes: 9 additions & 9 deletions src/main/java/ca/rttv/chatcalc/ChatHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import net.minecraft.client.gui.widget.TextFieldWidget;

public class ChatHelper {
public static String getWord(String input, int cursor) {
return input.substring(ChatHelper.getStartOfWord(input, cursor), ChatHelper.getEndOfWord(input, cursor));
public static String getSection(String input, int cursor) {
return input.substring(ChatHelper.getStartOfSection(input, cursor), ChatHelper.getEndOfSection(input, cursor));
}

public static boolean replaceWord(TextFieldWidget field, String replacement) {
public static boolean replaceSection(TextFieldWidget field, String replacement) {
String input = field.getText();
int cursor = field.getCursor();
int start = ChatHelper.getStartOfWord(input, cursor);
int end = ChatHelper.getEndOfWord(input, cursor);
int start = ChatHelper.getStartOfSection(input, cursor);
int end = ChatHelper.getEndOfSection(input, cursor);
String output = input.substring(0, start) + replacement + input.substring(end);
if (output.length() > 256 || input.substring(start, end).equals(replacement)) {
return false;
Expand All @@ -20,9 +20,9 @@ public static boolean replaceWord(TextFieldWidget field, String replacement) {
return true;
}

public static boolean addWordAfterIndex(TextFieldWidget field, String word) {
public static boolean addSectionAfterIndex(TextFieldWidget field, String word) {
String input = field.getText();
int index = ChatHelper.getEndOfWord(input, field.getCursor());
int index = ChatHelper.getEndOfSection(input, field.getCursor());
String output = input.substring(0, index) + word + input.substring(index);
if (output.length() > 256) {
return false;
Expand All @@ -31,7 +31,7 @@ public static boolean addWordAfterIndex(TextFieldWidget field, String word) {
return true;
}

public static int getStartOfWord(String input, int cursor) {
public static int getStartOfSection(String input, int cursor) {
if (cursor == 0) {
return 0;
}
Expand All @@ -46,7 +46,7 @@ public static int getStartOfWord(String input, int cursor) {
return 0;
}

public static int getEndOfWord(String input, int cursor) {
public static int getEndOfSection(String input, int cursor) {
if (cursor == input.length() - 1) {
return cursor;
}
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/ca/rttv/chatcalc/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class Config {
public static final JsonObject JSON;
public static final Gson GSON;
public static final File CONFIG_FILE;
public static final Map<String, CallableFunction> FUNCTIONS;
public static final Map<String, CustomFunction> FUNCTIONS;
public static final Map<String, CustomConstant> CONSTANTS;
public static final ImmutableMap<String, String> DEFAULTS;

static {
Expand Down Expand Up @@ -44,6 +45,7 @@ public class Config {
} catch (IOException ignored) {}
}
FUNCTIONS = new HashMap<>();
CONSTANTS = new HashMap<>();
if (CONFIG_FILE.exists() && CONFIG_FILE.isFile() && CONFIG_FILE.canRead()) {
readJson();
}
Expand Down Expand Up @@ -77,8 +79,10 @@ public static void refreshJson() {
try {
FileWriter writer = new FileWriter(CONFIG_FILE);
JSON.add("functions", FUNCTIONS.values().stream().map(Object::toString).collect(JsonArray::new, JsonArray::add, JsonArray::addAll));
JSON.add("constants", CONSTANTS.values().stream().map(Object::toString).collect(JsonArray::new, JsonArray::add, JsonArray::addAll));
writer.write(GSON.toJson(JSON));
JSON.remove("functions");
JSON.remove("constants");
writer.close();
} catch (Exception ignored) { }
}
Expand All @@ -97,10 +101,17 @@ public static void readJson() {
if (json.obj.get("functions") instanceof JsonArray array) {
array.forEach(e -> {
if (e instanceof JsonPrimitive primitive && primitive.isString()) {
CallableFunction.fromString(e.getAsString()).ifPresent(func -> FUNCTIONS.put(func.name(), func));
CustomFunction.fromString(e.getAsString()).ifPresent(func -> FUNCTIONS.put(func.name(), func));
}
});
}
if (json.obj.get("constants") instanceof JsonArray array) {
for (JsonElement e : array) {
if (e instanceof JsonPrimitive primitive && primitive.isString()) {
CustomConstant.fromString(e.getAsString()).ifPresent(constant -> CONSTANTS.put(constant.name(), constant));
}
}
}
} catch (Exception ignored) { }
}

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

public static double func(String name, double... values) {
CallableFunction func = FUNCTIONS.get(name);
CustomFunction func = FUNCTIONS.get(name);
if (func != null) {
if (values.length != func.params().length) {
throw new IllegalArgumentException("Invalid amount of arguments for custom function");
}
String input = func.rest();
String input = func.eval();
FunctionParameter[] parameters = new FunctionParameter[values.length];
for (int i = 0; i < parameters.length; i++) {
parameters[i] = new FunctionParameter(func.params()[i], values[i]);
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/ca/rttv/chatcalc/CustomConstant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ca.rttv.chatcalc;

import java.util.Optional;

public record CustomConstant(String name, String eval) {

public static Optional<CustomConstant> fromString(String text) {
int equalsIdx = text.indexOf('=');
if (equalsIdx == -1) {
return Optional.empty();
}

String lhs = text.substring(0, equalsIdx);
String rhs = text.substring(equalsIdx + 1);

if (!ChatCalc.CONSTANT.matcher(lhs).matches()) {
return Optional.empty();
}

return Optional.of(new CustomConstant(lhs, rhs));
}

public double value() {
return Config.makeEngine().eval(eval, new FunctionParameter[0]);
}

@Override
public String toString() {
return name + "=" + eval;
}
}
27 changes: 27 additions & 0 deletions src/main/java/ca/rttv/chatcalc/CustomFunction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ca.rttv.chatcalc;

import java.util.Optional;

public record CustomFunction(String name, String eval, String[] params) {
public static Optional<CustomFunction> fromString(String text) {
int equalsIdx = text.indexOf('=');
if (equalsIdx == -1) {
return Optional.empty();
}
String lhs = text.substring(0, equalsIdx);
String rhs = text.substring(equalsIdx + 1);
if (!ChatCalc.FUNCTION.matcher(lhs).matches()) {
return Optional.empty();
}
int functionNameEnd = lhs.indexOf('(');
String functionName = lhs.substring(0, functionNameEnd);
int paramsEnd = lhs.substring(functionNameEnd).indexOf(')') + functionNameEnd;
String[] params = lhs.substring(functionNameEnd + 1, paramsEnd).split(ChatCalc.SEPARATOR);
return Optional.of(new CustomFunction(functionName, rhs, params));
}

@Override
public String toString() {
return name + '(' + String.join(ChatCalc.SEPARATOR, params) + ")=" + eval;
}
}
43 changes: 43 additions & 0 deletions src/main/java/ca/rttv/chatcalc/MathematicalConstant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ca.rttv.chatcalc;

import net.minecraft.client.MinecraftClient;
import net.minecraft.util.math.MathHelper;

import java.util.LinkedHashSet;
import java.util.function.DoubleSupplier;

public class MathematicalConstant {
public static final LinkedHashSet<MathematicalConstant> CONSTANTS = new LinkedHashSet<>();

static {
CONSTANTS.add(new MathematicalConstant("random", Math::random));
CONSTANTS.add(new MathematicalConstant("rand", Math::random));
CONSTANTS.add(new MathematicalConstant("rad", () -> Config.radians() ? 1.0 : 57.29577951308232));
CONSTANTS.add(new MathematicalConstant("deg", () -> Config.radians() ? 0.017453292519943295 : 1.0));
CONSTANTS.add(new MathematicalConstant("yaw", () -> Config.convertFromDegrees(MathHelper.wrapDegrees(MinecraftClient.getInstance().player.getYaw()))));
CONSTANTS.add(new MathematicalConstant("pitch", () -> Config.convertFromDegrees(MathHelper.wrapDegrees(MinecraftClient.getInstance().player.getPitch()))));
CONSTANTS.add(new MathematicalConstant("pi", () -> Math.PI));
CONSTANTS.add(new MathematicalConstant("tau", () -> 2.0d * Math.PI));
CONSTANTS.add(new MathematicalConstant("e", () -> Math.E));
CONSTANTS.add(new MathematicalConstant("phi", () -> 1.6180339887498948482));
CONSTANTS.add(new MathematicalConstant("x", () -> MinecraftClient.getInstance().player.getPos().x));
CONSTANTS.add(new MathematicalConstant("y", () -> MinecraftClient.getInstance().player.getPos().y));
CONSTANTS.add(new MathematicalConstant("z", () -> MinecraftClient.getInstance().player.getPos().z));
}

private final String name;
private final DoubleSupplier value;

public MathematicalConstant(String name, DoubleSupplier value) {
this.name = name;
this.value = value;
}

public String name() {
return name;
}

public double value() {
return value.getAsDouble();
}
}
Loading

0 comments on commit 8ac0f62

Please sign in to comment.