mirror of
https://github.com/tanyaofei/minecraft-fakeplayer.git
synced 2025-07-13 21:02:27 +08:00
Lifecycle commands
This commit is contained in:
parent
a4961e09b3
commit
e050f8772a
@ -12,8 +12,8 @@
|
|||||||
<artifactId>fakeplayer-api</artifactId>
|
<artifactId>fakeplayer-api</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
package io.github.hello09x.fakeplayer.api.event;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.Cancellable;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.bukkit.event.player.PlayerEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public class FakePlayerSpawnEvent extends PlayerEvent implements Cancellable {
|
|
||||||
|
|
||||||
private final static HandlerList HANDLERS = new HandlerList();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Getter
|
|
||||||
private final CommandSender creator;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Getter
|
|
||||||
private Result result = Result.ALLOW;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Getter
|
|
||||||
private Component reason = Component.empty();
|
|
||||||
|
|
||||||
public FakePlayerSpawnEvent(@NotNull CommandSender creator, @NotNull Player who) {
|
|
||||||
super(who);
|
|
||||||
this.creator = creator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @NotNull HandlerList getHandlerList() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull HandlerList getHandlers() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return this.result != Result.ALLOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cancel true if you wish to cancel this event
|
|
||||||
* @deprecated 请使用 {@link #disallow(Component)} (Result, Component)}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public void setCancelled(boolean cancel) {
|
|
||||||
this.disallow(Component.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void allow() {
|
|
||||||
this.result = Result.ALLOW;
|
|
||||||
this.reason = Component.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disallow(@NotNull Component reason) {
|
|
||||||
this.result = Result.DISALLOW;
|
|
||||||
this.reason = reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Result {
|
|
||||||
|
|
||||||
ALLOW,
|
|
||||||
|
|
||||||
DISALLOW
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -12,8 +12,8 @@
|
|||||||
<artifactId>fakeplayer-core</artifactId>
|
<artifactId>fakeplayer-core</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import io.github.hello09x.devtools.core.utils.Exceptions;
|
|||||||
import io.github.hello09x.devtools.database.DatabaseModule;
|
import io.github.hello09x.devtools.database.DatabaseModule;
|
||||||
import io.github.hello09x.fakeplayer.core.command.CommandRegistry;
|
import io.github.hello09x.fakeplayer.core.command.CommandRegistry;
|
||||||
import io.github.hello09x.fakeplayer.core.config.FakeplayerConfig;
|
import io.github.hello09x.fakeplayer.core.config.FakeplayerConfig;
|
||||||
|
import io.github.hello09x.fakeplayer.core.listener.FakeplayerLifecycleListener;
|
||||||
import io.github.hello09x.fakeplayer.core.listener.FakeplayerListener;
|
import io.github.hello09x.fakeplayer.core.listener.FakeplayerListener;
|
||||||
import io.github.hello09x.fakeplayer.core.listener.PlayerListener;
|
import io.github.hello09x.fakeplayer.core.listener.PlayerListener;
|
||||||
import io.github.hello09x.fakeplayer.core.listener.ReplenishListener;
|
import io.github.hello09x.fakeplayer.core.listener.ReplenishListener;
|
||||||
@ -58,6 +59,7 @@ public final class Main extends JavaPlugin {
|
|||||||
{
|
{
|
||||||
var manager = getServer().getPluginManager();
|
var manager = getServer().getPluginManager();
|
||||||
manager.registerEvents(injector.getInstance(PlayerListener.class), this);
|
manager.registerEvents(injector.getInstance(PlayerListener.class), this);
|
||||||
|
manager.registerEvents(injector.getInstance(FakeplayerLifecycleListener.class), this);
|
||||||
manager.registerEvents(injector.getInstance(FakeplayerListener.class), this);
|
manager.registerEvents(injector.getInstance(FakeplayerListener.class), this);
|
||||||
manager.registerEvents(injector.getInstance(ReplenishListener.class), this);
|
manager.registerEvents(injector.getInstance(ReplenishListener.class), this);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package io.github.hello09x.fakeplayer.core.command;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import dev.jorel.commandapi.CommandPermission;
|
import dev.jorel.commandapi.CommandPermission;
|
||||||
import io.github.hello09x.devtools.command.exception.HelpCommand;
|
import io.github.hello09x.devtools.command.HelpCommand;
|
||||||
import io.github.hello09x.devtools.core.utils.ComponentUtils;
|
import io.github.hello09x.devtools.core.utils.ComponentUtils;
|
||||||
import io.github.hello09x.fakeplayer.api.spi.Action;
|
import io.github.hello09x.fakeplayer.api.spi.Action;
|
||||||
import io.github.hello09x.fakeplayer.core.command.impl.*;
|
import io.github.hello09x.fakeplayer.core.command.impl.*;
|
||||||
@ -15,7 +15,7 @@ import org.bukkit.entity.LivingEntity;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static io.github.hello09x.devtools.command.exception.Commands.*;
|
import static io.github.hello09x.devtools.command.Commands.*;
|
||||||
import static io.github.hello09x.fakeplayer.core.command.CommandSupports.*;
|
import static io.github.hello09x.fakeplayer.core.command.CommandSupports.*;
|
||||||
import static net.kyori.adventure.text.Component.translatable;
|
import static net.kyori.adventure.text.Component.translatable;
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static io.github.hello09x.devtools.command.exception.Commands.command;
|
import static io.github.hello09x.devtools.command.Commands.command;
|
||||||
import static io.github.hello09x.devtools.command.exception.Commands.int32;
|
import static io.github.hello09x.devtools.command.Commands.int32;
|
||||||
import static net.kyori.adventure.text.Component.translatable;
|
import static net.kyori.adventure.text.Component.translatable;
|
||||||
|
|
||||||
public abstract class CommandSupports {
|
public abstract class CommandSupports {
|
||||||
|
@ -111,7 +111,8 @@ public class FakePlayerCommandArgument extends Argument<CommandResult> implement
|
|||||||
// Get location sender is looking at if they are a Player, matching vanilla behavior
|
// Get location sender is looking at if they are a Player, matching vanilla behavior
|
||||||
// No builtin Commands use the location parameter, but they could
|
// No builtin Commands use the location parameter, but they could
|
||||||
Location location = null;
|
Location location = null;
|
||||||
if (sender instanceof Player player) {
|
if (sender instanceof Player) {
|
||||||
|
var player = (Player) sender;
|
||||||
Block block = player.getTargetBlockExact(5, FluidCollisionMode.NEVER);
|
Block block = player.getTargetBlockExact(5, FluidCollisionMode.NEVER);
|
||||||
if (block != null) {
|
if (block != null) {
|
||||||
location = block.getLocation();
|
location = block.getLocation();
|
||||||
|
@ -2,7 +2,7 @@ package io.github.hello09x.fakeplayer.core.command.impl;
|
|||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import dev.jorel.commandapi.executors.CommandArguments;
|
import dev.jorel.commandapi.executors.CommandArguments;
|
||||||
import io.github.hello09x.devtools.command.exception.Page;
|
import io.github.hello09x.devtools.command.Page;
|
||||||
import io.github.hello09x.fakeplayer.core.command.Permission;
|
import io.github.hello09x.fakeplayer.core.command.Permission;
|
||||||
import io.github.hello09x.fakeplayer.core.util.Mth;
|
import io.github.hello09x.fakeplayer.core.util.Mth;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -62,20 +62,35 @@ public class FakeplayerConfig extends PluginConfig {
|
|||||||
private int kaleTps;
|
private int kaleTps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 准备命令
|
* 创建前执行命令
|
||||||
*/
|
*/
|
||||||
private List<String> preparingCommands;
|
private List<String> preSpawnCommands;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时执行命令
|
||||||
|
*/
|
||||||
|
private List<String> postSpawnCommands;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建后执行命令
|
||||||
|
*/
|
||||||
|
private List<String> afterSpawnCommands;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出前执行命令
|
||||||
|
*/
|
||||||
|
private List<String> postQuitCommands;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出后命令
|
||||||
|
*/
|
||||||
|
private List<String> afterQuitCommands;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自执行命令
|
* 自执行命令
|
||||||
*/
|
*/
|
||||||
private List<String> selfCommands;
|
private List<String> selfCommands;
|
||||||
|
|
||||||
/**
|
|
||||||
* 销毁命令
|
|
||||||
*/
|
|
||||||
private List<String> destroyCommands;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退出时是否丢弃背包物品
|
* 退出时是否丢弃背包物品
|
||||||
*/
|
*/
|
||||||
@ -140,8 +155,14 @@ public class FakeplayerConfig extends PluginConfig {
|
|||||||
this.detectIp = file.getBoolean("detect-ip", false);
|
this.detectIp = file.getBoolean("detect-ip", false);
|
||||||
this.kaleTps = file.getInt("kale-tps", 0);
|
this.kaleTps = file.getInt("kale-tps", 0);
|
||||||
this.selfCommands = file.getStringList("self-commands");
|
this.selfCommands = file.getStringList("self-commands");
|
||||||
this.preparingCommands = file.getStringList("preparing-commands");
|
this.preSpawnCommands = file.getStringList("pre-spawn-commands");
|
||||||
this.destroyCommands = file.getStringList("destroy-commands");
|
this.postSpawnCommands = file.getStringList("post-spawn-commands");
|
||||||
|
deprecated:
|
||||||
|
this.afterSpawnCommands = file.getStringList("after-spawn-commands");
|
||||||
|
this.postQuitCommands = file.getStringList("post-quit-commands");
|
||||||
|
this.afterQuitCommands = file.getStringList("after-quit-commands");
|
||||||
|
// this.preparingCommands = file.getStringList("preparing-commands");
|
||||||
|
// this.destroyCommands = file.getStringList("destroy-commands");
|
||||||
this.nameTemplate = file.getString("name-template", "");
|
this.nameTemplate = file.getString("name-template", "");
|
||||||
this.dropInventoryOnQuiting = file.getBoolean("drop-inventory-on-quiting", true);
|
this.dropInventoryOnQuiting = file.getBoolean("drop-inventory-on-quiting", true);
|
||||||
this.persistData = file.getBoolean("persist-data", true);
|
this.persistData = file.getBoolean("persist-data", true);
|
||||||
@ -169,6 +190,19 @@ public class FakeplayerConfig extends PluginConfig {
|
|||||||
if (!this.allowCommands.isEmpty()) {
|
if (!this.allowCommands.isEmpty()) {
|
||||||
log.warning("allow-commands is deprecated which will be removed at 0.4.0, you should use Permissions Plugin to assign permission groups to fake players.");
|
log.warning("allow-commands is deprecated which will be removed at 0.4.0, you should use Permissions Plugin to assign permission groups to fake players.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var preparingCommands = file.getStringList("preparing-commands");
|
||||||
|
if (!preparingCommands.isEmpty()) {
|
||||||
|
log.warning("preparing-commands is deprecated, use post-spawn-commands instead.");
|
||||||
|
this.postSpawnCommands.addAll(preparingCommands);
|
||||||
|
}
|
||||||
|
|
||||||
|
var destroyCommands = file.getStringList("destroy-commands");
|
||||||
|
if (!destroyCommands.isEmpty()) {
|
||||||
|
log.warning("destroy-commands is deprecated, use post-quit-commands instead.");
|
||||||
|
this.postQuitCommands.addAll(destroyCommands);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable Duration getLifespan(@NotNull FileConfiguration file) {
|
private @Nullable Duration getLifespan(@NotNull FileConfiguration file) {
|
||||||
|
@ -4,7 +4,6 @@ import io.github.hello09x.devtools.core.message.RuntimeMessageException;
|
|||||||
import io.github.hello09x.devtools.core.utils.EntityUtils;
|
import io.github.hello09x.devtools.core.utils.EntityUtils;
|
||||||
import io.github.hello09x.devtools.core.utils.SchedulerUtils;
|
import io.github.hello09x.devtools.core.utils.SchedulerUtils;
|
||||||
import io.github.hello09x.devtools.core.utils.WorldUtils;
|
import io.github.hello09x.devtools.core.utils.WorldUtils;
|
||||||
import io.github.hello09x.fakeplayer.api.event.FakePlayerSpawnEvent;
|
|
||||||
import io.github.hello09x.fakeplayer.api.spi.Action;
|
import io.github.hello09x.fakeplayer.api.spi.Action;
|
||||||
import io.github.hello09x.fakeplayer.api.spi.NMSBridge;
|
import io.github.hello09x.fakeplayer.api.spi.NMSBridge;
|
||||||
import io.github.hello09x.fakeplayer.api.spi.NMSNetwork;
|
import io.github.hello09x.fakeplayer.api.spi.NMSNetwork;
|
||||||
@ -141,17 +140,6 @@ public class FakePlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
var event = this.callSpawnEvent();
|
|
||||||
if (event.isCancelled() && config.getPreventKicking().ordinal() < PreventKicking.ON_SPAWNING.ordinal()) {
|
|
||||||
throw new RuntimeMessageException(translatable(
|
|
||||||
"fakeplayer.command.spawn.error.disallowed", RED,
|
|
||||||
text(player.getName(), WHITE),
|
|
||||||
event.getReason()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.isDropInventoryOnQuiting()) {
|
if (config.isDropInventoryOnQuiting()) {
|
||||||
// 跨服背包同步插件可能导致假人既丢弃了一份到地上,在重新生成的时候又回来了
|
// 跨服背包同步插件可能导致假人既丢弃了一份到地上,在重新生成的时候又回来了
|
||||||
// 因此在生成的时候清空一次背包
|
// 因此在生成的时候清空一次背包
|
||||||
@ -242,12 +230,6 @@ public class FakePlayer {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NotNull FakePlayerSpawnEvent callSpawnEvent() {
|
|
||||||
var event = new FakePlayerSpawnEvent(this.creator, this.player);
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否是创建者
|
* 判断是否是创建者
|
||||||
* <p>如果玩家下线再重新登陆, entityID 将会不一样导致 {@link Object#equals(Object)} 返回 {@code false}</p>
|
* <p>如果玩家下线再重新登陆, entityID 将会不一样导致 {@link Object#equals(Object)} 返回 {@code false}</p>
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
package io.github.hello09x.fakeplayer.core.listener;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import io.github.hello09x.fakeplayer.core.Main;
|
||||||
|
import io.github.hello09x.fakeplayer.core.config.FakeplayerConfig;
|
||||||
|
import io.github.hello09x.fakeplayer.core.manager.FakeplayerManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanyaofei
|
||||||
|
* @since 2024/8/7
|
||||||
|
**/
|
||||||
|
@Singleton
|
||||||
|
public class FakeplayerLifecycleListener implements Listener {
|
||||||
|
|
||||||
|
private final FakeplayerManager manager;
|
||||||
|
private final FakeplayerConfig config;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public FakeplayerLifecycleListener(FakeplayerManager manager, FakeplayerConfig config) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
|
public void onPostSpawn(@NotNull PlayerJoinEvent event) {
|
||||||
|
var player = event.getPlayer();
|
||||||
|
if (this.manager.isNotFake(player)) {
|
||||||
|
// Not a fake player
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.dispatchCommands(player, config.getPostSpawnCommands());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||||
|
public void onAfterSpawn(@NotNull PlayerJoinEvent event) {
|
||||||
|
var player = event.getPlayer();
|
||||||
|
if (this.manager.isNotFake(player)) {
|
||||||
|
// Not a fake player
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskLater(Main.getInstance(), () -> {
|
||||||
|
if (player.isOnline()) {
|
||||||
|
manager.dispatchCommands(player, config.getAfterSpawnCommands());
|
||||||
|
manager.issueCommands(player, config.getSelfCommands());
|
||||||
|
}
|
||||||
|
}, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
|
public void onPostQuit(@NotNull PlayerQuitEvent event) {
|
||||||
|
var player = event.getPlayer();
|
||||||
|
if (this.manager.isNotFake(player)) {
|
||||||
|
// Not a fake player
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.dispatchCommands(player, config.getPostQuitCommands());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||||
|
public void onAfterQuit(@NotNull PlayerQuitEvent event) {
|
||||||
|
var player = event.getPlayer();
|
||||||
|
if (this.manager.isNotFake(player)) {
|
||||||
|
// Not a fake player
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskLater(Main.getInstance(), () -> {
|
||||||
|
manager.dispatchCommands(player, config.getAfterQuitCommands());
|
||||||
|
}, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.hello09x.fakeplayer.core.listener;
|
package io.github.hello09x.fakeplayer.core.listener;
|
||||||
|
|
||||||
import com.google.common.base.Throwables;
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import io.github.hello09x.devtools.core.utils.ComponentUtils;
|
import io.github.hello09x.devtools.core.utils.ComponentUtils;
|
||||||
@ -60,7 +59,7 @@ public class FakeplayerListener implements Listener {
|
|||||||
* 拒绝真实玩家使用假人用过的 ID 登陆
|
* 拒绝真实玩家使用假人用过的 ID 登陆
|
||||||
*/
|
*/
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
public void onLogin(@NotNull PlayerLoginEvent event) {
|
public void rejectForUsedUUID(@NotNull PlayerLoginEvent event) {
|
||||||
var player = event.getPlayer();
|
var player = event.getPlayer();
|
||||||
|
|
||||||
if (InternalAddressGenerator.canBeGenerated(event.getAddress())) {
|
if (InternalAddressGenerator.canBeGenerated(event.getAddress())) {
|
||||||
@ -119,7 +118,7 @@ public class FakeplayerListener implements Listener {
|
|||||||
* 死亡退出游戏
|
* 死亡退出游戏
|
||||||
*/
|
*/
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
public void onDead(@NotNull PlayerDeathEvent event) {
|
public void kickOnDead(@NotNull PlayerDeathEvent event) {
|
||||||
var player = event.getPlayer();
|
var player = event.getPlayer();
|
||||||
if (manager.isNotFake(player)) {
|
if (manager.isNotFake(player)) {
|
||||||
return;
|
return;
|
||||||
@ -140,29 +139,24 @@ public class FakeplayerListener implements Listener {
|
|||||||
/**
|
/**
|
||||||
* 退出游戏掉落背包
|
* 退出游戏掉落背包
|
||||||
*/
|
*/
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
|
||||||
public void onQuit(@NotNull PlayerQuitEvent event) {
|
public void cleanup(@NotNull PlayerQuitEvent event) {
|
||||||
var target = event.getPlayer();
|
var target = event.getPlayer();
|
||||||
if (manager.isNotFake(target)) {
|
if (manager.isNotFake(target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
manager.dispatchCommands(target, config.getDestroyCommands());
|
|
||||||
// 如果移除玩家后没有假人, 则更新命令列表
|
|
||||||
// 这个方法需要在 cleanup 之前执行, 不然无法获取假人的创建者
|
|
||||||
if (manager.getCreator(target) instanceof Player creator && manager.countByCreator(creator) == 1) {
|
if (manager.getCreator(target) instanceof Player creator && manager.countByCreator(creator) == 1) {
|
||||||
Bukkit.getScheduler().runTaskLater(Main.getInstance(), creator::updateCommands, 1); // 需要下 1 tick 移除后才正确刷新
|
Bukkit.getScheduler().runTaskLater(Main.getInstance(), creator::updateCommands, 1); // 需要下 1 tick 移除后才正确刷新
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
log.warning("执行 destroy-commands 时发生错误: \n" + Throwables.getStackTraceAsString(e));
|
|
||||||
} finally {
|
} finally {
|
||||||
manager.cleanup(target);
|
manager.cleanup(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||||
public void autoFish(@NotNull PlayerFishEvent event) {
|
public void autoFishing(@NotNull PlayerFishEvent event) {
|
||||||
if (event.getState() != PlayerFishEvent.State.BITE) {
|
if (event.getState() != PlayerFishEvent.State.BITE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -109,8 +109,10 @@ public class FakeplayerManager {
|
|||||||
sn,
|
sn,
|
||||||
lifespan
|
lifespan
|
||||||
);
|
);
|
||||||
|
|
||||||
var target = fp.getPlayer(); // 即使出现异常也不需要处理这个玩家, 最终会被 GC 掉
|
var target = fp.getPlayer(); // 即使出现异常也不需要处理这个玩家, 最终会被 GC 掉
|
||||||
|
|
||||||
|
this.dispatchCommandsEarly(fp, this.config.getPreSpawnCommands());
|
||||||
return CompletableFuture
|
return CompletableFuture
|
||||||
.supplyAsync(() -> {
|
.supplyAsync(() -> {
|
||||||
var configs = configManager.getConfigs(creator);
|
var configs = configManager.getConfigs(creator);
|
||||||
@ -126,15 +128,8 @@ public class FakeplayerManager {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.thenComposeAsync(fp::spawnAsync)
|
.thenComposeAsync(fp::spawnAsync)
|
||||||
.thenApply(nul -> {
|
.thenApply(ignored -> {
|
||||||
Bukkit.getScheduler().runTask(Main.getInstance(), () -> {
|
Bukkit.getScheduler().runTask(Main.getInstance(), () -> playerList.add(fp));
|
||||||
this.playerList.add(fp);
|
|
||||||
});
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskLater(Main.getInstance(), () -> {
|
|
||||||
this.dispatchCommands(target, config.getPreparingCommands());
|
|
||||||
this.issueCommands(target, config.getSelfCommands());
|
|
||||||
}, 20);
|
|
||||||
return target;
|
return target;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -451,7 +446,10 @@ public class FakeplayerManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var cmd : Commands.formatCommands(commands)) {
|
var p = target.getName();
|
||||||
|
var u = target.getUniqueId().toString();
|
||||||
|
var c = Objects.requireNonNull(this.getCreatorName(target));
|
||||||
|
for (var cmd : Commands.formatCommands(commands, "%p", p, "%u", u, "%c", c)) {
|
||||||
if (!target.performCommand(cmd)) {
|
if (!target.performCommand(cmd)) {
|
||||||
log.warning(target.getName() + " failed to execute command: " + cmd);
|
log.warning(target.getName() + " failed to execute command: " + cmd);
|
||||||
} else {
|
} else {
|
||||||
@ -460,6 +458,25 @@ public class FakeplayerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void dispatchCommandsEarly(@NotNull FakePlayer fp, @NotNull List<String> commands) {
|
||||||
|
if (commands.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var server = Bukkit.getServer();
|
||||||
|
var sender = Bukkit.getConsoleSender();
|
||||||
|
var p = fp.getName();
|
||||||
|
var u = fp.getUUID().toString();
|
||||||
|
var c = fp.getCreator().getName();
|
||||||
|
for (var cmd : Commands.formatCommands(commands, "%p", p, "%u", u, "%c", c)) {
|
||||||
|
if (!server.dispatchCommand(sender, cmd)) {
|
||||||
|
log.warning("Failed to execute command for %s: ".formatted(p) + cmd);
|
||||||
|
} else {
|
||||||
|
log.info("Dispatched command: " + cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 以控制台身份对玩家执行命令
|
* 以控制台身份对玩家执行命令
|
||||||
*
|
*
|
||||||
@ -471,20 +488,15 @@ public class FakeplayerManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNotFake(player)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var server = Bukkit.getServer();
|
var server = Bukkit.getServer();
|
||||||
var sender = Bukkit.getConsoleSender();
|
var sender = Bukkit.getConsoleSender();
|
||||||
for (var cmd : Commands.formatCommands(
|
|
||||||
commands,
|
var p = player.getName();
|
||||||
"%p", player.getName(),
|
var u = player.getUniqueId().toString();
|
||||||
"%u", player.getUniqueId().toString(),
|
var c = Objects.requireNonNull(this.getCreatorName(player));
|
||||||
"%c", Objects.requireNonNull(this.getCreatorName(player)))
|
for (var cmd : Commands.formatCommands(commands, "%p", p, "%u", u, "%c", c)) {
|
||||||
) {
|
|
||||||
if (!server.dispatchCommand(sender, cmd)) {
|
if (!server.dispatchCommand(sender, cmd)) {
|
||||||
log.warning("Failed to execute command for %s: ".formatted(player.getName()) + cmd);
|
log.warning("Failed to execute command for %s: ".formatted(p) + cmd);
|
||||||
} else {
|
} else {
|
||||||
log.info("Dispatched command: " + cmd);
|
log.info("Dispatched command: " + cmd);
|
||||||
}
|
}
|
||||||
@ -494,20 +506,20 @@ public class FakeplayerManager {
|
|||||||
/**
|
/**
|
||||||
* 让玩家打开假人背包
|
* 让玩家打开假人背包
|
||||||
*
|
*
|
||||||
* @param creator 玩家
|
* @param viewer 玩家
|
||||||
* @param target 假人
|
* @param target 假人
|
||||||
* @return 是否打开成功
|
* @return 是否打开成功
|
||||||
*/
|
*/
|
||||||
public boolean openInventory(@NotNull Player creator, @NotNull Player target) {
|
public boolean openInventory(@NotNull Player viewer, @NotNull Player target) {
|
||||||
var fp = this.playerList.getByName(target.getName());
|
var fp = this.playerList.getByName(target.getName());
|
||||||
if (fp == null) {
|
if (fp == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!creator.isOp() && !fp.isCreator(creator)) {
|
if (!viewer.isOp() && !fp.isCreator(viewer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.invsee.openInventory(creator, target);
|
this.invsee.openInventory(viewer, target);
|
||||||
var pos = target.getLocation();
|
var pos = target.getLocation();
|
||||||
pos.getWorld().playSound(pos, Sound.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.3f, 1.0f);
|
pos.getWorld().playSound(pos, Sound.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.3f, 1.0f);
|
||||||
return true;
|
return true;
|
||||||
|
@ -111,51 +111,110 @@ kick-on-dead: true
|
|||||||
# It's not recommended to enable this option, as it may cause the redstone machine to malfunction
|
# It's not recommended to enable this option, as it may cause the redstone machine to malfunction
|
||||||
kale-tps: 0
|
kale-tps: 0
|
||||||
|
|
||||||
# 预准备命令
|
|
||||||
# 假人诞生时会以控制台的身份按顺序执行以下命令, 这些命令会比 `self-commands` 更早执行
|
|
||||||
# 你可以用这个来实现权限组的分配之类的命令
|
# Pre-Spawn-Commands
|
||||||
# 占位符:
|
# Server will execute the following commands BEFORE trying to spawn a fake player.
|
||||||
# %p: 假人名称
|
# This is helpful for adding fake player into whitelist
|
||||||
# %u: 假人 uuid
|
# Variables:
|
||||||
# %c: 创建者的名称
|
# %p: the name of the fake player
|
||||||
# Server will execute the following commands after the fake player was spawned
|
# %u: the UUID of the fake player
|
||||||
# You can add some commands to give them permission, such as '/lp user %p permission set xxx true'
|
# %c: the name of the creator
|
||||||
# placeholder:
|
# 服务器会在假人创建前执行这些命令
|
||||||
# %p: the name of the fake player
|
# 这里可以添加类似于白名单的命令来保证后续创建过程的正常执行
|
||||||
# %u: the uuid of the fake player
|
# 变量:
|
||||||
# %c: the name of creator
|
# %p: 假人的名称
|
||||||
preparing-commands:
|
# %u: 假人的 UUID
|
||||||
|
# %c: 创建人的名称
|
||||||
|
pre-spawn-commands:
|
||||||
- ''
|
- ''
|
||||||
- ''
|
- ''
|
||||||
|
|
||||||
# 假人销毁时执行的命令
|
# Post-Spawn-Commands
|
||||||
# 与 `preparing-commands` 类似, 会在假人销毁时依次执行的命令
|
# Server will execute the following commands DURING spawning (in PlayerJoinEvent).
|
||||||
# 也许可以用来销毁第三方插件的档案?
|
# Variables:
|
||||||
# 占位符:
|
# %p: the name of the fake player
|
||||||
# %p: 假人名称
|
# %u: the UUID of the fake player
|
||||||
# %u: 假人 uuid
|
# %c: the name of the creator
|
||||||
# %c: 创建者的名称
|
# 服务器会在假人正在加入游戏中执行这些命令
|
||||||
# Server will execute the following commands before the fake player was quited(PlayerQuitEvent)
|
# 变量:
|
||||||
# you can add some commands to clean up data
|
# %p: 假人的名称
|
||||||
# placeholder:
|
# %u: 假人的 UUID
|
||||||
# %p: the name of the fake player
|
# %c: 创建人的名称
|
||||||
# %u: the uuid of the fake player
|
post-spawn-commands:
|
||||||
# %c: the name of creator
|
|
||||||
destroy-commands:
|
|
||||||
- ''
|
- ''
|
||||||
- ''
|
- ''
|
||||||
|
|
||||||
# 自执行命令
|
# After-Spawn-Commands
|
||||||
# 假人在诞生时会以自己的身份按顺序执行命令
|
# Server will execute the following commands AFTER the fake player was spawned (after PlayerJoinEvent).
|
||||||
# 你可以在这里做添加 /register 和 /login 命令来防止 `AuthMe` 等插件踢掉超时未登陆的玩家
|
# This is helpful for giving permission.
|
||||||
# The fake player will execute the following commands
|
# Variables:
|
||||||
# You can add some command to make him to login
|
# %p: the name of the fake player
|
||||||
# - '/register ANY_PASSWORD'
|
# %u: the UUID of the fake player
|
||||||
# - '/login ANY_PASSWORD'
|
# %c: the name of the creator
|
||||||
|
# 服务器会在假人创建后执行这里的命令
|
||||||
|
# 这里可以添加一些权限组分配之类的命令
|
||||||
|
# 变量:
|
||||||
|
# %p: 假人的名称
|
||||||
|
# %u: 假人的 UUID
|
||||||
|
# %c: 创建人的名称
|
||||||
|
after-spawn-commands:
|
||||||
|
- ''
|
||||||
|
- ''
|
||||||
|
|
||||||
|
# Self-Commands
|
||||||
|
# The fake player will execute the following commands AFTER they were joined the server.
|
||||||
|
# This is helpful for them to execute some login command.
|
||||||
|
# Ensure the password is complex enough otherwise the login plugin might reject it.
|
||||||
|
# Variables:
|
||||||
|
# %p: the name of the fake player
|
||||||
|
# %u: the UUID of the fake player
|
||||||
|
# %c: the name of the creator
|
||||||
|
# 假人在加入游戏后会执行以下命令
|
||||||
|
# 你可以添加一些登陆命令来让他们完成登陆过程
|
||||||
|
# 变量:
|
||||||
|
# %p: 假人的名称
|
||||||
|
# %u: 假人的 UUID
|
||||||
|
# %c: 创建人的名称
|
||||||
self-commands:
|
self-commands:
|
||||||
- ''
|
- ''
|
||||||
- ''
|
- ''
|
||||||
|
|
||||||
|
# Post-Destroy-Commands
|
||||||
|
# Server will execute the following commands when the fake player is quiting but not quited (in PlayerQuitEvent)
|
||||||
|
# This is helpful for cleaning up their inventory if you want it
|
||||||
|
# Variables:
|
||||||
|
# %p: the name of the fake player
|
||||||
|
# %u: the UUID of the fake player
|
||||||
|
# %c: the name of the creator
|
||||||
|
# 服务器会在假人正在退出时执行这些命令, 命令执行的那一刻假人还位于服务器
|
||||||
|
# 你可以添加一些用来清空假人背包之类的命令
|
||||||
|
# 变量:
|
||||||
|
# %p: 假人的名称
|
||||||
|
# %u: 假人的 UUID
|
||||||
|
# %c: 创建人的名称
|
||||||
|
post-quit-commands:
|
||||||
|
- ''
|
||||||
|
- ''
|
||||||
|
|
||||||
|
# Post-Destroy-Commands
|
||||||
|
# Server will execute the following commands AFTER the fake player was quited. (after PlayerQuitEvent)
|
||||||
|
# Variables:
|
||||||
|
# %p: the name of the fake player
|
||||||
|
# %u: the UUID of the fake player
|
||||||
|
# %c: the name of the creator
|
||||||
|
# 销毁后命令
|
||||||
|
# 服务器会在假人退出游戏之后执行这些命令
|
||||||
|
# 你可以添加一些清理白名单、取消权限分配、清理某些插件数据等命令
|
||||||
|
# 变量:
|
||||||
|
# %p: 假人的名称
|
||||||
|
# %u: 假人的 UUID
|
||||||
|
# %c: 创建人的名称
|
||||||
|
after-quit-commands:
|
||||||
|
- ''
|
||||||
|
- ''
|
||||||
|
|
||||||
|
|
||||||
# 允许玩家让假人执行的命令
|
# 允许玩家让假人执行的命令
|
||||||
# 在这里你可以放一些你服务器的命令,玩家就可以执行
|
# 在这里你可以放一些你服务器的命令,玩家就可以执行
|
||||||
# 例如添加 /sit 之后, 玩家可以通过 '/fp cmd myfakeplayer sit' 让假人坐下来
|
# 例如添加 /sit 之后, 玩家可以通过 '/fp cmd myfakeplayer sit' 让假人坐下来
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
<artifactId>fakeplayer-v1_20_R1</artifactId>
|
<artifactId>fakeplayer-v1_20_R1</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
<artifactId>fakeplayer-v1_20_R2</artifactId>
|
<artifactId>fakeplayer-v1_20_R2</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
<artifactId>fakeplayer-v1_20_R3_R4</artifactId>
|
<artifactId>fakeplayer-v1_20_R3_R4</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
<artifactId>fakeplayer-v1_20_R5_R6</artifactId>
|
<artifactId>fakeplayer-v1_20_R5_R6</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user