.username random/blank/empty #14

Merged
ChomeNS merged 1 commit from amy/chomensmod:1.21.4 into 1.21.4 2025-03-30 00:20:58 -04:00
4 changed files with 78 additions and 30 deletions

View file

@ -8,63 +8,94 @@ import static com.mojang.brigadier.arguments.StringArgumentType.*;
import static land.chipmunk.chipmunkmod.command.CommandManager.literal; import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
import static land.chipmunk.chipmunkmod.command.CommandManager.argument; import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
import land.chipmunk.chipmunkmod.mixin.ClientCommonNetworkHandlerAccessor;
import land.chipmunk.chipmunkmod.util.RandomUtilities;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.TitleScreen; import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen; import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ServerInfo; import net.minecraft.client.network.ServerInfo;
import net.minecraft.client.network.ServerAddress; import net.minecraft.client.network.ServerAddress;
import net.minecraft.client.session.Session; import net.minecraft.client.session.Session;
import net.minecraft.network.ClientConnection;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.Random;
import land.chipmunk.chipmunkmod.mixin.MinecraftClientAccessor; import land.chipmunk.chipmunkmod.mixin.MinecraftClientAccessor;
import net.minecraft.util.Uuids;
public class UsernameCommand { public class UsernameCommand {
private static final Session ORIGINAL_SESSION = MinecraftClient.getInstance().getSession();
private static final SimpleCommandExceptionType USERNAME_TOO_LONG = new SimpleCommandExceptionType(Text.translatable("The specified username is longer than 16 characters")); private static final SimpleCommandExceptionType USERNAME_TOO_LONG = new SimpleCommandExceptionType(Text.translatable("The specified username is longer than 16 characters"));
private static final char[] PREMIUM_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"
.toCharArray();
private static final char SECTION_CHAR = '§';
private static final Session ORIGINAL_SESSION = MinecraftClient.getInstance().getSession();
private static final Random RANDOM = new Random();
public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) { public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register( dispatcher.register(literal("username")
literal("username") .then(literal("set")
.then( .then(argument("username", string())
literal("set") .executes(c -> changeOffline(c, getString(c, "username")))))
.then( .then(literal("revert")
argument("username", string()) .executes(c -> changeSession(c, ORIGINAL_SESSION)))
.executes(UsernameCommand::updateUsername)
) .then(literal("random")
) .then(literal("blank")
.then( .executes(c -> changeOffline(c, RandomUtilities.emptyUsername(RANDOM, SECTION_CHAR))))
literal("revert") .executes(c -> changeOffline(c, RandomUtilities.randomString(RANDOM, PREMIUM_CHARS, RANDOM.nextInt(3, 16)))))
.executes(c -> updateSession(c, ORIGINAL_SESSION)) .then(literal("empty")
) .executes(c -> changeOffline(c, "")))
); );
} }
public static int updateUsername(CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException { private static Session offline(final String username) {
final String username = getString(context, "username"); // This is how Minecraft's Main class does it
if (username.length() > 16) throw USERNAME_TOO_LONG.create(); return new Session(username, Uuids.getOfflinePlayerUuid(username),
final Session session = new Session(username, new UUID(0L, 0L), "", Optional.empty(), Optional.empty(), Session.AccountType.MOJANG); "", Optional.empty(), Optional.empty(), Session.AccountType.LEGACY);
return updateSession(context, session);
} }
public static int updateSession(CommandContext<FabricClientCommandSource> context, Session session) { // TODO: Put this in a separate class
final FabricClientCommandSource source = context.getSource(); private static void reconnect(final MinecraftClient client) {
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
if (networkHandler == null) return; // single-player?
final MinecraftClient client = source.getClient(); final ServerInfo info = networkHandler.getServerInfo();
if (info == null) return; // definitely single-player
final ClientConnection connection = networkHandler.getConnection();
final Screen screen = Objects.requireNonNullElseGet(
((ClientCommonNetworkHandlerAccessor) networkHandler).getPostDisconnectScreen(),
TitleScreen::new);
// This stuff needs to run after we close chat, otherwise it kicks us to the title screen. Don't ask me why
client.send(() -> {
connection.disconnect(Text.translatable("disconnect.transfer"));
connection.tryDisableAutoRead();
connection.handleDisconnection();
ConnectScreen.connect(screen, client, ServerAddress.parse(info.address), info, false, null);
});
}
private static int changeSession(final CommandContext<FabricClientCommandSource> context, final Session session) {
final MinecraftClient client = context.getSource().getClient();
((MinecraftClientAccessor) client).session(session); ((MinecraftClientAccessor) client).session(session);
// TODO: Put this in a separate class reconnect(client);
final ServerInfo info = client.getCurrentServerEntry();
if (client.world != null) client.world.disconnect();
client.disconnect();
ConnectScreen.connect(new TitleScreen(), client, ServerAddress.parse(info.address), info, false, null);
return Command.SINGLE_SUCCESS; return Command.SINGLE_SUCCESS;
} }
private static int changeOffline(final CommandContext<FabricClientCommandSource> context, final String username) throws CommandSyntaxException {
if (username.length() > 16) throw USERNAME_TOO_LONG.create();
return changeSession(context, offline(username));
}
} }

View file

@ -0,0 +1,12 @@
package land.chipmunk.chipmunkmod.mixin;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.ClientCommonNetworkHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ClientCommonNetworkHandler.class)
public interface ClientCommonNetworkHandlerAccessor {
@Accessor("postDisconnectScreen")
Screen getPostDisconnectScreen();
}

View file

@ -9,12 +9,16 @@ public final class RandomUtilities {
.toCharArray(); .toCharArray();
public static String emptyUsername(final Random random) { public static String emptyUsername(final Random random) {
return RandomUtilities.emptyUsername(random, '&');
}
public static String emptyUsername(final Random random, char colorChar) {
final char[] buf = new char[16]; final char[] buf = new char[16];
for (int i = 0; i < 16; i += 2) { for (int i = 0; i < 16; i += 2) {
final int j = random.nextInt(LEGACY_STYLE_CODES.length); final int j = random.nextInt(LEGACY_STYLE_CODES.length);
buf[i] = '&'; buf[i] = colorChar;
buf[i + 1] = LEGACY_STYLE_CODES[j]; buf[i + 1] = LEGACY_STYLE_CODES[j];
} }

View file

@ -6,6 +6,7 @@
"client": [ "client": [
"ChatInputSuggestorMixin", "ChatInputSuggestorMixin",
"ChatScreenMixin", "ChatScreenMixin",
"ClientCommonNetworkHandlerAccessor",
"ClientConnectionMixin", "ClientConnectionMixin",
"ClientPlayerEntityMixin", "ClientPlayerEntityMixin",
"ClientPlayNetworkHandlerMixin", "ClientPlayNetworkHandlerMixin",