mirror of
https://github.com/tanyaofei/minecraft-fakeplayer.git
synced 2025-09-14 19:36:45 +08:00
优化代码
This commit is contained in:
parent
70da43b128
commit
7235afecac
44
README.md
44
README.md
@ -13,28 +13,28 @@
|
|||||||
|
|
||||||
## 命令
|
## 命令
|
||||||
|
|
||||||
+ /fp ? - 查看帮助手册
|
+ `/fp spawn [世界] [位置]` - 创建假人
|
||||||
+ /fp reload - 重载配置文件
|
+ `/fp kill [假人]` - 移除假人
|
||||||
+ /fp create - 创建一个假人
|
+ `/fp list [页码] [数量]` - 查看所有假人
|
||||||
+ /fp kill - 移除假人
|
+ `/fp distance` - 查看与假人的距离
|
||||||
+ /fp tp - 传送到假人身边
|
+ `/fp tp [假人]` - 传送到假人身边
|
||||||
+ /fp tps - 与假人交换位置
|
+ `/fp tphere [假人]` - 将假人传送到身边
|
||||||
+ /fp tphere - 将假人传送到自己身边
|
+ `/fp tps [假人]` - 与假人交换位置
|
||||||
+ /fp health - 查看假人的生命值
|
+ `/fp config get <配置项>` - 查看配置项
|
||||||
+ /fp exp - 查看假人的经验值
|
+ `/fp config set <配置项> <配置值>` - 设置配置项
|
||||||
+ /fp expme - 转移假人的经验值
|
+ `/fp health [假人]` - 查看生命值
|
||||||
+ /fp config - 玩家个性化配置
|
+ `/fp exp [假人]` - 查看经验值
|
||||||
+ /fp config set - 设置个性化配置
|
+ `/fp expme [假人]` - 转移经验值
|
||||||
+ /fp config get - 查看个性化配置
|
+ `/fp attack (once | continuous | interval | stop) [假人]` - 攻击/破坏
|
||||||
+ /fp drop - 丢弃手上物品
|
+ `/fp use (once | continuous | interval | stop) [假人]` - 使用/交互/放置
|
||||||
+ /fp dropinv - 丢弃背包物品
|
+ `/fp jump (once | continuous | interval | stop) [假人]` - 跳跃
|
||||||
+ /fp look - 让假人看向指定位置
|
+ `/fp drop [假人] [-a|--all]` - 丢弃手上物品
|
||||||
+ /fp move - 让假人移动
|
+ `/fp dropinv [假人]` - 丢弃背包物品
|
||||||
+ /fp turn - 让假人转身
|
+ `/fp look (north | south | east| west | up | down | at) [假人]` - 看向指定位置
|
||||||
+ /fp jump - 让假人跳跃
|
+ `/fp turn (left | right | back | to) [假人]` - 转身到指定位置
|
||||||
+ /fp attack - 让假人点击鼠标左键 **(实验性)**
|
+ `/fp move (forward | backward | left | right) [假人]` - 移动假人
|
||||||
+ /fp use - 让假人点击鼠标右键 **(实验性)**
|
+ `/fp cmd <假人>` - 执行命令
|
||||||
+ /fp cmd - 让假人执行他有权限执行的命令
|
+ `/fp reload` - 重载配置文件
|
||||||
|
|
||||||
此外,假人是一个模拟玩家,因此可以被任何指令所识别比如 `kick`, `tp`, `ban` 等等
|
此外,假人是一个模拟玩家,因此可以被任何指令所识别比如 `kick`, `tp`, `ban` 等等
|
||||||
|
|
||||||
|
@ -42,7 +42,12 @@ public class ActionCommand extends AbstractCommand {
|
|||||||
return (sender, args) -> action(sender, args, action, setting.clone());
|
return (sender, args) -> action(sender, args, action, setting.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void action(@NotNull CommandSender sender, @NotNull CommandArguments args, @NotNull Action action, @NotNull ActionSetting setting) throws WrapperCommandSyntaxException {
|
public void action(
|
||||||
|
@NotNull CommandSender sender,
|
||||||
|
@NotNull CommandArguments args,
|
||||||
|
@NotNull Action action,
|
||||||
|
@NotNull ActionSetting setting
|
||||||
|
) throws WrapperCommandSyntaxException {
|
||||||
var target = getTarget(sender, args);
|
var target = getTarget(sender, args);
|
||||||
actionManager.setAction(target, action, setting);
|
actionManager.setAction(target, action, setting);
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ public class Commands {
|
|||||||
"§6/fp look (north|south|east|west|up|down|at) [假人] §7- §f看向指定位置",
|
"§6/fp look (north|south|east|west|up|down|at) [假人] §7- §f看向指定位置",
|
||||||
"§6/fp turn (left|right|back|to) [假人] §7- §f转身到指定位置",
|
"§6/fp turn (left|right|back|to) [假人] §7- §f转身到指定位置",
|
||||||
"§6/fp move (forward|backward|left|right) [假人] §7- §f移动假人",
|
"§6/fp move (forward|backward|left|right) [假人] §7- §f移动假人",
|
||||||
"§6/fp cmd §7- §f执行命令",
|
"§6/fp cmd <假人> <命令> §7- §f执行命令",
|
||||||
"§6/fp reload §7- §f重载配置文件"
|
"§6/fp reload §7- §f重载配置文件"
|
||||||
)
|
)
|
||||||
.withSubcommands(
|
.withSubcommands(
|
||||||
|
@ -24,7 +24,7 @@ public class ConfigCommand extends AbstractCommand {
|
|||||||
|
|
||||||
private final UserConfigRepository repository = UserConfigRepository.instance;
|
private final UserConfigRepository repository = UserConfigRepository.instance;
|
||||||
|
|
||||||
public static Argument<Config<Object>> config(String nodeName) {
|
public static Argument<Config<Object>> config(@NotNull String nodeName) {
|
||||||
return new CustomArgument<>(new StringArgument(nodeName), info -> {
|
return new CustomArgument<>(new StringArgument(nodeName), info -> {
|
||||||
var arg = info.currentInput();
|
var arg = info.currentInput();
|
||||||
try {
|
try {
|
||||||
@ -35,7 +35,7 @@ public class ConfigCommand extends AbstractCommand {
|
|||||||
}).replaceSuggestions(ArgumentSuggestions.strings(Arrays.stream(Configs.values()).map(Config::name).toList()));
|
}).replaceSuggestions(ArgumentSuggestions.strings(Arrays.stream(Configs.values()).map(Config::name).toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Argument<Object> configValue(String configNodeName, String nodeName) {
|
public static Argument<Object> configValue(@NotNull String configNodeName, @NotNull String nodeName) {
|
||||||
return new CustomArgument<>(new StringArgument(nodeName), info -> {
|
return new CustomArgument<>(new StringArgument(nodeName), info -> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
var config = Objects.requireNonNull((Config<Object>) info.previousArgs().get(configNodeName));
|
var config = Objects.requireNonNull((Config<Object>) info.previousArgs().get(configNodeName));
|
||||||
|
@ -34,7 +34,7 @@ public class SpawnCommand extends AbstractCommand {
|
|||||||
MathUtils.round(location.getZ(), 0.5));
|
MathUtils.round(location.getZ(), 0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawn(@NotNull CommandSender sender, CommandArguments args) {
|
public void spawn(@NotNull CommandSender sender, @NotNull CommandArguments args) {
|
||||||
var world = (World) args.get("world");
|
var world = (World) args.get("world");
|
||||||
var location = (Location) args.get("location");
|
var location = (Location) args.get("location");
|
||||||
if (world == null || location == null) {
|
if (world == null || location == null) {
|
||||||
@ -48,7 +48,7 @@ public class SpawnCommand extends AbstractCommand {
|
|||||||
location.setWorld(world);
|
location.setWorld(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
var fakePlayer = fakeplayerManager.spawn(sender, location.clone());
|
var fakePlayer = fakeplayerManager.spawn(sender, location);
|
||||||
if (fakePlayer != null) {
|
if (fakePlayer != null) {
|
||||||
sender.sendMessage(textOfChildren(
|
sender.sendMessage(textOfChildren(
|
||||||
text("你创建了假人 ", GRAY),
|
text("你创建了假人 ", GRAY),
|
||||||
@ -59,7 +59,7 @@ public class SpawnCommand extends AbstractCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void kill(@NotNull CommandSender sender, CommandArguments args) {
|
public void kill(@NotNull CommandSender sender, @NotNull CommandArguments args) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
var targets = (List<Player>) args.get("targets");
|
var targets = (List<Player>) args.get("targets");
|
||||||
if (targets == null) {
|
if (targets == null) {
|
||||||
|
@ -2,14 +2,10 @@ package io.github.hello09x.fakeplayer.command;
|
|||||||
|
|
||||||
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
|
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
|
||||||
import dev.jorel.commandapi.executors.CommandArguments;
|
import dev.jorel.commandapi.executors.CommandArguments;
|
||||||
import org.bukkit.Sound;
|
import io.github.hello09x.fakeplayer.util.Teleportor;
|
||||||
import org.bukkit.SoundCategory;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import static org.bukkit.Sound.ENTITY_ENDERMAN_TELEPORT;
|
|
||||||
|
|
||||||
public class TpCommand extends AbstractCommand {
|
public class TpCommand extends AbstractCommand {
|
||||||
|
|
||||||
public final static TpCommand instance = new TpCommand();
|
public final static TpCommand instance = new TpCommand();
|
||||||
@ -27,19 +23,15 @@ public class TpCommand extends AbstractCommand {
|
|||||||
public void tps(@NotNull Player sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException {
|
public void tps(@NotNull Player sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException {
|
||||||
var target = getTarget(sender, args);
|
var target = getTarget(sender, args);
|
||||||
|
|
||||||
var l1 = sender.getLocation();
|
var l1 = sender.getLocation().clone();
|
||||||
var l2 = target.getLocation();
|
var l2 = target.getLocation().clone();
|
||||||
|
|
||||||
target.teleport(l1, PlayerTeleportEvent.TeleportCause.PLUGIN);
|
Teleportor.teleportAndSound(target, l1);
|
||||||
l1.getWorld().playSound(l1, Sound.ENTITY_ENDERMAN_TELEPORT, SoundCategory.PLAYERS, 1.0F, 1.0F);
|
Teleportor.teleportAndSound(sender, l2);
|
||||||
|
|
||||||
sender.teleport(l2, PlayerTeleportEvent.TeleportCause.PLUGIN);
|
|
||||||
l2.getWorld().playSound(l2, Sound.ENTITY_ENDERMAN_TELEPORT, SoundCategory.PLAYERS, 1.0F, 1.0F);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void teleport(@NotNull Player from, @NotNull Player to) {
|
private void teleport(@NotNull Player from, @NotNull Player to) {
|
||||||
from.teleport(to.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
|
Teleportor.teleportAndSound(from, to.getLocation());
|
||||||
to.getLocation().getWorld().playSound(to.getLocation(), ENTITY_ENDERMAN_TELEPORT, 1.0F, 1.0F);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,11 +9,11 @@ import io.github.hello09x.fakeplayer.repository.UsedIdRepository;
|
|||||||
import io.github.hello09x.fakeplayer.repository.UserConfigRepository;
|
import io.github.hello09x.fakeplayer.repository.UserConfigRepository;
|
||||||
import io.github.hello09x.fakeplayer.repository.model.Configs;
|
import io.github.hello09x.fakeplayer.repository.model.Configs;
|
||||||
import io.github.hello09x.fakeplayer.util.AddressUtils;
|
import io.github.hello09x.fakeplayer.util.AddressUtils;
|
||||||
|
import io.github.hello09x.fakeplayer.util.Teleportor;
|
||||||
import io.github.hello09x.fakeplayer.util.Unwrapper;
|
import io.github.hello09x.fakeplayer.util.Unwrapper;
|
||||||
import net.kyori.adventure.text.format.Style;
|
import net.kyori.adventure.text.format.Style;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Sound;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -94,7 +94,7 @@ public class FakeplayerManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var seqname = nameManager.take(creator);
|
var sn = nameManager.take(creator);
|
||||||
boolean invulnerable = true, lookAtEntity = true, collidable = true, pickupItems = true;
|
boolean invulnerable = true, lookAtEntity = true, collidable = true, pickupItems = true;
|
||||||
if (creator instanceof Player p) {
|
if (creator instanceof Player p) {
|
||||||
var creatorId = p.getUniqueId();
|
var creatorId = p.getUniqueId();
|
||||||
@ -107,16 +107,16 @@ public class FakeplayerManager {
|
|||||||
var player = new FakePlayer(
|
var player = new FakePlayer(
|
||||||
creator.getName(),
|
creator.getName(),
|
||||||
((CraftServer) Bukkit.getServer()).getServer(),
|
((CraftServer) Bukkit.getServer()).getServer(),
|
||||||
generateId(seqname.name()),
|
generateId(sn.name()),
|
||||||
seqname.name()
|
sn.name()
|
||||||
);
|
);
|
||||||
|
|
||||||
var bukkitPlayer = player.getBukkitPlayer();
|
var bukkitPlayer = player.getBukkitPlayer();
|
||||||
Metadatas.CREATOR.set(bukkitPlayer, creator.getName());
|
Metadatas.CREATOR.set(bukkitPlayer, creator.getName());
|
||||||
Metadatas.CREATOR_IP.set(bukkitPlayer, AddressUtils.getAddress(creator));
|
Metadatas.CREATOR_IP.set(bukkitPlayer, AddressUtils.getAddress(creator));
|
||||||
Metadatas.NAME_SOURCE.set(bukkitPlayer, seqname.source());
|
Metadatas.NAME_SOURCE.set(bukkitPlayer, sn.source());
|
||||||
Metadatas.NAME_SEQUENCE.set(bukkitPlayer, seqname.sequence());
|
Metadatas.NAME_SEQUENCE.set(bukkitPlayer, sn.sequence());
|
||||||
bukkitPlayer.playerListName(text(creator.getName() + "的假人").style(Style.style(GRAY, ITALIC)));
|
bukkitPlayer.playerListName(text(bukkitPlayer.getName() + " (假人)").style(Style.style(GRAY, ITALIC)));
|
||||||
|
|
||||||
player.spawn(invulnerable, collidable, lookAtEntity, pickupItems);
|
player.spawn(invulnerable, collidable, lookAtEntity, pickupItems);
|
||||||
|
|
||||||
@ -124,29 +124,30 @@ public class FakeplayerManager {
|
|||||||
dispatchCommands(bukkitPlayer, properties.getPreparingCommands());
|
dispatchCommands(bukkitPlayer, properties.getPreparingCommands());
|
||||||
performCommands(bukkitPlayer, properties.getSelfCommands());
|
performCommands(bukkitPlayer, properties.getSelfCommands());
|
||||||
|
|
||||||
bukkitPlayer.teleport(spawnAt); // 当前 tick 必须传到出生点否则无法触发区块刷新
|
spawnAt = spawnAt.clone();
|
||||||
spawnAt.getWorld().playSound(spawnAt, Sound.ENTITY_ENDERMAN_TELEPORT, 1.0F, 1.0F);
|
Teleportor.teleportAndSound(bukkitPlayer, spawnAt); // 当前 tick 必须传到出生点否则无法触发区块刷新
|
||||||
|
ensureSpawnpoint(bukkitPlayer, spawnAt); // 防止别的插件比如 `multicore` 把他带离出生点
|
||||||
|
|
||||||
// 可能被别的插件干预
|
return bukkitPlayer;
|
||||||
// 在下一 tick 里探测
|
}
|
||||||
|
|
||||||
|
private void ensureSpawnpoint(@NotNull Player player, @NotNull Location spawnpoint) {
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (spawnAt.distance(bukkitPlayer.getLocation()) < 16) {
|
if (spawnpoint.getWorld().equals(spawnpoint.getWorld()) && spawnpoint.distance(player.getLocation()) < 16) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bukkitPlayer.teleport(spawnAt.getWorld().getSpawnLocation());
|
player.teleport(spawnpoint.getWorld().getSpawnLocation());
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
bukkitPlayer.teleport(spawnAt);
|
player.teleport(spawnpoint);
|
||||||
}
|
}
|
||||||
}.runTaskLater(Main.getInstance(), 1);
|
}.runTaskLater(Main.getInstance(), 1);
|
||||||
}
|
}
|
||||||
}.runTaskLater(Main.getInstance(), 1);
|
}.runTaskLater(Main.getInstance(), 1);
|
||||||
|
|
||||||
return bukkitPlayer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Player get(@NotNull CommandSender creator, @NotNull String name) {
|
public @Nullable Player get(@NotNull CommandSender creator, @NotNull String name) {
|
||||||
|
@ -14,14 +14,12 @@ import java.util.logging.Logger;
|
|||||||
public class NameManager {
|
public class NameManager {
|
||||||
|
|
||||||
public final static NameManager instance = new NameManager();
|
public final static NameManager instance = new NameManager();
|
||||||
|
private final static Logger log = Main.getInstance().getLogger();
|
||||||
|
private final static int MAX_LENGTH = 16; // mojang required
|
||||||
private final FakeplayerProperties properties = FakeplayerProperties.instance;
|
private final FakeplayerProperties properties = FakeplayerProperties.instance;
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, NameSource> nameSources = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, NameSource> nameSources = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final static Logger log = Main.getInstance().getLogger();
|
public @NotNull SequenceName take(CommandSender creator) {
|
||||||
|
|
||||||
public SequenceName take(CommandSender creator) {
|
|
||||||
var source = properties.getNameTemplate();
|
var source = properties.getNameTemplate();
|
||||||
if (source.isBlank()) {
|
if (source.isBlank()) {
|
||||||
source = creator.getName();
|
source = creator.getName();
|
||||||
@ -33,8 +31,8 @@ public class NameManager {
|
|||||||
var suffix = "_" + (seq + 1);
|
var suffix = "_" + (seq + 1);
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
if (source.length() + suffix.length() > 16) {
|
if (source.length() + suffix.length() > MAX_LENGTH) {
|
||||||
name = source.substring(0, (16 - suffix.length()));
|
name = source.substring(0, (MAX_LENGTH - suffix.length()));
|
||||||
} else {
|
} else {
|
||||||
name = source;
|
name = source;
|
||||||
}
|
}
|
||||||
@ -52,7 +50,8 @@ public class NameManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = "FAKE_" + RandomStringUtils.random(11, true, true);
|
var name = "_fp_";
|
||||||
|
name = name + RandomStringUtils.random(MAX_LENGTH - name.length(), true, true);
|
||||||
log.warning("Could not generate a name which is never used at this server after 10 tries, using random player name as fallback: " + name);
|
log.warning("Could not generate a name which is never used at this server after 10 tries, using random player name as fallback: " + name);
|
||||||
return new SequenceName("random", 0, name);
|
return new SequenceName("random", 0, name);
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,7 @@ public class NameSource {
|
|||||||
this(0);
|
this(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public synchronized int pop() {
|
||||||
synchronized int pop() {
|
|
||||||
if (names.isEmpty()) {
|
if (names.isEmpty()) {
|
||||||
var newCapacity = capacity * 2;
|
var newCapacity = capacity * 2;
|
||||||
for (int i = capacity; i < newCapacity; i++) {
|
for (int i = capacity; i < newCapacity; i++) {
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package io.github.hello09x.fakeplayer.util;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class Teleportor {
|
||||||
|
|
||||||
|
public static void teleportAndSound(@NotNull Entity entity, @NotNull Location location) {
|
||||||
|
entity.teleport(location);
|
||||||
|
location.getWorld().playSound(location, Sound.ENTITY_ENDERMAN_TELEPORT, 1.0F, 1.0F);;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user