mirror of
https://github.com/tanyaofei/minecraft-fakeplayer.git
synced 2025-09-14 11:16:46 +08:00
添加 invsee, sleep, wakeup 命令
This commit is contained in:
parent
d7f01bc91e
commit
6eb3b1741e
24
README.md
24
README.md
@ -11,6 +11,16 @@
|
||||
1. 这个假人有点"真", 与真实玩家一致, 可以保持区块的刷新和怪物生成, 距离取决于服务器设置的模拟距离
|
||||
2. 假人的原生数据档案、成就数据不会存档,但第三方的档案还会存在
|
||||
|
||||
## 前置
|
||||
|
||||
### 必须前置:
|
||||
|
||||
- CommandAPI
|
||||
|
||||
### 可选前置:
|
||||
|
||||
- OpenInv: 有这个插件则玩家打开假人背包时可以操作编辑, 否则只能查看
|
||||
|
||||
## 命令
|
||||
|
||||
+ `/fp spawn [名称] [世界] [位置]` - 创建假人
|
||||
@ -22,10 +32,12 @@
|
||||
+ `/fp tps` - 与假人交换位置
|
||||
+ `/fp config get <配置项>` - 查看配置项
|
||||
+ `/fp config set <配置项> <配置值>` - 设置配置项
|
||||
+ `/fp config list` - 查看所有配置项
|
||||
+ `/fp health` - 查看生命值
|
||||
+ `/fp exp` - 查看经验值
|
||||
+ `/fp expme` - 转移经验值
|
||||
+ `/fp attack (once | continuous | interval | stop)` - 攻击/破坏
|
||||
+ `/fp attack (once | continuous | interval | stop)` - 攻击
|
||||
+ `/fp mine (once | continuous | interval | stop)` - 挖掘
|
||||
+ `/fp use (once | continuous | interval | stop)` - 使用/交互/放置
|
||||
+ `/fp jump (once | continuous | interval | stop)` - 跳跃
|
||||
+ `/fp drop [-a|--all]` - 丢弃手上物品
|
||||
@ -34,6 +46,10 @@
|
||||
+ `/fp turn (left | right | back | to)` - 转身到指定位置
|
||||
+ `/fp move (forward | backward | left | right)` - 移动假人
|
||||
+ `/fp ride (anything | vehicle | target | stop)` - 骑乘
|
||||
+ `/fp sleep` - 睡觉
|
||||
+ `/fp wakup` - 起床
|
||||
+ `/fp skin` - 拷贝皮肤
|
||||
+ `/fp invsee` - 查看背包 _(有 OpenInv 前置则可以编辑)_
|
||||
+ `/fp cmd <假人> <命令>` - 执行命令
|
||||
+ `/fp reload` - 重载配置文件
|
||||
|
||||
@ -44,14 +60,14 @@
|
||||
**_默认所有权限是 op 拥有,请通过权限管理插件来分配!_**
|
||||
|
||||
| 节点 | 指令 |
|
||||
|---------------------------|------------------------------------------------------------------|
|
||||
| fakeplayer.spawn | `spawn`, `list`, `kill`, `distance`, `dropinv`, `drop` |
|
||||
|---------------------------|-----------------------------------------------------------------------------------------------|
|
||||
| fakeplayer.spawn | `spawn`, `list`, `kill`, `distance`, `dropinv`, `drop`, `skin`, `invsee` |
|
||||
| fakeplayer.spawn.location | `spawn` 可以指定出生点 |
|
||||
| fakeplayer.spawn.name | `spawn` 可以自定义名称 |
|
||||
| fakeplayer.tp | `tp`, `tps`, `tphere` |
|
||||
| fakeplayer.profile | `exp`, `health` |
|
||||
| fakeplayer.exp | `expme` |
|
||||
| fakeplayer.action | `sneak`, `turn`, `jump`, `look`, `move`, `attack`, `use`, `ride` |
|
||||
| fakeplayer.action | `sneak`, `turn`, `jump`, `look`, `move`, `attack`, `use`, `ride`, `refill`, `sleep`, `wakeup` |
|
||||
| fakeplayer.cmd | `cmd` |
|
||||
| fakeplayer.admin | `reload` |
|
||||
| 无 | `config` |
|
||||
|
@ -51,6 +51,11 @@
|
||||
<artifactId>commandapi-bukkit-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.jikoo.OpenInv</groupId>
|
||||
<artifactId>openinvapi</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -7,6 +7,7 @@ import io.github.hello09x.fakeplayer.api.spi.VersionSupport;
|
||||
import io.github.hello09x.fakeplayer.core.command.CommandRegistry;
|
||||
import io.github.hello09x.fakeplayer.core.config.FakeplayerConfig;
|
||||
import io.github.hello09x.fakeplayer.core.listener.PlayerListeners;
|
||||
import io.github.hello09x.fakeplayer.core.listener.RefillListener;
|
||||
import io.github.hello09x.fakeplayer.core.manager.WildFakeplayerManager;
|
||||
import io.github.hello09x.fakeplayer.core.util.update.UpdateChecker;
|
||||
import lombok.Getter;
|
||||
@ -48,6 +49,7 @@ public final class Main extends RegistrablePlugin implements I18nSupported {
|
||||
|
||||
{
|
||||
getServer().getPluginManager().registerEvents(PlayerListeners.instance, this);
|
||||
getServer().getPluginManager().registerEvents(RefillListener.instance, this);
|
||||
}
|
||||
|
||||
if (FakeplayerConfig.instance.isCheckForUpdates()) {
|
||||
|
@ -136,8 +136,8 @@ public class ActionCommand extends AbstractCommand {
|
||||
case SOUTH -> look(target, 0, 0);
|
||||
case EAST -> look(target, -90, 0);
|
||||
case WEST -> look(target, 90, 0);
|
||||
case UP -> look(target, target.getYaw(), -90);
|
||||
case DOWN -> look(target, target.getYaw(), 90);
|
||||
case UP -> look(target, target.getLocation().getYaw(), -90);
|
||||
case DOWN -> look(target, target.getLocation().getYaw(), 90);
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +187,8 @@ public class ActionCommand extends AbstractCommand {
|
||||
}
|
||||
|
||||
private void turn(@NotNull Player player, float yaw, float pitch) {
|
||||
look(player, player.getYaw() + yaw, player.getPitch() + pitch);
|
||||
var pos = player.getLocation();
|
||||
look(player, pos.getYaw() + yaw, pos.getPitch() + pitch);
|
||||
}
|
||||
|
||||
|
||||
|
@ -53,6 +53,9 @@ public class CommandRegistry {
|
||||
Usage.of("drop", i18n.asString("fakeplayer.command.drop.description"), Permission.spawn),
|
||||
Usage.of("dropinv", i18n.asString("fakeplayer.command.dropinv.description"), Permission.spawn),
|
||||
Usage.of("skin", i18n.asString("fakeplayer.command.skin.description"), Permission.spawn),
|
||||
Usage.of("invsee", i18n.asString("fakeplayer.command.invsee.description"), Permission.spawn),
|
||||
Usage.of("sleep", i18n.asString("fakeplayer.command.sleep.description"), Permission.spawn),
|
||||
Usage.of("wakeup", i18n.asString("fakeplayer.command.wakeup.description"), Permission.spawn),
|
||||
Usage.of("tp", i18n.asString("fakeplayer.command.tp.description"), Permission.tp),
|
||||
Usage.of("tphere", i18n.asString("fakeplayer.command.tphere.description"), Permission.tp),
|
||||
Usage.of("tps", i18n.asString("fakeplayer.command.tps.description"), Permission.tp),
|
||||
@ -64,13 +67,14 @@ public class CommandRegistry {
|
||||
Usage.of("attack", i18n.asString("fakeplayer.command.attack.description"), Permission.action),
|
||||
Usage.of("mine", i18n.asString("fakeplayer.command.mine.description"), Permission.action),
|
||||
Usage.of("use", i18n.asString("fakeplayer.command.use.description"), Permission.action),
|
||||
Usage.of("refill", i18n.asString("fakeplayer.command.refill.description"), Permission.action),
|
||||
Usage.of("jump", i18n.asString("fakeplayer.command.jump.description"), Permission.action),
|
||||
Usage.of("look", i18n.asString("fakeplayer.command.look.description"), Permission.action),
|
||||
Usage.of("turn", i18n.asString("fakeplayer.command.turn.description"), Permission.action),
|
||||
Usage.of("move", i18n.asString("fakeplayer.command.move.description"), Permission.action),
|
||||
Usage.of("ride", i18n.asString("fakeplayer.command.ride.description"), Permission.action),
|
||||
Usage.of("sneak", i18n.asString("fakeplayer.command.sneak.description"), Permission.action),
|
||||
Usage.of("swap", i18n.asString("fakeplayer.command.swap.description"), Permission.spawn),
|
||||
Usage.of("swap", i18n.asString("fakeplayer.command.swap.description"), Permission.action),
|
||||
Usage.of("cmd", i18n.asString("fakeplayer.command.cmd.description"), Permission.cmd),
|
||||
Usage.of("reload", i18n.asString("fakeplayer.command.reload.description"), Permission.admin)
|
||||
),
|
||||
@ -115,6 +119,10 @@ public class CommandRegistry {
|
||||
.withArguments(offlinePlayer("player"))
|
||||
.withOptionalArguments(fakeplayer("name"))
|
||||
.executes(SkinCommand.instance::skin),
|
||||
command("invsee")
|
||||
.withPermission(Permission.spawn)
|
||||
.withOptionalArguments(fakeplayer("name"))
|
||||
.executesPlayer(InvseeCommand.instance::invsee),
|
||||
|
||||
command("exp")
|
||||
.withPermission(Permission.profile)
|
||||
@ -147,7 +155,9 @@ public class CommandRegistry {
|
||||
.withArguments(
|
||||
config("option"),
|
||||
configValue("option", "value"))
|
||||
.executesPlayer(ConfigCommand.instance::setConfig)
|
||||
.executesPlayer(ConfigCommand.instance::setConfig),
|
||||
command("list")
|
||||
.executesPlayer(ConfigCommand.instance::listConfig)
|
||||
),
|
||||
|
||||
command("attack")
|
||||
@ -287,6 +297,21 @@ public class CommandRegistry {
|
||||
.withPermission(Permission.action)
|
||||
.withOptionalArguments(fakeplayer("name"))
|
||||
.executes(ActionCommand.instance::swap),
|
||||
command("refill")
|
||||
.withPermission(Permission.action)
|
||||
.withOptionalArguments(
|
||||
literals("enabled", List.of("true", "false")),
|
||||
fakeplayer("name")
|
||||
)
|
||||
.executes(RefillCommand.instance::refill),
|
||||
command("sleep")
|
||||
.withPermission(Permission.action)
|
||||
.withOptionalArguments(fakeplayer("name"))
|
||||
.executes(SleepCommand.instance::sleep),
|
||||
command("wakeup")
|
||||
.withPermission(Permission.action)
|
||||
.withOptionalArguments(fakeplayer("name"))
|
||||
.executes(SleepCommand.instance::wakeup),
|
||||
|
||||
command("expme")
|
||||
.withPermission(Permission.exp)
|
||||
|
@ -1,16 +1,21 @@
|
||||
package io.github.hello09x.fakeplayer.core.command;
|
||||
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import io.github.hello09x.bedrock.util.Components;
|
||||
import io.github.hello09x.fakeplayer.core.Main;
|
||||
import io.github.hello09x.fakeplayer.core.repository.UserConfigRepository;
|
||||
import io.github.hello09x.fakeplayer.core.repository.model.Config;
|
||||
import io.github.hello09x.fakeplayer.core.repository.model.Configs;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.Component.textOfChildren;
|
||||
import static net.kyori.adventure.text.Component.*;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.*;
|
||||
|
||||
public class ConfigCommand extends AbstractCommand {
|
||||
@ -44,5 +49,22 @@ public class ConfigCommand extends AbstractCommand {
|
||||
));
|
||||
}
|
||||
|
||||
public void listConfig(@NotNull Player sender, @NotNull CommandArguments args) {
|
||||
var uuid = sender.getUniqueId();
|
||||
CompletableFuture.runAsync(() -> {
|
||||
var components = Arrays.stream(Configs.values()).map(config -> {
|
||||
var value = String.valueOf(repository.selectOrDefault(uuid, config));
|
||||
return textOfChildren(
|
||||
i18n.translate(config, GOLD),
|
||||
text(": ", GRAY),
|
||||
text(value, WHITE)
|
||||
);
|
||||
}).toList();
|
||||
|
||||
var message = Components.join(components, newline());
|
||||
Bukkit.getScheduler().runTask(Main.getInstance(), () -> sender.sendMessage(message));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package io.github.hello09x.fakeplayer.core.command;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPI;
|
||||
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class InvseeCommand extends AbstractCommand {
|
||||
|
||||
public final static InvseeCommand instance = new InvseeCommand();
|
||||
|
||||
public void invsee(@NotNull Player sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException {
|
||||
var target = getTarget(sender, args);
|
||||
if (!Objects.equals(sender.getLocation().getWorld(), target.getLocation().getWorld())) {
|
||||
throw CommandAPI.failWithString(i18n.asString("fakeplayer.command.invsee.error.not-the-same-world"));
|
||||
}
|
||||
fakeplayerManager.openInventory(sender, target);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package io.github.hello09x.fakeplayer.core.command;
|
||||
|
||||
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.*;
|
||||
|
||||
public class RefillCommand extends AbstractCommand {
|
||||
|
||||
public final static RefillCommand instance = new RefillCommand();
|
||||
|
||||
public void refill(@NotNull CommandSender sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException {
|
||||
var target = getTarget(sender, args);
|
||||
var refillable = args.getOptional("enabled").map(value -> Boolean.parseBoolean((String) value)).orElse(null);
|
||||
if (refillable == null) {
|
||||
refillable = !fakeplayerManager.isRefillable(target);
|
||||
}
|
||||
fakeplayerManager.setRefillable(target, refillable);
|
||||
sender.sendMessage(miniMessage.deserialize(
|
||||
"<gray>" + i18n.asString("fakeplayer.command.refill.success") + "</gray>",
|
||||
Placeholder.component("name", text(target.getName(), WHITE)),
|
||||
Placeholder.component("status", refillable
|
||||
? i18n.translate("fakeplayer.generic.enabled", DARK_GREEN)
|
||||
: i18n.translate("fakeplayer.generic.disabled", GRAY))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package io.github.hello09x.fakeplayer.core.command;
|
||||
|
||||
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import io.github.hello09x.bedrock.util.Blocks;
|
||||
import org.bukkit.block.data.type.Bed;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SleepCommand extends AbstractCommand {
|
||||
|
||||
public final static SleepCommand instance = new SleepCommand();
|
||||
|
||||
public void sleep(@NotNull CommandSender sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException {
|
||||
var target = getTarget(sender, args);
|
||||
var bed = Blocks.getNearbyBlock(target.getLocation(), 4, block -> {
|
||||
if (block.getType().data != Bed.class) {
|
||||
return false;
|
||||
}
|
||||
var data = (Bed) block.getBlockData();
|
||||
if (data.isOccupied()) {
|
||||
return false;
|
||||
}
|
||||
if (data.getPart() == Bed.Part.FOOT) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (bed == null) {
|
||||
return;
|
||||
}
|
||||
target.sleep(bed.getLocation(), false);
|
||||
}
|
||||
|
||||
public void wakeup(@NotNull CommandSender sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException {
|
||||
var target = getTarget(sender, args);
|
||||
if (!target.isSleeping()) {
|
||||
return;
|
||||
}
|
||||
|
||||
target.wakeup(true);
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import io.github.hello09x.fakeplayer.api.action.ActionType;
|
||||
import io.github.hello09x.fakeplayer.api.spi.NMSServerPlayer;
|
||||
import io.github.hello09x.fakeplayer.core.Main;
|
||||
import io.github.hello09x.fakeplayer.core.config.FakeplayerConfig;
|
||||
import io.github.hello09x.fakeplayer.core.manager.FakeplayerManager;
|
||||
import io.github.hello09x.fakeplayer.core.manager.action.ActionManager;
|
||||
import io.github.hello09x.fakeplayer.core.manager.naming.SequenceName;
|
||||
import io.github.hello09x.fakeplayer.core.util.InternalAddressGenerator;
|
||||
@ -145,6 +146,9 @@ public class FakePlayer {
|
||||
if (option.skin() && this.creator instanceof Player playerCreator) {
|
||||
handle.copyTexture(playerCreator);
|
||||
}
|
||||
if (option.refillable()) {
|
||||
FakeplayerManager.instance.setRefillable(player, true);
|
||||
}
|
||||
|
||||
var network = Main.getVersionSupport().network();
|
||||
network.bindEmptyServerGamePacketListener(Bukkit.getServer(), this.player, address);
|
||||
|
@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @param collidable 是否开启碰撞
|
||||
* @param lookAtEntity 是否看向附近实体
|
||||
* @param pickupItems 是否拾取物品
|
||||
* @param refillable 是否自动填装
|
||||
*/
|
||||
public record SpawnOption(
|
||||
@NotNull
|
||||
@ -22,7 +23,9 @@ public record SpawnOption(
|
||||
|
||||
boolean pickupItems,
|
||||
|
||||
boolean skin
|
||||
boolean skin,
|
||||
|
||||
boolean refillable
|
||||
|
||||
) {
|
||||
}
|
||||
|
@ -9,11 +9,15 @@ import io.github.hello09x.fakeplayer.core.repository.UsedIdRepository;
|
||||
import io.github.hello09x.fakeplayer.core.util.InternalAddressGenerator;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.attribute.AttributeInstance;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -58,6 +62,19 @@ public class PlayerListeners implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 由于查看假人背包时看不到盔甲栏, 且在将物品从假人背包移动到玩家背包时候有概率会将物品放置到假人的盔甲栏而找不到了, 因此禁止玩家操作假人背包
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onClickFakePlayerInventory(@NotNull InventoryClickEvent event) {
|
||||
var top = event.getView().getTopInventory();
|
||||
if (top.getType() == InventoryType.PLAYER && (top.getHolder() instanceof Player player && manager.isFake(player))) {
|
||||
if (event.getView().getTitle().startsWith("*")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 死亡退出游戏
|
||||
*/
|
||||
@ -96,4 +113,16 @@ public class PlayerListeners implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 右键假人打开其背包
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void invsee(@NotNull PlayerInteractAtEntityEvent event) {
|
||||
if (!(event.getRightClicked() instanceof Player target) || !manager.isFake(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
manager.openInventory(event.getPlayer(), target);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,124 @@
|
||||
package io.github.hello09x.fakeplayer.core.listener;
|
||||
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent;
|
||||
import io.github.hello09x.fakeplayer.core.Main;
|
||||
import io.github.hello09x.fakeplayer.core.manager.FakeplayerManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerItemBreakEvent;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class RefillListener implements Listener {
|
||||
|
||||
public final static RefillListener instance = new RefillListener();
|
||||
|
||||
private final FakeplayerManager manager = FakeplayerManager.instance;
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onItemUse(@NotNull PlayerItemConsumeEvent event) {
|
||||
var player = event.getPlayer();
|
||||
if (!manager.isRefillable(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var slot = event.getHand();
|
||||
var item = player.getInventory().getItem(slot);
|
||||
if (item.getAmount() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.refillLater(player, slot, item);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onBlockPlace(@NotNull BlockPlaceEvent event) {
|
||||
var player = event.getPlayer();
|
||||
if (!manager.isRefillable(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var slot = event.getHand();
|
||||
var item = player.getInventory().getItem(slot);
|
||||
if (item.getAmount() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.refillLater(player, slot, item);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
|
||||
public void onItemBreak(@NotNull PlayerItemBreakEvent event) {
|
||||
var player = event.getPlayer();
|
||||
if (!manager.isRefillable(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var item = event.getBrokenItem();
|
||||
var slot = getHoldingHand(player, item);
|
||||
if (slot == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.refillLater(player, slot, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发射投掷物, 如扔喷溅型药水
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onProjectileLaunch(@NotNull PlayerLaunchProjectileEvent event) {
|
||||
var player = event.getPlayer();
|
||||
if (!manager.isRefillable(event.getPlayer())) {
|
||||
return;
|
||||
}
|
||||
var item = event.getItemStack();
|
||||
if (item.getAmount() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var slot = getHoldingHand(player, item);
|
||||
if (slot == null) {
|
||||
return;
|
||||
}
|
||||
this.refillLater(player, slot, item);
|
||||
}
|
||||
|
||||
|
||||
public void refillLater(@NotNull Player player, @NotNull EquipmentSlot slot, @NotNull ItemStack item) {
|
||||
var requires = item.clone();
|
||||
Bukkit.getScheduler().runTaskLater(Main.getInstance(), () -> {
|
||||
var inv = player.getInventory();
|
||||
var current = inv.getItem(slot);
|
||||
for (int i = inv.getSize(); i >= 0; i--) {
|
||||
var replacement = inv.getItem(i);
|
||||
if (replacement != null && replacement.isSimilar(requires)) {
|
||||
inv.setItem(slot, replacement);
|
||||
inv.setItem(i, current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
private @Nullable EquipmentSlot getHoldingHand(@NotNull Player player, @NotNull ItemStack item) {
|
||||
var inv = player.getInventory();
|
||||
if (item.equals(inv.getItemInMainHand())) {
|
||||
return EquipmentSlot.HAND;
|
||||
} else if (item.equals(inv.getItemInOffHand())) {
|
||||
return EquipmentSlot.OFF_HAND;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ package io.github.hello09x.fakeplayer.core.manager;
|
||||
import io.github.hello09x.bedrock.command.MessageException;
|
||||
import io.github.hello09x.bedrock.i18n.I18n;
|
||||
import io.github.hello09x.bedrock.task.Tasks;
|
||||
import io.github.hello09x.bedrock.util.Components;
|
||||
import io.github.hello09x.fakeplayer.api.action.ActionSetting;
|
||||
import io.github.hello09x.fakeplayer.api.action.ActionType;
|
||||
import io.github.hello09x.fakeplayer.core.Main;
|
||||
@ -16,13 +17,17 @@ import io.github.hello09x.fakeplayer.core.manager.naming.exception.IllegalCustom
|
||||
import io.github.hello09x.fakeplayer.core.repository.UsedIdRepository;
|
||||
import io.github.hello09x.fakeplayer.core.repository.UserConfigRepository;
|
||||
import io.github.hello09x.fakeplayer.core.repository.model.Configs;
|
||||
import io.github.hello09x.fakeplayer.core.softdepend.OpenInvDepend;
|
||||
import io.github.hello09x.fakeplayer.core.util.AddressUtils;
|
||||
import io.github.hello09x.fakeplayer.core.util.Commands;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -47,6 +52,8 @@ public class FakeplayerManager {
|
||||
|
||||
private final static Logger log = Main.getInstance().getLogger();
|
||||
|
||||
private final static MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||
|
||||
private final FakeplayerConfig config = FakeplayerConfig.instance;
|
||||
|
||||
private final UsedIdRepository usedIdRepository = UsedIdRepository.instance;
|
||||
@ -59,6 +66,8 @@ public class FakeplayerManager {
|
||||
|
||||
private final I18n i18n = Main.i18n();
|
||||
|
||||
private final OpenInvDepend openInvDepend = OpenInvDepend.instance;
|
||||
|
||||
private FakeplayerManager() {
|
||||
var timer = Executors.newSingleThreadScheduledExecutor();
|
||||
timer.scheduleAtFixedRate(() -> {
|
||||
@ -113,7 +122,8 @@ public class FakeplayerManager {
|
||||
lookAtEntity = Configs.look_at_entity.defaultValue(),
|
||||
collidable = Configs.collidable.defaultValue(),
|
||||
pickupItems = Configs.pickup_items.defaultValue(),
|
||||
skin = Configs.skin.defaultValue();
|
||||
skin = Configs.skin.defaultValue(),
|
||||
refillable = Configs.refillable.defaultValue();
|
||||
|
||||
if (creator instanceof Player p) {
|
||||
var creatorId = p.getUniqueId();
|
||||
@ -122,6 +132,7 @@ public class FakeplayerManager {
|
||||
collidable = userConfigRepository.selectOrDefault(creatorId, Configs.collidable);
|
||||
pickupItems = userConfigRepository.selectOrDefault(creatorId, Configs.pickup_items);
|
||||
skin = userConfigRepository.selectOrDefault(creatorId, Configs.skin);
|
||||
refillable = userConfigRepository.selectOrDefault(creatorId, Configs.refillable);
|
||||
}
|
||||
|
||||
return new SpawnOption(
|
||||
@ -130,7 +141,8 @@ public class FakeplayerManager {
|
||||
collidable,
|
||||
lookAtEntity,
|
||||
pickupItems,
|
||||
skin
|
||||
skin,
|
||||
refillable
|
||||
);
|
||||
})
|
||||
.thenApplyAsync(option -> fp.spawnAsync(option).join())
|
||||
@ -289,6 +301,22 @@ public class FakeplayerManager {
|
||||
.count();
|
||||
}
|
||||
|
||||
public void setRefillable(@NotNull Player player, boolean refillable) {
|
||||
if (!this.isFake(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!refillable) {
|
||||
player.removeMetadata("fakeplayer:refillable", Main.getInstance());
|
||||
} else {
|
||||
player.setMetadata("fakeplayer:refillable", new FixedMetadataValue(Main.getInstance(), true));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRefillable(@NotNull Player player) {
|
||||
return player.hasMetadata("fakeplayer:refillable");
|
||||
}
|
||||
|
||||
/**
|
||||
* 以假人身份执行命令
|
||||
*
|
||||
@ -339,6 +367,21 @@ public class FakeplayerManager {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean openInventory(@NotNull Player creator, @NotNull Player player) {
|
||||
var fake = this.playerList.getByName(player.getName());
|
||||
if (fake == null) {
|
||||
return false;
|
||||
}
|
||||
if (!creator.isOp() && !fake.getCreator().equals(creator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!openInvDepend.openInventory(creator, player)) {
|
||||
this.openInventoryDefault(creator, player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkLimit(@NotNull CommandSender creator) throws MessageException {
|
||||
if (creator.isOp()) {
|
||||
return;
|
||||
@ -357,4 +400,14 @@ public class FakeplayerManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void openInventoryDefault(@NotNull Player player, @NotNull Player target) {
|
||||
var view = player.openInventory(target.getInventory());
|
||||
if (view != null) {
|
||||
view.setTitle("* " + Components.asString(miniMessage.deserialize(
|
||||
i18n.asString("fakeplayer.manager.inventory.title"),
|
||||
Placeholder.component("name", text(target.getName()))
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -64,6 +64,14 @@ public interface Configs {
|
||||
Boolean::valueOf
|
||||
);
|
||||
|
||||
Config<Boolean> refillable = build(
|
||||
"refillable",
|
||||
"fakeplayer.config.refillable",
|
||||
false,
|
||||
List.of("true", "false"),
|
||||
Boolean::valueOf
|
||||
);
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static <T> Config<T> build(
|
||||
@NotNull String name,
|
||||
|
@ -0,0 +1,45 @@
|
||||
package io.github.hello09x.fakeplayer.core.softdepend;
|
||||
|
||||
import com.lishid.openinv.IOpenInv;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OpenInvDepend {
|
||||
|
||||
public final static OpenInvDepend instance = new OpenInvDepend();
|
||||
private Bridge bridge = null;
|
||||
|
||||
public OpenInvDepend() {
|
||||
try {
|
||||
if (Bukkit.getPluginManager().getPlugin("OpenInv") != null) {
|
||||
bridge = new Bridge();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public boolean openInventory(@NotNull Player player, @NotNull Player target) {
|
||||
if (bridge == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
bridge.openInventory(player, target);
|
||||
} catch (Throwable e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private final static class Bridge {
|
||||
private IOpenInv iOpenInv = (IOpenInv) Bukkit.getPluginManager().getPlugin("OpenInv");
|
||||
|
||||
public void openInventory(@NotNull Player player, @NotNull Player target) throws Throwable {
|
||||
iOpenInv.openInventory(player, iOpenInv.getSpecialInventory(target, true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -120,4 +120,14 @@ fakeplayer.command.config.set.error.invalid-value=Unknown value
|
||||
fakeplayer.command.generic.error.non-fake-player=You haven't spawn fake player yet
|
||||
fakeplayer.command.skin.description=Copy skin from a player who has played before
|
||||
fakeplayer.command.skin.error.too-many-operations=You did this too frequently, you can't copy skin of offline players for now, try online players instaed~
|
||||
fakeplayer.command.refill.description=Config whether auto replacing their broken tools, or items
|
||||
fakeplayer.manager.inventory.title=<name>'s Inventory
|
||||
fakeplayer.command.invsee.error.not-the-same-world=You are not in the same world
|
||||
fakeplayer.command.refill.success=<name> refillable was set to <status>
|
||||
fakeplayer.generic.enabled=enabled
|
||||
fakeplayer.generic.disabled=disabled
|
||||
fakeplayer.config.refillable=Auto-Refill
|
||||
fakeplayer.command.invsee.description=Open inventory
|
||||
fakeplayer.command.sleep.description=Sleep
|
||||
fakeplayer.command.wakeup.description=Wakup
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
fakeplayer.command.attack.description=\u653B\u51FB
|
||||
fakeplayer.command.config.get.description=\u67E5\u770B\u914D\u7F6E
|
||||
fakeplayer.command.config.set.description=\u8BBE\u7F6E\u914D\u7F6E\u9879
|
||||
fakeplayer.command.distance.description=\u67E5\u770B\u4E0E\u5BB6\u4EBA\u7684\u8DDD\u79BB
|
||||
fakeplayer.command.distance.description=\u67E5\u770B\u8DDD\u79BB
|
||||
fakeplayer.command.drop.description=\u4E22\u5F03\u624B\u4E0A\u7269\u54C1
|
||||
fakeplayer.command.dropinv.description=\u4E22\u5F03\u80CC\u5305\u7269\u54C1
|
||||
fakeplayer.command.exp.description=\u67E5\u770B\u7ECF\u9A8C\u503C
|
||||
fakeplayer.command.expme.description=\u8F6C\u79FB\u7ECF\u9A8C\u503C
|
||||
fakeplayer.command.health.description=\u67E5\u770B\u5047\u4EBA\u751F\u547D\u503C
|
||||
fakeplayer.command.health.description=\u67E5\u770B\u751F\u547D\u503C
|
||||
fakeplayer.command.jump.description=\u8DF3\u8DC3
|
||||
fakeplayer.command.kill.description=\u79FB\u9664\u5047\u4EBA
|
||||
fakeplayer.command.list.description=\u67E5\u770B\u6240\u6709\u5047\u4EBA
|
||||
@ -48,7 +48,7 @@ fakeplayer.command.ride.stop.description=\u505C\u6B62\u9A91\u4E58
|
||||
fakeplayer.command.fp.short-description=\u5047\u4EBA
|
||||
fakeplayer.command.fp.full-description=\u53EF\u4EE5\u521B\u5EFA\u6A21\u62DF\u73A9\u5BB6\u7684\u5047\u4EBA\uFF0C\u4FDD\u6301\u533A\u5757\u7684\u5237\u65B0\uFF0C\u602A\u7269\u7684\u751F\u6210\u3002\u540C\u65F6\u63D0\u4F9B\u4E00\u4E9B\u547D\u4EE4\u8BA9\u4F60\u64CD\u63A7\u5047\u4EBA\u7684\u52A8\u4F5C\u3002
|
||||
fakeplayer.config.collidable=\u78B0\u649E\u7BB1
|
||||
fakeplayer.config.invulnerable=\u65E0\u654C
|
||||
fakeplayer.config.invulnerable=\u65E0\u654C\u6A21\u5F0F
|
||||
fakeplayer.config.look_at_entity=\u76EE\u89C6\u5B9E\u4F53
|
||||
fakeplayer.config.pickup_items=\u62FE\u53D6\u7269\u54C1
|
||||
fakeplayer.config.skin=\u4F7F\u7528\u76AE\u80A4
|
||||
@ -120,3 +120,13 @@ fakeplayer.command.config.set.error.invalid-value=\u672A\u77E5\u914D\u7F6E\u503C
|
||||
fakeplayer.command.generic.error.non-fake-player=\u4F60\u8FD8\u6CA1\u53EC\u5524\u5047\u4EBA\u5462
|
||||
fakeplayer.command.skin.description=\u62F7\u8D1D\u53E6\u5916\u4E00\u540D\u73A9\u5BB6\u7684\u76AE\u80A4
|
||||
fakeplayer.command.skin.error.too-many-operations=\u64CD\u4F5C\u8FC7\u4E8E\u9891\u7E41, \u4F60\u77ED\u65F6\u95F4\u5185\u4E0D\u80FD\u62F7\u8D1D\u79BB\u7EBF\u73A9\u5BB6\u7684\u76AE\u80A4, \u8BD5\u8BD5\u5728\u7EBF\u73A9\u5BB6\u7684\u5427\uFF5E
|
||||
fakeplayer.command.refill.description=\u8BBE\u7F6E\u81EA\u52A8\u586B\u88C5
|
||||
fakeplayer.manager.inventory.title=<name> \u7684\u7269\u54C1\u680F
|
||||
fakeplayer.command.invsee.error.not-the-same-world=\u53EA\u80FD\u6253\u5F00\u540C\u4E00\u4E2A\u4E16\u754C\u7684\u5047\u4EBA\u80CC\u5305
|
||||
fakeplayer.command.refill.success=<name> \u81EA\u52A8\u88C5\u586B\u5DF2 <status>
|
||||
fakeplayer.generic.enabled=\u542F\u7528
|
||||
fakeplayer.generic.disabled=\u7981\u7528
|
||||
fakeplayer.config.refillable=\u81EA\u52A8\u586B\u88C5
|
||||
fakeplayer.command.invsee.description=\u67E5\u770B\u80CC\u5305
|
||||
fakeplayer.command.sleep.description=\u7761\u89C9
|
||||
fakeplayer.command.wakeup.description=\u8D77\u5E8A
|
||||
|
@ -7,6 +7,9 @@ website: 'https://github.com/tanyaofei/minecraft-fakeplayer'
|
||||
depend:
|
||||
- CommandAPI
|
||||
|
||||
softdepend:
|
||||
- OpenInv
|
||||
|
||||
permissions:
|
||||
fakeplayer.all:
|
||||
description: '假人所有基础权限(即将删除, 请替换成 `fakeplayer.basic`)'
|
||||
|
11
pom.xml
11
pom.xml
@ -41,6 +41,10 @@
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -103,6 +107,13 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.jikoo.OpenInv</groupId>
|
||||
<artifactId>openinvapi</artifactId>
|
||||
<version>4.4.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user