mirror of
https://github.com/tanyaofei/minecraft-fakeplayer.git
synced 2025-09-14 11:16:46 +08:00
优化代码
This commit is contained in:
parent
03c45c6b88
commit
340a6b701c
@ -5,7 +5,7 @@ import dev.jorel.commandapi.CommandAPIBukkitConfig;
|
||||
import io.github.hello09x.fakeplayer.command.Commands;
|
||||
import io.github.hello09x.fakeplayer.listener.PlayerListeners;
|
||||
import io.github.hello09x.fakeplayer.manager.FakeplayerManager;
|
||||
import io.github.hello09x.fakeplayer.optional.BungeeCordServer;
|
||||
import io.github.hello09x.fakeplayer.optional.Multiserver;
|
||||
import io.github.hello09x.fakeplayer.repository.UsedIdRepository;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
@ -29,7 +29,7 @@ public final class Main extends JavaPlugin {
|
||||
CommandAPI.onEnable();
|
||||
|
||||
{
|
||||
getServer().getMessenger().registerIncomingPluginChannel(Main.getInstance(), "BungeeCord", BungeeCordServer.instance);
|
||||
getServer().getMessenger().registerIncomingPluginChannel(Main.getInstance(), "BungeeCord", Multiserver.instance);
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(Main.getInstance(), "BungeeCord");
|
||||
}
|
||||
|
||||
@ -39,7 +39,9 @@ public final class Main extends JavaPlugin {
|
||||
@Override
|
||||
public void onDisable() {
|
||||
FakeplayerManager.instance.removeAll();
|
||||
UsedIdRepository.instance.save();
|
||||
UsedIdRepository.instance.saveAll();
|
||||
FakeplayerManager.instance.onDisable();
|
||||
Multiserver.instance.onDisable();
|
||||
|
||||
{
|
||||
getServer().getMessenger().unregisterIncomingPluginChannel(this);
|
||||
|
@ -11,6 +11,7 @@ import io.github.hello09x.fakeplayer.manager.FakeplayerManager;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -23,19 +24,11 @@ public abstract class AbstractCommand {
|
||||
|
||||
public static Argument<Player> targetArgument(@NotNull String nodeName) {
|
||||
return new CustomArgument<>(new StringArgument(nodeName), info -> {
|
||||
var sender = info.sender();
|
||||
var name = info.currentInput();
|
||||
var target = sender.isOp()
|
||||
? FakeplayerManager.instance.get(name)
|
||||
: FakeplayerManager.instance.get(sender, name);
|
||||
|
||||
var target = tryGetTarget(info.sender(), info.currentInput());
|
||||
if (target == null) {
|
||||
var targets = FakeplayerManager.instance.getAll(sender);
|
||||
if (targets.size() != 1) {
|
||||
throw CustomArgument.CustomArgumentException.fromString("你需要指定假人");
|
||||
}
|
||||
target = targets.get(0);
|
||||
throw CustomArgument.CustomArgumentException.fromString("你需要指定假人");
|
||||
}
|
||||
|
||||
return target;
|
||||
}).replaceSuggestions(ArgumentSuggestions.strings(info -> {
|
||||
var sender = info.sender();
|
||||
@ -59,21 +52,17 @@ public abstract class AbstractCommand {
|
||||
var sender = info.sender();
|
||||
var name = info.currentInput();
|
||||
|
||||
if (name.equals("--all")) {
|
||||
if (name.equals("--all") || name.equals("-a")) {
|
||||
return sender.isOp()
|
||||
? FakeplayerManager.instance.getAll()
|
||||
: FakeplayerManager.instance.getAll(sender);
|
||||
}
|
||||
|
||||
var one = sender.isOp()
|
||||
? FakeplayerManager.instance.get(name)
|
||||
: FakeplayerManager.instance.get(sender, name);
|
||||
var target = tryGetTarget(sender, name);
|
||||
return target == null
|
||||
? Collections.emptyList()
|
||||
: Collections.singletonList(target);
|
||||
|
||||
if (one == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.singletonList(one);
|
||||
}).replaceSuggestions(ArgumentSuggestions.strings(info -> {
|
||||
var sender = info.sender();
|
||||
var arg = info.currentArg().toLowerCase();
|
||||
@ -82,16 +71,26 @@ public abstract class AbstractCommand {
|
||||
? FakeplayerManager.instance.getAll()
|
||||
: FakeplayerManager.instance.getAll(sender);
|
||||
|
||||
var names = fakes.stream().map(Player::getName);
|
||||
var names = Stream.concat(fakes.stream().map(Player::getName), Stream.of("-a", "--all"));
|
||||
if (!arg.isEmpty()) {
|
||||
names = names.filter(n -> n.toLowerCase().contains(arg));
|
||||
}
|
||||
|
||||
names = Stream.concat(Stream.of("--all"), names);
|
||||
return names.toArray(String[]::new);
|
||||
}));
|
||||
}
|
||||
|
||||
private static @Nullable Player tryGetTarget(@NotNull CommandSender sender, @NotNull String name) {
|
||||
if (name.isBlank()) {
|
||||
var targets = FakeplayerManager.instance.getAll(sender);
|
||||
return targets.size() == 1 ? targets.get(0) : null;
|
||||
} else {
|
||||
return sender.isOp()
|
||||
? FakeplayerManager.instance.get(name)
|
||||
: FakeplayerManager.instance.get(sender, name);
|
||||
}
|
||||
}
|
||||
|
||||
protected @NotNull Player getTarget(@NotNull CommandSender sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException {
|
||||
return Optional
|
||||
.ofNullable((Player) args.getUnchecked("target"))
|
||||
|
@ -2,6 +2,7 @@ package io.github.hello09x.fakeplayer.command;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.arguments.IntegerArgument;
|
||||
import dev.jorel.commandapi.arguments.LocationArgument;
|
||||
import dev.jorel.commandapi.arguments.MultiLiteralArgument;
|
||||
import dev.jorel.commandapi.executors.CommandExecutor;
|
||||
import io.github.hello09x.fakeplayer.entity.action.Action;
|
||||
@ -16,6 +17,7 @@ import static io.github.hello09x.fakeplayer.command.AbstractCommand.targetArgume
|
||||
public class Commands {
|
||||
|
||||
private final static String PERMISSION_SPAWN = "fakeplayer.spawn";
|
||||
private final static String PERMISSION_SPAWN_LOCATION = "fakeplayer.spawn.location";
|
||||
private final static String PERMISSION_PROFILE = "fakeplayer.profile";
|
||||
private final static String PERMISSION_TP = "fakeplayer.tp";
|
||||
private final static String PERMISSION_EXP = "fakeplayer.exp";
|
||||
@ -31,7 +33,7 @@ public class Commands {
|
||||
"fakeplayer 可以用来创建一个模拟为玩家的假人, 能保持附近区块的刷新、触发怪物生成。同时还提供了一些操作命令让你控制假人的物品、动作等等。"
|
||||
)
|
||||
.withUsage(
|
||||
"§6/fp create §7- §f创建假人",
|
||||
"§6/fp spawn §7- §f创建假人",
|
||||
"§6/fp kill [假人] §7- §f移除假人",
|
||||
"§6/fp list [页码] [数量] §7- §f查看所有假人",
|
||||
"§6/fp tp [假人] §7- §f传送到假人身边",
|
||||
@ -45,8 +47,9 @@ public class Commands {
|
||||
"§6/fp drop [假人] [-a|--all] §7- §f丢弃手上物品",
|
||||
"§6/fp dropinv [假人] §7- §f丢弃背包物品",
|
||||
"§6/fp sneak [假人] §7- §f开启/取消潜行",
|
||||
"§6/fp attack <once|continuous|interval|stop> [假人] §7- §f鼠标左键",
|
||||
"§6/fp use <once|continuous|interval|stop> [假人] §7- §f鼠标右键"
|
||||
"§6/fp attack <once|continuous|interval|stop> [假人] §7- §f模拟鼠标左键",
|
||||
"§6/fp use <once|continuous|interval|stop> [假人] §7- §f模拟鼠标右键",
|
||||
"§6/fp reload §7- §f重载配置文件"
|
||||
)
|
||||
.withSubcommands(
|
||||
new CommandAPICommand("help")
|
||||
@ -54,9 +57,10 @@ public class Commands {
|
||||
.withOptionalArguments(new IntegerArgument("page", 1))
|
||||
.executesPlayer(HelpCommand.instance::help),
|
||||
|
||||
new CommandAPICommand("create")
|
||||
new CommandAPICommand("spawn")
|
||||
.withPermission(PERMISSION_SPAWN)
|
||||
.executesPlayer(SpawnCommand.instance::create),
|
||||
.withOptionalArguments(new LocationArgument("location").withPermission(PERMISSION_SPAWN_LOCATION))
|
||||
.executes(SpawnCommand.instance::spawn),
|
||||
new CommandAPICommand("kill")
|
||||
.withPermission(PERMISSION_SPAWN)
|
||||
.withOptionalArguments(multiTargetArgument("targets"))
|
||||
@ -65,6 +69,10 @@ public class Commands {
|
||||
.withPermission(PERMISSION_SPAWN)
|
||||
.withOptionalArguments(new IntegerArgument("page", 1), new IntegerArgument("size", 1))
|
||||
.executes(SpawnCommand.instance::list),
|
||||
new CommandAPICommand("distance")
|
||||
.withPermission(PERMISSION_SPAWN)
|
||||
.withOptionalArguments(targetArgument("target"))
|
||||
.executesPlayer(SpawnCommand.instance::distance),
|
||||
|
||||
new CommandAPICommand("exp")
|
||||
.withPermission(PERMISSION_PROFILE)
|
||||
@ -96,8 +104,7 @@ public class Commands {
|
||||
new CommandAPICommand("set")
|
||||
.withArguments(
|
||||
ConfigCommand.configArgument("config"),
|
||||
ConfigCommand.configValueArgument("config", "value")
|
||||
)
|
||||
ConfigCommand.configValueArgument("config", "value"))
|
||||
.executesPlayer(ConfigCommand.instance::setConfig)
|
||||
),
|
||||
new CommandAPICommand("attack")
|
||||
@ -110,8 +117,7 @@ public class Commands {
|
||||
.withPermission(PERMISSION_ACTION)
|
||||
.withOptionalArguments(
|
||||
targetArgument("target"),
|
||||
new MultiLiteralArgument("all", List.of("-a", "--all"))
|
||||
)
|
||||
new MultiLiteralArgument("all", List.of("-a", "--all")))
|
||||
.executes((CommandExecutor) (sender, args) -> ActionCommand.instance.action(
|
||||
sender,
|
||||
args,
|
||||
@ -155,8 +161,7 @@ public class Commands {
|
||||
new CommandAPICommand("interval")
|
||||
.withOptionalArguments(
|
||||
new IntegerArgument("interval", 1),
|
||||
targetArgument("target")
|
||||
)
|
||||
targetArgument("target"))
|
||||
.executes((sender, args) -> {
|
||||
int interval = (int) args.getOptional("interval").orElse(1);
|
||||
ActionCommand.instance.action(sender, args, action, ActionSetting.interval(interval));
|
||||
|
@ -2,6 +2,7 @@ package io.github.hello09x.fakeplayer.command;
|
||||
|
||||
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import io.github.hello09x.fakeplayer.util.MathUtils;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.attribute.AttributeInstance;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -58,17 +59,12 @@ public class ProfileCommand extends AbstractCommand {
|
||||
sender.sendMessage(textOfChildren(
|
||||
text(target.getName()),
|
||||
text(" 当前生命值: ", GRAY),
|
||||
text(round(health, 0.5), color),
|
||||
text(MathUtils.round(health, 0.5), color),
|
||||
text("/", color),
|
||||
text(max, color)
|
||||
));
|
||||
}
|
||||
|
||||
private static double round(double num, double base) {
|
||||
if (num % base == 0) {
|
||||
return num;
|
||||
}
|
||||
return Math.floor(num / base) * base;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,48 +2,85 @@ package io.github.hello09x.fakeplayer.command;
|
||||
|
||||
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import io.github.hello09x.fakeplayer.util.MathUtils;
|
||||
import io.github.tanyaofei.plugin.toolkit.database.Page;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.Component.textOfChildren;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.WHITE;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.*;
|
||||
|
||||
public class SpawnCommand extends AbstractCommand {
|
||||
|
||||
public final static SpawnCommand instance = new SpawnCommand();
|
||||
|
||||
public void create(@NotNull Player sender, CommandArguments args) {
|
||||
var fakePlayer = fakeplayerManager.spawn(sender, sender.getLocation().clone());
|
||||
private static String toLocationString(@NotNull Location location) {
|
||||
return location.getWorld().getName()
|
||||
+ " 世界: "
|
||||
+ StringUtils.joinWith(", ",
|
||||
MathUtils.round(location.getX(), 0.5),
|
||||
MathUtils.round(location.getY(), 0.5),
|
||||
MathUtils.round(location.getZ(), 0.5));
|
||||
|
||||
}
|
||||
|
||||
public void spawn(@NotNull CommandSender sender, CommandArguments args) {
|
||||
var location = (Location) args.get("location");
|
||||
if (location == null) {
|
||||
if (sender instanceof Player p) {
|
||||
location = p.getLocation();
|
||||
} else {
|
||||
location = Bukkit.getServer().getWorlds().get(0).getSpawnLocation();
|
||||
}
|
||||
}
|
||||
|
||||
var fakePlayer = fakeplayerManager.spawn(sender, location.clone());
|
||||
if (fakePlayer != null) {
|
||||
sender.sendMessage(textOfChildren(
|
||||
text("你创建了假人 ", GRAY),
|
||||
text(fakePlayer.getName())
|
||||
text(fakePlayer.getName()),
|
||||
text(", 位于 ", GRAY),
|
||||
text(toLocationString(fakePlayer.getLocation()))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public void kill(@NotNull CommandSender sender, CommandArguments args) throws WrapperCommandSyntaxException {
|
||||
public void kill(@NotNull CommandSender sender, CommandArguments args) {
|
||||
@SuppressWarnings("unchecked")
|
||||
var targets = (List<Player>) Optional.ofNullable(args.get("targets")).orElse(Collections.emptyList());
|
||||
var targets = (List<Player>) args.get("targets");
|
||||
if (targets == null) {
|
||||
var reserved = fakeplayerManager.getAll(sender);
|
||||
if (reserved.size() == 1) {
|
||||
targets = Collections.singletonList(reserved.get(0));
|
||||
} else {
|
||||
targets = Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
if (targets.isEmpty()) {
|
||||
sender.sendMessage(text("没有移除任何假人", GRAY));
|
||||
return;
|
||||
}
|
||||
|
||||
var names = new StringJoiner(", ");
|
||||
for (var target : targets) {
|
||||
if (fakeplayerManager.remove(target.getName())) {
|
||||
count++;
|
||||
names.add(target.getName());
|
||||
}
|
||||
}
|
||||
sender.sendMessage(textOfChildren(
|
||||
text("你移除了 ", GRAY),
|
||||
text(count, WHITE),
|
||||
text(" 个假人", GRAY)
|
||||
text("你移除了假人: ", GRAY),
|
||||
text(names.toString())
|
||||
));
|
||||
}
|
||||
|
||||
@ -67,13 +104,39 @@ public class SpawnCommand extends AbstractCommand {
|
||||
|
||||
sender.sendMessage(p.toComponent(
|
||||
"假人",
|
||||
record -> textOfChildren(
|
||||
text(record.getName()),
|
||||
text(" - "),
|
||||
text(Optional.ofNullable(fakeplayerManager.getCreator(record)).orElse("<不在线>"))
|
||||
fakeplayer -> textOfChildren(
|
||||
text(fakeplayer.getName() + " (" + fakeplayerManager.getCreator(fakeplayer) + ")", GOLD),
|
||||
text(" - ", GRAY),
|
||||
text(toLocationString(fakeplayer.getLocation()), WHITE),
|
||||
text(" [<--传送]", AQUA).clickEvent(ClickEvent.runCommand("/fp tp " + fakeplayer.getName())),
|
||||
text(" [<--移除]", RED).clickEvent(ClickEvent.runCommand("/fp kill " + fakeplayer.getName()))
|
||||
),
|
||||
String.format("/fp list %d %d", page - 1, size),
|
||||
String.format("/fp list %d %d", page + 1, size)
|
||||
));
|
||||
}
|
||||
|
||||
public void distance(@NotNull Player sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException {
|
||||
var target = getTarget(sender, args);
|
||||
var location1 = target.getLocation();
|
||||
var location2 = sender.getLocation();
|
||||
if (!location2.getWorld().equals(location1.getWorld())) {
|
||||
sender.sendMessage(textOfChildren(
|
||||
text("你离 ", GRAY),
|
||||
text(target.getName()),
|
||||
text(" 十分遥远", GRAY)
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
var distance = location1.distance(location2);
|
||||
sender.sendMessage(textOfChildren(
|
||||
text("你与 "),
|
||||
text(target.getName()),
|
||||
text(" 相距 "),
|
||||
text(MathUtils.round(distance, 0.5), WHITE)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
package io.github.hello09x.fakeplayer.entity;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum FakeplayerMetadata {
|
||||
|
||||
CREATOR("creator"),
|
||||
CREATOR_IP("creator-ip"),
|
||||
NAME_SOURCE("name-source"),
|
||||
NAME_SEQUENCE("name-sequence"),
|
||||
ACTION_TASK_ID("action-task-id");
|
||||
|
||||
public final String key;
|
||||
|
||||
FakeplayerMetadata(@NotNull String key) {
|
||||
this.key = "fakeplayer:" + key;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package io.github.hello09x.fakeplayer.entity;
|
||||
|
||||
import io.github.hello09x.fakeplayer.Main;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public enum Metadatas {
|
||||
|
||||
CREATOR("creator"),
|
||||
CREATOR_IP("creator-ip"),
|
||||
NAME_SOURCE("name-source"),
|
||||
NAME_SEQUENCE("name-sequence"),
|
||||
ACTION_TASK_ID("action-task-id");
|
||||
|
||||
public final String key;
|
||||
|
||||
Metadatas(@NotNull String key) {
|
||||
this.key = "fakeplayer:" + key;
|
||||
}
|
||||
|
||||
public void set(@NotNull Player player, @NotNull Object value) {
|
||||
player.setMetadata(this.key, new FixedMetadataValue(Main.getInstance(), value));
|
||||
}
|
||||
|
||||
public void remove(@NotNull Player player) {
|
||||
if (player.hasMetadata(this.key)) {
|
||||
player.removeMetadata(this.key, Main.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull MetadataValue get(@NotNull Player player) {
|
||||
return player.getMetadata(this.key).get(0);
|
||||
}
|
||||
|
||||
public @NotNull Optional<MetadataValue> getOptional(@NotNull Player player) {
|
||||
var metadata = player.getMetadata(this.key);
|
||||
if (metadata.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(metadata.get(0));
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package io.github.hello09x.fakeplayer.entity.action;
|
||||
|
||||
import io.github.hello09x.fakeplayer.Main;
|
||||
import io.github.hello09x.fakeplayer.util.UnwrapUtils;
|
||||
import io.github.hello09x.fakeplayer.util.Unwrapper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
@ -36,7 +36,7 @@ public class PlayerActionManager {
|
||||
) {
|
||||
var managers = MANAGERS.computeIfAbsent(player.getUniqueId(), key -> new HashMap<>());
|
||||
var manager = managers.computeIfAbsent(action, key -> new ActionManager(
|
||||
UnwrapUtils.getServerPlayer(player),
|
||||
Unwrapper.getServerPlayer(player),
|
||||
action,
|
||||
setting
|
||||
));
|
||||
|
@ -2,26 +2,22 @@ package io.github.hello09x.fakeplayer.manager;
|
||||
|
||||
import io.github.hello09x.fakeplayer.Main;
|
||||
import io.github.hello09x.fakeplayer.entity.FakePlayer;
|
||||
import io.github.hello09x.fakeplayer.entity.FakeplayerMetadata;
|
||||
import io.github.hello09x.fakeplayer.entity.Metadatas;
|
||||
import io.github.hello09x.fakeplayer.entity.action.Action;
|
||||
import io.github.hello09x.fakeplayer.optional.BungeeCordServer;
|
||||
import io.github.hello09x.fakeplayer.optional.Multiserver;
|
||||
import io.github.hello09x.fakeplayer.properties.FakeplayerProperties;
|
||||
import io.github.hello09x.fakeplayer.repository.UsedIdRepository;
|
||||
import io.github.hello09x.fakeplayer.repository.UserConfigRepository;
|
||||
import io.github.hello09x.fakeplayer.repository.model.Configs;
|
||||
import io.github.hello09x.fakeplayer.util.AddressUtils;
|
||||
import io.github.hello09x.fakeplayer.util.MetadataUtils;
|
||||
import io.github.hello09x.fakeplayer.util.UnwrapUtils;
|
||||
import io.github.hello09x.fakeplayer.util.Unwrapper;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -29,6 +25,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -51,60 +50,47 @@ public class FakeplayerManager {
|
||||
|
||||
private final UserConfigRepository userConfigRepository = UserConfigRepository.instance;
|
||||
|
||||
private final BungeeCordServer bungee = BungeeCordServer.instance;
|
||||
private final Multiserver multiserver = Multiserver.instance;
|
||||
|
||||
private final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
private FakeplayerManager() {
|
||||
var timer = new Timer();
|
||||
|
||||
// 服务器 tps 过低删除所有假人
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (Bukkit.getServer().getTPS()[1] < properties.getKaleTps()) {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (removeAll() > 0) {
|
||||
Bukkit.getServer().broadcast(text("[服务器过于卡顿, 已移除所有假人]").style(Style.style(RED, ITALIC)));
|
||||
timer.scheduleAtFixedRate(() -> {
|
||||
if (Bukkit.getServer().getTPS()[1] < properties.getKaleTps()) {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (removeAll() > 0) {
|
||||
Bukkit.getServer().broadcast(text("[服务器过于卡顿, 已移除所有假人]").style(Style.style(RED, ITALIC)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTask(Main.getInstance());
|
||||
}
|
||||
}
|
||||
}, 60_000, 60_000);
|
||||
|
||||
// 移除下线的
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!properties.isFollowQuiting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var group = getAll()
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(FakeplayerManager.this::getCreator));
|
||||
|
||||
for (var entry : group.entrySet()) {
|
||||
if (bungee.isPlayerOnline(entry.getKey())) {
|
||||
continue;
|
||||
}.runTask(Main.getInstance());
|
||||
}
|
||||
}, 0, 60, TimeUnit.SECONDS
|
||||
);
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (var fakePlayer : entry.getValue()) {
|
||||
remove(fakePlayer.getName());
|
||||
}
|
||||
log.info(String.format("玩家 %s 已不在线, 已移除 %d 个假人", entry.getKey(), entry.getValue().size()));
|
||||
}
|
||||
}.runTask(Main.getInstance());
|
||||
timer.scheduleAtFixedRate(() -> {
|
||||
@SuppressWarnings("all")
|
||||
var group = getAll()
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(FakeplayerManager.this::getCreator));
|
||||
|
||||
for (var entry : group.entrySet()) {
|
||||
if (multiserver.isPlayerOnline(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (var fakePlayer : entry.getValue()) {
|
||||
remove(fakePlayer.getName());
|
||||
}
|
||||
log.info(String.format("玩家 %s 已不在线, 已移除 %d 个假人", entry.getKey(), entry.getValue().size()));
|
||||
}
|
||||
}.runTask(Main.getInstance());
|
||||
}
|
||||
}, 15_000, 15_000);
|
||||
|
||||
}, 0, 15, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,7 +120,7 @@ public class FakeplayerManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
var name = nameManager.take(creator);
|
||||
var seqname = nameManager.take(creator);
|
||||
boolean invulnerable = true, lookAtEntity = true, collidable = true, pickupItems = true;
|
||||
if (creator instanceof Player p) {
|
||||
var creatorId = p.getUniqueId();
|
||||
@ -147,22 +133,21 @@ public class FakeplayerManager {
|
||||
var player = new FakePlayer(
|
||||
creator.getName(),
|
||||
((CraftServer) Bukkit.getServer()).getServer(),
|
||||
generateId(name.name()),
|
||||
name.name(),
|
||||
generateId(seqname.name()),
|
||||
seqname.name(),
|
||||
spawnAt
|
||||
);
|
||||
|
||||
var bukkitPlayer = player.getBukkitPlayer();
|
||||
bukkitPlayer.setMetadata(FakeplayerMetadata.CREATOR.key, new FixedMetadataValue(Main.getInstance(), creator.getName()));
|
||||
bukkitPlayer.setMetadata(FakeplayerMetadata.CREATOR_IP.key, new FixedMetadataValue(Main.getInstance(), AddressUtils.getAddress(creator)));
|
||||
bukkitPlayer.setMetadata(FakeplayerMetadata.NAME_SOURCE.key, new FixedMetadataValue(Main.getInstance(), name.source()));
|
||||
bukkitPlayer.setMetadata(FakeplayerMetadata.NAME_SEQUENCE.key, new FixedMetadataValue(Main.getInstance(), name.sequence()));
|
||||
Metadatas.CREATOR.set(bukkitPlayer, creator.getName());
|
||||
Metadatas.CREATOR_IP.set(bukkitPlayer, AddressUtils.getAddress(creator));
|
||||
Metadatas.NAME_SOURCE.set(bukkitPlayer, seqname.source());
|
||||
Metadatas.NAME_SEQUENCE.set(bukkitPlayer, seqname.sequence());
|
||||
bukkitPlayer.playerListName(text(creator.getName() + "的假人").style(Style.style(GRAY, ITALIC)));
|
||||
|
||||
player.spawn(invulnerable, collidable, lookAtEntity, pickupItems);
|
||||
|
||||
usedIdRepository.add(bukkitPlayer.getUniqueId());
|
||||
|
||||
dispatchCommands(bukkitPlayer, properties.getPreparingCommands());
|
||||
performCommands(bukkitPlayer);
|
||||
|
||||
@ -245,9 +230,7 @@ public class FakeplayerManager {
|
||||
* @return 假人的创建者
|
||||
*/
|
||||
public @Nullable String getCreator(@NotNull Player fakePlayer) {
|
||||
return Optional.ofNullable(MetadataUtils.getFirst(fakePlayer, FakeplayerMetadata.CREATOR.key))
|
||||
.map(MetadataValue::asString)
|
||||
.orElse(null);
|
||||
return Metadatas.CREATOR.getOptional(fakePlayer).map(MetadataValue::asString).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -269,44 +252,21 @@ public class FakeplayerManager {
|
||||
.getServer()
|
||||
.getOnlinePlayers()
|
||||
.stream()
|
||||
.filter(p -> !p.getMetadata(FakeplayerMetadata.CREATOR.key).isEmpty())
|
||||
.filter(p -> Metadatas.CREATOR.getOptional(p).isPresent())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void openInventory(@NotNull Player player, @NotNull Player fakePlayer) {
|
||||
if (!isFake(fakePlayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.showTitle(Title.title(
|
||||
text("取物品有概率消失", RED),
|
||||
text("尽量使用 Shift + 左键取物品"),
|
||||
Title.Times.times(Ticks.duration(10), Ticks.duration(20), Ticks.duration(20))
|
||||
));
|
||||
|
||||
var inv = fakePlayer.getInventory();
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
public void cleanup(@NotNull Player fakePlayer) {
|
||||
if (!isFake(fakePlayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var metas = MetadataUtils.get(fakePlayer, FakeplayerMetadata.NAME_SOURCE.key, FakeplayerMetadata.NAME_SEQUENCE.key);
|
||||
var source = metas[0];
|
||||
var sequence = metas[1];
|
||||
nameManager.giveback(source.asString(), sequence.asInt());
|
||||
|
||||
Action.dropInventory(UnwrapUtils.getServerPlayer(fakePlayer));
|
||||
|
||||
Arrays.stream(FakeplayerMetadata.values()).map(m -> m.key).forEach(
|
||||
key -> {
|
||||
if (fakePlayer.hasMetadata(key)) {
|
||||
fakePlayer.removeMetadata(key, Main.getInstance());
|
||||
}
|
||||
}
|
||||
nameManager.giveback(
|
||||
Metadatas.NAME_SOURCE.get(fakePlayer).asString(),
|
||||
Metadatas.NAME_SEQUENCE.get(fakePlayer).asInt()
|
||||
);
|
||||
Arrays.stream(Metadatas.values()).forEach(meta -> meta.remove(fakePlayer));
|
||||
Action.dropInventory(Unwrapper.getServerPlayer(fakePlayer));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -321,9 +281,7 @@ public class FakeplayerManager {
|
||||
.getServer()
|
||||
.getOnlinePlayers()
|
||||
.stream()
|
||||
.filter(p -> p.getMetadata(FakeplayerMetadata.CREATOR.key)
|
||||
.stream()
|
||||
.anyMatch(meta -> meta.asString().equals(name)))
|
||||
.filter(p -> Metadatas.CREATOR.getOptional(p).filter(c -> c.asString().equals(name)).isPresent())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@ -334,7 +292,7 @@ public class FakeplayerManager {
|
||||
* @return 是否是假人
|
||||
*/
|
||||
public boolean isFake(@NotNull Player player) {
|
||||
return !player.getMetadata(FakeplayerMetadata.CREATOR.key).isEmpty();
|
||||
return Metadatas.CREATOR.getOptional(player).isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -347,7 +305,7 @@ public class FakeplayerManager {
|
||||
return Bukkit.getServer()
|
||||
.getOnlinePlayers()
|
||||
.stream()
|
||||
.filter(p -> p.getMetadata(FakeplayerMetadata.CREATOR_IP.key).stream().anyMatch(meta -> meta.asString().equals(address)))
|
||||
.filter(p -> Metadatas.CREATOR_IP.getOptional(p).map(MetadataValue::asString).filter(v -> v.equals(address)).isPresent())
|
||||
.count();
|
||||
}
|
||||
|
||||
@ -360,7 +318,7 @@ public class FakeplayerManager {
|
||||
var uuid = UUID.nameUUIDFromBytes(name.getBytes(StandardCharsets.UTF_8));
|
||||
if (Bukkit.getServer().getOfflinePlayer(uuid).hasPlayedBefore()) {
|
||||
uuid = UUID.randomUUID();
|
||||
log.warning("Could not generate a UUID bound with name which is never used at this server, using random UUID as fallback: " + uuid);
|
||||
log.warning("Could not generate a UUID bound with name which is never played at this server, using random UUID as fallback: " + uuid);
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
@ -414,5 +372,8 @@ public class FakeplayerManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
this.timer.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ public class NameManager {
|
||||
|
||||
private final static Logger log = Main.getInstance().getLogger();
|
||||
|
||||
public GeneratedName take(CommandSender creator) {
|
||||
public SequenceName take(CommandSender creator) {
|
||||
var source = properties.getNameTemplate();
|
||||
if (source.isBlank()) {
|
||||
source = creator.getName();
|
||||
@ -45,7 +45,7 @@ public class NameManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
return new GeneratedName(
|
||||
return new SequenceName(
|
||||
source,
|
||||
seq,
|
||||
name
|
||||
@ -54,7 +54,7 @@ public class NameManager {
|
||||
|
||||
var name = "FAKE_" + RandomStringUtils.random(11, 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);
|
||||
return new GeneratedName("random", 0, name);
|
||||
return new SequenceName("random", 0, name);
|
||||
}
|
||||
|
||||
public void giveback(@NotNull String source, @NotNull Integer sequence) {
|
||||
@ -62,7 +62,7 @@ public class NameManager {
|
||||
}
|
||||
|
||||
|
||||
public record GeneratedName(
|
||||
public record SequenceName(
|
||||
String source,
|
||||
Integer sequence,
|
||||
String name
|
||||
|
@ -2,28 +2,29 @@ package io.github.hello09x.fakeplayer.optional;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import io.github.hello09x.fakeplayer.Main;
|
||||
import io.github.hello09x.fakeplayer.manager.FakeplayerManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BungeeCordServer implements PluginMessageListener {
|
||||
public class Multiserver implements PluginMessageListener {
|
||||
|
||||
|
||||
public final static BungeeCordServer instance = new BungeeCordServer();
|
||||
public final static Multiserver instance = new Multiserver();
|
||||
|
||||
private final Set<String> onlinePlayers = new HashSet<>();
|
||||
|
||||
public BungeeCordServer() {
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
refreshOnlinePlayersAsynchronously();
|
||||
}
|
||||
}, 0, 10_000);
|
||||
private final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
public Multiserver() {
|
||||
timer.scheduleAtFixedRate(this::refreshOnlinePlayersAsynchronously, 0, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public boolean isPlayerOnline(@NotNull String name) {
|
||||
@ -61,7 +62,6 @@ public class BungeeCordServer implements PluginMessageListener {
|
||||
.getServer()
|
||||
.getOnlinePlayers()
|
||||
.stream()
|
||||
.filter(p -> !FakeplayerManager.instance.isFake(p))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
|
||||
@ -79,5 +79,9 @@ public class BungeeCordServer implements PluginMessageListener {
|
||||
);
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
this.timer.shutdown();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -58,7 +58,7 @@ public class UsedIdRepository {
|
||||
}
|
||||
}
|
||||
|
||||
public void save() {
|
||||
public void saveAll() {
|
||||
var folder = Main.getInstance().getDataFolder();
|
||||
if (!folder.exists() && !folder.mkdirs()) {
|
||||
return;
|
||||
|
@ -0,0 +1,14 @@
|
||||
package io.github.hello09x.fakeplayer.util;
|
||||
|
||||
public class MathUtils {
|
||||
|
||||
|
||||
public static double round(double num, double base) {
|
||||
if (num % base == 0) {
|
||||
return num;
|
||||
}
|
||||
return Math.floor(num / base) * base;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package io.github.hello09x.fakeplayer.util;
|
||||
|
||||
import net.minecraft.data.DataProvider;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.metadata.Metadatable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.table.TableRowSorter;
|
||||
|
||||
public class MetadataUtils {
|
||||
|
||||
public static @Nullable MetadataValue getFirst(@NotNull Metadatable keeper, @NotNull String key) {
|
||||
var meta = keeper.getMetadata(key);
|
||||
if (meta.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return meta.get(0);
|
||||
}
|
||||
|
||||
public static @NotNull MetadataValue[] get(@NotNull Metadatable keeper, String... keys) {
|
||||
if (keys.length == 0) {
|
||||
return new MetadataValue[0];
|
||||
}
|
||||
|
||||
var ret = new MetadataValue[keys.length];
|
||||
int i = 0;
|
||||
for(var key: keys) {
|
||||
var meta = keeper.getMetadata(key);
|
||||
if (meta.isEmpty()) {
|
||||
throw new IllegalArgumentException(String.format("Could not find metadata key named '%s' from '%s'", key, keeper));
|
||||
}
|
||||
ret[i++] = meta.get(0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,7 @@ import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class UnwrapUtils {
|
||||
public class Unwrapper {
|
||||
|
||||
public static @NotNull ServerPlayer getServerPlayer(@NotNull Player player) {
|
||||
return ((CraftPlayer) player).getHandle();
|
@ -16,7 +16,11 @@ permissions:
|
||||
default: op
|
||||
|
||||
fakeplayer.spawn:
|
||||
description: '拥有 create, kill, list 命令权限'
|
||||
description: '拥有 spawn, kill, list 命令权限'
|
||||
default: op
|
||||
|
||||
fakeplayer.spawn.location:
|
||||
description: '使用 spawn 命令时可以指定出生点'
|
||||
default: op
|
||||
|
||||
fakeplayer.tp:
|
||||
|
Loading…
Reference in New Issue
Block a user