/* * Copyright (C) 2014 - 2020 | Alexander01998 | All rights reserved. * * This source code is subject to the terms of the GNU General Public * License, version 3. If a copy of the GPL was not distributed with this * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt */ package net.wurstclient.serverfinder; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import org.lwjgl.glfw.GLFW; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.network.ServerInfo; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.LiteralText; import net.minecraft.util.Util; import net.wurstclient.WurstClient; import net.wurstclient.mixinterface.IMultiplayerScreen; import net.wurstclient.util.MathUtils; public class ServerFinderScreen extends Screen { private MultiplayerScreen prevScreen; private TextFieldWidget ipBox; private TextFieldWidget maxThreadsBox; private ButtonWidget searchButton; private ServerFinderState state; private int maxThreads; private int checked; private int working; public ServerFinderScreen(MultiplayerScreen prevMultiplayerMenu) { super(new LiteralText("")); prevScreen = prevMultiplayerMenu; } @Override public void init() { addButton(searchButton = new ButtonWidget(width / 2 - 100, height / 4 + 96 + 12, 200, 20, new LiteralText("Search"), b -> searchOrCancel())); addButton(new ButtonWidget(width / 2 - 100, height / 4 + 120 + 12, 200, 20, new LiteralText("Tutorial"), b -> Util.getOperatingSystem().open( "https://www.wurstclient.net/wiki/Special_Features/Server_Finder/"))); addButton(new ButtonWidget(width / 2 - 100, height / 4 + 144 + 12, 200, 20, new LiteralText("Back"), b -> client.openScreen(prevScreen))); ipBox = new TextFieldWidget(textRenderer, width / 2 - 100, height / 4 + 34, 200, 20, new LiteralText("")); ipBox.setMaxLength(200); ipBox.setSelected(true); children.add(ipBox); maxThreadsBox = new TextFieldWidget(textRenderer, width / 2 - 32, height / 4 + 58, 26, 12, new LiteralText("")); maxThreadsBox.setMaxLength(3); maxThreadsBox.setText("128"); children.add(maxThreadsBox); setInitialFocus(ipBox); state = ServerFinderState.NOT_RUNNING; WurstClient.INSTANCE.getAnalytics() .trackPageView("/multiplayer/server-finder", "Server Finder"); } private void searchOrCancel() { if(state.isRunning()) { state = ServerFinderState.CANCELLED; return; } state = ServerFinderState.RESOLVING; maxThreads = Integer.parseInt(maxThreadsBox.getText()); checked = 0; working = 0; new Thread(() -> findServers(), "Server Finder").start(); } private void findServers() { try { InetAddress addr = InetAddress.getByName(ipBox.getText().split(":")[0].trim()); int[] ipParts = new int[4]; for(int i = 0; i < 4; i++) ipParts[i] = addr.getAddress()[i] & 0xff; state = ServerFinderState.SEARCHING; ArrayList<WurstServerPinger> pingers = new ArrayList<>(); int[] changes = {0, 1, -1, 2, -2, 3, -3}; for(int change : changes) for(int i2 = 0; i2 <= 255; i2++) { if(state == ServerFinderState.CANCELLED) return; int[] ipParts2 = ipParts.clone(); ipParts2[2] = ipParts[2] + change & 0xff; ipParts2[3] = i2; String ip = ipParts2[0] + "." + ipParts2[1] + "." + ipParts2[2] + "." + ipParts2[3]; WurstServerPinger pinger = new WurstServerPinger(); pinger.ping(ip); pingers.add(pinger); while(pingers.size() >= maxThreads) { if(state == ServerFinderState.CANCELLED) return; updatePingers(pingers); } } while(pingers.size() > 0) { if(state == ServerFinderState.CANCELLED) return; updatePingers(pingers); } state = ServerFinderState.DONE; }catch(UnknownHostException e) { state = ServerFinderState.UNKNOWN_HOST; }catch(Exception e) { e.printStackTrace(); state = ServerFinderState.ERROR; } } @Override public void tick() { ipBox.tick(); searchButton.setMessage( new LiteralText(state.isRunning() ? "Cancel" : "Search")); ipBox.active = !state.isRunning(); maxThreadsBox.active = !state.isRunning(); searchButton.active = MathUtils.isInteger(maxThreadsBox.getText()) && !ipBox.getText().isEmpty(); } private boolean isServerInList(String ip) { for(int i = 0; i < prevScreen.getServerList().size(); i++) if(prevScreen.getServerList().get(i).address.equals(ip)) return true; return false; } private void updatePingers(ArrayList<WurstServerPinger> pingers) { for(int i = 0; i < pingers.size(); i++) if(!pingers.get(i).isStillPinging()) { checked++; if(pingers.get(i).isWorking()) { working++; if(!isServerInList(pingers.get(i).getServerIP())) { prevScreen.getServerList() .add(new ServerInfo("Grief me #" + working, pingers.get(i).getServerIP(), false)); prevScreen.getServerList().saveFile(); ((IMultiplayerScreen)prevScreen).getServerListSelector() .setSelected(null); ((IMultiplayerScreen)prevScreen).getServerListSelector() .setServers(prevScreen.getServerList()); } } pingers.remove(i); } } @Override public boolean keyPressed(int keyCode, int scanCode, int int_3) { if(keyCode == GLFW.GLFW_KEY_ENTER) searchButton.onPress(); return super.keyPressed(keyCode, scanCode, int_3); } @Override public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { renderBackground(matrixStack); drawCenteredString(matrixStack, textRenderer, "Server Finder", width / 2, 20, 16777215); drawCenteredString(matrixStack, textRenderer, "This will search for servers with similar IPs", width / 2, 40, 10526880); drawCenteredString(matrixStack, textRenderer, "to the IP you type into the field below.", width / 2, 50, 10526880); drawCenteredString(matrixStack, textRenderer, "The servers it finds will be added to your server list.", width / 2, 60, 10526880); drawStringWithShadow(matrixStack, textRenderer, "Server address:", width / 2 - 100, height / 4 + 24, 10526880); ipBox.render(matrixStack, mouseX, mouseY, partialTicks); drawStringWithShadow(matrixStack, textRenderer, "Max. threads:", width / 2 - 100, height / 4 + 60, 10526880); maxThreadsBox.render(matrixStack, mouseX, mouseY, partialTicks); drawCenteredString(matrixStack, textRenderer, state.toString(), width / 2, height / 4 + 73, 10526880); drawStringWithShadow(matrixStack, textRenderer, "Checked: " + checked + " / 1792", width / 2 - 100, height / 4 + 84, 10526880); drawStringWithShadow(matrixStack, textRenderer, "Working: " + working, width / 2 - 100, height / 4 + 94, 10526880); super.render(matrixStack, mouseX, mouseY, partialTicks); } @Override public void onClose() { state = ServerFinderState.CANCELLED; super.onClose(); } enum ServerFinderState { NOT_RUNNING(""), SEARCHING("\u00a72Searching..."), RESOLVING("\u00a72Resolving..."), UNKNOWN_HOST("\u00a74Unknown Host!"), CANCELLED("\u00a74Cancelled!"), DONE("\u00a72Done!"), ERROR("\u00a74An error occurred!"); private final String name; private ServerFinderState(String name) { this.name = name; } public boolean isRunning() { return this == SEARCHING || this == RESOLVING; } @Override public String toString() { return name; } } }