1
mirror of https://github.com/CarmJos/MoeTeleport.git synced 2024-09-19 21:35:56 +00:00

1.0.2 版本更新

1. 修复back有时无法使用的问题
2. 添加权限节点的前缀,避免权限混用
3. 实装多条请求处理的提示
4. 针对home和back取消safety判断,避免无法返回。
5. 修复请求超时不清理的问题。
6. 修复部分消息不全的问题。
7. 添加Tpa/TpaHere的限制,短时间只允许一条请求,避免刷屏。
This commit is contained in:
Carm Jos 2021-12-17 13:29:12 +08:00
parent 98a88356d8
commit 5439c57dde
18 changed files with 135 additions and 169 deletions

View File

@ -13,7 +13,7 @@
<groupId>cc.carm.plugin</groupId>
<artifactId>moeteleport</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>
<name>MoeTeleport</name>
<description>喵喵传送,简单的传送、设置家的插件。</description>

View File

@ -4,8 +4,12 @@ import cc.carm.plugin.moeteleport.command.BackCommand;
import cc.carm.plugin.moeteleport.command.completer.HomeNameCompleter;
import cc.carm.plugin.moeteleport.command.completer.PlayerNameCompleter;
import cc.carm.plugin.moeteleport.command.completer.TpRequestCompleter;
import cc.carm.plugin.moeteleport.command.home.*;
import cc.carm.plugin.moeteleport.command.tpa.*;
import cc.carm.plugin.moeteleport.command.home.DelHomeCommand;
import cc.carm.plugin.moeteleport.command.home.GoHomeCommand;
import cc.carm.plugin.moeteleport.command.home.ListHomeCommand;
import cc.carm.plugin.moeteleport.command.home.SetHomeCommand;
import cc.carm.plugin.moeteleport.command.tpa.TpHandleCommand;
import cc.carm.plugin.moeteleport.command.tpa.TpaCommand;
import cc.carm.plugin.moeteleport.listener.UserListener;
import cc.carm.plugin.moeteleport.manager.ConfigManager;
import cc.carm.plugin.moeteleport.manager.RequestManager;
@ -57,9 +61,9 @@ public class Main extends JavaPlugin {
registerCommand("listHome", new ListHomeCommand());
registerCommand("tpa", new TpaCommand(), new PlayerNameCompleter());
registerCommand("tpaHere", new TpaHereCommand(), new PlayerNameCompleter());
registerCommand("tpAccept", new TpAcceptCommand(), new TpRequestCompleter());
registerCommand("tpDeny", new TpDenyCommand(), new TpRequestCompleter());
registerCommand("tpaHere", new TpaCommand(), new PlayerNameCompleter());
registerCommand("tpAccept", new TpHandleCommand(), new TpRequestCompleter());
registerCommand("tpDeny", new TpHandleCommand(), new TpRequestCompleter());
log("加载完成 ,共耗时 " + (System.currentTimeMillis() - startTime) + " ms 。");

View File

@ -21,13 +21,7 @@ public class BackCommand implements CommandExecutor {
PluginMessages.NO_LAST_LOCATION.send(player);
return true;
}
if (!TeleportManager.isSafeLocation(data.getLastLocation())) {
PluginMessages.DANGEROUS.send(player);
return true;
}
TeleportManager.teleport(player, data.getLastLocation());
TeleportManager.teleport(player, data.getLastLocation(), false);
return true;
}

View File

@ -29,7 +29,7 @@ public class DelHomeCommand implements CommandExecutor {
} else {
PluginMessages.Home.REMOVED.sendWithPlaceholders(player,
new String[]{"%(name)", "%(location)"},
new Object[]{locationInfo.getKey(), locationInfo.getValue().toString()});
new Object[]{locationInfo.getKey(), locationInfo.getValue().toFlatString()});
data.delHomeLocation(homeName);
}
return true;

View File

@ -26,7 +26,7 @@ public class GoHomeCommand implements CommandExecutor {
if (locationInfo == null) {
PluginMessages.Home.NOT_FOUND.sendWithPlaceholders(player);
} else {
TeleportManager.teleport(player, locationInfo.getValue());
TeleportManager.teleport(player, locationInfo.getValue(), false);
}
return true;
}

View File

