Skip to content

Commit

Permalink
added creply / cr (#648)
Browse files Browse the repository at this point in the history
* added creply / cr

* Made changes in response to review

Co-authored-by: Frederik van der Els <[email protected]>

* fine then earth

* changed it to not crash cross-dimensionally, and to allow for max length messages

* ok thats fine

* Update ReplyCommand.java

* Update ReplyCommand.java

* Update en_us.json

* Update ReplyCommand.java

* Update ReplyCommand.java

* Update ReplyCommand.java

* Update ReplyCommand.java

* Update ReplyCommand.java

* Add intellij project icon

* Remove incompatibility with seedcrackerx. Closes #653

* np

* made the code a bit prettier

* ok

* ok

* ok

* changed it to be a 0.5 second threshold

* fixed stuff from review

* added a break

---------

Co-authored-by: Frederik van der Els <[email protected]>
Co-authored-by: joe <[email protected]>
  • Loading branch information
3 people authored Nov 30, 2024
1 parent 9030ddf commit 22f4579
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ public static void registerCommands(CommandDispatcher<FabricClientCommandSource>
PosCommand.register(dispatcher);
RelogCommand.register(dispatcher);
RenderCommand.register(dispatcher);
ReplyCommand.register(dispatcher);
ShrugCommand.register(dispatcher);
SignSearchCommand.register(dispatcher);
SnakeCommand.register(dispatcher);
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/net/earthcomputer/clientcommands/Configs.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.earthcomputer.clientcommands;

import dev.xpple.betterconfig.api.Config;
import net.earthcomputer.clientcommands.command.ReplyCommand;
import net.earthcomputer.clientcommands.features.ChorusManipulation;
import net.earthcomputer.clientcommands.features.EnchantmentCracker;
import net.earthcomputer.clientcommands.features.FishingCracker;
Expand Down Expand Up @@ -176,4 +177,10 @@ public enum PacketDumpMethod {

@Config
public static int maximumPacketFieldDepth = 10;

@Config(temporary = true, setter = @Config.Setter("setMinimumReplyDelaySeconds"))
public static float minimumReplyDelaySeconds = 0.5f;
public static void setMinimumReplyDelaySeconds(float minimumReplyDelaySeconds) {
Configs.minimumReplyDelaySeconds = Math.clamp(minimumReplyDelaySeconds, 0.0f, ReplyCommand.MAXIMUM_REPLY_DELAY_SECONDS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package net.earthcomputer.clientcommands.command;

import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.earthcomputer.clientcommands.Configs;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.SharedConstants;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

import static dev.xpple.clientarguments.arguments.CMessageArgument.*;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*;

public class ReplyCommand {
public static final float MAXIMUM_REPLY_DELAY_SECONDS = 300.0f;

private static final SimpleCommandExceptionType NO_TARGET_FOUND_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.creply.noTargetFound"));
private static final Dynamic2CommandExceptionType MESSAGE_TOO_LONG_EXCEPTION = new Dynamic2CommandExceptionType((a, b) -> Component.translatable("commands.creply.messageTooLong", a, b));

private static final List<ReplyCandidate> replyCandidates = new ArrayList<>();

@Nullable
public static String getCurrentTarget() {
long now = System.currentTimeMillis();

for (int i = 0; i < replyCandidates.size(); i++) {
ReplyCandidate candidate = replyCandidates.get(i);
if (now - candidate.timestampMs > MAXIMUM_REPLY_DELAY_SECONDS * 1_000.0f) {
replyCandidates.remove(i--);
} else {
// list is ordered and `now - candidate.timestampMs` will only get smaller and smaller, so the cmp above will never change
break;
}
}

for (int i = replyCandidates.size() - 1; i >= 0; i--) {
ReplyCandidate candidate = replyCandidates.get(i);
if (now - candidate.timestampMs >= Configs.minimumReplyDelaySeconds * 1_000.0f) {
return candidate.username;
}
}

return null;
}

public static void addReplyCandidate(String username, long timestamp) {
replyCandidates.add(new ReplyCandidate(username, timestamp));
}

public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) {
var command = dispatcher.register(literal("creply")
.then(argument("message", message())
.executes(ctx -> reply(ctx.getSource(), getMessage(ctx, "message")))));
dispatcher.register(literal("cr").redirect(command));
}

public static int reply(FabricClientCommandSource source, Component message) throws CommandSyntaxException {
String target = ReplyCommand.getCurrentTarget();
if (target == null) {
throw NO_TARGET_FOUND_EXCEPTION.create();
}

String text = message.getString();
String command = String.format("w %s %s", target, text);

if (command.length() > SharedConstants.MAX_CHAT_LENGTH) {
throw MESSAGE_TOO_LONG_EXCEPTION.create(SharedConstants.MAX_CHAT_LENGTH - (command.length() - text.length()), text.length());
}

source.getClient().getConnection().sendCommand(command);

return Command.SINGLE_SUCCESS;
}

private record ReplyCandidate(String username, long timestampMs) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.earthcomputer.clientcommands.mixin.commands.reply;

import net.earthcomputer.clientcommands.command.ReplyCommand;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.multiplayer.PlayerInfo;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket;
import org.jetbrains.annotations.Nullable;
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 java.util.UUID;

@Mixin(ClientPacketListener.class)
public abstract class ClientPacketListenerMixin {
@Shadow public abstract @Nullable PlayerInfo getPlayerInfo(UUID uniqueId);

@Inject(method = "handlePlayerChat", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/PacketUtils;ensureRunningOnSameThread(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketListener;Lnet/minecraft/util/thread/BlockableEventLoop;)V", shift = At.Shift.AFTER))
private void onHandlePlayerChat(ClientboundPlayerChatPacket packet, CallbackInfo ci) {
if (packet.chatType().chatType().is(ChatType.MSG_COMMAND_INCOMING) || packet.chatType().chatType().is(ChatType.MSG_COMMAND_OUTGOING)) {
PlayerInfo info = getPlayerInfo(packet.sender());
if (info != null) {
ReplyCommand.addReplyCandidate(info.getProfile().getName(), System.currentTimeMillis());
}
}
}
}
3 changes: 3 additions & 0 deletions src/main/resources/assets/clientcommands/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@

"commands.crender.entities.success": "Entity rendering rules have been updated",

"commands.creply.noTargetFound": "Could not find a target to reply to",
"commands.creply.messageTooLong": "Your reply was too long (maximum: %d, given: %d)",

"commands.csignsearch.starting": "Searching signs",

"commands.csnap.airborne": "You cannot snap while airborne",
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/mixins.clientcommands.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"commands.alias.ClientSuggestionProviderMixin",
"commands.enchant.MultiPlayerGameModeMixin",
"commands.findblock.ClientLevelMixin",
"commands.reply.ClientPacketListenerMixin",
"commands.generic.CommandSuggestionsMixin",
"commands.glow.LivingEntityRenderStateMixin",
"commands.snap.MinecraftMixin",
Expand Down

0 comments on commit 22f4579

Please sign in to comment.