Item Generator and Server finder
This commit is contained in:
committed by
Cloudburst
parent
ea106d6f70
commit
97d42528bc
@@ -57,6 +57,7 @@ public class MeteorRejectsAddon extends MeteorAddon {
|
||||
modules.add(new GhostMode());
|
||||
modules.add(new Glide());
|
||||
modules.add(new InstaMine());
|
||||
modules.add(new ItemGenerator());
|
||||
modules.add(new InteractionMenu());
|
||||
modules.add(new Lavacast());
|
||||
modules.add(new NewChunks());
|
||||
@@ -121,7 +122,7 @@ public class MeteorRejectsAddon extends MeteorAddon {
|
||||
.get().getMetadata()
|
||||
.getCustomValue("github:sha")
|
||||
.getAsString();
|
||||
LOG.info(String.format("Rejects version: %s", commit.toString()));
|
||||
LOG.info(String.format("Rejects version: %s", commit));
|
||||
return commit.isEmpty() ? null : commit.trim();
|
||||
}
|
||||
|
||||
|
||||
124
src/main/java/anticope/rejects/gui/servers/CleanUpScreen.java
Normal file
124
src/main/java/anticope/rejects/gui/servers/CleanUpScreen.java
Normal file
@@ -0,0 +1,124 @@
|
||||
package anticope.rejects.gui.servers;
|
||||
|
||||
import anticope.rejects.mixin.MultiplayerScreenAccessor;
|
||||
import anticope.rejects.mixin.ServerListAccessor;
|
||||
import meteordevelopment.meteorclient.gui.GuiTheme;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WCheckbox;
|
||||
import meteordevelopment.meteorclient.utils.render.color.Color;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class CleanUpScreen extends WindowScreen {
|
||||
private final MultiplayerScreen multiplayerScreen;
|
||||
private final WCheckbox removeAll;
|
||||
private final WCheckbox removeFailed;
|
||||
private final WCheckbox removeOutdated;
|
||||
private final WCheckbox removeUnknown;
|
||||
private final WCheckbox removeGriefMe;
|
||||
private final WCheckbox removeDuplicates;
|
||||
private final WCheckbox rename;
|
||||
|
||||
public CleanUpScreen(GuiTheme theme, MultiplayerScreen multiplayerScreen, Screen parent) {
|
||||
super(theme, "Clean Up");
|
||||
this.multiplayerScreen = multiplayerScreen;
|
||||
this.parent = parent;
|
||||
removeUnknown = theme.checkbox(true);
|
||||
removeOutdated = theme.checkbox(false);
|
||||
removeFailed = theme.checkbox(true);
|
||||
removeGriefMe = theme.checkbox(false);
|
||||
removeAll = theme.checkbox(false);
|
||||
removeDuplicates = theme.checkbox(true);
|
||||
rename = theme.checkbox(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
WTable table = add(new WTable()).widget();
|
||||
table.add(theme.label("Remove:"));
|
||||
table.row();
|
||||
table.add(theme.label("Unknown Hosts:")).widget().tooltip = "";
|
||||
table.add(removeUnknown).widget();
|
||||
table.row();
|
||||
table.add(theme.label("Outdated Servers:"));
|
||||
table.add(removeOutdated).widget();
|
||||
table.row();
|
||||
table.add(theme.label("Failed Ping:"));
|
||||
table.add(removeFailed).widget();
|
||||
table.row();
|
||||
table.add(theme.label("\"Server discovery\" Servers:"));
|
||||
table.add(removeGriefMe).widget();
|
||||
table.row();
|
||||
table.add(theme.label("Everything:")).widget().color = new Color(255, 0, 0);
|
||||
table.add(removeAll).widget();
|
||||
table.row();
|
||||
table.add(theme.label("Duplicates:"));
|
||||
table.add(removeDuplicates).widget();
|
||||
table.row();
|
||||
table.add(theme.label("Rename all Servers:"));
|
||||
table.add(rename).widget();
|
||||
table.row();
|
||||
table.add(theme.button("Execute!")).expandX().widget().action = this::cleanUp;
|
||||
}
|
||||
|
||||
private void cleanUp() {
|
||||
Set<String> knownIPs = new HashSet<>();
|
||||
List<ServerInfo> servers = ((ServerListAccessor) multiplayerScreen.getServerList()).getServers();
|
||||
for (ServerInfo server : servers.toArray(ServerInfo[]::new)) {
|
||||
if (removeAll.checked || shouldRemove(server, knownIPs))
|
||||
servers.remove(server);
|
||||
}
|
||||
|
||||
if (rename.checked)
|
||||
for (int i = 0; i < servers.size(); i++) {
|
||||
ServerInfo server = servers.get(i);
|
||||
server.name = "Server discovery " + (i + 1);
|
||||
}
|
||||
|
||||
saveServerList();
|
||||
client.setScreen(parent);
|
||||
}
|
||||
|
||||
private boolean shouldRemove(ServerInfo server, Set<String> knownIPs) {
|
||||
return server != null && (removeUnknown.checked && isUnknownHost(server)
|
||||
|| removeOutdated.checked && !isSameProtocol(server)
|
||||
|| removeFailed.checked && isFailedPing(server)
|
||||
|| removeGriefMe.checked && isGriefMeServer(server)
|
||||
|| removeDuplicates.checked && !knownIPs.add(server.address));
|
||||
}
|
||||
|
||||
private boolean isUnknownHost(ServerInfo server) {
|
||||
if (server.label == null || server.label.getString() == null) return false;
|
||||
|
||||
return server.label.getString().equals("\u00a74Can't resolve hostname");
|
||||
}
|
||||
|
||||
private boolean isSameProtocol(ServerInfo server) {
|
||||
return server.protocolVersion == SharedConstants.getGameVersion().getProtocolVersion();
|
||||
}
|
||||
|
||||
private boolean isFailedPing(ServerInfo server) {
|
||||
return server.ping != -2L && server.ping < 0L;
|
||||
}
|
||||
|
||||
private boolean isGriefMeServer(ServerInfo server) {
|
||||
return server.name != null && server.name.startsWith("Server discovery ");
|
||||
}
|
||||
|
||||
private void saveServerList() {
|
||||
multiplayerScreen.getServerList().saveFile();
|
||||
|
||||
MultiplayerServerListWidget serverListSelector = ((MultiplayerScreenAccessor) multiplayerScreen).getServerListWidget();
|
||||
|
||||
serverListSelector.setSelected(null);
|
||||
serverListSelector.setServers(multiplayerScreen.getServerList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package anticope.rejects.gui.servers;
|
||||
|
||||
import anticope.rejects.mixin.MultiplayerScreenAccessor;
|
||||
import anticope.rejects.utils.server.LegacyServerPinger;
|
||||
import meteordevelopment.meteorclient.gui.GuiTheme;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.WLabel;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.input.WIntEdit;
|
||||
import meteordevelopment.meteorclient.gui.widgets.input.WTextBox;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LegacyServerFinderScreen extends WindowScreen {
|
||||
private final MultiplayerScreen multiplayerScreen;
|
||||
private final WTextBox ipBox;
|
||||
private final WIntEdit maxThreadsBox;
|
||||
private final WButton searchButton;
|
||||
private final WLabel stateLabel;
|
||||
private final WLabel checkedLabel;
|
||||
private final WLabel workingLabel;
|
||||
private ServerFinderState state;
|
||||
private int maxThreads;
|
||||
private int checked;
|
||||
private int working;
|
||||
|
||||
public LegacyServerFinderScreen(GuiTheme theme, MultiplayerScreen multiplayerScreen, Screen parent) {
|
||||
super(theme, "Legacy Server Discovery");
|
||||
this.multiplayerScreen = multiplayerScreen;
|
||||
this.parent = parent;
|
||||
ipBox = theme.textBox("127.0.0.1");
|
||||
maxThreadsBox = theme.intEdit(128, 1, 256, 1, 256);
|
||||
stateLabel = theme.label("");
|
||||
checkedLabel = theme.label("");
|
||||
workingLabel = theme.label("");
|
||||
searchButton = theme.button("Search");
|
||||
state = ServerFinderState.NOT_RUNNING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
add(theme.label("This will search for servers with similar IPs"));
|
||||
add(theme.label("to the IP you type into the field below."));
|
||||
add(theme.label("The servers it finds will be added to your server list."));
|
||||
WTable table = add(new WTable()).expandX().widget();
|
||||
table.add(theme.label("Server address:"));
|
||||
table.add(ipBox).expandX();
|
||||
table.row();
|
||||
table.add(theme.label("Max. Threads:"));
|
||||
table.add(maxThreadsBox);
|
||||
add(stateLabel);
|
||||
add(checkedLabel);
|
||||
add(workingLabel);
|
||||
add(searchButton).expandX();
|
||||
searchButton.action = this::searchOrCancel;
|
||||
}
|
||||
|
||||
private void searchOrCancel() {
|
||||
if (state.isRunning()) {
|
||||
state = ServerFinderState.CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
state = ServerFinderState.RESOLVING;
|
||||
maxThreads = maxThreadsBox.get();
|
||||
checked = 0;
|
||||
working = 0;
|
||||
|
||||
new Thread(this::findServers, "Server Discovery").start();
|
||||
}
|
||||
|
||||
private void findServers() {
|
||||
try {
|
||||
InetAddress addr =
|
||||
InetAddress.getByName(ipBox.get().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<LegacyServerPinger> 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];
|
||||
|
||||
LegacyServerPinger pinger = new LegacyServerPinger();
|
||||
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() {
|
||||
searchButton.set(state.isRunning() ? "Cancel" : "Search");
|
||||
if (state.isRunning()) {
|
||||
ipBox.setFocused(false);
|
||||
maxThreadsBox.set(maxThreads);
|
||||
}
|
||||
stateLabel.set(state.toString());
|
||||
checkedLabel.set("Checked: " + checked + " / 1792");
|
||||
workingLabel.set("Working: " + working);
|
||||
searchButton.visible = !ipBox.get().isEmpty();
|
||||
}
|
||||
|
||||
private boolean isServerInList(String ip) {
|
||||
for (int i = 0; i < multiplayerScreen.getServerList().size(); i++)
|
||||
if (multiplayerScreen.getServerList().get(i).address.equals(ip))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updatePingers(ArrayList<LegacyServerPinger> 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())) {
|
||||
multiplayerScreen.getServerList()
|
||||
.add(new ServerInfo("Server discovery " + working,
|
||||
pingers.get(i).getServerIP(), false), false);
|
||||
multiplayerScreen.getServerList().saveFile();
|
||||
((MultiplayerScreenAccessor) multiplayerScreen).getServerListWidget()
|
||||
.setSelected(null);
|
||||
((MultiplayerScreenAccessor) multiplayerScreen).getServerListWidget()
|
||||
.setServers(multiplayerScreen.getServerList());
|
||||
}
|
||||
}
|
||||
pingers.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
state = ServerFinderState.CANCELLED;
|
||||
super.close();
|
||||
}
|
||||
|
||||
enum ServerFinderState {
|
||||
NOT_RUNNING(""),
|
||||
SEARCHING("Searching..."),
|
||||
RESOLVING("Resolving..."),
|
||||
UNKNOWN_HOST("Unknown Host!"),
|
||||
CANCELLED("Cancelled!"),
|
||||
DONE("Done!"),
|
||||
ERROR("An error occurred!");
|
||||
|
||||
private final String name;
|
||||
|
||||
ServerFinderState(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return this == SEARCHING || this == RESOLVING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
package anticope.rejects.gui.servers;
|
||||
|
||||
import anticope.rejects.mixin.MultiplayerScreenAccessor;
|
||||
import anticope.rejects.utils.server.IServerFinderDoneListener;
|
||||
import anticope.rejects.utils.server.MServerInfo;
|
||||
import anticope.rejects.utils.server.ServerPinger;
|
||||
import meteordevelopment.meteorclient.gui.GuiTheme;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.WLabel;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.input.WIntEdit;
|
||||
import meteordevelopment.meteorclient.gui.widgets.input.WTextBox;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WCheckbox;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Stack;
|
||||
|
||||
public class ServerFinderScreen extends WindowScreen implements IServerFinderDoneListener {
|
||||
public static ServerFinderScreen instance = null;
|
||||
private static int searchNumber = 0;
|
||||
private final MultiplayerScreen multiplayerScreen;
|
||||
private final WTextBox ipBox;
|
||||
private final WTextBox versionBox;
|
||||
private final WIntEdit maxThreadsBox;
|
||||
private final WButton searchButton;
|
||||
private final WLabel stateLabel;
|
||||
private final WLabel checkedLabel;
|
||||
private final WLabel workingLabel;
|
||||
private final WCheckbox scanPortsBox;
|
||||
private final Stack<String> ipsToPing = new Stack<>();
|
||||
private final Object serverFinderLock = new Object();
|
||||
private ServerFinderState state;
|
||||
private int maxThreads;
|
||||
private volatile int numActiveThreads;
|
||||
private volatile int checked;
|
||||
private volatile int working;
|
||||
private int targetChecked = 1792;
|
||||
private ArrayList<String> versionFilters = new ArrayList<>();
|
||||
private int playerCountFilter = 0;
|
||||
|
||||
public ServerFinderScreen(GuiTheme theme, MultiplayerScreen multiplayerScreen, Screen parent) {
|
||||
super(theme, "Server Discovery");
|
||||
this.multiplayerScreen = multiplayerScreen;
|
||||
this.parent = parent;
|
||||
ipBox = theme.textBox("127.0.0.1");
|
||||
versionBox = theme.textBox("1.18; 1.17; 1.16; 1.15; 1.14; 1.13; 1.12; 1.11; 1.10; 1.9; 1.8");
|
||||
maxThreadsBox = theme.intEdit(128, 1, 256, 1, 256);
|
||||
stateLabel = theme.label("");
|
||||
checkedLabel = theme.label("");
|
||||
searchButton = theme.button("Search");
|
||||
workingLabel = theme.label("");
|
||||
scanPortsBox = theme.checkbox(true);
|
||||
state = ServerFinderState.NOT_RUNNING;
|
||||
newSearch();
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static int getSearchNumber() {
|
||||
return searchNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
add(theme.label("This will search for servers with similar IPs"));
|
||||
add(theme.label("to the IP you type into the field below."));
|
||||
add(theme.label("The servers it finds will be added to your server list."));
|
||||
WTable table = add(new WTable()).expandX().widget();
|
||||
table.add(theme.label("Server address:"));
|
||||
table.add(ipBox).expandX();
|
||||
table.row();
|
||||
table.add(theme.label("Max. Threads:"));
|
||||
table.add(maxThreadsBox);
|
||||
table.row();
|
||||
table.add(theme.label("Scan ports"));
|
||||
table.add(scanPortsBox);
|
||||
table.row();
|
||||
table.add(theme.label("Versions:"));
|
||||
table.add(versionBox).expandX();
|
||||
add(stateLabel);
|
||||
add(checkedLabel);
|
||||
add(workingLabel);
|
||||
WHorizontalList list = add(theme.horizontalList()).expandX().widget();
|
||||
list.add(searchButton).expandX();
|
||||
searchButton.action = this::searchOrCancel;
|
||||
}
|
||||
|
||||
private void newSearch() {
|
||||
searchNumber = (searchNumber + 1) % 1000;
|
||||
}
|
||||
|
||||
public void incrementTargetChecked(int amount) {
|
||||
synchronized (serverFinderLock) {
|
||||
if (state != ServerFinderState.CANCELLED)
|
||||
targetChecked += amount;
|
||||
}
|
||||
}
|
||||
|
||||
public ServerFinderState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
private void searchOrCancel() {
|
||||
if (state.isRunning()) {
|
||||
state = ServerFinderState.CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
state = ServerFinderState.RESOLVING;
|
||||
maxThreads = maxThreadsBox.get();
|
||||
ipsToPing.clear();
|
||||
targetChecked = 1792;
|
||||
numActiveThreads = 0;
|
||||
checked = 0;
|
||||
working = 0;
|
||||
|
||||
newSearch();
|
||||
|
||||
parseVersionFilters();
|
||||
|
||||
findServers();
|
||||
}
|
||||
|
||||
private void parseVersionFilters() {
|
||||
String filter = versionBox.get();
|
||||
String[] versions = filter.split(";");
|
||||
if (versionFilters == null) {
|
||||
versionFilters = new ArrayList<>();
|
||||
}
|
||||
versionFilters.clear();
|
||||
for (String version : versions) {
|
||||
String trimmed = version.trim();
|
||||
if (trimmed.length() > 0)
|
||||
versionFilters.add(version.trim());
|
||||
}
|
||||
}
|
||||
|
||||
private void findServers() {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByName(ipBox.get().split(":")[0].trim());
|
||||
|
||||
int[] ipParts = new int[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
ipParts[i] = addr.getAddress()[i] & 0xff;
|
||||
|
||||
state = ServerFinderState.SEARCHING;
|
||||
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];
|
||||
|
||||
ipsToPing.push(ip);
|
||||
}
|
||||
while (numActiveThreads < maxThreads && pingNewIP()) {
|
||||
}
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
state = ServerFinderState.UNKNOWN_HOST;
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
state = ServerFinderState.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean pingNewIP() {
|
||||
synchronized (serverFinderLock) {
|
||||
if (ipsToPing.size() > 0) {
|
||||
String ip = ipsToPing.pop();
|
||||
ServerPinger pinger = new ServerPinger(scanPortsBox.checked, searchNumber);
|
||||
pinger.addServerFinderDoneListener(this);
|
||||
pinger.ping(ip);
|
||||
numActiveThreads++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
searchButton.set(state.isRunning() ? "Cancel" : "Search");
|
||||
if (state.isRunning()) {
|
||||
ipBox.setFocused(false);
|
||||
maxThreadsBox.set(maxThreads);
|
||||
}
|
||||
stateLabel.set(state.toString());
|
||||
checkedLabel.set("Checked: " + checked + " / " + targetChecked);
|
||||
workingLabel.set("Working: " + working);
|
||||
searchButton.visible = !ipBox.get().isEmpty();
|
||||
}
|
||||
|
||||
private boolean isServerInList(String ip) {
|
||||
for (int i = 0; i < multiplayerScreen.getServerList().size(); i++)
|
||||
if (multiplayerScreen.getServerList().get(i).address.equals(ip))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
state = ServerFinderState.CANCELLED;
|
||||
super.close();
|
||||
}
|
||||
|
||||
private boolean filterPass(MServerInfo info) {
|
||||
if (info == null)
|
||||
return false;
|
||||
if (info.playerCount < playerCountFilter)
|
||||
return false;
|
||||
for (String version : versionFilters) {
|
||||
if (info.version != null && info.version.contains(version)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return versionFilters.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerDone(ServerPinger pinger) {
|
||||
if (state == ServerFinderState.CANCELLED || pinger == null || pinger.getSearchNumber() != searchNumber)
|
||||
return;
|
||||
synchronized (serverFinderLock) {
|
||||
checked++;
|
||||
numActiveThreads--;
|
||||
}
|
||||
if (pinger.isWorking()) {
|
||||
if (!isServerInList(pinger.getServerIP()) && filterPass(pinger.getServerInfo())) {
|
||||
synchronized (serverFinderLock) {
|
||||
working++;
|
||||
multiplayerScreen.getServerList().add(new ServerInfo("Server discovery #" + working, pinger.getServerIP(), false), false);
|
||||
multiplayerScreen.getServerList().saveFile();
|
||||
((MultiplayerScreenAccessor) multiplayerScreen).getServerListWidget().setSelected(null);
|
||||
((MultiplayerScreenAccessor) multiplayerScreen).getServerListWidget().setServers(multiplayerScreen.getServerList());
|
||||
}
|
||||
}
|
||||
}
|
||||
while (numActiveThreads < maxThreads && pingNewIP()) ;
|
||||
synchronized (serverFinderLock) {
|
||||
if (checked == targetChecked) {
|
||||
state = ServerFinderState.DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerFailed(ServerPinger pinger) {
|
||||
if (state == ServerFinderState.CANCELLED || pinger == null || pinger.getSearchNumber() != searchNumber)
|
||||
return;
|
||||
synchronized (serverFinderLock) {
|
||||
checked++;
|
||||
numActiveThreads--;
|
||||
}
|
||||
while (numActiveThreads < maxThreads && pingNewIP()) ;
|
||||
synchronized (serverFinderLock) {
|
||||
if (checked == targetChecked) {
|
||||
state = ServerFinderState.DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ServerFinderState {
|
||||
NOT_RUNNING(""),
|
||||
SEARCHING("Searching..."),
|
||||
RESOLVING("Resolving..."),
|
||||
UNKNOWN_HOST("Unknown Host!"),
|
||||
CANCELLED("Cancelled!"),
|
||||
DONE("Done!"),
|
||||
ERROR("An error occurred!");
|
||||
|
||||
private final String name;
|
||||
|
||||
ServerFinderState(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return this == SEARCHING || this == RESOLVING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package anticope.rejects.gui.servers;
|
||||
|
||||
import anticope.rejects.MeteorRejectsAddon;
|
||||
import anticope.rejects.mixin.MultiplayerScreenAccessor;
|
||||
import anticope.rejects.mixin.ServerListAccessor;
|
||||
import anticope.rejects.utils.server.IPAddress;
|
||||
import meteordevelopment.meteorclient.gui.GuiTheme;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WContainer;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import meteordevelopment.meteorclient.utils.misc.IGetter;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
import net.minecraft.client.option.ServerList;
|
||||
import net.minecraft.client.toast.SystemToast;
|
||||
import net.minecraft.text.Text;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.lwjgl.util.tinyfd.TinyFileDialogs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ServerManagerScreen extends WindowScreen {
|
||||
|
||||
private static final PointerBuffer saveFileFilters;
|
||||
|
||||
static {
|
||||
saveFileFilters = BufferUtils.createPointerBuffer(1);
|
||||
saveFileFilters.put(MemoryUtil.memASCII("*.txt"));
|
||||
saveFileFilters.rewind();
|
||||
}
|
||||
|
||||
private final MultiplayerScreen multiplayerScreen;
|
||||
|
||||
public ServerManagerScreen(GuiTheme theme, MultiplayerScreen multiplayerScreen) {
|
||||
super(theme, "Manage Servers");
|
||||
this.parent = multiplayerScreen;
|
||||
this.multiplayerScreen = multiplayerScreen;
|
||||
}
|
||||
|
||||
public static Runnable tryHandle(ThrowingRunnable<?> tr, Consumer<Throwable> handler) {
|
||||
return Objects.requireNonNull(tr).addHandler(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
WHorizontalList l = add(theme.horizontalList()).expandX().widget();
|
||||
addButton(l, "Find Servers (new)", () -> new ServerFinderScreen(theme, multiplayerScreen, this));
|
||||
addButton(l, "Find Servers (legacy)", () -> new LegacyServerFinderScreen(theme, multiplayerScreen, this));
|
||||
addButton(l, "Clean Up", () -> new CleanUpScreen(theme, multiplayerScreen, this));
|
||||
l = add(theme.horizontalList()).expandX().widget();
|
||||
l.add(theme.button("Save IPs")).expandX().widget().action = tryHandle(() -> {
|
||||
String targetPath = TinyFileDialogs.tinyfd_saveFileDialog("Save IPs", null, saveFileFilters, null);
|
||||
if (targetPath == null) return;
|
||||
if (!targetPath.endsWith(".txt")) targetPath += ".txt";
|
||||
Path filePath = Path.of(targetPath);
|
||||
|
||||
int newIPs = 0;
|
||||
|
||||
Set<IPAddress> hashedIPs = new HashSet<>();
|
||||
if (Files.exists(filePath)) {
|
||||
try {
|
||||
List<String> ips = Files.readAllLines(filePath);
|
||||
for (String ip : ips) {
|
||||
IPAddress parsedIP = IPAddress.fromText(ip);
|
||||
if (parsedIP != null)
|
||||
hashedIPs.add(parsedIP);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
ServerList servers = multiplayerScreen.getServerList();
|
||||
for (int i = 0; i < servers.size(); i++) {
|
||||
ServerInfo info = servers.get(i);
|
||||
IPAddress addr = IPAddress.fromText(info.address);
|
||||
if (addr != null && hashedIPs.add(addr))
|
||||
newIPs++;
|
||||
}
|
||||
|
||||
StringBuilder fileOutput = new StringBuilder();
|
||||
for (IPAddress ip : hashedIPs) {
|
||||
String stringIP = ip.toString();
|
||||
if (stringIP != null)
|
||||
fileOutput.append(stringIP).append("\n");
|
||||
}
|
||||
|
||||
try {
|
||||
Files.writeString(filePath, fileOutput.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
toast("Success!", newIPs == 1 ? "Saved %s new IP" : "Saved %s new IPs", newIPs);
|
||||
}, e -> {
|
||||
MeteorRejectsAddon.LOG.error("Could not save IPs");
|
||||
toast("Something went wrong", "The IPs could not be saved, look at the log for details");
|
||||
});
|
||||
l.add(theme.button("Load IPs")).expandX().widget().action = tryHandle(() -> {
|
||||
String targetPath = TinyFileDialogs.tinyfd_openFileDialog("Load IPs", null, saveFileFilters, "", false);
|
||||
if (targetPath == null) return;
|
||||
Path filePath = Path.of(targetPath);
|
||||
if (!Files.exists(filePath)) return;
|
||||
|
||||
List<ServerInfo> servers = ((ServerListAccessor) multiplayerScreen.getServerList()).getServers();
|
||||
Set<String> presentAddresses = new HashSet<>();
|
||||
int newIPs = 0;
|
||||
for (ServerInfo server : servers) presentAddresses.add(server.address);
|
||||
for (String addr : MinecraftClient.getInstance().keyboard.getClipboard().split("[\r\n]+")) {
|
||||
if (presentAddresses.add(addr = addr.split(" ")[0])) {
|
||||
servers.add(new ServerInfo("Server discovery #" + presentAddresses.size(), addr, false));
|
||||
newIPs++;
|
||||
}
|
||||
}
|
||||
multiplayerScreen.getServerList().saveFile();
|
||||
((MultiplayerScreenAccessor) multiplayerScreen).getServerListWidget().setSelected(null);
|
||||
((MultiplayerScreenAccessor) multiplayerScreen).getServerListWidget().setServers(multiplayerScreen.getServerList());
|
||||
toast("Success!", newIPs == 1 ? "Loaded %s new IP" : "Loaded %s new IPs", newIPs);
|
||||
}, e -> {
|
||||
MeteorRejectsAddon.LOG.error("Could not load IPs");
|
||||
toast("Something went wrong", "The IPs could not be loaded, look at the log for details");
|
||||
});
|
||||
}
|
||||
|
||||
private void toast(String titleKey, String descriptionKey, Object... params) {
|
||||
SystemToast.add(client.getToastManager(), SystemToast.Type.WORLD_BACKUP, Text.literal(titleKey), Text.translatable(descriptionKey, params));
|
||||
}
|
||||
|
||||
private void addButton(WContainer c, String text, IGetter<Screen> action) {
|
||||
WButton button = c.add(theme.button(text)).expandX().widget();
|
||||
button.action = () -> client.setScreen(action.get());
|
||||
}
|
||||
|
||||
public interface ThrowingRunnable<TEx extends Throwable> {
|
||||
void run() throws TEx;
|
||||
|
||||
default Runnable addHandler(Consumer<Throwable> handler) {
|
||||
Objects.requireNonNull(handler);
|
||||
return () -> {
|
||||
try {
|
||||
this.run();
|
||||
} catch (Throwable var3) {
|
||||
handler.accept(var3);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package anticope.rejects.mixin;
|
||||
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(MultiplayerScreen.class)
|
||||
public interface MultiplayerScreenAccessor {
|
||||
@Accessor("serverListWidget")
|
||||
MultiplayerServerListWidget getServerListWidget();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package anticope.rejects.mixin;
|
||||
|
||||
import anticope.rejects.gui.servers.ServerManagerScreen;
|
||||
import meteordevelopment.meteorclient.gui.GuiThemes;
|
||||
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.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MultiplayerScreen.class)
|
||||
public abstract class MultiplayerScreenMixin extends Screen {
|
||||
protected MultiplayerScreenMixin(Text title) {
|
||||
super(title);
|
||||
}
|
||||
|
||||
@Inject(method = "init", at = @At("TAIL"))
|
||||
private void onInit(CallbackInfo info) {
|
||||
addDrawableChild(new ButtonWidget(this.width - 75 - 3 - 75 - 2 - 75 - 2, 3, 75, 20, Text.literal("Servers"), button -> {
|
||||
client.setScreen(new ServerManagerScreen(GuiThemes.get(), (MultiplayerScreen) (Object) this));
|
||||
}));
|
||||
}
|
||||
}
|
||||
14
src/main/java/anticope/rejects/mixin/ServerListAccessor.java
Normal file
14
src/main/java/anticope/rejects/mixin/ServerListAccessor.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package anticope.rejects.mixin;
|
||||
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
import net.minecraft.client.option.ServerList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(ServerList.class)
|
||||
public interface ServerListAccessor {
|
||||
@Accessor
|
||||
List<ServerInfo> getServers();
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package anticope.rejects.modules;
|
||||
|
||||
import anticope.rejects.MeteorRejectsAddon;
|
||||
import meteordevelopment.meteorclient.MeteorClient;
|
||||
import meteordevelopment.meteorclient.events.world.TickEvent;
|
||||
import meteordevelopment.meteorclient.settings.BoolSetting;
|
||||
import meteordevelopment.meteorclient.settings.Setting;
|
||||
@@ -58,12 +57,6 @@ public class ExtraElytra extends Module {
|
||||
@Override
|
||||
public void onActivate() {
|
||||
jumpTimer = 0;
|
||||
MeteorClient.EVENT_BUS.subscribe(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeactivate() {
|
||||
MeteorClient.EVENT_BUS.unsubscribe(this);
|
||||
}
|
||||
|
||||
public ExtraElytra() {
|
||||
|
||||
68
src/main/java/anticope/rejects/modules/ItemGenerator.java
Normal file
68
src/main/java/anticope/rejects/modules/ItemGenerator.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package anticope.rejects.modules;
|
||||
|
||||
import anticope.rejects.MeteorRejectsAddon;
|
||||
import meteordevelopment.orbit.EventHandler;
|
||||
import meteordevelopment.meteorclient.events.world.TickEvent;
|
||||
import meteordevelopment.meteorclient.settings.IntSetting;
|
||||
import meteordevelopment.meteorclient.settings.Setting;
|
||||
import meteordevelopment.meteorclient.settings.SettingGroup;
|
||||
import meteordevelopment.meteorclient.systems.modules.Module;
|
||||
import meteordevelopment.meteorclient.utils.player.InvUtils;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryEntry;
|
||||
|
||||
public class ItemGenerator extends Module {
|
||||
private final SettingGroup sgGeneral = settings.getDefaultGroup();
|
||||
private final Setting<Integer> speed = sgGeneral.add(new IntSetting.Builder()
|
||||
.name("speed")
|
||||
.description("\u00a74\u00a7lWARNING:\u00a7r High speeds will cause a ton\n"
|
||||
+ "of lag and can easily crash the game!")
|
||||
.defaultValue(1)
|
||||
.min(1)
|
||||
.max(36)
|
||||
.sliderMax(36)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> stackSize = sgGeneral.add(new IntSetting.Builder()
|
||||
.name("stack-size")
|
||||
.description("How many items to place in each stack.\n"
|
||||
+ "Doesn't seem to affect performance.")
|
||||
.defaultValue(1)
|
||||
.min(1)
|
||||
.max(64)
|
||||
.sliderMax(64)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Random random = Random.create();
|
||||
|
||||
public ItemGenerator() {
|
||||
super(MeteorRejectsAddon.CATEGORY, "item-generator", "Spawns a lot of unwanted items");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivate() {
|
||||
if(!mc.player.getAbilities().creativeMode) {
|
||||
error("Creative mode only.");
|
||||
this.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onTick(TickEvent.Post event) {
|
||||
int stacks = speed.get();
|
||||
int size = stackSize.get();
|
||||
for(int i = 9; i < 9 + stacks; i++) {
|
||||
mc.player.networkHandler.sendPacket(new CreativeInventoryActionC2SPacket(i, new ItemStack(Registry.ITEM.getRandom(random).map(RegistryEntry::value).orElse(Items.DIRT), size)));
|
||||
}
|
||||
|
||||
for(int i = 9; i < 9 + stacks; i++) {
|
||||
InvUtils.drop().slot(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
92
src/main/java/anticope/rejects/utils/server/IPAddress.java
Normal file
92
src/main/java/anticope/rejects/utils/server/IPAddress.java
Normal file
@@ -0,0 +1,92 @@
|
||||
package anticope.rejects.utils.server;
|
||||
|
||||
public class IPAddress {
|
||||
private final int[] octets;
|
||||
private final int port;
|
||||
|
||||
public IPAddress(int o1, int o2, int o3, int o4, int port) {
|
||||
this.octets = new int[]{o1, o2, o3, o4};
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public IPAddress(int[] octets, int port) {
|
||||
this.octets = octets;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public static IPAddress fromText(String ip) {
|
||||
String[] sections = ip.split(":");
|
||||
if (sections.length < 1 || sections.length > 2)
|
||||
return null;
|
||||
|
||||
int port = 25565;
|
||||
if (sections.length == 2) {
|
||||
try {
|
||||
port = Integer.parseInt(sections[1].trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
int[] octets = new int[4];
|
||||
|
||||
String[] address = sections[0].trim().split("\\.");
|
||||
if (address.length != 4)
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
try {
|
||||
octets[i] = Integer.parseInt(address[i].trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return new IPAddress(octets, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof IPAddress other))
|
||||
return false;
|
||||
|
||||
if (octets.length != other.octets.length)
|
||||
return false;
|
||||
|
||||
if (port != other.port)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < octets.length; i++)
|
||||
if (octets[i] != other.octets[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
assert (octets.length == 4);
|
||||
|
||||
int hash = 43;
|
||||
hash = hash * 59 + octets[0];
|
||||
hash = hash * 83 + octets[1];
|
||||
hash = hash * 71 + octets[2];
|
||||
hash = hash * 17 + octets[3];
|
||||
hash = hash * 31 + port;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (octets.length == 0)
|
||||
return null;
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append(octets[0]);
|
||||
for (int i = 1; i < octets.length; i++) {
|
||||
result.append('.').append(octets[i]);
|
||||
}
|
||||
result.append(':').append(port);
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package anticope.rejects.utils.server;
|
||||
|
||||
public interface IServerFinderDisconnectListener {
|
||||
void onServerDisconnect();
|
||||
|
||||
void onServerFailed();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package anticope.rejects.utils.server;
|
||||
|
||||
public interface IServerFinderDoneListener {
|
||||
void onServerDone(ServerPinger pinger);
|
||||
|
||||
void onServerFailed(ServerPinger pinger);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package anticope.rejects.utils.server;
|
||||
|
||||
import anticope.rejects.MeteorRejectsAddon;
|
||||
import net.minecraft.client.network.MultiplayerServerListPinger;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class LegacyServerPinger {
|
||||
private static final AtomicInteger threadNumber = new AtomicInteger(0);
|
||||
private ServerInfo server;
|
||||
private boolean done = false;
|
||||
private boolean failed = false;
|
||||
|
||||
public void ping(String ip) {
|
||||
ping(ip, 25565);
|
||||
}
|
||||
|
||||
public void ping(String ip, int port) {
|
||||
server = new ServerInfo("", ip + ":" + port, false);
|
||||
|
||||
new Thread(() -> pingInCurrentThread(ip, port),
|
||||
"Server Pinger #" + threadNumber.incrementAndGet()).start();
|
||||
}
|
||||
|
||||
private void pingInCurrentThread(String ip, int port) {
|
||||
MultiplayerServerListPinger pinger = new MultiplayerServerListPinger();
|
||||
MeteorRejectsAddon.LOG.info("Pinging " + ip + ":" + port + "...");
|
||||
|
||||
try {
|
||||
pinger.add(server, () -> {
|
||||
});
|
||||
MeteorRejectsAddon.LOG.info("Ping successful: " + ip + ":" + port);
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
MeteorRejectsAddon.LOG.warn("Unknown host: " + ip + ":" + port);
|
||||
failed = true;
|
||||
|
||||
} catch (Exception e2) {
|
||||
MeteorRejectsAddon.LOG.warn("Ping failed: " + ip + ":" + port);
|
||||
failed = true;
|
||||
}
|
||||
|
||||
pinger.cancel();
|
||||
done = true;
|
||||
}
|
||||
|
||||
public boolean isStillPinging() {
|
||||
return !done;
|
||||
}
|
||||
|
||||
public boolean isWorking() {
|
||||
return !failed;
|
||||
}
|
||||
|
||||
public String getServerIP() {
|
||||
return server.address;
|
||||
}
|
||||
}
|
||||
37
src/main/java/anticope/rejects/utils/server/MServerInfo.java
Normal file
37
src/main/java/anticope/rejects/utils/server/MServerInfo.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package anticope.rejects.utils.server;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.text.Text;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MServerInfo {
|
||||
public String name;
|
||||
public String address;
|
||||
public String playerCountLabel;
|
||||
public int playerCount;
|
||||
public int playercountMax;
|
||||
public String label;
|
||||
public long ping;
|
||||
public int protocolVersion = SharedConstants.getGameVersion().getProtocolVersion();
|
||||
public String version = null;
|
||||
public List<Text> playerListSummary = Collections.emptyList();
|
||||
@Nullable
|
||||
private String icon;
|
||||
|
||||
public MServerInfo(String name, String address) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getIcon() {
|
||||
return this.icon;
|
||||
}
|
||||
|
||||
public void setIcon(@Nullable String string) {
|
||||
this.icon = string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
package anticope.rejects.utils.server;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import net.minecraft.client.network.ServerAddress;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.listener.ClientQueryPacketListener;
|
||||
import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.query.QueryPingC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.query.QueryRequestC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.query.QueryPongS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.query.QueryResponseS2CPacket;
|
||||
import net.minecraft.server.ServerMetadata;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class ServerListPinger {
|
||||
private static final Splitter ZERO_SPLITTER = Splitter.on('\u0000').limit(6);
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final List<ClientConnection> clientConnections = Collections.synchronizedList(Lists.newArrayList());
|
||||
private final ArrayList<IServerFinderDisconnectListener> disconnectListeners = new ArrayList<>();
|
||||
private boolean notifiedDisconnectListeners = false;
|
||||
private boolean failedToConnect = true;
|
||||
|
||||
private static String getPlayerCountLabel(int i, int j) {
|
||||
return i + "/" + j;
|
||||
}
|
||||
|
||||
public void addServerFinderDisconnectListener(IServerFinderDisconnectListener listener) {
|
||||
disconnectListeners.add(listener);
|
||||
}
|
||||
|
||||
private void notifyDisconnectListeners() {
|
||||
synchronized (this) {
|
||||
if (!notifiedDisconnectListeners) {
|
||||
notifiedDisconnectListeners = true;
|
||||
for (IServerFinderDisconnectListener l : disconnectListeners) {
|
||||
if (l != null) {
|
||||
if (failedToConnect) {
|
||||
l.onServerFailed();
|
||||
} else {
|
||||
l.onServerDisconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void add(final MServerInfo entry, final Runnable runnable) throws UnknownHostException {
|
||||
Timer timeoutTimer = new Timer();
|
||||
ServerAddress serverAddress = ServerAddress.parse(entry.address);
|
||||
timeoutTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
notifyDisconnectListeners();
|
||||
}
|
||||
}, 20000);
|
||||
final ClientConnection clientConnection = ClientConnection.connect(new InetSocketAddress(InetAddress.getByName(serverAddress.getAddress()), serverAddress.getPort()), false);
|
||||
failedToConnect = false;
|
||||
this.clientConnections.add(clientConnection);
|
||||
entry.label = "multiplayer.status.pinging";
|
||||
entry.ping = -1L;
|
||||
entry.playerListSummary = null;
|
||||
clientConnection.setPacketListener(new ClientQueryPacketListener() {
|
||||
private boolean sentQuery;
|
||||
private boolean received;
|
||||
private long startTime;
|
||||
|
||||
public void onResponse(QueryResponseS2CPacket packet) {
|
||||
if (this.received) {
|
||||
clientConnection.disconnect(Text.translatable("multiplayer.status.unrequested"));
|
||||
} else {
|
||||
this.received = true;
|
||||
ServerMetadata serverMetadata = packet.getServerMetadata();
|
||||
if (serverMetadata.getDescription() != null) {
|
||||
entry.label = serverMetadata.getDescription().getString();
|
||||
} else {
|
||||
entry.label = "";
|
||||
}
|
||||
|
||||
if (serverMetadata.getVersion() != null) {
|
||||
entry.version = serverMetadata.getVersion().getGameVersion();
|
||||
entry.protocolVersion = serverMetadata.getVersion().getProtocolVersion();
|
||||
} else {
|
||||
entry.version = "multiplayer.status.old";
|
||||
entry.protocolVersion = 0;
|
||||
}
|
||||
|
||||
if (serverMetadata.getPlayers() != null) {
|
||||
entry.playerCountLabel = ServerListPinger.getPlayerCountLabel(serverMetadata.getPlayers().getOnlinePlayerCount(), serverMetadata.getPlayers().getPlayerLimit());
|
||||
entry.playerCount = serverMetadata.getPlayers().getOnlinePlayerCount();
|
||||
entry.playercountMax = serverMetadata.getPlayers().getPlayerLimit();
|
||||
List<Text> list = Lists.newArrayList();
|
||||
if (ArrayUtils.isNotEmpty(serverMetadata.getPlayers().getSample())) {
|
||||
GameProfile[] var4 = serverMetadata.getPlayers().getSample();
|
||||
|
||||
for (GameProfile gameProfile : var4) {
|
||||
list.add(Text.literal(gameProfile.getName()));
|
||||
}
|
||||
|
||||
if (serverMetadata.getPlayers().getSample().length < serverMetadata.getPlayers().getOnlinePlayerCount()) {
|
||||
list.add(Text.translatable("multiplayer.status.and_more", serverMetadata.getPlayers().getOnlinePlayerCount() - serverMetadata.getPlayers().getSample().length));
|
||||
}
|
||||
|
||||
entry.playerListSummary = list;
|
||||
}
|
||||
} else {
|
||||
entry.playerCountLabel = "multiplayer.status.unknown";
|
||||
}
|
||||
|
||||
String string = null;
|
||||
if (serverMetadata.getFavicon() != null) {
|
||||
String string2 = serverMetadata.getFavicon();
|
||||
if (string2.startsWith("data:image/png;base64,")) {
|
||||
string = string2.substring("data:image/png;base64," .length());
|
||||
} else {
|
||||
ServerListPinger.LOGGER.error("Invalid server icon (unknown format)");
|
||||
}
|
||||
}
|
||||
|
||||
if (!Objects.equals(string, entry.getIcon())) {
|
||||
entry.setIcon(string);
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
this.startTime = Util.getMeasuringTimeMs();
|
||||
clientConnection.send(new QueryPingC2SPacket(this.startTime));
|
||||
this.sentQuery = true;
|
||||
notifyDisconnectListeners();
|
||||
}
|
||||
}
|
||||
|
||||
public void onPong(QueryPongS2CPacket packet) {
|
||||
long l = this.startTime;
|
||||
long m = Util.getMeasuringTimeMs();
|
||||
entry.ping = m - l;
|
||||
clientConnection.disconnect(Text.translatable("multiplayer.status.finished"));
|
||||
}
|
||||
|
||||
public void onDisconnected(Text reason) {
|
||||
if (!this.sentQuery) {
|
||||
ServerListPinger.LOGGER.error("Can't ping {}: {}", entry.address, reason.getString());
|
||||
entry.label = "multiplayer.status.cannot_connect";
|
||||
entry.playerCountLabel = "";
|
||||
entry.playerCount = 0;
|
||||
entry.playercountMax = 0;
|
||||
ServerListPinger.this.ping(entry);
|
||||
}
|
||||
notifyDisconnectListeners();
|
||||
}
|
||||
|
||||
public ClientConnection getConnection() {
|
||||
return clientConnection;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
clientConnection.send(new HandshakeC2SPacket(serverAddress.getAddress(), serverAddress.getPort(), NetworkState.STATUS));
|
||||
clientConnection.send(new QueryRequestC2SPacket());
|
||||
} catch (Throwable var6) {
|
||||
LOGGER.error("Couldn't send handshake", var6);
|
||||
}
|
||||
}
|
||||
|
||||
private void ping(final MServerInfo serverInfo) {
|
||||
final ServerAddress serverAddress = ServerAddress.parse(serverInfo.address);
|
||||
(new Bootstrap()).group(ClientConnection.CLIENT_IO_GROUP.get()).handler(new ChannelInitializer<>() {
|
||||
protected void initChannel(Channel channel) {
|
||||
try {
|
||||
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||
} catch (ChannelException var3) {
|
||||
}
|
||||
|
||||
channel.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
|
||||
public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
|
||||
super.channelActive(channelHandlerContext);
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
|
||||
try {
|
||||
byteBuf.writeByte(254);
|
||||
byteBuf.writeByte(1);
|
||||
byteBuf.writeByte(250);
|
||||
char[] cs = "MC|PingHost" .toCharArray();
|
||||
byteBuf.writeShort(cs.length);
|
||||
char[] var4 = cs;
|
||||
int var5 = cs.length;
|
||||
|
||||
int var6;
|
||||
char d;
|
||||
for (var6 = 0; var6 < var5; ++var6) {
|
||||
d = var4[var6];
|
||||
byteBuf.writeChar(d);
|
||||
}
|
||||
|
||||
byteBuf.writeShort(7 + 2 * serverAddress.getAddress().length());
|
||||
byteBuf.writeByte(127);
|
||||
cs = serverAddress.getAddress().toCharArray();
|
||||
byteBuf.writeShort(cs.length);
|
||||
var4 = cs;
|
||||
var5 = cs.length;
|
||||
|
||||
for (var6 = 0; var6 < var5; ++var6) {
|
||||
d = var4[var6];
|
||||
byteBuf.writeChar(d);
|
||||
}
|
||||
|
||||
byteBuf.writeInt(serverAddress.getPort());
|
||||
channelHandlerContext.channel().writeAndFlush(byteBuf).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
|
||||
} finally {
|
||||
byteBuf.release();
|
||||
}
|
||||
}
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) {
|
||||
short s = byteBuf.readUnsignedByte();
|
||||
if (s == 255) {
|
||||
String string = new String(byteBuf.readBytes(byteBuf.readShort() * 2).array(), StandardCharsets.UTF_16BE);
|
||||
String[] strings = Iterables.toArray(ServerListPinger.ZERO_SPLITTER.split(string), String.class);
|
||||
if ("§1" .equals(strings[0])) {
|
||||
String string2 = strings[2];
|
||||
String string3 = strings[3];
|
||||
int j = MathHelper.parseInt(strings[4], -1);
|
||||
int k = MathHelper.parseInt(strings[5], -1);
|
||||
serverInfo.protocolVersion = -1;
|
||||
serverInfo.version = string2;
|
||||
serverInfo.label = string3;
|
||||
serverInfo.playerCountLabel = ServerListPinger.getPlayerCountLabel(j, k);
|
||||
}
|
||||
}
|
||||
|
||||
channelHandlerContext.close();
|
||||
}
|
||||
|
||||
public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) {
|
||||
channelHandlerContext.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).channel(NioSocketChannel.class).connect(serverAddress.getAddress(), serverAddress.getPort());
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
synchronized (this.clientConnections) {
|
||||
Iterator<ClientConnection> iterator = this.clientConnections.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ClientConnection clientConnection = iterator.next();
|
||||
if (clientConnection.isOpen()) {
|
||||
clientConnection.tick();
|
||||
} else {
|
||||
iterator.remove();
|
||||
clientConnection.handleDisconnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
synchronized (this.clientConnections) {
|
||||
Iterator<ClientConnection> iterator = this.clientConnections.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ClientConnection clientConnection = iterator.next();
|
||||
if (clientConnection.isOpen()) {
|
||||
iterator.remove();
|
||||
clientConnection.disconnect(Text.translatable("multiplayer.status.cancelled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
213
src/main/java/anticope/rejects/utils/server/ServerPinger.java
Normal file
213
src/main/java/anticope/rejects/utils/server/ServerPinger.java
Normal file
@@ -0,0 +1,213 @@
|
||||
package anticope.rejects.utils.server;
|
||||
|
||||
import anticope.rejects.gui.servers.ServerFinderScreen;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class ServerPinger implements IServerFinderDoneListener, IServerFinderDisconnectListener {
|
||||
private static final AtomicInteger threadNumber = new AtomicInteger(0);
|
||||
private final Object portPingerLock = new Object();
|
||||
private MServerInfo server;
|
||||
private boolean done = false;
|
||||
private boolean failed = false;
|
||||
private Thread thread;
|
||||
private int pingPort;
|
||||
private ServerListPinger pinger;
|
||||
private boolean notifiedDoneListeners = false;
|
||||
private boolean scanPorts;
|
||||
private int searchNumber;
|
||||
private int currentIncrement = 1;
|
||||
private boolean startingIncrement = true;
|
||||
private ArrayList<IServerFinderDoneListener> doneListeners = new ArrayList<>();
|
||||
private int portPingers = 0;
|
||||
private int successfulPortPingers = 0;
|
||||
private String pingIP;
|
||||
|
||||
public ServerPinger(boolean scanPorts, int searchNumber) {
|
||||
pinger = new ServerListPinger();
|
||||
pinger.addServerFinderDisconnectListener(this);
|
||||
this.scanPorts = scanPorts;
|
||||
this.searchNumber = searchNumber;
|
||||
}
|
||||
|
||||
public void addServerFinderDoneListener(IServerFinderDoneListener listener) {
|
||||
doneListeners.add(listener);
|
||||
}
|
||||
|
||||
public void ping(String ip) {
|
||||
ping(ip, 25565);
|
||||
}
|
||||
|
||||
public int getSearchNumber() {
|
||||
return searchNumber;
|
||||
}
|
||||
|
||||
public Thread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
public int getPingPort() {
|
||||
return pingPort;
|
||||
}
|
||||
|
||||
public MServerInfo getServerInfo() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void ping(String ip, int port) {
|
||||
if (isOldSearch())
|
||||
return;
|
||||
|
||||
pingIP = ip;
|
||||
pingPort = port;
|
||||
server = new MServerInfo("", ip + ":" + port);
|
||||
server.version = null;
|
||||
|
||||
if (scanPorts) {
|
||||
thread = new Thread(() -> pingInCurrentThread(ip, port),
|
||||
"Server Pinger #" + threadNumber.incrementAndGet());
|
||||
} else {
|
||||
thread = new Thread(() -> pingInCurrentThread(ip, port),
|
||||
"Server Pinger #" + threadNumber + ", " + port);
|
||||
}
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public ServerListPinger getServerListPinger() {
|
||||
return pinger;
|
||||
}
|
||||
|
||||
private boolean isOldSearch() {
|
||||
return ServerFinderScreen.instance == null || ServerFinderScreen.instance.getState() == ServerFinderScreen.ServerFinderState.CANCELLED || ServerFinderScreen.getSearchNumber() != searchNumber;
|
||||
}
|
||||
|
||||
private void runPortIncrement(String ip) {
|
||||
synchronized (portPingerLock) {
|
||||
portPingers = 0;
|
||||
successfulPortPingers = 0;
|
||||
}
|
||||
for (int i = startingIncrement ? 1 : currentIncrement; i < currentIncrement * 2; i++) {
|
||||
if (isOldSearch())
|
||||
return;
|
||||
ServerPinger pp1 = new ServerPinger(false, searchNumber);
|
||||
ServerPinger pp2 = new ServerPinger(false, searchNumber);
|
||||
for (IServerFinderDoneListener doneListener : doneListeners) {
|
||||
pp1.addServerFinderDoneListener(doneListener);
|
||||
pp2.addServerFinderDoneListener(doneListener);
|
||||
}
|
||||
pp1.addServerFinderDoneListener(this);
|
||||
pp2.addServerFinderDoneListener(this);
|
||||
if (ServerFinderScreen.instance != null && !isOldSearch()) {
|
||||
ServerFinderScreen.instance.incrementTargetChecked(2);
|
||||
}
|
||||
pp1.ping(ip, 25565 - i);
|
||||
pp2.ping(ip, 25565 + i);
|
||||
}
|
||||
synchronized (portPingerLock) {
|
||||
currentIncrement *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void pingInCurrentThread(String ip, int port) {
|
||||
if (isOldSearch())
|
||||
return;
|
||||
|
||||
|
||||
try {
|
||||
pinger.add(server, () -> {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
startingIncrement = true;
|
||||
if (!failed) {
|
||||
currentIncrement = 8;
|
||||
}
|
||||
|
||||
if (!failed && scanPorts) {
|
||||
runPortIncrement(ip);
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
pinger.cancel();
|
||||
done = true;
|
||||
notifyDoneListeners(false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStillPinging() {
|
||||
return !done;
|
||||
}
|
||||
|
||||
public boolean isWorking() {
|
||||
return !failed;
|
||||
}
|
||||
|
||||
public boolean isOtherVersion() {
|
||||
return server.protocolVersion != 47;
|
||||
}
|
||||
|
||||
public String getServerIP() {
|
||||
return server.address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerDisconnect() {
|
||||
if (isOldSearch())
|
||||
return;
|
||||
|
||||
pinger.cancel();
|
||||
done = true;
|
||||
notifyDoneListeners(false);
|
||||
}
|
||||
|
||||
private void notifyDoneListeners(boolean failure) {
|
||||
synchronized (this) {
|
||||
if (!notifiedDoneListeners) {
|
||||
notifiedDoneListeners = true;
|
||||
for (IServerFinderDoneListener doneListener : doneListeners) {
|
||||
if (doneListener != null) {
|
||||
if (failure) {
|
||||
doneListener.onServerFailed(this);
|
||||
} else {
|
||||
doneListener.onServerDone(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerFailed() {
|
||||
if (isOldSearch())
|
||||
return;
|
||||
|
||||
pinger.cancel();
|
||||
done = true;
|
||||
notifyDoneListeners(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerDone(ServerPinger pinger) {
|
||||
synchronized (portPingerLock) {
|
||||
portPingers += 1;
|
||||
if (pinger.isWorking())
|
||||
successfulPortPingers += 1;
|
||||
if (portPingers == (startingIncrement ? currentIncrement * 2 - 2 : currentIncrement) && currentIncrement <= 5000 && successfulPortPingers > 0) {
|
||||
startingIncrement = false;
|
||||
new Thread(() -> runPortIncrement(pingIP)).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerFailed(ServerPinger pinger) {
|
||||
synchronized (portPingerLock) {
|
||||
portPingers += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,10 @@
|
||||
"StructureVoidBlockMixin",
|
||||
"ToastManagerMixin",
|
||||
"LivingEntityMixin",
|
||||
"baritone.MineProcessMixin"
|
||||
"baritone.MineProcessMixin",
|
||||
"MultiplayerScreenAccessor",
|
||||
"MultiplayerScreenMixin",
|
||||
"ServerListAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
||||
Reference in New Issue
Block a user