turn fakeplayer from a command into a clickgui module
FakePlayer now lives under Misc: enabling spawns the dummy at your position with your equipment, disabling removes it, and it respawns itself after a world change. Settings replace the old subcommands - Name for its name, Swim for the swim pose (live-toggled), PopOnSpawn for the totem event. Drops the .fakeplayer/.fp command.
This commit is contained in:
@@ -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<RemotePlayer> 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<CommandManager> 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<RemotePlayer> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<String> name = str("Name", "FakePlayer");
|
||||||
|
private final Setting<Boolean> swim = bool("Swim", false);
|
||||||
|
private final Setting<Boolean> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,6 @@ public class CommandManager extends Feature implements Jsonable {
|
|||||||
public void init() {
|
public void init() {
|
||||||
register(new BindCommand());
|
register(new BindCommand());
|
||||||
register(new DrawnCommand());
|
register(new DrawnCommand());
|
||||||
register(new FakePlayerCommand());
|
|
||||||
register(new FriendCommand());
|
register(new FriendCommand());
|
||||||
register(new HelpCommand());
|
register(new HelpCommand());
|
||||||
register(new PrefixCommand());
|
register(new PrefixCommand());
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import cc.fros.features.modules.hud.RadarHudModule;
|
|||||||
import cc.fros.features.modules.hud.TimeHudModule;
|
import cc.fros.features.modules.hud.TimeHudModule;
|
||||||
import cc.fros.features.modules.hud.WelcomerHudModule;
|
import cc.fros.features.modules.hud.WelcomerHudModule;
|
||||||
import cc.fros.features.modules.hud.WatermarkHudModule;
|
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.misc.MCFModule;
|
||||||
import cc.fros.features.modules.movement.FastAccelModule;
|
import cc.fros.features.modules.movement.FastAccelModule;
|
||||||
import cc.fros.features.modules.movement.ReverseStepModule;
|
import cc.fros.features.modules.movement.ReverseStepModule;
|
||||||
@@ -70,6 +71,7 @@ public class ModuleManager implements Jsonable, Util {
|
|||||||
register(new NotificationsModule());
|
register(new NotificationsModule());
|
||||||
register(new CriticalsModule());
|
register(new CriticalsModule());
|
||||||
register(new MCFModule());
|
register(new MCFModule());
|
||||||
|
register(new FakePlayerModule());
|
||||||
register(new StepModule());
|
register(new StepModule());
|
||||||
register(new ReverseStepModule());
|
register(new ReverseStepModule());
|
||||||
register(new FastPlaceModule());
|
register(new FastPlaceModule());
|
||||||
|
|||||||
Reference in New Issue
Block a user