mirror of
https://github.com/tanyaofei/minecraft-fakeplayer.git
synced 2025-07-13 21:02:27 +08:00
fix
This commit is contained in:
parent
3de5d680fc
commit
35ef7644b9
@ -22,9 +22,9 @@ public final class Main extends JavaPlugin {
|
||||
}
|
||||
|
||||
{
|
||||
getServer().getPluginManager().registerEvents(PlayerQuitListener.instance, Main.getInstance());
|
||||
// getServer().getPluginManager().registerEvents(PlayerQuitListener.instance, Main.getInstance());
|
||||
getServer().getPluginManager().registerEvents(PlayerDeathListener.instance, Main.getInstance());
|
||||
getServer().getPluginManager().registerEvents(PlayerTeleportListener.instance, Main.getInstance());
|
||||
// getServer().getPluginManager().registerEvents(PlayerTeleportListener.instance, Main.getInstance());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package io.github.hello09x.fakeplayer.command.player;
|
||||
|
||||
import io.github.hello09x.fakeplayer.manager.FakePlayerManager;
|
||||
import io.github.tanyaofei.plugin.toolkit.command.ExecutableCommand;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -36,14 +37,29 @@ public class CreateCommand extends ExecutableCommand {
|
||||
@NotNull String label,
|
||||
@NotNull String[] args
|
||||
) {
|
||||
if (!(sender instanceof Player p)) {
|
||||
sender.sendMessage(text("你不是玩家...", RED));
|
||||
return true;
|
||||
if (sender instanceof Player p) {
|
||||
manager.spawnFakePlayer(
|
||||
p,
|
||||
((Player) sender).getLocation()
|
||||
);
|
||||
} else {
|
||||
if (args.length != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double x, y, z;
|
||||
try {
|
||||
x = Double.parseDouble(args[0]);
|
||||
y = Double.parseDouble(args[1]);
|
||||
z = Double.parseDouble(args[2]);
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var world = sender.getServer().getWorlds().get(0);
|
||||
manager.spawnFakePlayer(sender, new Location(world, x, y, z));
|
||||
}
|
||||
manager.spawnFakePlayer(
|
||||
p,
|
||||
((Player) sender).getLocation()
|
||||
);
|
||||
|
||||
sender.sendMessage(text("创建成功", GRAY));
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package io.github.hello09x.fakeplayer.core;
|
||||
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
|
||||
public class EmptyConnection extends ServerGamePacketListenerImpl {
|
||||
public EmptyConnection(MinecraftServer minecraftServer, Connection networkManager, ServerPlayer entityPlayer) {
|
||||
super(minecraftServer, networkManager, entityPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Packet<?> packet) {
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +1,30 @@
|
||||
package io.github.hello09x.fakeplayer.core;
|
||||
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.PacketSendListener;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
|
||||
public class EmptyNetworkManager extends NetworkManager {
|
||||
import java.io.IOException;
|
||||
|
||||
public EmptyNetworkManager(EnumProtocolDirection enumprotocoldirection) {
|
||||
super(enumprotocoldirection);
|
||||
this.m = new EmptyChannel(null);
|
||||
this.n = this.m.remoteAddress();
|
||||
this.preparing = false;
|
||||
public class EmptyNetworkManager extends Connection {
|
||||
public EmptyNetworkManager(PacketFlow flag) throws IOException {
|
||||
super(flag);
|
||||
this.channel = new EmptyChannel(null);
|
||||
this.address = this.channel.remoteAddress();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Packet packet, PacketSendListener genericfuturelistener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDisconnection() {
|
||||
super.handleDisconnection();
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.github.hello09x.fakeplayer.core;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
public class EmptySocket extends Socket {
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return new ByteArrayInputStream(EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return new ByteArrayOutputStream(5);
|
||||
}
|
||||
|
||||
private static final byte[] EMPTY = new byte[50];
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package io.github.hello09x.fakeplayer.entity;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.github.hello09x.fakeplayer.Main;
|
||||
import io.github.hello09x.fakeplayer.core.EmptyConnection;
|
||||
import io.github.hello09x.fakeplayer.core.EmptyNetworkManager;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
||||
import net.minecraft.network.protocol.game.ServerboundClientInformationPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.HumanoidArm;
|
||||
import net.minecraft.world.entity.player.ChatVisiblity;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class FakePlayer extends ServerPlayer {
|
||||
|
||||
private final UUID uniqueId;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Location spawnLocation;
|
||||
|
||||
public FakePlayer(
|
||||
MinecraftServer server,
|
||||
ServerLevel world,
|
||||
UUID uniqueId,
|
||||
String name,
|
||||
Location at
|
||||
) {
|
||||
super(server, world, new GameProfile(uniqueId, name));
|
||||
this.uniqueId = uniqueId;
|
||||
this.name = name;
|
||||
this.spawnLocation = at;
|
||||
|
||||
try {
|
||||
var networkManager = new EmptyNetworkManager(PacketFlow.CLIENTBOUND);
|
||||
this.connection = new EmptyConnection(server, networkManager, this);
|
||||
networkManager.setListener(this.connection);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isChunkLoaded(Location at) {
|
||||
if (at.getWorld() == null) {
|
||||
return false;
|
||||
}
|
||||
int x = at.getBlockX() >> 4;
|
||||
int z = at.getBlockZ() >> 4;
|
||||
return at.getWorld().isChunkLoaded(x, z);
|
||||
}
|
||||
|
||||
public Player prepare() {
|
||||
addToPlayerList();
|
||||
spawn();
|
||||
|
||||
var p = Objects.requireNonNull(Bukkit.getPlayer(this.uuid));
|
||||
p.setSleepingIgnored(true);
|
||||
p.setPersistent(false);
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doTick();
|
||||
tickCount++;
|
||||
}
|
||||
}.runTaskTimer(Main.getInstance(), 0, 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void addToPlayerList() {
|
||||
var packet = new ServerboundClientInformationPacket(
|
||||
"EN",
|
||||
10,
|
||||
ChatVisiblity.FULL,
|
||||
false,
|
||||
0,
|
||||
HumanoidArm.LEFT,
|
||||
false,
|
||||
true
|
||||
);
|
||||
this.updateOptions(packet);
|
||||
|
||||
var entity = this.getBukkitEntity();
|
||||
var handle = (ServerPlayer) ((CraftEntity) entity).getHandle();
|
||||
if (handle.level() == null) {
|
||||
return;
|
||||
}
|
||||
var playerList = handle.level().players();
|
||||
if (!playerList.contains(handle)) {
|
||||
((List) playerList).add(handle);
|
||||
}
|
||||
|
||||
try {
|
||||
var updatePlayerStatus = ChunkMap.class.getDeclaredMethod(
|
||||
"a",
|
||||
ServerPlayer.class,
|
||||
boolean.class
|
||||
);
|
||||
updatePlayerStatus.setAccessible(true);
|
||||
updatePlayerStatus.invoke(
|
||||
((ServerLevel) handle.level()).getChunkSource().chunkMap,
|
||||
handle,
|
||||
true
|
||||
);
|
||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
for(var online: Bukkit.getOnlinePlayers()) {
|
||||
((CraftPlayer) online).getHandle().connection.send(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, handle));
|
||||
((CraftPlayer) online).getHandle().connection.send(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, handle));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void spawn() {
|
||||
var entity = this.getBukkitEntity();
|
||||
var handle = (ServerPlayer) ((CraftEntity) entity).getHandle();
|
||||
|
||||
if (!isChunkLoaded(spawnLocation)) {
|
||||
spawnLocation.getChunk().load();
|
||||
}
|
||||
handle.level().addFreshEntity(handle, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
|
||||
((CraftServer) Bukkit.getServer()).getHandle().respawn(
|
||||
this,
|
||||
true,
|
||||
PlayerRespawnEvent.RespawnReason.PLUGIN
|
||||
);
|
||||
|
||||
// move directly
|
||||
getBukkitEntity().teleport(spawnLocation);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,8 +1,15 @@
|
||||
package io.github.hello09x.fakeplayer.manager;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.github.hello09x.fakeplayer.Main;
|
||||
import io.github.hello09x.fakeplayer.entity.FakePlayer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import properties.FakeplayerProperties;
|
||||
@ -21,8 +28,8 @@ public class FakePlayerManager {
|
||||
private final FakeplayerProperties properties = FakeplayerProperties.instance;
|
||||
|
||||
public synchronized void spawnFakePlayer(
|
||||
@NotNull Player creator,
|
||||
@NotNull Location location
|
||||
@NotNull CommandSender creator,
|
||||
@NotNull Location at
|
||||
) {
|
||||
var existed = getFakePlayers(creator).size();
|
||||
if (!creator.isOp() && existed >= properties.getMaximum()) {
|
||||
@ -36,22 +43,26 @@ public class FakePlayerManager {
|
||||
name = name.substring(0, (16 - suffix.length()));
|
||||
}
|
||||
name = name + suffix;
|
||||
FakePlayerSpawner.spawn(
|
||||
|
||||
var player = new FakePlayer(
|
||||
((CraftServer) Bukkit.getServer()).getServer(),
|
||||
((CraftWorld) at.getWorld()).getHandle(),
|
||||
UUID.randomUUID(),
|
||||
name,
|
||||
creator,
|
||||
location
|
||||
at
|
||||
);
|
||||
var p = player.prepare();
|
||||
p.setMetadata(FakePlayerSpawner.META_KEY_CREATOR, new FixedMetadataValue(Main.getInstance(), creator.getName()));
|
||||
}
|
||||
|
||||
public @Nullable Player getFakePlayer(@NotNull Player creator, @NotNull String name) {
|
||||
public @Nullable Player getFakePlayer(@NotNull CommandSender creator, @NotNull String name) {
|
||||
var fake = getFakePlayer(name);
|
||||
if (fake == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var c = getCreator(fake);
|
||||
if (c == null || !c.equals(creator.getUniqueId())) {
|
||||
if (c == null || !c.equals(creator.getName())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -79,13 +90,13 @@ public class FakePlayerManager {
|
||||
return fakes.size();
|
||||
}
|
||||
|
||||
public @Nullable UUID getCreator(@NotNull Player fakePlayer) {
|
||||
public @Nullable String getCreator(@NotNull Player fakePlayer) {
|
||||
var meta = fakePlayer.getMetadata(FakePlayerSpawner.META_KEY_CREATOR);
|
||||
if (meta.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return UUID.fromString(meta.get(0).asString());
|
||||
return meta.get(0).asString();
|
||||
}
|
||||
|
||||
public int removeFakePlayers() {
|
||||
@ -105,15 +116,15 @@ public class FakePlayerManager {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public @NotNull List<Player> getFakePlayers(@NotNull Player creator) {
|
||||
var creatorUniqueId = creator.getUniqueId().toString();
|
||||
public @NotNull List<Player> getFakePlayers(@NotNull CommandSender creator) {
|
||||
var name = creator.getName();
|
||||
return Bukkit
|
||||
.getServer()
|
||||
.getOnlinePlayers()
|
||||
.stream()
|
||||
.filter(p -> p.getMetadata(FakePlayerSpawner.META_KEY_CREATOR)
|
||||
.stream()
|
||||
.anyMatch(meta -> meta.asString().equals(creatorUniqueId)))
|
||||
.anyMatch(meta -> meta.asString().equals(name)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -27,73 +27,73 @@ public class FakePlayerSpawner {
|
||||
|
||||
public final static String META_KEY_CREATOR = "fakeplayer::creator";
|
||||
|
||||
public static @NotNull Player spawn(
|
||||
@NotNull UUID uniqueId,
|
||||
@NotNull String name,
|
||||
@NotNull Player creator,
|
||||
@NotNull Location at
|
||||
) {
|
||||
var craftServer = (CraftServer) Bukkit.getServer();
|
||||
var server = craftServer.getServer();
|
||||
var gameProfile = new GameProfile(uniqueId, name);
|
||||
var world = ((CraftWorld) at.getWorld()).getHandle();
|
||||
|
||||
var entityPlayer = new EntityPlayer(server, world, gameProfile);
|
||||
var craftPlayer = entityPlayer.getBukkitEntity();
|
||||
|
||||
|
||||
entityPlayer.f = 0; // ping
|
||||
entityPlayer.c = new PlayerConnection(
|
||||
server,
|
||||
new EmptyNetworkManager(EnumProtocolDirection.a),
|
||||
entityPlayer
|
||||
);
|
||||
|
||||
craftPlayer.setFirstPlayed(System.currentTimeMillis());
|
||||
craftServer.getHandle().respawn(
|
||||
entityPlayer,
|
||||
true,
|
||||
PlayerRespawnEvent.RespawnReason.PLUGIN
|
||||
);
|
||||
refreshTabList(entityPlayer);
|
||||
|
||||
var holder = Objects.requireNonNull(Bukkit.getPlayer(uniqueId));
|
||||
holder.setViewDistance(9);
|
||||
holder.setAffectsSpawning(true);
|
||||
holder.setSleepingIgnored(true);
|
||||
holder.setPersistent(false);
|
||||
holder.setGameMode(GameMode.CREATIVE);
|
||||
holder.setAllowFlight(true);
|
||||
holder.setMetadata(META_KEY_CREATOR, new FixedMetadataValue(Main.getInstance(), creator.getUniqueId().toString()));
|
||||
holder.teleport(at, PlayerTeleportEvent.TeleportCause.SPECTATE);
|
||||
creator.playSound(Sound.sound(
|
||||
ENTITY_ENDERMAN_TELEPORT.key(),
|
||||
Sound.Source.PLAYER,
|
||||
1.0F,
|
||||
1.0F
|
||||
));
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
System.out.println(holder);
|
||||
System.out.println(craftPlayer);
|
||||
});
|
||||
return holder;
|
||||
}
|
||||
|
||||
private static void refreshTabList(EntityPlayer player) {
|
||||
try {
|
||||
var field = EntityPlayer.class.getDeclaredField("cU");
|
||||
field.setAccessible(true);
|
||||
field.set(player, true);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
for (var online : Bukkit.getOnlinePlayers()) {
|
||||
((CraftPlayer) online).getHandle().c.a(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.a, player)); //ADD_PLAYER
|
||||
((CraftPlayer) online).getHandle().c.a(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.d, player)); //UPDATE_LISTED
|
||||
}
|
||||
}
|
||||
// public static @NotNull Player spawn(
|
||||
// @NotNull UUID uniqueId,
|
||||
// @NotNull String name,
|
||||
// @NotNull Player creator,
|
||||
// @NotNull Location at
|
||||
// ) {
|
||||
// var craftServer = (CraftServer) Bukkit.getServer();
|
||||
// var server = craftServer.getServer();
|
||||
// var gameProfile = new GameProfile(uniqueId, name);
|
||||
// var world = ((CraftWorld) at.getWorld()).getHandle();
|
||||
//
|
||||
// var entityPlayer = new EntityPlayer(server, world, gameProfile);
|
||||
// var craftPlayer = entityPlayer.getBukkitEntity();
|
||||
//
|
||||
//
|
||||
// entityPlayer.f = 0; // ping
|
||||
// entityPlayer.c = new PlayerConnection(
|
||||
// server,
|
||||
// new EmptyNetworkManager(EnumProtocolDirection.a),
|
||||
// entityPlayer
|
||||
// );
|
||||
//
|
||||
// craftPlayer.setFirstPlayed(System.currentTimeMillis());
|
||||
// craftServer.getHandle().respawn(
|
||||
// entityPlayer,
|
||||
// true,
|
||||
// PlayerRespawnEvent.RespawnReason.PLUGIN
|
||||
// );
|
||||
// refreshTabList(entityPlayer);
|
||||
//
|
||||
// var holder = Objects.requireNonNull(Bukkit.getPlayer(uniqueId));
|
||||
// holder.setViewDistance(9);
|
||||
// holder.setAffectsSpawning(true);
|
||||
// holder.setSleepingIgnored(true);
|
||||
// holder.setPersistent(false);
|
||||
// holder.setGameMode(GameMode.CREATIVE);
|
||||
// holder.setAllowFlight(true);
|
||||
// holder.setMetadata(META_KEY_CREATOR, new FixedMetadataValue(Main.getInstance(), creator.getUniqueId().toString()));
|
||||
// holder.teleport(at, PlayerTeleportEvent.TeleportCause.SPECTATE);
|
||||
// creator.playSound(Sound.sound(
|
||||
// ENTITY_ENDERMAN_TELEPORT.key(),
|
||||
// Sound.Source.PLAYER,
|
||||
// 1.0F,
|
||||
// 1.0F
|
||||
// ));
|
||||
//
|
||||
// CompletableFuture.runAsync(() -> {
|
||||
// System.out.println(holder);
|
||||
// System.out.println(craftPlayer);
|
||||
// });
|
||||
// return holder;
|
||||
// }
|
||||
//
|
||||
// private static void refreshTabList(EntityPlayer player) {
|
||||
// try {
|
||||
// var field = EntityPlayer.class.getDeclaredField("cU");
|
||||
// field.setAccessible(true);
|
||||
// field.set(player, true);
|
||||
// } catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
//
|
||||
// for (var online : Bukkit.getOnlinePlayers()) {
|
||||
// ((CraftPlayer) online).getHandle().c.a(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.a, player)); //ADD_PLAYER
|
||||
// ((CraftPlayer) online).getHandle().c.a(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.d, player)); //UPDATE_LISTED
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user