diff --git a/src/main/java/cc/fros/features/commands/impl/FakePlayerCommand.java b/src/main/java/cc/fros/features/commands/impl/FakePlayerCommand.java deleted file mode 100644 index 34185b3..0000000 --- a/src/main/java/cc/fros/features/commands/impl/FakePlayerCommand.java +++ /dev/null @@ -1,142 +0,0 @@ -package cc.fros.features.commands.impl; - -import com.mojang.authlib.GameProfile; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import cc.fros.features.commands.Command; -import cc.fros.manager.CommandManager; -import net.minecraft.client.player.RemotePlayer; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.Pose; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; - -public class FakePlayerCommand extends Command { - - private static final byte TOTEM_POP_EVENT_ID = 35; - - private static final EquipmentSlot[] COPIED_SLOTS = { - EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND, - EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET - }; - - private final List spawned = new ArrayList<>(); - private int nextId = -13337; - - public FakePlayerCommand() { - super("fakeplayer", "fp"); - setDescription("Spawns a client-side fake player to test on"); - } - - @Override - public void createArgumentBuilder(LiteralArgumentBuilder builder) { - builder.executes(ctx -> spawn("FakePlayer")) - .then(literal("remove") - .executes(ctx -> removeAll())) - .then(literal("pop") - .executes(ctx -> popAll())) - .then(literal("swim") - .executes(ctx -> toggleSwim())) - .then(argument("name", StringArgumentType.word()) - .executes(ctx -> spawn(StringArgumentType.getString(ctx, "name")))); - } - - private int popAll() { - if (nullCheck() || mc.getConnection() == null) { - return fail("You need to be in a world to do that."); - } - - int popped = 0; - for (RemotePlayer fake : spawned) { - if (fake.level() != mc.level) continue; - mc.getConnection().handleEntityEvent(new ClientboundEntityEventPacket(fake, TOTEM_POP_EVENT_ID)); - popped++; - } - - if (popped == 0) { - return fail("No fake players to pop. Spawn one first."); - } - return success("Popped %s fake player(s)", popped); - } - - private int toggleSwim() { - if (nullCheck()) { - return fail("You need to be in a world to do that."); - } - - boolean anyStanding = false; - int found = 0; - for (RemotePlayer fake : spawned) { - if (fake.level() != mc.level) continue; - found++; - if (fake.getPose() != Pose.SWIMMING) anyStanding = true; - } - if (found == 0) { - return fail("No fake players. Spawn one first."); - } - - Pose pose = anyStanding ? Pose.SWIMMING : Pose.STANDING; - for (RemotePlayer fake : spawned) { - if (fake.level() != mc.level) continue; - fake.setPose(pose); - fake.refreshDimensions(); - } - return success(pose == Pose.SWIMMING - ? "Fake player(s) now in swim pose." - : "Fake player(s) now standing."); - } - - private int spawn(String name) { - if (nullCheck()) { - return fail("You need to be in a world to do that."); - } - - int despawned = despawnAll(); - - GameProfile profile = new GameProfile(UUID.randomUUID(), name); - RemotePlayer fake = new RemotePlayer(mc.level, profile); - fake.setId(nextId--); - fake.copyPosition(mc.player); - fake.setYHeadRot(mc.player.getYHeadRot()); - fake.setHealth(20f); - for (EquipmentSlot slot : COPIED_SLOTS) { - fake.setItemSlot(slot, mc.player.getItemBySlot(slot).copy()); - } - mc.level.addEntity(fake); - spawned.add(fake); - if (despawned > 0) { - return success("Replaced fake player with {green} %s", name); - } - return success("Spawned fake player {green} %s", name); - } - - private int removeAll() { - if (nullCheck()) { - spawned.clear(); - return fail("You need to be in a world to do that."); - } - int removed = despawnAll(); - if (removed == 0) { - return success("No fake players to remove."); - } - return success("Removed %s fake player(s)", removed); - } - - private int despawnAll() { - int removed = 0; - Iterator it = spawned.iterator(); - while (it.hasNext()) { - RemotePlayer fake = it.next(); - it.remove(); - if (fake.level() != mc.level) continue; - mc.level.removeEntity(fake.getId(), Entity.RemovalReason.DISCARDED); - removed++; - } - return removed; - } -} diff --git a/src/main/java/cc/fros/features/modules/misc/FakePlayerModule.java b/src/main/java/cc/fros/features/modules/misc/FakePlayerModule.java new file mode 100644 index 0000000..ab18312 --- /dev/null +++ b/src/main/java/cc/fros/features/modules/misc/FakePlayerModule.java @@ -0,0 +1,94 @@ +package cc.fros.features.modules.misc; + +import cc.fros.features.modules.Module; +import cc.fros.features.settings.Setting; +import com.mojang.authlib.GameProfile; +import net.minecraft.client.player.RemotePlayer; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.Pose; + +import java.util.UUID; + +public class FakePlayerModule extends Module { + + private static final byte TOTEM_POP_EVENT_ID = 35; + + private static final EquipmentSlot[] COPIED_SLOTS = { + EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND, + EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET + }; + + private final Setting name = str("Name", "FakePlayer"); + private final Setting swim = bool("Swim", false); + private final Setting popOnSpawn = bool("PopOnSpawn", false); + + private RemotePlayer fake; + private int nextId = -13337; + + public FakePlayerModule() { + super("FakePlayer", "Spawns a client-side fake player to test on", Category.MISC); + } + + @Override + public void onEnable() { + spawn(); + } + + @Override + public void onDisable() { + despawn(); + } + + @Override + public void onTick() { + if (nullCheck()) return; + + // respawn after a world change or if anything removed it + if (fake == null || fake.level() != mc.level || fake.isRemoved()) { + spawn(); + return; + } + + // keep the pose in sync with the setting + Pose desired = swim.getValue() ? Pose.SWIMMING : Pose.STANDING; + if (fake.getPose() != desired) { + fake.setPose(desired); + fake.refreshDimensions(); + } + } + + private void spawn() { + if (nullCheck()) return; + + despawn(); + + GameProfile profile = new GameProfile(UUID.randomUUID(), name.getValue()); + fake = new RemotePlayer(mc.level, profile); + fake.setId(nextId--); + fake.copyPosition(mc.player); + fake.setYHeadRot(mc.player.getYHeadRot()); + fake.setHealth(20f); + for (EquipmentSlot slot : COPIED_SLOTS) { + fake.setItemSlot(slot, mc.player.getItemBySlot(slot).copy()); + } + if (swim.getValue()) { + fake.setPose(Pose.SWIMMING); + fake.refreshDimensions(); + } + mc.level.addEntity(fake); + + if (popOnSpawn.getValue() && mc.getConnection() != null) { + mc.getConnection().handleEntityEvent(new ClientboundEntityEventPacket(fake, TOTEM_POP_EVENT_ID)); + } + } + + private void despawn() { + if (fake == null) return; + if (mc.level != null && fake.level() == mc.level) { + mc.level.removeEntity(fake.getId(), Entity.RemovalReason.DISCARDED); + } + fake = null; + } +} diff --git a/src/main/java/cc/fros/manager/CommandManager.java b/src/main/java/cc/fros/manager/CommandManager.java index 7e8c242..c265d08 100644 --- a/src/main/java/cc/fros/manager/CommandManager.java +++ b/src/main/java/cc/fros/manager/CommandManager.java @@ -35,7 +35,6 @@ public class CommandManager extends Feature implements Jsonable { public void init() { register(new BindCommand()); register(new DrawnCommand()); - register(new FakePlayerCommand()); register(new FriendCommand()); register(new HelpCommand()); register(new PrefixCommand()); diff --git a/src/main/java/cc/fros/manager/ModuleManager.java b/src/main/java/cc/fros/manager/ModuleManager.java index bb390fb..53d163c 100644 --- a/src/main/java/cc/fros/manager/ModuleManager.java +++ b/src/main/java/cc/fros/manager/ModuleManager.java @@ -29,6 +29,7 @@ import cc.fros.features.modules.hud.RadarHudModule; import cc.fros.features.modules.hud.TimeHudModule; import cc.fros.features.modules.hud.WelcomerHudModule; import cc.fros.features.modules.hud.WatermarkHudModule; +import cc.fros.features.modules.misc.FakePlayerModule; import cc.fros.features.modules.misc.MCFModule; import cc.fros.features.modules.movement.FastAccelModule; import cc.fros.features.modules.movement.ReverseStepModule; @@ -70,6 +71,7 @@ public class ModuleManager implements Jsonable, Util { register(new NotificationsModule()); register(new CriticalsModule()); register(new MCFModule()); + register(new FakePlayerModule()); register(new StepModule()); register(new ReverseStepModule()); register(new FastPlaceModule());