.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.argument;
import land.chipmunk.chipmunkmod.mixin.ClientCommonNetworkHandlerAccessor;
import land.chipmunk.chipmunkmod.util.RandomUtilities;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
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.multiplayer.ConnectScreen;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ServerInfo;
import net.minecraft.client.network.ServerAddress;
import net.minecraft.client.session.Session;
import net.minecraft.network.ClientConnection;
import net.minecraft.text.Text;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.Random;
import land.chipmunk.chipmunkmod.mixin.MinecraftClientAccessor;
import net.minecraft.util.Uuids;
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 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) {
dispatcher.register(
literal("username")
.then(
literal("set")
.then(
argument("username", string())
.executes(UsernameCommand::updateUsername)
)
)
.then(
literal("revert")
.executes(c -> updateSession(c, ORIGINAL_SESSION))
)
dispatcher.register(literal("username")
.then(literal("set")
.then(argument("username", string())
.executes(c -> changeOffline(c, getString(c, "username")))))
.then(literal("revert")
.executes(c -> changeSession(c, ORIGINAL_SESSION)))
.then(literal("random")
.then(literal("blank")
.executes(c -> changeOffline(c, RandomUtilities.emptyUsername(RANDOM, SECTION_CHAR))))
.executes(c -> changeOffline(c, RandomUtilities.randomString(RANDOM, PREMIUM_CHARS, RANDOM.nextInt(3, 16)))))
.then(literal("empty")
.executes(c -> changeOffline(c, "")))
);
}
public static int updateUsername(CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
final String username = getString(context, "username");
if (username.length() > 16) throw USERNAME_TOO_LONG.create();
final Session session = new Session(username, new UUID(0L, 0L), "", Optional.empty(), Optional.empty(), Session.AccountType.MOJANG);
return updateSession(context, session);
private static Session offline(final String username) {
// This is how Minecraft's Main class does it
return new Session(username, Uuids.getOfflinePlayerUuid(username),
"", Optional.empty(), Optional.empty(), Session.AccountType.LEGACY);
}
public static int updateSession(CommandContext<FabricClientCommandSource> context, Session session) {
final FabricClientCommandSource source = context.getSource();
// TODO: Put this in a separate class
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);
// TODO: Put this in a separate class
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);
reconnect(client);
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();
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];
for (int i = 0; i < 16; i += 2) {
final int j = random.nextInt(LEGACY_STYLE_CODES.length);
buf[i] = '&';
buf[i] = colorChar;
buf[i + 1] = LEGACY_STYLE_CODES[j];
}

View file

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