优化代码

This commit is contained in:
tanyaofei 2023-07-27 15:16:29 +08:00
parent 03c45c6b88
commit 340a6b701c
16 changed files with 275 additions and 239 deletions

View File

@ -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);

View File

@ -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"))

View File

@ -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));

View File

@ -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;
}
}

View File

@ -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)
));
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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
));

View File

@ -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();
}
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -58,7 +58,7 @@ public class UsedIdRepository {
}
}
public void save() {
public void saveAll() {
var folder = Main.getInstance().getDataFolder();
if (!folder.exists() && !folder.mkdirs()) {
return;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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: