.username random/blank/empty #14
4 changed files with 78 additions and 30 deletions
src/main
java/land/chipmunk/chipmunkmod
resources
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"client": [
|
"client": [
|
||||||
"ChatInputSuggestorMixin",
|
"ChatInputSuggestorMixin",
|
||||||
"ChatScreenMixin",
|
"ChatScreenMixin",
|
||||||
|
"ClientCommonNetworkHandlerAccessor",
|
||||||
"ClientConnectionMixin",
|
"ClientConnectionMixin",
|
||||||
"ClientPlayerEntityMixin",
|
"ClientPlayerEntityMixin",
|
||||||
"ClientPlayNetworkHandlerMixin",
|
"ClientPlayNetworkHandlerMixin",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue