diff --git a/src/main/java/land/chipmunk/chipmunkmod/ChipmunkMod.java b/src/main/java/land/chipmunk/chipmunkmod/ChipmunkMod.java index 1ba0e84..5e75e01 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/ChipmunkMod.java +++ b/src/main/java/land/chipmunk/chipmunkmod/ChipmunkMod.java @@ -1,6 +1,7 @@ package land.chipmunk.chipmunkmod; import com.google.gson.GsonBuilder; +import land.chipmunk.chipmunkmod.testclient.modules.utility.AntiChatSpamModule; import land.chipmunk.chipmunkmod.util.Keybinds; import land.chipmunk.chipmunkmod.util.TickRunnableHandler; import land.chipmunk.chipmunkmod.util.gson.BlockPosTypeAdapter; diff --git a/src/main/java/land/chipmunk/chipmunkmod/Configuration.java b/src/main/java/land/chipmunk/chipmunkmod/Configuration.java index 5669d52..1c12922 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/Configuration.java +++ b/src/main/java/land/chipmunk/chipmunkmod/Configuration.java @@ -10,6 +10,7 @@ public class Configuration { public CommandCore core = new CommandCore(); public Bots bots = new Bots(); public CustomChat customChat = new CustomChat(); + public AntiSpam antiSpam = new AntiSpam(); public boolean fullbright = true; // should this be false? public String autoSkinUsername = "off"; public String testbotWebhook = null; @@ -40,4 +41,10 @@ public class Configuration { public static class CustomChat { public JsonObject format; } + + public static class AntiSpam { + public int matchingMessagesToBeSpam = 50; + public int messageTimeInTicks = 100; + public int blockedPatternDurationInTicks = 72000; + } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/command/CommandManager.java b/src/main/java/land/chipmunk/chipmunkmod/command/CommandManager.java index 2953ac5..e3854fc 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/command/CommandManager.java +++ b/src/main/java/land/chipmunk/chipmunkmod/command/CommandManager.java @@ -42,6 +42,7 @@ public class CommandManager { ReloadConfigCommand.register(this.dispatcher); LoopCrouchCommand.register(this.dispatcher); AutoDeopCommand.register(this.dispatcher); + DebugCommand.register(this.dispatcher); } public void executeCommand (String command) { diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/DebugCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/DebugCommand.java new file mode 100644 index 0000000..7fb9621 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/DebugCommand.java @@ -0,0 +1,65 @@ +package land.chipmunk.chipmunkmod.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import land.chipmunk.chipmunkmod.util.Debug; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.ArrayList; + +import static land.chipmunk.chipmunkmod.command.CommandManager.literal; +import static land.chipmunk.chipmunkmod.command.CommandManager.argument; +import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; +import static com.mojang.brigadier.arguments.StringArgumentType.string; + +public class DebugCommand { + public static SuggestionProvider knownSuggestions = (context, builder) -> { + Debug.known.stream() + .filter(option -> option.startsWith(builder.getRemaining().toLowerCase())) + .forEach(builder::suggest); + return builder.buildFuture(); + }; + public static SuggestionProvider selectedSuggestions = (context, builder) -> { + Debug.selected.stream() + .filter(option -> option.startsWith(builder.getRemaining().toLowerCase())) + .forEach(builder::suggest); + return builder.buildFuture(); + }; + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + literal("debug") + .then(literal("add") + .then(argument("caller", string()) + .suggests(knownSuggestions) + .executes(DebugCommand::add))) + .then(literal("remove") + .then(argument("caller", string()) + .suggests(selectedSuggestions) + .executes(DebugCommand::remove))) + .then(literal("clear") + .executes(DebugCommand::clear)) + ); + } + + public static int add(CommandContext context) { + String caller = context.getArgument("caller", String.class); + Debug.selected.add(caller); + context.getSource().sendFeedback(Text.literal("Added ").append(Text.literal(caller).formatted(Formatting.YELLOW)).append(Text.literal(" to the debug list!"))); + return 0; + } + public static int remove(CommandContext context) { + String caller = context.getArgument("caller", String.class); + Debug.selected.remove(caller); + context.getSource().sendFeedback(Text.literal("Removed ").append(Text.literal(caller).formatted(Formatting.YELLOW)).append(Text.literal(" from the debug list!"))); + return 0; + } + public static int clear(CommandContext context) { + Debug.selected = new ArrayList<>(); + context.getSource().sendFeedback(Text.literal("Cleared the debug list!")); + return 0; + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/ValidateCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/ValidateCommand.java index bd844e7..ba7c510 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/commands/ValidateCommand.java +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/ValidateCommand.java @@ -100,7 +100,7 @@ public class ValidateCommand { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); - String time = String.valueOf(System.currentTimeMillis() / 10000); + String time = String.valueOf(System.currentTimeMillis() / 5000); String input = time + key; byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8)); String stringHash = Hexadecimal.encode(hash).substring(0, 16); diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatHudMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatHudMixin.java index 96a6430..ab0b04f 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatHudMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatHudMixin.java @@ -4,6 +4,7 @@ import land.chipmunk.chipmunkmod.listeners.Listener; import land.chipmunk.chipmunkmod.listeners.ListenerManager; import land.chipmunk.chipmunkmod.modules.RainbowName; import land.chipmunk.chipmunkmod.testclient.modules.op.AutoDeopModule; +import land.chipmunk.chipmunkmod.testclient.modules.utility.AntiChatSpamModule; import net.minecraft.client.gui.hud.MessageIndicator; import net.minecraft.network.message.MessageSignatureData; import net.minecraft.text.Text; @@ -49,6 +50,11 @@ public class ChatHudMixin { for (Listener listener : ListenerManager.listeners) { listener.chatMessageReceived(message); } + + for (AntiChatSpamModule.BlockedPattern pattern : AntiChatSpamModule.instance.patterns) { + if(pattern.pattern().matcher(message.getString()).matches()) ci.cancel(); + } + new AntiChatSpamModule.ChatMessage(message.getString()); } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ElderGuardianAppearanceParticleMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ElderGuardianAppearanceParticleMixin.java index 622c513..6be7fd1 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ElderGuardianAppearanceParticleMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ElderGuardianAppearanceParticleMixin.java @@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ElderGuardianAppearanceParticle.Factory.class) public class ElderGuardianAppearanceParticleMixin { - @Inject(method = "createParticle(Lnet/minecraft/particle/DefaultParticleType;Lnet/minecraft/client/world/ClientWorld;DDDDDD)Lnet/minecraft/client/particle/Particle;", at = @At("HEAD")) + @Inject(method = "createParticle(Lnet/minecraft/particle/DefaultParticleType;Lnet/minecraft/client/world/ClientWorld;DDDDDD)Lnet/minecraft/client/particle/Particle;", at = @At("HEAD"), cancellable = true) private void testClient$limitGuardianParticles(DefaultParticleType defaultParticleType, ClientWorld clientWorld, double d, double e, double f, double g, double h, double i, CallbackInfoReturnable cir) { if(BlockGuardianParticlesModule.instance.isEnabled) cir.cancel(); if(SharedVariables.elderGuardianParticleTimer > 0) cir.cancel(); diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/KeyboardInputMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/KeyboardInputMixin.java index a0bb60f..a82fc41 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/KeyboardInputMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/KeyboardInputMixin.java @@ -45,7 +45,7 @@ public class KeyboardInputMixin extends Input { } } - private float getMovementMultiplier(boolean positive, boolean negative) { + private static float getMovementMultiplier(boolean positive, boolean negative) { if (positive == negative) { return 0.0f; } diff --git a/src/main/java/land/chipmunk/chipmunkmod/testclient/gui/Gui.java b/src/main/java/land/chipmunk/chipmunkmod/testclient/gui/Gui.java index 923c5fb..642fee7 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/testclient/gui/Gui.java +++ b/src/main/java/land/chipmunk/chipmunkmod/testclient/gui/Gui.java @@ -10,6 +10,7 @@ import land.chipmunk.chipmunkmod.testclient.modules.op.AntiTeleportModule; import land.chipmunk.chipmunkmod.testclient.modules.op.AutoDeopModule; import land.chipmunk.chipmunkmod.testclient.modules.op.AutoOpModule; import land.chipmunk.chipmunkmod.testclient.modules.op.AutoSudoKickModule; +import land.chipmunk.chipmunkmod.testclient.modules.utility.AntiChatSpamModule; import land.chipmunk.chipmunkmod.testclient.modules.utility.AutoToolsModule; import land.chipmunk.chipmunkmod.testclient.modules.utility.BlockGuardianParticlesModule; import land.chipmunk.chipmunkmod.testclient.modules.utility.GuiMoveModule; @@ -181,6 +182,7 @@ public class Gui extends Screen{ .withModule(AntiVoidModule.instance) .withModule(BlockGuardianParticlesModule.instance) .withModule(new GuiMoveModule()) + .withModule(AntiChatSpamModule.instance) .register(); new Category("OP") .withModule(new AntiTeleportModule()) diff --git a/src/main/java/land/chipmunk/chipmunkmod/testclient/modules/utility/AntiChatSpamModule.java b/src/main/java/land/chipmunk/chipmunkmod/testclient/modules/utility/AntiChatSpamModule.java new file mode 100644 index 0000000..c9bbdb2 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/testclient/modules/utility/AntiChatSpamModule.java @@ -0,0 +1,320 @@ +package land.chipmunk.chipmunkmod.testclient.modules.utility; + +import land.chipmunk.chipmunkmod.ChipmunkMod; +import land.chipmunk.chipmunkmod.Configuration; +import land.chipmunk.chipmunkmod.testclient.gui.components.Module; +import land.chipmunk.chipmunkmod.util.Chat; +import land.chipmunk.chipmunkmod.util.Debug; +import land.chipmunk.chipmunkmod.util.Executor; +import lombok.Getter; +import lombok.Setter; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.minecraft.client.MinecraftClient; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; + +public class AntiChatSpamModule extends Module { + public static AntiChatSpamModule instance = new AntiChatSpamModule(); + public ArrayList messages = new ArrayList<>(); + public ArrayList patterns = new ArrayList<>(); + private int threadCheckStateTimer = 0; + private static final String debugCallerPrefix = "AntiChatSpam."; + private static final String debugTickedCaller = debugCallerPrefix + "tick"; + private static final String debugThreadCaller = debugCallerPrefix + "thread"; + private static final String debugRegexProcessCaller = debugCallerPrefix + "regex_process"; + private static final String debugRegexOutputCaller = debugCallerPrefix + "regex_output"; + private static final String debugComparableStringCaller = debugCallerPrefix + "comparable_string"; + public AntiChatSpamModule() { + super("Anti chat spam"); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + for (int i = 0; i < messages.size(); i++) { + Debug.debug("Ticked message: "+messages.get(i).content, debugTickedCaller); + messages.get(i).tick(); + } + for (int i = 0; i < patterns.size(); i++) { + Debug.debug("Ticked pattern: "+patterns.get(i).pattern().toString(), debugTickedCaller); + patterns.get(i).tick(); + } + if(threadCheckStateTimer >= 10) { + Debug.debug("Thread done: "+thread.isDone(), debugThreadCaller); + threadCheckStateTimer = -1; + } + threadCheckStateTimer++; + }); + + // ig make theredaadd thingy here because else it says it's null and stuff or idk + thread = Executor.submit(() -> { + boolean interrupted = false; + String caller = debugThreadCaller; + while(!interrupted) { + Debug.debug("woke up", caller); + while(threadQueue.size()>0) { + threadQueue.get(0).run(); + threadQueue.remove(0); + Debug.debug("ran a thing in the queue now "+threadQueue.size()+" left", caller); + } + Debug.debug("going zzz", caller); + try { + Thread.sleep(50); + } catch (InterruptedException e) { + interrupted = true; + Debug.debug("Thread interrupted by exception!", caller); + } catch (Exception e) { + Debug.debug("Got an exception or idk printing trace", caller); + e.printStackTrace(); + interrupted = true; + } + } + Debug.debug("out of while loop or idk bye ig!!!", caller); + }); + + } // 72000 ticks for expiry + // and ig remember messages for 100 ticks + + public static class ComparableString{ + @Getter @Setter private String value; + public int index = 0; + public ComparableString(String value) { + Debug.debug("Created comparable string with value: "+value, debugComparableStringCaller); + this.value = value; + } + public String getChar() { + if (index < 0 || value.length() < index) throw new RuntimeException("Index is out of bounds! (INDEX:"+index+", LENGTH:"+value.length()+")"); + String toReturn = switch (value.charAt(index)) { + case '.' -> "\\."; + case '[' -> "\\["; + case ']' -> "\\]"; + case '(' -> "\\("; + case ')' -> "\\)"; + case '*' -> "\\*"; + case '?' -> "\\?"; + default -> String.valueOf(value.charAt(index)); + }; + Debug.debug("Got character: "+toReturn, debugComparableStringCaller); + return toReturn; + } + + public void repeat(RepeatableRunnable runnable) { + while(index characters = new ArrayList<>(); + firstString.index = 0; + firstString.repeat(i -> { + Debug.debug("[A] Char index "+i+": "+firstString.getChar(), debugRegexProcessCaller); + secondString.index = 0; + secondString.repeat(j -> { + Debug.debug(" [B] Char index "+j+": "+secondString.getChar(), debugRegexProcessCaller); + if(firstString.getChar().equals(secondString.getChar())) { + Debug.debug("OMGOMG THEY MATCH adding to characters array", debugRegexProcessCaller); + characters.add(new CharacterInPattern(firstString.getChar(), i, j)); + return true; + } + return false; + }); + return false; + }); + + Debug.debug("--- SORTING CHARS ---", debugRegexProcessCaller); + // sort based on index sum + Comparator comparator = new Comparator() { + @Override + public int compare(CharacterInPattern character1, CharacterInPattern character2) { + return Integer.compare(character1.indexesSum(), character2.indexesSum()); + } + }; + characters.sort(comparator); + for (CharacterInPattern character : characters) { + Debug.debug(character.indexesSum() + " - " + character.character(), debugRegexProcessCaller); + } + + + Debug.debug("--- CONFIRMING & PLACING CHARACTERS ---", debugRegexProcessCaller); + ArrayList confirmedCharacters = new ArrayList<>(); + for (int k = 0, charactersSize = characters.size(); k < charactersSize; k++) { + CharacterInPattern character = characters.get(k); + Debug.debug("Finding if B has been placed", debugRegexProcessCaller); + //find if index B has been placed somewhere + AtomicBoolean isIndexBTaken = new AtomicBoolean(false); + confirmedCharacters.forEach(character1 -> { + if (character.indexB() == character1.indexB()) isIndexBTaken.set(true); + }); + + // if B has already been placed somewhere, resume analysis + if (isIndexBTaken.get()) { + Debug.debug("It has! resuping analysis", debugRegexProcessCaller); + firstString.index = character.indexA(); + secondString.index = character.indexB()+1; + Debug.debug("[A] Char index " + firstString.index + ": " + firstString.getChar(), debugRegexProcessCaller); + secondString.repeat(j -> { + Debug.debug(" [B] Char index " + j + ": " + secondString.getChar(), debugRegexProcessCaller); + if (firstString.getChar().equals(secondString.getChar())) { + Debug.debug("OMGOMG THEY MATCH adding to characters array", debugRegexProcessCaller); +// characters.add(new CharacterInPattern(firstString.getChar(), firstString.index, j)); + for (int i = 0, sortedCharactersSize = characters.size(); i < sortedCharactersSize; i++) { + CharacterInPattern sortedCharacter = characters.get(i); + if (sortedCharacter.indexesSum() < j) { + characters.add(i, new CharacterInPattern(firstString.getChar(), firstString.index, j)); + Debug.debug("Added to sorted chars at index " + i, debugRegexProcessCaller); + break; + } + } + return true; + } + return false; + }); + } + + // check if you can place it somewhere in the output + // this means that one index must never be greater than another character's if the other is not. + + // if it's the first character, add it no matter what. No need to check lol + if (character.indexesSum() == 0) { + Debug.debug("First char so putting it at start of output", debugRegexProcessCaller); + confirmedCharacters.add(character); + continue; + } + + // if output is empty and it's not the first character, add a .*? and then the character + if (confirmedCharacters.isEmpty()) { + Debug.debug("Not first char but output empty so putting .*? then char at start", debugRegexProcessCaller); + confirmedCharacters.add(new CharacterInPattern(".*?", 0, 0)); + confirmedCharacters.add(character); + continue; + } + + Debug.debug("Not at the start so checking where tf it is", debugRegexProcessCaller); + // end of special cases now just check if u can place it somewhere + AtomicInteger index = new AtomicInteger(); + boolean rightAfter = false; + for (int i = 0; i < confirmedCharacters.size(); i++) { + CharacterInPattern character1 = confirmedCharacters.get(i); + Debug.debug("Checking character " + character1.character(), debugRegexProcessCaller); + // right after the character + if (character.indexA() == character1.indexA() + 1 && character.indexB() == character1.indexB() + 1) { + Debug.debug("It's right after the char so placing it there", debugRegexProcessCaller); + i++; + if (i >= confirmedCharacters.size()) confirmedCharacters.add(character); + else confirmedCharacters.add(i, character); + rightAfter = true; + break; + } + } + for (int i = 0; i < confirmedCharacters.size() && !rightAfter; i++) { + CharacterInPattern character1 = confirmedCharacters.get(i); + Debug.debug("Checking character " + character1.character(), debugRegexProcessCaller); + //somewhere else after che character + if (character1.indexA() < character.indexA() && character1.indexB() < character.indexB()) { + Debug.debug("It's somewhere after the char so putting it there with .*? in front", debugRegexProcessCaller); + if (index.get() >= confirmedCharacters.size()) { + i++; + confirmedCharacters.add(new CharacterInPattern(".*?", character1.indexA() + 1, character.indexB() + 1)); + i++; + confirmedCharacters.add(character); + } else { + i++; + confirmedCharacters.add(i, new CharacterInPattern(".*?", character1.indexA() + 1, character.indexB() + 1)); + i++; + confirmedCharacters.add(i, character); + } + } + + index.getAndIncrement(); + } + + } + StringBuilder regex = new StringBuilder(); + for (int i = 0, confirmedCharactersSize = confirmedCharacters.size(); i < confirmedCharactersSize; i++) { + CharacterInPattern c = confirmedCharacters.get(i); + regex.append(c.character); + } + Debug.debug("Returning regex "+regex, debugRegexProcessCaller); + Debug.debug("Returning regex '"+regex+"' for strings:", debugRegexOutputCaller); + Debug.debug(" - "+firstString, debugRegexOutputCaller); + Debug.debug(" - "+secondString, debugRegexOutputCaller); + return Pattern.compile(regex.toString()); + } + + public static class CharacterInPattern { + @Getter private final String character; + @Getter private final int indexA; + @Getter private final int indexB; // setter so I can change it while resuming analysis later on + @Getter private final int indexesSum; + public CharacterInPattern(String character, int indexA, int indexB) { + this.character = character; + this.indexA = indexA; + this.indexB = indexB; + indexesSum = indexA + indexB; + } + } + + public interface RepeatableRunnable{ + /** + * @param i the current index + * @return if the loop should break + */ + boolean run(int i); // to repeat for the length of the string ig + } + + public static class ChatMessage { + @Getter private final String content; + public int timer = ChipmunkMod.CONFIG.antiSpam.messageTimeInTicks; + public ChatMessage(String content) { + this.content = content; + + threadQueue.add(() -> { + ArrayList chatMessages = instance.messages; + for (int i = 0; i < chatMessages.size(); i++) { + ChatMessage message = chatMessages.get(i); + Pattern pattern = getPattern(new ComparableString(this.content()), new ComparableString(message.content())); + int matching = 0; + for (ChatMessage message1 : instance.messages) { + if (pattern.matcher(message1.content()).matches()) matching++; + } + if (matching >= ChipmunkMod.CONFIG.antiSpam.matchingMessagesToBeSpam) { + instance.patterns.add(new BlockedPattern(pattern)); + } + } + }); + + instance.messages.add(this); + } + public void tick() {timer--; if(timer <= 0) instance.messages.remove(this);} + } + + public static class BlockedPattern { + @Getter private final Pattern pattern; + public int timer = ChipmunkMod.CONFIG.antiSpam.blockedPatternDurationInTicks; + public BlockedPattern(Pattern pattern) { + this.pattern = pattern; + instance.patterns.add(this); + Chat.send("[AntiSpam] Blocked pattern "+pattern.toString()); + } + public void tick() {timer--; if(timer <= 0) instance.patterns.remove(this);} + } + public static ArrayList threadQueue = new ArrayList<>(); + public static Future thread; + + public static void debug(String message) { + Debug.debug(message, "AntiChatSpam"); + } +} // holy shit 200 lines and i havent ran this once this is not going to go well +// it did not go well \ No newline at end of file diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/Debug.java b/src/main/java/land/chipmunk/chipmunkmod/util/Debug.java new file mode 100644 index 0000000..e11fc48 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/util/Debug.java @@ -0,0 +1,14 @@ +package land.chipmunk.chipmunkmod.util; + +import land.chipmunk.chipmunkmod.ChipmunkMod; + +import java.util.ArrayList; + +public class Debug { + public static ArrayList known = new ArrayList<>(); + public static ArrayList selected = new ArrayList<>(); + public static void debug(String string, String caller) { + if(selected.contains(caller)) ChipmunkMod.LOGGER.info(String.format("[DEBUG|%s] %s", caller, string)); + if(!known.contains(caller)) known.add(caller); + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/Executor.java b/src/main/java/land/chipmunk/chipmunkmod/util/Executor.java new file mode 100644 index 0000000..b485d17 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/util/Executor.java @@ -0,0 +1,12 @@ +package land.chipmunk.chipmunkmod.util; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class Executor { + public static ExecutorService service = Executors.newFixedThreadPool(10); + public static Future submit(Runnable runnable) { + return service.submit(runnable); + } +} diff --git a/src/main/resources/chipmunkmod.mixins.json b/src/main/resources/chipmunkmod.mixins.json index a1a0ff2..0f1471d 100644 --- a/src/main/resources/chipmunkmod.mixins.json +++ b/src/main/resources/chipmunkmod.mixins.json @@ -29,6 +29,7 @@ "mixins": [ "NbtIoInvoker", "PlayerEntityMixin", - "TextMixin" + "TextMixin", + "TextSerializerMixin" ] }