package ar.com.companeros.body; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.AttributeKey; import java.net.InetSocketAddress; import java.net.SocketAddress; import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketSendListener; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraftforge.network.NetworkConstants; /** Transporte de un participante del mismo servidor: canal local, sin abrir sockets. */ final class LocalConnection extends Connection { private final EmbeddedChannel localChannel; private long deliveredPackets; LocalConnection() { super(PacketFlow.SERVERBOUND); localChannel = new EmbeddedChannel(); localChannel.pipeline().addLast("packet_handler", this); try { // channelActive inicializa los atributos vanilla sin reflection ni AccessTransformer. super.channelActive(localChannel.pipeline().context(this)); } catch (Exception failure) { localChannel.finishAndReleaseAll(); throw new IllegalStateException("No se pudo abrir el canal local del agente", failure); } localChannel.attr(AttributeKey.valueOf("fml:netversion")).set(NetworkConstants.NETVERSION); setProtocol(ConnectionProtocol.PLAY); pump(); } // Los paquetes dirigidos al propio agente no se guardan en una cola sin consumidor. @Override public void send(Packet packet, PacketSendListener completion) { deliveredPackets++; if (completion != null) completion.onSuccess(); } @Override public void tick() { } @Override public boolean isMemoryConnection() { return true; } @Override public SocketAddress getRemoteAddress() { return new InetSocketAddress("127.0.0.1", 0); } long deliveredPackets() { return deliveredPackets; } void pump() { localChannel.runPendingTasks(); localChannel.checkException(); } void close() { disconnect(Component.literal("Sesión del agente cerrada")); localChannel.finishAndReleaseAll(); } }