Gamemode Notifier and Anti Vanish more modes (#211)

closes https://github.com/AntiCope/meteor-rejects/issues/203
This commit is contained in:
Soda5601
2023-01-24 23:49:55 +08:00
committed by GitHub
parent db004341cd
commit e8905d671a
7 changed files with 305 additions and 95 deletions

View File

@@ -56,6 +56,7 @@
- Coord Logger (World events from [JexClient](https://github.com/DustinRepo/JexClient-main/blob/main/src/main/java/me/dustin/jex/feature/mod/impl/misc/CoordFinder.java)) - Coord Logger (World events from [JexClient](https://github.com/DustinRepo/JexClient-main/blob/main/src/main/java/me/dustin/jex/feature/mod/impl/misc/CoordFinder.java))
- Custom Packets - Custom Packets
- Extra Elytra (Ported from [Wurst](https://github.com/Wurst-Imperium/Wurst7/tree)) - Extra Elytra (Ported from [Wurst](https://github.com/Wurst-Imperium/Wurst7/tree))
- Gamemode notifier
- Ghost Mode (Taken from an [unmerged PR](https://github.com/MeteorDevelopment/meteor-client/pull/1932)) - Ghost Mode (Taken from an [unmerged PR](https://github.com/MeteorDevelopment/meteor-client/pull/1932))
- Glide (Ported from [Wurst](https://github.com/Wurst-Imperium/Wurst7/tree)) - Glide (Ported from [Wurst](https://github.com/Wurst-Imperium/Wurst7/tree))
- Insta Mine (Removed from Meteor in [62cd0](https://github.com/MeteorDevelopment/meteor-client/commit/62cd0461e48a6c50f040bf48de25be1fa4eba77e)) - Insta Mine (Removed from Meteor in [62cd0](https://github.com/MeteorDevelopment/meteor-client/commit/62cd0461e48a6c50f040bf48de25be1fa4eba77e))

View File

@@ -58,6 +58,7 @@ public class MeteorRejectsAddon extends MeteorAddon {
modules.add(new CoordLogger()); modules.add(new CoordLogger());
modules.add(new CustomPackets()); modules.add(new CustomPackets());
modules.add(new ExtraElytra()); modules.add(new ExtraElytra());
modules.add(new GamemodeNotifier());
modules.add(new GhostMode()); modules.add(new GhostMode());
modules.add(new Glide()); modules.add(new Glide());
modules.add(new InstaMine()); modules.add(new InstaMine());

View File

@@ -1,127 +1,146 @@
package anticope.rejects.modules; package anticope.rejects.modules;
import anticope.rejects.MeteorRejectsAddon; import anticope.rejects.MeteorRejectsAddon;
import com.google.gson.JsonArray; import com.mojang.brigadier.suggestion.Suggestion;
import meteordevelopment.orbit.EventHandler; import meteordevelopment.meteorclient.events.game.ReceiveMessageEvent;
import meteordevelopment.meteorclient.events.game.GameLeftEvent;
import meteordevelopment.meteorclient.events.packets.PacketEvent; import meteordevelopment.meteorclient.events.packets.PacketEvent;
import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.events.world.TickEvent;
import meteordevelopment.meteorclient.gui.GuiTheme;
import meteordevelopment.meteorclient.gui.widgets.WWidget;
import meteordevelopment.meteorclient.gui.widgets.containers.WVerticalList;
import meteordevelopment.meteorclient.settings.*;
import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.systems.modules.Module;
import meteordevelopment.meteorclient.utils.network.Http; import meteordevelopment.orbit.EventHandler;
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
import net.minecraft.network.packet.s2c.play.CommandSuggestionsS2CPacket;
import net.minecraft.client.MinecraftClient; import java.util.*;
import net.minecraft.entity.player.PlayerEntity; import java.util.function.Predicate;
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import java.util.stream.Collectors;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
public class AntiVanish extends Module { public class AntiVanish extends Module {
private final SettingGroup sgGeneral = settings.getDefaultGroup();
private final Queue<UUID> toLookup = new ConcurrentLinkedQueue<UUID>();
private long lastTick = 0; private final Setting<Integer> interval = sgGeneral.add(new IntSetting.Builder()
.name("interval")
.description("Vanish check interval.")
.defaultValue(100)
.min(0)
.sliderMax(300)
.build()
);
private final Setting<Mode> mode = sgGeneral.add(new EnumSetting.Builder<Mode>()
.name("mode")
.defaultValue(Mode.LeaveMessage)
.build()
);
private final Setting<String> command = sgGeneral.add(new StringSetting.Builder()
.name("command")
.description("The completion command.")
.defaultValue("minecraft:msg")
.visible(() -> mode.get() == Mode.RealJoinMessage)
.build()
);
private Map<UUID, String> playerCache = new HashMap<>();
private final List<String> messageCache = new ArrayList<>();
private final Random random = new Random();
private final List<Integer> completionIDs = new ArrayList<>();
private List<String> completionPlayerCache = new ArrayList<>();
private int timer = 0;
public AntiVanish() { public AntiVanish() {
super(MeteorRejectsAddon.CATEGORY, "anti-vanish", "Notifies user when a admin uses /vanish"); super(MeteorRejectsAddon.CATEGORY, "anti-vanish", "Notifies user when a admin uses /vanish");
} }
@Override @Override
public void onDeactivate() { public void onActivate() {
toLookup.clear(); timer = 0;
completionIDs.clear();
messageCache.clear();
} }
@EventHandler
public void onLeave(GameLeftEvent event) { @Override
toLookup.clear(); public WWidget getWidget(GuiTheme theme) {
WVerticalList l = theme.verticalList();
l.add(theme.label("LeaveMessage: If client didn't receive a quit game message (like essentials)."));
l.add(theme.label("RealJoinMessage: Tell whether the player is really left."));
return l;
} }
@EventHandler @EventHandler
public void onPacket(PacketEvent.Receive event) { private void onPacket(PacketEvent.Receive event) {
if (event.packet instanceof PlayerListS2CPacket packet) { if (mode.get() == Mode.RealJoinMessage && event.packet instanceof CommandSuggestionsS2CPacket packet) {
if (packet.getActions().contains(PlayerListS2CPacket.Action.UPDATE_LATENCY)) { if (completionIDs.contains(packet.getCompletionId())) {
try { var lastUsernames = completionPlayerCache.stream().toList();
for (PlayerListS2CPacket.Entry entry : packet.getEntries()) {
if (mc.getNetworkHandler().getPlayerListEntry(entry.profileId()) != null) completionPlayerCache = packet.getSuggestions().getList().stream()
continue; .map(Suggestion::getText)
toLookup.add(entry.profileId()); .toList();
if (lastUsernames.isEmpty()) return;
Predicate<String> joinedOrQuit = playerName -> lastUsernames.contains(playerName) != completionPlayerCache.contains(playerName);
for (String playerName : completionPlayerCache) {
if (Objects.equals(playerName, mc.player.getName().getString())) continue;
if (joinedOrQuit.test(playerName)) {
info("Player joined: " + playerName);
} }
} catch (Exception ignore) {} }
for (String playerName : lastUsernames) {
if (Objects.equals(playerName, mc.player.getName().getString())) continue;
if (joinedOrQuit.test(playerName)) {
info("Player left: " + playerName);
}
}
completionIDs.remove(Integer.valueOf(packet.getCompletionId()));
event.cancel();
} }
} }
} }
@EventHandler @EventHandler
public void onTick(TickEvent.Post event) { private void onReceiveMessage(ReceiveMessageEvent event) {
long time = mc.world.getTime(); messageCache.add(event.getMessage().getString());
UUID lookup;
if (Math.abs(lastTick - time) > 100 && (lookup = toLookup.poll()) != null) {
try {
String name = getPlayerNameFromUUID(lookup);
if (name != null) {
warning(name + " has gone into vanish.");
}
} catch (Exception ignore) {}
lastTick = time;
}
} }
public String getPlayerNameFromUUID(UUID id) { @EventHandler
try { private void onTick(TickEvent.Post event) {
final NameLookup process = new NameLookup(id, mc); timer++;
final Thread thread = new Thread(process); if (timer < interval.get()) return;
thread.start();
thread.join();
return process.getName();
} catch (Exception ignored) {
return null;
}
}
public static class NameLookup implements Runnable { switch (mode.get()) {
private final String uuidstr; case LeaveMessage -> {
private final UUID uuid; Map<UUID, String> oldPlayers = Map.copyOf(playerCache);
private final MinecraftClient mc; playerCache = mc.getNetworkHandler().getPlayerList().stream().collect(Collectors.toMap(e -> e.getProfile().getId(), e -> e.getProfile().getName()));
private volatile String name;
public NameLookup(final String input, MinecraftClient mc) { for (UUID uuid : oldPlayers.keySet()) {
this.uuidstr = input; if (playerCache.containsKey(uuid)) continue;
this.uuid = UUID.fromString(input); String name = oldPlayers.get(uuid);
this.mc = mc; if (messageCache.stream().noneMatch(s -> s.contains(name))) {
} warning(name + " has gone into vanish.");
}
public NameLookup(final UUID input, MinecraftClient mc) {
this.uuid = input;
this.uuidstr = input.toString();
this.mc = mc;
}
@Override
public void run() {
name = this.lookUpName();
}
public String lookUpName() {
PlayerEntity player = null;
if (mc.world != null) {
player = mc.world.getPlayerByUuid(uuid);
}
if (player == null) {
final String url = "https://api.mojang.com/user/profiles/" + uuidstr.replace("-", "") + "/names";
try {
JsonArray res = Http.get(url).sendJson(JsonArray.class);
return res.get(res.size() - 1).getAsJsonObject().get("name").getAsString();
} catch (Exception e) {
return uuidstr;
} }
} }
return player.getName().getString(); case RealJoinMessage -> {
} int id = random.nextInt(200);
completionIDs.add(id);
public String getName() { mc.getNetworkHandler().sendPacket(new RequestCommandCompletionsC2SPacket(id, command.get() + " "));
return this.name; }
} }
timer = 0;
messageCache.clear();
} }
}
public enum Mode {
LeaveMessage,
RealJoinMessage//https://github.com/xtrm-en/meteor-antistaff/blob/main/src/main/java/me/xtrm/meteorclient/antistaff/modules/AntiStaff.java
}
}

View File

@@ -0,0 +1,45 @@
package anticope.rejects.modules;
import anticope.rejects.MeteorRejectsAddon;
import anticope.rejects.settings.GameModeListSetting;
import meteordevelopment.meteorclient.events.packets.PacketEvent;
import meteordevelopment.meteorclient.settings.Setting;
import meteordevelopment.meteorclient.settings.SettingGroup;
import meteordevelopment.meteorclient.systems.modules.Module;
import meteordevelopment.orbit.EventHandler;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
import net.minecraft.world.GameMode;
import java.util.List;
public class GamemodeNotifier extends Module {
private final SettingGroup sgGeneral = settings.getDefaultGroup();
private final Setting<List<GameMode>> gamemodes = sgGeneral.add(new GameModeListSetting.Builder()
.name("gamemode")
.description("Which gamemodes to notify.")
.build()
);
public GamemodeNotifier() {
super(MeteorRejectsAddon.CATEGORY, "gamemode-notifier", "Notifies user a player's gamemode was changed.");
}
@EventHandler
public void onPacket(PacketEvent.Receive event) {
if (event.packet instanceof PlayerListS2CPacket packet) {
for (PlayerListS2CPacket.Entry entry : packet.getEntries()) {
if (!packet.getActions().contains(PlayerListS2CPacket.Action.UPDATE_GAME_MODE)) continue;
PlayerListEntry entry1 = mc.getNetworkHandler().getPlayerListEntry(entry.profileId());
if (entry1 == null) continue;
GameMode gameMode = entry.gameMode();
if (entry1.getGameMode() != gameMode) {
if (!gamemodes.get().contains(gameMode)) continue;
info("Player %s changed gamemode to %s", entry1.getProfile().getName(), entry.gameMode());
}
}
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/
package anticope.rejects.settings;
import meteordevelopment.meteorclient.settings.IVisible;
import meteordevelopment.meteorclient.settings.Setting;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtString;
import net.minecraft.world.GameMode;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class GameModeListSetting extends Setting<List<GameMode>> {
public GameModeListSetting(String name, String description, List<GameMode> defaultValue, Consumer<List<GameMode>> onChanged, Consumer<Setting<List<GameMode>>> onModuleActivated, IVisible visible) {
super(name, description, defaultValue, onChanged, onModuleActivated, visible);
}
@Override
protected List<GameMode> parseImpl(String str) {
String[] values = str.split(",");
List<GameMode> modes = new ArrayList<>(values.length);
for (String s : values) {
GameMode mode = GameMode.byName(s);
if (mode != null) modes.add(mode);
}
return modes;
}
@Override
protected boolean isValueValid(List<GameMode> value) {
return true;
}
@Override
protected void resetImpl() {
value = new ArrayList<>();
}
@Override
public NbtCompound save(NbtCompound tag) {
NbtList valueTag = new NbtList();
for (GameMode mode : get()) {
valueTag.add(NbtString.of(mode.getName()));
}
tag.put("value", valueTag);
return tag;
}
@Override
public List<GameMode> load(NbtCompound tag) {
get().clear();
NbtList valueTag = tag.getList("value", 8);
for (NbtElement tagI : valueTag) {
GameMode mode = GameMode.byName(tagI.asString());
if (mode != null)
get().add(mode);
}
return get();
}
public static class Builder extends SettingBuilder<Builder, List<GameMode>, GameModeListSetting> {
public Builder() {
super(new ArrayList<>(0));
}
public Builder defaultValue(List<GameMode> map) {
this.defaultValue = map;
return this;
}
@Override
public GameModeListSetting build() {
return new GameModeListSetting(name, description, defaultValue, onChanged, onModuleActivated, visible);
}
}
}

View File

@@ -0,0 +1,41 @@
package anticope.rejects.settings;
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.Utils;
import net.minecraft.world.GameMode;
import java.util.List;
public class GameModeListSettingScreen extends WindowScreen {
private final GameModeListSetting setting;
private final WTable table;
public GameModeListSettingScreen(GuiTheme theme, GameModeListSetting setting) {
super(theme, "Select Gamemodes");
this.setting = setting;
table = super.add(theme.table()).expandX().widget();
}
@Override
public void initWidgets() {
List<GameMode> gms = setting.get();
for (GameMode gameMode : GameMode.values()) {
table.add(theme.label(Utils.nameToTitle(gameMode.getName()))).expandCellX();
boolean contains = setting.get().contains(gameMode);
WCheckbox checkbox = table.add(theme.checkbox(contains)).widget();
checkbox.action = () -> {
if (contains) {
gms.remove(gameMode);
} else {
gms.add(gameMode);
}
};
table.row();
}
}
}

View File

@@ -1,11 +1,19 @@
package anticope.rejects.settings; package anticope.rejects.settings;
import meteordevelopment.meteorclient.gui.DefaultSettingsWidgetFactory;
import meteordevelopment.meteorclient.gui.GuiTheme; import meteordevelopment.meteorclient.gui.GuiTheme;
import meteordevelopment.meteorclient.gui.renderer.GuiRenderer;
import meteordevelopment.meteorclient.gui.screens.settings.EntityTypeListSettingScreen;
import meteordevelopment.meteorclient.gui.utils.SettingsWidgetFactory; import meteordevelopment.meteorclient.gui.utils.SettingsWidgetFactory;
import meteordevelopment.meteorclient.gui.widgets.containers.WContainer;
import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList;
import meteordevelopment.meteorclient.gui.widgets.containers.WTable; import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
import java.util.Map; import java.util.Map;
import static meteordevelopment.meteorclient.MeteorClient.mc;
public class RejectsSettings { public class RejectsSettings {
private final Map<Class<?>, SettingsWidgetFactory.Factory> factories; private final Map<Class<?>, SettingsWidgetFactory.Factory> factories;
@@ -18,10 +26,19 @@ public class RejectsSettings {
public void addSettings() { public void addSettings() {
factories.put(StringMapSetting.class, (table, setting) -> stringMapW(table, (StringMapSetting) setting)); factories.put(StringMapSetting.class, (table, setting) -> stringMapW(table, (StringMapSetting) setting));
factories.put(GameModeListSetting.class, (table, setting) -> gameModeListW(table, (GameModeListSetting) setting));
} }
private void stringMapW(WTable table, StringMapSetting setting) { private void stringMapW(WTable table, StringMapSetting setting) {
WTable wtable = table.add(theme.table()).expandX().widget(); WTable wtable = table.add(theme.table()).expandX().widget();
StringMapSetting.fillTable(theme, wtable, setting); StringMapSetting.fillTable(theme, wtable, setting);
} }
private void gameModeListW(WTable table, GameModeListSetting setting) {
WButton button = table.add(theme.button("Select")).expandCellX().widget();
button.action = () -> mc.setScreen(new GameModeListSettingScreen(theme, setting));
WButton reset = table.add(theme.button(GuiRenderer.RESET)).widget();
reset.action = setting::reset;
}
} }