@ -20,8 +20,8 @@ public class ListHomeCommand implements CommandExecutor {
PluginMessages.Home.HEADER.sendWithPlaceholders(player);
data.getHomeLocations().forEach((name, loc) -> PluginMessages.Home.LIST_OBJECT
.sendWithPlaceholders(player,
new String[]{"%(name)", "%(location)"},
new Object[]{name, loc.toString()}
new String[]{"%(id)", "%(location)"},
new Object[]{name, loc.toFlatString()}
));
return true;
}

View File

@ -1,47 +0,0 @@
package cc.carm.plugin.moeteleport.command.tpa;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.model.TeleportRequest;
import cc.carm.plugin.moeteleport.model.UserData;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
public class TpDenyCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
UserData data = Main.getUserManager().getData(player);
if (data.getReceivedRequests().isEmpty()) {
PluginMessages.Request.NOT_FOUND.sendWithPlaceholders(player);
return true;
}
String targetName = args.length > 0 ? args[0] : null;
if (targetName != null) {
Player target = Bukkit.getPlayer(targetName);
if (target == null || !data.getReceivedRequests().containsKey(target.getUniqueId())) {
PluginMessages.Request.NOT_FOUND_PLAYER.sendWithPlaceholders(player,
new String[]{"%(player)"},
new Object[]{target == null ? targetName : target.getName()}
);
} else {
TeleportRequest request = data.getReceivedRequests().get(target.getUniqueId());
Main.getRequestManager().denyRequest(request); // 交给Manager处理
}
} else {
data.getReceivedRequests().values().stream()
.min(Comparator.comparingLong(TeleportRequest::getActiveTime))
.ifPresent(request -> Main.getRequestManager().denyRequest(request));
}
return true;
}
}

View File

@ -13,10 +13,11 @@ import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
public class TpAcceptCommand implements CommandExecutor {
public class TpHandleCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
UserData data = Main.getUserManager().getData(player);
@ -25,6 +26,8 @@ public class TpAcceptCommand implements CommandExecutor {
return true;
}
String targetName = args.length > 0 ? args[0] : null;
boolean accept = command.getName().equalsIgnoreCase("tpAccept");
data.setEnableAutoSelect(false);
if (targetName != null) {
Player target = Bukkit.getPlayer(targetName);
if (target == null || !data.getReceivedRequests().containsKey(target.getUniqueId())) {
@ -33,15 +36,30 @@ public class TpAcceptCommand implements CommandExecutor {
new Object[]{target == null ? targetName : target.getName()}
);
} else {
TeleportRequest request = data.getReceivedRequests().get(target.getUniqueId());
Main.getRequestManager().acceptRequest(request); // 交给Manager处理
handle(data.getReceivedRequests().get(target.getUniqueId()), accept); // 交给Manager处理
}
} else {
data.getReceivedRequests().values().stream()
.min(Comparator.comparingLong(TeleportRequest::getActiveTime))
.ifPresent(request -> Main.getRequestManager().acceptRequest(request));
if (data.getReceivedRequests().size() == 1 || data.isEnableAutoSelect()) {
data.getReceivedRequests().values().stream()
.min(Comparator.comparingLong(TeleportRequest::getActiveTime))
.ifPresent(request -> handle(request, accept));
} else {
PluginMessages.Request.MULTI.sendWithPlaceholders(player,
new String[]{"%(num)", "%(command)"},
new Object[]{data.getReceivedRequests().size(), command.getName()}
);
data.setEnableAutoSelect(true);
}
}
return true;
}
private void handle(TeleportRequest request, boolean accept) {
if (accept) {
Main.getRequestManager().acceptRequest(request);
} else {
Main.getRequestManager().denyRequest(request);
}
}
}

View File

@ -13,7 +13,8 @@ import org.jetbrains.annotations.NotNull;
public class TpaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player) || args.length < 1) return false;
Player player = (Player) sender;
Player target = Bukkit.getPlayer(args[0]);
@ -21,7 +22,21 @@ public class TpaCommand implements CommandExecutor {
PluginMessages.NOT_ONLINE.sendWithPlaceholders(player);
return true;
}
Main.getRequestManager().sendRequest(player, target, TeleportRequest.RequestType.TPA);
TeleportRequest request = Main.getUserManager().getData(target).getReceivedRequests().get(player.getUniqueId());
if (request != null) {
PluginMessages.Request.DUPLICATE.sendWithPlaceholders(sender,
new String[]{"%(player)", "%(expire)"},
new Object[]{target.getName(), request.getRemainSeconds()}
);
return true;
}
if (command.getName().equalsIgnoreCase("tpa")) {
Main.getRequestManager().sendRequest(player, target, TeleportRequest.RequestType.TPA);
} else {
Main.getRequestManager().sendRequest(player, target, TeleportRequest.RequestType.TPA_HERE);
}
return true;
}

