242 lines
8.3 KiB
Java
242 lines
8.3 KiB
Java
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<String> structure;
|
|
HashMap<String,String> marks;
|
|
int[] center;
|
|
String id;
|
|
ArrayList<String> actions;
|
|
String precondition_task;
|
|
ArrayList<String> 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<BlockType> 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<String> getActions() {
|
|
return data.actions;
|
|
}
|
|
|
|
/**
|
|
* 破坏整个结构
|
|
* @param pos 结构中心位置
|
|
*/
|
|
public void breakStructure(Location pos) {
|
|
// 清理赦免:D (学生物学的)
|
|
// FIXME 这东西用不了
|
|
ArrayList<BlockType> 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;
|
|
}
|
|
}
|