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