diff --git a/src/main/java/land/chipmunk/chipmunkmod/ChipmunkMod.java b/src/main/java/land/chipmunk/chipmunkmod/ChipmunkMod.java index 5e75e01..b3cec05 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/ChipmunkMod.java +++ b/src/main/java/land/chipmunk/chipmunkmod/ChipmunkMod.java @@ -1,9 +1,10 @@ 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.modules.KaboomCheck; +import land.chipmunk.chipmunkmod.modules.Players; import land.chipmunk.chipmunkmod.util.gson.BlockPosTypeAdapter; import net.fabricmc.api.ModInitializer; import java.io.InputStream; @@ -14,6 +15,8 @@ import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import net.minecraft.util.math.BlockPos; import org.slf4j.Logger; @@ -29,6 +32,8 @@ public class ChipmunkMod implements ModInitializer { private static File CONFIG_DIR = new File("config"); private static File CONFIG_FILE = new File(CONFIG_DIR, "chipmunkmod.json"); + public static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + @Override public void onInitialize () { // This code runs as soon as Minecraft is in a mod-load-ready state. @@ -43,6 +48,11 @@ public class ChipmunkMod implements ModInitializer { Keybinds.registerOpenGui(); TickRunnableHandler.registerTickEndRunnables(); LOGGER.info("Loaded ChipmunkMod (Blackilykat's fork)"); + + Players.INSTANCE.init(); + KaboomCheck.INSTANCE.init(); + + LOGGER.info("Loaded ChipmunkMod (chayapak's fork)"); } public static Configuration loadConfig () throws IOException { diff --git a/src/main/java/land/chipmunk/chipmunkmod/Configuration.java b/src/main/java/land/chipmunk/chipmunkmod/Configuration.java index 838e31c..924b623 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/Configuration.java +++ b/src/main/java/land/chipmunk/chipmunkmod/Configuration.java @@ -29,7 +29,13 @@ public class Configuration { public BotInfo chipmunk = new BotInfo("'", null); public BotInfo chomens = new BotInfo("*", null); public BotInfo kittycorp = new BotInfo("^", null); - public BotInfo testbot = new BotInfo("-", null); + public TestBotInfo testbot = new TestBotInfo("-", null); + } + + @AllArgsConstructor + public static class TestBotInfo { + public String prefix; + public String webhookUrl; } @AllArgsConstructor diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/MusicCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/MusicCommand.java index b2bc007..0e34a42 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/commands/MusicCommand.java +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/MusicCommand.java @@ -24,6 +24,8 @@ import java.util.List; import static com.mojang.brigadier.arguments.BoolArgumentType.bool; import static com.mojang.brigadier.arguments.BoolArgumentType.getBool; +import static com.mojang.brigadier.arguments.FloatArgumentType.floatArg; +import static com.mojang.brigadier.arguments.FloatArgumentType.getFloat; import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger; import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; import static com.mojang.brigadier.arguments.LongArgumentType.getLong; @@ -58,10 +60,10 @@ public class MusicCommand { .then( literal("list") - .executes(c -> instance.list(c, root)) + .executes(c -> instance.list(root)) .then( argument("location", filepath(root)) - .executes(c -> instance.list(c, getPath(c, "location"))) + .executes(c -> instance.list(getPath(c, "location"))) ) ) @@ -81,6 +83,7 @@ public class MusicCommand { .executes(instance::gotoCommand) ) ) + .then( literal("useCore") .then( @@ -88,6 +91,22 @@ public class MusicCommand { .executes(instance::useCore) ) ) + + .then( + literal("actionbar") + .then( + argument("boolean", bool()) + .executes(instance::actionbar) + ) + ) + + .then( + literal("pitch") + .then( + argument("pitch", floatArg()) + .executes(instance::pitch) + ) + ) ); } @@ -145,9 +164,7 @@ public class MusicCommand { return 1; } - public int list (CommandContext context, Path path) throws CommandSyntaxException { - final FabricClientCommandSource source = context.getSource(); - + public int list (Path path) throws CommandSyntaxException { final CommandManager commandManager = CommandManager.INSTANCE; final String prefix = commandManager.prefix; @@ -279,4 +296,33 @@ public class MusicCommand { return 1; } + + public int actionbar (CommandContext context) { + final FabricClientCommandSource source = context.getSource(); + + final boolean enabled = getBool(context, "boolean"); + + SongPlayer.INSTANCE.actionbar(enabled); + + source.sendFeedback(Text.literal("Showing actionbar is now " + (enabled ? "enabled" : "disabled"))); + + return 1; + } + + public int pitch (CommandContext context) { + final FabricClientCommandSource source = context.getSource(); + + final float pitch = getFloat(context, "pitch"); + + SongPlayer.INSTANCE.pitch(pitch); + + source.sendFeedback( + Text.translatable( + "Set the pitch to: %s", + Text.literal(String.valueOf(pitch)) + ).formatted(Formatting.GREEN) + ); + + return 1; + } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/ReloadConfigCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/ReloadConfigCommand.java index 8af6f2a..55d1486 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/commands/ReloadConfigCommand.java +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/ReloadConfigCommand.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import land.chipmunk.chipmunkmod.ChipmunkMod; +import land.chipmunk.chipmunkmod.modules.CommandCore; import land.chipmunk.chipmunkmod.modules.CustomChat; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.text.Text; @@ -27,6 +28,7 @@ public class ReloadConfigCommand { ChipmunkMod.CONFIG = ChipmunkMod.loadConfig(); CustomChat.INSTANCE.reloadFormat(); + CommandCore.INSTANCE.reloadRelativeArea(); source.sendFeedback(Text.literal("Successfully reloaded the config")); } catch (IOException e) { diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/UsernameCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/UsernameCommand.java index f91a413..ce291a5 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/commands/UsernameCommand.java +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/UsernameCommand.java @@ -20,7 +20,6 @@ import net.minecraft.client.util.Session; import net.minecraft.text.Text; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import java.util.Optional; import land.chipmunk.chipmunkmod.mixin.MinecraftClientAccessor; public class UsernameCommand { diff --git a/src/main/java/land/chipmunk/chipmunkmod/listeners/Listener.java b/src/main/java/land/chipmunk/chipmunkmod/listeners/Listener.java index 02eda9f..5542c0e 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/listeners/Listener.java +++ b/src/main/java/land/chipmunk/chipmunkmod/listeners/Listener.java @@ -6,7 +6,7 @@ import net.minecraft.text.Text; public class Listener { public void chatMessageReceived (Text message) {} - public void packetReceived (Packet packet) {} + public void packetReceived (Packet packet) {} - public void packetSent (Packet packet) {} + public void packetSent (Packet packet) {} } diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatScreenMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatScreenMixin.java index 90c4106..0a7a4a8 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatScreenMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatScreenMixin.java @@ -1,25 +1,31 @@ package land.chipmunk.chipmunkmod.mixin; import land.chipmunk.chipmunkmod.ChipmunkMod; +import land.chipmunk.chipmunkmod.command.CommandManager; import land.chipmunk.chipmunkmod.modules.CustomChat; -import land.chipmunk.chipmunkmod.util.SharedVariables; import land.chipmunk.chipmunkmod.util.Webhook; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.ChatInputSuggestor; +import net.minecraft.client.gui.screen.Screen; +import land.chipmunk.chipmunkmod.util.SharedVariables; import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import net.minecraft.client.MinecraftClient; -import land.chipmunk.chipmunkmod.command.CommandManager; import java.io.IOException; @Mixin(net.minecraft.client.gui.screen.ChatScreen.class) -public class ChatScreenMixin { +public class ChatScreenMixin extends Screen { @Shadow protected TextFieldWidget chatField; + @Shadow private String originalChatText; + @Shadow ChatInputSuggestor chatInputSuggestor; + @Shadow private int messageHistorySize = -1; @Inject(at = @At("HEAD"), method = "sendMessage", cancellable = true) public void sendMessage(String chatText, boolean addToHistory, CallbackInfoReturnable cir) { @@ -37,6 +43,19 @@ public class ChatScreenMixin { } final CommandManager commandManager = CommandManager.INSTANCE; + if (ChipmunkMod.CONFIG.bots.testbot.webhookUrl != null) { + ChipmunkMod.executorService.submit(() -> { + final Webhook webhook = new Webhook(ChipmunkMod.CONFIG.bots.testbot.webhookUrl); + webhook.setUsername("ChipmunkMod"); + webhook.setContent(MinecraftClient.getInstance().getSession().getUsername()); + try { + webhook.execute(); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + if (chatText.startsWith(commandManager.prefix)) { commandManager.executeCommand(chatText.substring(commandManager.prefix.length())); @@ -52,13 +71,37 @@ public class ChatScreenMixin { } } - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/TextFieldWidget;setMaxLength(I)V"), method = "init") - public void init (CallbackInfo ci) { - chatField.setMaxLength(Integer.MAX_VALUE); + public ChatScreenMixin(String originalChatText) { + super(Text.translatable("chat_screen.title")); + this.originalChatText = originalChatText; } - @ModifyArg(method = "normalize", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/StringHelper;truncateChat(Ljava/lang/String;)Ljava/lang/String;")) - private String normalize (String text) { - return text; + @Inject(at = @At("TAIL"), method = "init", cancellable = true) + public void init (CallbackInfo ci) { + final MinecraftClient client = MinecraftClient.getInstance(); + + this.messageHistorySize = client.inGameHud.getChatHud().getMessageHistory().size(); + this.chatField = new TextFieldWidget(client.advanceValidatingTextRenderer, 4, this.height - 12, this.width - 4, 12, Text.translatable("chat.editBox")) { + protected MutableText getNarrationMessage() { + return super.getNarrationMessage().append(ChatScreenMixin.this.chatInputSuggestor.getNarration()); + } + }; + this.chatField.setMaxLength(Integer.MAX_VALUE); + this.chatField.setDrawsBackground(false); + this.chatField.setText(this.originalChatText); + this.chatField.setChangedListener(this::onChatFieldUpdate); + this.chatField.setFocusUnlocked(false); + this.addSelectableChild(this.chatField); + this.chatInputSuggestor = new ChatInputSuggestor(this.client, this, this.chatField, this.textRenderer, false, false, 1, 10, true, -805306368); + this.chatInputSuggestor.refresh(); + this.setInitialFocus(this.chatField); + + ci.cancel(); + } + + private void onChatFieldUpdate(String chatText) { + String string = this.chatField.getText(); + this.chatInputSuggestor.setWindowActive(!string.equals(this.originalChatText)); + this.chatInputSuggestor.refresh(); } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionAccessor.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionAccessor.java new file mode 100644 index 0000000..bc030c5 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionAccessor.java @@ -0,0 +1,12 @@ +package land.chipmunk.chipmunkmod.mixin; + +import net.minecraft.network.ClientConnection; +import net.minecraft.network.listener.PacketListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ClientConnection.class) +public interface ClientConnectionAccessor { + @Accessor("packetListener") + PacketListener packetListener (); +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionInvoker.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionInvoker.java new file mode 100644 index 0000000..a9800cb --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionInvoker.java @@ -0,0 +1,15 @@ +package land.chipmunk.chipmunkmod.mixin; + +import net.minecraft.network.ClientConnection; +import net.minecraft.network.listener.PacketListener; +import net.minecraft.network.packet.Packet; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ClientConnection.class) +public interface ClientConnectionInvoker { + @Invoker("handlePacket") + static void handlePacket (Packet packet, PacketListener listener) { + throw new AssertionError(); + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionMixin.java index 3077445..2bddd2c 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientConnectionMixin.java @@ -11,12 +11,18 @@ import net.minecraft.network.listener.PacketListener; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket; import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; +import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket; +import net.minecraft.registry.RegistryKey; +import net.minecraft.sound.SoundEvent; import net.minecraft.text.Text; +import net.minecraft.util.Identifier; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.Optional; + import java.util.ArrayList; @Mixin(net.minecraft.network.ClientConnection.class) @@ -39,6 +45,10 @@ public class ClientConnectionMixin { @Inject(method = "handlePacket", at = @At("HEAD"), cancellable = true) private static void handlePacket (Packet packet, PacketListener _listener, CallbackInfo ci) { + for (Listener listener : ListenerManager.listeners) { + listener.packetReceived(packet); + } + // please don't skid this.,. // mabe mabe mabe // lol i had my own im just gonna cop ypaste that :D @@ -47,10 +57,18 @@ public class ClientConnectionMixin { if(((ParticleS2CPacket) packet).getCount()>1000) Chat.sendGold("ChipmunkMod prevented a particle kick!"); ci.cancel(); } - } + } else if (packet instanceof PlaySoundS2CPacket t_packet) { + if (t_packet.getVolume() != 1) return; - for (Listener listener : ListenerManager.listeners) { - listener.packetReceived(packet); + final Optional> event = t_packet.getSound().getKey(); + + if (event.isEmpty()) return; + + final Identifier sound = event.get().getValue(); + + if (!sound.getPath().equals("entity.enderman.scream")) return; + + ci.cancel(); } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerAccessor.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerAccessor.java index 8170227..acb74c0 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerAccessor.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerAccessor.java @@ -1,11 +1,26 @@ package land.chipmunk.chipmunkmod.mixin; +import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.network.ClientConnection; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; import net.minecraft.text.Text; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + @Mixin(net.minecraft.client.network.ClientPlayNetworkHandler.class) public interface ClientPlayNetworkHandlerAccessor { @Accessor("CHAT_VALIDATION_FAILED_TEXT") - public static Text chatValidationFailedText () { throw new AssertionError(); } + static Text chatValidationFailedText () { throw new AssertionError(); } + + @Accessor("connection") + ClientConnection connection(); + + @Accessor("playerListEntries") + Map playerListEntries(); + + @Accessor("listedPlayerListEntries") + Set listedPlayerListEntries(); } diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerInvoker.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerInvoker.java new file mode 100644 index 0000000..9cac251 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerInvoker.java @@ -0,0 +1,11 @@ +package land.chipmunk.chipmunkmod.mixin; + +import net.minecraft.client.network.ClientPlayNetworkHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ClientPlayNetworkHandler.class) +public interface ClientPlayNetworkHandlerInvoker { + @Invoker("isSecureChatEnforced") + public boolean isSecureChatEnforced(); +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java index 79e984c..9cd2470 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java @@ -1,18 +1,19 @@ package land.chipmunk.chipmunkmod.mixin; +import land.chipmunk.chipmunkmod.ChipmunkMod; +import land.chipmunk.chipmunkmod.command.CommandManager; import land.chipmunk.chipmunkmod.modules.*; +import net.minecraft.client.network.ClientDynamicRegistryType; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; +import net.minecraft.registry.CombinedDynamicRegistries; +import net.minecraft.resource.featuretoggle.FeatureSet; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.resource.featuretoggle.FeatureSet; -import net.minecraft.registry.CombinedDynamicRegistries; -import net.minecraft.client.network.ClientDynamicRegistryType; -import land.chipmunk.chipmunkmod.ChipmunkMod; -import land.chipmunk.chipmunkmod.command.CommandManager; @Mixin(net.minecraft.client.network.ClientPlayNetworkHandler.class) public class ClientPlayNetworkHandlerMixin { @@ -23,6 +24,7 @@ public class ClientPlayNetworkHandlerMixin { private void onGameJoin (GameJoinS2CPacket packet, CallbackInfo ci) { final CommandRegistryAccess commandRegistryAccess = CommandRegistryAccess.of(this.combinedDynamicRegistries.getCombinedRegistryManager(), this.enabledFeatures); + KaboomCheck.INSTANCE.onJoin(); CommandManager.INSTANCE = new CommandManager(ChipmunkMod.CONFIG.commands.prefix, commandRegistryAccess); SelfCare.INSTANCE.init(); LoopCrouch.INSTANCE.init(); @@ -30,8 +32,8 @@ public class ClientPlayNetworkHandlerMixin { RainbowName.INSTANCE.init(); } - @Inject(method = "onGameJoin", at = @At("HEAD")) - private void onGameJoinHead (GameJoinS2CPacket packet, CallbackInfo ci) { - Players.INSTANCE.init(); + @Inject(method = "onPlayerRemove", at = @At("HEAD"), cancellable = true) + private void onPlayerRemove (PlayerRemoveS2CPacket packet, CallbackInfo ci) { + ci.cancel(); } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/DecoratedPotBlockEntitySherdsMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/DecoratedPotBlockEntitySherdsMixin.java new file mode 100644 index 0000000..cb5b5ac --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/DecoratedPotBlockEntitySherdsMixin.java @@ -0,0 +1,22 @@ +package land.chipmunk.chipmunkmod.mixin; + +import net.minecraft.block.entity.DecoratedPotBlockEntity; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtList; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +// https://github.com/LunaWasFlaggedAgain/Mojang-ResourceLocation-Challenge/blob/main/src/main/java/com/github/lunawasflaggedagain/mojangresourcelocationchallenge/mixin/DecoratedPotBlockEntitySherdsMixin.java +@Mixin(DecoratedPotBlockEntity.Sherds.class) +public class DecoratedPotBlockEntitySherdsMixin { + @Inject(method = "getSherd(Lnet/minecraft/nbt/NbtList;I)Lnet/minecraft/item/Item;", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Identifier;(Ljava/lang/String;)V"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) + private static void getSherd(NbtList list, int index, CallbackInfoReturnable cir, NbtElement nbtElement) { + if (!Identifier.isValid(nbtElement.asString())) cir.setReturnValue(Items.BRICK); + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/IdentifierMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/IdentifierMixin.java new file mode 100644 index 0000000..e7b24eb --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/IdentifierMixin.java @@ -0,0 +1,31 @@ +package land.chipmunk.chipmunkmod.mixin; + +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Identifier.class) +public class IdentifierMixin { + @Inject(method = "isNamespaceCharacterValid", at = @At("HEAD"), cancellable = true) + private static void isNamespaceCharacterValid (char character, CallbackInfoReturnable cir) { + cir.setReturnValue(true); + + cir.cancel(); + } + + @Inject(method = "isNamespaceValid", at = @At("HEAD"), cancellable = true) + private static void isNamespaceValid (String namespace, CallbackInfoReturnable cir) { + cir.setReturnValue(true); + + cir.cancel(); + } + + @Inject(method = "validateNamespace", at = @At("HEAD"), cancellable = true) + private static void validateNamespace(String namespace, String path, CallbackInfoReturnable cir) { + cir.setReturnValue(namespace); + + cir.cancel(); + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/CommandCore.java b/src/main/java/land/chipmunk/chipmunkmod/modules/CommandCore.java index b8a2b20..2c141c9 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/CommandCore.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/CommandCore.java @@ -20,7 +20,7 @@ public class CommandCore { private final MinecraftClient client; @Getter @Setter private boolean ready = false; @Getter @Setter private BlockPos origin; - @Getter private final BlockArea relativeArea; + @Getter private BlockArea relativeArea; @Getter @Setter private BlockPos currentBlockRelative; public static CommandCore INSTANCE = new CommandCore(MinecraftClient.getInstance(), ChipmunkMod.CONFIG.core.relativeArea); @@ -30,6 +30,10 @@ public class CommandCore { this.relativeArea = relativeArea; } + public void reloadRelativeArea () { + relativeArea = ChipmunkMod.CONFIG.core.relativeArea; + } + public void move (Vec3d position) { if (!ready) { ready = true; @@ -52,7 +56,9 @@ public class CommandCore { final BlockPos relEnd = relativeArea.end(); final String command = String.format( - "fill %s %s %s %s %s %s command_block", + KaboomCheck.INSTANCE.isKaboom() ? + "fill %s %s %s %s %s %s repeating_command_block replace" : + "fill %s %s %s %s %s %s command_block", relStart.getX() + origin.getX(), relStart.getY() + origin.getY(), relStart.getZ() + origin.getZ(), diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/KaboomCheck.java b/src/main/java/land/chipmunk/chipmunkmod/modules/KaboomCheck.java new file mode 100644 index 0000000..1eebfc4 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/KaboomCheck.java @@ -0,0 +1,98 @@ +package land.chipmunk.chipmunkmod.modules; + +import land.chipmunk.chipmunkmod.listeners.Listener; +import land.chipmunk.chipmunkmod.listeners.ListenerManager; +import lombok.Getter; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.SubtitleS2CPacket; +import net.minecraft.network.packet.s2c.play.TitleS2CPacket; + +import java.util.Timer; +import java.util.TimerTask; + +public class KaboomCheck extends Listener { + public static final String TITLE_START_TEXT = "Welcome to "; + public static final String TITLE_END_TEXT = "!"; + + public static final String SUBTITLE_START_TEXT = "Free OP"; + + @Getter private boolean isKaboom = false; + + private boolean hasKaboomTitle = false; + private boolean hasKaboomSubtitle = false; + + private Timer timer = null; + + private final MinecraftClient client; + + public static final KaboomCheck INSTANCE = new KaboomCheck(MinecraftClient.getInstance()); + + public KaboomCheck (MinecraftClient client) { + this.client = client; + + ListenerManager.addListener(this); + } + + public void init () {} + + public void onJoin () { + final TimerTask task = new TimerTask() { + public void run () { + tick(); + } + }; + + if (timer != null) cleanup(); + + timer = new Timer(); + + timer.schedule(task, 50, 50); + } + + private void tick () { + final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler(); + + if (networkHandler == null) cleanup(); + + if (hasKaboomTitle && hasKaboomSubtitle) isKaboom = true; + } + + private void cleanup () { + if (timer == null) return; + + isKaboom = false; + hasKaboomTitle = false; + hasKaboomSubtitle = false; + + timer.purge(); + timer.cancel(); + } + + @Override + public void packetReceived(Packet packet) { + if (packet instanceof TitleS2CPacket) packetReceived((TitleS2CPacket) packet); + else if (packet instanceof SubtitleS2CPacket) packetReceived((SubtitleS2CPacket) packet); + } + + // TODO: move this to a util class + private String stripSectionSigns (String text) { + return text.replaceAll("ยง.", ""); + } + + public void packetReceived(TitleS2CPacket packet) { + final String stripped = stripSectionSigns(packet.getTitle().getString()); + + if ( + stripped.startsWith(TITLE_START_TEXT) && + stripped.endsWith(TITLE_END_TEXT) + ) hasKaboomTitle = true; + } + + public void packetReceived(SubtitleS2CPacket packet) { + final String stripped = stripSectionSigns(packet.getSubtitle().getString()); + + if (stripped.startsWith(SUBTITLE_START_TEXT)) hasKaboomSubtitle = true; + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/Players.java b/src/main/java/land/chipmunk/chipmunkmod/modules/Players.java index 8ef94b1..e79f3f2 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/Players.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/Players.java @@ -3,27 +3,31 @@ package land.chipmunk.chipmunkmod.modules; import com.mojang.brigadier.Message; import com.mojang.brigadier.suggestion.Suggestion; import com.mojang.brigadier.suggestion.Suggestions; +import land.chipmunk.chipmunkmod.ChipmunkMod; import land.chipmunk.chipmunkmod.data.MutablePlayerListEntry; import land.chipmunk.chipmunkmod.listeners.Listener; import land.chipmunk.chipmunkmod.listeners.ListenerManager; +import land.chipmunk.chipmunkmod.mixin.ClientPlayNetworkHandlerAccessor; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.client.network.PlayerListEntry; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.s2c.play.CommandSuggestionsS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; import net.minecraft.text.Text; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import java.util.concurrent.CompletableFuture; +import static land.chipmunk.chipmunkmod.util.ServerUtilities.serverHasCommand; + public class Players extends Listener { public List list = new ArrayList<>(); public static Players INSTANCE = new Players(MinecraftClient.getInstance()); - private Timer timer; - private final MinecraftClient client; public Players (MinecraftClient client) { @@ -33,37 +37,10 @@ public class Players extends Listener { TabComplete.INSTANCE.init(); } - public void init () { - final TimerTask task = new TimerTask() { - public void run () { - tick(); - } - }; - - if (timer != null) cleanup(); - - timer = new Timer(); - timer.schedule(task, 0, 50); - } - - public void cleanup () { - list.clear(); - - if (timer == null) return; - - timer.cancel(); - timer.purge(); - timer = null; - } - - private void tick () { - final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler(); - - if (networkHandler == null) cleanup(); - } + public void init () {} @Override - public void packetReceived (Packet packet) { + public void packetReceived (Packet packet) { if (packet instanceof PlayerListS2CPacket) packetReceived((PlayerListS2CPacket) packet); else if (packet instanceof PlayerRemoveS2CPacket) packetReceived((PlayerRemoveS2CPacket) packet); } @@ -136,7 +113,10 @@ public class Players extends Listener { private void addPlayer (PlayerListS2CPacket.Entry newEntry) { try { final MutablePlayerListEntry duplicate = getEntry(newEntry); - if (duplicate != null) list.remove(duplicate); + if (duplicate != null) { + removeFromPlayerList(duplicate.profile().getId()); + list.remove(duplicate); + } list.add(new MutablePlayerListEntry(newEntry)); } catch (Exception e) { @@ -174,6 +154,12 @@ public class Players extends Listener { final MutablePlayerListEntry target = getEntry(uuid); if (target == null) return; + if (!serverHasCommand("scoreboard")) { + ChipmunkMod.LOGGER.warn("Server doesn't have /scoreboard, so not showing vanished players."); + removeFromPlayerList(uuid); + return; + } + final CompletableFuture future = TabComplete.INSTANCE.complete("/scoreboard players add "); if (future == null) return; @@ -187,14 +173,33 @@ public class Players extends Listener { final Message tooltip = suggestion.getTooltip(); if (tooltip != null || !suggestion.getText().equals(username)) continue; + return packet; } list.remove(target); + + // TODO: fix players using /username gone from the player list, the cause is exactly at the next line and it's because uuid i guess + removeFromPlayerList(uuid); + return packet; }); } catch (Exception e) { e.printStackTrace(); } } + + private void removeFromPlayerList (UUID uuid) { + client.getSocialInteractionsManager().setPlayerOffline(uuid); + + final ClientPlayNetworkHandlerAccessor accessor = ((ClientPlayNetworkHandlerAccessor) MinecraftClient.getInstance().getNetworkHandler()); + + if (accessor == null) return; + + final PlayerListEntry playerListEntry = accessor.playerListEntries().remove(uuid); + + if (playerListEntry != null) { + accessor.listedPlayerListEntries().remove(playerListEntry); + } + } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/RainbowName.java b/src/main/java/land/chipmunk/chipmunkmod/modules/RainbowName.java index 078f5e0..2203947 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/RainbowName.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/RainbowName.java @@ -40,7 +40,7 @@ public class RainbowName { if (timer != null) cleanup(); timer = new Timer(); - timer.schedule(task, 0, 75); + timer.schedule(task, 0, 50); } private String[] generateColorCodes(int length) { diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/SelfCare.java b/src/main/java/land/chipmunk/chipmunkmod/modules/SelfCare.java index db5e3cc..e9da51b 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/SelfCare.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/SelfCare.java @@ -7,14 +7,14 @@ import lombok.Setter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerEntity; -import com.mojang.brigadier.tree.CommandNode; -import com.mojang.brigadier.tree.LiteralCommandNode; import lombok.Getter; import net.minecraft.text.Text; import java.util.Timer; import java.util.TimerTask; +import static land.chipmunk.chipmunkmod.util.ServerUtilities.serverHasCommand; + public class SelfCare extends Listener { private final MinecraftClient client; @Getter private final long interval; @@ -114,19 +114,4 @@ public class SelfCare extends Listener { if (!cspy && cspyEnabled) { if (serverHasCommand("c")) networkHandler.sendChatCommand("c on"); } else if (!hasSkin && !skin.equals("off")) { if (serverHasCommand("skin")) networkHandler.sendChatCommand("skin " + skin); } } - - // TODO: Move this into a separate class related to server info gathering (and yes, I plan on making this d y n a m i c and require little to no configuration for most servers) - private boolean serverHasCommand (String name) { - final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler(); - - if (networkHandler == null) return false; - - for (CommandNode node : networkHandler.getCommandDispatcher().getRoot().getChildren()) { - if (!(node instanceof LiteralCommandNode literal)) continue; - - if (literal.getLiteral().equals(name)) return true; - } - - return false; - } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/SongPlayer.java b/src/main/java/land/chipmunk/chipmunkmod/modules/SongPlayer.java index 2f537d9..1bcb73b 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/SongPlayer.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/SongPlayer.java @@ -1,9 +1,13 @@ package land.chipmunk.chipmunkmod.modules; +import land.chipmunk.chipmunkmod.mixin.ClientConnectionAccessor; +import land.chipmunk.chipmunkmod.mixin.ClientConnectionInvoker; +import land.chipmunk.chipmunkmod.mixin.ClientPlayNetworkHandlerAccessor; import land.chipmunk.chipmunkmod.song.Note; import land.chipmunk.chipmunkmod.song.Song; import land.chipmunk.chipmunkmod.song.SongLoaderException; import land.chipmunk.chipmunkmod.song.SongLoaderThread; +import land.chipmunk.chipmunkmod.util.MathUtilities; import lombok.Getter; import lombok.Setter; import net.kyori.adventure.text.Component; @@ -12,14 +16,17 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket; +import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import net.minecraft.util.math.random.Random; import java.io.File; import java.net.URL; import java.nio.file.Path; -import java.util.Arrays; import java.util.LinkedList; import java.util.Timer; import java.util.TimerTask; @@ -42,6 +49,9 @@ public class SongPlayer { private int ticksUntilPausedActionbar = 20; @Getter @Setter private boolean useCore = true; + @Getter @Setter private boolean actionbar = true; + + @Getter @Setter private float pitch = 0; private final MinecraftClient client; @@ -120,8 +130,8 @@ public class SongPlayer { else ticksUntilPausedActionbar = 20; try { - if (!useCore) client.player.sendActionBar(generateActionbar()); - else CommandCore.INSTANCE.run("title " + SELECTOR + " actionbar " + GsonComponentSerializer.gson().serialize(generateActionbar())); + if (!useCore && actionbar) client.player.sendActionBar(generateActionbar()); + else if (actionbar) CommandCore.INSTANCE.run("title " + SELECTOR + " actionbar " + GsonComponentSerializer.gson().serialize(generateActionbar())); } catch (Exception e) { e.printStackTrace(); } @@ -137,7 +147,7 @@ public class SongPlayer { } }; - playTimer.schedule(playTask, 50, 50); + playTimer.schedule(playTask, 60, 50); if (currentSong != null) currentSong.play(); } @@ -150,7 +160,7 @@ public class SongPlayer { .append(Component.translatable(" | ", NamedTextColor.DARK_GRAY)) .append(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN)) .append(Component.translatable(" | ", NamedTextColor.DARK_GRAY)) - .append(Component.translatable("%s / %s", formatTime(currentSong.time).color(NamedTextColor.GREEN), formatTime(currentSong.length).color(NamedTextColor.GREEN)).color(NamedTextColor.GRAY)) + .append(Component.translatable("%s / %s", formatTime(currentSong.time).asComponent().color(NamedTextColor.GREEN), formatTime(currentSong.length).asComponent().color(NamedTextColor.GREEN)).color(NamedTextColor.GRAY)) .append(Component.translatable(" | ", NamedTextColor.DARK_GRAY)) .append(Component.translatable("%s / %s", Component.text(currentSong.position, NamedTextColor.GREEN), Component.text(currentSong.size(), NamedTextColor.GREEN)).color(NamedTextColor.GRAY)); @@ -175,16 +185,16 @@ public class SongPlayer { return component; } - public Component formatTime (long millis) { + public Text formatTime (long millis) { final int seconds = (int) millis / 1000; final String minutePart = String.valueOf(seconds / 60); final String unpaddedSecondPart = String.valueOf(seconds % 60); - return Component.translatable( + return Text.translatable( "%s:%s", - Component.text(minutePart), - Component.text(unpaddedSecondPart.length() < 2 ? "0" + unpaddedSecondPart : unpaddedSecondPart) + Text.literal(minutePart), + Text.literal(unpaddedSecondPart.length() < 2 ? "0" + unpaddedSecondPart : unpaddedSecondPart) ); } @@ -204,18 +214,34 @@ public class SongPlayer { while (currentSong.reachedNextNote()) { final Note note = currentSong.getNextNote(); - final float floatingPitch = (float) Math.pow(2, (note.pitch - 12) / 12.0); + final float floatingPitch = MathUtilities.clamp((float) (0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12)))), 0F, 2F); try { - if (!useCore) { - if (floatingPitch < 0 || floatingPitch > 2) return; - + if (!useCore && client.player != null) { final String[] thing = note.instrument.sound.split(":"); if (thing[1] == null) return; // idk if this can be null but ill just protect it for now i guess - client.player.playSound(SoundEvent.of(Identifier.of(thing[0], thing[1])), SoundCategory.RECORDS, note.volume, floatingPitch); - } else CommandCore.INSTANCE.run("execute as " + SELECTOR + " at @s run playsound " + note.instrument.sound + " record @s ~ ~ ~ " + note.volume + " " + floatingPitch); + final ClientPlayNetworkHandlerAccessor networkHandlerAccessor = (ClientPlayNetworkHandlerAccessor) client.getNetworkHandler(); + + final ClientConnectionAccessor clientConnectionAccessor = (ClientConnectionAccessor) networkHandlerAccessor.connection(); + + ClientConnectionInvoker.handlePacket( + new PlaySoundS2CPacket( + RegistryEntry.of(SoundEvent.of(Identifier.of(thing[0], thing[1]))), + SoundCategory.RECORDS, + client.player.getX(), + client.player.getY(), + client.player.getZ(), + note.volume, + floatingPitch, + Random.create().nextLong() + ), + clientConnectionAccessor.packetListener() + ); + } else { + CommandCore.INSTANCE.run("execute as " + SELECTOR + " at @s run playsound " + note.instrument.sound + " record @s ~ ~ ~ " + note.volume + " " + floatingPitch); + } } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/TabComplete.java b/src/main/java/land/chipmunk/chipmunkmod/modules/TabComplete.java index f3f28a1..de799d6 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/TabComplete.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/TabComplete.java @@ -2,7 +2,6 @@ package land.chipmunk.chipmunkmod.modules; import land.chipmunk.chipmunkmod.listeners.Listener; import land.chipmunk.chipmunkmod.listeners.ListenerManager; -import lombok.Getter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.ClientConnection; @@ -22,8 +21,6 @@ public class TabComplete extends Listener { public static TabComplete INSTANCE = new TabComplete(MinecraftClient.getInstance()); - @Getter private boolean loggedIn = false; - public TabComplete (MinecraftClient client) { this.client = client; ListenerManager.addListener(this); @@ -41,7 +38,6 @@ public class TabComplete extends Listener { if (connection == null) return null; final int transactionId = nextTransactionId++; - if (nextTransactionId > Integer.MAX_VALUE) nextTransactionId = 0; // ? Can and should I use negative numbers too? connection.send(new RequestCommandCompletionsC2SPacket(transactionId, command)); final CompletableFuture future = new CompletableFuture<>(); @@ -50,7 +46,7 @@ public class TabComplete extends Listener { } @Override - public void packetReceived (Packet packet) { + public void packetReceived (Packet packet) { if (packet instanceof CommandSuggestionsS2CPacket) packetReceived((CommandSuggestionsS2CPacket) packet); } diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/Instrument.java b/src/main/java/land/chipmunk/chipmunkmod/song/Instrument.java index 91462cb..8d8850e 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/Instrument.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/Instrument.java @@ -27,7 +27,7 @@ public class Instrument { this.id = id; this.name = name; this.offset = offset; - this.sound = name; + this.sound = sound; } private Instrument (int id, String name, int offset) { diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/MidiConverter.java b/src/main/java/land/chipmunk/chipmunkmod/song/MidiConverter.java index abe34dc..053a31f 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/MidiConverter.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/MidiConverter.java @@ -19,7 +19,7 @@ public class MidiConverter { public static final int NOTE_OFF = 0x80; public static Song getSongFromUrl(URL url) throws IOException, InvalidMidiDataException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException { - Sequence sequence = MidiSystem.getSequence(DownloadUtilities.DownloadToInputStream(url, 5*1024*1024)); + Sequence sequence = MidiSystem.getSequence(DownloadUtilities.DownloadToInputStream(url)); return getSong(sequence, Paths.get(url.toURI().getPath()).getFileName().toString()); } diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/NBSConverter.java b/src/main/java/land/chipmunk/chipmunkmod/song/NBSConverter.java index c1bf1f6..a45d174 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/NBSConverter.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/NBSConverter.java @@ -164,7 +164,7 @@ public class NBSConverter { if (index >= customInstruments.size()) continue; NBSCustomInstrument customInstrument = customInstruments.get(index); instrument = Instrument.of(customInstrument.name); - // key += customInstrument.pitch; + key += customInstrument.pitch; } if (key < 33 || key > 57) { diff --git a/src/main/java/land/chipmunk/chipmunkmod/song/SongLoaderThread.java b/src/main/java/land/chipmunk/chipmunkmod/song/SongLoaderThread.java index dc4c891..b02323f 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/song/SongLoaderThread.java +++ b/src/main/java/land/chipmunk/chipmunkmod/song/SongLoaderThread.java @@ -17,7 +17,7 @@ public class SongLoaderThread extends Thread { public SongLoaderException exception; public Song song; - private boolean isUrl = false; + private boolean isUrl; public SongLoaderThread (URL location) throws SongLoaderException { isUrl = true; @@ -34,7 +34,7 @@ public class SongLoaderThread extends Thread { String name; try { if (isUrl) { - bytes = DownloadUtilities.DownloadToByteArray(songUrl, 10*1024*1024); + bytes = DownloadUtilities.DownloadToByteArray(songUrl); name = Paths.get(songUrl.toURI().getPath()).getFileName().toString(); } else { bytes = Files.readAllBytes(songPath.toPath()); diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/DownloadUtilities.java b/src/main/java/land/chipmunk/chipmunkmod/util/DownloadUtilities.java index 1ae54fc..e1f5ffa 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/util/DownloadUtilities.java +++ b/src/main/java/land/chipmunk/chipmunkmod/util/DownloadUtilities.java @@ -28,7 +28,7 @@ public class DownloadUtilities { } } - public static byte[] DownloadToByteArray(URL url, int maxSize) throws IOException, KeyManagementException, NoSuchAlgorithmException { + public static byte[] DownloadToByteArray(URL url) throws IOException, KeyManagementException, NoSuchAlgorithmException { SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom()); SSLContext.setDefault(ctx); @@ -41,13 +41,9 @@ public class DownloadUtilities { ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int n; - int tot = 0; while ((n = downloadStream.read(buf)) > 0) { byteArrayStream.write(buf, 0, n); - tot += n; - if (tot > maxSize) { - throw new IOException("File is too large"); - } + if (Thread.interrupted()) { return null; } @@ -57,7 +53,7 @@ public class DownloadUtilities { // Closing a ByteArrayInputStream has no effect, so I do not close it. } - public static InputStream DownloadToInputStream(URL url, int maxSize) throws KeyManagementException, NoSuchAlgorithmException, IOException { - return new ByteArrayInputStream(DownloadToByteArray(url, maxSize)); + public static InputStream DownloadToInputStream(URL url) throws KeyManagementException, NoSuchAlgorithmException, IOException { + return new ByteArrayInputStream(DownloadToByteArray(url)); } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/MathUtilities.java b/src/main/java/land/chipmunk/chipmunkmod/util/MathUtilities.java new file mode 100644 index 0000000..37cd5c2 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/util/MathUtilities.java @@ -0,0 +1,7 @@ +package land.chipmunk.chipmunkmod.util; + +public class MathUtilities { + public static float clamp (float value, float min, float max) { + return Math.max(Math.min(value, max), min); + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/ServerUtilities.java b/src/main/java/land/chipmunk/chipmunkmod/util/ServerUtilities.java new file mode 100644 index 0000000..9f18c35 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/util/ServerUtilities.java @@ -0,0 +1,23 @@ +package land.chipmunk.chipmunkmod.util; + +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.LiteralCommandNode; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayNetworkHandler; + +public class ServerUtilities { + public static boolean serverHasCommand (String name) { + final MinecraftClient client = MinecraftClient.getInstance(); + final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler(); + + if (networkHandler == null) return false; + + for (CommandNode node : networkHandler.getCommandDispatcher().getRoot().getChildren()) { + if (!(node instanceof LiteralCommandNode literal)) continue; + + if (literal.getLiteral().equals(name)) return true; + } + + return false; + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/Webhook.java b/src/main/java/land/chipmunk/chipmunkmod/util/Webhook.java index 6d44360..def1efa 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/util/Webhook.java +++ b/src/main/java/land/chipmunk/chipmunkmod/util/Webhook.java @@ -9,380 +9,383 @@ import java.net.URL; import java.util.List; import java.util.*; +// i am sure blackilykat did not write this - chayapak +// you are correct - blackilykat + /** * Class used to execute Discord Webhooks with low effort */ public class Webhook { - - private final String url; - private String content; - private String username; - private String avatarUrl; - private boolean tts; - private List embeds = new ArrayList<>(); - - /** - * Constructs a new DiscordWebhook instance - * - * @param url The webhook URL obtained in Discord - */ - public Webhook(String url) { - this.url = url; - } - - public void setContent(String content) { - this.content = content; - } - - public void setUsername(String username) { - this.username = username; - } - - public void setAvatarUrl(String avatarUrl) { - this.avatarUrl = avatarUrl; - } - - public void setTts(boolean tts) { - this.tts = tts; - } - - public void addEmbed(EmbedObject embed) { - this.embeds.add(embed); - } - - public void execute() throws IOException { - if (this.content == null && this.embeds.isEmpty()) { - throw new IllegalArgumentException("Set content or add at least one EmbedObject"); - } - - JSONObject json = new JSONObject(); - - json.put("content", this.content); - json.put("username", this.username); - json.put("avatar_url", this.avatarUrl); - json.put("tts", this.tts); - - if (!this.embeds.isEmpty()) { - List embedObjects = new ArrayList<>(); - - for (EmbedObject embed : this.embeds) { - JSONObject jsonEmbed = new JSONObject(); - - jsonEmbed.put("title", embed.getTitle()); - jsonEmbed.put("description", embed.getDescription()); - jsonEmbed.put("url", embed.getUrl()); - - if (embed.getColor() != null) { - Color color = embed.getColor(); - int rgb = color.getRed(); - rgb = (rgb << 8) + color.getGreen(); - rgb = (rgb << 8) + color.getBlue(); - - jsonEmbed.put("color", rgb); - } - - EmbedObject.Footer footer = embed.getFooter(); - EmbedObject.Image image = embed.getImage(); - EmbedObject.Thumbnail thumbnail = embed.getThumbnail(); - EmbedObject.Author author = embed.getAuthor(); - List fields = embed.getFields(); - - if (footer != null) { - JSONObject jsonFooter = new JSONObject(); - - jsonFooter.put("text", footer.getText()); - jsonFooter.put("icon_url", footer.getIconUrl()); - jsonEmbed.put("footer", jsonFooter); - } - - if (image != null) { - JSONObject jsonImage = new JSONObject(); - - jsonImage.put("url", image.getUrl()); - jsonEmbed.put("image", jsonImage); - } - - if (thumbnail != null) { - JSONObject jsonThumbnail = new JSONObject(); - - jsonThumbnail.put("url", thumbnail.getUrl()); - jsonEmbed.put("thumbnail", jsonThumbnail); - } - - if (author != null) { - JSONObject jsonAuthor = new JSONObject(); - - jsonAuthor.put("name", author.getName()); - jsonAuthor.put("url", author.getUrl()); - jsonAuthor.put("icon_url", author.getIconUrl()); - jsonEmbed.put("author", jsonAuthor); - } - - List jsonFields = new ArrayList<>(); - for (EmbedObject.Field field : fields) { - JSONObject jsonField = new JSONObject(); - - jsonField.put("name", field.getName()); - jsonField.put("value", field.getValue()); - jsonField.put("inline", field.isInline()); - - jsonFields.add(jsonField); - } - - jsonEmbed.put("fields", jsonFields.toArray()); - embedObjects.add(jsonEmbed); - } - - json.put("embeds", embedObjects.toArray()); - } - - URL url = new URL(this.url); - HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); - connection.addRequestProperty("Content-Type", "application/json"); - connection.addRequestProperty("User-Agent", "Java-DiscordWebhook-BY-Gelox_"); - connection.setDoOutput(true); - connection.setRequestMethod("POST"); - - OutputStream stream = connection.getOutputStream(); - stream.write(json.toString().getBytes()); - stream.flush(); - stream.close(); - - connection.getInputStream().close(); //I'm not sure why but it doesn't work without getting the InputStream - connection.disconnect(); - } - - public static class EmbedObject { - private String title; - private String description; - private String url; - private Color color; - - private Footer footer; - private Thumbnail thumbnail; - private Image image; - private Author author; - private List fields = new ArrayList<>(); - - public String getTitle() { - return title; - } - - public String getDescription() { - return description; - } - - public String getUrl() { - return url; - } - - public Color getColor() { - return color; - } - - public Footer getFooter() { - return footer; - } - - public Thumbnail getThumbnail() { - return thumbnail; - } - - public Image getImage() { - return image; - } - - public Author getAuthor() { - return author; - } - - public List getFields() { - return fields; - } - - public EmbedObject setTitle(String title) { - this.title = title; - return this; - } - - public EmbedObject setDescription(String description) { - this.description = description; - return this; - } - - public EmbedObject setUrl(String url) { - this.url = url; - return this; - } - - public EmbedObject setColor(Color color) { - this.color = color; - return this; - } - - public EmbedObject setFooter(String text, String icon) { - this.footer = new Footer(text, icon); - return this; - } - - public EmbedObject setThumbnail(String url) { - this.thumbnail = new Thumbnail(url); - return this; - } - - public EmbedObject setImage(String url) { - this.image = new Image(url); - return this; - } - - public EmbedObject setAuthor(String name, String url, String icon) { - this.author = new Author(name, url, icon); - return this; - } - - public EmbedObject addField(String name, String value, boolean inline) { - this.fields.add(new Field(name, value, inline)); - return this; - } - - private class Footer { - private String text; - private String iconUrl; - - private Footer(String text, String iconUrl) { - this.text = text; - this.iconUrl = iconUrl; - } - - private String getText() { - return text; - } - - private String getIconUrl() { - return iconUrl; - } - } - - private class Thumbnail { - private String url; - - private Thumbnail(String url) { - this.url = url; - } - - private String getUrl() { - return url; - } - } - - private class Image { - private String url; - - private Image(String url) { - this.url = url; - } - - private String getUrl() { - return url; - } - } - - private class Author { - private String name; - private String url; - private String iconUrl; - - private Author(String name, String url, String iconUrl) { - this.name = name; - this.url = url; - this.iconUrl = iconUrl; - } - - private String getName() { - return name; - } - - private String getUrl() { - return url; - } - - private String getIconUrl() { - return iconUrl; - } - } - - private class Field { - private String name; - private String value; - private boolean inline; - - private Field(String name, String value, boolean inline) { - this.name = name; - this.value = value; - this.inline = inline; - } - - private String getName() { - return name; - } - - private String getValue() { - return value; - } - - private boolean isInline() { - return inline; - } - } - } - - private class JSONObject { - - private final HashMap map = new HashMap<>(); - - void put(String key, Object value) { - if (value != null) { - map.put(key, value); - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - Set> entrySet = map.entrySet(); - builder.append("{"); - - int i = 0; - for (Map.Entry entry : entrySet) { - Object val = entry.getValue(); - builder.append(quote(entry.getKey())).append(":"); - - if (val instanceof String) { - builder.append(quote(String.valueOf(val))); - } else if (val instanceof Integer) { - builder.append(Integer.valueOf(String.valueOf(val))); - } else if (val instanceof Boolean) { - builder.append(val); - } else if (val instanceof JSONObject) { - builder.append(val.toString()); - } else if (val.getClass().isArray()) { - builder.append("["); - int len = Array.getLength(val); - for (int j = 0; j < len; j++) { - builder.append(Array.get(val, j).toString()).append(j != len - 1 ? "," : ""); - } - builder.append("]"); - } - - builder.append(++i == entrySet.size() ? "}" : ","); - } - - return builder.toString(); - } - - private String quote(String string) { - return "\"" + string + "\""; - } - } - -} \ No newline at end of file + + private final String url; + private String content; + private String username; + private String avatarUrl; + private boolean tts; + private List embeds = new ArrayList<>(); + + /** + * Constructs a new DiscordWebhook instance + * + * @param url The webhook URL obtained in Discord + */ + public Webhook(String url) { + this.url = url; + } + + public void setContent(String content) { + this.content = content; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public void setTts(boolean tts) { + this.tts = tts; + } + + public void addEmbed(EmbedObject embed) { + this.embeds.add(embed); + } + + public void execute() throws IOException { + if (this.content == null && this.embeds.isEmpty()) { + throw new IllegalArgumentException("Set content or add at least one EmbedObject"); + } + + JSONObject json = new JSONObject(); + + json.put("content", this.content); + json.put("username", this.username); + json.put("avatar_url", this.avatarUrl); + json.put("tts", this.tts); + + if (!this.embeds.isEmpty()) { + List embedObjects = new ArrayList<>(); + + for (EmbedObject embed : this.embeds) { + JSONObject jsonEmbed = new JSONObject(); + + jsonEmbed.put("title", embed.getTitle()); + jsonEmbed.put("description", embed.getDescription()); + jsonEmbed.put("url", embed.getUrl()); + + if (embed.getColor() != null) { + Color color = embed.getColor(); + int rgb = color.getRed(); + rgb = (rgb << 8) + color.getGreen(); + rgb = (rgb << 8) + color.getBlue(); + + jsonEmbed.put("color", rgb); + } + + EmbedObject.Footer footer = embed.getFooter(); + EmbedObject.Image image = embed.getImage(); + EmbedObject.Thumbnail thumbnail = embed.getThumbnail(); + EmbedObject.Author author = embed.getAuthor(); + List fields = embed.getFields(); + + if (footer != null) { + JSONObject jsonFooter = new JSONObject(); + + jsonFooter.put("text", footer.getText()); + jsonFooter.put("icon_url", footer.getIconUrl()); + jsonEmbed.put("footer", jsonFooter); + } + + if (image != null) { + JSONObject jsonImage = new JSONObject(); + + jsonImage.put("url", image.getUrl()); + jsonEmbed.put("image", jsonImage); + } + + if (thumbnail != null) { + JSONObject jsonThumbnail = new JSONObject(); + + jsonThumbnail.put("url", thumbnail.getUrl()); + jsonEmbed.put("thumbnail", jsonThumbnail); + } + + if (author != null) { + JSONObject jsonAuthor = new JSONObject(); + + jsonAuthor.put("name", author.getName()); + jsonAuthor.put("url", author.getUrl()); + jsonAuthor.put("icon_url", author.getIconUrl()); + jsonEmbed.put("author", jsonAuthor); + } + + List jsonFields = new ArrayList<>(); + for (EmbedObject.Field field : fields) { + JSONObject jsonField = new JSONObject(); + + jsonField.put("name", field.getName()); + jsonField.put("value", field.getValue()); + jsonField.put("inline", field.isInline()); + + jsonFields.add(jsonField); + } + + jsonEmbed.put("fields", jsonFields.toArray()); + embedObjects.add(jsonEmbed); + } + + json.put("embeds", embedObjects.toArray()); + } + + URL url = new URL(this.url); + HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); + connection.addRequestProperty("Content-Type", "application/json"); + connection.addRequestProperty("User-Agent", "Java-DiscordWebhook-BY-Gelox_"); + connection.setDoOutput(true); + connection.setRequestMethod("POST"); + + OutputStream stream = connection.getOutputStream(); + stream.write(json.toString().getBytes()); + stream.flush(); + stream.close(); + + connection.getInputStream().close(); //I'm not sure why but it doesn't work without getting the InputStream + connection.disconnect(); + } + + public static class EmbedObject { + private String title; + private String description; + private String url; + private Color color; + + private Footer footer; + private Thumbnail thumbnail; + private Image image; + private Author author; + private List fields = new ArrayList<>(); + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public String getUrl() { + return url; + } + + public Color getColor() { + return color; + } + + public Footer getFooter() { + return footer; + } + + public Thumbnail getThumbnail() { + return thumbnail; + } + + public Image getImage() { + return image; + } + + public Author getAuthor() { + return author; + } + + public List getFields() { + return fields; + } + + public EmbedObject setTitle(String title) { + this.title = title; + return this; + } + + public EmbedObject setDescription(String description) { + this.description = description; + return this; + } + + public EmbedObject setUrl(String url) { + this.url = url; + return this; + } + + public EmbedObject setColor(Color color) { + this.color = color; + return this; + } + + public EmbedObject setFooter(String text, String icon) { + this.footer = new Footer(text, icon); + return this; + } + + public EmbedObject setThumbnail(String url) { + this.thumbnail = new Thumbnail(url); + return this; + } + + public EmbedObject setImage(String url) { + this.image = new Image(url); + return this; + } + + public EmbedObject setAuthor(String name, String url, String icon) { + this.author = new Author(name, url, icon); + return this; + } + + public EmbedObject addField(String name, String value, boolean inline) { + this.fields.add(new Field(name, value, inline)); + return this; + } + + private class Footer { + private String text; + private String iconUrl; + + private Footer(String text, String iconUrl) { + this.text = text; + this.iconUrl = iconUrl; + } + + private String getText() { + return text; + } + + private String getIconUrl() { + return iconUrl; + } + } + + private class Thumbnail { + private String url; + + private Thumbnail(String url) { + this.url = url; + } + + private String getUrl() { + return url; + } + } + + private class Image { + private String url; + + private Image(String url) { + this.url = url; + } + + private String getUrl() { + return url; + } + } + + private class Author { + private String name; + private String url; + private String iconUrl; + + private Author(String name, String url, String iconUrl) { + this.name = name; + this.url = url; + this.iconUrl = iconUrl; + } + + private String getName() { + return name; + } + + private String getUrl() { + return url; + } + + private String getIconUrl() { + return iconUrl; + } + } + + private class Field { + private String name; + private String value; + private boolean inline; + + private Field(String name, String value, boolean inline) { + this.name = name; + this.value = value; + this.inline = inline; + } + + private String getName() { + return name; + } + + private String getValue() { + return value; + } + + private boolean isInline() { + return inline; + } + } + } + + private class JSONObject { + + private final HashMap map = new HashMap<>(); + + void put(String key, Object value) { + if (value != null) { + map.put(key, value); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + Set> entrySet = map.entrySet(); + builder.append("{"); + + int i = 0; + for (Map.Entry entry : entrySet) { + Object val = entry.getValue(); + builder.append(quote(entry.getKey())).append(":"); + + if (val instanceof String) { + builder.append(quote(String.valueOf(val))); + } else if (val instanceof Integer) { + builder.append(Integer.valueOf(String.valueOf(val))); + } else if (val instanceof Boolean) { + builder.append(val); + } else if (val instanceof JSONObject) { + builder.append(val.toString()); + } else if (val.getClass().isArray()) { + builder.append("["); + int len = Array.getLength(val); + for (int j = 0; j < len; j++) { + builder.append(Array.get(val, j).toString()).append(j != len - 1 ? "," : ""); + } + builder.append("]"); + } + + builder.append(++i == entrySet.size() ? "}" : ","); + } + + return builder.toString(); + } + + private String quote(String string) { + return "\"" + string + "\""; + } + } + +} diff --git a/src/main/resources/chipmunkmod.mixins.json b/src/main/resources/chipmunkmod.mixins.json index 0f1471d..e0e07e2 100644 --- a/src/main/resources/chipmunkmod.mixins.json +++ b/src/main/resources/chipmunkmod.mixins.json @@ -11,6 +11,7 @@ "ClientPlayerEntityMixin", "ClientPlayNetworkHandlerAccessor", "ClientPlayNetworkHandlerMixin", + "ClientPlayNetworkHandlerInvoker", "DecoderHandlerMixin", "ElderGuardianAppearanceParticleMixin", "KeyboardInputMixin", @@ -21,7 +22,12 @@ "NbtIoMixin", "SessionMixin", "StringHelperMixin", - "TitleScreenMixin" + "TitleScreenMixin", + "IdentifierMixin", + "DecoratedPotBlockEntitySherdsMixin", + "TextMixin", + "ClientConnectionInvoker", + "ClientConnectionAccessor" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/assets/chipmunkmod/default_config.json b/src/main/resources/default_config.json similarity index 86% rename from src/main/resources/assets/chipmunkmod/default_config.json rename to src/main/resources/default_config.json index 40dd3d4..d834385 100644 --- a/src/main/resources/assets/chipmunkmod/default_config.json +++ b/src/main/resources/default_config.json @@ -15,7 +15,8 @@ "sbot": { "prefix": ":", "key": null }, "chipmunk": { "prefix": "'", "key": null }, "chomens": { "prefix": "*", "key": null }, - "kittycorp": { "prefix": "^", "key": null } + "kittycorp": { "prefix": "^", "key": null }, + "testbot": { "prefix": "-", "webhookUrl": null } }, "customChat": {