.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.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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"client": [
|
||||
"ChatInputSuggestorMixin",
|
||||
"ChatScreenMixin",
|
||||
"ClientCommonNetworkHandlerAccessor",
|
||||
"ClientConnectionMixin",
|
||||
"ClientPlayerEntityMixin",
|
||||
"ClientPlayNetworkHandlerMixin",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue