minecraft-fakeplayer/src/main/java/io/github/hello09x/fakeplayer/entity/FakePlayer.java
tanyaofei 61c0381326 1. 更改命令的实现方式,更符合 minecraft 的风格
2. 添加 `self-commands` 配置
3. 配置项新增是否拾取物品
2023-07-26 18:40:02 +08:00

159 lines
5.8 KiB
Java

package io.github.hello09x.fakeplayer.entity;
import com.mojang.authlib.GameProfile;
import io.github.hello09x.fakeplayer.Main;
import io.github.hello09x.fakeplayer.core.EmptyAdvancements;
import io.github.hello09x.fakeplayer.core.EmptyConnection;
import io.github.hello09x.fakeplayer.core.EmptyLoginPacketListener;
import io.github.hello09x.fakeplayer.core.EmptyServerGamePacketListener;
import io.github.hello09x.fakeplayer.properties.FakeplayerProperties;
import io.github.hello09x.fakeplayer.util.ReflectionUtils;
import io.papermc.paper.entity.LookAnchor;
import lombok.Getter;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerAdvancements;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.util.Objects;
import java.util.UUID;
import java.util.logging.Logger;
public class FakePlayer {
private final static Field advancements = ReflectionUtils.getFirstFieldByType(ServerPlayer.class, PlayerAdvancements.class, false);
private final static Logger log = Main.getInstance().getLogger();
private final static InetAddress fakeAddress = InetAddress.getLoopbackAddress();
private final FakeplayerProperties properties = FakeplayerProperties.instance;
private final MinecraftServer server;
@Getter
private final String creator;
@Getter
private final ServerPlayer handle;
@Getter
private final Player bukkitPlayer;
public FakePlayer(
@NotNull String creator,
@NotNull MinecraftServer server,
@NotNull UUID uniqueId,
@NotNull String name
) {
this.creator = creator;
this.handle = new ServerPlayer(server, Objects.requireNonNull(server.getLevel(ServerLevel.OVERWORLD), "缺少 overworld 世界"), new GameProfile(uniqueId, name));
this.bukkitPlayer = this.handle.getBukkitEntity();
((CraftPlayer) this.bukkitPlayer).readExtraData(new CompoundTag()); // set play before avoiding first join message
this.server = server;
this.bukkitPlayer.setPersistent(false);
if (advancements != null) {
try {
advancements.set(
this.handle,
new EmptyAdvancements(
server.getFixerUpper(),
server.getPlayerList(),
server.getAdvancements(),
Main.getInstance().getDataFolder().getParentFile().toPath(),
this.handle
));
} catch (IllegalAccessException ignored) {
}
}
}
public void spawn(
boolean invulnerable,
boolean collidable,
boolean lookAtEntity,
boolean pickupItems
) {
if (properties.isSimulateLogin()) {
preLogin:
new BukkitRunnable() {
@Override
public void run() {
var preLoginEvent = new AsyncPlayerPreLoginEvent(
handle.getGameProfile().getName(),
fakeAddress,
fakeAddress,
handle.getUUID(),
bukkitPlayer.getPlayerProfile(),
fakeAddress.getHostName()
);
Bukkit.getPluginManager().callEvent(preLoginEvent);
}
}.runTaskAsynchronously(Main.getInstance());
login:
{
Bukkit.getPluginManager().callEvent(new PlayerLoginEvent(
this.bukkitPlayer,
fakeAddress.getHostName(),
fakeAddress
));
}
}
gaming:
{
var connection = new EmptyConnection(PacketFlow.CLIENTBOUND);
var listener = new EmptyServerGamePacketListener(this.server, connection, this.handle);
this.handle.connection = listener;
connection.setListener(listener);
}
spawn:
{
var connection = new EmptyConnection(PacketFlow.CLIENTBOUND);
var listener = new EmptyLoginPacketListener(server, connection);
((CraftServer) Bukkit.getServer()).getHandle().placeNewPlayer(
listener.connection,
handle
);
connection.setListener(listener);
}
bukkitPlayer.setInvulnerable(invulnerable);
bukkitPlayer.setCollidable(collidable);
bukkitPlayer.setCanPickupItems(pickupItems);
new BukkitRunnable() {
@Override
public void run() {
if (!bukkitPlayer.isOnline()) {
cancel();
return;
}
// tick() 伤害计算
// doTick() 移动计算
handle.doTick();
if (lookAtEntity) {
var entities = bukkitPlayer.getNearbyEntities(3, 3, 3);
if (!entities.isEmpty()) {
bukkitPlayer.lookAt(entities.get(0), LookAnchor.EYES, LookAnchor.EYES);
}
}
}
}.runTaskTimer(Main.getInstance(), 0, 1);
}
}