package ganarchy.friendcode.client; import it.unimi.dsi.fastutil.booleans.BooleanConsumer; import net.minecraft.client.gui.screen.LoadingDisplay; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.network.ServerInfo; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.screen.ScreenTexts; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Util; import org.apache.commons.codec.binary.Base32; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Base64; import java.util.Locale; public class FriendConnectingScreen extends Screen { private static final Text PATIENCE_TEXT = Text.translatable("friendcode.patience"); private final ServerInfo serverEntry; private final BooleanConsumer callback; private final SamProxyThread proxyThread; private long startTimeMs; private Text renderText = null; public FriendConnectingScreen(ServerInfo serverEntry, BooleanConsumer callback, String text) { super(Text.translatable("friendcode.connecting")); this.serverEntry = serverEntry; this.callback = callback; this.startTimeMs = Util.getMeasuringTimeMs(); this.proxyThread = new SamProxyThread(text); } @Override protected void init() { try { this.proxyThread.start(); } catch (IllegalThreadStateException ignored) { } // cancel friend code. this.addDrawableChild(new ButtonWidget( this.width / 2 - 155, this.height - 28, 310, 20, ScreenTexts.CANCEL, button -> this.close() )); } @Override public void close() { super.close(); if (this.proxyThread.status() != SamProxyThread.Status.RUNNING) { this.proxyThread.stopProxy(); } } @Override public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { this.renderBackground(matrices); FriendConnectingScreen.drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 50, 0xFFFFFF); if (this.renderText != null) { FriendConnectingScreen.drawCenteredText(matrices, this.textRenderer, this.renderText, this.width / 2, 82, 0xFFFFFF); } else { FriendConnectingScreen.drawCenteredText(matrices, this.textRenderer, PATIENCE_TEXT, this.width / 2, 82, 0xFFFFFF); final String string = LoadingDisplay.get(Util.getMeasuringTimeMs()); this.client.textRenderer.draw(matrices, string, (float) (this.client.currentScreen.width / 2 - this.client.textRenderer.getWidth(string) / 2), (float) (this.client.currentScreen.height / 2 + this.client.textRenderer.fontHeight), 0x808080); } super.render(matrices, mouseX, mouseY, delta); } @Override public void tick() { super.tick(); if (proxyThread.status() != SamProxyThread.Status.IDLE) { switch (proxyThread.status()) { case CONNECTION_FAILED -> { this.renderText = Text.translatable("friendcode.connect.no_i2p"); break; } case SETUP_FAILED -> { this.renderText = Text.translatable("friendcode.connect.failed"); break; } case RESOLUTION_FAILED -> { this.renderText = Text.translatable("friendcode.connect.no_such_code"); break; } case RUNNING -> { this.serverEntry.address = "[::1]:" + this.proxyThread.port(); this.callback.accept(true); break; } } } if (!this.proxyThread.isConnecting()) { startTimeMs = Util.getMeasuringTimeMs(); } if (Util.getMeasuringTimeMs() - startTimeMs > 20 * 1000) { // keep it from getting stuck. // FIXME this is wrong. //this.proxyThread.interrupt(); } } }