mirror of
https://github.com/AntiCope/meteor-rejects.git
synced 2025-09-06 12:25:49 +00:00
Gamemode Notifier and Anti Vanish more modes (#211)
closes https://github.com/AntiCope/meteor-rejects/issues/203
This commit is contained in:
@@ -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))
|
||||
- Custom Packets
|
||||
- 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))
|
||||
- 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))
|
||||
|
@@ -58,6 +58,7 @@ public class MeteorRejectsAddon extends MeteorAddon {
|
||||
modules.add(new CoordLogger());
|
||||
modules.add(new CustomPackets());
|
||||
modules.add(new ExtraElytra());
|
||||
modules.add(new GamemodeNotifier());
|
||||
modules.add(new GhostMode());
|
||||
modules.add(new Glide());
|
||||
modules.add(new InstaMine());
|
||||
|
@@ -1,127 +1,146 @@
|
||||
package anticope.rejects.modules;
|
||||
|
||||
import anticope.rejects.MeteorRejectsAddon;
|
||||
import com.google.gson.JsonArray;
|
||||
import meteordevelopment.orbit.EventHandler;
|
||||
import meteordevelopment.meteorclient.events.game.GameLeftEvent;
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import meteordevelopment.meteorclient.events.game.ReceiveMessageEvent;
|
||||
import meteordevelopment.meteorclient.events.packets.PacketEvent;
|
||||
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.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 net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AntiVanish extends Module {
|
||||
|
||||
private final Queue<UUID> toLookup = new ConcurrentLinkedQueue<UUID>();
|
||||
private long lastTick = 0;
|
||||
|
||||
private final SettingGroup sgGeneral = settings.getDefaultGroup();
|
||||
|
||||
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() {
|
||||
super(MeteorRejectsAddon.CATEGORY, "anti-vanish", "Notifies user when a admin uses /vanish");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDeactivate() {
|
||||
toLookup.clear();
|
||||
public void onActivate() {
|
||||
timer = 0;
|
||||
completionIDs.clear();
|
||||
messageCache.clear();
|
||||
}
|
||||
@EventHandler
|
||||
public void onLeave(GameLeftEvent event) {
|
||||
toLookup.clear();
|
||||
|
||||
@Override
|
||||
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
|
||||
public void onPacket(PacketEvent.Receive event) {
|
||||
if (event.packet instanceof PlayerListS2CPacket packet) {
|
||||
if (packet.getActions().contains(PlayerListS2CPacket.Action.UPDATE_LATENCY)) {
|
||||
try {
|
||||
for (PlayerListS2CPacket.Entry entry : packet.getEntries()) {
|
||||
if (mc.getNetworkHandler().getPlayerListEntry(entry.profileId()) != null)
|
||||
continue;
|
||||
toLookup.add(entry.profileId());
|
||||
private void onPacket(PacketEvent.Receive event) {
|
||||
if (mode.get() == Mode.RealJoinMessage && event.packet instanceof CommandSuggestionsS2CPacket packet) {
|
||||
if (completionIDs.contains(packet.getCompletionId())) {
|
||||
var lastUsernames = completionPlayerCache.stream().toList();
|
||||
|
||||
completionPlayerCache = packet.getSuggestions().getList().stream()
|
||||
.map(Suggestion::getText)
|
||||
.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
|
||||
public void onTick(TickEvent.Post event) {
|
||||
long time = mc.world.getTime();
|
||||
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;
|
||||
}
|
||||
private void onReceiveMessage(ReceiveMessageEvent event) {
|
||||
messageCache.add(event.getMessage().getString());
|
||||
}
|
||||
|
||||
public String getPlayerNameFromUUID(UUID id) {
|
||||
try {
|
||||
final NameLookup process = new NameLookup(id, mc);
|
||||
final Thread thread = new Thread(process);
|
||||
thread.start();
|
||||
thread.join();
|
||||
return process.getName();
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@EventHandler
|
||||
private void onTick(TickEvent.Post event) {
|
||||
timer++;
|
||||
if (timer < interval.get()) return;
|
||||
|
||||
public static class NameLookup implements Runnable {
|
||||
private final String uuidstr;
|
||||
private final UUID uuid;
|
||||
private final MinecraftClient mc;
|
||||
private volatile String name;
|
||||
switch (mode.get()) {
|
||||
case LeaveMessage -> {
|
||||
Map<UUID, String> oldPlayers = Map.copyOf(playerCache);
|
||||
playerCache = mc.getNetworkHandler().getPlayerList().stream().collect(Collectors.toMap(e -> e.getProfile().getId(), e -> e.getProfile().getName()));
|
||||
|
||||
public NameLookup(final String input, MinecraftClient mc) {
|
||||
this.uuidstr = input;
|
||||
this.uuid = UUID.fromString(input);
|
||||
this.mc = mc;
|
||||
}
|
||||
|
||||
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;
|
||||
for (UUID uuid : oldPlayers.keySet()) {
|
||||
if (playerCache.containsKey(uuid)) continue;
|
||||
String name = oldPlayers.get(uuid);
|
||||
if (messageCache.stream().noneMatch(s -> s.contains(name))) {
|
||||
warning(name + " has gone into vanish.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return player.getName().getString();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
case RealJoinMessage -> {
|
||||
int id = random.nextInt(200);
|
||||
completionIDs.add(id);
|
||||
mc.getNetworkHandler().sendPacket(new RequestCommandCompletionsC2SPacket(id, command.get() + " "));
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
45
src/main/java/anticope/rejects/modules/GamemodeNotifier.java
Normal file
45
src/main/java/anticope/rejects/modules/GamemodeNotifier.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +1,19 @@
|
||||
package anticope.rejects.settings;
|
||||
|
||||
import meteordevelopment.meteorclient.gui.DefaultSettingsWidgetFactory;
|
||||
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.widgets.containers.WContainer;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
public class RejectsSettings {
|
||||
private final Map<Class<?>, SettingsWidgetFactory.Factory> factories;
|
||||
|
||||
@@ -18,10 +26,19 @@ public class RejectsSettings {
|
||||
|
||||
public void addSettings() {
|
||||
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) {
|
||||
WTable wtable = table.add(theme.table()).expandX().widget();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user