├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── feature_issues.md │ └── bugs_report.md └── workflows │ ├── release.yml │ └── maven.yml ├── .gitignore ├── lib ├── CMILib1.2.4.5.jar └── CMI-API9.3.1.2.jar ├── renovate.json ├── src └── main │ ├── java │ └── cc │ │ └── carm │ │ └── plugin │ │ └── moeteleport │ │ ├── util │ │ └── DataTaskRunner.java │ │ ├── teleport │ │ ├── target │ │ │ ├── TeleportPlayerTarget.java │ │ │ ├── TeleportLocationTarget.java │ │ │ └── TeleportTarget.java │ │ ├── TeleportQueue.java │ │ └── TeleportRequest.java │ │ ├── command │ │ ├── sub │ │ │ ├── teleport │ │ │ │ ├── TeleportRandomCommand.java │ │ │ │ ├── TeleportCancelCommand.java │ │ │ │ ├── TeleportRequestCommand.java │ │ │ │ └── TeleportHandleCommand.java │ │ │ ├── home │ │ │ │ ├── HomeListCommand.java │ │ │ │ ├── HomeTeleportCommand.java │ │ │ │ ├── HomeDeleteCommand.java │ │ │ │ ├── HomeCreateCommand.java │ │ │ │ └── HomeRenameCommand.java │ │ │ ├── ReloadCommand.java │ │ │ ├── BackCommand.java │ │ │ ├── warp │ │ │ │ ├── WarpInfoCommand.java │ │ │ │ ├── WarpTeleportCommand.java │ │ │ │ ├── WarpDeleteCommand.java │ │ │ │ ├── WarpRenameCommand.java │ │ │ │ ├── WarpListCommand.java │ │ │ │ └── WarpCreateCommand.java │ │ │ ├── TeleportCommands.java │ │ │ ├── HomeCommands.java │ │ │ └── WarpCommands.java │ │ ├── MainCommands.java │ │ └── base │ │ │ ├── HomeSubCommand.java │ │ │ ├── TeleportSubCommand.java │ │ │ └── WarpSubCommand.java │ │ ├── model │ │ └── WarpInfo.java │ │ ├── MoeTeleport.java │ │ ├── listener │ │ ├── UserListener.java │ │ └── TeleportListener.java │ │ ├── storage │ │ ├── DataSerializer.java │ │ ├── impl │ │ │ ├── PluginBasedStorage.java │ │ │ └── FileBasedStorage.java │ │ ├── database │ │ │ ├── DatabaseConfig.java │ │ │ ├── DatabaseTables.java │ │ │ └── MySQLStorage.java │ │ ├── custom │ │ │ └── CustomStorage.java │ │ ├── DataStorage.java │ │ ├── StorageMethod.java │ │ ├── UserData.java │ │ ├── extension │ │ │ ├── CMIStorage.java │ │ │ └── EssentialStorage.java │ │ └── file │ │ │ ├── YAMLStorage.java │ │ │ └── JSONStorage.java │ │ ├── manager │ │ ├── WarpManager.java │ │ ├── RequestManager.java │ │ ├── TeleportManager.java │ │ └── UserManager.java │ │ ├── conf │ │ ├── location │ │ │ └── DataLocation.java │ │ ├── PluginConfig.java │ │ └── PluginMessages.java │ │ └── Main.java │ └── resources │ ├── PLUGIN_INFO │ └── plugin.yml ├── README.md ├── README-EN.md └── pom.xml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | 2 | custom: ['https://donate.carm.cc'] 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /target/ 3 | ./*.iml 4 | *.iml 5 | asset/ -------------------------------------------------------------------------------- /lib/CMILib1.2.4.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarmJos/MoeTeleport/HEAD/lib/CMILib1.2.4.5.jar -------------------------------------------------------------------------------- /lib/CMI-API9.3.1.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarmJos/MoeTeleport/HEAD/lib/CMI-API9.3.1.2.jar -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/util/DataTaskRunner.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.util; 2 | 3 | import cc.carm.plugin.moeteleport.storage.DataStorage; 4 | 5 | @FunctionalInterface 6 | public interface DataTaskRunner { 7 | void run(DataStorage storage) throws Exception; 8 | } 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_issues.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 功能需求 3 | about: 希望我们提供更多的功能。 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **功能简述** 11 | 12 | 13 | **需求来源** 14 | 15 | 16 | **功能参考**(可选) 17 | 18 | 19 | **附加内容** 20 | 21 | -------------------------------------------------------------------------------- /src/main/resources/PLUGIN_INFO: -------------------------------------------------------------------------------- 1 | &d _____ &5 _____ _ _ 2 | &d| |___ ___&5|_ _|___| |___ ___ ___ ___| |_ 3 | &d| | | | . | -_|&5 | | | -_| | -_| . | . | _| _| 4 | &d|_|_|_|___|___|&5 |_| |___|_|___| _|___|_| |_| 5 | &8# &dMoe&5Teleport &5 |_| 6 | &f 当前版本 &d${project.version} &f查看更多信息请访问项目主页 7 | &8 -> &d https://github.com/CarmJos/MoeTeleport -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bugs_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 问题提交 3 | about: 提交并描述问题,帮助我们对其进行检查与修复。 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **问题简述** 11 | 12 | 13 | **问题来源** 14 | 20 | 21 | **预期结果**(可选) 22 | 23 | 24 | **问题截图/问题报错** 25 | 26 | 27 | **操作环境** 28 | 29 | 30 | 31 | **其他补充** 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/teleport/target/TeleportPlayerTarget.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.teleport.target; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.entity.Player; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public class TeleportPlayerTarget implements TeleportTarget { 8 | 9 | protected final @NotNull Player target; 10 | 11 | public TeleportPlayerTarget(@NotNull Player target) { 12 | this.target = target; 13 | } 14 | 15 | @Override 16 | public Location prepare() { 17 | return target.isOnline() ? target.getLocation() : null; 18 | } 19 | 20 | @Override 21 | public String getText() { 22 | return target.getName(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/teleport/TeleportRandomCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.teleport; 2 | 3 | import cc.carm.plugin.moeteleport.command.sub.TeleportCommands; 4 | import cc.carm.plugin.moeteleport.command.base.TeleportSubCommand; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.plugin.java.JavaPlugin; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public class TeleportRandomCommand extends TeleportSubCommand { 10 | 11 | public TeleportRandomCommand(@NotNull TeleportCommands parent, String name, String... aliases) { 12 | super(parent, name, aliases); 13 | } 14 | 15 | @Override 16 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 17 | return null; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | main: cc.carm.plugin.moeteleport.Main 2 | name: MoeTeleport 3 | version: ${project.version} 4 | author: CarmJos 5 | website: ${project.url} 6 | description: ${project.description} 7 | 8 | api-version: 1.13 9 | 10 | softdepend: 11 | - PlaceholderAPI 12 | - Essentials 13 | - CMI 14 | 15 | permissions: 16 | 17 | "MoeTeleport.admin": 18 | description: "插件的管理员权限节点" 19 | default: op 20 | 21 | "MoeTeleport.teleport": 22 | description: "使用传送请求相关指令的权限。" 23 | default: true 24 | 25 | "MoeTeleport.home": 26 | description: "使用家相关指令的权限。" 27 | default: true 28 | 29 | "MoeTeleport.warp": 30 | description: "使用传送请求相关指令的权限。" 31 | default: true 32 | 33 | "MoeTeleport.back": 34 | description: "使用返回相关指令的权限。" 35 | default: true 36 | 37 | commands: 38 | "MoeTeleport": 39 | description: "插件的主命令,用于重载插件或查看插件信息。" 40 | usage: "您可以输入 /MoeTeleport help 查看插件的相关帮助。" 41 | aliases: 42 | - mt -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Version 2 | 3 | on: 4 | release: 5 | types: 6 | - published # 创建release的时候触发 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v6 15 | - name: "Set up JDK" 16 | uses: actions/setup-java@v5 17 | with: 18 | java-version: '11' 19 | distribution: 'adopt' 20 | # cache: maven 21 | server-id: github 22 | server-username: MAVEN_USERNAME 23 | server-password: MAVEN_TOKEN 24 | - name: "Package" 25 | run: mvn -B package --file pom.xml -Dmaven.javadoc.skip=true -DskipTests 26 | env: 27 | MAVEN_USERNAME: ${{ github.repository_owner }} 28 | MAVEN_TOKEN: ${{secrets.GITHUB_TOKEN}} 29 | 30 | - name: "Upload Release Asset" 31 | id: upload-release-asset 32 | uses: shogo82148/actions-upload-release-asset@v1 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | with: 36 | upload_url: ${{ github.event.release.upload_url }} 37 | asset_path: asset/*.jar 38 | asset_content_type: application/java-archive -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/teleport/target/TeleportLocationTarget.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.teleport.target; 2 | 3 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 4 | import org.bukkit.Location; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class TeleportLocationTarget implements TeleportTarget { 9 | 10 | private final @NotNull DataLocation location; 11 | 12 | public TeleportLocationTarget(@NotNull DataLocation location) { 13 | this.location = location; 14 | } 15 | 16 | public TeleportLocationTarget(@NotNull Location location) { 17 | this(new DataLocation(location)); 18 | } 19 | 20 | public @NotNull DataLocation getDataLocation() { 21 | return location; 22 | } 23 | 24 | public @Nullable Location getLocation() { 25 | return getDataLocation().getBukkitLocation(); 26 | } 27 | 28 | @Override 29 | public Location prepare() { 30 | Location loc = getLocation(); 31 | if (loc == null || !loc.isWorldLoaded()) return null; 32 | return loc; 33 | } 34 | 35 | @Override 36 | public String getText() { 37 | return getDataLocation().toFlatString(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/MainCommands.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command; 2 | 3 | import cc.carm.lib.easyplugin.command.CommandHandler; 4 | import cc.carm.plugin.moeteleport.command.sub.*; 5 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 6 | import org.bukkit.command.CommandSender; 7 | import org.bukkit.plugin.java.JavaPlugin; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class MainCommands extends CommandHandler { 11 | 12 | public MainCommands(@NotNull JavaPlugin plugin) { 13 | super(plugin); 14 | 15 | registerHandler(new TeleportCommands(plugin, this, "teleport", "tp")); 16 | registerHandler(new WarpCommands(plugin, this, "warp", "warps")); 17 | registerHandler(new HomeCommands(plugin, this, "home", "homes")); 18 | 19 | registerSubCommand(new BackCommand(this, "back")); 20 | registerSubCommand(new ReloadCommand(this, "reload")); 21 | } 22 | 23 | @Override 24 | public Void noArgs(CommandSender sender) { 25 | PluginMessages.USAGE.COMMAND.send(sender); 26 | return null; 27 | } 28 | 29 | @Override 30 | public Void noPermission(CommandSender sender) { 31 | PluginMessages.NO_PERMISSION.send(sender); 32 | return null; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/teleport/target/TeleportTarget.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.teleport.target; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.block.Block; 5 | import org.bukkit.block.BlockFace; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public interface TeleportTarget { 9 | 10 | /** 11 | * 准备可传送的目的地 12 | * 13 | * @return 准备传送目的地 14 | */ 15 | @Nullable Location prepare(); 16 | 17 | /** 18 | * @return 目标的文字介绍 19 | */ 20 | String getText(); 21 | 22 | /** 23 | * 检查一个位置是否安全 24 | * 25 | * @param location 位置 26 | * @return 是否安全 27 | */ 28 | @Deprecated 29 | static boolean checkLocation(Location location) { 30 | Block leg = location.getBlock(); 31 | if (!leg.getType().isAir()) { 32 | return false; // not transparent (will suffocate) 33 | } 34 | Block head = leg.getRelative(BlockFace.UP); 35 | if (!head.getType().isAir()) { 36 | return false; // not transparent (will suffocate) 37 | } 38 | Block ground = leg.getRelative(BlockFace.DOWN); 39 | // return !PluginConfig.TELEPORTATION.DANGEROUS_TYPES.getNotNull().contains(ground.getType().name()); 40 | return !ground.isPassable(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Build & Tests 5 | 6 | on: 7 | # 支持手动触发构建 8 | workflow_dispatch: 9 | push: 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v6 18 | - name: "Set up JDK" 19 | uses: actions/setup-java@v5 20 | with: 21 | java-version: '11' 22 | distribution: 'adopt' 23 | cache: maven 24 | server-id: github 25 | server-username: MAVEN_USERNAME 26 | server-password: MAVEN_TOKEN 27 | - name: "Package" 28 | run: mvn -B package --file pom.xml 29 | env: 30 | MAVEN_USERNAME: ${{ github.repository_owner }} 31 | MAVEN_TOKEN: ${{secrets.GITHUB_TOKEN}} 32 | 33 | - name: "Target Staging" 34 | run: | 35 | mkdir artifacts 36 | cp -vrf target/ artifacts/target/ 37 | cp -vrf asset/*.jar artifacts 38 | 39 | - name: "Upload artifact" 40 | uses: actions/upload-artifact@v5 41 | with: 42 | name: Artifact 43 | path: artifacts -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/model/WarpInfo.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.model; 2 | 3 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.OfflinePlayer; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.UUID; 10 | 11 | public class WarpInfo { 12 | 13 | private final @NotNull String name; 14 | private final @Nullable UUID owner; 15 | private final @NotNull DataLocation location; 16 | 17 | public WarpInfo(@NotNull String name, @Nullable UUID owner, @NotNull DataLocation location) { 18 | this.name = name; 19 | this.owner = owner; 20 | this.location = location; 21 | } 22 | 23 | public @NotNull String getName() { 24 | return name; 25 | } 26 | 27 | public @Nullable UUID getOwner() { 28 | return owner; 29 | } 30 | 31 | public @Nullable String getOwnerName() { 32 | if (getOwner() != null) { 33 | OfflinePlayer offline = Bukkit.getOfflinePlayer(getOwner()); 34 | if (offline.getName() != null) { 35 | return offline.getName(); 36 | } 37 | } 38 | return null; 39 | } 40 | 41 | 42 | public @NotNull DataLocation getLocation() { 43 | return location; 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/MoeTeleport.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport; 2 | 3 | import cc.carm.plugin.moeteleport.manager.RequestManager; 4 | import cc.carm.plugin.moeteleport.manager.TeleportManager; 5 | import cc.carm.plugin.moeteleport.manager.UserManager; 6 | import cc.carm.plugin.moeteleport.manager.WarpManager; 7 | import cc.carm.plugin.moeteleport.storage.DataStorage; 8 | import cc.carm.plugin.moeteleport.storage.StorageMethod; 9 | 10 | public class MoeTeleport { 11 | 12 | public static DataStorage getStorage() { 13 | return Main.getInstance().storage; 14 | } 15 | 16 | public static WarpManager getWarpManager() { 17 | return Main.getInstance().warpManager; 18 | } 19 | 20 | public static UserManager getUserManager() { 21 | return Main.getInstance().userManager; 22 | } 23 | 24 | public static RequestManager getRequestManager() { 25 | return Main.getInstance().requestManager; 26 | } 27 | 28 | public static TeleportManager getTeleportManager() { 29 | return Main.getInstance().teleportManager; 30 | } 31 | 32 | 33 | public void setStorage(DataStorage storage) { 34 | Main.getInstance().storage = storage; 35 | } 36 | 37 | public void registerCustomStorage(Class storageClazz) { 38 | StorageMethod.CUSTOM.setStorageClazz(storageClazz); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/listener/UserListener.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.listener; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 5 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.entity.PlayerDeathEvent; 10 | import org.bukkit.event.player.PlayerJoinEvent; 11 | import org.bukkit.event.player.PlayerQuitEvent; 12 | 13 | public class UserListener implements Listener { 14 | 15 | @EventHandler 16 | public void onJoin(PlayerJoinEvent event) { 17 | MoeTeleport.getUserManager().loadData(event.getPlayer().getUniqueId()); 18 | } 19 | 20 | @EventHandler 21 | public void onQuit(PlayerQuitEvent event) { 22 | Player player = event.getPlayer(); 23 | MoeTeleport.getRequestManager().cancelAllRequests(player); 24 | MoeTeleport.getUserManager().unloadData(player.getUniqueId()); 25 | } 26 | 27 | @EventHandler 28 | public void onDeath(PlayerDeathEvent event) { 29 | if (PluginConfig.BACK.DEATH.getNotNull()) { 30 | Player player = event.getEntity(); 31 | MoeTeleport.getUserManager().getData(player).setLastLocation(player.getLocation()); 32 | PluginMessages.BACK.DEATH_MESSAGE.send(player); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/home/HomeListCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.home; 2 | 3 | import cc.carm.plugin.moeteleport.command.sub.HomeCommands; 4 | import cc.carm.plugin.moeteleport.command.base.HomeSubCommand; 5 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 6 | import cc.carm.plugin.moeteleport.storage.UserData; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.plugin.java.JavaPlugin; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | public class HomeListCommand extends HomeSubCommand { 13 | 14 | public HomeListCommand(@NotNull HomeCommands parent, String name, String... aliases) { 15 | super(parent, name, aliases); 16 | } 17 | 18 | @Override 19 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) { 20 | if (!(sender instanceof Player)) { 21 | PluginMessages.NOT_PLAYER.send(sender); 22 | return null; 23 | } 24 | 25 | Player player = (Player) sender; 26 | UserData data = getData(player); 27 | 28 | if (data.getHomeLocations().isEmpty()) { 29 | PluginMessages.HOME.EMPTY.send(sender); 30 | return null; 31 | } 32 | 33 | PluginMessages.HOME.LIST.HEADER.send(player); 34 | data.getHomeLocations().forEach((name, loc) -> PluginMessages.HOME.LIST.OBJECT.send(player, name, loc.toFlatString())); 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/ReloadCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub; 2 | 3 | import cc.carm.lib.easyplugin.command.SubCommand; 4 | import cc.carm.plugin.moeteleport.Main; 5 | import cc.carm.plugin.moeteleport.command.MainCommands; 6 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.plugin.java.JavaPlugin; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class ReloadCommand extends SubCommand { 12 | 13 | public ReloadCommand(@NotNull MainCommands parent, String name, String... aliases) { 14 | super(parent, name, aliases); 15 | } 16 | 17 | @Override 18 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) { 19 | 20 | PluginMessages.RELOAD.START.send(sender); 21 | long s1 = System.currentTimeMillis(); 22 | 23 | try { 24 | Main.getInstance().getConfigProvider().reload(); 25 | Main.getInstance().getMessageProvider().reload(); 26 | 27 | PluginMessages.RELOAD.COMPLETE.send(sender, System.currentTimeMillis() - s1); 28 | } catch (Exception ex) { 29 | PluginMessages.RELOAD.ERROR.send(sender); 30 | ex.printStackTrace(); 31 | } 32 | 33 | return null; 34 | } 35 | 36 | @Override 37 | public boolean hasPermission(CommandSender sender) { 38 | return sender.hasPermission("MoeTeleport.admin"); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/base/HomeSubCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.base; 2 | 3 | import cc.carm.lib.easyplugin.command.SubCommand; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.command.sub.HomeCommands; 6 | import cc.carm.plugin.moeteleport.storage.UserData; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.util.StringUtil; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | import java.util.UUID; 16 | import java.util.stream.Collectors; 17 | 18 | public abstract class HomeSubCommand extends SubCommand { 19 | public HomeSubCommand(@NotNull HomeCommands parent, String name, String... aliases) { 20 | super(parent, name, aliases); 21 | } 22 | 23 | public @NotNull UserData getData(Player player) { 24 | return MoeTeleport.getUserManager().getData(player); 25 | } 26 | 27 | public @Nullable UserData getData(UUID player) { 28 | return MoeTeleport.getUserManager().getData(player); 29 | } 30 | 31 | public @NotNull List listHomes(CommandSender sender, String input) { 32 | if (!(sender instanceof Player)) return Collections.emptyList(); 33 | 34 | return MoeTeleport.getUserManager().getData((Player) sender) 35 | .getHomeLocations().keySet().stream() 36 | .filter(s -> StringUtil.startsWithIgnoreCase(s, input)) 37 | .limit(10).collect(Collectors.toList()); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/teleport/TeleportQueue.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.teleport; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.storage.UserData; 5 | import cc.carm.plugin.moeteleport.teleport.target.TeleportTarget; 6 | import org.bukkit.entity.Player; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.time.Duration; 11 | 12 | public class TeleportQueue { 13 | 14 | private final @NotNull Player player; 15 | private final @NotNull TeleportTarget target; 16 | 17 | private final long createMillis; 18 | private final long executeMillis; 19 | 20 | public TeleportQueue(@NotNull Player player, @NotNull TeleportTarget target, @Nullable Duration delay) { 21 | this.player = player; 22 | this.target = target; 23 | this.createMillis = System.currentTimeMillis(); 24 | this.executeMillis = delay == null ? 0 : System.currentTimeMillis() + delay.toMillis(); 25 | } 26 | 27 | public @NotNull Player getPlayer() { 28 | return player; 29 | } 30 | 31 | public @NotNull UserData getUser() { 32 | return MoeTeleport.getUserManager().getData(getPlayer()); 33 | } 34 | 35 | public @NotNull TeleportTarget getTarget() { 36 | return target; 37 | } 38 | 39 | public long getCreateMillis() { 40 | return createMillis; 41 | } 42 | 43 | public long getExecuteMillis() { 44 | return executeMillis; 45 | } 46 | 47 | public long getRemainSeconds() { 48 | return (executeMillis - System.currentTimeMillis()) / 1000; 49 | } 50 | 51 | public boolean checkTime() { 52 | return System.currentTimeMillis() >= executeMillis; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/BackCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub; 2 | 3 | import cc.carm.lib.easyplugin.command.SubCommand; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.command.MainCommands; 6 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 7 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 8 | import cc.carm.plugin.moeteleport.storage.UserData; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.plugin.java.JavaPlugin; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public class BackCommand extends SubCommand { 15 | 16 | public BackCommand(@NotNull MainCommands parent, String name, String... aliases) { 17 | super(parent, name, aliases); 18 | } 19 | 20 | @Override 21 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) { 22 | if (!(sender instanceof Player)) { 23 | PluginMessages.NOT_PLAYER.send(sender); 24 | return null; 25 | } 26 | 27 | if (!PluginConfig.BACK.ENABLE.getNotNull()) { 28 | PluginMessages.NOT_ENABLED.send(sender); 29 | return null; 30 | } 31 | 32 | Player player = (Player) sender; 33 | UserData data = MoeTeleport.getUserManager().getData(player); 34 | if (data.getLastLocation() == null) { 35 | PluginMessages.BACK.NO_LAST_LOCATION.send(player); 36 | return null; 37 | } 38 | MoeTeleport.getTeleportManager().queueTeleport(player, data.getLastLocation()); 39 | return null; 40 | } 41 | 42 | @Override 43 | public boolean hasPermission(CommandSender sender) { 44 | return sender.hasPermission("MoeTeleport.back"); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/warp/WarpInfoCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.warp; 2 | 3 | import cc.carm.plugin.moeteleport.command.sub.WarpCommands; 4 | import cc.carm.plugin.moeteleport.command.base.WarpSubCommand; 5 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 6 | import cc.carm.plugin.moeteleport.model.WarpInfo; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.plugin.java.JavaPlugin; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | public class WarpInfoCommand extends WarpSubCommand { 15 | 16 | public WarpInfoCommand(@NotNull WarpCommands parent, String name, String... aliases) { 17 | super(parent, name, aliases); 18 | } 19 | 20 | @Override 21 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) { 22 | String warpName = args[0]; 23 | 24 | WarpInfo info = getWarp(warpName); 25 | if (info == null) { 26 | PluginMessages.WARP.NOT_FOUND.send(sender, warpName); 27 | return null; 28 | } 29 | 30 | String ownerName = info.getOwnerName(); 31 | if (ownerName != null) { 32 | PluginMessages.WARP.INFO_FULL.send(sender, warpName, ownerName, info.getLocation().toFlatString()); 33 | } else { 34 | PluginMessages.WARP.INFO_LOCATION.send(sender, warpName, info.getLocation().toFlatString()); 35 | } 36 | 37 | return null; 38 | } 39 | 40 | @Override 41 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 42 | if (args.length == 1) { 43 | return listWarpNames(sender, args[args.length - 1], false); 44 | } else return Collections.emptyList(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/DataSerializer.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage; 2 | 3 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 4 | import cc.carm.plugin.moeteleport.model.WarpInfo; 5 | import org.bukkit.Location; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.LinkedHashMap; 9 | import java.util.Map; 10 | import java.util.Optional; 11 | 12 | public class DataSerializer { 13 | 14 | public static Map serializeLocationsMap(LinkedHashMap data) { 15 | LinkedHashMap after = new LinkedHashMap<>(); 16 | if (data == null || data.isEmpty()) return after; 17 | data.forEach((name, loc) -> after.put(name, loc.serializeToText())); 18 | return after; 19 | } 20 | 21 | public static @Nullable String serializeLocation(@Nullable DataLocation loc) { 22 | return Optional.ofNullable(loc).map(DataLocation::serializeToText).orElse(null); 23 | } 24 | 25 | public static @Nullable String serializeLocation(@Nullable Location loc) { 26 | return serializeLocation(Optional.ofNullable(loc).map(DataLocation::new).orElse(null)); 27 | } 28 | 29 | public static Map serializeWarpMap(WarpInfo info) { 30 | LinkedHashMap after = new LinkedHashMap<>(); 31 | if (info.getOwner() != null) after.put("owner", info.getOwner().toString()); 32 | after.put("world", info.getLocation().getWorldName()); 33 | after.put("x", info.getLocation().getX()); 34 | after.put("y", info.getLocation().getY()); 35 | after.put("z", info.getLocation().getZ()); 36 | after.put("yaw", info.getLocation().getYaw()); 37 | after.put("pitch", info.getLocation().getPitch()); 38 | return after; 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/impl/PluginBasedStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.impl; 2 | 3 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 4 | import cc.carm.plugin.moeteleport.storage.UserData; 5 | import cc.carm.plugin.moeteleport.model.WarpInfo; 6 | import cc.carm.plugin.moeteleport.storage.DataStorage; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.plugin.Plugin; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Map; 12 | import java.util.UUID; 13 | 14 | public abstract class PluginBasedStorage implements DataStorage { 15 | 16 | protected Plugin dependPlugin; 17 | 18 | public PluginBasedStorage(String dependPluginName) { 19 | this.dependPlugin = Bukkit.getPluginManager().getPlugin(dependPluginName); 20 | } 21 | 22 | @Override 23 | public void initialize() throws NullPointerException { 24 | if (dependPlugin == null) { 25 | throw new NullPointerException("该存储类型依赖的插件不存在,请检查配置文件"); 26 | } 27 | } 28 | 29 | public Plugin getDependPlugin() { 30 | return dependPlugin; 31 | } 32 | 33 | @Override 34 | public void shutdown() { 35 | // 一般啥也不需要我们做 36 | } 37 | 38 | @Override 39 | public void saveUserData(@NotNull UserData data) { 40 | // 一般都由其他插件自行保存,不需要实现。 41 | } 42 | 43 | @Override 44 | public void saveWarps(@NotNull Map warps) { 45 | // 一般都由其他插件自行保存,不需要实现。 46 | } 47 | 48 | @Override 49 | public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) { 50 | // 一般都由其他插件自行保存,不需要实现。 51 | } 52 | 53 | @Override 54 | public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) { 55 | // 一般都由其他插件自行保存,不需要实现。 56 | return true; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/warp/WarpTeleportCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.warp; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.command.sub.WarpCommands; 5 | import cc.carm.plugin.moeteleport.command.base.WarpSubCommand; 6 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 7 | import cc.carm.plugin.moeteleport.model.WarpInfo; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | public class WarpTeleportCommand extends WarpSubCommand { 17 | 18 | public WarpTeleportCommand(@NotNull WarpCommands parent, String name, String... aliases) { 19 | super(parent, name, aliases); 20 | } 21 | 22 | @Override 23 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) { 24 | if (!(sender instanceof Player)) { 25 | PluginMessages.NOT_PLAYER.send(sender); 26 | return null; 27 | } 28 | 29 | if (args.length < 1) return getParent().noArgs(sender); 30 | 31 | Player player = (Player) sender; 32 | 33 | WarpInfo info = getWarp(args[0]); 34 | if (info == null) { 35 | PluginMessages.WARP.NOT_FOUND.send(player, args[0]); 36 | return null; 37 | } 38 | 39 | MoeTeleport.getTeleportManager().queueTeleport(player, info.getLocation()); 40 | return null; 41 | } 42 | 43 | @Override 44 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 45 | if (args.length == 1) { 46 | return listWarpNames(sender, args[args.length - 1], false); 47 | } else return Collections.emptyList(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/teleport/TeleportCancelCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.teleport; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.command.sub.TeleportCommands; 5 | import cc.carm.plugin.moeteleport.command.base.TeleportSubCommand; 6 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 7 | import cc.carm.plugin.moeteleport.teleport.TeleportRequest; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | public class TeleportCancelCommand extends TeleportSubCommand { 17 | 18 | public TeleportCancelCommand(@NotNull TeleportCommands parent, String name, String... aliases) { 19 | super(parent, name, aliases); 20 | } 21 | 22 | @Override 23 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 24 | if (!(sender instanceof Player)) { 25 | PluginMessages.NOT_PLAYER.send(sender); 26 | return null; 27 | } 28 | 29 | Player player = (Player) sender; 30 | 31 | TeleportRequest request = MoeTeleport.getRequestManager().getRequest(player.getUniqueId()); 32 | if (request == null) { 33 | PluginMessages.REQUESTS.EMPTY_REQUESTS.send(player); 34 | return null; 35 | } 36 | 37 | MoeTeleport.getRequestManager().cancelRequest(request); 38 | return null; 39 | } 40 | 41 | @Override 42 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 43 | if (args.length == 1) { 44 | return listRequests(sender, args[args.length - 1]); 45 | } else return Collections.emptyList(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/base/TeleportSubCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.base; 2 | 3 | import cc.carm.lib.easyplugin.command.SubCommand; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.command.sub.TeleportCommands; 6 | import cc.carm.plugin.moeteleport.storage.UserData; 7 | import cc.carm.plugin.moeteleport.teleport.TeleportRequest; 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.entity.HumanEntity; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.util.StringUtil; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.*; 17 | import java.util.stream.Collectors; 18 | 19 | public abstract class TeleportSubCommand extends SubCommand { 20 | 21 | public TeleportSubCommand(@NotNull TeleportCommands parent, String name, String... aliases) { 22 | super(parent, name, aliases); 23 | } 24 | 25 | public @NotNull UserData getData(Player player) { 26 | return MoeTeleport.getUserManager().getData(player); 27 | } 28 | 29 | public @Nullable UserData getData(UUID player) { 30 | return MoeTeleport.getUserManager().getData(player); 31 | } 32 | 33 | public @NotNull List listRequests(CommandSender sender, String input) { 34 | if (!(sender instanceof Player)) return Collections.emptyList(); 35 | return getReceivedRequests((Player) sender).keySet().stream() 36 | .map(Bukkit::getPlayer).filter(Objects::nonNull).map(HumanEntity::getName) 37 | .filter(s -> StringUtil.startsWithIgnoreCase(s, input)) 38 | .limit(10).collect(Collectors.toList()); 39 | } 40 | 41 | public @NotNull Map getReceivedRequests(Player player) { 42 | return MoeTeleport.getRequestManager().getUserReceivedRequests(player.getUniqueId()); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/TeleportCommands.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub; 2 | 3 | import cc.carm.lib.easyplugin.command.CommandHandler; 4 | import cc.carm.plugin.moeteleport.command.MainCommands; 5 | import cc.carm.plugin.moeteleport.command.sub.teleport.TeleportCancelCommand; 6 | import cc.carm.plugin.moeteleport.command.sub.teleport.TeleportHandleCommand; 7 | import cc.carm.plugin.moeteleport.command.sub.teleport.TeleportRequestCommand; 8 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 9 | import cc.carm.plugin.moeteleport.teleport.TeleportRequest; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.plugin.java.JavaPlugin; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public class TeleportCommands extends CommandHandler { 15 | 16 | protected final @NotNull MainCommands main; 17 | 18 | public TeleportCommands(@NotNull JavaPlugin plugin, @NotNull MainCommands main, 19 | @NotNull String cmd, @NotNull String... aliases) { 20 | super(plugin, cmd, aliases); 21 | this.main = main; 22 | 23 | registerSubCommand(new TeleportRequestCommand(this, TeleportRequest.Type.TPA_TO, "to")); 24 | registerSubCommand(new TeleportRequestCommand(this, TeleportRequest.Type.TPA_HERE, "here")); 25 | registerSubCommand(new TeleportHandleCommand(this, true, "accept", "agree")); 26 | registerSubCommand(new TeleportHandleCommand(this, false, "deny", "refuse")); 27 | registerSubCommand(new TeleportCancelCommand(this, "cancel")); 28 | } 29 | 30 | @Override 31 | public Void noArgs(CommandSender sender) { 32 | PluginMessages.USAGE.TELEPORT.send(sender); 33 | return null; 34 | } 35 | 36 | @Override 37 | public Void noPermission(CommandSender sender) { 38 | return main.noPermission(sender); 39 | } 40 | 41 | @Override 42 | public boolean hasPermission(CommandSender sender) { 43 | return sender.hasPermission("MoeTeleport.teleport"); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/home/HomeTeleportCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.home; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.command.sub.HomeCommands; 5 | import cc.carm.plugin.moeteleport.command.base.HomeSubCommand; 6 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 7 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 8 | import cc.carm.plugin.moeteleport.storage.UserData; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.plugin.java.JavaPlugin; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.Collections; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | public class HomeTeleportCommand extends HomeSubCommand { 19 | 20 | public HomeTeleportCommand(@NotNull HomeCommands parent, String name, String... aliases) { 21 | super(parent, name, aliases); 22 | } 23 | 24 | @Override 25 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 26 | if (!(sender instanceof Player)) { 27 | PluginMessages.NOT_PLAYER.send(sender); 28 | return null; 29 | } 30 | 31 | Player player = (Player) sender; 32 | UserData data = getData(player); 33 | String homeName = args.length >= 1 ? args[0] : null; 34 | 35 | Map.Entry locationInfo = data.getHomeLocation(homeName); 36 | if (locationInfo == null) { 37 | PluginMessages.HOME.NOT_FOUND.send(player); 38 | } else { 39 | MoeTeleport.getTeleportManager().queueTeleport(player, locationInfo.getValue()); 40 | } 41 | 42 | return null; 43 | } 44 | 45 | @Override 46 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 47 | if (args.length == 1) { 48 | return listHomes(sender, args[args.length - 1]); 49 | } else return Collections.emptyList(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/database/DatabaseConfig.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.database; 2 | 3 | import cc.carm.lib.configuration.core.ConfigurationRoot; 4 | import cc.carm.lib.configuration.core.annotation.ConfigPath; 5 | import cc.carm.lib.configuration.core.annotation.HeaderComment; 6 | import cc.carm.lib.configuration.core.value.ConfigValue; 7 | import cc.carm.lib.configuration.core.value.type.ConfiguredValue; 8 | 9 | 10 | @HeaderComment("选择 database (如mysql) 存储方式时的数据库配置") 11 | @ConfigPath("storage.database") 12 | public class DatabaseConfig extends ConfigurationRoot { 13 | 14 | @ConfigPath("driver") 15 | protected static final ConfigValue DRIVER_NAME = ConfiguredValue.of( 16 | String.class, "com.mysql.jdbc.Driver" 17 | ); 18 | 19 | protected static final ConfigValue HOST = ConfiguredValue.of(String.class, "127.0.0.1"); 20 | protected static final ConfigValue PORT = ConfiguredValue.of(Integer.class, 3306); 21 | protected static final ConfigValue DATABASE = ConfiguredValue.of(String.class, "minecraft"); 22 | protected static final ConfigValue USERNAME = ConfiguredValue.of(String.class, "root"); 23 | protected static final ConfigValue PASSWORD = ConfiguredValue.of(String.class, "password"); 24 | protected static final ConfigValue EXTRA = ConfiguredValue.of(String.class, "?useSSL=false"); 25 | 26 | @HeaderComment("插件相关表的名称") 27 | public static final class TABLES extends ConfigurationRoot { 28 | 29 | public static final ConfigValue LAST_LOCATION = ConfiguredValue.of(String.class, "mt_last_locations"); 30 | public static final ConfigValue HOMES = ConfiguredValue.of(String.class, "mt_homes"); 31 | public static final ConfigValue WARPS = ConfiguredValue.of(String.class, "mt_warps"); 32 | 33 | } 34 | 35 | protected static String buildJDBC() { 36 | return String.format("jdbc:mysql://%s:%s/%s%s", 37 | HOST.getNotNull(), PORT.getNotNull(), DATABASE.getNotNull(), EXTRA.getNotNull() 38 | ); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/home/HomeDeleteCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.home; 2 | 3 | import cc.carm.plugin.moeteleport.command.sub.HomeCommands; 4 | import cc.carm.plugin.moeteleport.command.base.HomeSubCommand; 5 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 6 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 7 | import cc.carm.plugin.moeteleport.storage.UserData; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | public class HomeDeleteCommand extends HomeSubCommand { 18 | 19 | public HomeDeleteCommand(@NotNull HomeCommands parent, String name, String... aliases) { 20 | super(parent, name, aliases); 21 | } 22 | 23 | @Override 24 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 25 | if (!(sender instanceof Player)) { 26 | PluginMessages.NOT_PLAYER.send(sender); 27 | return null; 28 | } 29 | 30 | if (args.length < 1) return getParent().noArgs(sender); 31 | 32 | Player player = (Player) sender; 33 | UserData data = getData(player); 34 | String homeName = args[0]; 35 | 36 | Map.Entry locationInfo = data.getHomeLocation(homeName); 37 | if (locationInfo == null) { 38 | PluginMessages.HOME.NOT_FOUND.send(player); 39 | } else { 40 | PluginMessages.HOME.REMOVED.send(player, locationInfo.getKey(), locationInfo.getValue().toFlatString()); 41 | data.delHomeLocation(homeName); 42 | } 43 | 44 | return null; 45 | } 46 | 47 | @Override 48 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 49 | if (args.length == 1) { 50 | return listHomes(sender, args[args.length - 1]); 51 | } else return Collections.emptyList(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/warp/WarpDeleteCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.warp; 2 | 3 | import cc.carm.plugin.moeteleport.command.sub.WarpCommands; 4 | import cc.carm.plugin.moeteleport.command.base.WarpSubCommand; 5 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 6 | import cc.carm.plugin.moeteleport.model.WarpInfo; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.plugin.java.JavaPlugin; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | public class WarpDeleteCommand extends WarpSubCommand { 16 | 17 | public WarpDeleteCommand(@NotNull WarpCommands parent, String name, String... aliases) { 18 | super(parent, name, aliases); 19 | } 20 | 21 | @Override 22 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 23 | if (args.length < 1) return getParent().noArgs(sender); 24 | 25 | String warpName = args[0]; 26 | 27 | WarpInfo info = getWarp(warpName); 28 | if (info == null) { 29 | PluginMessages.WARP.NOT_FOUND.send(sender, warpName); 30 | return null; 31 | } 32 | 33 | if (sender instanceof Player && !sender.isOp() 34 | && !sender.hasPermission("MoeTeleport.admin")) { 35 | Player player = (Player) sender; 36 | if (info.getOwner() == null || !info.getOwner().equals(player.getUniqueId())) { 37 | PluginMessages.WARP.NOT_OWNER.send(sender); 38 | return null; 39 | } 40 | } 41 | 42 | getManager().delWarpAsync(warpName); 43 | PluginMessages.WARP.REMOVED.send(sender, warpName, info.getLocation().toFlatString()); 44 | 45 | return null; 46 | } 47 | 48 | @Override 49 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 50 | if (args.length == 1) { 51 | return listWarpNames(sender, args[args.length - 1], true); 52 | } else return Collections.emptyList(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/base/WarpSubCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.base; 2 | 3 | import cc.carm.lib.easyplugin.command.SubCommand; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.command.sub.WarpCommands; 6 | import cc.carm.plugin.moeteleport.manager.WarpManager; 7 | import cc.carm.plugin.moeteleport.model.WarpInfo; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.util.StringUtil; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Unmodifiable; 13 | 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.stream.Collectors; 17 | 18 | public abstract class WarpSubCommand extends SubCommand { 19 | public WarpSubCommand(@NotNull WarpCommands parent, String name, String... aliases) { 20 | super(parent, name, aliases); 21 | } 22 | 23 | public WarpManager getManager() { 24 | return MoeTeleport.getWarpManager(); 25 | } 26 | 27 | @NotNull 28 | @Unmodifiable 29 | public Map listWarps() { 30 | return getManager().listWarps(); 31 | } 32 | 33 | public WarpInfo getWarp(@NotNull String name) { 34 | return getManager().getWarp(name); 35 | } 36 | 37 | public List listWarpNames(CommandSender sender, String input, boolean limitOwner) { 38 | if (limitOwner && sender instanceof Player) { 39 | Player player = (Player) sender; 40 | return listWarps().entrySet().stream() 41 | .filter(entry -> entry.getValue().getOwner() != null) 42 | .filter(entry -> entry.getValue().getOwner().equals(player.getUniqueId())) 43 | .map(Map.Entry::getKey) 44 | .filter(s -> StringUtil.startsWithIgnoreCase(s, input)) 45 | .limit(10).collect(Collectors.toList()); 46 | } else { 47 | return listWarps().keySet().stream() 48 | .filter(s -> StringUtil.startsWithIgnoreCase(s, input)) 49 | .limit(10).collect(Collectors.toList()); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/HomeCommands.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub; 2 | 3 | import cc.carm.lib.easyplugin.command.CommandHandler; 4 | import cc.carm.plugin.moeteleport.command.MainCommands; 5 | import cc.carm.plugin.moeteleport.command.sub.home.*; 6 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 7 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 8 | import org.bukkit.command.Command; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class HomeCommands extends CommandHandler { 14 | 15 | protected final @NotNull MainCommands main; 16 | 17 | public HomeCommands(@NotNull JavaPlugin plugin, @NotNull MainCommands main, 18 | @NotNull String cmd, @NotNull String... aliases) { 19 | super(plugin, cmd, aliases); 20 | this.main = main; 21 | 22 | registerSubCommand(new HomeTeleportCommand(this, "to", "teleport", "tp")); 23 | registerSubCommand(new HomeListCommand(this, "list", "ls")); 24 | registerSubCommand(new HomeCreateCommand(this, "set", "create")); 25 | registerSubCommand(new HomeDeleteCommand(this, "delete", "remove", "del")); 26 | registerSubCommand(new HomeRenameCommand(this, "rename", "rn")); 27 | } 28 | 29 | 30 | @Override 31 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 32 | if (!PluginConfig.HOMES.ENABLE.getNotNull()) { 33 | PluginMessages.NOT_ENABLED.send(sender); 34 | return true; 35 | } 36 | 37 | return super.onCommand(sender, command, label, args); 38 | } 39 | 40 | @Override 41 | public Void noArgs(CommandSender sender) { 42 | PluginMessages.USAGE.HOMES.send(sender); 43 | return null; 44 | } 45 | 46 | @Override 47 | public Void noPermission(CommandSender sender) { 48 | return main.noPermission(sender); 49 | } 50 | 51 | @Override 52 | public boolean hasPermission(CommandSender sender) { 53 | return sender.hasPermission("MoeTeleport.home"); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/listener/TeleportListener.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.listener; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 5 | import cc.carm.plugin.moeteleport.teleport.TeleportQueue; 6 | import org.bukkit.Location; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.EventHandler; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 11 | import org.bukkit.event.player.PlayerMoveEvent; 12 | import org.bukkit.event.player.PlayerToggleSneakEvent; 13 | 14 | public class TeleportListener implements Listener { 15 | 16 | @EventHandler 17 | public void onMove(PlayerMoveEvent event) { 18 | if (!PluginConfig.TELEPORTATION.INTERRUPT.MOVE.getNotNull()) return; 19 | 20 | Location from = event.getFrom(); 21 | Location to = event.getTo(); 22 | if (to == null) return; 23 | 24 | if (from.getBlockX() == to.getBlockX() 25 | && from.getBlockY() == to.getBlockY() 26 | && from.getBlockZ() == to.getBlockZ()) { 27 | return; 28 | } 29 | 30 | TeleportQueue queue = MoeTeleport.getTeleportManager().getQueue(event.getPlayer()); 31 | if (queue == null) return; 32 | 33 | MoeTeleport.getTeleportManager().interruptQueue(queue); 34 | } 35 | 36 | @EventHandler 37 | public void onDamage(EntityDamageByEntityEvent event) { 38 | if (!PluginConfig.TELEPORTATION.INTERRUPT.ATTACK.getNotNull()) return; 39 | if (!(event.getEntity() instanceof Player)) return; 40 | 41 | TeleportQueue queue = MoeTeleport.getTeleportManager().getQueue((Player) event.getEntity()); 42 | if (queue == null) return; 43 | 44 | MoeTeleport.getTeleportManager().interruptQueue(queue); 45 | } 46 | 47 | @EventHandler 48 | public void onSnake(PlayerToggleSneakEvent event) { 49 | if (!PluginConfig.TELEPORTATION.INTERRUPT.SNAKE.getNotNull()) return; 50 | TeleportQueue queue = MoeTeleport.getTeleportManager().getQueue(event.getPlayer()); 51 | if (queue == null) return; 52 | 53 | MoeTeleport.getTeleportManager().interruptQueue(queue); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/WarpCommands.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub; 2 | 3 | import cc.carm.lib.easyplugin.command.CommandHandler; 4 | import cc.carm.plugin.moeteleport.command.MainCommands; 5 | import cc.carm.plugin.moeteleport.command.sub.warp.*; 6 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 7 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 8 | import org.bukkit.command.Command; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class WarpCommands extends CommandHandler { 14 | 15 | protected final @NotNull MainCommands main; 16 | 17 | public WarpCommands(@NotNull JavaPlugin plugin, @NotNull MainCommands main, 18 | @NotNull String cmd, @NotNull String... aliases) { 19 | super(plugin, cmd, aliases); 20 | this.main = main; 21 | 22 | registerSubCommand(new WarpTeleportCommand(this, "to", "teleport", "tp")); 23 | registerSubCommand(new WarpListCommand(this, "list", "ls")); 24 | registerSubCommand(new WarpInfoCommand(this, "info", "i")); 25 | registerSubCommand(new WarpCreateCommand(this, "set", "create")); 26 | registerSubCommand(new WarpDeleteCommand(this, "delete", "remove", "del")); 27 | registerSubCommand(new WarpRenameCommand(this, "rename", "rn")); 28 | 29 | } 30 | 31 | @Override 32 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 33 | if (!PluginConfig.WARPS.ENABLE.getNotNull()) { 34 | PluginMessages.NOT_ENABLED.send(sender); 35 | return true; 36 | } 37 | 38 | return super.onCommand(sender, command, label, args); 39 | } 40 | 41 | @Override 42 | public Void noArgs(CommandSender sender) { 43 | PluginMessages.USAGE.WARPS.send(sender); 44 | return null; 45 | } 46 | 47 | @Override 48 | public Void noPermission(CommandSender sender) { 49 | return main.noPermission(sender); 50 | } 51 | 52 | 53 | @Override 54 | public boolean hasPermission(CommandSender sender) { 55 | return sender.hasPermission("MoeTeleport.warp"); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/custom/CustomStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.custom; 2 | 3 | import cc.carm.plugin.moeteleport.Main; 4 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 5 | import cc.carm.plugin.moeteleport.storage.UserData; 6 | import cc.carm.plugin.moeteleport.model.WarpInfo; 7 | import cc.carm.plugin.moeteleport.storage.DataStorage; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | import org.jetbrains.annotations.TestOnly; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.UUID; 15 | 16 | public class CustomStorage implements DataStorage { 17 | 18 | @Override 19 | @TestOnly 20 | public void initialize() throws UnsupportedOperationException { 21 | Main.severe("您选择使用自定义存储,但并没有应用成功。"); 22 | Main.severe("You are using CustomStorage, but not overwrite the methods."); 23 | throw new UnsupportedOperationException("您选择使用自定义存储,但并没有应用成功。"); 24 | } 25 | 26 | @Override 27 | @TestOnly 28 | public void shutdown() { 29 | 30 | } 31 | 32 | @Override 33 | @TestOnly 34 | public @Nullable UserData loadData(@NotNull UUID uuid) throws UnsupportedOperationException { 35 | throw new UnsupportedOperationException("您选择使用自定义存储,但并没有应用成功。"); 36 | } 37 | 38 | @Override 39 | @TestOnly 40 | public void saveUserData(@NotNull UserData data) throws UnsupportedOperationException { 41 | throw new UnsupportedOperationException("您选择使用自定义存储,但并没有应用成功。"); 42 | } 43 | 44 | @Override 45 | public Map getWarps() { 46 | return new HashMap<>(); 47 | } 48 | 49 | @Override 50 | public void saveWarps(@NotNull Map warps) { 51 | 52 | } 53 | 54 | @Override 55 | public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) { 56 | 57 | } 58 | 59 | @Override 60 | public boolean delWarp(@NotNull String name) { 61 | return true; 62 | } 63 | 64 | @Override 65 | public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) throws Exception { 66 | } 67 | 68 | @Override 69 | public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) { 70 | return true; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/DataStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage; 2 | 3 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 4 | import cc.carm.plugin.moeteleport.manager.UserManager; 5 | import cc.carm.plugin.moeteleport.model.WarpInfo; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.Map; 10 | import java.util.UUID; 11 | 12 | public interface DataStorage { 13 | 14 | /** 15 | * 在插件加载存储源时执行。 16 | * 17 | * @throws Exception 当出现任何错误时抛出 18 | */ 19 | void initialize() throws Exception; 20 | 21 | /** 22 | * 在插件被卸载时执行。 23 | */ 24 | void shutdown(); 25 | 26 | /** 27 | * 用于加载用户数据的方法。该方法将会被异步运行! 28 | *
该方法一般无需自行执行,见 {@link UserManager#loadData(UUID)} 29 | *
30 | *
若不存在该用户的数据,请返回 null 。 31 | *
若加载出现任何错误,请抛出异常。 32 | * 33 | * @param uuid 用户UUID 34 | * @throws Exception 当出现任何错误时抛出 35 | */ 36 | @Nullable 37 | UserData loadData(@NotNull UUID uuid) throws Exception; 38 | 39 | /** 40 | * 用于保存用户数据的方法。 该方法将会被异步运行! 41 | *
该方法一般无需自行执行,见 {@link UserManager#saveData(UserData)} 42 | * 43 | * @param data 用户数据 44 | * @throws Exception 当出现任何错误时抛出 45 | */ 46 | void saveUserData(@NotNull UserData data) throws Exception; 47 | 48 | Map getWarps(); 49 | 50 | default void saveWarps() throws Exception { 51 | saveWarps(getWarps()); 52 | } 53 | 54 | void saveWarps(@NotNull Map warps) throws Exception; 55 | 56 | void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) throws Exception; 57 | 58 | boolean delWarp(@NotNull String name) throws Exception; 59 | 60 | default boolean hasWarp(@NotNull String name) { 61 | return getWarps().containsKey(name); 62 | } 63 | 64 | /** 65 | * 为某用户设定一个家的位置。 66 | * 67 | * @param uuid 用户UUID 68 | * @param homeName 家的名称 69 | * @param homeLocation 家的位置 70 | * @throws Exception 当出现任何错误时抛出 71 | */ 72 | void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) throws Exception; 73 | 74 | 75 | /** 76 | * 为某用户移除一个家的位置。 77 | * 78 | * @param uuid 用户UUID 79 | * @param homeName 家的名称 80 | * @return 是否有一个家被移除 81 | * @throws Exception 当出现任何错误时抛出 82 | */ 83 | boolean delHome(@NotNull UUID uuid, @NotNull String homeName) throws Exception; 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/warp/WarpRenameCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.warp; 2 | 3 | import cc.carm.plugin.moeteleport.Main; 4 | import cc.carm.plugin.moeteleport.command.sub.WarpCommands; 5 | import cc.carm.plugin.moeteleport.command.base.WarpSubCommand; 6 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 7 | import cc.carm.plugin.moeteleport.model.WarpInfo; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | public class WarpRenameCommand extends WarpSubCommand { 17 | 18 | public WarpRenameCommand(@NotNull WarpCommands parent, String name, String... aliases) { 19 | super(parent, name, aliases); 20 | } 21 | 22 | @Override 23 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 24 | if (!(sender instanceof Player)) { 25 | PluginMessages.NOT_PLAYER.send(sender); 26 | return null; 27 | } 28 | 29 | if (args.length < 2) return getParent().noArgs(sender); 30 | 31 | String oldName = args[0]; 32 | String newName = args[1]; 33 | 34 | if (oldName.equals(newName)) return getParent().noArgs(sender); 35 | if (newName.length() > 16) { // 超过地标的名字长度限定 36 | PluginMessages.WARP.NAME_TOO_LONG.send(sender); 37 | return null; 38 | } 39 | 40 | Player player = (Player) sender; 41 | 42 | 43 | WarpInfo info = getWarp(oldName); 44 | if (info == null) { 45 | PluginMessages.WARP.NOT_FOUND.send(player); 46 | return null; 47 | } 48 | 49 | WarpInfo newInfo = getWarp(oldName); 50 | if (newInfo != null) { 51 | PluginMessages.WARP.ALREADY_EXITS.send(player); 52 | return null; 53 | } 54 | 55 | PluginMessages.WARP.RENAMED.send(player, newName, info.getLocation()); 56 | Main.getInstance().getScheduler().runAsync(() -> { 57 | getManager().setWarp(newName, player.getUniqueId(), info.getLocation()); 58 | getManager().delWarp(oldName); 59 | }); 60 | 61 | return null; 62 | } 63 | 64 | @Override 65 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 66 | if (args.length == 1) { 67 | return listWarpNames(sender, args[args.length - 1], true); 68 | } else return Collections.emptyList(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/home/HomeCreateCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.home; 2 | 3 | import cc.carm.lib.easyplugin.command.SimpleCompleter; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.command.sub.HomeCommands; 6 | import cc.carm.plugin.moeteleport.command.base.HomeSubCommand; 7 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 8 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 9 | import cc.carm.plugin.moeteleport.storage.UserData; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.plugin.java.JavaPlugin; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.Collections; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | public class HomeCreateCommand extends HomeSubCommand { 20 | public HomeCreateCommand(@NotNull HomeCommands parent, String name, String... aliases) { 21 | super(parent, name, aliases); 22 | } 23 | 24 | @Override 25 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 26 | if (!(sender instanceof Player)) { 27 | PluginMessages.NOT_PLAYER.send(sender); 28 | return null; 29 | } 30 | 31 | Player player = (Player) sender; 32 | UserData data = getData(player); 33 | String homeName = args.length >= 1 ? args[0] : "home"; 34 | 35 | if (homeName.length() > 32) { // 超过家的名字长度限定 36 | PluginMessages.HOME.NAME_TOO_LONG.send(sender); 37 | return null; 38 | } 39 | 40 | Map.Entry lastHomeLocation = data.getHomeLocation(homeName); 41 | 42 | int maxHome = MoeTeleport.getUserManager().getMaxHome(player); 43 | if (data.getHomeLocations().size() >= maxHome && lastHomeLocation == null) { 44 | PluginMessages.HOME.OVER_LIMIT.send(sender, maxHome); 45 | return null; 46 | } 47 | 48 | data.setHomeLocation(homeName, player.getLocation()); 49 | if (lastHomeLocation != null) { 50 | PluginMessages.HOME.OVERRIDE.send(sender, homeName, lastHomeLocation.getValue().toFlatString()); 51 | } else { 52 | PluginMessages.HOME.SET.send(player, homeName); 53 | } 54 | 55 | return null; 56 | } 57 | 58 | @Override 59 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 60 | if (args.length == 1) { 61 | return SimpleCompleter.text(args[args.length - 1], "home", sender.getName()); 62 | } else return Collections.emptyList(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/home/HomeRenameCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.home; 2 | 3 | import cc.carm.plugin.moeteleport.command.sub.HomeCommands; 4 | import cc.carm.plugin.moeteleport.command.base.HomeSubCommand; 5 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 6 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 7 | import cc.carm.plugin.moeteleport.storage.UserData; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | public class HomeRenameCommand extends HomeSubCommand { 18 | 19 | public HomeRenameCommand(@NotNull HomeCommands parent, String name, String... aliases) { 20 | super(parent, name, aliases); 21 | } 22 | 23 | @Override 24 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 25 | if (!(sender instanceof Player)) { 26 | PluginMessages.NOT_PLAYER.send(sender); 27 | return null; 28 | } 29 | 30 | if (args.length < 2) return getParent().noArgs(sender); 31 | 32 | String homeName = args[0]; 33 | String newName = args[1]; 34 | 35 | if (homeName.equals(newName)) return getParent().noArgs(sender); 36 | if (newName.length() > 32) { // 超过家的名字长度限定 37 | PluginMessages.HOME.NAME_TOO_LONG.send(sender); 38 | return null; 39 | } 40 | 41 | Player player = (Player) sender; 42 | UserData data = getData(player); 43 | 44 | Map.Entry locationInfo = data.getHomeLocation(homeName); 45 | if (locationInfo == null) { 46 | PluginMessages.HOME.NOT_FOUND.send(player); 47 | return null; 48 | } 49 | 50 | Map.Entry newInfo = data.getHomeLocation(newName); 51 | if (newInfo != null) { 52 | PluginMessages.HOME.ALREADY_EXITS.send(player); 53 | return null; 54 | } 55 | 56 | PluginMessages.HOME.RENAMED.send(player, newName, locationInfo.getKey()); 57 | 58 | data.setHomeLocation(newName, locationInfo.getValue().getBukkitLocation()); 59 | data.delHomeLocation(homeName); 60 | 61 | return null; 62 | } 63 | 64 | @Override 65 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 66 | if (args.length == 1) { 67 | return listHomes(sender, args[args.length - 1]); 68 | } else return Collections.emptyList(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/impl/FileBasedStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.impl; 2 | 3 | import cc.carm.lib.configuration.core.value.ConfigValue; 4 | import cc.carm.lib.configuration.core.value.type.ConfiguredValue; 5 | import cc.carm.plugin.moeteleport.Main; 6 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 7 | import cc.carm.plugin.moeteleport.model.WarpInfo; 8 | import cc.carm.plugin.moeteleport.storage.DataStorage; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.io.File; 13 | import java.util.UUID; 14 | 15 | public abstract class FileBasedStorage implements DataStorage { 16 | 17 | protected static final ConfigValue FILE_PATH = ConfiguredValue.builder(String.class) 18 | .fromString().defaults("data") 19 | .headerComments( 20 | "选择 yaml/json 存储方式时的存储路径", 21 | "默认为相对路径,相对于插件生成的配置文件夹下的路径", 22 | "支持绝对路径,如 “/var/data/moe-teleport/\"(linux) 或 \"D:\\data\\moe-teleport\\\"(windows)", 23 | "使用绝对路径时请注意权限问题" 24 | ).build(); 25 | 26 | protected @Nullable File dataFolder; 27 | 28 | @Override 29 | public void initialize() throws Exception { 30 | FILE_PATH.initialize( 31 | Main.getInstance().getConfigProvider(), true, 32 | "storage.file", null, null 33 | ); 34 | 35 | this.dataFolder = new File(Main.getInstance().getDataFolder(), FILE_PATH.getNotNull()); 36 | if (!dataFolder.exists()) { 37 | if (!dataFolder.mkdir()) { 38 | throw new Exception("无法创建数据文件夹!"); 39 | } 40 | } else if (!dataFolder.isDirectory()) { 41 | throw new Exception("数据文件夹路径对应的不是一个文件夹!"); 42 | } 43 | } 44 | 45 | @Override 46 | public void shutdown() { 47 | // 似乎没什么需要做的? 48 | dataFolder = null; 49 | } 50 | 51 | @Override 52 | public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation homeLocation) throws Exception { 53 | // saveData 方法即保存所有数据,不需要针对单个数据进行变更。 54 | } 55 | 56 | @Override 57 | public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) { 58 | // saveData 方法即保存所有数据,不需要针对单个数据进行变更。 59 | return true; 60 | } 61 | 62 | @Override 63 | public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) { 64 | // saveWarp 方法即保存所有数据,不需要针对单个数据进行变更。 65 | } 66 | 67 | @Override 68 | public boolean delWarp(@NotNull String name) { 69 | // saveWarp 方法即保存所有数据,不需要针对单个数据进行变更。 70 | return true; 71 | } 72 | 73 | public @Nullable File getDataFolder() { 74 | return dataFolder; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/warp/WarpListCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.warp; 2 | 3 | import cc.carm.lib.easyplugin.command.SimpleCompleter; 4 | import cc.carm.plugin.moeteleport.command.sub.WarpCommands; 5 | import cc.carm.plugin.moeteleport.command.base.WarpSubCommand; 6 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 7 | import cc.carm.plugin.moeteleport.model.WarpInfo; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.plugin.java.JavaPlugin; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Collections; 14 | import java.util.List; 15 | import java.util.stream.IntStream; 16 | 17 | public class WarpListCommand extends WarpSubCommand { 18 | 19 | public WarpListCommand(@NotNull WarpCommands parent, String name, String... aliases) { 20 | super(parent, name, aliases); 21 | } 22 | 23 | @Override 24 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) { 25 | ArrayList warps = new ArrayList<>(listWarps().values()); 26 | if (warps.isEmpty()) { 27 | PluginMessages.WARP.EMPTY.send(sender); 28 | return null; 29 | } 30 | 31 | String pageString = args.length > 0 ? args[0] : null; 32 | int page = 1; 33 | if (pageString != null) { 34 | try { 35 | page = Integer.parseInt(pageString); 36 | } catch (Exception ignored) { 37 | } 38 | } 39 | 40 | int maxPage = (int) Math.ceil(warps.size() / 10.0); 41 | int currentPage = Math.min(page, maxPage); 42 | 43 | int startIndex = Math.max(0, (currentPage - 1) * 10); 44 | int endIndex = Math.min(warps.size(), startIndex + 9); 45 | 46 | PluginMessages.WARP.LIST.HEADER.send(sender, currentPage, maxPage); 47 | for (int i = startIndex; i < endIndex; i++) { 48 | WarpInfo info = warps.get(i); 49 | String ownerName = info.getOwnerName(); 50 | if (ownerName == null) { 51 | PluginMessages.WARP.LIST.OBJECT_NO_OWNER.send(sender, info.getName(), info.getLocation().toFlatString()); 52 | } else { 53 | PluginMessages.WARP.LIST.OBJECT.send(sender, info.getName(), ownerName, info.getLocation().toFlatString()); 54 | } 55 | } 56 | 57 | return null; 58 | } 59 | 60 | @Override 61 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 62 | if (args.length == 1) { 63 | int maxPage = (int) Math.ceil(listWarps().size() / 10.0); 64 | return SimpleCompleter.objects(args[args.length - 1], IntStream.rangeClosed(1, maxPage).boxed()); 65 | } else return Collections.emptyList(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/teleport/TeleportRequest.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.teleport; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 5 | import cc.carm.plugin.moeteleport.storage.UserData; 6 | import cc.carm.plugin.moeteleport.teleport.target.TeleportPlayerTarget; 7 | import org.bukkit.entity.Player; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.time.Duration; 12 | 13 | public class TeleportRequest { 14 | 15 | public enum Type {TPA_TO, TPA_HERE} 16 | 17 | private final @NotNull Type type; 18 | 19 | private final @NotNull Player sender; 20 | private final @NotNull Player receiver; 21 | 22 | private final long createMillis; 23 | 24 | public TeleportRequest(@NotNull Type type, @NotNull Player sender, @NotNull Player receiver) { 25 | this.type = type; 26 | this.sender = sender; 27 | this.receiver = receiver; 28 | this.createMillis = System.currentTimeMillis(); 29 | } 30 | 31 | public @NotNull Type getRequestType() { 32 | return type; 33 | } 34 | 35 | public @NotNull Player getReceiver() { 36 | return receiver; 37 | } 38 | 39 | public @NotNull UserData getReceiverUser() { 40 | return MoeTeleport.getUserManager().getData(getReceiver()); 41 | } 42 | 43 | public @NotNull Player getSender() { 44 | return sender; 45 | } 46 | 47 | public @NotNull UserData getSenderUser() { 48 | return MoeTeleport.getUserManager().getData(getSender()); 49 | } 50 | 51 | public long getCreateMillis() { 52 | return createMillis; 53 | } 54 | 55 | public long getActiveMillis() { 56 | return System.currentTimeMillis() - getCreateMillis(); 57 | } 58 | 59 | public long getRemainMillis() { 60 | return PluginConfig.REQUEST.EXPIRE_TIME.getNotNull() * 1000 - getActiveMillis(); 61 | } 62 | 63 | public long getRemainSeconds() { 64 | return getRemainMillis() / 1000; 65 | } 66 | 67 | public boolean isExpired() { 68 | return getActiveMillis() > PluginConfig.REQUEST.EXPIRE_TIME.getNotNull() * 1000; 69 | } 70 | 71 | public @Nullable TeleportQueue createQueue(@Nullable Duration delay) { 72 | Player player; 73 | TeleportPlayerTarget destination; 74 | 75 | if (type == Type.TPA_TO) { 76 | destination = new TeleportPlayerTarget(receiver); 77 | player = sender; 78 | } else if (type == Type.TPA_HERE) { 79 | destination = new TeleportPlayerTarget(sender); 80 | player = receiver; 81 | } else { 82 | return null; 83 | } 84 | 85 | return new TeleportQueue(player, destination, delay); 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/teleport/TeleportRequestCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.teleport; 2 | 3 | import cc.carm.lib.easyplugin.command.SimpleCompleter; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.command.sub.TeleportCommands; 6 | import cc.carm.plugin.moeteleport.command.base.TeleportSubCommand; 7 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 8 | import cc.carm.plugin.moeteleport.teleport.TeleportRequest; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.plugin.java.JavaPlugin; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.Collections; 16 | import java.util.List; 17 | 18 | public class TeleportRequestCommand extends TeleportSubCommand { 19 | 20 | private final @NotNull TeleportRequest.Type type; 21 | 22 | public TeleportRequestCommand(@NotNull TeleportCommands parent, 23 | @NotNull TeleportRequest.Type type, 24 | String name, String... aliases) { 25 | super(parent, name, aliases); 26 | this.type = type; 27 | } 28 | 29 | @Override 30 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 31 | if (!(sender instanceof Player)) { 32 | PluginMessages.NOT_PLAYER.send(sender); 33 | return null; 34 | } 35 | 36 | if (args.length < 1) return getParent().noArgs(sender); 37 | 38 | Player player = (Player) sender; 39 | Player target = Bukkit.getPlayer(args[0]); 40 | if (target == null) { 41 | PluginMessages.NOT_ONLINE.send(player); 42 | return null; 43 | } 44 | 45 | if (player == target) { 46 | // fix #5 - 玩家给自己发送传送请求 47 | PluginMessages.REQUESTS.SELF.send(player); 48 | return null; 49 | } 50 | 51 | TeleportRequest sent = MoeTeleport.getRequestManager().getRequest(player.getUniqueId()); 52 | if (sent != null) { 53 | PluginMessages.REQUESTS.DUPLICATE.send(sender, target.getName(), sent.getRemainSeconds()); 54 | return null; 55 | } 56 | 57 | MoeTeleport.getRequestManager().sendRequest(player, target, type); 58 | return null; 59 | } 60 | 61 | @Override 62 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 63 | if (args.length == 1) { 64 | return SimpleCompleter.objects( 65 | args[args.length - 1], 15, 66 | Bukkit.getOnlinePlayers().stream() 67 | .map(Player::getName) 68 | .filter(s -> !s.equalsIgnoreCase(sender.getName())) 69 | ); 70 | } else return Collections.emptyList(); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/warp/WarpCreateCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.warp; 2 | 3 | import cc.carm.lib.easyplugin.command.SimpleCompleter; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.command.sub.WarpCommands; 6 | import cc.carm.plugin.moeteleport.command.base.WarpSubCommand; 7 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 8 | import cc.carm.plugin.moeteleport.model.WarpInfo; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.plugin.java.JavaPlugin; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.Collections; 15 | import java.util.List; 16 | 17 | public class WarpCreateCommand extends WarpSubCommand { 18 | 19 | public WarpCreateCommand(@NotNull WarpCommands parent, String name, String... aliases) { 20 | super(parent, name, aliases); 21 | } 22 | 23 | @Override 24 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) { 25 | if (!(sender instanceof Player)) { 26 | PluginMessages.NOT_PLAYER.send(sender); 27 | return null; 28 | } 29 | 30 | Player player = (Player) sender; 31 | String warpName = args.length >= 1 ? args[0] : player.getName(); 32 | 33 | if (warpName.length() > 16) { // 超过地标的名字长度限定 34 | PluginMessages.WARP.NAME_TOO_LONG.send(sender); 35 | return null; 36 | } 37 | 38 | WarpInfo info = getWarp(warpName); 39 | 40 | if (!player.isOp() && !player.hasPermission("MoeTeleport.admin")) { 41 | if (info != null && (info.getOwner() == null || !info.getOwner().equals(player.getUniqueId()))) { 42 | PluginMessages.WARP.NOT_OWNER.send(sender, warpName); 43 | return null; 44 | } 45 | 46 | int maxWarp = MoeTeleport.getUserManager().getMaxWarps(player); 47 | long currentUsed = MoeTeleport.getUserManager().countUserWarps(player.getUniqueId()); 48 | if (currentUsed >= maxWarp && info == null) { 49 | PluginMessages.WARP.OVER_LIMIT.send(sender, maxWarp); 50 | return null; 51 | } 52 | } 53 | 54 | getManager().setWarpAsync(warpName, player.getUniqueId(), player.getLocation()); 55 | if (info != null) { 56 | PluginMessages.WARP.OVERRIDE.send(sender, warpName, info.getLocation().toFlatString()); 57 | } else { 58 | PluginMessages.WARP.SET.send(sender, warpName); 59 | } 60 | 61 | return null; 62 | } 63 | 64 | @Override 65 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 66 | if (args.length == 1) { 67 | return SimpleCompleter.text(args[args.length - 1], sender.getName()); 68 | } else return Collections.emptyList(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/manager/WarpManager.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.manager; 2 | 3 | import cc.carm.plugin.moeteleport.Main; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 6 | import cc.carm.plugin.moeteleport.model.WarpInfo; 7 | import com.google.common.collect.ImmutableMap; 8 | import org.bukkit.Location; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | import org.jetbrains.annotations.Unmodifiable; 12 | 13 | import java.util.Map; 14 | import java.util.UUID; 15 | 16 | public class WarpManager { 17 | 18 | public void saveWarps() { 19 | try { 20 | MoeTeleport.getStorage().saveWarps(); 21 | } catch (Exception exception) { 22 | Main.severe("保存地标数据失败,请检查配置文件。"); 23 | exception.printStackTrace(); 24 | } 25 | } 26 | 27 | public void setWarp(@NotNull String name, @Nullable UUID owner, @NotNull Location location) { 28 | setWarp(name, owner, new DataLocation(location)); 29 | } 30 | 31 | public void setWarp(@NotNull String name, @Nullable UUID owner, @NotNull DataLocation location) { 32 | 33 | try { 34 | MoeTeleport.getStorage().setWarp(name, new WarpInfo(name,owner, location)); 35 | } catch (Exception exception) { 36 | Main.severe("保存地标数据 " + name + " 失败,请检查配置文件。"); 37 | exception.printStackTrace(); 38 | } 39 | 40 | } 41 | 42 | public void setWarpAsync(@NotNull String name, @Nullable UUID owner, @NotNull Location location) { 43 | Main.getInstance().getScheduler().runAsync(() -> setWarp(name, owner, location)); 44 | } 45 | 46 | public void setWarpAsync(@NotNull String name, @Nullable UUID owner, @NotNull DataLocation location) { 47 | Main.getInstance().getScheduler().runAsync(() -> setWarp(name, owner, location)); 48 | } 49 | 50 | public void delWarp(@NotNull String name) { 51 | try { 52 | MoeTeleport.getStorage().delWarp(name); 53 | } catch (Exception exception) { 54 | Main.severe("删除地标数据 " + name + " 失败,请检查配置文件。"); 55 | exception.printStackTrace(); 56 | } 57 | } 58 | 59 | public void delWarpAsync(@NotNull String name) { 60 | Main.getInstance().getScheduler().runAsync(() -> delWarp(name)); 61 | } 62 | 63 | public WarpInfo getWarp(@NotNull String name) { 64 | return listWarps().entrySet().stream() 65 | .filter(entry -> entry.getKey().equalsIgnoreCase(name)) 66 | .map(Map.Entry::getValue) 67 | .findFirst().orElse(null); 68 | } 69 | 70 | public boolean hasWarp(@NotNull String name) { 71 | return MoeTeleport.getStorage().hasWarp(name); 72 | } 73 | 74 | @NotNull 75 | @Unmodifiable 76 | public Map listWarps() { 77 | return ImmutableMap.copyOf(getWarpsMap()); 78 | } 79 | 80 | @NotNull 81 | protected Map getWarpsMap() { 82 | return MoeTeleport.getStorage().getWarps(); 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/StorageMethod.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage; 2 | 3 | import cc.carm.plugin.moeteleport.storage.custom.CustomStorage; 4 | import cc.carm.plugin.moeteleport.storage.database.MySQLStorage; 5 | import cc.carm.plugin.moeteleport.storage.extension.CMIStorage; 6 | import cc.carm.plugin.moeteleport.storage.extension.EssentialStorage; 7 | import cc.carm.plugin.moeteleport.storage.file.JSONStorage; 8 | import cc.carm.plugin.moeteleport.storage.file.YAMLStorage; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.util.Arrays; 13 | import java.util.Optional; 14 | 15 | public enum StorageMethod { 16 | 17 | CUSTOM(0, new String[]{}, CustomStorage.class), 18 | YAML(1, new String[]{"yml"}, YAMLStorage.class), 19 | JSON(2, new String[]{}, JSONStorage.class), 20 | MYSQL(3, new String[]{"my-sql", "mariadb", "sql", "database"}, MySQLStorage.class), 21 | 22 | ESSENTIALS(11, new String[]{"essential", "ess", "EssentialsX", "essX"}, EssentialStorage.class), 23 | CMI(12, new String[]{}, CMIStorage.class); 24 | 25 | private final int id; 26 | private final String[] alias; 27 | private @NotNull Class storageClazz; 28 | 29 | StorageMethod(int id, String[] alias, @NotNull Class storageClazz) { 30 | this.id = id; 31 | this.alias = alias; 32 | this.storageClazz = storageClazz; 33 | } 34 | 35 | public static @NotNull StorageMethod read(String s) { 36 | StorageMethod byName = readByName(s); 37 | if (byName != null) return byName; 38 | StorageMethod byAlias = readByAlias(s); 39 | if (byAlias != null) return byAlias; 40 | try { 41 | return Optional.ofNullable(readByID(Integer.parseInt(s))).orElse(YAML); 42 | } catch (Exception ex) { 43 | return YAML; 44 | } 45 | } 46 | 47 | public static @Nullable StorageMethod readByName(String name) { 48 | return Arrays.stream(values()).filter(value -> value.name().equalsIgnoreCase(name)).findFirst().orElse(null); 49 | } 50 | 51 | public static @Nullable StorageMethod readByAlias(String name) { 52 | return Arrays.stream(values()) 53 | .filter(value -> Arrays.stream(value.getAlias()).anyMatch(alias -> alias.equalsIgnoreCase(name))) 54 | .findFirst().orElse(null); 55 | } 56 | 57 | public static @Nullable StorageMethod readByID(int id) { 58 | return Arrays.stream(values()).filter(value -> value.getID() == id).findFirst().orElse(null); 59 | } 60 | 61 | public int getID() { 62 | return id; 63 | } 64 | 65 | public String[] getAlias() { 66 | return alias; 67 | } 68 | 69 | public @NotNull Class getStorageClazz() { 70 | return storageClazz; 71 | } 72 | 73 | public void setStorageClazz(@NotNull Class storageClazz) { 74 | this.storageClazz = storageClazz; 75 | } 76 | 77 | public @NotNull DataStorage createStorage() throws Exception { 78 | return getStorageClazz().newInstance(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/UserData.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 5 | import org.bukkit.Location; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.*; 10 | 11 | public class UserData { 12 | 13 | protected final @NotNull UUID userUUID; 14 | private final LinkedHashMap homeLocations; 15 | 16 | public boolean enableAutoSelect = false; 17 | private @Nullable Location lastLocation; 18 | 19 | public UserData(@NotNull UUID userUUID) { 20 | this(userUUID, null, new LinkedHashMap<>()); 21 | } 22 | 23 | public UserData(@NotNull UUID userUUID, 24 | @Nullable DataLocation lastLocation, 25 | @NotNull LinkedHashMap homeLocations) { 26 | this.userUUID = userUUID; 27 | this.lastLocation = Optional.ofNullable(lastLocation).map(DataLocation::getBukkitLocation).orElse(null); 28 | this.homeLocations = homeLocations; 29 | } 30 | 31 | public @NotNull UUID getUserUUID() { 32 | return userUUID; 33 | } 34 | 35 | public LinkedHashMap getHomeLocations() { 36 | return homeLocations; 37 | } 38 | 39 | public void setHomeLocation(String homeName, Location location) { 40 | delHomeLocation(homeName); 41 | getHomeLocations().put(homeName, new DataLocation(location)); 42 | MoeTeleport.getUserManager().editData((storage) -> storage.setHome(userUUID, homeName, new DataLocation(location))); 43 | } 44 | 45 | public void delHomeLocation(String homeName) { 46 | Map.Entry lastLocation = getHomeLocation(homeName); 47 | if (lastLocation != null) getHomeLocations().remove(lastLocation.getKey()); 48 | MoeTeleport.getUserManager().editData((storage) -> storage.delHome(userUUID, homeName)); 49 | } 50 | 51 | public Map.Entry getHomeLocation(@Nullable String homeName) { 52 | LinkedHashMap homes = getHomeLocations(); 53 | if (homeName == null) { 54 | if (homes.containsKey("home")) { 55 | return new AbstractMap.SimpleEntry<>("home", homes.get("home")); 56 | } else { 57 | return homes.entrySet().stream().findFirst().orElse(null); 58 | } 59 | } else { 60 | return homes.entrySet().stream() 61 | .filter(entry -> entry.getKey().equalsIgnoreCase(homeName)) 62 | .findFirst().orElse(null); 63 | } 64 | } 65 | 66 | public @Nullable Location getLastLocation() { 67 | return lastLocation; 68 | } 69 | 70 | public void setLastLocation(@Nullable Location lastLocation) { 71 | this.lastLocation = lastLocation; 72 | } 73 | 74 | public boolean isEnableAutoSelect() { 75 | return enableAutoSelect; 76 | } 77 | 78 | public void setEnableAutoSelect(boolean enableAutoSelect) { 79 | this.enableAutoSelect = enableAutoSelect; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/command/sub/teleport/TeleportHandleCommand.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.command.sub.teleport; 2 | 3 | import cc.carm.plugin.moeteleport.MoeTeleport; 4 | import cc.carm.plugin.moeteleport.command.sub.TeleportCommands; 5 | import cc.carm.plugin.moeteleport.command.base.TeleportSubCommand; 6 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 7 | import cc.carm.plugin.moeteleport.storage.UserData; 8 | import cc.carm.plugin.moeteleport.teleport.TeleportRequest; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.plugin.java.JavaPlugin; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.*; 16 | 17 | public class TeleportHandleCommand extends TeleportSubCommand { 18 | 19 | protected final boolean accept; 20 | 21 | public TeleportHandleCommand(@NotNull TeleportCommands parent, boolean accept, String name, String... aliases) { 22 | super(parent, name, aliases); 23 | this.accept = accept; 24 | } 25 | 26 | @Override 27 | public Void execute(JavaPlugin plugin, CommandSender sender, String[] args) throws Exception { 28 | if (!(sender instanceof Player)) { 29 | PluginMessages.NOT_PLAYER.send(sender); 30 | return null; 31 | } 32 | 33 | Player player = (Player) sender; 34 | UserData data = MoeTeleport.getUserManager().getData(player); 35 | 36 | Map receivedRequests = getReceivedRequests(player); 37 | if (receivedRequests.isEmpty()) { 38 | PluginMessages.REQUESTS.EMPTY_REQUESTS.send(player); 39 | return null; 40 | } 41 | 42 | String targetName = args.length > 0 ? args[0] : null; 43 | data.setEnableAutoSelect(false); 44 | 45 | if (targetName != null) { 46 | Player target = Bukkit.getPlayer(targetName); 47 | TeleportRequest request = target == null ? null : receivedRequests.get(target.getUniqueId()); 48 | 49 | if (request == null) { 50 | PluginMessages.REQUESTS.NO_REQUEST_FROM.send(player, target == null ? targetName : target.getName()); 51 | } else { 52 | handle(request); // 交给Manager处理 53 | } 54 | } else { 55 | if (receivedRequests.size() == 1 || data.isEnableAutoSelect()) { 56 | receivedRequests.values().stream() 57 | .min(Comparator.comparingLong(TeleportRequest::getActiveMillis)) 58 | .ifPresent(this::handle); 59 | } else { 60 | PluginMessages.REQUESTS.MULTI.send(player, 61 | receivedRequests.size(), 62 | "moeteleport teleport " + (accept ? "tpAccept" : "tpDeny").toLowerCase() 63 | ); 64 | data.setEnableAutoSelect(true); 65 | } 66 | } 67 | return null; 68 | } 69 | 70 | private void handle(TeleportRequest request) { 71 | if (accept) { 72 | MoeTeleport.getRequestManager().acceptRequest(request); 73 | } else { 74 | MoeTeleport.getRequestManager().denyRequest(request); 75 | } 76 | } 77 | 78 | @Override 79 | public List tabComplete(JavaPlugin plugin, CommandSender sender, String[] args) { 80 | if (args.length == 1) { 81 | return listRequests(sender, args[args.length - 1]); 82 | } else return Collections.emptyList(); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/database/DatabaseTables.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.database; 2 | 3 | import cc.carm.lib.configuration.core.value.ConfigValue; 4 | import cc.carm.lib.easysql.api.SQLManager; 5 | import cc.carm.lib.easysql.api.SQLTable; 6 | import cc.carm.lib.easysql.api.builder.TableCreateBuilder; 7 | import cc.carm.lib.easysql.api.enums.IndexType; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.sql.SQLException; 12 | import java.util.function.Consumer; 13 | 14 | public enum DatabaseTables implements SQLTable { 15 | 16 | LAST_LOCATION(DatabaseConfig.TABLES.LAST_LOCATION, (table) -> { 17 | table.addColumn("uuid", "CHAR(36) NOT NULL PRIMARY KEY"); // 用户的UUID 18 | 19 | // 坐标世界与位置 20 | table.addColumn("world", "VARCHAR(128) NOT NULL"); 21 | table.addColumn("x", "DOUBLE NOT NULL"); 22 | table.addColumn("y", "DOUBLE NOT NULL"); 23 | table.addColumn("z", "DOUBLE NOT NULL"); 24 | table.addColumn("yaw", "DOUBLE NOT NULL"); 25 | table.addColumn("pitch", "DOUBLE NOT NULL"); 26 | 27 | table.addColumn("update", 28 | "DATETIME NOT NULL " + 29 | "DEFAULT CURRENT_TIMESTAMP " + 30 | "ON UPDATE CURRENT_TIMESTAMP" 31 | ); 32 | }), 33 | 34 | HOMES(DatabaseConfig.TABLES.HOMES, (table) -> { 35 | table.addAutoIncrementColumn("id", true, true); 36 | table.addColumn("uuid", "CHAR(36) NOT NULL"); 37 | table.addColumn("name", "VARCHAR(32) NOT NULL"); 38 | 39 | // 坐标世界与位置 40 | table.addColumn("world", "VARCHAR(128) NOT NULL"); 41 | table.addColumn("x", "DOUBLE NOT NULL"); 42 | table.addColumn("y", "DOUBLE NOT NULL"); 43 | table.addColumn("z", "DOUBLE NOT NULL"); 44 | table.addColumn("yaw", "DOUBLE NOT NULL"); 45 | table.addColumn("pitch", "DOUBLE NOT NULL"); 46 | 47 | table.setIndex(IndexType.INDEX, "idx_homes_user", "uuid"); 48 | table.setIndex(IndexType.UNIQUE_KEY, "uk_homes", "uuid", "name"); 49 | }), 50 | 51 | WRAPS(DatabaseConfig.TABLES.WARPS, (table) -> { 52 | 53 | table.addAutoIncrementColumn("id", true, true); 54 | table.addColumn("name", "VARCHAR(32) NOT NULL"); 55 | table.addColumn("owner", "CHAR(36) NOT NULL"); 56 | 57 | // 坐标世界与位置 58 | table.addColumn("world", "VARCHAR(128) NOT NULL"); 59 | table.addColumn("x", "DOUBLE NOT NULL"); 60 | table.addColumn("y", "DOUBLE NOT NULL"); 61 | table.addColumn("z", "DOUBLE NOT NULL"); 62 | table.addColumn("yaw", "DOUBLE NOT NULL"); 63 | table.addColumn("pitch", "DOUBLE NOT NULL"); 64 | 65 | table.setIndex(IndexType.UNIQUE_KEY, "uk_wraps", "name"); 66 | }); 67 | 68 | private final Consumer builder; 69 | private final ConfigValue name; 70 | private @Nullable SQLManager manager; 71 | 72 | DatabaseTables(ConfigValue name, 73 | Consumer builder) { 74 | this.name = name; 75 | this.builder = builder; 76 | } 77 | 78 | @Override 79 | public @Nullable SQLManager getSQLManager() { 80 | return this.manager; 81 | } 82 | 83 | @Override 84 | public @NotNull String getTableName() { 85 | return this.name.getNotNull(); 86 | } 87 | 88 | @Override 89 | public boolean create(SQLManager sqlManager) throws SQLException { 90 | if (this.manager == null) this.manager = sqlManager; 91 | 92 | TableCreateBuilder tableBuilder = sqlManager.createTable(getTableName()); 93 | if (builder != null) builder.accept(tableBuilder); 94 | return tableBuilder.build().executeFunction(l -> l > 0, false); 95 | } 96 | } -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/extension/CMIStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.extension; 2 | 3 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 4 | import cc.carm.plugin.moeteleport.model.WarpInfo; 5 | import cc.carm.plugin.moeteleport.storage.UserData; 6 | import cc.carm.plugin.moeteleport.storage.impl.PluginBasedStorage; 7 | import com.Zrips.CMI.CMI; 8 | import com.Zrips.CMI.Containers.CMIUser; 9 | import com.Zrips.CMI.Modules.Homes.CmiHome; 10 | import com.Zrips.CMI.Modules.Warps.CmiWarp; 11 | import com.Zrips.CMI.Modules.Warps.WarpManager; 12 | import net.Zrips.CMILib.Container.CMILocation; 13 | import org.bukkit.Location; 14 | import org.jetbrains.annotations.NotNull; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.util.LinkedHashMap; 18 | import java.util.Map; 19 | import java.util.UUID; 20 | 21 | public class CMIStorage extends PluginBasedStorage { 22 | 23 | public CMIStorage() { 24 | super("CMI"); 25 | } 26 | 27 | @Override 28 | public @Nullable UserData loadData(@NotNull UUID uuid) { 29 | return new CMIUserData(uuid); 30 | } 31 | 32 | @Override 33 | public Map getWarps() { 34 | Map warps = new LinkedHashMap<>(); 35 | 36 | cmi().getWarps().forEach((name, warp) -> warps.put(name, new WarpInfo(name, warp.getCreator(), convert(warp.getLoc())))); 37 | 38 | return warps; 39 | } 40 | 41 | @Override 42 | public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) throws Exception { 43 | CmiWarp warp = new CmiWarp(name); 44 | 45 | warp.setLoc(convert(warpInfo.getLocation())); 46 | warp.setCreator(warpInfo.getOwner()); 47 | 48 | cmi().addWarp(warp); 49 | } 50 | 51 | @Override 52 | public boolean delWarp(@NotNull String name) throws Exception { 53 | CmiWarp warp = cmi().getWarp(name); 54 | if (warp == null) return false; 55 | cmi().remove(warp); 56 | return true; 57 | } 58 | 59 | @Override 60 | public boolean hasWarp(@NotNull String name) { 61 | return cmi().getWarp(name) != null; 62 | } 63 | 64 | protected WarpManager cmi() { 65 | return CMI.getInstance().getWarpManager(); 66 | } 67 | 68 | public static DataLocation convert(CMILocation loc) { 69 | return new DataLocation(loc.getWorldName(), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); 70 | } 71 | 72 | public static CMILocation convert(DataLocation loc) { 73 | return new CMILocation(loc.getWorldName(), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); 74 | } 75 | 76 | public static class CMIUserData extends UserData { 77 | 78 | CMIUser cmiUser; 79 | 80 | public CMIUserData(@NotNull UUID userUUID) { 81 | super(userUUID); 82 | this.cmiUser = CMI.getInstance().getPlayerManager().getUser(userUUID); 83 | } 84 | 85 | public CMIUser getCMIUser() { 86 | return cmiUser; 87 | } 88 | 89 | @Override 90 | public LinkedHashMap getHomeLocations() { 91 | LinkedHashMap homes = new LinkedHashMap<>(); 92 | getCMIUser().getHomes().forEach((name, home) -> { 93 | homes.put(name, convert(home.getLoc())); 94 | }); 95 | return homes; 96 | } 97 | 98 | @Override 99 | public void setHomeLocation(String homeName, Location location) { 100 | getCMIUser().addHome(new CmiHome(homeName, new CMILocation(location)), true); 101 | } 102 | 103 | @Override 104 | public void delHomeLocation(String homeName) { 105 | try { 106 | getCMIUser().removeHome(homeName); 107 | } catch (Exception ignored) { 108 | } 109 | } 110 | 111 | @Override 112 | public @Nullable Location getLastLocation() { 113 | return getCMIUser().getLastTeleportLocation(); 114 | } 115 | 116 | @Override 117 | public void setLastLocation(@Nullable Location lastLocation) { 118 | getCMIUser().setLastTeleportLocation(lastLocation); 119 | } 120 | 121 | } 122 | 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/extension/EssentialStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.extension; 2 | 3 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 4 | import cc.carm.plugin.moeteleport.storage.UserData; 5 | import cc.carm.plugin.moeteleport.model.WarpInfo; 6 | import cc.carm.plugin.moeteleport.storage.impl.PluginBasedStorage; 7 | import com.earth2me.essentials.Essentials; 8 | import com.earth2me.essentials.User; 9 | import org.bukkit.Location; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.LinkedHashMap; 14 | import java.util.Map; 15 | import java.util.UUID; 16 | 17 | public class EssentialStorage extends PluginBasedStorage { 18 | 19 | public EssentialStorage() { 20 | super("Essentials"); 21 | } 22 | 23 | @Override 24 | public @Nullable UserData loadData(@NotNull UUID uuid) { 25 | return new EssentialUserData(uuid, getEssentials()); 26 | } 27 | 28 | @Override 29 | public Map getWarps() { 30 | Map warps = new LinkedHashMap<>(); 31 | 32 | for (String warpName : getEssentials().getWarps().getList()) { 33 | try { 34 | Location warpLocation = getEssentials().getWarps().getWarp(warpName); 35 | UUID owner = getEssentials().getWarps().getLastOwner(warpName); 36 | warps.put(warpName, new WarpInfo(warpName, owner, new DataLocation(warpLocation))); 37 | } catch (Exception ignore) { 38 | } 39 | } 40 | 41 | return warps; 42 | } 43 | 44 | @Override 45 | public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) throws Exception { 46 | User user = getEssentials().getUser(warpInfo.getOwner()); 47 | Location location = warpInfo.getLocation().getBukkitLocation(); 48 | if (location == null) return; 49 | 50 | if (user == null) { 51 | getEssentials().getWarps().setWarp(name, location); 52 | } else { 53 | getEssentials().getWarps().setWarp(user, name, warpInfo.getLocation().getBukkitLocation()); 54 | } 55 | } 56 | 57 | @Override 58 | public boolean delWarp(@NotNull String name) throws Exception { 59 | boolean has = hasWarp(name); 60 | getEssentials().getWarps().removeWarp(name); 61 | return has; 62 | } 63 | 64 | @Override 65 | public boolean hasWarp(@NotNull String name) { 66 | return getEssentials().getWarps().isWarp(name); 67 | } 68 | 69 | public Essentials getEssentials() { 70 | return (Essentials) getDependPlugin(); 71 | } 72 | 73 | public static class EssentialUserData extends UserData { 74 | 75 | User essentialsUser; 76 | 77 | public EssentialUserData(@NotNull UUID userUUID, Essentials essentials) { 78 | super(userUUID); 79 | this.essentialsUser = essentials.getUser(userUUID); 80 | } 81 | 82 | public User getEssUser() { 83 | return essentialsUser; 84 | } 85 | 86 | @Override 87 | public LinkedHashMap getHomeLocations() { 88 | LinkedHashMap homes = new LinkedHashMap<>(); 89 | getEssUser().getHomes().forEach(homeName -> { 90 | Location homeLocation = getEssUser().getHome(homeName); 91 | if (homeLocation != null) homes.put(homeName, new DataLocation(homeLocation)); 92 | }); 93 | return homes; 94 | } 95 | 96 | @Override 97 | public void setHomeLocation(String homeName, Location location) { 98 | getEssUser().setHome(homeName, location); 99 | } 100 | 101 | @Override 102 | public void delHomeLocation(String homeName) { 103 | try { 104 | getEssUser().delHome(homeName); 105 | } catch (Exception ignored) { 106 | } 107 | } 108 | 109 | @Override 110 | public @Nullable Location getLastLocation() { 111 | return getEssUser().getLastLocation(); 112 | } 113 | 114 | @Override 115 | public void setLastLocation(@Nullable Location lastLocation) { 116 | getEssUser().setLastLocation(lastLocation); 117 | } 118 | 119 | 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/conf/location/DataLocation.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.conf.location; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.Location; 6 | import org.bukkit.World; 7 | import org.bukkit.util.NumberConversions; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.text.DecimalFormat; 12 | import java.util.Objects; 13 | 14 | public class DataLocation implements Cloneable { 15 | 16 | public static final DecimalFormat format = new DecimalFormat("0.00"); 17 | private final String worldName; 18 | private double x; 19 | private double y; 20 | private double z; 21 | private float yaw; 22 | private float pitch; 23 | 24 | public DataLocation(Location location) { 25 | this(location.getWorld() != null ? location.getWorld().getName() : "", location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); 26 | } 27 | 28 | public DataLocation(final String worldName, final double x, final double y, final double z) { 29 | this(worldName, x, y, z, 0, 0); 30 | } 31 | 32 | public DataLocation(final String worldName, final double x, final double y, final double z, final float yaw, final float pitch) { 33 | this.worldName = worldName; 34 | this.x = x; 35 | this.y = y; 36 | this.z = z; 37 | this.pitch = pitch; 38 | this.yaw = yaw; 39 | } 40 | 41 | public static DataLocation deserializeText(String s) { 42 | if (s == null || !s.contains(";")) return null; 43 | String[] args = StringUtils.split(s, ";"); 44 | if (args.length < 4) return null; 45 | try { 46 | String worldName = args[0]; 47 | double x = NumberConversions.toDouble(args[1]); 48 | double y = NumberConversions.toDouble(args[2]); 49 | double z = NumberConversions.toDouble(args[3]); 50 | float yaw = 0; 51 | float pitch = 0; 52 | if (args.length == 6) { 53 | yaw = NumberConversions.toFloat(args[4]); 54 | pitch = NumberConversions.toFloat(args[5]); 55 | } 56 | return new DataLocation(worldName, x, y, z, yaw, pitch); 57 | } catch (Exception ex) { 58 | return null; 59 | } 60 | } 61 | 62 | @Deprecated 63 | public static DataLocation parseString(String s) { 64 | return deserializeText(s); 65 | } 66 | 67 | public String getWorldName() { 68 | return worldName; 69 | } 70 | 71 | public double getX() { 72 | return x; 73 | } 74 | 75 | public void setX(double x) { 76 | this.x = x; 77 | } 78 | 79 | public double getY() { 80 | return y; 81 | } 82 | 83 | public void setY(double y) { 84 | this.y = y; 85 | } 86 | 87 | public double getZ() { 88 | return z; 89 | } 90 | 91 | public void setZ(double z) { 92 | this.z = z; 93 | } 94 | 95 | public float getYaw() { 96 | return yaw; 97 | } 98 | 99 | public void setYaw(float yaw) { 100 | this.yaw = yaw; 101 | } 102 | 103 | public float getPitch() { 104 | return pitch; 105 | } 106 | 107 | public void setPitch(float pitch) { 108 | this.pitch = pitch; 109 | } 110 | 111 | public @NotNull Location getBukkitLocation(World world) { 112 | return new Location(world, getX(), getY(), getZ(), getYaw(), getPitch()); 113 | } 114 | 115 | public @Nullable Location getBukkitLocation() { 116 | World world = Bukkit.getWorld(getWorldName()); 117 | if (world == null) return null; 118 | else return new Location(world, getX(), getY(), getZ(), getYaw(), getPitch()); 119 | } 120 | 121 | @Override 122 | public Object clone() { 123 | try { 124 | return super.clone(); 125 | } catch (Exception ex) { 126 | return null; 127 | } 128 | } 129 | 130 | @Override 131 | public boolean equals(Object o) { 132 | if (this == o) return true; 133 | if (!(o instanceof DataLocation)) return false; 134 | DataLocation that = (DataLocation) o; 135 | return that.worldName.equals(worldName) 136 | && Double.compare(that.x, x) == 0 137 | && Double.compare(that.y, y) == 0 138 | && Double.compare(that.z, z) == 0 139 | && Float.compare(that.pitch, pitch) == 0 140 | && Float.compare(that.yaw, yaw) == 0; 141 | } 142 | 143 | @Override 144 | public int hashCode() { 145 | return Objects.hash(x, y, z, yaw, pitch); 146 | } 147 | 148 | @Override 149 | public String toString() { 150 | return worldName + " " + x + " " + y + " " + z + " " + yaw + " " + pitch; 151 | } 152 | 153 | public String toFlatString() { 154 | return worldName + "@" + format.format(x) + ", " + format.format(y) + ", " + format.format(z); 155 | } 156 | 157 | @Deprecated 158 | public String toSerializedString() { 159 | return serializeToText(); 160 | } 161 | 162 | public String serializeToText() { 163 | if (getYaw() != 0 || getPitch() != 0) { 164 | return worldName + ";" + x + ";" + y + ";" + z + ";" + yaw + ";" + pitch; 165 | } else { 166 | return worldName + ";" + x + ";" + y + ";" + z; 167 | } 168 | } 169 | 170 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ```text 2 | __ ___ ______ __ __ 3 | / |/ /__ __/_ __/__ / /__ ___ ___ ____/ /_ 4 | / /|_/ / _ \/ -_) / / -_) / -_) _ \/ _ \/ __/ __/ 5 | /_/ /_/\___/\__/_/ \__/_/\__/ .__/\___/_/ \__/ 6 | /_/ 7 | ``` 8 | README LANGUAGES [ [**中文**](README.md) | [English](README-EN.md) ] 9 | 10 | # MoeTeleport 喵喵传送 11 | 12 | [![CodeFactor](https://www.codefactor.io/repository/github/CarmJos/MoeTeleport/badge?s=b76fec1f64726b5f19989aace6adb5f85fdab840)](https://www.codefactor.io/repository/github/CarmJos/MoeTeleport) 13 | ![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/MoeTeleport) 14 | [![Download](https://img.shields.io/github/downloads/CarmJos/MoeTeleport/total)](https://github.com/CarmJos/MoeTeleport/releases) 15 | [![Java CI with Maven](https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml) 16 | ![Support](https://img.shields.io/badge/Minecraft-Java%201.13--Latest-blue) 17 | ![](https://visitor-badge.glitch.me/badge?page_id=moeteleport.readme) 18 | 19 | 开源的传送插件,包含数个功能,并根据用户需求持续更新添加新功能。 20 | 21 | 项目代码符合开发规范,适合新手开发者学习Bukkit,制作属于自己的插件。 22 | 23 | ## 功能与优势 24 | 25 | ### 当前功能 26 | 27 | - 多种存储格式,按需选择。 28 | - 支持 YAML、JSON 与 MySQL/MariaDB 存储方式 29 | - 支持直接调用 [EssentialsX](https://github.com/EssentialsX/Essentials) / CMI 数据,无缝切换 30 | - 可点击的消息(如“点击同意”) 31 | - 基于MineDown语法,可自定义配置 32 | - 玩家间的传送请求 33 | - 支持指定处理某位玩家的请求 34 | - 设置地标点 35 | - 支持依照权限设定不同数量的地标点作为VIP附加内容 36 | - 设置家位置 (可以理解为私人地标) 37 | - 支持依照权限设定不同数量的家作为VIP附加内容 38 | - 回到死亡地点、上一传送地点 39 | 40 | ### 优势 41 | 42 | - **轻量插件。** 适合小型服务器使用,配置简单方便。 43 | - **规范开发。** 插件架构符合开发规范,适合新手开发者学习。 44 | - 自 [3.0.0]() 版本开始采用了 EasyPlugin 开发,可能与其他主流插件结构有些不同。 45 | - **持续维护。** 新功能需求均可提交,大概率在后续开发中支持。 46 | - 功能需求请 [提交Issues](https://github.com/CarmJos/MoeTeleport/issues/new?assignees=&labels=enhancement&template=feature_issues.md&title=) 47 | ,不要在帖子中提交! 48 | - 提交与 “传送” 相关联的请求才大概率会被更新支持。 49 | 50 | ## [依赖](https://github.com/CarmJos/MoeTeleport/network/dependencies) 51 | 52 | - **[必须]** 插件本体基于 [Spigot-API](https://hub.spigotmc.org/stash/projects/SPIGOT) 、[BukkitAPI](http://bukkit.org/) 53 | 实现。 54 | - **[自带]** 消息格式基于 [MineDown](https://github.com/Phoenix616/MineDown) 实现。 55 | - 所有 messages.yml 均支持 MineDown 语法。 56 | - **[推荐]** 变量部分基于 [PlaceholderAPI](https://www.spigotmc.org/resources/6245/) 实现。 57 | 58 | 详细依赖列表可见 [Dependencies](https://github.com/CarmJos/MoeTeleport/network/dependencies) 。 59 | 60 | ## [指令](src/main/resources/plugin.yml) 61 | 62 | 以下指令的主指令为 `/MoeTeleport` 或 `/mt`。 63 | 64 | 本插件所有指令支持配置“简化指令”,如允许玩家直接输入 `/back` 执行 `/MoeTeleport back`,详见 [配置文件](#配置) 相关内容。 65 | 66 | - 必须参数 `<参数>` 67 | - 可选参数 `[参数]` 68 | 69 | ```text 70 | # reload 71 | @ 管理指令 (MoeTeleport.admin) 72 | - 重载插件配置文件。 73 | 74 | # back 75 | - 回到之前的传送位置。 76 | 77 | ----- [ 传送相关指令 ] ----- 78 | 79 | # teleport to <目标玩家> 80 | - 请求传送到目标玩家的位置。 81 | 82 | # teleport here <玩家> 83 | - 请求目标玩家传送到自己的位置。 84 | 85 | # teleport accept [玩家] 86 | - 同意一个传送请求(可具体指定玩家的请求)。 87 | 88 | # teleport deny [玩家] 89 | - 拒绝一个传送请求(可具体指定玩家的请求)。 90 | 91 | ----- [ 家相关指令 ] ----- 92 | 93 | # home to [家名] 94 | - 传送到指定的家。 95 | - 若不填写具体的家明则返回首个设置的家, 96 | - 若存在名为“home”的家则优先返回“home”。 97 | 98 | # home list 99 | - 列出所有的家位置。 100 | 101 | # home set [家名] 102 | - 设定一个家的位置。 103 | - 若不填写家的名称则默认为“home”。 104 | 105 | # home delete [家名] 106 | - 删除一个家的位置。 107 | 108 | ----- [ 地标相关指令 ] ----- 109 | 110 | # warp to <地标名> 111 | - 传送到指定的地标点。 112 | 113 | # warp list 114 | - 列出当前所有的地标点。 115 | 116 | # warp set <地标名> 117 | - 设定一个地标点。 118 | - 若地标点已存在,且您是地标点的设立者(或是服务器管理员), 119 | - 则会覆盖原有的地标点位置。 120 | 121 | # warp delete <地标名> 122 | - 删除一个自己设立的地标点。 123 | 124 | ``` 125 | 126 | ## 配置 127 | 128 | ### 插件配置文件 ([config.yml]()) 129 | 130 | 详见源文件。 131 | 132 | ### 消息配置文件 ([messages.yml]()) 133 | 134 | 支持 [MineDown 语法](https://wiki.phoenix616.dev/library:minedown:syntax),详见源文件。 135 | 136 | ## 使用统计 137 | 138 | [![bStats](https://bstats.org/signatures/bukkit/MoeTeleport.svg)](https://bstats.org/plugin/bukkit/MoeTeleport/14459) 139 | 140 | ## 支持与捐赠 141 | 142 | 若您觉得本插件做的不错,您可以捐赠支持我,感谢您成为开源项目的支持者! 143 | 144 | 由衷感谢以下支持本项目开发的朋友们: 145 | - 本插件由 [**璎珞**服务器](https://www.yingluo.world/) 委托本人开发,经过授权后开源。 146 | - 感谢 [**XingMC**(MagicMC服务器开发者)](https://www.mcbbs.net/?4816320) 为本插件提供后续开发的资金赞助。 147 | 148 | Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects. 149 | [![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/UserPrefix) 150 | 151 | ## 开源协议 152 | 153 | 本项目源码采用 [GNU General Public License v3.0](https://opensource.org/licenses/GPL-3.0) 开源协议。 154 |
155 | 关于 GPL 协议 156 | 157 | > GNU General Public Licence (GPL) 有可能是开源界最常用的许可模式。GPL 保证了所有开发者的权利,同时为使用者提供了足够的复制,分发,修改的权利: 158 | > 159 | > #### 可自由复制 160 | > 你可以将软件复制到你的电脑,你客户的电脑,或者任何地方。复制份数没有任何限制。 161 | > #### 可自由分发 162 | > 在你的网站提供下载,拷贝到U盘送人,或者将源代码打印出来从窗户扔出去(环保起见,请别这样做)。 163 | > #### 可以用来盈利 164 | > 你可以在分发软件的时候收费,但你必须在收费前向你的客户提供该软件的 GNU GPL 许可协议,以便让他们知道,他们可以从别的渠道免费得到这份软件,以及你收费的理由。 165 | > #### 可自由修改 166 | > 如果你想添加或删除某个功能,没问题,如果你想在别的项目中使用部分代码,也没问题,唯一的要求是,使用了这段代码的项目也必须使用 167 | > GPL 协议。 168 | > 169 | > 需要注意的是,分发的时候,需要明确提供源代码和二进制文件,另外,用于某些程序的某些协议有一些问题和限制,你可以看一下 170 | > @PierreJoye 写的 Practical Guide to GPL Compliance 一文。使用 GPL 协议,你必须在源代码代码中包含相应信息,以及协议本身。 171 | > 172 | > *以上文字来自 [五种开源协议GPL,LGPL,BSD,MIT,Apache](https://www.oschina.net/question/54100_9455) 。* 173 |
174 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/file/YAMLStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.file; 2 | 3 | import cc.carm.plugin.moeteleport.Main; 4 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 5 | import cc.carm.plugin.moeteleport.storage.UserData; 6 | import cc.carm.plugin.moeteleport.model.WarpInfo; 7 | import cc.carm.plugin.moeteleport.storage.DataSerializer; 8 | import cc.carm.plugin.moeteleport.storage.impl.FileBasedStorage; 9 | import org.bukkit.configuration.ConfigurationSection; 10 | import org.bukkit.configuration.file.FileConfiguration; 11 | import org.bukkit.configuration.file.YamlConfiguration; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.io.File; 16 | import java.util.LinkedHashMap; 17 | import java.util.Map; 18 | import java.util.Optional; 19 | import java.util.UUID; 20 | 21 | public class YAMLStorage extends FileBasedStorage { 22 | 23 | Map warpsMap; 24 | 25 | File warpsDataFile; 26 | FileConfiguration warpsConfiguration; 27 | 28 | @Override 29 | public void initialize() throws Exception { 30 | super.initialize(); 31 | this.warpsDataFile = new File(getDataFolder(), "warps.yml"); 32 | if (!this.warpsDataFile.exists() && !warpsDataFile.createNewFile()) { 33 | throw new Exception("无法创建 warps.yml 文件。"); 34 | } 35 | this.warpsConfiguration = YamlConfiguration.loadConfiguration(warpsDataFile); 36 | this.warpsMap = loadWarps(); 37 | } 38 | 39 | @Override 40 | public void saveWarps(@NotNull Map warps) throws Exception { 41 | this.warpsConfiguration.save(this.warpsDataFile); 42 | } 43 | 44 | @Override 45 | public @Nullable UserData loadData(@NotNull UUID uuid) { 46 | if (getDataFolder() == null || !getDataFolder().exists() || !getDataFolder().isDirectory()) { 47 | throw new NullPointerException("Storage data folder is not initialized."); 48 | } 49 | File userDataFile = new File(getDataFolder(), uuid + ".yml"); 50 | if (!userDataFile.exists()) { 51 | Main.debugging("当前文件夾内不存在玩家 " + uuid + " 的数据,视作新档。"); 52 | return null; 53 | } 54 | 55 | YamlConfiguration userConfiguration = YamlConfiguration.loadConfiguration(userDataFile); 56 | 57 | DataLocation lastLocation = Optional 58 | .ofNullable(userConfiguration.getString("lastLocation")) 59 | .map(DataLocation::deserializeText) 60 | .orElse(null); 61 | 62 | LinkedHashMap homeData = new LinkedHashMap<>(); 63 | Optional.ofNullable(userConfiguration.getConfigurationSection("homes")).ifPresent( 64 | section -> section.getKeys(false).forEach(homeName -> { 65 | DataLocation location = DataLocation.deserializeText(section.getString(homeName)); 66 | if (location != null) homeData.put(homeName, location); 67 | })); 68 | 69 | return new UserData(uuid, lastLocation, homeData); 70 | } 71 | 72 | @Override 73 | public void saveUserData(@NotNull UserData data) throws Exception { 74 | if (getDataFolder() == null || !getDataFolder().exists() || !getDataFolder().isDirectory()) { 75 | throw new NullPointerException("Storage data folder is not initialized."); 76 | } 77 | 78 | YamlConfiguration userConfiguration = new YamlConfiguration(); 79 | if (data.getLastLocation() != null) { 80 | userConfiguration.set("lastLocation", DataSerializer.serializeLocation(data.getLastLocation())); 81 | } 82 | 83 | userConfiguration.createSection("homes", DataSerializer.serializeLocationsMap(data.getHomeLocations())); 84 | userConfiguration.save(new File(getDataFolder(), data.getUserUUID() + ".yml")); 85 | } 86 | 87 | private @NotNull Map loadWarps() { 88 | LinkedHashMap warps = new LinkedHashMap<>(); 89 | 90 | ConfigurationSection warpsSection = this.warpsConfiguration.getConfigurationSection("warps"); 91 | if (warpsSection == null) return warps; 92 | 93 | for (String warpName : warpsSection.getKeys(false)) { 94 | ConfigurationSection warpInfoSection = warpsSection.getConfigurationSection(warpName); 95 | if (warpInfoSection == null) continue; 96 | try { 97 | String ownerString = warpInfoSection.getString("owner"); 98 | UUID owner = ownerString == null ? null : UUID.fromString(ownerString); 99 | DataLocation location = new DataLocation( 100 | warpInfoSection.getString("world"), 101 | warpInfoSection.getDouble("x"), 102 | warpInfoSection.getDouble("y"), 103 | warpInfoSection.getDouble("z"), 104 | warpInfoSection.getLong("yaw"), 105 | warpInfoSection.getLong("pitch") 106 | ); 107 | warps.put(warpName, new WarpInfo(warpName, owner, location)); 108 | } catch (Exception ignore) { 109 | } 110 | } 111 | 112 | return warps; 113 | } 114 | 115 | @Override 116 | public Map getWarps() { 117 | return warpsMap; 118 | } 119 | 120 | @Override 121 | public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) { 122 | this.warpsMap.put(name, warpInfo); 123 | this.warpsConfiguration.createSection("warps." + name, DataSerializer.serializeWarpMap(warpInfo)); 124 | } 125 | 126 | @Override 127 | public boolean delWarp(@NotNull String name) { 128 | this.warpsConfiguration.set("warps." + name, null); 129 | return this.warpsMap.remove(name) != null; 130 | } 131 | 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/manager/RequestManager.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.manager; 2 | 3 | import cc.carm.plugin.moeteleport.Main; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 6 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 7 | import cc.carm.plugin.moeteleport.teleport.TeleportRequest; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.scheduler.BukkitRunnable; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | import org.jetbrains.annotations.Unmodifiable; 13 | 14 | import java.time.Duration; 15 | import java.time.temporal.ChronoUnit; 16 | import java.util.Collections; 17 | import java.util.Iterator; 18 | import java.util.Map; 19 | import java.util.UUID; 20 | import java.util.concurrent.ConcurrentHashMap; 21 | import java.util.stream.Collectors; 22 | 23 | public class RequestManager { 24 | 25 | protected final Map requests = new ConcurrentHashMap<>(); 26 | protected BukkitRunnable runnable; 27 | 28 | public RequestManager(Main main) { 29 | this.runnable = new BukkitRunnable() { 30 | @Override 31 | public void run() { 32 | tickRequests(); 33 | } 34 | }; 35 | this.runnable.runTaskTimerAsynchronously(main, 100L, 20L); 36 | } 37 | 38 | public void shutdown() { 39 | if (!this.runnable.isCancelled()) { 40 | this.runnable.cancel(); 41 | } 42 | } 43 | 44 | @Unmodifiable 45 | public Map getRequests() { 46 | return Collections.unmodifiableMap(requests); 47 | } 48 | 49 | public @Nullable TeleportRequest getRequest(UUID senderUUID) { 50 | return requests.get(senderUUID); 51 | } 52 | 53 | @Unmodifiable 54 | public @NotNull Map getUserReceivedRequests(@NotNull UUID receiverUUID) { 55 | return requests.values().stream() 56 | .filter(request -> request.getReceiver().getUniqueId().equals(receiverUUID)) 57 | .collect(Collectors.toMap(request -> request.getSender().getUniqueId(), request -> request)); 58 | } 59 | 60 | public void tickRequests() { 61 | Iterator> requestIterator = requests.entrySet().iterator(); 62 | while (requestIterator.hasNext()) { 63 | Map.Entry entry = requestIterator.next(); 64 | TeleportRequest request = entry.getValue(); 65 | if (!request.isExpired()) continue; 66 | 67 | requestIterator.remove(); // 移除过期的请求 68 | 69 | // 发送提示 70 | PluginMessages.REQUESTS.SENT_TIMEOUT.send(request.getSender(), request.getReceiver().getName()); 71 | PluginMessages.REQUESTS.RECEIVED_TIMEOUT.send(request.getReceiver(), request.getSender().getName()); 72 | } 73 | } 74 | 75 | public void sendRequest(Player sender, Player receiver, TeleportRequest.Type type) { 76 | int expireTime = PluginConfig.REQUEST.EXPIRE_TIME.getNotNull(); 77 | 78 | PluginConfig.REQUEST.SOUND.SENT.playTo(sender); 79 | PluginConfig.REQUEST.SOUND.RECEIVED.playTo(receiver); 80 | 81 | PluginMessages.REQUESTS.SENT.send(sender, receiver.getName(), expireTime); 82 | switch (type) { 83 | case TPA_TO: { 84 | PluginMessages.REQUESTS.RECEIVED_TP_HERE.send(receiver, sender.getName(), expireTime); 85 | break; 86 | } 87 | case TPA_HERE: { 88 | PluginMessages.REQUESTS.RECEIVED_TP_TO.send(receiver, sender.getName(), expireTime); 89 | break; 90 | } 91 | } 92 | 93 | requests.put(sender.getUniqueId(), new TeleportRequest(type, sender, receiver)); 94 | } 95 | 96 | public void acceptRequest(TeleportRequest request) { 97 | PluginMessages.REQUESTS.WAS_ACCEPTED.send(request.getSender(), request.getReceiver().getName()); 98 | PluginMessages.REQUESTS.ACCEPTED.send(request.getReceiver(), request.getSender().getName()); 99 | 100 | removeRequests(request); 101 | MoeTeleport.getTeleportManager().queueTeleport(request.createQueue( 102 | Duration.of(PluginConfig.TELEPORTATION.WAIT_TIME.getNotNull(), ChronoUnit.SECONDS) 103 | )); 104 | } 105 | 106 | public void cancelRequest(TeleportRequest request) { 107 | PluginMessages.REQUESTS.SENT_CANCELLED.send(request.getSender(), request.getReceiver().getName()); 108 | PluginMessages.REQUESTS.RECEIVED_CANCELLED.send(request.getReceiver(), request.getSender().getName()); 109 | PluginConfig.REQUEST.SOUND.CANCELLED.playTo(request.getSender()); 110 | PluginConfig.REQUEST.SOUND.CANCELLED.playTo(request.getReceiver()); 111 | removeRequests(request); 112 | } 113 | 114 | public void denyRequest(TeleportRequest request) { 115 | PluginMessages.REQUESTS.WAS_DENIED.send(request.getSender(), request.getReceiver().getName()); 116 | PluginMessages.REQUESTS.DENIED.send(request.getReceiver(), request.getSender().getName()); 117 | removeRequests(request); 118 | } 119 | 120 | public void removeRequests(TeleportRequest request) { 121 | this.requests.remove(request.getSender().getUniqueId()); 122 | } 123 | 124 | public void cancelAllRequests(Player player) { 125 | UUID playerUUID = player.getUniqueId(); 126 | 127 | TeleportRequest sent = requests.remove(playerUUID); 128 | if (sent != null) { 129 | PluginMessages.REQUESTS.OFFLINE.send(sent.getReceiver(), player.getName()); 130 | } 131 | 132 | for (TeleportRequest received : getUserReceivedRequests(playerUUID).values()) { 133 | PluginMessages.REQUESTS.OFFLINE.send(received.getSender(), player.getName()); 134 | removeRequests(received); 135 | } 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/Main.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport; 2 | 3 | import cc.carm.lib.configuration.core.source.ConfigurationProvider; 4 | import cc.carm.lib.easyplugin.EasyPlugin; 5 | import cc.carm.lib.easyplugin.command.alias.AliasCommandManager; 6 | import cc.carm.lib.easyplugin.updatechecker.GHUpdateChecker; 7 | import cc.carm.lib.mineconfiguration.bukkit.MineConfiguration; 8 | import cc.carm.plugin.moeteleport.command.MainCommands; 9 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 10 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 11 | import cc.carm.plugin.moeteleport.listener.TeleportListener; 12 | import cc.carm.plugin.moeteleport.listener.UserListener; 13 | import cc.carm.plugin.moeteleport.manager.*; 14 | import cc.carm.plugin.moeteleport.storage.DataStorage; 15 | import cc.carm.plugin.moeteleport.storage.StorageMethod; 16 | import org.bstats.bukkit.Metrics; 17 | import org.bstats.charts.SimplePie; 18 | import org.bukkit.Bukkit; 19 | import org.jetbrains.annotations.NotNull; 20 | import xyz.xenondevs.particle.utils.ReflectionUtils; 21 | 22 | public class Main extends EasyPlugin { 23 | private static Main instance; 24 | 25 | protected ConfigurationProvider configProvider; 26 | protected ConfigurationProvider messageProvider; 27 | 28 | protected DataStorage storage; 29 | protected WarpManager warpManager; 30 | protected UserManager userManager; 31 | protected RequestManager requestManager; 32 | protected TeleportManager teleportManager; 33 | protected AliasCommandManager commandManager; 34 | 35 | public Main() { 36 | instance = this; 37 | } 38 | 39 | @Override 40 | protected void load() { 41 | 42 | log("加载插件配置文件..."); 43 | this.configProvider = MineConfiguration.from(this, "config.yml"); 44 | this.configProvider.initialize(PluginConfig.class); 45 | 46 | this.messageProvider = MineConfiguration.from(this, "messages.yml"); 47 | this.messageProvider.initialize(PluginMessages.class); 48 | 49 | } 50 | 51 | @Override 52 | protected boolean initialize() { 53 | 54 | log("初始化存储方式..."); 55 | StorageMethod storageMethod = StorageMethod.read(PluginConfig.STORAGE.METHOD.get()); 56 | 57 | try { 58 | log(" 正在使用 " + storageMethod.name() + " 进行数据存储"); 59 | storage = storageMethod.createStorage(); 60 | storage.initialize(); 61 | } catch (Exception ex) { 62 | severe("初始化存储失败,请检查配置文件。"); 63 | setEnabled(false); 64 | return false; // 初始化失败,不再继续加载 65 | } 66 | 67 | log("加载地标管理器..."); 68 | warpManager = new WarpManager(); 69 | 70 | log("加载用户管理器..."); 71 | this.userManager = new UserManager(); 72 | if (Bukkit.getOnlinePlayers().size() > 0) { 73 | log(" 加载现有用户数据..."); 74 | this.userManager.loadAll(); 75 | } 76 | 77 | log("加载请求管理器..."); 78 | this.requestManager = new RequestManager(this); 79 | 80 | log("加载传送管理器..."); 81 | this.teleportManager = new TeleportManager(this); 82 | 83 | log("注册监听器..."); 84 | registerListener(new UserListener()); 85 | registerListener(new TeleportListener()); 86 | 87 | log("注册指令..."); 88 | registerCommand("MoeTeleport", new MainCommands(this)); 89 | 90 | if (PluginConfig.COMMAND.ENABLE.getNotNull()) { 91 | log("注册简化指令映射..."); 92 | try { 93 | this.commandManager = new AliasCommandManager(this); 94 | PluginConfig.COMMAND.ALIAS.getNotNull().forEach(commandManager::register); 95 | } catch (Exception e) { 96 | log("注册简化指令失败: " + e.getMessage()); 97 | e.printStackTrace(); 98 | } 99 | } 100 | 101 | if (PluginConfig.METRICS.getNotNull()) { 102 | log("启用统计数据..."); 103 | Metrics metrics = new Metrics(this, 14459); 104 | metrics.addCustomChart(new SimplePie("storage_method", storageMethod::name)); 105 | } 106 | 107 | if (PluginConfig.CHECK_UPDATE.getNotNull()) { 108 | log("开始检查更新..."); 109 | getScheduler().runAsync(GHUpdateChecker.runner(this)); 110 | } else { 111 | log("已禁用检查更新,跳过。"); 112 | } 113 | 114 | log("初始化粒子库..."); 115 | ReflectionUtils.setPlugin(this); 116 | 117 | return true; 118 | } 119 | 120 | @Override 121 | protected void shutdown() { 122 | if (PluginConfig.COMMAND.ENABLE.getNotNull() && this.commandManager != null) { 123 | log("清空简化指令..."); 124 | this.commandManager.unregisterAll(); 125 | } 126 | 127 | log("关闭所有请求..."); 128 | this.requestManager.shutdown(); 129 | this.teleportManager.shutdown(); 130 | 131 | log("保存用户数据..."); 132 | this.userManager.unloadAll(true); 133 | 134 | log("保存地标数据..."); 135 | this.warpManager.saveWarps(); 136 | 137 | log("终止存储源..."); 138 | this.storage.shutdown(); 139 | 140 | log("卸载监听器..."); 141 | Bukkit.getServicesManager().unregisterAll(this); 142 | } 143 | 144 | @Override 145 | public boolean isDebugging() { 146 | return PluginConfig.DEBUG.getNotNull(); 147 | } 148 | 149 | public static void info(String... messages) { 150 | getInstance().log(messages); 151 | } 152 | 153 | public static void severe(String... messages) { 154 | getInstance().error(messages); 155 | } 156 | 157 | public static void debugging(String... messages) { 158 | getInstance().debug(messages); 159 | } 160 | 161 | public static Main getInstance() { 162 | return instance; 163 | } 164 | 165 | public ConfigurationProvider getConfigProvider() { 166 | return configProvider; 167 | } 168 | 169 | public ConfigurationProvider getMessageProvider() { 170 | return messageProvider; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/file/JSONStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.file; 2 | 3 | import cc.carm.lib.easysql.api.util.UUIDUtil; 4 | import cc.carm.plugin.moeteleport.Main; 5 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 6 | import cc.carm.plugin.moeteleport.storage.UserData; 7 | import cc.carm.plugin.moeteleport.model.WarpInfo; 8 | import cc.carm.plugin.moeteleport.storage.DataSerializer; 9 | import cc.carm.plugin.moeteleport.storage.impl.FileBasedStorage; 10 | import com.google.gson.Gson; 11 | import com.google.gson.JsonElement; 12 | import com.google.gson.JsonObject; 13 | import com.google.gson.JsonParser; 14 | import org.jetbrains.annotations.NotNull; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.io.File; 18 | import java.io.FileReader; 19 | import java.io.FileWriter; 20 | import java.util.HashMap; 21 | import java.util.LinkedHashMap; 22 | import java.util.Map; 23 | import java.util.UUID; 24 | 25 | public class JSONStorage extends FileBasedStorage { 26 | 27 | protected static final Gson GSON = new Gson(); 28 | protected static final JsonParser PARSER = new JsonParser(); 29 | 30 | Map warpsMap = new HashMap<>(); 31 | 32 | @Override 33 | public void initialize() throws Exception { 34 | super.initialize(); 35 | this.warpsMap = loadWarps(); 36 | } 37 | 38 | @Override 39 | public @Nullable UserData loadData(@NotNull UUID uuid) throws Exception { 40 | File userDataFile = new File(getDataFolder(), uuid + ".json"); 41 | if (!userDataFile.exists()) { 42 | Main.debugging("当前文件夾内不存在玩家 " + uuid + " 的数据,视作新档。"); 43 | return null; 44 | } 45 | 46 | JsonElement dataElement = PARSER.parse(new FileReader(userDataFile)); 47 | if (!dataElement.isJsonObject()) throw new NullPointerException(userDataFile.getName()); 48 | 49 | JsonObject dataObject = dataElement.getAsJsonObject(); 50 | DataLocation lastLocation = null; 51 | if (dataObject.has("lastLocation")) { 52 | lastLocation = DataLocation.deserializeText(dataObject.get("lastLocation").getAsString()); 53 | } 54 | 55 | LinkedHashMap homeData = new LinkedHashMap<>(); 56 | if (dataObject.has("homes")) { 57 | JsonObject homesObject = dataObject.getAsJsonObject("homes"); 58 | if (homesObject != null) { 59 | homesObject.entrySet().forEach(entry -> { 60 | DataLocation location = DataLocation.deserializeText(entry.getValue().getAsString()); 61 | if (location != null) homeData.put(entry.getKey(), location); 62 | }); 63 | } 64 | } 65 | 66 | return new UserData(uuid, lastLocation, homeData); 67 | } 68 | 69 | @Override 70 | public void saveUserData(@NotNull UserData data) throws Exception { 71 | JsonObject dataObject = new JsonObject(); 72 | if (data.getLastLocation() != null) { 73 | dataObject.addProperty("lastLocation", DataSerializer.serializeLocation(data.getLastLocation())); 74 | } 75 | dataObject.add("homes", GSON.toJsonTree(DataSerializer.serializeLocationsMap(data.getHomeLocations()))); 76 | 77 | FileWriter writer = new FileWriter(new File(getDataFolder(), data.getUserUUID() + ".json")); 78 | writer.write(GSON.toJson(dataObject)); 79 | writer.flush(); 80 | writer.close(); 81 | } 82 | 83 | private @NotNull Map loadWarps() throws Exception { 84 | File warpDataFile = new File(getDataFolder(), "warps.json"); 85 | if (!warpDataFile.exists()) return new LinkedHashMap<>(); 86 | 87 | JsonElement dataElement = PARSER.parse(new FileReader(warpDataFile)); 88 | if (!dataElement.isJsonObject()) throw new NullPointerException(warpDataFile.getName()); 89 | 90 | JsonObject dataObject = dataElement.getAsJsonObject(); 91 | LinkedHashMap warps = new LinkedHashMap<>(); 92 | dataObject.entrySet().forEach(entry -> { 93 | String warpName = entry.getKey(); 94 | if (entry.getValue().isJsonObject()) { 95 | try { 96 | JsonObject warpObject = entry.getValue().getAsJsonObject(); 97 | UUID owner = warpObject.has("owner") ? UUIDUtil.toUUID(warpObject.get("owner").getAsString()) : null; 98 | DataLocation location = new DataLocation( 99 | warpObject.get("world").getAsString(), 100 | warpObject.get("x").getAsDouble(), 101 | warpObject.get("y").getAsDouble(), 102 | warpObject.get("z").getAsDouble(), 103 | warpObject.get("yaw").getAsFloat(), 104 | warpObject.get("pitch").getAsFloat() 105 | ); 106 | warps.put(warpName, new WarpInfo(warpName, owner, location)); 107 | } catch (Exception ignore) { 108 | } 109 | } 110 | }); 111 | return warps; 112 | } 113 | 114 | @Override 115 | public void saveWarps(@NotNull Map warps) throws Exception { 116 | JsonObject dataObject = new JsonObject(); 117 | 118 | warps.forEach((name, info) -> dataObject.add(name, GSON.toJsonTree(DataSerializer.serializeWarpMap(info)))); 119 | 120 | FileWriter writer = new FileWriter(new File(getDataFolder(), "warps.json")); 121 | writer.write(GSON.toJson(dataObject)); 122 | writer.flush(); 123 | writer.close(); 124 | } 125 | 126 | @Override 127 | public Map getWarps() { 128 | return warpsMap; 129 | } 130 | 131 | @Override 132 | public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) { 133 | this.warpsMap.put(name, warpInfo); 134 | } 135 | 136 | @Override 137 | public boolean delWarp(@NotNull String name) { 138 | return this.warpsMap.remove(name) != null; 139 | } 140 | 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/manager/TeleportManager.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.manager; 2 | 3 | import cc.carm.plugin.moeteleport.Main; 4 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 5 | import cc.carm.plugin.moeteleport.conf.PluginMessages; 6 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 7 | import cc.carm.plugin.moeteleport.teleport.TeleportQueue; 8 | import cc.carm.plugin.moeteleport.teleport.TeleportRequest; 9 | import cc.carm.plugin.moeteleport.teleport.target.TeleportLocationTarget; 10 | import cc.carm.plugin.moeteleport.teleport.target.TeleportTarget; 11 | import org.bukkit.Location; 12 | import org.bukkit.Material; 13 | import org.bukkit.entity.Player; 14 | import org.bukkit.inventory.ItemStack; 15 | import org.bukkit.scheduler.BukkitRunnable; 16 | import org.jetbrains.annotations.Nullable; 17 | import xyz.xenondevs.particle.ParticleBuilder; 18 | import xyz.xenondevs.particle.ParticleEffect; 19 | import xyz.xenondevs.particle.data.texture.ItemTexture; 20 | 21 | import java.time.Duration; 22 | import java.time.temporal.ChronoUnit; 23 | import java.util.Iterator; 24 | import java.util.Map; 25 | import java.util.UUID; 26 | import java.util.concurrent.ConcurrentHashMap; 27 | 28 | public class TeleportManager { 29 | 30 | protected final Map teleportQueue = new ConcurrentHashMap<>(); 31 | protected BukkitRunnable runnable; 32 | 33 | public TeleportManager(Main main) { 34 | this.runnable = new BukkitRunnable() { 35 | @Override 36 | public void run() { 37 | tickQueue(); 38 | } 39 | }; 40 | this.runnable.runTaskTimerAsynchronously(main, 20L, 20L); 41 | } 42 | 43 | public void shutdown() { 44 | if (!this.runnable.isCancelled()) { 45 | this.runnable.cancel(); 46 | } 47 | } 48 | 49 | public void tickQueue() { 50 | boolean enableEffect = PluginConfig.TELEPORTATION.EFFECTS.getNotNull(); 51 | 52 | Iterator> queueIterator = teleportQueue.entrySet().iterator(); 53 | while (queueIterator.hasNext()) { 54 | Map.Entry entry = queueIterator.next(); 55 | TeleportQueue queue = entry.getValue(); 56 | if (!queue.checkTime()) { 57 | PluginConfig.TELEPORTATION.SOUND.CHANNELING.playTo(queue.getPlayer()); 58 | PluginConfig.TELEPORTATION.TITLE.CHANNELING.send( 59 | queue.getPlayer(), 60 | queue.getRemainSeconds() + 1, queue.getTarget().getText() 61 | ); 62 | 63 | if (enableEffect) { 64 | new ParticleBuilder(ParticleEffect.PORTAL, queue.getPlayer().getLocation()) 65 | .setAmount(100).setOffsetY(1F).display(); 66 | } 67 | 68 | continue; 69 | } 70 | 71 | queueIterator.remove(); 72 | executeTeleport(queue); 73 | } 74 | } 75 | 76 | public void interruptQueue(TeleportQueue queue) { 77 | teleportQueue.remove(queue.getPlayer().getUniqueId()); 78 | PluginMessages.TELEPORT.INTERRUPTED.send(queue.getPlayer()); 79 | PluginConfig.TELEPORTATION.SOUND.INTERRUPTED.playTo(queue.getPlayer()); 80 | } 81 | 82 | public TeleportQueue getQueue(UUID uuid) { 83 | return teleportQueue.get(uuid); 84 | } 85 | 86 | public TeleportQueue getQueue(Player player) { 87 | return getQueue(player.getUniqueId()); 88 | } 89 | 90 | public boolean isChanneling(UUID uuid) { 91 | return teleportQueue.containsKey(uuid); 92 | } 93 | 94 | public boolean isChanneling(Player player) { 95 | return isChanneling(player.getUniqueId()); 96 | } 97 | 98 | public @Nullable Duration getDelayDuration() { 99 | return Duration.of(PluginConfig.TELEPORTATION.WAIT_TIME.getNotNull(), ChronoUnit.SECONDS); 100 | } 101 | 102 | public void queueTeleport(@Nullable TeleportQueue queue) { 103 | if (queue == null) return; 104 | if (queue.checkTime()) { // 直接满足传送条件 105 | executeTeleport(queue); 106 | return; 107 | } 108 | teleportQueue.put(queue.getPlayer().getUniqueId(), queue); 109 | } 110 | 111 | public void queueTeleport(TeleportRequest request) { 112 | queueTeleport(request.createQueue(getDelayDuration())); 113 | } 114 | 115 | public void queueTeleport(Player player, TeleportTarget target) { 116 | queueTeleport(new TeleportQueue(player, target, getDelayDuration())); 117 | } 118 | 119 | public void queueTeleport(Player player, DataLocation target) { 120 | queueTeleport(player, new TeleportLocationTarget(target)); 121 | } 122 | 123 | public void queueTeleport(Player player, Location target) { 124 | queueTeleport(player, new TeleportLocationTarget(target)); 125 | } 126 | 127 | protected void executeTeleport(TeleportQueue queue) { 128 | Player player = queue.getPlayer(); 129 | queue.getUser().setLastLocation(player.getLocation()); 130 | 131 | Location location = queue.getTarget().prepare(); 132 | if (location == null) { 133 | PluginMessages.TELEPORT.NOT_AVAILABLE.send(player, queue.getTarget().getText()); 134 | PluginConfig.TELEPORTATION.SOUND.FAILED.playTo(player); 135 | } else { 136 | PluginMessages.TELEPORT.TELEPORTED.send(player, queue.getTarget().getText()); 137 | PluginConfig.TELEPORTATION.TITLE.TELEPORTED.send(player, queue.getTarget().getText()); 138 | Main.getInstance().getScheduler().run(() -> { 139 | player.teleport(location); 140 | PluginConfig.TELEPORTATION.SOUND.TELEPORTED.playTo(player); 141 | }); 142 | 143 | 144 | if (PluginConfig.TELEPORTATION.EFFECTS.getNotNull()) { 145 | new ParticleBuilder(ParticleEffect.ITEM_CRACK, location) 146 | .setParticleData(new ItemTexture(new ItemStack(Material.ENDER_EYE))) 147 | .setAmount(1).setOffsetY(1F).display(); 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/manager/UserManager.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.manager; 2 | 3 | import cc.carm.plugin.moeteleport.Main; 4 | import cc.carm.plugin.moeteleport.MoeTeleport; 5 | import cc.carm.plugin.moeteleport.conf.PluginConfig; 6 | import cc.carm.plugin.moeteleport.model.WarpInfo; 7 | import cc.carm.plugin.moeteleport.storage.DataStorage; 8 | import cc.carm.plugin.moeteleport.storage.UserData; 9 | import cc.carm.plugin.moeteleport.util.DataTaskRunner; 10 | import com.google.common.collect.ImmutableMap; 11 | import org.bukkit.Bukkit; 12 | import org.bukkit.entity.Player; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | import org.jetbrains.annotations.Unmodifiable; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.Objects; 20 | import java.util.UUID; 21 | 22 | public class UserManager { 23 | 24 | private final HashMap userDataMap; 25 | 26 | public UserManager() { 27 | this.userDataMap = new HashMap<>(); 28 | } 29 | 30 | private static int getMaxValue(Player player, Map permissions, int defaultValue) { 31 | int current = defaultValue; 32 | 33 | for (Map.Entry entry : permissions.entrySet()) { 34 | if (entry.getKey() > current && player.hasPermission(entry.getValue())) { 35 | current = entry.getKey(); 36 | } 37 | } 38 | 39 | return current; 40 | } 41 | 42 | @NotNull 43 | public UserData readData(UUID userUUID) { 44 | try { 45 | long start = System.currentTimeMillis(); 46 | DataStorage storage = MoeTeleport.getStorage(); 47 | Main.debugging("正通过 " + storage.getClass().getSimpleName() + " 读取 " + userUUID + " 的用户数据...(" + System.currentTimeMillis() + ")"); 48 | 49 | UserData data = storage.loadData(userUUID); 50 | 51 | if (data == null) { 52 | Main.debugging("当前还不存在玩家 " + userUUID + " 的数据,视作新档。"); 53 | return new UserData(userUUID); 54 | } 55 | 56 | Main.debugging("通过 " + storage.getClass().getSimpleName() + "读取 " + userUUID + " 的用户数据完成," 57 | + "耗时 " + (System.currentTimeMillis() - start) + "ms。"); 58 | 59 | return data; 60 | } catch (Exception e) { 61 | Main.severe("无法正常读取玩家数据,玩家操作将不会被保存,请检查数据配置!"); 62 | Main.severe("Could not load user's data, please check the data configuration!"); 63 | e.printStackTrace(); 64 | return new UserData(userUUID); 65 | } 66 | } 67 | 68 | public void saveData(UserData data) { 69 | try { 70 | long start = System.currentTimeMillis(); 71 | DataStorage storage = MoeTeleport.getStorage(); 72 | 73 | Main.debugging("正通过 " + storage.getClass().getSimpleName() + " 保存 " + data.getUserUUID() + " 的用户数据...(" + System.currentTimeMillis() + ")"); 74 | storage.saveUserData(data); 75 | 76 | Main.debugging("通过 " + storage.getClass().getSimpleName() + " 保存 " + data.getUserUUID() + " 的用户数据完成," + 77 | "耗时 " + (System.currentTimeMillis() - start) + "ms。"); 78 | 79 | } catch (Exception e) { 80 | Main.severe("无法正常保存玩家数据,请检查数据配置!"); 81 | Main.severe("Could not save user's data, please check the data configuration!"); 82 | e.printStackTrace(); 83 | } 84 | } 85 | 86 | public void loadData(UUID userUUID) { 87 | getUserDataMap().put(userUUID, readData(userUUID)); 88 | } 89 | 90 | public void unloadData(UUID userUUID) { 91 | unloadData(userUUID, true); 92 | } 93 | 94 | public void unloadData(UUID userUUID, boolean save) { 95 | UserData data = getData(userUUID); 96 | if (data == null) return; 97 | if (save) saveData(data); 98 | getUserDataMap().remove(userUUID); 99 | } 100 | 101 | public void loadAll() { 102 | for (Player player : Bukkit.getOnlinePlayers()) { 103 | if (getUserDataMap().containsKey(player.getUniqueId())) continue; 104 | loadData(player.getUniqueId()); 105 | } 106 | } 107 | 108 | public void saveAll() { 109 | getUserDataMap().values().forEach(this::saveData); 110 | } 111 | 112 | public void unloadAll(boolean save) { 113 | if (save) saveAll(); 114 | getUserDataMap().clear(); 115 | } 116 | 117 | @Nullable 118 | public UserData getData(UUID userUUID) { 119 | return getUserDataMap().get(userUUID); 120 | } 121 | 122 | @NotNull 123 | public UserData getData(Player player) { 124 | return getUserDataMap().get(player.getUniqueId()); 125 | } 126 | 127 | public long countUserWarps(UUID userUUID) { 128 | return MoeTeleport.getWarpManager().listWarps().values().stream() 129 | .map(WarpInfo::getOwner).filter(Objects::nonNull) 130 | .filter(ownerUUID -> ownerUUID.equals(userUUID)) 131 | .count(); 132 | } 133 | 134 | public int getMaxHome(Player player) { 135 | return getMaxValue(player, PluginConfig.HOMES.PERMISSIONS.getNotNull(), PluginConfig.HOMES.DEFAULTS.getNotNull()); 136 | } 137 | 138 | public int getMaxWarps(Player player) { 139 | return getMaxValue(player, PluginConfig.WARPS.PERMISSIONS.getNotNull(), PluginConfig.WARPS.DEFAULTS.getNotNull()); 140 | } 141 | 142 | public void editData(@NotNull DataTaskRunner task) { 143 | try { 144 | task.run(MoeTeleport.getStorage()); 145 | } catch (Exception exception) { 146 | Main.severe("无法正常更改玩家数据,请检查数据配置!"); 147 | Main.severe("Could not edit user's data, please check the data configuration!"); 148 | exception.printStackTrace(); 149 | } 150 | } 151 | 152 | public void editDataAsync(@NotNull DataTaskRunner task) { 153 | Main.getInstance().getScheduler().runAsync(() -> editData(task)); 154 | } 155 | 156 | @NotNull 157 | @Unmodifiable 158 | public Map listUserData() { 159 | return ImmutableMap.copyOf(getUserDataMap()); 160 | } 161 | 162 | protected @NotNull HashMap getUserDataMap() { 163 | return userDataMap; 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /README-EN.md: -------------------------------------------------------------------------------- 1 | ```text 2 | __ ___ ______ __ __ 3 | / |/ /__ __/_ __/__ / /__ ___ ___ ____/ /_ 4 | / /|_/ / _ \/ -_) / / -_) / -_) _ \/ _ \/ __/ __/ 5 | /_/ /_/\___/\__/_/ \__/_/\__/ .__/\___/_/ \__/ 6 | /_/ 7 | ``` 8 | README LANGUAGES [ [中文](README.md) | [**English**](README-EN.md) ] 9 | 10 | # MoeTeleport 11 | 12 | [![CodeFactor](https://www.codefactor.io/repository/github/CarmJos/MoeTeleport/badge?s=b76fec1f64726b5f19989aace6adb5f85fdab840)](https://www.codefactor.io/repository/github/CarmJos/MoeTeleport) 13 | ![CodeSize](https://img.shields.io/github/languages/code-size/CarmJos/MoeTeleport) 14 | [![Download](https://img.shields.io/github/downloads/CarmJos/MoeTeleport/total)](https://github.com/CarmJos/MoeTeleport/releases) 15 | [![Java CI with Maven](https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml) 16 | ![Support](https://img.shields.io/badge/Minecraft-Java%201.13--Latest-blue) 17 | ![](https://visitor-badge.glitch.me/badge?page_id=moeteleport.readme) 18 | 19 | MoeTeleport is an open source delivery plugin that contains several features and will be always updated to add new features based on users' requirements. 20 | 21 | The project code conforms to the development specifications and is suitable for new developers to learn Bukkit and make their own plugins. 22 | 23 | ## Functions and advantages 24 | 25 | ### Current functions 26 | 27 | - Multiple storage formats, select on demand. 28 | - Support YAML, JSON and MySQL/MariaDB storage 29 | - Support direct call [EssentialsX] (https://github.com/EssentialsX/Essentials)/CMI data, Seamless switching 30 | - Clickable messages (such as "Click-Agree") 31 | - Based on the MineDown syntax, Customizable configuration 32 | - Teleport requests between players 33 | - Support to specify handling a player's request 34 | - Set warp locations 35 | - Support to set a different number of warp locations as VIP add-on content based on permissions 36 | - Set home locations (understood as private warps) 37 | - Support setting different number of homes according to permissions as VIP add-on content 38 | - Return to the place of death and the last location 39 | 40 | ### Advantages 41 | 42 | - ** Lightweight plugin. ** Suitable for small servers, simple and convenient configuration. 43 | - ** Specification development. ** Plugin architecture conforms to development specifications, suitable for new developers to learn. 44 | - EasyPlugin has been used since [3.0.0]() and may be somewhat different from other mainstream plugin structures. 45 | - ** Continuous maintenance. ** All new functional requirements can be submitted, which is likely to be supported in the subsequent development. 46 | - Functional requirements please [submit Issues] (HTTP: / / https://github.com/CarmJos/MoeTeleport/issues/new?assignees=&labels=enhancement&template=feature issues.md&title=), do not submit in the post! 47 | - Submitting requests associated with "teleport" will most likely be updated and supported. 48 | 49 | ## [Dependencies](https://github.com/CarmJos/MoeTeleport/network/dependencies) 50 | 51 | - **[Necessary]** The plugin is based on [Spigot-API](https://hub.spigotmc.org/stash/projects/SPIGOT) 、[BukkitAPI](http://bukkit.org/). 52 | - **[Included]** Message format is based on [MineDown](https://github.com/Phoenix616/MineDown). 53 | - All messages.yml support MineDown syntax。 54 | - **[Recommended]** The variable part is based on [PlaceholderAPI](https://www.spigotmc.org/resources/6245/). 55 | 56 | Read this if you need more details. [Dependencies](https://github.com/CarmJos/MoeTeleport/network/dependencies). 57 | 58 | ## [Commands](src/main/resources/plugin.yml) 59 | 60 | The main command is `/MoeTeleport` or `/mt`. 61 | 62 | All commands in this plugin support configuration of "simplified commands", 63 | such as allowing the player to directly input '/back' and execute '/MoeTeleport back', see [configuration](#Config) related content. 64 | 65 | - Required parameter '< Parameter >' 66 | - Optional parameter '[parameter]' 67 | 68 | ```text 69 | # reload 70 | @ Admin command (MoeTeleport.admin) 71 | - Reload the plugin configuration file. 72 | 73 | # back 74 | - Return to the last location. 75 | 76 | ----- [Teleport commands] ----- 77 | 78 | # teleport to 79 | - Request to teleport to target player's location. 80 | 81 | # teleport here 82 | - Request the target player to teleport to their location. 83 | 84 | # teleport accept [target player] 85 | - Grant a teleport request (player requests can be specified). 86 | 87 | # teleport deny [target player]. 88 | - Reject a teleport request (player requests can be specified). 89 | 90 | ----- [Home commands] ----- 91 | 92 | # home to [home name] 93 | - Send to the specified home. 94 | - If you do not fill in the specific home, return to the first set of home. 95 | - If there is a home named "home", return to "home" preferentially. 96 | 97 | # home list 98 | - List all the home names. 99 | 100 | # home set [home name] 101 | - Set a home location. 102 | - If you do not specify the name of home, the default value is "home". 103 | 104 | # home delete [home name] 105 | -Delete a home location 106 | 107 | 108 | ----- [Warp commands] ----- 109 | 110 | # warp to 111 | - Teleport to the specified location. 112 | 113 | # warp list 114 | - List all current warp locations. 115 | 116 | # warp set 117 | - Set a warp location. 118 | - If the warp already exists and you are the owner (or the server administrator) of the warp, 119 | - the old warp point will be overwritten. 120 | 121 | # warp delete 122 | - Delete one of your own warps 123 | 124 | ``` 125 | 126 | ## Config 127 | 128 | ### Plugin configuration file ([config.yml]()) 129 | 130 | Read source file for more details. 131 | 132 | ### Message configuration file ([messages.yml]()) 133 | 134 | Support [MineDown syntax](https://wiki.phoenix616.dev/library:minedown:syntax) 135 | 136 | Read source file for more details. 137 | 138 | ## Usage statistics 139 | 140 | [![bStats](https://bstats.org/signatures/bukkit/MoeTeleport.svg)](https://bstats.org/plugin/bukkit/MoeTeleport/14459) 141 | 142 | ## Support and donate 143 | 144 | If you find this plugin helps, you can donate to support me. Thank you for being a supporter of this open source project! 145 | 146 | Sincere thanks to the following friends who support the development of this project: 147 | - This plugin is entrusted by [**璎珞 **](https://www.yingluo.world/) server , authorized already. 148 | - Thank you to [**XingMC**(MagicMC server developer)](https://www.mcbbs.net/?4816320) for funding the subsequent development of this plugin. 149 | 150 | Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects. 151 | [![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/UserPrefix) 152 | 153 | ## Open source agreement 154 | 155 | The source code of this project uses [GNU General Public License v3.0](https://opensource.org/licenses/GPL-3.0) License. -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/storage/database/MySQLStorage.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.storage.database; 2 | 3 | import cc.carm.lib.easysql.EasySQL; 4 | import cc.carm.lib.easysql.api.SQLManager; 5 | import cc.carm.lib.easysql.api.util.UUIDUtil; 6 | import cc.carm.plugin.moeteleport.Main; 7 | import cc.carm.plugin.moeteleport.conf.location.DataLocation; 8 | import cc.carm.plugin.moeteleport.model.WarpInfo; 9 | import cc.carm.plugin.moeteleport.storage.DataStorage; 10 | import cc.carm.plugin.moeteleport.storage.UserData; 11 | import org.bukkit.Location; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.sql.ResultSet; 16 | import java.sql.SQLException; 17 | import java.util.HashMap; 18 | import java.util.LinkedHashMap; 19 | import java.util.Map; 20 | import java.util.UUID; 21 | 22 | public class MySQLStorage implements DataStorage { 23 | 24 | SQLManager sqlManager; 25 | 26 | Map warpsMap = new HashMap<>(); 27 | 28 | @Override 29 | public void initialize() throws Exception { 30 | 31 | Main.info("加载数据库配置..."); 32 | Main.getInstance().getConfigProvider().initialize(DatabaseConfig.class); 33 | 34 | try { 35 | Main.info(" 尝试连接到数据库..."); 36 | this.sqlManager = EasySQL.createManager( 37 | DatabaseConfig.DRIVER_NAME.getNotNull(), DatabaseConfig.buildJDBC(), 38 | DatabaseConfig.USERNAME.getNotNull(), DatabaseConfig.PASSWORD.getNotNull() 39 | ); 40 | this.sqlManager.setDebugMode(() -> Main.getInstance().isDebugging()); 41 | } catch (Exception exception) { 42 | throw new Exception("无法连接到数据库,请检查配置文件", exception); 43 | } 44 | 45 | try { 46 | Main.info(" 创建插件所需表..."); 47 | for (DatabaseTables value : DatabaseTables.values()) { 48 | value.create(this.sqlManager); 49 | } 50 | } catch (SQLException exception) { 51 | throw new Exception("无法创建插件所需的表,请检查数据库权限。", exception); 52 | } 53 | 54 | Main.info(" 加载地标数据..."); 55 | try { 56 | this.warpsMap = loadWarps(); 57 | } catch (Exception e) { 58 | throw new Exception("无法加载地标数据,请检查数据库权限和相关表。", e); 59 | } 60 | } 61 | 62 | @Override 63 | public void shutdown() { 64 | Main.info(" 关闭数据库连接..."); 65 | EasySQL.shutdownManager(getSQLManager()); 66 | this.sqlManager = null; 67 | } 68 | 69 | public SQLManager getSQLManager() { 70 | return sqlManager; 71 | } 72 | 73 | @Override 74 | public @Nullable UserData loadData(@NotNull UUID uuid) throws Exception { 75 | LinkedHashMap homes = loadHomes(uuid); 76 | DataLocation lastLocation = loadLastLocation(uuid); 77 | return new UserData(uuid, lastLocation, homes); 78 | } 79 | 80 | @Override 81 | public void saveUserData(@NotNull UserData data) throws Exception { 82 | Location location = data.getLastLocation(); 83 | if (location != null && location.getWorld() != null) { 84 | DatabaseTables.LAST_LOCATION.createReplace() 85 | .setColumnNames("uuid", "world", "x", "y", "z", "yaw", "pitch") 86 | .setParams( 87 | data.getUserUUID(), location.getWorld().getName(), 88 | location.getX(), location.getY(), location.getZ(), 89 | location.getYaw(), location.getPitch() 90 | ).execute(); 91 | } else { 92 | DatabaseTables.LAST_LOCATION.createDelete() 93 | .addCondition("uuid", data.getUserUUID()).setLimit(1) 94 | .build().execute(); 95 | } 96 | } 97 | 98 | @Override 99 | public Map getWarps() { 100 | return this.warpsMap; 101 | } 102 | 103 | @Override 104 | public void saveWarps(@NotNull Map warps) { 105 | // 单独保存,不需要统一存储 106 | } 107 | 108 | private @NotNull LinkedHashMap loadHomes(@NotNull UUID uuid) throws Exception { 109 | return DatabaseTables.HOMES.createQuery() 110 | .addCondition("uuid", uuid).build() 111 | .executeFunction((query) -> { 112 | LinkedHashMap homes = new LinkedHashMap<>(); 113 | ResultSet resultSet = query.getResultSet(); 114 | if (resultSet == null) return homes; 115 | while (resultSet.next()) { 116 | String name = resultSet.getString("name"); 117 | if (name == null) continue; 118 | homes.put(name, readLocation(resultSet)); 119 | } 120 | return homes; 121 | }, new LinkedHashMap<>()); 122 | } 123 | 124 | private @Nullable DataLocation loadLastLocation(@NotNull UUID uuid) throws Exception { 125 | return DatabaseTables.LAST_LOCATION.createQuery() 126 | .addCondition("uuid", uuid).setLimit(1).build() 127 | .executeFunction((query) -> { 128 | ResultSet resultSet = query.getResultSet(); 129 | if (resultSet == null || !resultSet.next()) return null; 130 | return readLocation(resultSet); 131 | }); 132 | } 133 | 134 | private @NotNull Map loadWarps() throws Exception { 135 | return DatabaseTables.WRAPS.createQuery() 136 | .orderBy("id", true).build().executeFunction((query) -> { 137 | LinkedHashMap warps = new LinkedHashMap<>(); 138 | ResultSet resultSet = query.getResultSet(); 139 | if (resultSet == null) return warps; 140 | while (resultSet.next()) { 141 | String uuidString = resultSet.getString("owner"); 142 | UUID uuid = uuidString == null ? null : UUIDUtil.toUUID(uuidString); 143 | String name = resultSet.getString("name"); 144 | DataLocation location = readLocation(resultSet); 145 | warps.put(name, new WarpInfo(name, uuid, location)); 146 | } 147 | return warps; 148 | }, new LinkedHashMap<>()); 149 | } 150 | 151 | @Override 152 | public void setHome(@NotNull UUID uuid, @NotNull String homeName, @NotNull DataLocation location) throws Exception { 153 | DatabaseTables.HOMES.createReplace() 154 | .setColumnNames("uuid", "name", "world", "x", "y", "z", "yaw", "pitch") 155 | .setParams( 156 | uuid, homeName, location.getWorldName(), 157 | location.getX(), location.getY(), location.getZ(), 158 | location.getYaw(), location.getPitch() 159 | ).execute(); 160 | } 161 | 162 | 163 | @Override 164 | public boolean delHome(@NotNull UUID uuid, @NotNull String homeName) throws Exception { 165 | return DatabaseTables.HOMES.createDelete() 166 | .addCondition("uuid", uuid) 167 | .addCondition("name", homeName) 168 | .setLimit(1) 169 | .build().executeFunction((i) -> i > 0, false); 170 | } 171 | 172 | @Override 173 | public void setWarp(@NotNull String name, @NotNull WarpInfo warpInfo) throws Exception { 174 | this.warpsMap.put(name, warpInfo); 175 | DataLocation location = warpInfo.getLocation(); 176 | DatabaseTables.WRAPS.createReplace() 177 | .setColumnNames("name", "owner", "world", "x", "y", "z", "yaw", "pitch") 178 | .setParams( 179 | name, warpInfo.getOwner(), location.getWorldName(), 180 | location.getX(), location.getY(), location.getZ(), 181 | location.getYaw(), location.getPitch() 182 | ).execute(); 183 | } 184 | 185 | @Override 186 | public boolean delWarp(@NotNull String name) throws Exception { 187 | String actualName = this.warpsMap.keySet().stream().filter(s -> s.equalsIgnoreCase(name)).findFirst().orElse(null); 188 | if (actualName == null) return false; 189 | 190 | this.warpsMap.remove(actualName); 191 | return DatabaseTables.WRAPS.createDelete() 192 | .addCondition("name", actualName).setLimit(1) 193 | .build().executeFunction((i) -> i > 0, false); 194 | } 195 | 196 | protected DataLocation readLocation(ResultSet result) throws SQLException { 197 | return new DataLocation( 198 | result.getString("world"), 199 | result.getDouble("x"), 200 | result.getDouble("y"), 201 | result.getDouble("z"), 202 | result.getFloat("yaw"), 203 | result.getFloat("pitch") 204 | ); 205 | } 206 | 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/conf/PluginConfig.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.conf; 2 | 3 | 4 | import cc.carm.lib.configuration.core.ConfigurationRoot; 5 | import cc.carm.lib.configuration.core.annotation.HeaderComment; 6 | import cc.carm.lib.configuration.core.util.MapFactory; 7 | import cc.carm.lib.configuration.core.value.ConfigValue; 8 | import cc.carm.lib.configuration.core.value.type.ConfiguredMap; 9 | import cc.carm.lib.configuration.core.value.type.ConfiguredValue; 10 | import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredSound; 11 | import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredTitle; 12 | 13 | public class PluginConfig extends ConfigurationRoot { 14 | 15 | public static final ConfigValue DEBUG = ConfiguredValue.of(Boolean.class, false); 16 | 17 | @HeaderComment({ 18 | "统计数据设定", 19 | "该选项用于帮助开发者统计插件版本与使用情况,且绝不会影响性能与使用体验。", 20 | "当然,您也可以选择在这里关闭,或在plugins/bStats下的配置文件中关闭。" 21 | }) 22 | public static final ConfigValue METRICS = ConfiguredValue.of(Boolean.class, true); 23 | 24 | @HeaderComment({ 25 | "检查更新设定", 26 | "该选项用于插件判断是否要检查更新,若您不希望插件检查更新并提示您,可以选择关闭。", 27 | "检查更新为异步操作,绝不会影响性能与使用体验。" 28 | }) 29 | public static final ConfigValue CHECK_UPDATE = ConfiguredValue.of(Boolean.class, true); 30 | 31 | @HeaderComment("简化插件指令设定") 32 | public static final class COMMAND extends ConfigurationRoot { 33 | 34 | @HeaderComment({"是否启用简化指令"}) 35 | public static final ConfigValue ENABLE = ConfiguredValue.of(Boolean.class, true); 36 | 37 | @HeaderComment({ 38 | "简化指令表,配置以方便玩家使用。", 39 | "格式: 简短指令: 本插件子指令(不含前缀)", 40 | "如 [back: back] 代表 玩家可以输入/back 代替 /MoeTeleport back", 41 | "注意:简短指令不应当包含空格,且不可与其他插件指令重复,否则将会被覆盖。", 42 | }) 43 | public static final ConfiguredMap ALIAS = ConfiguredMap.builder(String.class, String.class) 44 | .fromString().defaults((map) -> { 45 | map.put("back", "back"); 46 | map.put("tpa", "teleport to"); 47 | map.put("tpaHere", "teleport here"); 48 | map.put("tpAccept", "teleport accept"); 49 | map.put("tpDeny", "teleport deny"); 50 | map.put("tpCancel", "teleport cancel"); 51 | 52 | map.put("home", "home to"); 53 | map.put("setHome", "home set"); 54 | map.put("delHome", "home delete"); 55 | map.put("listHomes", "home list"); 56 | map.put("listHome", "home list"); 57 | map.put("renameHome", "home rename"); 58 | 59 | map.put("warp", "warp to"); 60 | map.put("setWarp", "warp set"); 61 | map.put("delWarp", "warp delete"); 62 | map.put("warpInfo", "warp info"); 63 | map.put("listWarps", "warp list"); 64 | map.put("listWarp", "warp list"); 65 | map.put("renameWarp", "warp rename"); 66 | }).build(); 67 | 68 | } 69 | 70 | @HeaderComment({"存储相关配置", "注意:存储配置不会通过重载指令生效,如有修改请重新启动服务器。"}) 71 | public static final class STORAGE extends ConfigurationRoot { 72 | 73 | @HeaderComment("存储方式,可选 [ yaml | json | mysql | Essential(须安装ess插件) | CMI(须安装CMI插件) | custom(自定义,须重写功能) ]") 74 | public static final ConfigValue METHOD = ConfiguredValue.of(String.class, "YAML"); 75 | 76 | } 77 | 78 | @HeaderComment("传送的相关配置") 79 | public static final class TELEPORTATION extends ConfigurationRoot { 80 | 81 | /* Will be supported again in the future 82 | @HeaderComment("危险的方块类型,将判断目的地脚下的方块的类型是否在这个列表中") 83 | public static final ConfiguredList DANGEROUS_TYPES = ConfiguredList.builder(String.class) 84 | .fromString() 85 | .defaults("LAVA", "AIR") 86 | .build(); 87 | */ 88 | 89 | @HeaderComment("传送的引导时间,单位为秒") 90 | public static final ConfigValue WAIT_TIME = ConfiguredValue.of(Integer.class, 3); 91 | 92 | @HeaderComment("打断传送引导的方式") 93 | public static final class INTERRUPT extends ConfigurationRoot { 94 | 95 | @HeaderComment("在传送引导时是否会因为移动打断传送") 96 | public static final ConfigValue MOVE = ConfiguredValue.of(Boolean.class, true); 97 | 98 | @HeaderComment("在传送引导时是否会因为攻击/被攻击打断传送") 99 | public static final ConfigValue ATTACK = ConfiguredValue.of(Boolean.class, true); 100 | 101 | @HeaderComment("在传送引导时是否会因为下蹲打断传送") 102 | public static final ConfigValue SNAKE = ConfiguredValue.of(Boolean.class, false); 103 | 104 | } 105 | 106 | @HeaderComment("传送过程中的标题") 107 | public static final class TITLE extends ConfigurationRoot { 108 | 109 | public static final ConfiguredTitle CHANNELING = PluginMessages.title().defaults( 110 | "&d&l将在 %(time) 秒后传送", 111 | "&7传送过程中请不要移动" 112 | ).params("time", "target").fadeIn(0).stay(25).fadeOut(0).build(); 113 | 114 | public static final ConfiguredTitle TELEPORTED = PluginMessages.title().defaults( 115 | "&d&l传送完成", 116 | "&7已将您传送到 %(target)" 117 | ).params("target").fadeIn(0).stay(20).fadeOut(10).build(); 118 | 119 | } 120 | 121 | @HeaderComment("传送引导过程中的音效") 122 | public static final class SOUND extends ConfigurationRoot { 123 | 124 | public static final ConfiguredSound CHANNELING = ConfiguredSound.of("UI_BUTTON_CLICK", 0.5f, 1.0f); 125 | public static final ConfiguredSound TELEPORTED = ConfiguredSound.of("ENTITY_ENDERMAN_TELEPORT", 0.5f, 1.0f); 126 | public static final ConfiguredSound FAILED = ConfiguredSound.of("ENTITY_VILLAGER_NO", 0.5f, 1.0f); 127 | public static final ConfiguredSound INTERRUPTED = ConfiguredSound.of("BLOCK_NOTE_BLOCK_BASEDRUM", 1f, 1.0f); 128 | 129 | } 130 | 131 | @HeaderComment("传送引导特效") 132 | public static final ConfigValue EFFECTS = ConfiguredValue.of(Boolean.class, true); 133 | 134 | } 135 | 136 | 137 | @HeaderComment("传送请求的相关配置") 138 | public static final class REQUEST extends ConfigurationRoot { 139 | 140 | @HeaderComment("请求的过期时间,单位为秒") 141 | public static final ConfigValue EXPIRE_TIME = ConfiguredValue.of(Integer.class, 30); 142 | 143 | 144 | public static final class SOUND extends ConfigurationRoot { 145 | 146 | public static final ConfiguredSound SENT = ConfiguredSound.of("UI_BUTTON_CLICK", 0.5f, 1.0f); 147 | public static final ConfiguredSound RECEIVED = ConfiguredSound.of("ENTITY_EXPERIENCE_ORB_PICKUP", 0.5f, 1.0f); 148 | public static final ConfiguredSound CANCELLED = ConfiguredSound.of("ENTITY_VILLAGER_NO", 0.5f, 1.0f); 149 | 150 | } 151 | 152 | } 153 | 154 | @HeaderComment("返回上一传送点的相关配置") 155 | public static final class BACK extends ConfigurationRoot { 156 | 157 | @HeaderComment("是否启用返回上一传送点功能") 158 | public static final ConfigValue ENABLE = ConfiguredValue.of(Boolean.class, false); 159 | 160 | @HeaderComment({"返回死亡点", "开启后将允许玩家输入 /back 返回死亡地点。"}) 161 | public static final ConfigValue DEATH = ConfiguredValue.of(Boolean.class, true); 162 | 163 | } 164 | 165 | @HeaderComment("“家”功能相关配置") 166 | public static final class HOMES extends ConfigurationRoot { 167 | 168 | @HeaderComment("是否启用家功能") 169 | public static final ConfigValue ENABLE = ConfiguredValue.of(Boolean.class, false); 170 | 171 | @HeaderComment("普通玩家可设置多少家") 172 | public static final ConfigValue DEFAULTS = ConfiguredValue.of(Integer.class, 2); 173 | 174 | @HeaderComment("设定权限对应的可设置家的数量。 (数量: 权限)") 175 | public static final ConfiguredMap PERMISSIONS = ConfiguredMap 176 | .builder(Integer.class, String.class) 177 | .fromString() 178 | .parseKey(Integer::parseInt).serializeKey(Object::toString) 179 | .defaults(MapFactory.linkedMap(10, "MoeTeleport.vip").build()) 180 | .build(); 181 | 182 | } 183 | 184 | @HeaderComment("“地标”功能相关配置") 185 | public static final class WARPS extends ConfigurationRoot { 186 | 187 | @HeaderComment("是否启用地标功能") 188 | public static final ConfigValue ENABLE = ConfiguredValue.of(Boolean.class, false); 189 | 190 | @HeaderComment("普通玩家可设置多少地标") 191 | public static final ConfigValue DEFAULTS = ConfiguredValue.of(Integer.class, 0); 192 | 193 | @HeaderComment("设定权限对应的可设置地标的数量。 (数量: 权限)") 194 | public static final ConfiguredMap PERMISSIONS = ConfiguredMap 195 | .builder(Integer.class, String.class) 196 | .fromString() 197 | .parseKey(Integer::parseInt).serializeKey(Object::toString) 198 | .defaults(MapFactory.linkedMap(2, "MoeTeleport.vip").build()) 199 | .build(); 200 | } 201 | 202 | 203 | } 204 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | 8 9 | ${project.jdk.version} 10 | ${project.jdk.version} 11 | UTF-8 12 | UTF-8 13 | 14 | 1.5.14 15 | 0.4.7 16 | 3.1.3 17 | 18 | 19 | cc.carm.plugin 20 | moeteleport 21 | 4.0.3 22 | 23 | MoeTeleport 24 | 喵喵传送,简单的传送、设置家的插件。 25 | https://github.com/CarmJos/MoeTeleport 26 | 27 | 28 | GitHub Issues 29 | https://github.com/CarmJos/MoeTeleport/issues 30 | 31 | 32 | 33 | GitHub Actions 34 | https://github.com/CarmJos/MoeTeleport/actions/workflows/maven.yml 35 | 36 | 37 | 38 | 39 | CarmJos 40 | Carm Jos 41 | carm@carm.cc 42 | https://work.carm.cc 43 | 44 | 45 | 46 | 47 | 48 | spigot-repo 49 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 50 | 51 | 52 | 53 | placeholder-api-repo 54 | https://repo.extendedclip.com/content/repositories/placeholderapi/ 55 | 56 | 57 | 58 | oss-repo 59 | https://oss.sonatype.org/content/groups/public/ 60 | 61 | 62 | 63 | nexus 64 | https://mvn.lumine.io/repository/maven-public/ 65 | 66 | 67 | 68 | maven-central 69 | https://repo1.maven.org/maven2/ 70 | 71 | 72 | 73 | minebench-repo 74 | https://repo.minebench.de/ 75 | 76 | 77 | 78 | essentials-repo 79 | https://repo.essentialsx.net/releases/ 80 | 81 | 82 | 83 | carm-repo 84 | Carm's Repo 85 | https://repo.carm.cc/repository/maven-public/ 86 | 87 | 88 | 89 | 90 | 91 | https://github.com/CarmJos/MoeTeleport/releases 92 | 93 | github 94 | GitHub Packages 95 | https://maven.pkg.github.com/CarmJos/MoeTeleport 96 | 97 | 98 | 99 | 100 | 101 | 102 | cc.carm.lib 103 | mineconfiguration-bukkit 104 | ${deps.mineconfig.version} 105 | compile 106 | true 107 | 108 | 109 | 110 | cc.carm.lib 111 | easyplugin-main 112 | ${deps.easyplugin.version} 113 | compile 114 | true 115 | 116 | 117 | 118 | cc.carm.lib 119 | easyplugin-command 120 | ${deps.easyplugin.version} 121 | compile 122 | true 123 | 124 | 125 | 126 | cc.carm.lib 127 | easyplugin-command-alias 128 | ${deps.easyplugin.version} 129 | compile 130 | true 131 | 132 | 133 | 134 | cc.carm.lib 135 | easyplugin-githubchecker 136 | ${deps.easyplugin.version} 137 | compile 138 | true 139 | 140 | 141 | 142 | net.essentialsx 143 | EssentialsX 144 | 2.21.2 145 | provided 146 | 147 | 148 | 149 | com.Zrips 150 | CMI-API 151 | 9.3.1.2 152 | system 153 | ${project.basedir}/lib/CMI-API9.3.1.2.jar 154 | 155 | 156 | 157 | com.Zrips 158 | CMILib 159 | 1.2.4.5 160 | system 161 | ${project.basedir}/lib/CMILib1.2.4.5.jar 162 | 163 | 164 | 165 | cc.carm.lib 166 | easysql-beecp 167 | ${deps.easysql.version} 168 | compile 169 | true 170 | 171 | 172 | 173 | de.themoep 174 | minedown 175 | 1.7.1-SNAPSHOT 176 | compile 177 | true 178 | 179 | 180 | 181 | xyz.xenondevs 182 | particle 183 | 1.8.4 184 | compile 185 | true 186 | 187 | 188 | 189 | org.spigotmc 190 | spigot-api 191 | 1.19-R0.1-20220725.090125-47 192 | provided 193 | 194 | 195 | 196 | com.comphenix.protocol 197 | ProtocolLib 198 | 5.3.0 199 | provided 200 | 201 | 202 | 203 | org.bstats 204 | bstats-bukkit 205 | 3.1.0 206 | compile 207 | true 208 | 209 | 210 | 211 | me.clip 212 | placeholderapi 213 | 2.11.7 214 | provided 215 | 216 | 217 | 218 | junit 219 | junit 220 | 4.13.2 221 | test 222 | 223 | 224 | 225 | org.jetbrains 226 | annotations 227 | 26.0.2-1 228 | provided 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | org.apache.maven.plugins 237 | maven-clean-plugin 238 | 3.5.0 239 | 240 | 241 | 242 | ${project.basedir}/asset/ 243 | true 244 | 245 | **/* 246 | 247 | 248 | 249 | ${project.basedir}/api-docs/ 250 | true 251 | 252 | **/* 253 | 254 | 255 | 256 | 257 | 258 | 259 | org.apache.maven.plugins 260 | maven-compiler-plugin 261 | 3.14.1 262 | 263 | ${project.jdk.version} 264 | ${project.jdk.version} 265 | UTF-8 266 | -parameters 267 | 268 | 269 | 270 | org.apache.maven.plugins 271 | maven-jar-plugin 272 | 3.5.0 273 | 274 | 275 | org.apache.maven.plugins 276 | maven-source-plugin 277 | 3.4.0 278 | 279 | 280 | package 281 | 282 | jar-no-fork 283 | 284 | 285 | 286 | 287 | 288 | org.apache.maven.plugins 289 | maven-shade-plugin 290 | 3.6.1 291 | 292 | 293 | package 294 | 295 | shade 296 | 297 | 298 | 299 | 300 | MoeTeleport-${project.version} 301 | ${project.basedir}/asset/ 302 | false 303 | 304 | 305 | *:* 306 | 307 | META-INF/MANIFEST.MF 308 | META-INF/*.txt 309 | 310 | 311 | 312 | 313 | 314 | cc.carm.lib 315 | cc.carm.plugin.moeteleport.lib 316 | 317 | 318 | de.themoep.minedown 319 | cc.carm.plugin.moeteleport.lib.minedown 320 | 321 | 322 | org.bstats 323 | cc.carm.plugin.moeteleport.lib.bstats 324 | 325 | 326 | xyz.xenondevs.particle 327 | cc.carm.plugin.moeteleport.lib.praticle 328 | 329 | 330 | org.json 331 | cc.carm.plugin.moeteleport.lib.json 332 | 333 | 334 | 335 | 336 | 337 | org.apache.maven.plugins 338 | maven-surefire-plugin 339 | 3.5.4 340 | 341 | false 342 | 343 | 344 | 345 | 346 | 347 | src/main/resources 348 | true 349 | 350 | 351 | 352 | 353 | 354 | -------------------------------------------------------------------------------- /src/main/java/cc/carm/plugin/moeteleport/conf/PluginMessages.java: -------------------------------------------------------------------------------- 1 | package cc.carm.plugin.moeteleport.conf; 2 | 3 | import cc.carm.lib.configuration.core.ConfigurationRoot; 4 | import cc.carm.lib.configuration.core.annotation.HeaderComment; 5 | import cc.carm.lib.easyplugin.utils.ColorParser; 6 | import cc.carm.lib.easyplugin.utils.MessageUtils; 7 | import cc.carm.lib.mineconfiguration.bukkit.builder.message.CraftMessageListBuilder; 8 | import cc.carm.lib.mineconfiguration.bukkit.builder.message.CraftMessageValueBuilder; 9 | import cc.carm.lib.mineconfiguration.bukkit.builder.title.TitleConfigBuilder; 10 | import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredMessage; 11 | import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredMessageList; 12 | import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredTitle; 13 | import de.themoep.minedown.MineDown; 14 | import net.md_5.bungee.api.chat.BaseComponent; 15 | import org.bukkit.command.CommandSender; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | import java.util.function.BiFunction; 19 | 20 | 21 | @HeaderComment({ 22 | "MoeTeleport 传送插件的消息配置文件", 23 | "如特定的消息不需要任何提示,可直接留下单行空内容消息。", 24 | "支持 支持 &+颜色代码(原版颜色)、§(#XXXXXX)(RGB颜色) 与 &<#XXXXXX>(前后标注RGB颜色渐变)。", 25 | " " 26 | }) 27 | public class PluginMessages extends ConfigurationRoot { 28 | 29 | public static @NotNull CraftMessageListBuilder list() { 30 | return ConfiguredMessageList.create(getParser()) 31 | .whenSend((sender, message) -> message.forEach(m -> sender.spigot().sendMessage(m))); 32 | } 33 | 34 | public static @NotNull CraftMessageValueBuilder value() { 35 | return ConfiguredMessage.create(getParser()) 36 | .whenSend((sender, message) -> sender.spigot().sendMessage(message)); 37 | } 38 | 39 | public static @NotNull TitleConfigBuilder title() { 40 | return ConfiguredTitle.create().whenSend((player, in, stay, out, line1, line2) -> player.sendTitle(line1, line2, in, stay, out)); 41 | } 42 | 43 | public static @NotNull BiFunction getParser() { 44 | return (sender, message) -> MineDown.parse(ColorParser.parse(MessageUtils.setPlaceholders(sender, message))); 45 | } 46 | 47 | public static final ConfiguredMessageList NO_PERMISSION = list().defaults( 48 | "&c&l抱歉!&f但您没有足够的权限使用该指令。" 49 | ).build(); 50 | 51 | public static final ConfiguredMessageList NOT_ONLINE = list().defaults( 52 | "&f目标玩家并不在线,无法发送请求。" 53 | ).build(); 54 | 55 | public static final ConfiguredMessageList NOT_PLAYER = list().defaults( 56 | "&f该指令请以玩家身份执行。" 57 | ).build(); 58 | 59 | public static final ConfiguredMessageList NOT_ENABLED = list().defaults( 60 | "&f该功能在次服务器中并未被启用。" 61 | ).build(); 62 | 63 | public static class USAGE extends ConfigurationRoot { 64 | 65 | public static final ConfiguredMessageList COMMAND = list().defaults( 66 | "&5&l喵喵传送 &f指令帮助", 67 | "&8#&f teleport help", 68 | "&8-&7 查看传送请求相关帮助。", 69 | "&8#&f warp help", 70 | "&8-&7 查看地标点相关帮助。", 71 | "&8#&f home Help", 72 | "&8-&7 查看家传送点的相关帮助。", 73 | "&8#&f back", 74 | "&8-&7 回到之前的传送位置。" 75 | ).build(); 76 | 77 | public static final ConfiguredMessageList TELEPORT = list().defaults( 78 | "&5&l喵喵传送 &f传送指令帮助", 79 | "&8#&f teleport to &d<目标玩家>", 80 | "&8-&7 请求传送到目标玩家的位置。", 81 | "&8#&f teleport here &d<目标玩家>", 82 | "&8-&7 请求目标玩家传送到自己的位置。", 83 | "&8#&f teleport accept &d[玩家]", 84 | "&8-&7 同意一个传送请求(可具体指定玩家的请求)。", 85 | "&8#&f teleport deny &d[玩家]", 86 | "&8-&7 拒绝一个传送请求(可具体指定玩家的请求)。", 87 | "&8#&f teleport cancel", 88 | "&8-&7 取消已经发出的传送请求。" 89 | ).build(); 90 | 91 | public static final ConfiguredMessageList WARPS = list().defaults( 92 | "&5&l喵喵传送 &f地标指令帮助", 93 | "&8#&f warp list", 94 | "&8-&7 列出当前所有的地标点。", 95 | "&8#&f warp to &d<地标名>", 96 | "&8-&7 传送到指定的地标点。", 97 | "&8#&f warp set &d[地标名]", 98 | "&8-&7 设定一个地标点。", 99 | "&8-&7&o 若地标点已存在,且您是地标点的设立者,", 100 | "&8-&7&o 则会覆盖原有的地标点位置。", 101 | "&8#&f warp delete &d[地标名]", 102 | "&8-&7 删除一个自己设立的地标点。", 103 | "&8#&f warp rename &d<原地标名> &d<新地标名>", 104 | "&8-&7 重命名一个自己设立的地标点。" 105 | ).build(); 106 | 107 | public static final ConfiguredMessageList HOMES = list().defaults( 108 | "&5&l喵喵传送 &f家指令帮助", 109 | "&8#&f home list", 110 | "&8-&7 列出所有的家位置。", 111 | "&8#&f home to &d[家名]", 112 | "&8-&7 传送到指定的家。", 113 | "&8-&7&o 若不填写具体的名称则返回首个设置的家,", 114 | "&8-&7&o 若存在名为“home”的家则优先返回“home”。", 115 | "&8#&f home set &d[家名]", 116 | "&8-&7 设定一个家的位置。", 117 | "&8-&7&o 若不填写家的名称则默认为“home”", 118 | "&8#&f home delete &d[家名]", 119 | "&8-&7 删除一个家的位置。", 120 | "&8#&f home rename &d<原家名> &d<新家名>", 121 | "&8-&7 重命名一个家传送点的名称。" 122 | ).build(); 123 | 124 | } 125 | 126 | public static class RELOAD extends ConfigurationRoot { 127 | 128 | public static final ConfiguredMessageList START = list().defaults( 129 | "&f正在重载配置文件..." 130 | ).build(); 131 | 132 | public static final ConfiguredMessageList ERROR = list().defaults( 133 | "&f配置文件&c重载失败!&f详细原因详见后台输出。" 134 | ).build(); 135 | 136 | public static final ConfiguredMessageList COMPLETE = list().defaults( 137 | "&f配置文件重载完成,共耗时 &d%(time)&fms 。" 138 | ).params("time").build(); 139 | 140 | } 141 | 142 | public static class BACK extends ConfigurationRoot { 143 | 144 | public static final ConfiguredMessageList NO_LAST_LOCATION = list().defaults( 145 | "&f您当前没有进行任何传送,无法返回上个地点。" 146 | ).build(); 147 | 148 | public static final ConfiguredMessageList DEATH_MESSAGE = list().defaults( 149 | "&f您可以输入 &5/back &f或 [&d&l点击这里](show_text=点击返回到死亡地点 run_command=/moeteleport back) &f返回您的死亡地点。" 150 | ).build(); 151 | 152 | } 153 | 154 | public static class TELEPORT extends ConfigurationRoot { 155 | public static final ConfiguredMessageList TELEPORTED = list().defaults( 156 | "&f正在将您传送到 &d%(target) &f..." 157 | ).params("target").build(); 158 | 159 | public static final ConfiguredMessageList NOT_SAFE = list().defaults( 160 | "&f目标地点 &d%(location) &f可能并不安全,因此传送被暂缓执行。", 161 | "&7如您确认传送到目标位置,请再次输入接受指令以执行本次传送。" 162 | ).params("location").build(); 163 | 164 | public static final ConfiguredMessageList NOT_AVAILABLE = list().defaults( 165 | "&f目标地点丢失,暂时无法前往,传送被取消。" 166 | ).build(); 167 | 168 | public static final ConfiguredMessageList INTERRUPTED = list().defaults( 169 | "&c&l传送中断!&f传送过程中请不要移动。" 170 | ).build(); 171 | 172 | } 173 | 174 | public static class REQUESTS extends ConfigurationRoot { 175 | 176 | public static final ConfiguredMessageList SELF = list().defaults("&f您不能向自己发送请求。").build(); 177 | 178 | public static final ConfiguredMessageList OFFLINE = list().defaults( 179 | "&d%(player) &f离线,相关请求已自动取消。" 180 | ).params("player").build(); 181 | 182 | public static final ConfiguredMessageList MULTI = list().defaults( 183 | "&f您当前有&d%(num)条请求&f待处理,请输入 &5/%(command) <玩家名> &f决定回应谁的请求。", 184 | "&f您也可以再次输入 &5/%(command) &f快速回应最近的一条请求。" 185 | ).params("num", "command").build(); 186 | 187 | public static final ConfiguredMessageList EMPTY_REQUESTS = list() 188 | .defaults("&f您当前没有任何待处理的传送请求。") 189 | .build(); 190 | 191 | public static final ConfiguredMessageList NO_REQUEST_FROM = list().defaults( 192 | "&f您当前没有收到来自 &d%(player) &f的传送请求。" 193 | ).params("player").build(); 194 | 195 | public static final ConfiguredMessageList SENT = list().defaults( 196 | "&f成功向玩家 &d%(player) &f发送传送请求,对方有 &5%(expire)秒 &f的时间回应该请求。" 197 | ).params("player", "expire").build(); 198 | 199 | public static final ConfiguredMessageList DUPLICATE = list().defaults( 200 | "&f您已经向 &d%(player) &f发送过传送请求,对方仍有 &5%(expire)秒 &f的时间回应该请求。", 201 | "&f如您想要取消该请求,请输入 [&e&l[点击取消]](show_text=点击同意请求 run_command=/moeteleport teleport cancel %(player)) &f或输入 &5/tpCancel &f取消该请求。" 202 | ).params("player", "expire").build(); 203 | 204 | public static final ConfiguredMessageList RECEIVED_TP_HERE = list().defaults( 205 | "&d%(player) &f请求传送到您身边,您有 &5%(expire)秒 &f的时间回应。", 206 | " [&a&l[点击同意]](show_text=点击同意请求 run_command=/moeteleport teleport accept %(player)) &f或输入 &5/tpAccept &f同意该请求。", 207 | " [&c&l[点击拒绝]](show_text=点击拒绝请求 run_command=/moeteleport teleport deny %(player)) &f或输入 &5/tpDeny &f拒绝该请求。" 208 | ).params("player", "expire").build(); 209 | 210 | public static final ConfiguredMessageList RECEIVED_TP_TO = list().defaults( 211 | "&d%(player) &f请求传送您到Ta身边,您有 &5%(expire)秒 &f的时间回应。", 212 | " [&a&l[点击同意]](show_text=点击同意请求 run_command=/moeteleport teleport accept %(player)) &f或输入 &5/tpAccept &f同意该请求。", 213 | " [&c&l[点击拒绝]](show_text=点击拒绝请求 run_command=/moeteleport teleport deny %(player)) &f或输入 &5/tpDeny &f拒绝该请求。" 214 | ).params("player", "expire").build(); 215 | 216 | 217 | public static final ConfiguredMessageList ACCEPTED = list().defaults( 218 | "&f您同意了 &d%(player) &f的传送请求。" 219 | ).params("player").build(); 220 | 221 | public static final ConfiguredMessageList DENIED = list().defaults( 222 | "&f您&d拒绝&f了 &d%(player) &f的传送请求。" 223 | ).params("player").build(); 224 | 225 | public static final ConfiguredMessageList WAS_ACCEPTED = list().defaults( 226 | "&d%(player) &f同意了您的传送请求。" 227 | ).params("player").build(); 228 | 229 | public static final ConfiguredMessageList WAS_DENIED = list().defaults( 230 | "&d%(player) &f拒绝了您的传送请求。" 231 | ).params("player").build(); 232 | 233 | public static final ConfiguredMessageList SENT_TIMEOUT = list().defaults( 234 | "&f发往 &d%(player) &f的传送请求已超时。" 235 | ).params("player").build(); 236 | 237 | public static final ConfiguredMessageList RECEIVED_TIMEOUT = list().defaults( 238 | "&f来自 &d%(player) &f的传送请求已超时。" 239 | ).params("player").build(); 240 | 241 | public static final ConfiguredMessageList SENT_CANCELLED = list().defaults( 242 | "&f发往 &d%(player) &f的传送请求已取消。" 243 | ).params("player").build(); 244 | 245 | public static final ConfiguredMessageList RECEIVED_CANCELLED = list().defaults( 246 | "&f来自 &d%(player) &f的传送请求已被取消。" 247 | ).params("player").build(); 248 | 249 | } 250 | 251 | 252 | public static class HOME extends ConfigurationRoot { 253 | 254 | public static final ConfiguredMessageList EMPTY = list().defaults( 255 | "&f您还没有设置任何家的位置,快设置一个吧!" 256 | ).build(); 257 | 258 | public static final ConfiguredMessageList NAME_TOO_LONG = list() 259 | .defaults("&f您所输入的家的名字太长,家的名称不应当超过 &d32 &f个字符。") 260 | .build(); 261 | 262 | public static final ConfiguredMessageList OVER_LIMIT = list().defaults( 263 | "&f您最多只能设置 &d%(max) &f个家传送点!", 264 | "&7可以输入 &5/delHome <家名称> &7删除之前的家传送点,", 265 | "&7或输入 &5/setHome <家名称> &7覆盖之前的家传送点。" 266 | ).params("max").build(); 267 | 268 | public static final ConfiguredMessageList ALREADY_EXITS = list() 269 | .defaults("&f您已存在名为 &d%(name) &f的家传送点,换个名字叭~") 270 | .params("name") 271 | .build(); 272 | 273 | public static final ConfiguredMessageList NOT_FOUND = list() 274 | .defaults("&f您还没有设置这个家,请先输入 &5/setHome <家名称> &f设置一个吧!") 275 | .build(); 276 | 277 | public static final ConfiguredMessageList SET = list().defaults( 278 | "&f成功设定名为 &d%(name) &f的家传送点。" 279 | ).params("name").build(); 280 | 281 | public static final ConfiguredMessageList OVERRIDE = list().defaults( 282 | "&f成功覆盖名为 &d%(name) &f的家传送点。", 283 | "&8原先位置为 &5%(location) &8。" 284 | ).params("name", "location").build(); 285 | 286 | public static final ConfiguredMessageList REMOVED = list().defaults( 287 | "&f成功移除名为 &d%(name) &f的家传送点。", 288 | "&8原先位置为 &5%(location) &8。" 289 | ).params("name", "location").build(); 290 | 291 | public static final ConfiguredMessageList RENAMED = list().defaults( 292 | "&f成功以 &d%(newName) 重命名原先的家传送点 &d&o%(oldName) &f。" 293 | ).params("newName", "oldName").build(); 294 | 295 | public static class LIST extends ConfigurationRoot { 296 | 297 | public static final ConfiguredMessageList HEADER = list().defaults( 298 | "&f您当前设定的所有家:" 299 | ).build(); 300 | 301 | public static final ConfiguredMessageList OBJECT = list().defaults( 302 | "&8# &f%(id) &d%(location) [&7✈](show_text=点击返回家 %(id) run_command=/moeteleport home to %(id))" 303 | ).params("id", "location").build(); 304 | 305 | } 306 | 307 | } 308 | 309 | public static class WARP extends ConfigurationRoot { 310 | 311 | public static final ConfiguredMessageList EMPTY = list().defaults( 312 | "&f当前服务器暂无任何地标点,快设置一个吧!" 313 | ).build(); 314 | 315 | public static final ConfiguredMessageList NOT_OWNER = list().defaults( 316 | "&f您不是地标 &d%(name) &f的创建者,无法进行此操作。" 317 | ).params("name").build(); 318 | 319 | public static final ConfiguredMessageList NOT_FOUND = list() 320 | .defaults("&f目前暂不存在ID为 %(id) 的地标点。") 321 | .params("id") 322 | .build(); 323 | 324 | public static final ConfiguredMessageList NAME_TOO_LONG = list() 325 | .defaults("&f您所输入的家的名字太长,地标的名称不应当超过 &d16 &f个字符。") 326 | .build(); 327 | 328 | public static final ConfiguredMessageList OVER_LIMIT = list().defaults( 329 | "&f您最多只能设置 &d%(max) &f个地标传送点!", 330 | "&7可以输入 &5/delWarp <地标名称> &7删除之前的地标传送点,", 331 | "&7或输入 &5/setWarp <地标名称> &7覆盖之前的地标传送点。" 332 | ).params("max").build(); 333 | 334 | public static final ConfiguredMessageList INFO_LOCATION = list().defaults( 335 | "&f地标点 &d%(name) &f所在位置为 &5%(location) &f。[&7✈](show_text=点击前往&d %(name) run_command=/moeteleport warp to %(name))" 336 | ).params("name", "location").build(); 337 | 338 | public static final ConfiguredMessageList INFO_FULL = list().defaults( 339 | "&f地标点 &d%(name) &f由 &5%(owner) &f创建,所在位置为 &d%(location) &f。[&7✈](show_text=点击前往&d %(name) run_command=/moeteleport warp to %(name))" 340 | ).params("name", "owner", "location").build(); 341 | 342 | public static final ConfiguredMessageList SET = list().defaults( 343 | "&f成功设定名为 &d%(name) &f的地标传送点。" 344 | ).params("name").build(); 345 | 346 | public static final ConfiguredMessageList OVERRIDE = list().defaults( 347 | "&f成功覆盖名为 &d%(name) &f的地标传送点。", 348 | "&8原先位置为 &5%(location) &8。" 349 | ).params("name", "location").build(); 350 | 351 | public static final ConfiguredMessageList REMOVED = list().defaults( 352 | "&f成功移除名为 &d%(name) &f的地标传送点。", 353 | "&8原先位置为 &5%(location) &8。" 354 | ).params("name", "location").build(); 355 | 356 | public static final ConfiguredMessageList ALREADY_EXITS = list() 357 | .defaults("&f已存在名为 &d%(name) &f的地标点,换个名字叭~") 358 | .params("name") 359 | .build(); 360 | 361 | public static final ConfiguredMessageList RENAMED = list().defaults( 362 | "&f成功以 &d%(newName) 重命名原先的地标点 &d&o%(oldName) &f。" 363 | ).params("newName", "oldName").build(); 364 | 365 | public static class LIST extends ConfigurationRoot { 366 | 367 | public static final ConfiguredMessageList HEADER = list().defaults( 368 | "&f当前地标列表 &7(第&f%(current)&8/%(max)&7页):" 369 | ).params("current", "max").build(); 370 | 371 | public static final ConfiguredMessageList OBJECT = list().defaults( 372 | "&8# &f%(id) &7[由%(owner)创建]", 373 | "&8- &d%(location) [&7✈](show_text=点击前往&d %(id) run_command=/moeteleport warp to %(id))" 374 | ).params("id", "owner", "location").build(); 375 | 376 | public static final ConfiguredMessageList OBJECT_NO_OWNER = list().defaults( 377 | "&8# &f%(id)", 378 | "&8- &d%(location) [&7✈](show_text=点击前往&d %(id) run_command=/moeteleport warp to %(id))" 379 | ).params("id", "location").build(); 380 | 381 | } 382 | 383 | } 384 | 385 | 386 | } 387 | --------------------------------------------------------------------------------