package top.sunsetlab.utils; import com.google.gson.Gson; import org.bukkit.*; import org.bukkit.block.BlockType; import org.jspecify.annotations.NonNull; import top.sunsetlab.PluginMain; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Objects; import java.util.logging.Level; class JsonStructureData { ArrayList structure; HashMap marks; 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) { throw new RuntimeException(location + " not found"); } InputStreamReader reader = new InputStreamReader(file); BufferedReader bufferedReader = new BufferedReader(reader); Gson gson = new Gson(); data = gson.fromJson(bufferedReader, JsonStructureData.class); structure_loc = location; } /** * 尝试匹配结构 * @param pos 结构中心点位置 * @return 结构是否匹配? */ public boolean match(Location pos) { // 确定起始点,终点 World world = pos.getWorld(); Location currentpos = new Location( world, pos.getX() - data.center[0], pos.getY(), pos.getZ() - data.center[1] ); Location startpos = currentpos.clone(); Location endpos = new Location( world, pos.getX() + data.center[0], pos.getY(), pos.getZ() + data.center[1] ); if (PluginMain.DEBUG) { 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) { // PluginMain.LOGGER.log(Level.INFO, "Matching location " // + 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); } 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 + "))" + " Tried any, but got " + world.getBlockAt(currentpos).getType()); return false; } } // 递增当前坐标 currentpos.add(1,0,0); if (currentpos.getBlockX() == endpos.getBlockX() + 1) { currentpos.setX(startpos.getBlockX()); currentpos.setZ(currentpos.getBlockZ() + 1); if (currentpos.getBlockZ() == endpos.getBlockZ() + 1) { break; } } } 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; } }