View File

@ -1,28 +0,0 @@
package cc.carm.plugin.moeteleport.command.tpa;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.model.TeleportRequest;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class TpaHereCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player) || args.length < 1) return false;
Player player = (Player) sender;
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
PluginMessages.NOT_ONLINE.sendWithPlaceholders(player);
return true;
}
Main.getRequestManager().sendRequest(player, target, TeleportRequest.RequestType.TPA_HERE);
return true;
}
}

View File

@ -25,6 +25,7 @@ public class PluginMessages {
public static final ConfigMessageList NOT_AVAILABLE = new ConfigMessageList("notAvailable");
public static class Request {
public static final ConfigMessageList DUPLICATE = new ConfigMessageList("request-duplicate");
public static final ConfigMessageList OFFLINE = new ConfigMessageList("offline");
public static final ConfigMessageList SENT = new ConfigMessageList("request-sent");

View File

@ -8,10 +8,12 @@ import org.bukkit.util.NumberConversions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat;
import java.util.Objects;
public class DataLocation implements Cloneable {
public static final DecimalFormat format = new DecimalFormat("0.00");
private String worldName;
private double x;
private double y;
@ -97,8 +99,8 @@ public class DataLocation implements Cloneable {
try {
return super.clone();
} catch (Exception ex) {
return null;
}
return null;
}
@Override
@ -124,6 +126,10 @@ public class DataLocation implements Cloneable {
return worldName + " " + x + " " + y + " " + z + " " + yaw + " " + pitch;
}
public String toFlatString() {
return worldName + "@" + format.format(x) + ", " + format.format(y) + ", " + format.format(z);
}
@Deprecated
public String toSerializedString() {
return serializeToText();

View File

@ -42,7 +42,10 @@ public class RequestManager {
.peek(entry -> PluginMessages.Request.RECEIVED_TIMEOUT.sendWithPlaceholders(
entry.getValue().getReceiver(), new String[]{"%(player)"},
new Object[]{entry.getValue().getSender().getName()}))
.forEach(entry -> data.getSentRequests().remove(entry.getKey()))
.peek(entry -> Main.getUserManager()
.getData(entry.getValue().getSender()).getSentRequests()
.remove(entry.getKey()))
.forEach(entry -> data.getReceivedRequests().remove(entry.getKey()))
);
}
@ -51,8 +54,9 @@ public class RequestManager {
PluginMessages.Request.SENT.sendWithPlaceholders(sender,
new String[]{"%(player)", "%(expire)"},
new Object[]{receiver, expireTime}
new Object[]{receiver.getName(), expireTime}
);
switch (type) {
case TPA: {
PluginMessages.TPA.sendWithPlaceholders(receiver,
@ -85,7 +89,7 @@ public class RequestManager {
new String[]{"%(player)"},
new Object[]{request.getSender().getName()}
);
TeleportManager.teleport(request.getTeleportPlayer(), request.getTeleportLocation());
TeleportManager.teleport(request.getTeleportPlayer(), request.getTeleportLocation(), true);
removeRequests(request);
}

View File

@ -1,5 +1,6 @@
package cc.carm.plugin.moeteleport.manager;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
@ -10,29 +11,34 @@ import org.bukkit.entity.Player;
public class TeleportManager {
public static void teleport(Player player, DataLocation targetLocation) {
public static void teleport(Player player, DataLocation targetLocation, boolean onlySafety) {
Location location = targetLocation.getBukkitLocation();
if (location == null) {
PluginMessages.NOT_AVAILABLE.sendWithPlaceholders(player,
new String[]{"%(location)"},
new Object[]{targetLocation.toString()}
new Object[]{targetLocation.toFlatString()}
);
} else {
teleport(player, location);
teleport(player, location, onlySafety);
}
}
public static void teleport(Player player, Location targetLocation) {
public static void teleport(Player player, Location targetLocation, boolean onlySafety) {
if (targetLocation.isWorldLoaded()) {
player.teleport(targetLocation);
PluginMessages.TELEPORTING.sendWithPlaceholders(player,
new String[]{"%(location)"},
new Object[]{new DataLocation(targetLocation).toString()}
);
if (!onlySafety || TeleportManager.isSafeLocation(targetLocation)) {
Main.getUserManager().getData(player).setLastLocation(player.getLocation());
player.teleport(targetLocation);
PluginMessages.TELEPORTING.sendWithPlaceholders(player,
new String[]{"%(location)"},
new Object[]{new DataLocation(targetLocation).toFlatString()}
);
} else {
PluginMessages.DANGEROUS.send(player);
}
} else {
PluginMessages.NOT_AVAILABLE.sendWithPlaceholders(player,
new String[]{"%(location)"},
new Object[]{new DataLocation(targetLocation).toString()}
new Object[]{new DataLocation(targetLocation).toFlatString()}
);
}
}

View File

@ -1,8 +1,6 @@
package cc.carm.plugin.moeteleport.model;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
import cc.carm.plugin.moeteleport.configuration.PluginMessages;
import cc.carm.plugin.moeteleport.manager.TeleportManager;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@ -52,25 +50,16 @@ public class TeleportRequest {
return System.currentTimeMillis() - getCreateTime();
}
public long getRemainTime() {
return PluginConfig.EXPIRE_TIME.get() * 1000 - getActiveTime();
}
/**
* 尝试对玩家进行传送
*
* @return 是否传送成功
*/
public boolean tryTeleport(@NotNull Location location) {
if (!location.isWorldLoaded()) return false;
if (!TeleportManager.isSafeLocation(location)) {
PluginMessages.DANGEROUS.sendWithPlaceholders(getTeleportPlayer());
return false;
} else {
TeleportManager.teleport(getTeleportPlayer(), location);
return true;
}
public long getRemainSeconds() {
return getRemainTime() / 1000;
}
public boolean isExpired() {
return getActiveTime() > PluginConfig.EXPIRE_TIME.get() * 10000;
return getActiveTime() > PluginConfig.EXPIRE_TIME.get() * 1000;
}
public enum RequestType {

View File

@ -1,12 +1,10 @@
package cc.carm.plugin.moeteleport.model;
import cc.carm.plugin.moeteleport.Main;
import cc.carm.plugin.moeteleport.configuration.PluginConfig;
import cc.carm.plugin.moeteleport.configuration.location.DataLocation;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -24,8 +22,10 @@ public class UserData {
private LinkedHashMap<String, DataLocation> homeLocations;
private HashSet<UUID/*receiverUUID*/> sentRequests; // 记录发出的请求
private ConcurrentHashMap<UUID/*senderUUID*/, TeleportRequest> receivedRequests; // 记录收到的传送请求
private final HashSet<UUID/*receiverUUID*/> sentRequests = new HashSet<>(); // 记录发出的请求
private final ConcurrentHashMap<UUID/*senderUUID*/, TeleportRequest> receivedRequests = new ConcurrentHashMap<>(); // 记录收到的传送请求
public boolean enableAutoSelect = false;
public UserData(@NotNull File dataFolder, @NotNull UUID uuid) {
this(new File(dataFolder, uuid + ".yml"));
@ -88,12 +88,8 @@ public class UserData {
return lastLocation;
}
public boolean backToLocation(Player player) {
if (getLastLocation() == null) return false;
else {
player.teleport(getLastLocation());
return true;
}
public void setLastLocation(@Nullable Location lastLocation) {
this.lastLocation = lastLocation;
}
public HashSet<UUID> getSentRequests() {
@ -104,7 +100,13 @@ public class UserData {
return receivedRequests;
}
public void setEnableAutoSelect(boolean enableAutoSelect) {
this.enableAutoSelect = enableAutoSelect;
}
public boolean isEnableAutoSelect() {
return enableAutoSelect;
}
public @NotNull File getDataFile() {
return dataFile;

View File

@ -4,39 +4,41 @@ no-last-location:
not-online:
- "&f目标玩家并不在线无法发送请求。"
tpa:
- "&6%(player) &f请求传送到您身边您有%(expire)秒的时间回应。"
- "&a&l[同意] &f输入 &e/tpaccept &f同意该请求。"
- "&c&l[拒绝] &f输入 &e/tpdeny &f拒绝该请求。"
- "&d%(player) &f请求传送到您身边您有 &5%(expire)秒 &f的时间回应。"
- "&a&l[同意] &f输入 &5/tpaccept &f同意该请求。"
- "&c&l[拒绝] &f输入 &5/tpdeny &f拒绝该请求。"
tpahere:
- "&6%(player) &f请求传送您到Ta身边您有%(expire)秒的时间回应。"
- "&a&l[同意] &f输入 &e/tpaccept &f同意该请求。"
- "&c&l[拒绝] &f输入 &e/tpdeny &f拒绝该请求。"
- "&d%(player) &f请求传送您到Ta身边您有 &5%(expire)秒 &f的时间回应。"
- "&a&l[同意] &f输入 &5/tpaccept &f同意该请求。"
- "&c&l[拒绝] &f输入 &5/tpdeny &f拒绝该请求。"
tpaccept:
- "&f您同意了 &6%(player) &f的传送请求。"
- "&f您同意了 &d%(player) &f的传送请求。"
tpdeny:
- "&f您&c拒绝&f了 &6%(player) &f的传送请求。"
- "&f您&d拒绝&f了 &d%(player) &f的传送请求。"
accepted:
- "&6%(player) &f同意了您的传送请求。"
- "&d%(player) &f同意了您的传送请求。"
denied:
- "&6%(player) &c拒绝&f了您的传送请求。"
- "&d%(player) &f拒绝了您的传送请求。"
offline:
- "&6%(player) &f离线相关请求已自动取消。"
- "&d%(player) &f离线相关请求已自动取消。"
request-duplicate:
- "&f您已经向 &d%(player) &f发送过传送请求对方仍有 &5%(expire)秒 &f的时间回应该请求。"
request-sent:
- "&f成功向玩家 &6%(player) 发送传送请求,对方有%(expire)秒的时间回应该请求。"
- "&f成功向玩家 &d%(player) &f发送传送请求对方有 &5%(expire)秒 &f的时间回应该请求。"
no-request:
- "&f您当前没有任何待处理的传送请求。"
no-request-player:
- "&f您当前没有收到来自 &6%(player) &f的传送请求。"
- "&f您当前没有收到来自 &d%(player) &f的传送请求。"
multi-requests:
- "&f您当前有条请求待处理,请输入 &6%(command) <玩家名> &f决定回应谁的请求。"
- "&f您也可以再次输入 &6%(command) &f直接回应最近的一条请求。"
- "&f您当前有&d%(num)条请求&f待处理请输入 &5/%(command) <玩家名> &f决定回应谁的请求。"
- "&f您也可以再次输入 &5/%(command) &f直接回应最近的一条请求。"
request-sent-timeout:
- "&f发往 &6%(player) &f的传送请求已超时。"
- "&f发往 &d%(player) &f的传送请求已超时。"
request-received-timeout:
- "&f来自 &6%(player) &f的传送请求已超时。"
- "&f来自 &d%(player) &f的传送请求已超时。"
teleporting:
- "&f正在传送到 &6%(location) &f..."
- "&f正在传送到 &d%(location) &f..."
dangerous:
- "&f目标地点不安全传送被取消。"
dangerous-here:
@ -46,15 +48,15 @@ notAvailable:
home-list-header:
- "&f您当前设定的所有家"
home-list-object: "&8#&f%(id) &6%(location)"
home-list-object: "&8#&f%(id) &d%(location)"
home-not-found:
- "&f您还没有设置这个家请先输入 &e/setHome <家名称> &f设置一个吧"
- "&f您还没有设置这个家请先输入 &5/setHome <家名称> &f设置一个吧"
home-set:
- "&f成功设定名为 &6%(name) &f的家传送点。"
- "&f成功设定名为 &d%(name) &f的家传送点。"
home-removed:
- "&f成功移除名为 &6%(name) &f的家传送点。"
- "&f成功移除名为 &d%(name) &f的家传送点。"
- "&7原先位置为 &f%(location) &7。"
home-over-limit:
- "&f您最多只能设置 &6%(max) &f个家传送点"
- "&7可以输入 &e/delHome <家名称> &7删除之前的家传送点"
- "&7或输入 &e/setHome <家名称> &7覆盖之前的家传送点。"
- "&f您最多只能设置 &d%(max) &f个家传送点"
- "&7可以输入 &5/delHome <家名称> &7删除之前的家传送点"
- "&7或输入 &5/setHome <家名称> &7覆盖之前的家传送点。"

View File

@ -23,10 +23,10 @@ commands:
"tpaHere":
usage: "/tpaHere <玩家>"
description: 请求一个玩家传送到自己身边。
"tpaAccept":
"tpAccept":
usage: "/tpAccept [玩家]"
description: 同意一个请求,可以限定某个玩家。
"tpaDeny":
"tpDeny":
usage: "/tpDeny [玩家]"
description: 拒绝一个请求,可以限定某个玩家。