diff --git a/src/main/java/top/sunsetlab/PluginMain.java b/src/main/java/top/sunsetlab/PluginMain.java index 548480c..c11db84 100644 --- a/src/main/java/top/sunsetlab/PluginMain.java +++ b/src/main/java/top/sunsetlab/PluginMain.java @@ -4,6 +4,7 @@ import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import top.sunsetlab.event.EventListener; import top.sunsetlab.utils.ActionManager; +import top.sunsetlab.utils.ChatListener; import top.sunsetlab.utils.LangUtils; import top.sunsetlab.utils.StructureManager; @@ -45,6 +46,10 @@ public class PluginMain extends JavaPlugin implements Listener { * 语言管理,本地化用 */ public static LangUtils langUtils; + /** + * 消息监听器 + */ + public static ChatListener chatListener; /** * 插件启用时调用 @@ -60,8 +65,10 @@ public class PluginMain extends JavaPlugin implements Listener { structureManager.load(); actionManager = new ActionManager(); actionManager.load(); + chatListener = new ChatListener(); getLogger().info("Plugin ver" + VERSION + " loaded." + (DEBUG?"(DEBUG)":"")); // 注册时间监听器 getServer().getPluginManager().registerEvents(new EventListener(), this); + getServer().getPluginManager().registerEvents(chatListener, this); } } diff --git a/src/main/java/top/sunsetlab/actions/SendMessage.java b/src/main/java/top/sunsetlab/actions/SendMessage.java new file mode 100644 index 0000000..c987f95 --- /dev/null +++ b/src/main/java/top/sunsetlab/actions/SendMessage.java @@ -0,0 +1,19 @@ +package top.sunsetlab.actions; + +import net.kyori.adventure.text.Component; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import top.sunsetlab.PluginMain; + +public class SendMessage implements IActionBase { + @Override + public boolean call(Location location, Player caller, ActionParam data) { + if (!data.hasKey("message")) { + PluginMain.LOGGER.warning("Failed to send message: message undefined"); + return false; + } + String message = PluginMain.langUtils.translate(data.getString("message")); + caller.sendMessage(Component.text(message)); + return true; + } +} diff --git a/src/main/java/top/sunsetlab/actions/WaitForMessage.java b/src/main/java/top/sunsetlab/actions/WaitForMessage.java new file mode 100644 index 0000000..2aa96b5 --- /dev/null +++ b/src/main/java/top/sunsetlab/actions/WaitForMessage.java @@ -0,0 +1,61 @@ +package top.sunsetlab.actions; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import top.sunsetlab.PluginMain; +import top.sunsetlab.utils.ChatListener; +import top.sunsetlab.utils.RandomSentenceGenerator; + +import java.util.IllegalFormatException; + +/** + * 监听聊天消息 + * 需要设置sync为false + */ +public class WaitForMessage implements IActionBase { + @Override + public boolean call(Location location, Player caller, ActionParam data) { + if (!data.hasKey("message")) { + PluginMain.LOGGER.warning("Wait for message but message not specified"); + return false; + } + String message = PluginMain.langUtils.translate(data.getString("message")); + int max_tick = data.hasKey("maxtick") ? data.getInt("maxtick") : 100; // 5sec + + if (data.hasKey("random")) { + int random = data.getInt("random"); + message = RandomSentenceGenerator.generateRandomSentence(random); + if (data.hasKey("prompt")) { + String prompt = PluginMain.langUtils.translate(data.getString("prompt")); + try { + prompt = String.format(prompt, message); + }catch (IllegalFormatException e){ + PluginMain.LOGGER.warning("Invalid prompt format!"); + PluginMain.LOGGER.warning(e.getMessage()); + } + caller.sendMessage(prompt); + } + } + + ChatListener listener = PluginMain.chatListener; + int listenid = listener.listen(caller, message); + + int count = 0; + while (count < max_tick) { + if (listener.check(listenid)) { // 消息触发 + listener.pop(listenid); + return true; + } + try { + Thread.sleep(50); + } catch (InterruptedException ignored) {} + count++; + } + listener.pop(listenid); + + if (data.hasKey("failmsg")) { + caller.sendMessage(PluginMain.langUtils.translate(data.getString("failmsg"))); + } + return false; + } +} diff --git a/src/main/java/top/sunsetlab/event/EventListener.java b/src/main/java/top/sunsetlab/event/EventListener.java index 9a1ec7a..6e56789 100644 --- a/src/main/java/top/sunsetlab/event/EventListener.java +++ b/src/main/java/top/sunsetlab/event/EventListener.java @@ -54,20 +54,26 @@ public class EventListener implements Listener { return; } - if (structure.getPreConditionTask() != null) { - StructureAction structureAction = structure.getPreConditionTask(); - if (!PluginMain.actionManager.call(structureAction.id, location, player, structureAction.param)) { - return; - } - } - - structure.breakStructure(location); - // 异步执行动作 Bukkit.getScheduler().runTaskAsynchronously(PluginMain.plugin, () -> { + if (structure.getPreConditionTask() != null) { + for (StructureAction action : structure.getPreConditionTask()) { + if (!PluginMain.actionManager.call(action.id, location, player, action.param)) { + return; + } + } + } + + Bukkit.getScheduler().runTask(PluginMain.plugin, () -> { + structure.breakStructure(location); + }); + ArrayList actions = structure.getActions(); for (StructureAction action : actions) { - PluginMain.actionManager.call(action.id, location, player, action.param); + boolean result = PluginMain.actionManager.call(action.id, location, player, action.param); + if (!result) { + break; + } } }); event.setCancelled(true); diff --git a/src/main/java/top/sunsetlab/utils/ChatListener.java b/src/main/java/top/sunsetlab/utils/ChatListener.java new file mode 100644 index 0000000..9865f14 --- /dev/null +++ b/src/main/java/top/sunsetlab/utils/ChatListener.java @@ -0,0 +1,82 @@ +package top.sunsetlab.utils; + +import io.papermc.paper.event.player.AsyncChatEvent; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.PriorityQueue; + +class ChatParam { + Player player; + String message; + boolean status; +} + +public class ChatListener implements Listener { + private final HashMap params = new HashMap<>(); + private final PriorityQueue id_queue = new PriorityQueue<>(); + private final HashMap> player_map = new HashMap<>(); + private int id_cur = 0; + + public int listen(Player player, String message) { + ChatParam param = new ChatParam(); + param.player = player; + param.message = message; + param.status = false; + int id = -1; + if (!id_queue.isEmpty()) { + id = id_queue.poll(); + }else { + id = id_cur; + id_cur++; + } + params.put(id, param); + + if (!player_map.containsKey(player)) { + player_map.put(player, new ArrayList<>()); + } + player_map.get(player).add(id); + return id; + } + + public boolean check(int id) { + if (!params.containsKey(id)) { + return false; + } + return params.get(id).status; + } + + public boolean pop(int id) { + if (!params.containsKey(id)) { + return false; + } + ChatParam param = params.get(id); + params.remove(id); + id_queue.offer(id); + + player_map.get(param.player).remove(id); + if (player_map.get(param.player).isEmpty()) { + player_map.remove(param.player); + } + return param.status; + } + + @EventHandler + public void onChat(AsyncChatEvent e) { + Player player = e.getPlayer(); + Component message = e.originalMessage(); + String text = PlainTextComponentSerializer.plainText().serialize(message); + + for (int id : player_map.get(player)) { + ChatParam param = params.get(id); + if (param.message.equals(text)) { + param.status = true; + } + } + } +} diff --git a/src/main/java/top/sunsetlab/utils/JsonStructure.java b/src/main/java/top/sunsetlab/utils/JsonStructure.java index e16cb95..f5625c1 100644 --- a/src/main/java/top/sunsetlab/utils/JsonStructure.java +++ b/src/main/java/top/sunsetlab/utils/JsonStructure.java @@ -21,7 +21,7 @@ class JsonStructureData { int[] center; String id; ArrayList actions; - StructureAction precondition_task; + ArrayList precondition_task; ArrayList noclear; } @@ -236,7 +236,7 @@ public class JsonStructure { * 获取门控任务(仅当该任务成功时执行任务列表) * @return 门控任务id */ - public StructureAction getPreConditionTask() { + public ArrayList getPreConditionTask() { return data.precondition_task; } } diff --git a/src/main/java/top/sunsetlab/utils/RandomSentenceGenerator.java b/src/main/java/top/sunsetlab/utils/RandomSentenceGenerator.java new file mode 100644 index 0000000..c57c602 --- /dev/null +++ b/src/main/java/top/sunsetlab/utils/RandomSentenceGenerator.java @@ -0,0 +1,40 @@ +package top.sunsetlab.utils; + +import java.util.Random; + +/** + * 懒得写啦,ai生成的 + */ +public class RandomSentenceGenerator { + + /** + * 生成一个由随机英文字母组成的句子。 + * + * @param wordCount 句子中包含的单词数量 + * @return 由随机单词组成的句子,单词间以空格分隔 + */ + public static String generateRandomSentence(int wordCount) { + if (wordCount <= 0) { + return ""; + } + + Random random = new Random(); + StringBuilder sentence = new StringBuilder(); + String alphabet = "abcdefghijklmnopqrstuvwxyz"; + + for (int i = 0; i < wordCount; i++) { + // 随机单词长度:3 到 8 个字母 + int wordLength = random.nextInt(6) + 3; // nextInt(6) 返回 0-5,加3得3-8 + StringBuilder word = new StringBuilder(wordLength); + for (int j = 0; j < wordLength; j++) { + char randomChar = alphabet.charAt(random.nextInt(alphabet.length())); + word.append(randomChar); + } + sentence.append(word); + if (i < wordCount - 1) { + sentence.append(' '); + } + } + return sentence.toString(); + } +} \ No newline at end of file diff --git a/src/main/resources/actions.json b/src/main/resources/actions.json index c911994..5efaf0a 100644 --- a/src/main/resources/actions.json +++ b/src/main/resources/actions.json @@ -4,6 +4,8 @@ "actions/castdelay.json", "actions/checkglowdust.json", "actions/placeblock.json", - "actions/playsound.json" + "actions/playsound.json", + "actions/sendmessage.json", + "actions/waitformessage.json" ] } \ No newline at end of file diff --git a/src/main/resources/actions/sendmessage.json b/src/main/resources/actions/sendmessage.json new file mode 100644 index 0000000..9c72581 --- /dev/null +++ b/src/main/resources/actions/sendmessage.json @@ -0,0 +1,5 @@ +{ + "id": "sendmessage", + "classname": "top.sunsetlab.actions.SendMessage", + "sync": false +} \ No newline at end of file diff --git a/src/main/resources/actions/waitformessage.json b/src/main/resources/actions/waitformessage.json new file mode 100644 index 0000000..615319b --- /dev/null +++ b/src/main/resources/actions/waitformessage.json @@ -0,0 +1,5 @@ +{ + "id": "waitformessage", + "classname": "top.sunsetlab.actions.WaitForMessage", + "sync": false +} \ No newline at end of file diff --git a/src/main/resources/structures/01.json b/src/main/resources/structures/01.json index b8fbfb3..cbead52 100644 --- a/src/main/resources/structures/01.json +++ b/src/main/resources/structures/01.json @@ -39,12 +39,14 @@ } } ], - "precondition_task": { - "id": "checkglowdust", - "param": { - "data": { - "amount": 3 + "precondition_task": [ + { + "id": "checkglowdust", + "param": { + "data": { + "amount": 3 + } } } - } + ] } \ No newline at end of file diff --git a/src/main/resources/structures/transformation.json b/src/main/resources/structures/transformation.json index 1bfb310..81e7b21 100644 --- a/src/main/resources/structures/transformation.json +++ b/src/main/resources/structures/transformation.json @@ -74,7 +74,7 @@ "id": "castdelay", "param": { "data": { - "ticks": 250 + "ticks": 200 } } }, @@ -107,14 +107,36 @@ } } ], - "precondition_task": { - "id": "checkglowdust", - "param": { - "data": { - "amount": 20 + "precondition_task": [ + { + "id": "sendmessage", + "param": { + "data": { + "message": "你感到古老的力量在法阵中汇聚" + } + } + }, + { + "id": "waitformessage", + "param": { + "data": { + "message": "", + "prompt": "古老的字句在你脑海中回荡: %s", + "random": 4, + "maxtick": 200, + "failmsg": "古老的力量消散了" + } + } + }, + { + "id": "checkglowdust", + "param": { + "data": { + "amount": 20 + } } } - }, + ], "noclear": [ "minecraft:diamond_block" ]