package com.github.steveice10.mc.protocol.test; import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.auth.service.AuthenticationService; import com.github.steveice10.mc.auth.service.SessionService; import com.github.steveice10.mc.protocol.MinecraftConstants; import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.ServerLoginHandler; import com.github.steveice10.mc.protocol.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.status.PlayerInfo; import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo; import com.github.steveice10.mc.protocol.data.status.VersionInfo; import com.github.steveice10.mc.protocol.data.status.handler.ServerInfoBuilder; import com.github.steveice10.mc.protocol.data.status.handler.ServerInfoHandler; import com.github.steveice10.mc.protocol.data.status.handler.ServerPingTimeHandler; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket; import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.FloatTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.LongTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.packetlib.ProxyInfo; import com.github.steveice10.packetlib.Server; import com.github.steveice10.packetlib.Session; import com.github.steveice10.packetlib.event.server.ServerAdapter; import com.github.steveice10.packetlib.event.server.ServerClosedEvent; import com.github.steveice10.packetlib.event.server.SessionAddedEvent; import com.github.steveice10.packetlib.event.server.SessionRemovedEvent; import com.github.steveice10.packetlib.event.session.DisconnectedEvent; import com.github.steveice10.packetlib.event.session.PacketReceivedEvent; import com.github.steveice10.packetlib.event.session.SessionAdapter; import com.github.steveice10.packetlib.tcp.TcpClientSession; import com.github.steveice10.packetlib.tcp.TcpServer; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; import java.net.Proxy; import java.util.Arrays; import java.util.Map; public class MinecraftProtocolTest { private static final boolean SPAWN_SERVER = true; private static final boolean VERIFY_USERS = false; private static final String HOST = "127.0.0.1"; private static final int PORT = 25565; private static final ProxyInfo PROXY = null; private static final Proxy AUTH_PROXY = Proxy.NO_PROXY; private static final String USERNAME = "Username"; private static final String PASSWORD = "Password"; public static void main(String[] args) { if(SPAWN_SERVER) { SessionService sessionService = new SessionService(); sessionService.setProxy(AUTH_PROXY); Server server = new TcpServer(HOST, PORT, MinecraftProtocol.class); server.setGlobalFlag(MinecraftConstants.SESSION_SERVICE_KEY, sessionService); server.setGlobalFlag(MinecraftConstants.VERIFY_USERS_KEY, VERIFY_USERS); server.setGlobalFlag(MinecraftConstants.SERVER_INFO_BUILDER_KEY, (ServerInfoBuilder) session -> new ServerStatusInfo( new VersionInfo(MinecraftConstants.GAME_VERSION, MinecraftConstants.PROTOCOL_VERSION), new PlayerInfo(100, 0, new GameProfile[0]), Component.text("Hello world!"), null ) ); server.setGlobalFlag(MinecraftConstants.SERVER_LOGIN_HANDLER_KEY, (ServerLoginHandler) session -> session.send(new ServerJoinGamePacket( 0, false, GameMode.SURVIVAL, GameMode.SURVIVAL, 1, new String[] {"minecraft:world"}, getDimensionTag(), getOverworldTag(), "minecraft:world", 100, 0, 16, false, false, false, false )) ); server.setGlobalFlag(MinecraftConstants.SERVER_COMPRESSION_THRESHOLD, 100); server.addListener(new ServerAdapter() { @Override public void serverClosed(ServerClosedEvent event) { System.out.println("Server closed."); } @Override public void sessionAdded(SessionAddedEvent event) { event.getSession().addListener(new SessionAdapter() { @Override public void packetReceived(PacketReceivedEvent event) { if(event.getPacket() instanceof ClientChatPacket) { ClientChatPacket packet = event.getPacket(); GameProfile profile = event.getSession().getFlag(MinecraftConstants.PROFILE_KEY); System.out.println(profile.getName() + ": " + packet.getMessage()); Component msg = Component.text("Hello, ") .color(NamedTextColor.GREEN) .append(Component.text(profile.getName()) .color(NamedTextColor.AQUA) .decorate(TextDecoration.UNDERLINED)) .append(Component.text("!") .color(NamedTextColor.GREEN)); event.getSession().send(new ServerChatPacket(msg)); } } }); } @Override public void sessionRemoved(SessionRemovedEvent event) { MinecraftProtocol protocol = (MinecraftProtocol) event.getSession().getPacketProtocol(); if(protocol.getSubProtocol() == SubProtocol.GAME) { System.out.println("Closing server."); event.getServer().close(false); } } }); server.bind(); } status(); login(); } private static void status() { SessionService sessionService = new SessionService(); sessionService.setProxy(AUTH_PROXY); MinecraftProtocol protocol = new MinecraftProtocol(); Session client = new TcpClientSession(HOST, PORT, protocol, PROXY); client.setFlag(MinecraftConstants.SESSION_SERVICE_KEY, sessionService); client.setFlag(MinecraftConstants.SERVER_INFO_HANDLER_KEY, (ServerInfoHandler) (session, info) -> { System.out.println("Version: " + info.getVersionInfo().getVersionName() + ", " + info.getVersionInfo().getProtocolVersion()); System.out.println("Player Count: " + info.getPlayerInfo().getOnlinePlayers() + " / " + info.getPlayerInfo().getMaxPlayers()); System.out.println("Players: " + Arrays.toString(info.getPlayerInfo().getPlayers())); System.out.println("Description: " + info.getDescription()); System.out.println("Icon: " + info.getIconPng()); }); client.setFlag(MinecraftConstants.SERVER_PING_TIME_HANDLER_KEY, (ServerPingTimeHandler) (session, pingTime) -> System.out.println("Server ping took " + pingTime + "ms")); client.connect(); while(client.isConnected()) { try { Thread.sleep(5); } catch(InterruptedException e) { e.printStackTrace(); } } } private static void login() { MinecraftProtocol protocol = null; if(VERIFY_USERS) { try { AuthenticationService authService = new AuthenticationService(); authService.setUsername(USERNAME); authService.setPassword(PASSWORD); authService.setProxy(AUTH_PROXY); authService.login(); protocol = new MinecraftProtocol(authService.getSelectedProfile(), authService.getAccessToken()); System.out.println("Successfully authenticated user."); } catch(RequestException e) { e.printStackTrace(); return; } } else { protocol = new MinecraftProtocol(USERNAME); } SessionService sessionService = new SessionService(); sessionService.setProxy(AUTH_PROXY); Session client = new TcpClientSession(HOST, PORT, protocol, PROXY); client.setFlag(MinecraftConstants.SESSION_SERVICE_KEY, sessionService); client.addListener(new SessionAdapter() { @Override public void packetReceived(PacketReceivedEvent event) { if(event.getPacket() instanceof ServerJoinGamePacket) { event.getSession().send(new ClientChatPacket("Hello, this is a test of MCProtocolLib.")); } else if(event.getPacket() instanceof ServerChatPacket) { Component message = event.getPacket().getMessage(); System.out.println("Received Message: " + message); event.getSession().disconnect("Finished"); } } @Override public void disconnected(DisconnectedEvent event) { System.out.println("Disconnected: " + event.getReason()); if(event.getCause() != null) { event.getCause().printStackTrace(); } } }); client.connect(); } private static CompoundTag getDimensionTag() { CompoundTag tag = new CompoundTag(""); CompoundTag dimensionTypes = new CompoundTag("minecraft:dimension_type"); dimensionTypes.put(new StringTag("type", "minecraft:dimension_type")); ListTag dimensionTag = new ListTag("value"); CompoundTag overworldTag = convertToValue("minecraft:overworld", 0, getOverworldTag().getValue()); dimensionTag.add(overworldTag); dimensionTypes.put(dimensionTag); tag.put(dimensionTypes); CompoundTag biomeTypes = new CompoundTag("minecraft:worldgen/biome"); biomeTypes.put(new StringTag("type", "minecraft:worldgen/biome")); ListTag biomeTag = new ListTag("value"); CompoundTag plainsTag = convertToValue("minecraft:plains", 0, getPlainsTag().getValue()); biomeTag.add(plainsTag); biomeTypes.put(biomeTag); tag.put(biomeTypes); return tag; } private static CompoundTag getOverworldTag() { CompoundTag overworldTag = new CompoundTag(""); overworldTag.put(new StringTag("name", "minecraft:overworld")); overworldTag.put(new ByteTag("piglin_safe", (byte) 0)); overworldTag.put(new ByteTag("natural", (byte) 1)); overworldTag.put(new FloatTag("ambient_light", 0f)); overworldTag.put(new StringTag("infiniburn", "minecraft:infiniburn_overworld")); overworldTag.put(new ByteTag("respawn_anchor_works", (byte) 0)); overworldTag.put(new ByteTag("has_skylight", (byte) 1)); overworldTag.put(new ByteTag("bed_works", (byte) 1)); overworldTag.put(new StringTag("effects", "minecraft:overworld")); overworldTag.put(new ByteTag("has_raids", (byte) 1)); overworldTag.put(new IntTag("logical_height", 256)); overworldTag.put(new FloatTag("coordinate_scale", 1f)); overworldTag.put(new ByteTag("ultrawarm", (byte) 0)); overworldTag.put(new ByteTag("has_ceiling", (byte) 0)); return overworldTag; } private static CompoundTag getPlainsTag() { CompoundTag plainsTag = new CompoundTag(""); plainsTag.put(new StringTag("name", "minecraft:plains")); plainsTag.put(new StringTag("precipitation", "rain")); plainsTag.put(new FloatTag("depth", 0.125f)); plainsTag.put(new FloatTag("temperature", 0.8f)); plainsTag.put(new FloatTag("scale", 0.05f)); plainsTag.put(new FloatTag("downfall", 0.4f)); plainsTag.put(new StringTag("category", "plains")); CompoundTag effects = new CompoundTag("effects"); effects.put(new LongTag("sky_color", 7907327)); effects.put(new LongTag("water_fog_color", 329011)); effects.put(new LongTag("fog_color", 12638463)); effects.put(new LongTag("water_color", 4159204)); CompoundTag moodSound = new CompoundTag("mood_sound"); moodSound.put(new IntTag("tick_delay", 6000)); moodSound.put(new FloatTag("offset", 2.0f)); moodSound.put(new StringTag("sound", "minecraft:ambient.cave")); moodSound.put(new IntTag("block_search_extent", 8)); effects.put(moodSound); plainsTag.put(effects); return plainsTag; } private static CompoundTag convertToValue(String name, int id, Map values) { CompoundTag tag = new CompoundTag(name); tag.put(new StringTag("name", name)); tag.put(new IntTag("id", id)); CompoundTag element = new CompoundTag("element"); element.setValue(values); tag.put(element); return tag; } }