diff --git a/src/main/java/top/sunsetlab/PluginMain.java b/src/main/java/top/sunsetlab/PluginMain.java index d9df726..6289925 100644 --- a/src/main/java/top/sunsetlab/PluginMain.java +++ b/src/main/java/top/sunsetlab/PluginMain.java @@ -4,27 +4,48 @@ 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.LangUtils; import top.sunsetlab.utils.StructureManager; import java.util.logging.Logger; +/** + * 插件主类 + */ public class PluginMain extends JavaPlugin implements Listener { + /// 插件版本 public static final String VERSION = "0.0.1-alpha"; + /// 插件语言 + public static final String LANG = "zh_CN"; + /// 调试模式 public static final boolean DEBUG = true; + /// 日志类 - 仅在初始化后调用 public static Logger LOGGER; + /// 结构管理器,用于加载/匹配预设的结构 public static StructureManager structureManager; + /// 动作管理器,用于加载/调用预设的动作 public static ActionManager actionManager; + /// 插件实例 public static JavaPlugin plugin; + /// 语言管理,本地化用 + public static LangUtils langUtils; + /** + * 插件启用时调用 + */ @Override public void onEnable() { + // 初始化 plugin = this; LOGGER = getLogger(); + langUtils = new LangUtils(); + langUtils.init(LANG); structureManager = new StructureManager(); structureManager.load(); actionManager = new ActionManager(); actionManager.load(); - getLogger().info("Plugin ver" + VERSION + "loaded." + (DEBUG?"(DEBUG)":"")); + getLogger().info("Plugin ver" + VERSION + " loaded." + (DEBUG?"(DEBUG)":"")); + // 注册时间监听器 getServer().getPluginManager().registerEvents(new EventListener(), this); } } diff --git a/src/main/java/top/sunsetlab/actions/ActionLightning.java b/src/main/java/top/sunsetlab/actions/ActionLightning.java index 9be8bd9..95a3af4 100644 --- a/src/main/java/top/sunsetlab/actions/ActionLightning.java +++ b/src/main/java/top/sunsetlab/actions/ActionLightning.java @@ -3,7 +3,14 @@ package top.sunsetlab.actions; import org.bukkit.Location; import org.bukkit.entity.Player; +/// 打雷动作 public class ActionLightning implements IActionBase{ + /** + * 调用动作 + * @param location 动作执行位置 + * @param caller 动作执行者 + * @return 是否成功 + */ @Override public boolean call(Location location, Player caller) { location.getWorld().strikeLightning(location); diff --git a/src/main/java/top/sunsetlab/actions/CastDelay.java b/src/main/java/top/sunsetlab/actions/CastDelay.java new file mode 100644 index 0000000..37d96ce --- /dev/null +++ b/src/main/java/top/sunsetlab/actions/CastDelay.java @@ -0,0 +1,35 @@ +package top.sunsetlab.actions; + +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.entity.Player; + +/// 施放延迟 +public class CastDelay implements IActionBase{ + /** + * 调用动作 + * @param location 动作执行位置 + * @param caller 动作执行者 + * @return 是否成功 + */ + @Override + public boolean call(Location location, Player caller) { + int count = 0; + while (count < 50) { + try { + Thread.sleep(100); + }catch (InterruptedException ignored){} + location.getWorld().spawnParticle( + Particle.DUST, + location, + 20, + 1.0, + 0.0, + 1.0, + new Particle.DustOptions(Color.RED, 1.0f)); + count++; + } + return true; + } +} diff --git a/src/main/java/top/sunsetlab/actions/CheckGlowDust.java b/src/main/java/top/sunsetlab/actions/CheckGlowDust.java new file mode 100644 index 0000000..c5c7109 --- /dev/null +++ b/src/main/java/top/sunsetlab/actions/CheckGlowDust.java @@ -0,0 +1,32 @@ +package top.sunsetlab.actions; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import top.sunsetlab.PluginMain; + +/// 门控动作,检查莹石存量 +public class CheckGlowDust implements IActionBase { + /** + * 调用动作 + * @param location 动作执行位置 + * @param caller 动作执行者 + * @return 是否成功 + */ + @Override + public boolean call(Location location, Player caller) { + if (PluginMain.DEBUG) { + PluginMain.LOGGER.info("Checking amount of glow dust"); + } + if (caller.getInventory().getItemInMainHand().getType() == Material.GLOWSTONE_DUST + && caller.getInventory().getItemInMainHand().getAmount() >= 20) { + int amount = caller.getInventory().getItemInMainHand().getAmount(); + caller.getInventory().getItemInMainHand().setAmount(amount - 20); + return true; + } + caller.sendMessage(PluginMain.langUtils.translateC("starlight.message.glowdust_lack")); + return false; + } +} diff --git a/src/main/java/top/sunsetlab/actions/IActionBase.java b/src/main/java/top/sunsetlab/actions/IActionBase.java index 8d65cd2..4ca8b3b 100644 --- a/src/main/java/top/sunsetlab/actions/IActionBase.java +++ b/src/main/java/top/sunsetlab/actions/IActionBase.java @@ -3,6 +3,13 @@ package top.sunsetlab.actions; import org.bukkit.Location; import org.bukkit.entity.Player; +/// 动作基类 public interface IActionBase { + /** + * 调用动作 + * @param location 动作执行位置 + * @param caller 动作执行者 + * @return 是否成功 + */ boolean call(Location location, Player caller); } diff --git a/src/main/java/top/sunsetlab/actions/PlaceFire.java b/src/main/java/top/sunsetlab/actions/PlaceFire.java new file mode 100644 index 0000000..fe359b3 --- /dev/null +++ b/src/main/java/top/sunsetlab/actions/PlaceFire.java @@ -0,0 +1,34 @@ +package top.sunsetlab.actions; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.Player; + +/// 放置火焰 +public class PlaceFire implements IActionBase { + /** + * 调用动作 + * @param location 动作执行位置 + * @param caller 动作执行者 + * @return 是否成功 + */ + @Override + public boolean call(Location location, Player caller) { + placeFire(location.clone().add(1,0,0)); + placeFire(location.clone().add(-1,0,0)); + placeFire(location.clone().add(0,0,1)); + placeFire(location.clone().add(0,0,-1)); + placeFire(location.clone().add(0,0,0)); + return true; + } + + /** + * 在指定位置放置火焰 + * @param location 位置 + */ + private void placeFire(Location location) { + World world = location.getWorld(); + world.setBlockData(location, Material.FIRE.createBlockData()); + } +} diff --git a/src/main/java/top/sunsetlab/actions/PlayAnvilSound.java b/src/main/java/top/sunsetlab/actions/PlayAnvilSound.java new file mode 100644 index 0000000..a7a9c37 --- /dev/null +++ b/src/main/java/top/sunsetlab/actions/PlayAnvilSound.java @@ -0,0 +1,20 @@ +package top.sunsetlab.actions; + +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; + +/// 向调用者播放铁砧的声音 +public class PlayAnvilSound implements IActionBase { + /** + * 调用动作 + * @param location 动作执行位置 + * @param caller 动作执行者 + * @return 是否成功 + */ + @Override + public boolean call(Location location, Player caller) { + caller.playSound(location, Sound.BLOCK_ANVIL_LAND, 1, 1); + return true; + } +} diff --git a/src/main/java/top/sunsetlab/actions/Transformation.java b/src/main/java/top/sunsetlab/actions/Transformation.java new file mode 100644 index 0000000..b3881e2 --- /dev/null +++ b/src/main/java/top/sunsetlab/actions/Transformation.java @@ -0,0 +1,33 @@ +package top.sunsetlab.actions; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +/// 嬗变!(神奇炼金术) +public class Transformation implements IActionBase { + /** + * 调用动作 + * @param location 动作执行位置 + * @param caller 动作执行者 + * @return 是否成功 + */ + @Override + public boolean call(Location location, Player caller) { + location.getWorld().setBlockData( + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + Material.NETHERITE_BLOCK.createBlockData() + ); + location.getWorld().setBlockData( + location.clone().subtract(1,0,0), + Material.AIR.createBlockData() + ); + location.getWorld().setBlockData( + location.clone().add(1,0,0), + Material.AIR.createBlockData() + ); + return true; + } +} diff --git a/src/main/java/top/sunsetlab/event/EventListener.java b/src/main/java/top/sunsetlab/event/EventListener.java index 0e2a4fe..4c085aa 100644 --- a/src/main/java/top/sunsetlab/event/EventListener.java +++ b/src/main/java/top/sunsetlab/event/EventListener.java @@ -1,7 +1,9 @@ package top.sunsetlab.event; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; @@ -11,31 +13,47 @@ import top.sunsetlab.utils.JsonStructure; import java.util.ArrayList; +/// 事件监听器 public class EventListener implements Listener { + /** + * 当玩家与世界交互时触发 + * @param event 事件实例 + */ @EventHandler public void clickEvent(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { return; } - if (event.getPlayer().getInventory().getItemInMainHand().getType() != Material.GLOWSTONE_DUST) { + Player player = event.getPlayer(); + if (player.getInventory().getItemInMainHand().getType() != Material.GLOWSTONE_DUST) { return; } if (event.getClickedBlock() != null && event.getClickedBlock().getType() != Material.REDSTONE_WIRE) { return; } + Location location = event.getClickedBlock().getLocation(); + String structid = PluginMain.structureManager.match(location); + if (structid == null) { + return; + } + JsonStructure structure = PluginMain.structureManager.getStructure(structid); + if (structure == null) { + return; + } + + if (structure.getPreConditionTask() != null + && !PluginMain.actionManager.call(structure.getPreConditionTask(), location, player)) { + return; + } + + structure.breakStructure(location); + + // 异步执行动作 Bukkit.getScheduler().runTaskAsynchronously(PluginMain.plugin, () -> { - String structid = PluginMain.structureManager.match(event.getClickedBlock().getLocation()); - if (structid == null) { - return; - } - JsonStructure structure = PluginMain.structureManager.getStructure(structid); - if (structure == null) { - return; - } ArrayList actions = structure.getActions(); for (String action : actions) { - PluginMain.actionManager.call(action, event.getClickedBlock().getLocation(), event.getPlayer()); + PluginMain.actionManager.call(action, location, player); } }); event.setCancelled(true); diff --git a/src/main/java/top/sunsetlab/utils/ActionManager.java b/src/main/java/top/sunsetlab/utils/ActionManager.java index db43fad..cad72eb 100644 --- a/src/main/java/top/sunsetlab/utils/ActionManager.java +++ b/src/main/java/top/sunsetlab/utils/ActionManager.java @@ -16,20 +16,29 @@ class ActionList { ArrayList locations; } +/** + * 动作管理器 + */ public class ActionManager { private final HashMap actions; public ActionManager() { actions = new HashMap<>(); } + /** + * 初始化 + */ public void load() { + // 从本地文件读取 InputStream is = ActionManager.class.getResourceAsStream("/actions.json"); if (is == null) { throw new RuntimeException("actions.json file not found!"); } BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + // 解析json Gson gson = new Gson(); ActionList actionList = gson.fromJson(reader, ActionList.class); + // 加载单个动作 for (String location : actionList.locations) { JsonAction action = new JsonAction(location); actions.put(action.getId(), action); @@ -37,7 +46,15 @@ public class ActionManager { PluginMain.LOGGER.info("Loaded " + actions.size() + " actions."); } + /** + * 调用动作 + * @param actionId 动作id + * @param location 执行位置 + * @param caller 执行者 + * @return 动作是否执行成功,sync动作始终返回true + */ public boolean call(String actionId, Location location, Player caller) { + // 获取动作 JsonAction action = actions.get(actionId); if (action == null) { throw new RuntimeException("Invalid action id " + actionId); diff --git a/src/main/java/top/sunsetlab/utils/JsonAction.java b/src/main/java/top/sunsetlab/utils/JsonAction.java index dc236aa..4201454 100644 --- a/src/main/java/top/sunsetlab/utils/JsonAction.java +++ b/src/main/java/top/sunsetlab/utils/JsonAction.java @@ -1,8 +1,10 @@ package top.sunsetlab.utils; import com.google.gson.Gson; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; +import top.sunsetlab.PluginMain; import top.sunsetlab.actions.IActionBase; import java.io.BufferedReader; @@ -14,11 +16,19 @@ import java.lang.reflect.InvocationTargetException; class ActionData { String id; String classname; + boolean sync; } +/** + * Json定义的动作 + */ public class JsonAction { private final ActionData data; + /** + * 构造器 + * @param location 资源文件(json)的位置 + */ public JsonAction(String location) { InputStream is = JsonAction.class.getResourceAsStream("/" + location); if (is == null) { @@ -29,15 +39,32 @@ public class JsonAction { data = gson.fromJson(br, ActionData.class); } + /** + * 调用动作 + * @param location 调用位置 + * @param caller 执行者 + * @return 动作是否成功运行,sync动作始终为true + */ public boolean run(Location location, Player caller) { try { + // 通过反射加载动作类 Class clazz = Class.forName(data.classname); if (!IActionBase.class.isAssignableFrom(clazz)) { throw new RuntimeException(data.classname + " is not a Action"); } + // 获取构造器 Constructor constructor = clazz.getConstructor(); IActionBase action = (IActionBase) constructor.newInstance(); - return action.call(location, caller); + if (data.sync) { + // 在Minecraft线程内执行,一般用于世界交互 + Bukkit.getScheduler().runTask(PluginMain.plugin, () -> { + action.call(location, caller); + }); + return true; + }else { + // 异步执行 + return action.call(location, caller); + } }catch (ClassNotFoundException | NoSuchMethodException | SecurityException @@ -51,6 +78,10 @@ public class JsonAction { } } + /** + * 获取动作id + * @return 动作id + */ public String getId() { return data.id; } diff --git a/src/main/java/top/sunsetlab/utils/JsonStructure.java b/src/main/java/top/sunsetlab/utils/JsonStructure.java index 03879ac..8200482 100644 --- a/src/main/java/top/sunsetlab/utils/JsonStructure.java +++ b/src/main/java/top/sunsetlab/utils/JsonStructure.java @@ -1,11 +1,9 @@ package top.sunsetlab.utils; import com.google.gson.Gson; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.block.BlockType; +import org.jspecify.annotations.NonNull; import top.sunsetlab.PluginMain; import java.io.BufferedReader; @@ -22,12 +20,22 @@ class JsonStructureData { int[] center; String id; ArrayList actions; + String precondition_task; + ArrayList noclear; } +/// Json定义的结构 public class JsonStructure { + /// 结构数据 private final JsonStructureData data; + /// 结构资源文件位置 private final String structure_loc; + /** + * 构造函数 + * @param location 资源文件的位置 + * @throws RuntimeException 在无法读取资源文件时抛出 + */ public JsonStructure(String location) throws RuntimeException { InputStream file = JsonStructure.class.getResourceAsStream("/" + location); if (file == null) { @@ -40,7 +48,13 @@ public class JsonStructure { structure_loc = location; } + /** + * 尝试匹配结构 + * @param pos 结构中心点位置 + * @return 结构是否匹配? + */ public boolean match(Location pos) { + // 确定起始点,终点 World world = pos.getWorld(); Location currentpos = new Location( world, @@ -59,7 +73,14 @@ public class JsonStructure { PluginMain.LOGGER.log(Level.INFO, "Matching structure " + structure_loc + "; From " + currentpos + " To " + endpos); } + + // 记录方块种类 - 仅在需要时生成 + ArrayList types = null; + + // 循环匹配每个方块 + // TODO 有没有更好的方法 while (!currentpos.equals(endpos)) { + // 相对西北角的位置 int rx = currentpos.getBlockX() - startpos.getBlockX(); int rz = currentpos.getBlockZ() - startpos.getBlockZ(); // if (PluginMain.DEBUG) { @@ -67,28 +88,50 @@ public class JsonStructure { // + currentpos // + "(relative (" + rx + "," + rz + "))"); // } + // 应该存在的方块 String mark = String.valueOf(data.structure.get(rz).charAt(rx)); String type = data.marks.get(mark); if (type == null) { throw new RuntimeException("In Structure "+ structure_loc +"; Undefined mark: " + mark); } - NamespacedKey key = NamespacedKey.fromString(type); - if (key == null) { - throw new RuntimeException("In Structure "+ structure_loc +"; Invalid key: " + type); - } - BlockType blockType = Registry.BLOCK.get(key); - if (blockType == null) { - throw new RuntimeException("In Structure "+ structure_loc +"; Invalid block type: " + type); - } - if (!Objects.equals(world.getBlockAt(currentpos).getType().asBlockType(), blockType)) { - if (PluginMain.DEBUG) { + + if (!type.equals("any")) { + // 匹配特定方块 + BlockType blockType = getBlockType(type); + if (!Objects.equals(world.getBlockAt(currentpos).getType().asBlockType(), blockType)) { + if (PluginMain.DEBUG) { + PluginMain.LOGGER.log(Level.INFO, "Block Mismatch at " + currentpos + + "(relative (" + rx + "," + rz + "))" + + "; Expected " + blockType + + ", but got " + world.getBlockAt(currentpos).getType()); + } + return false; + } + }else { + // 匹配任意方块 + if (types == null) { + types = new ArrayList<>(); + for (String s : data.marks.values()) { + if (s.equals("any")) { + continue; + } + types.add(getBlockType(s)); + } + } + // 是否为空气 + boolean isAir = Objects.equals(world.getBlockAt(currentpos).getType().asBlockType(), Material.AIR.asBlockType()); + // 是否在列表内 - 为了防止玩家摆个正方形导致怪异的匹配 + boolean isInList = types.contains(world.getBlockAt(currentpos).getType().asBlockType()); + // 当非空气且在列表内时终止 + if (!isAir && isInList ) { PluginMain.LOGGER.log(Level.INFO, "Block Mismatch at " + currentpos + "(relative (" + rx + "," + rz + "))" - + "; Expected " + blockType - + ", but got " + world.getBlockAt(currentpos).getType()); + + " Tried any, but got " + world.getBlockAt(currentpos).getType()); + return false; } - return false; } + + // 递增当前坐标 currentpos.add(1,0,0); if (currentpos.getBlockX() == endpos.getBlockX() + 1) { currentpos.setX(startpos.getBlockX()); @@ -101,11 +144,96 @@ public class JsonStructure { return true; } + /** + * 通过id获取方块类型 + * @param type 方块id + * @return 方块类型 + */ + private @NonNull BlockType getBlockType(String type) { + NamespacedKey key = NamespacedKey.fromString(type); + if (key == null) { + throw new RuntimeException("In Structure " + structure_loc + "; Invalid key: " + type); + } + BlockType blockType = Registry.BLOCK.get(key); + if (blockType == null) { + throw new RuntimeException("In Structure " + structure_loc + "; Invalid block type: " + type); + } + return blockType; + } + + /** + * 获取结构id + * @return 结构id + */ public String getId() { return data.id; } + /** + * 获取要执行的动作列表 + * @return 动作列表 + */ public ArrayList getActions() { return data.actions; } + + /** + * 破坏整个结构 + * @param pos 结构中心位置 + */ + public void breakStructure(Location pos) { + // 清理赦免:D (学生物学的) + // FIXME 这东西用不了 + ArrayList noclears = new ArrayList<>(); + if (data.noclear != null) { + // 已知这里正常 + for (String s : data.noclear) { + if (PluginMain.DEBUG) { + PluginMain.LOGGER.log(Level.INFO, "Will not clear " + s); + } + noclears.add(getBlockType(s)); + } + } + + // 确认起始点和终点 + World world = pos.getWorld(); + Location beginPos = new Location( + pos.getWorld(), + pos.getBlockX() - data.center[0], + pos.getBlockY(), + pos.getBlockZ() - data.center[1] + ); + Location currentPos = beginPos.clone(); + Location endPos = new Location( + pos.getWorld(), + pos.getBlockX() + data.center[0], + pos.getBlockY(), + pos.getBlockZ() + data.center[1] + ); + + // 遍历每一个方块 + // TODO 有没有更好的方法 + while (!beginPos.equals(endPos)) { + // 这里的判断貌似有问题 + if (!noclears.contains(world.getBlockAt(beginPos).getType().asBlockType())) { + world.getBlockAt(currentPos).setType(Material.AIR); + } + currentPos.add(1,0,0); + if (currentPos.getBlockX() == endPos.getBlockX() + 1) { + currentPos.setX(beginPos.getBlockX()); + currentPos.setZ(currentPos.getBlockZ() + 1); + if (currentPos.getBlockZ() == endPos.getBlockZ() + 1) { + break; + } + } + } + } + + /** + * 获取门控任务(仅当该任务成功时执行任务列表) + * @return 门控任务id + */ + public String getPreConditionTask() { + return data.precondition_task; + } } diff --git a/src/main/java/top/sunsetlab/utils/LangUtils.java b/src/main/java/top/sunsetlab/utils/LangUtils.java new file mode 100644 index 0000000..adcb35b --- /dev/null +++ b/src/main/java/top/sunsetlab/utils/LangUtils.java @@ -0,0 +1,51 @@ +package top.sunsetlab.utils; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import net.kyori.adventure.text.Component; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; + +/// 本地化工具 +public class LangUtils { + /// 一个很好用的键值对 + private HashMap map; + + /** + * 初始化 + * @param lang 使用的语言 + */ + public void init(String lang){ + InputStream is = LangUtils.class.getResourceAsStream("/assets/lang/" + lang + ".json"); + if (is == null) { + throw new RuntimeException("Unable to load language file: " + lang + ".json"); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + Gson gson = new Gson(); + map = gson.fromJson(reader, new TypeToken>(){}.getType()); + } + + /** + * 获取本地化文本 + * @param key 本地化键 + * @return 本地化文本 + */ + public String translate(String key) { + if (map.containsKey(key)) { + return map.get(key); + } + return key; + } + + /** + * 获取本地化文本组件 + * @param key 本地化键 + * @return 本地化文本组件 + */ + public Component translateC(String key) { + return Component.text(translate(key)); + } +} diff --git a/src/main/java/top/sunsetlab/utils/StructureManager.java b/src/main/java/top/sunsetlab/utils/StructureManager.java index 5bf6836..4207545 100644 --- a/src/main/java/top/sunsetlab/utils/StructureManager.java +++ b/src/main/java/top/sunsetlab/utils/StructureManager.java @@ -16,14 +16,25 @@ class StructureList { ArrayList locations = new ArrayList<>(); } +// 呜呜呜补文档补的快哭了 + +/// 结构管理器 public class StructureManager { + /// 又是一个好用的键值对 private final HashMap structures; + + /** + * 构造函数 + */ public StructureManager() { structures = new HashMap<>(); } + /** + * 初始化函数 + */ public void load() { - InputStream is = StructureList.class.getResourceAsStream("/structures.json"); + InputStream is = StructureManager.class.getResourceAsStream("/structures.json"); if (is == null) { throw new RuntimeException("structures.json not found"); } @@ -37,6 +48,11 @@ public class StructureManager { PluginMain.LOGGER.log(Level.INFO, "Loaded " + structures.size() + " structures"); } + /** + * 在所有结构中尝试匹配 + * @param location 结构的中心位置 + * @return 匹配到的id,没有匹配到则为null + */ public @Nullable String match(Location location) { for (JsonStructure structure : structures.values()) { if (structure.match(location)) { @@ -46,7 +62,25 @@ public class StructureManager { return null; } + /** + * 根据id获取结构 + * @param id 结构id + * @return 结构对象 + */ public @Nullable JsonStructure getStructure(String id) { return structures.get(id); } + + /** + * 根据id破坏结构 + * @param id 结构id + * @param location 结构的中心位置 + */ + public void breakStructure(String id, Location location) { + JsonStructure structure = structures.get(id); + if (structure == null) { + throw new RuntimeException("structure with id " + id + " not found"); + } + structure.breakStructure(location); + } } diff --git a/src/main/resources/actions.json b/src/main/resources/actions.json index 6e53952..4997f52 100644 --- a/src/main/resources/actions.json +++ b/src/main/resources/actions.json @@ -1,5 +1,10 @@ { "locations": [ - "actions/lightning.json" + "actions/lightning.json", + "actions/castdelay.json", + "actions/checkglowdust.json", + "actions/transformation.json", + "actions/placefire.json", + "actions/playanvilsound.json" ] } \ No newline at end of file diff --git a/src/main/resources/actions/castdelay.json b/src/main/resources/actions/castdelay.json new file mode 100644 index 0000000..565582c --- /dev/null +++ b/src/main/resources/actions/castdelay.json @@ -0,0 +1,5 @@ +{ + "id": "castdelay", + "classname": "top.sunsetlab.actions.CastDelay", + "sync": false +} \ No newline at end of file diff --git a/src/main/resources/actions/checkglowdust.json b/src/main/resources/actions/checkglowdust.json new file mode 100644 index 0000000..a5aac0a --- /dev/null +++ b/src/main/resources/actions/checkglowdust.json @@ -0,0 +1,5 @@ +{ + "id": "checkglowdust", + "classname": "top.sunsetlab.actions.CheckGlowDust", + "sync": false +} \ No newline at end of file diff --git a/src/main/resources/actions/lightning.json b/src/main/resources/actions/lightning.json index 326ce6d..c0acb90 100644 --- a/src/main/resources/actions/lightning.json +++ b/src/main/resources/actions/lightning.json @@ -1,4 +1,5 @@ { "id": "lightning", - "classname": "top.sunsetlab.actions.ActionLightning" + "classname": "top.sunsetlab.actions.ActionLightning", + "sync": true } \ No newline at end of file diff --git a/src/main/resources/actions/placefire.json b/src/main/resources/actions/placefire.json new file mode 100644 index 0000000..3b2845d --- /dev/null +++ b/src/main/resources/actions/placefire.json @@ -0,0 +1,5 @@ +{ + "id": "placefire", + "classname": "top.sunsetlab.actions.PlaceFire", + "sync": true +} \ No newline at end of file diff --git a/src/main/resources/actions/playanvilsound.json b/src/main/resources/actions/playanvilsound.json new file mode 100644 index 0000000..8de09ad --- /dev/null +++ b/src/main/resources/actions/playanvilsound.json @@ -0,0 +1,5 @@ +{ + "id": "playanvilsound", + "classname": "top.sunsetlab.actions.PlayAnvilSound", + "sync": false +} \ No newline at end of file diff --git a/src/main/resources/actions/transformation.json b/src/main/resources/actions/transformation.json new file mode 100644 index 0000000..b0f6be8 --- /dev/null +++ b/src/main/resources/actions/transformation.json @@ -0,0 +1,5 @@ +{ + "id": "transformation", + "classname": "top.sunsetlab.actions.Transformation", + "sync": true +} \ No newline at end of file diff --git a/src/main/resources/assets/lang/en_US.json b/src/main/resources/assets/lang/en_US.json new file mode 100644 index 0000000..3e7840f --- /dev/null +++ b/src/main/resources/assets/lang/en_US.json @@ -0,0 +1,3 @@ +{ + "starlight.message.glowdust_lack": "Seems i cannot afford this spell" +} \ No newline at end of file diff --git a/src/main/resources/assets/lang/zh_CN.json b/src/main/resources/assets/lang/zh_CN.json new file mode 100644 index 0000000..a0084cd --- /dev/null +++ b/src/main/resources/assets/lang/zh_CN.json @@ -0,0 +1,3 @@ +{ + "starlight.message.glowdust_lack": "貌似我无法承受这个法阵的消耗" +} \ No newline at end of file diff --git a/src/main/resources/structures.json b/src/main/resources/structures.json index 5cb68be..7f47a34 100644 --- a/src/main/resources/structures.json +++ b/src/main/resources/structures.json @@ -1,5 +1,6 @@ { "locations": [ - "structures/01.json" + "structures/01.json", + "structures/transformation.json" ] } \ No newline at end of file diff --git a/src/main/resources/structures/01.json b/src/main/resources/structures/01.json index 3342094..0e16828 100644 --- a/src/main/resources/structures/01.json +++ b/src/main/resources/structures/01.json @@ -16,11 +16,12 @@ " xxx " ], "marks": { - " ": "minecraft:air", + " ": "any", "x": "minecraft:redstone_wire" }, "center": [6,6], "actions": [ + "castdelay", "lightning" ] } \ No newline at end of file diff --git a/src/main/resources/structures/transformation.json b/src/main/resources/structures/transformation.json new file mode 100644 index 0000000..48dbd3e --- /dev/null +++ b/src/main/resources/structures/transformation.json @@ -0,0 +1,31 @@ +{ + "id": "transformation", + "structure": [ + " x ", + " xxxxx ", + " x p x ", + "xxoxoxx", + " x p x ", + " xxxxx ", + " x " + ], + "marks": { + "x": "minecraft:redstone_wire", + "o": "minecraft:diamond_block", + "p": "minecraft:redstone_block", + " ": "any" + }, + "center": [3,3], + "actions": [ + "placefire", + "playanvilsound", + "castdelay", + "playanvilsound", + "transformation", + "lightning" + ], + "precondition_task": "checkglowdust", + "noclear": [ + "minecraft:diamond_block" + ] +} \ No newline at end of file