commit 9e1a8f0298b01276cf4ac19ec3e27822e7a90aa0
Author: YuTian <2953516620@qq.com>
Date: Sat Aug 10 11:36:54 2024 +0800
1.0
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fdb2b18
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,115 @@
+# User-specific stuff
+.idea/
+
+*.iml
+*.ipr
+*.iws
+
+# IntelliJ
+out/
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+target/
+
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+.flattened-pom.xml
+
+# Common working directory
+run/
+/src1.7z
+/src.7z
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..4432167
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,74 @@
+
+
+ 4.0.0
+
+ TheWarDungeonPlus
+ TheWarDungeonPlus
+ 1.0-SNAPSHOT
+ jar
+
+ TheWarDungeonPlus
+
+
+ 1.8
+ UTF-8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 16
+ 16
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
+
+ package
+
+ shade
+
+
+ false
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ papermc-repo
+ https://repo.papermc.io/repository/maven-public/
+
+
+ sonatype
+ https://oss.sonatype.org/content/groups/public/
+
+
+
+
+
+ io.papermc.paper
+ paper-api
+ 1.18.2-R0.1-SNAPSHOT
+ provided
+
+
+
diff --git a/src/main/java/com/io/yutian/thewardungeon/TheWarDungeon.java b/src/main/java/com/io/yutian/thewardungeon/TheWarDungeon.java
new file mode 100644
index 0000000..45c1ce8
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/TheWarDungeon.java
@@ -0,0 +1,89 @@
+package com.io.yutian.thewardungeon;
+
+import com.io.yutian.thewardungeon.command.DungeonCommand;
+import com.io.yutian.thewardungeon.config.CommonConfig;
+import com.io.yutian.thewardungeon.dungeon.Dungeon;
+import com.io.yutian.thewardungeon.dungeon.DungeonInstance;
+import com.io.yutian.thewardungeon.hook.PluginHook;
+import com.io.yutian.thewardungeon.lang.Lang;
+import com.io.yutian.thewardungeon.listener.DungeonListener;
+import com.io.yutian.thewardungeon.listener.ObjectiveListener;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewardungeon.manager.MapManager;
+import com.io.yutian.thewardungeon.manager.RegistryManager;
+import com.io.yutian.thewardungeon.papi.DungeonPAPI;
+import com.io.yutian.thewarskyblocklib.gui.GuiListener;
+import com.io.yutian.thewarskyblocklib.manager.CommandManager;
+import com.io.yutian.thewarskyblocklib.util.FileUtil;
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.io.File;
+
+public final class TheWarDungeon extends JavaPlugin {
+
+ private static final String PERSION = "1.0beta";
+
+ private static TheWarDungeon instance;
+
+ @Override
+ public void onEnable() {
+ instance = this;
+
+ PluginHook.hook();
+ RegistryManager.init();
+ CommonConfig.init();
+ DungeonCommand.init();
+ Lang.reload();
+ MapManager.load();
+ DungeonManager.load();
+
+ registerListener();
+
+ checkWorldFile();
+
+ new DungeonPAPI().register();
+
+ }
+
+ @Override
+ public void onDisable() {
+
+ CommandManager.unregisterAll();
+
+ /*
+ for (Dungeon dungeon : DungeonManager.getDungeons()) {
+ for (DungeonInstance dungeonInstance : dungeon.getQueue().getAllDungeonInstance()) {
+ dungeonInstance.getWorldInstance().remove();
+ }
+ }
+ */
+
+ checkWorldFile();
+
+ }
+
+ private void checkWorldFile() {
+ File path = new File(System.getProperty("user.dir"));
+ for (File file : path.listFiles()) {
+ if (file.isDirectory() && file.getName().startsWith("dw_")) {
+ File file1 = new File(file+File.separator+"dungeonworld.token");
+ if (file1.exists()) {
+ FileUtil.removeDir(file);
+ }
+ }
+ }
+ }
+
+ private void registerListener() {
+ Bukkit.getPluginManager().registerEvents(new DungeonListener(), this);
+ Bukkit.getPluginManager().registerEvents(new ObjectiveListener(), this);
+ Bukkit.getPluginManager().registerEvents(new GuiListener(), this);
+ }
+
+ public static TheWarDungeon inst() {
+ return instance;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/DungeonCommand.java b/src/main/java/com/io/yutian/thewardungeon/command/DungeonCommand.java
new file mode 100644
index 0000000..f01e2a6
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/DungeonCommand.java
@@ -0,0 +1,27 @@
+package com.io.yutian.thewardungeon.command;
+
+import com.io.yutian.thewardungeon.TheWarDungeon;
+import com.io.yutian.thewardungeon.command.list.*;
+import com.io.yutian.thewarskyblocklib.command.Command;
+import com.io.yutian.thewarskyblocklib.command.list.CommandHelp;
+import com.io.yutian.thewarskyblocklib.manager.CommandManager;
+
+public class DungeonCommand {
+
+ private static Command command;
+
+ public static void init() {
+ command = Command.of(TheWarDungeon.inst(), "thewardungeon");
+ command.addAlias("dungeon");
+ command.register(new CommandHelp(command, "TheWarDungeon"),
+ new CommandCreate(),
+ new CommandStart(),
+ new CommandLeave(),
+ new CommandGui(),
+ new CommandState(),
+ new CommandDungeonEvent(),
+ new CommandReload());
+ CommandManager.register(command);
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/list/CommandCreate.java b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandCreate.java
new file mode 100644
index 0000000..5092e8d
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandCreate.java
@@ -0,0 +1,65 @@
+package com.io.yutian.thewardungeon.command.list;
+
+import com.io.yutian.thewardungeon.TheWarDungeon;
+import com.io.yutian.thewardungeon.dungeon.Dungeon;
+import com.io.yutian.thewardungeon.dungeon.config.DungeonConfig;
+import com.io.yutian.thewardungeon.lang.Lang;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewarskyblocklib.command.CommandContext;
+import com.io.yutian.thewarskyblocklib.command.ICommand;
+import com.io.yutian.thewarskyblocklib.command.argument.Argument;
+import com.io.yutian.thewarskyblocklib.command.argument.ArgumentTypes;
+import com.io.yutian.thewarskyblocklib.util.FileUtil;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+
+import java.io.File;
+
+public class CommandCreate extends ICommand {
+
+ public CommandCreate() {
+ super("create");
+ addArgument(Argument.argument("id", ArgumentTypes.STRING));
+ addArgument(Argument.argument("world", ArgumentTypes.STRING));
+ }
+
+ @Override
+ public void executes(CommandContext commandContext) {
+ CommandSender sender = commandContext.getSender();
+ String id = commandContext.getArgumentsValue("id").getString();
+ String worldName = commandContext.getArgumentsValue("world").getString();
+ if (DungeonManager.getDungeon(id) != null) {
+ sender.sendMessage(Component.text(Lang.prefix+"§c副本 "+id+" 已存在"));
+ return;
+ }
+ File folder = new File(DungeonManager.MAIN_FOLDER, id);
+ File worldFolder = new File(TheWarDungeon.inst().getDataFolder()+File.separator+"maps"+File.separator+worldName);
+ boolean copy = !worldFolder.exists();
+ World world = Bukkit.getWorld(worldName);
+ if (world != null) {
+ if (world.getPlayerCount() > 0) {
+ sender.sendMessage(Component.text(Lang.prefix+"§c世界"+worldName+"已加载且世界内有玩家,请先卸载世界"));
+ return;
+ }
+ sender.sendMessage(Component.text(Lang.prefix+"§c世界"+worldName+"已加载,请先卸载世界"));
+ return;
+ }
+ sender.sendMessage(Component.text(Lang.prefix+"§e正在创建副本..."));
+ if (copy) {
+ worldFolder.mkdirs();
+ File importMapFolder = new File(worldName);
+ FileUtil.copyDir(importMapFolder, worldFolder, "advancements", "DIM1", "DIM-1", "data", "datapacks", "playerdata", "stats", "paper-world.yml", "uid.dat", "icon.png", "serverconfig");
+ }
+ if (folder.exists()) {
+ folder.mkdirs();
+ }
+ DungeonConfig dungeonConfig = new DungeonConfig(worldName, folder);
+ dungeonConfig.initConfig();
+ Dungeon dungeon = new Dungeon(id, dungeonConfig);
+ DungeonManager.registerDungeon(id, dungeon);
+ sender.sendMessage(Component.text(Lang.prefix+"§a成功创建副本 §b"+id));
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/list/CommandDungeonEvent.java b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandDungeonEvent.java
new file mode 100644
index 0000000..1a21dff
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandDungeonEvent.java
@@ -0,0 +1,52 @@
+package com.io.yutian.thewardungeon.command.list;
+
+import com.io.yutian.thewardungeon.dungeon.DungeonInstance;
+import com.io.yutian.thewardungeon.dungeon.player.DungeonPlayer;
+import com.io.yutian.thewardungeon.dungeon.player.PlayerState;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewarskyblocklib.command.CommandContext;
+import com.io.yutian.thewarskyblocklib.command.ICommand;
+import com.io.yutian.thewarskyblocklib.command.argument.Argument;
+import com.io.yutian.thewarskyblocklib.command.argument.ArgumentTypes;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.UUID;
+
+public class CommandDungeonEvent extends ICommand {
+
+ public CommandDungeonEvent() {
+ super("dungeonevent");
+ addArgument(Argument.argument("uuid", ArgumentTypes.UUID));
+ addArgument(Argument.argument("event", ArgumentTypes.STRING));
+ }
+
+ @Override
+ public void executes(CommandContext commandContext) {
+ Player player = (Player) commandContext.getSender();
+ UUID uuid = commandContext.getArgumentsValue("uuid").getUUID();
+ String event = commandContext.getArgumentsValue("event").getString();
+ if (!uuid.equals(player.getUniqueId())) {
+ return;
+ }
+ if (event.equalsIgnoreCase("respawn")) {
+ DungeonInstance dungeonInstance = DungeonManager.getDungeonInstance(player);
+ DungeonPlayer dungeonPlayer = dungeonInstance.getPlayer(player);
+ if (dungeonPlayer == null || !dungeonPlayer.getState().equals(PlayerState.DEAD)) {
+ return;
+ }
+ dungeonInstance.respawn(dungeonPlayer);
+ }
+ }
+
+ @Override
+ public boolean hide() {
+ return true;
+ }
+
+ @Override
+ public boolean hasPermission(CommandSender sender) {
+ return sender instanceof Player;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/list/CommandGui.java b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandGui.java
new file mode 100644
index 0000000..62b7def
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandGui.java
@@ -0,0 +1,62 @@
+package com.io.yutian.thewardungeon.command.list;
+
+import com.io.yutian.thewardungeon.dungeon.Dungeon;
+import com.io.yutian.thewardungeon.gui.DungeonRoomGui;
+import com.io.yutian.thewardungeon.lang.Lang;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewarskyblocklib.command.CommandContext;
+import com.io.yutian.thewarskyblocklib.command.ICommand;
+import com.io.yutian.thewarskyblocklib.command.argument.Argument;
+import com.io.yutian.thewarskyblocklib.command.argument.ArgumentTypes;
+import com.io.yutian.thewarskyblocklib.command.argument.Suggests;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.entity.Player;
+
+public class CommandGui extends ICommand {
+
+ public CommandGui() {
+ super("gui");
+ addArgument(Argument.argument("id", ArgumentTypes.STRING).suggest(Suggests.DUNGEON_LIST));
+ addArgument(Argument.argument("player", ArgumentTypes.STRING).suggest(Suggests.PLAYER_LIST).optional(null));
+ }
+
+ @Override
+ public void executes(CommandContext commandContext) {
+ CommandSender sender = commandContext.getSender();
+ String id = commandContext.getArgumentsValue("id").getString();
+ String playerName = commandContext.getArgumentsValue("player").getString();
+ Dungeon dungeon = DungeonManager.getDungeon(id);
+ if (dungeon == null) {
+ sender.sendMessage(Component.text(Lang.prefix+"§c副本 "+id+" 不存在"));
+ return;
+ }
+ if (playerName == null && sender instanceof ConsoleCommandSender) {
+ sender.sendMessage(Lang.prefix+"§c请输入玩家ID");
+ return;
+ }
+ Player player = null;
+ if (sender instanceof Player) {
+ player = (Player) sender;
+ } else if (sender instanceof ConsoleCommandSender) {
+ Player player1 = Bukkit.getPlayer(playerName);
+ player = player1;
+ }
+ if (player == null || !player.isOnline()) {
+ sender.sendMessage(Lang.prefix+Lang.get("command-player-noonline"));
+ return;
+ }
+ if (DungeonManager.getDungeonInstance(player) != null) {
+ if (player.equals(sender)) {
+ sender.sendMessage(Lang.prefix+"§f你已在副本中");
+ } else {
+ sender.sendMessage(Lang.prefix+"§f该玩家已在副本中");
+ }
+ return;
+ }
+ new DungeonRoomGui(player, dungeon).open();
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/list/CommandLeave.java b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandLeave.java
new file mode 100644
index 0000000..483511c
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandLeave.java
@@ -0,0 +1,37 @@
+package com.io.yutian.thewardungeon.command.list;
+
+import com.io.yutian.thewardungeon.dungeon.DungeonInstance;
+import com.io.yutian.thewardungeon.lang.Lang;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewarskyblocklib.command.CommandContext;
+import com.io.yutian.thewarskyblocklib.command.ICommand;
+import net.kyori.adventure.text.Component;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class CommandLeave extends ICommand {
+
+ public CommandLeave() {
+ super("leave");
+ }
+
+ @Override
+ public void executes(CommandContext commandContext) {
+ Player player = (Player) commandContext.getSender();
+ DungeonInstance dungeonInstance = DungeonManager.getDungeonInstance(player);
+ if (dungeonInstance == null) {
+ player.sendMessage(Component.text(Lang.get("dungeon.level.no-in-dungeon")));
+ return;
+ }
+ dungeonInstance.leave(player);
+ player.sendMessage(Component.text(Lang.prefix+Lang.get("dungeon.level.message")));
+
+
+ }
+
+ @Override
+ public boolean hasPermission(CommandSender sender) {
+ return sender instanceof Player;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/list/CommandReload.java b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandReload.java
new file mode 100644
index 0000000..74afcb3
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandReload.java
@@ -0,0 +1,45 @@
+package com.io.yutian.thewardungeon.command.list;
+
+import com.io.yutian.thewardungeon.dungeon.Dungeon;
+import com.io.yutian.thewardungeon.dungeon.DungeonInstance;
+import com.io.yutian.thewardungeon.lang.Lang;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewardungeon.manager.MapManager;
+import com.io.yutian.thewarskyblocklib.command.CommandContext;
+import com.io.yutian.thewarskyblocklib.command.ICommand;
+import org.bukkit.command.CommandSender;
+
+public class CommandReload extends ICommand {
+
+ public CommandReload() {
+ super("reload");
+ }
+
+ @Override
+ public void executes(CommandContext commandContext) {
+ CommandSender commandSender = commandContext.getSender();
+ for (Dungeon dungeon : DungeonManager.getDungeons()) {
+ for (DungeonInstance dungeonInstance : dungeon.getQueue().getAllDungeonInstance()) {
+ dungeonInstance.stop();
+ }
+ }
+ Lang.reload();
+ MapManager.load();
+ DungeonManager.load();
+ commandSender.sendMessage(Lang.prefix+"§a重载成功");
+ }
+
+ @Override
+ public boolean emptyExecutes(CommandSender commandSender) {
+ for (Dungeon dungeon : DungeonManager.getDungeons()) {
+ for (DungeonInstance dungeonInstance : dungeon.getQueue().getAllDungeonInstance()) {
+ dungeonInstance.stop();
+ }
+ }
+ Lang.reload();
+ DungeonManager.load();
+ commandSender.sendMessage(Lang.prefix+"§a重载成功");
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/list/CommandStart.java b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandStart.java
new file mode 100644
index 0000000..4725f58
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandStart.java
@@ -0,0 +1,103 @@
+package com.io.yutian.thewardungeon.command.list;
+
+import com.io.yutian.thewardungeon.dungeon.Dungeon;
+import com.io.yutian.thewardungeon.dungeon.DungeonInstance;
+import com.io.yutian.thewardungeon.lang.Lang;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewarskyblocklib.command.CommandContext;
+import com.io.yutian.thewarskyblocklib.command.ICommand;
+import com.io.yutian.thewarskyblocklib.command.argument.Argument;
+import com.io.yutian.thewarskyblocklib.command.argument.ArgumentTypes;
+import com.io.yutian.thewarskyblocklib.command.argument.Suggests;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.Arrays;
+
+public class CommandStart extends ICommand {
+
+ public CommandStart() {
+ super("start");
+ addArgument(Argument.argument("id", ArgumentTypes.STRING).suggest(Suggests.DUNGEON_LIST));
+ addArgument(Argument.argument("mode", ArgumentTypes.STRING).suggest(()-> Arrays.asList("start", "match", "room")));
+ addArgument(Argument.argument("player", ArgumentTypes.STRING).suggest(Suggests.PLAYER_LIST).optional(null));
+ }
+
+ @Override
+ public void executes(CommandContext commandContext) {
+ CommandSender sender = commandContext.getSender();
+ String id = commandContext.getArgumentsValue("id").getString();
+ String mode = commandContext.getArgumentsValue("mode").getString();
+ String playerName = commandContext.getArgumentsValue("player").getString();
+ Dungeon dungeon = DungeonManager.getDungeon(id);
+ if (dungeon == null) {
+ sender.sendMessage(Component.text(Lang.prefix+"§c副本 "+id+" 不存在"));
+ return;
+ }
+ if (playerName == null && sender instanceof ConsoleCommandSender) {
+ sender.sendMessage(Lang.prefix+"§c请输入玩家ID");
+ return;
+ }
+ Player player = null;
+ if (sender instanceof Player) {
+ player = (Player) sender;
+ } else if (sender instanceof ConsoleCommandSender) {
+ Player player1 = Bukkit.getPlayer(playerName);
+ player = player1;
+ }
+ if (player == null || !player.isOnline()) {
+ sender.sendMessage(Lang.prefix+Lang.get("command-player-noonline"));
+ return;
+ }
+ if (DungeonManager.getDungeonInstance(player) != null) {
+ if (player.equals(sender)) {
+ player.sendMessage(Lang.prefix+"§f你已在副本中");
+ } else {
+ sender.sendMessage(Lang.prefix+"§f该玩家已在副本中");
+ }
+ return;
+ }
+ mode = mode.toLowerCase();
+ if (mode.equalsIgnoreCase("start")) {
+ if (!dungeon.getConfig().getConditionGroup().isValid(player) && !player.isOp()) {
+ return;
+ }
+ if (dungeon.getConfig().getOption().getMin() != 1) {
+ player.sendMessage(Lang.prefix+"§c该副本无法单独开始");
+ return;
+ }
+ if (!dungeon.hasFreeInstance()) {
+ player.sendMessage(Lang.prefix+"§c当前队列已满,请稍等");
+ return;
+ }
+ DungeonInstance instance = dungeon.newInstance();
+ instance.join(player, true);
+ } else if (mode.equalsIgnoreCase("match")) {
+ if (!dungeon.getConfig().getConditionGroup().isValid(player)) {
+ return;
+ }
+ DungeonInstance dungeonInstance = dungeon.getQueue().findFreeDungeonInstance();
+ if (dungeonInstance == null) {
+ player.sendMessage(Lang.prefix+"§c未找到空闲房间");
+ return;
+ }
+ dungeonInstance.join(player, false);
+ } else if (mode.equalsIgnoreCase("room")) {
+ if (!dungeon.getConfig().getConditionGroup().isValid(player)) {
+ return;
+ }
+ if (!dungeon.hasFreeInstance()) {
+ player.sendMessage(Lang.prefix+"§c当前队列已满,请稍等");
+ return;
+ }
+ DungeonInstance instance = dungeon.newInstance();
+ instance.join(player, false);
+ } else {
+ sender.sendMessage(Lang.prefix+"§c未知的模式");
+ }
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/list/CommandState.java b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandState.java
new file mode 100644
index 0000000..2a74c1f
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandState.java
@@ -0,0 +1,39 @@
+package com.io.yutian.thewardungeon.command.list;
+
+import com.io.yutian.thewardungeon.dungeon.Dungeon;
+import com.io.yutian.thewardungeon.lang.Lang;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewarskyblocklib.command.CommandContext;
+import com.io.yutian.thewarskyblocklib.command.ICommand;
+import com.io.yutian.thewarskyblocklib.command.argument.Argument;
+import com.io.yutian.thewarskyblocklib.command.argument.ArgumentTypes;
+import com.io.yutian.thewarskyblocklib.command.argument.Suggests;
+import net.kyori.adventure.text.Component;
+import org.bukkit.command.CommandSender;
+
+import java.io.File;
+
+public class CommandState extends ICommand {
+
+ public CommandState() {
+ super("state");
+ addArgument(Argument.argument("id", ArgumentTypes.STRING).suggest(Suggests.DUNGEON_LIST));
+ }
+
+ @Override
+ public void executes(CommandContext commandContext) {
+ CommandSender sender = commandContext.getSender();
+ String id = commandContext.getArgumentsValue("id").getString();
+ Dungeon dungeon = DungeonManager.getDungeon(id);
+ if (dungeon == null) {
+ sender.sendMessage(Component.text(Lang.prefix+"§c副本 "+id+" 不存在"));
+ return;
+ }
+ sender.sendMessage(Component.text("§7---------- §8[§9"+id+"§8]§7----------"));
+ sender.sendMessage(Component.text("§aId: §f"+id));
+ sender.sendMessage(Component.text("§a文件目录: §f"+"plugins"+File.separator+"TheWarDungeon"+File.separator+"dungeons"+File.separator+id));
+ sender.sendMessage(Component.text("§a实例数量: §f"+dungeon.getQueue().size()));
+ sender.sendMessage(Component.text("§a空闲房间数量: §f"+dungeon.getQueue().getAllFreeDungeonInstance().size()));
+ sender.sendMessage(Component.text("§7---------- §8[§9"+id+"§8]§7----------"));
+ }
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/command/list/CommandTest.java b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandTest.java
new file mode 100644
index 0000000..438bf39
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/command/list/CommandTest.java
@@ -0,0 +1,43 @@
+package com.io.yutian.thewardungeon.command.list;
+
+import com.io.yutian.thewardungeon.TheWarDungeon;
+import com.io.yutian.thewardungeon.dungeon.Dungeon;
+import com.io.yutian.thewardungeon.dungeon.DungeonInstance;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewarskyblocklib.command.CommandContext;
+import com.io.yutian.thewarskyblocklib.command.ICommand;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class CommandTest extends ICommand {
+
+ public CommandTest() {
+ super("test");
+ }
+
+ @Override
+ public void executes(CommandContext commandContext) {
+ Player player = (Player) commandContext.getSender();
+ new BukkitRunnable() {
+
+ private int i = 0;
+
+ @Override
+ public void run() {
+ i++;
+ if (i >= 5) {
+ cancel();
+ return;
+ }
+ Dungeon dungeon = DungeonManager.getDungeon("fb2");
+ DungeonInstance dungeonInstance = dungeon.newInstance();
+ dungeonInstance.join(player, true);
+ Bukkit.getScheduler().runTaskLater(TheWarDungeon.inst(), ()->{
+ dungeonInstance.stop();
+ }, 40L);
+ }
+ }.runTaskTimer(TheWarDungeon.inst(), 0L, 60L);
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/config/CommonConfig.java b/src/main/java/com/io/yutian/thewardungeon/config/CommonConfig.java
new file mode 100644
index 0000000..26f57e9
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/config/CommonConfig.java
@@ -0,0 +1,25 @@
+package com.io.yutian.thewardungeon.config;
+
+import com.io.yutian.thewardungeon.TheWarDungeon;
+import com.io.yutian.thewarskyblocklib.config.Config;
+import com.io.yutian.thewarskyblocklib.util.FileUtil;
+
+import java.io.File;
+
+public class CommonConfig {
+
+ private static Config config;
+
+ public static Config.StringListValue allowCommands;
+ public static Config.LocationValue safeLocation;
+
+ public static void init() {
+ FileUtil.saveResource(TheWarDungeon.inst(), "config.yml", false);
+ File file = FileUtil.getFile(TheWarDungeon.inst(), "config.yml");
+ config = new Config(file, CommonConfig.class);
+ config.define("allowCommands", "allowCommands", new Config.StringListValue());
+ config.define("safeLocation", "safeLocation", new Config.LocationValue());
+ config.load();
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/data/LineMetadata.java b/src/main/java/com/io/yutian/thewardungeon/data/LineMetadata.java
new file mode 100644
index 0000000..f843846
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/data/LineMetadata.java
@@ -0,0 +1,212 @@
+package com.io.yutian.thewardungeon.data;
+
+import com.io.yutian.thewardungeon.util.ClassUtil;
+import com.io.yutian.thewarskyblocklib.util.StringUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class LineMetadata {
+
+ private String source;
+ private Map metadata = new HashMap<>();
+
+ public LineMetadata(String source, Map metadata) {
+ this.source = source;
+ this.metadata = metadata;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public boolean contains(String key) {
+ return metadata.containsKey(key);
+ }
+
+ public String getString(String key) {
+ return getString(key, "");
+ }
+
+ public String getString(String key, String defaultValue) {
+ String s = key.toLowerCase();
+ return metadata.getOrDefault(s, defaultValue);
+ }
+
+ public int getInt(@NotNull String key) {
+ return getInt(key, 0);
+ }
+
+ public int getInt(@NotNull String key, @NotNull int defaultValue) {
+ String s = this.metadata.get(key.toLowerCase());
+ if (s == null) {
+ return defaultValue;
+ }
+ try {
+ return Integer.parseInt(s);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ public boolean getBoolean(@NotNull String key) {
+ return getBoolean(key, false);
+ }
+
+ public boolean getBoolean(@NotNull String key, @NotNull boolean defaultValue) {
+ String s = this.metadata.get(key.toLowerCase());
+ if (s == null) {
+ return defaultValue;
+ }
+ try {
+ return Boolean.parseBoolean(s);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ public double getDouble(@NotNull String key) {
+ return getDouble(key, 0.0D);
+ }
+
+ public double getDouble(@NotNull String key, @NotNull double defaultValue) {
+ String s = this.metadata.get(key.toLowerCase());
+ if (s == null) {
+ return defaultValue;
+ }
+ try {
+ return Double.parseDouble(s);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ public float getFloat(@NotNull String key) {
+ return getFloat(key, 0.0F);
+ }
+
+ public float getFloat(@NotNull String key, @NotNull float defaultValue) {
+ String s = this.metadata.get(key.toLowerCase());
+ if (s == null) {
+ return defaultValue;
+ }
+ try {
+ return Float.parseFloat(s);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ public long getLong(@NotNull String key) {
+ return getLong(key, 0L);
+ }
+
+ public long getLong(@NotNull String key, @NotNull long defaultValue) {
+ String s = this.metadata.get(key.toLowerCase());
+ if (s == null) {
+ return defaultValue;
+ }
+ try {
+ return Long.parseLong(s);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ public List getList(@NotNull String key, @NotNull Class clazz) {
+ return getList(key, clazz, new ArrayList<>());
+ }
+
+ public List getList(@NotNull String key, @NotNull Class clazz, @NotNull List defaultValue) {
+ String s = this.metadata.get(key.toLowerCase());
+ if (s == null) {
+ return defaultValue;
+ }
+ if (!s.startsWith("[") || !s.endsWith("]")) {
+ return defaultValue;
+ }
+ try {
+ String s1 = s.substring(1, s.length()-1);
+ List list = new ArrayList<>();
+ if (s1.contains(",")) {
+ if (s1.startsWith(",") || s1.endsWith(",")) {
+ return defaultValue;
+ }
+ String[] array = s1.split(",");
+ for (String arg : array) {
+ T obj = loadValue(arg, clazz);
+ if (obj != null) {
+ list.add(obj);
+ }
+ }
+ } else {
+ T obj = loadValue(s1, clazz);
+ if (obj != null) {
+ list.add(obj);
+ }
+ }
+ return list;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return defaultValue;
+ }
+ }
+
+ private static @Nullable T loadValue(String arg, Class clazz) {
+ Class> clazz1 = ClassUtil.PRIMITIVE_TO_WRAPPER.getOrDefault(clazz, clazz);
+ if (clazz1.equals(String.class)) {
+ if (arg.startsWith("\"") && arg.endsWith("\"")) {
+ String arg1 = arg.substring(1, arg.length()-1);
+ return (T) arg1;
+ }
+ return (T) arg;
+ } else if (clazz1.equals(Integer.class)) {
+ if (!StringUtil.isInt(arg)) {
+ return null;
+ } else {
+ return (T)(Integer)Integer.parseInt(arg);
+ }
+ } else if (clazz1.equals(Double.class)) {
+ if (!StringUtil.isDouble(arg)) {
+ return null;
+ } else {
+ return (T)(Double)Double.parseDouble(arg);
+ }
+ } else if (clazz1.equals(Float.class)) {
+ if (!StringUtil.isFloat(arg)) {
+ return null;
+ } else {
+ return (T)(Float)Float.parseFloat(arg);
+ }
+ } else if (clazz1.equals(Long.class)) {
+ if (!StringUtil.isLong(arg)) {
+ return null;
+ } else {
+ return (T)(Long)Long.parseLong(arg);
+ }
+ } else if (clazz1.equals(Byte.class)) {
+ if (!StringUtil.isByte(arg)) {
+ return null;
+ } else {
+ return (T)(Byte)Byte.parseByte(arg);
+ }
+ } else if (clazz1.equals(Boolean.class)) {
+ if (!StringUtil.isBoolean(arg)) {
+ return null;
+ } else {
+ return (T)(Boolean)Boolean.parseBoolean(arg);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "LineMetadata{" + source + "}";
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/Dungeon.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/Dungeon.java
new file mode 100644
index 0000000..c223785
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/Dungeon.java
@@ -0,0 +1,122 @@
+package com.io.yutian.thewardungeon.dungeon;
+
+import com.io.yutian.thewardungeon.TheWarDungeon;
+import com.io.yutian.thewardungeon.dungeon.config.DungeonConfig;
+import com.io.yutian.thewardungeon.dungeon.queue.DungeonQueue;
+import com.io.yutian.thewardungeon.dungeon.world.WorldInstance;
+import com.io.yutian.thewardungeon.util.Log;
+import com.io.yutian.thewarskyblocklib.util.FileUtil;
+import org.bukkit.World;
+import org.bukkit.WorldCreator;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+public class Dungeon {
+
+ private final String id;
+ private final DungeonConfig config;
+
+ private File mapFolder;
+
+ private final DungeonQueue queue;
+ private List worldInstances;
+
+ public Dungeon(String id, DungeonConfig config) {
+ this.id = id;
+ this.config = config;
+ this.config.read();
+ this.queue = new DungeonQueue(this, config.getOption().getMaxInstance());
+ this.worldInstances = new LinkedList<>();
+ this.mapFolder = new File(TheWarDungeon.inst().getDataFolder()+File.separator+"maps"+File.separator+config.getMap());
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public DungeonConfig getConfig() {
+ return config;
+ }
+
+ public File getMapFolder() {
+ return mapFolder;
+ }
+
+ public boolean hasFreeInstance() {
+ if (worldInstances.size() < config.getOption().getMaxInstance()) {
+ return true;
+ }
+ for (WorldInstance worldInstance : worldInstances) {
+ if (!worldInstance.isOccupied()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public WorldInstance getFreeInstance() {
+ for (WorldInstance worldInstance : worldInstances) {
+ if (!worldInstance.isOccupied()) {
+ return worldInstance;
+ }
+ }
+ if (worldInstances.size() >= config.getOption().getMaxInstance()) {
+ return null;
+ }
+ if (!mapFolder.exists()) {
+ Log.error("副本Map文件不存在"+ mapFolder);
+ return null;
+ }
+ UUID uuid = UUID.randomUUID();
+ String worldName = "dw_"+id + "_"+ uuid.toString().replace("_", "");
+ File folder = new File(worldName);
+ folder.mkdirs();
+ FileUtil.copyDir(mapFolder, folder);
+ File tFile = new File(folder+File.separator+"dungeonworld.token");
+ if (!tFile.exists()) {
+ try {
+ tFile.createNewFile();
+ } catch (Exception e) {
+ }
+ }
+ World world;
+ WorldCreator dungeonWorldCreator = new WorldCreator(worldName);
+ try {
+ world = dungeonWorldCreator.createWorld();
+ world.setKeepSpawnInMemory(false);
+ world.setAutoSave(false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ WorldInstance worldInstance = new WorldInstance(folder, world, uuid);
+ worldInstances.add(worldInstance);
+ return worldInstance;
+ }
+
+ @Nullable
+ public DungeonInstance newInstance() {
+ if (!hasFreeInstance()) {
+ return null;
+ }
+ WorldInstance worldInstance = getFreeInstance();
+ DungeonInstance dungeonInstance = new DungeonInstance(worldInstance.getUUID(), this, worldInstance);
+ worldInstance.setOccupied(true);
+ queue.add(dungeonInstance);
+ return dungeonInstance;
+ }
+
+ public DungeonQueue getQueue() {
+ return queue;
+ }
+
+ @Override
+ public String toString() {
+ return "Dungeon["+id+"]";
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonInstance.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonInstance.java
new file mode 100644
index 0000000..55116fb
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonInstance.java
@@ -0,0 +1,401 @@
+package com.io.yutian.thewardungeon.dungeon;
+
+import com.io.yutian.thewardungeon.TheWarDungeon;
+import com.io.yutian.thewardungeon.dungeon.objective.Objective;
+import com.io.yutian.thewardungeon.dungeon.objective.ObjectiveGourp;
+import com.io.yutian.thewardungeon.dungeon.objective.list.LocationObjective;
+import com.io.yutian.thewardungeon.dungeon.objective.list.RegionObjective;
+import com.io.yutian.thewardungeon.dungeon.objective.list.TimeObjective;
+import com.io.yutian.thewardungeon.dungeon.player.DungeonPlayer;
+import com.io.yutian.thewardungeon.dungeon.player.PlayerState;
+import com.io.yutian.thewardungeon.dungeon.world.WorldInstance;
+import com.io.yutian.thewardungeon.lang.Lang;
+import com.io.yutian.thewardungeon.manager.DungeonManager;
+import com.io.yutian.thewardungeon.script.ScriptGourp;
+import com.io.yutian.thewardungeon.util.LogUtil;
+import com.io.yutian.thewarskyblocklib.math.Point;
+import io.lumine.mythic.bukkit.BukkitAdapter;
+import io.lumine.mythic.bukkit.MythicBukkit;
+import io.lumine.mythic.core.mobs.ActiveMob;
+import io.lumine.mythic.core.mobs.MobRegistry;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scheduler.BukkitTask;
+
+import java.util.*;
+
+public class DungeonInstance {
+
+ protected final UUID uuid;
+ private final Dungeon dungeon;
+ private final WorldInstance worldInstance;
+
+ private int id;
+
+ private DungeonState state = DungeonState.WAITING;
+
+ private DungeonLobby dungeonLobby;
+
+ private Point spawnPoint;
+
+ private Map players = new HashMap<>();
+ private List objectiveGourps = new ArrayList<>();
+
+ private int time;
+
+ protected int countdown = -1;
+
+ private List activeMobs = new ArrayList<>();
+
+ private List tasks = new ArrayList<>();
+
+ private boolean loaded = false;
+ private boolean overdue = false;
+
+ public DungeonInstance(UUID uuid, Dungeon dungeon, WorldInstance worldInstance) {
+ this.uuid = uuid;
+ this.dungeon = dungeon;
+ this.worldInstance = worldInstance;
+ }
+
+ public void join(Player player, boolean start) {
+ if (!canJoin(player)) {
+ return;
+ }
+ addPlayer(player);
+ if (start && players.size() == 1) {
+ player.teleport(dungeon.getConfig().getLobbyPoint().toLocation(worldInstance.getWorld()));
+ Bukkit.getScheduler().runTaskLater(TheWarDungeon.inst(), this::start, 10L);
+ } else {
+ player.teleport(dungeon.getConfig().getLobbyPoint().toLocation(worldInstance.getWorld()));
+ if (dungeonLobby == null) {
+ this.dungeonLobby = new DungeonLobby(this);
+ this.dungeonLobby.runTaskTimer(TheWarDungeon.inst(), 0, 20L);
+ }
+ dungeonLobby.showBossBar(player);
+ }
+ if (players.size() == dungeon.getConfig().getOption().getMax()) {
+ if (dungeonLobby != null) {
+ dungeonLobby.setCounter(10);
+ for (DungeonPlayer dungeonPlayer : getPlayers()) {
+ dungeonPlayer.getPlayer().sendMessage(Lang.prefix+Lang.get("dungeon.lobby.max"));
+ }
+ }
+ }
+ for (DungeonPlayer dungeonPlayer : getPlayers()) {
+ Player player1 = dungeonPlayer.getPlayer();
+ player1.sendMessage(Lang.prefix+Lang.get("dungeon.lobby.join", player.getName(), players.size(), dungeon.getConfig().getOption().getMax()));
+ }
+ }
+
+ public void leave(Player player) {
+ if (dungeonLobby != null && state.equals(DungeonState.WAITING)) {
+ dungeonLobby.removeBossBar(player);
+ }
+ DungeonPlayer dungeonPlayer = getPlayer(player);
+ if (dungeonPlayer != null) {
+ player.setGameMode(dungeonPlayer.getGameMode());
+ }
+ if (players.size() - 1 == 0) {
+ if (dungeonLobby != null && dungeonLobby.isCancelled()) {
+ dungeonLobby.cancel();
+ }
+ stop();
+ } else {
+ players.remove(player.getUniqueId());
+ player.teleport(dungeon.getConfig().getEndPoint());
+ }
+ }
+
+
+ public void respawn(DungeonPlayer player) {
+ if (player.getDeath() > dungeon.getConfig().getOption().getReviveAmount()) {
+ return;
+ }
+ if (player.getState().equals(PlayerState.DEAD)) {
+ player.setState(PlayerState.LIVING);
+ }
+ player.getPlayer().setGameMode(dungeon.getConfig().getOption().getGameMode());
+ World world = worldInstance.getWorld();
+ Location respawnLocation = dungeon.getConfig().getStartPoint().toLocation(world);
+ if (spawnPoint != null) {
+ respawnLocation = spawnPoint.toLocation(world);
+ }
+ player.getPlayer().teleport(respawnLocation);
+ }
+
+ public boolean canJoin(Player player) {
+ return state.equals(DungeonState.WAITING) && players.size() < dungeon.getConfig().getOption().getMax();
+ }
+
+ private void addPlayer(Player player) {
+ if (!state.equals(DungeonState.WAITING)) {
+ return;
+ }
+ players.put(player.getUniqueId(), new DungeonPlayer(player));
+ }
+
+ public void setState(DungeonState state) {
+ this.state = state;
+ }
+
+ public void addTask(BukkitTask task) {
+ if (overdue) {
+ return;
+ }
+ tasks.add(task);
+ }
+
+ public void addActiveMob(ActiveMob activeMob) {
+ activeMobs.add(activeMob);
+ }
+
+ public List getActiveMobs() {
+ return activeMobs;
+ }
+
+ public Dungeon getDungeon() {
+ return dungeon;
+ }
+
+ public List getObjectiveGourps() {
+ return objectiveGourps;
+ }
+
+ public void checkObjectiveGroup() {
+ List scriptGourps = new ArrayList<>();
+ Iterator gourpIterator = objectiveGourps.iterator();
+ while (gourpIterator.hasNext()) {
+ ObjectiveGourp gourp = gourpIterator.next();
+ boolean flag = true;
+ for (Objective objective : gourp.getObjectives()) {
+ if (!objective.isComplete()) {
+ flag = false;
+ }
+ }
+ if (flag) {
+ ScriptGourp scriptGourp = new ScriptGourp(gourp.getScripts());
+ scriptGourps.add(scriptGourp);
+ gourpIterator.remove();
+ }
+ }
+ scriptGourps.forEach(scriptGourp -> scriptGourp.execute(this));
+ }
+
+ public void addObjectiveGourp(ObjectiveGourp gourp) {
+ this.objectiveGourps.add(gourp);
+ for (TimeObjective objective : gourp.getObjectives(TimeObjective.class)) {
+ addTask(objective.createTask(this));
+ }
+ }
+
+ public WorldInstance getWorldInstance() {
+ return worldInstance;
+ }
+
+ public int getTime() {
+ return time;
+ }
+
+ public DungeonState getState() {
+ return state;
+ }
+
+ public List getPlayers() {
+ List list = new ArrayList<>();
+ players.values().forEach(list::add);
+ return Collections.unmodifiableList(list);
+ }
+
+ public DungeonPlayer getPlayer(Player player) {
+ return players.get(player.getUniqueId());
+ }
+
+ public void start() {
+ if (overdue || worldInstance.isDestroyed()) {
+ return;
+ }
+ boolean flag = true;
+ while (flag) {
+ if (!isWorldLoaded()) {
+ flag = true;
+ break;
+ }
+ state = DungeonState.RUNNING;
+ countdown = dungeon.getConfig().getOption().getCountdown();
+ for (DungeonPlayer dungeonPlayer : getPlayers()) {
+ dungeonPlayer.getPlayer().setGameMode(dungeon.getConfig().getOption().getGameMode());
+ dungeonPlayer.getPlayer().teleport(dungeon.getConfig().getStartPoint().toLocation(worldInstance.getWorld()));
+ }
+ Bukkit.getScheduler().runTaskLater(TheWarDungeon.inst(), ()-> dungeon.getConfig().getStartScript().execute(this), 5L);
+ tasks.add(new BukkitRunnable() {
+ @Override
+ public void run() {
+ if (overdue) {
+ cancel();
+ return;
+ }
+ time++;
+ }
+ }.runTaskTimer(TheWarDungeon.inst(), 0L, 1L));
+ tasks.add(new BukkitRunnable() {
+ @Override
+ public void run() {
+ if (overdue) {
+ cancel();
+ return;
+ }
+ if (countdown > 0) {
+ countdown--;
+ if (countdown == 0) {
+ stop();
+ cancel();
+ }
+ }
+ }
+ }.runTaskTimer(TheWarDungeon.inst(), 20L, 20L));
+ tasks.add(new BukkitRunnable() {
+ @Override
+ public void run() {
+ for (DungeonPlayer dungeonPlayer : getPlayers()) {
+ Player player = dungeonPlayer.getPlayer();
+ DungeonInstance dungeonInstance = DungeonManager.getDungeonInstance(player.getWorld());
+ if (dungeonInstance == null || !dungeonInstance.getState().equals(DungeonState.RUNNING)) {
+ return;
+ }
+ for (ObjectiveGourp gourp : dungeonInstance.getObjectiveGourps()) {
+ List objectiveList1 = gourp.getObjectives(LocationObjective.class);
+ if (objectiveList1.size() > 0) {
+ for (LocationObjective locationObjective : objectiveList1) {
+ if (locationObjective.isArrive(dungeonInstance, player)) {
+ locationObjective.call();
+ }
+ }
+ }
+ List objectiveList2 = gourp.getObjectives(RegionObjective.class);
+ if (objectiveList2.size() > 0) {
+ for (RegionObjective regionObjective : objectiveList2) {
+ if (regionObjective.isInRegion(dungeonInstance, player)) {
+ regionObjective.call();
+ }
+ }
+ }
+ }
+ dungeonInstance.checkObjectiveGroup();
+ }
+ }
+ }.runTaskTimer(TheWarDungeon.inst(), 0L, 10L));
+ flag = false;
+ }
+ }
+
+ private boolean isWorldLoaded() {
+ try {
+ BukkitAdapter.adapt(worldInstance.getWorld());
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public void stop() {
+ if (overdue) {
+ return;
+ }
+ overdue = true;
+ state = DungeonState.END;
+ LogUtil.logTimeMap.remove(this.getUUID());
+
+ Bukkit.getScheduler().runTaskLater(TheWarDungeon.inst(), ()-> {
+ MobRegistry mobRegistry = MythicBukkit.inst().getMobManager().getMobRegistry();
+ for (Entity entity : worldInstance.getWorld().getEntities()) {
+ if (entity instanceof Player) {
+ continue;
+ }
+ entity.remove();
+ }
+ for (ActiveMob activeMob : activeMobs) {
+ activeMob.setDespawned();
+ MythicBukkit.inst().getMobManager().unregisterActiveMob(activeMob);
+ }
+ }, 15L);
+
+ dungeon.getConfig().getEndScript().execute(this);
+ tasks.forEach(bukkitTask -> {
+ if (!bukkitTask.isCancelled()) {
+ bukkitTask.cancel();
+ }
+ });
+ Bukkit.getScheduler().runTaskLater(TheWarDungeon.inst(), ()-> {
+ for (DungeonPlayer dungeonPlayer : getPlayers()) {
+ if (dungeonPlayer.getPlayer() != null && dungeonPlayer.getPlayer().isOnline()) {
+ dungeonPlayer.getPlayer().setGameMode(dungeonPlayer.getGameMode());
+ dungeonPlayer.getPlayer().teleport(dungeon.getConfig().getEndPoint());
+ }
+ }
+ worldInstance.setOccupied(false);
+ }, 20L);
+ }
+
+ public boolean isOverdue() {
+ return overdue;
+ }
+
+ public UUID getUUID() {
+ return uuid;
+ }
+
+ public int getCountdown() {
+ return countdown;
+ }
+
+ public void setSpawnPoint(Point spawnPoint) {
+ this.spawnPoint = spawnPoint;
+ }
+
+ public Point getSpawnPoint() {
+ return spawnPoint;
+ }
+
+ public void setDungeonLobby(DungeonLobby dungeonLobby) {
+ this.dungeonLobby = dungeonLobby;
+ }
+
+ public DungeonLobby getDungeonLobby() {
+ return dungeonLobby;
+ }
+
+ public boolean isLoaded() {
+ return loaded;
+ }
+
+ public void setLoaded(boolean loaded) {
+ this.loaded = loaded;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DungeonInstance that = (DungeonInstance) o;
+ return Objects.equals(uuid, that.uuid);
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uuid);
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonLobby.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonLobby.java
new file mode 100644
index 0000000..2dd5220
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonLobby.java
@@ -0,0 +1,93 @@
+package com.io.yutian.thewardungeon.dungeon;
+
+import com.io.yutian.thewardungeon.dungeon.player.DungeonPlayer;
+import com.io.yutian.thewardungeon.lang.Lang;
+import net.kyori.adventure.bossbar.BossBar;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Sound;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.List;
+
+public class DungeonLobby extends BukkitRunnable {
+
+ private DungeonInstance dungeonInstance;
+
+ private int counter;
+ private int maxTime;
+
+ private BossBar bossBar;
+
+ public DungeonLobby(DungeonInstance dungeonInstance) {
+ this.dungeonInstance = dungeonInstance;
+ this.maxTime = dungeonInstance.getDungeon().getConfig().getOption().getLobbyWaitTime();
+ this.counter = maxTime;
+ this.bossBar = BossBar.bossBar(Component.text(Lang.get("dungeon.lobby.bossbar", counter)), 1.0F, BossBar.Color.WHITE, BossBar.Overlay.PROGRESS);
+ }
+
+ public void showBossBar(Player player) {
+ player.showBossBar(bossBar);
+ }
+
+ public void removeBossBar(Player player) {
+ player.hideBossBar(bossBar);
+ }
+
+ @Override
+ public void run() {
+ List players = this.dungeonInstance.getPlayers();
+ if (this.dungeonInstance.getState() != DungeonState.WAITING) {
+ this.dungeonInstance.setDungeonLobby(null);
+ this.cancel();
+ return;
+ }
+ bossBar.progress((float) ((double) counter / (double) maxTime));
+ bossBar.name(Component.text(Lang.get("dungeon.lobby.bossbar", counter)));
+ if (this.counter == 15) {
+ for (DungeonPlayer dungeonPlayer : players) {
+ Player player = dungeonPlayer.getPlayer();
+ player.sendMessage(Lang.prefix+Lang.get("dungeon.lobby.time-15"));
+ player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.0f);
+ }
+ }
+
+ if (this.counter <= 3 && this.counter > 0) {
+ for (DungeonPlayer dungeonPlayer : players) {
+ Player player = dungeonPlayer.getPlayer();
+ player.sendMessage(Lang.prefix+Lang.get("dungeon.lobby.time-lessthan-3", this.counter));
+ player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.0f);
+ }
+ }
+ if (this.counter == 0) {
+ if (dungeonInstance.getPlayers().size() < dungeonInstance.getDungeon().getConfig().getOption().getMin()) {
+ this.counter = maxTime;
+ for (DungeonPlayer dungeonPlayer : players) {
+ Player player = dungeonPlayer.getPlayer();
+ player.sendMessage(Lang.prefix+Lang.get("dungeon.lobby.min-reset"));
+ player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.0f);
+ }
+ return;
+ }
+ start();
+ return;
+ }
+ this.counter--;
+
+ }
+
+ public void setCounter(int counter) {
+ this.counter = counter;
+ }
+
+ public void start() {
+ dungeonInstance.setDungeonLobby(null);
+ for (DungeonPlayer dungeonPlayer : this.dungeonInstance.getPlayers()) {
+ Player player = dungeonPlayer.getPlayer();
+ removeBossBar(player);
+ }
+ this.dungeonInstance.start();
+ this.cancel();
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonMap.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonMap.java
new file mode 100644
index 0000000..23940b2
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonMap.java
@@ -0,0 +1,23 @@
+package com.io.yutian.thewardungeon.dungeon;
+
+import java.io.File;
+
+public class DungeonMap {
+
+ private String id;
+ private File folder;
+
+ public DungeonMap(String id, File folder) {
+ this.id = id;
+ this.folder = folder;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public File getFolder() {
+ return folder;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonState.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonState.java
new file mode 100644
index 0000000..80eae0d
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/DungeonState.java
@@ -0,0 +1,9 @@
+package com.io.yutian.thewardungeon.dungeon;
+
+public enum DungeonState {
+
+ WAITING,
+ RUNNING,
+ END
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/Condition.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/Condition.java
new file mode 100644
index 0000000..0b0cf64
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/Condition.java
@@ -0,0 +1,59 @@
+package com.io.yutian.thewardungeon.dungeon.condition;
+
+import com.io.yutian.thewardungeon.data.LineMetadata;
+import com.io.yutian.thewardungeon.hook.PluginHook;
+import com.io.yutian.thewardungeon.util.JSUtil;
+import com.io.yutian.thewardungeon.util.Log;
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+public class Condition extends ICondition {
+
+ private String text;
+ private String message;
+
+ public Condition(LineMetadata metadata) {
+ super(metadata);
+ this.text = metadata.getString("text", null);
+ this.message = metadata.getString("message", null);
+ }
+
+ @Override
+ public boolean isValid(Player player) {
+ if (text == null) {
+ Log.warning("运行条件时出现错误!");
+ Log.warning("脚本: "+metadata.getSource());
+ Log.warning("原因: text 参数错误");
+ return false;
+ }
+ if (message == null) {
+ Log.warning("运行条件时出现错误!");
+ Log.warning("脚本: "+metadata.getSource());
+ Log.warning("原因: message 参数错误");
+ return false;
+ }
+ String s = text;
+ if (PluginHook.isHookPlaceholderAPI()) {
+ s = PlaceholderAPI.setPlaceholders(player, s);
+ }
+ try {
+ Object result = JSUtil.eval(s);
+ if (!(result instanceof Boolean)) {
+ Log.warning("运行条件时出现错误!");
+ Log.warning("脚本: "+metadata.getSource());
+ Log.warning("原因: JS条件结果非布尔值");
+ return false;
+ }
+ boolean r = (Boolean) result;
+ if (!r) {
+ String m = ChatColor.translateAlternateColorCodes('&', message);
+ player.sendMessage(m);
+ }
+ return r;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/ConditionGroup.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/ConditionGroup.java
new file mode 100644
index 0000000..9cfe6ee
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/ConditionGroup.java
@@ -0,0 +1,25 @@
+package com.io.yutian.thewardungeon.dungeon.condition;
+
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public class ConditionGroup {
+
+ private List conditions;
+
+ public ConditionGroup(List conditions) {
+ this.conditions = conditions;
+ }
+
+ public boolean isValid(Player player) {
+ boolean flag = true;
+ for (ICondition condition : conditions) {
+ if (!condition.isValid(player)) {
+ flag = false;
+ }
+ }
+ return flag;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/ICondition.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/ICondition.java
new file mode 100644
index 0000000..f9886be
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/condition/ICondition.java
@@ -0,0 +1,108 @@
+package com.io.yutian.thewardungeon.dungeon.condition;
+
+import com.io.yutian.thewardungeon.data.LineMetadata;
+import com.io.yutian.thewardungeon.script.SelectorType;
+import com.io.yutian.thewardungeon.util.ConsoleColor;
+import com.io.yutian.thewardungeon.util.Log;
+import javassist.bytecode.Opcode;
+import org.bukkit.entity.Player;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class ICondition {
+
+ public LineMetadata metadata;
+
+ public ICondition(LineMetadata metadata) {
+ this.metadata = metadata;
+ }
+
+ public abstract boolean isValid(Player player);
+
+ public static ICondition getCondition(String arg) {
+ String key;
+ String s = arg.toLowerCase();
+ if (s.contains("{")) {
+ key = s.substring(0, s.indexOf("{"));
+ } else if (s.contains("[")) {
+ key = s.substring(0, s.indexOf("["));
+ } else {
+ key = s;
+ }
+ Map valueMap = new HashMap<>();
+ String s2 = arg;
+ SelectorType selectorType1 = SelectorType.NULL;
+ if (s2.contains("{") && s2.contains("}")) {
+ int count = 0;
+ String s3 = s2.substring(s2.indexOf(Opcode.LSHR) + 1, s2.lastIndexOf(Opcode.LUSHR));
+ char[] charArray = s3.toCharArray();
+ int length = charArray.length;
+ for (int i = 0; i < length; i++) {
+ char c = charArray[i];
+ count = c == '{' ? count + 1 : count;
+ if (c == '}') {
+ count--;
+ }
+ }
+ if (count != 0) {
+ Log.error(ConsoleColor.RED + "加载条件时发生错误: 不平衡支撑" + ConsoleColor.WHITE);
+ Log.error(ConsoleColor.RED + "[Line]: " + ConsoleColor.WHITE + s3);
+ } else if (s3.length() != 0) {
+ int start = 0;
+ int pos = 0;
+ int depth = 0;
+ String s4 = s3 + "}";
+ char[] charArray2 = s4.toCharArray();
+ int length2 = charArray2.length;
+ for (int i2 = 0; i2 < length2; i2++) {
+ char c2 = charArray2[i2];
+ depth = (c2 == '}' || c2 == ']') ? ((c2 == '{' || c2 == '[') ? depth + 1 : depth) - 1 : depth;
+ if ((c2 == ';' && depth == 0) || (c2 == '}' && depth < 0)) {
+ try {
+ String element = s4.substring(start, pos);
+ if (pos - start > 0 && element.length() > 0) {
+ valueMap.put(element.substring(0, element.indexOf(61)).trim().toLowerCase(), element.substring(element.indexOf(61) + 1).trim());
+ }
+ start = pos + 1;
+ } catch (Exception e) {
+ start = pos + 1;
+ } catch (Throwable th) {
+ int i3 = pos + 1;
+ throw th;
+ }
+ }
+ pos++;
+ }
+ }
+ } else if (!s2.contains("[") || !s2.contains("]")) {
+ key = s2;
+ } else {
+ try {
+ s2 = s2.split("\\[")[1].split("\\]")[0];
+ } catch (ArrayIndexOutOfBoundsException e2) {
+ Log.error(ConsoleColor.RED + "加载条件时发生错误: 无效语法" + ConsoleColor.WHITE);
+ Log.error(ConsoleColor.RED + "[Line]: " + ConsoleColor.WHITE + s2);
+ }
+ }
+
+ key = key.toLowerCase();
+ if (!key.equalsIgnoreCase("condition")) {
+ Log.error(ConsoleColor.RED + "加载条件时发生错误: 无效条件" + ConsoleColor.WHITE);
+ Log.error(ConsoleColor.RED + "[Line]: " + ConsoleColor.WHITE + key);
+ return null;
+ }
+ try {
+ Constructor constructor = Condition.class.getConstructor(LineMetadata.class);
+ ICondition condition = (ICondition) constructor.newInstance(new LineMetadata(arg, valueMap));
+ return condition;
+ } catch (Exception e) {
+ Log.error(ConsoleColor.RED + "加载条件时发生错误: 未知错误" + ConsoleColor.WHITE);
+ Log.error(ConsoleColor.RED + "[Line]: " + ConsoleColor.WHITE + key);
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/thewardungeon/dungeon/config/DungeonConfig.java b/src/main/java/com/io/yutian/thewardungeon/dungeon/config/DungeonConfig.java
new file mode 100644
index 0000000..8a4d9c5
--- /dev/null
+++ b/src/main/java/com/io/yutian/thewardungeon/dungeon/config/DungeonConfig.java
@@ -0,0 +1,322 @@
+package com.io.yutian.thewardungeon.dungeon.config;
+
+import com.io.yutian.thewardungeon.dungeon.condition.ConditionGroup;
+import com.io.yutian.thewardungeon.dungeon.condition.ICondition;
+import com.io.yutian.thewardungeon.dungeon.objective.Objective;
+import com.io.yutian.thewardungeon.dungeon.objective.ObjectiveGourp;
+import com.io.yutian.thewardungeon.script.Script;
+import com.io.yutian.thewardungeon.script.ScriptGourp;
+import com.io.yutian.thewardungeon.util.ConsoleColor;
+import com.io.yutian.thewardungeon.util.Log;
+import com.io.yutian.thewarskyblocklib.math.DirectionPoint;
+import com.io.yutian.thewarskyblocklib.math.Point;
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.util.*;
+
+public class DungeonConfig {
+
+ protected File folder;
+
+ private String map;
+ private DirectionPoint lobbyPoint;
+ private DirectionPoint startPoint;
+ private Location endPoint;
+
+ private DungeonOption option = new DungeonOption();
+
+ private ScriptGourp startScript;
+ private ScriptGourp endScript;
+ private Map timingScripts;
+
+ private ObjectiveGourp defaultObjecive;
+ private ConditionGroup conditionGroup;
+
+ private Map scriptGourpMap = new HashMap<>();
+ private Map objectiveGourpMap = new HashMap<>();
+
+ public DungeonConfig(File folder) {
+ this.folder = folder;
+ }
+
+ public DungeonConfig(String map, File folder) {
+ this.map = map;
+ this.folder = folder;
+ }
+
+ public void read() {
+ File configFile = new File(folder, "config.yml");
+ File scriptFile = new File(folder, "script.yml");
+ File objectiveFile = new File(folder, "objective.yml");
+ File conditionFile = new File(folder, "condition.yml");
+ if (!configFile.exists()) {
+ initConfigFile();
+ }
+ if (!scriptFile.exists()) {
+ initScriptFile();
+ }
+ if (!objectiveFile.exists()) {
+ initObjectiveFile();
+ }
+ if (!conditionFile.exists()) {
+ initConditionFile();
+ }
+ FileConfiguration configFileConfiguration = YamlConfiguration.loadConfiguration(configFile);
+ FileConfiguration scriptFileConfiguration = YamlConfiguration.loadConfiguration(scriptFile);
+ FileConfiguration objectiveFileConfiguration = YamlConfiguration.loadConfiguration(objectiveFile);
+ FileConfiguration conditionFileConfiguration = YamlConfiguration.loadConfiguration(conditionFile);
+
+ // config.yml //
+ map = configFileConfiguration.getString("map");
+ lobbyPoint = configFileConfiguration.contains("location.lobby") && configFileConfiguration.isConfigurationSection("location.lobby") ? DirectionPoint.deserialize(configFileConfiguration.getConfigurationSection("location.lobby")) : null;
+ startPoint = configFileConfiguration.contains("location.start") && configFileConfiguration.isConfigurationSection("location.start") ? DirectionPoint.deserialize(configFileConfiguration.getConfigurationSection("location.start")) : null;
+ if (configFileConfiguration.contains("location.end") && configFileConfiguration.isConfigurationSection("location.end")) {
+ ConfigurationSection configurationSection = configFileConfiguration.getConfigurationSection("location.end");
+ World world = Bukkit.getWorld(configurationSection.getString("world"));
+ if (world != null) {
+ double x = configurationSection.getDouble("x");
+ double y = configurationSection.getDouble("y");
+ double z = configurationSection.getDouble("z");
+ float yaw = (float) configurationSection.getDouble("yaw", 0.0);
+ float pitch = (float) configurationSection.getDouble("pitch", 0.0);
+ endPoint = new Location(world, x, y, z, yaw, pitch);
+ }
+ }
+
+ ConfigurationSection section0 = configFileConfiguration.getConfigurationSection("options");
+ option.load(section0);
+ // config.yml //
+
+ // script.yml //
+ for (String key : scriptFileConfiguration.getKeys(false)) {
+ if (!scriptFileConfiguration.isList(key)) {
+ Log.error(ConsoleColor.RED + "加载脚本时发生错误: 错误的数据结构" + ConsoleColor.WHITE);
+ Log.error(ConsoleColor.RED + "[Location]: " + ConsoleColor.WHITE +"./dungeons/"+folder.getName()+"/script.yml");
+ Log.error(ConsoleColor.RED + "[Key]: " + ConsoleColor.WHITE + key);
+ continue;
+ }
+ List lines = scriptFileConfiguration.getStringList(key);
+ List