增加一些动作/结构并且补注释:( 呜呜呜补注释好累头号疼
This commit is contained in:
@@ -4,27 +4,48 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import top.sunsetlab.event.EventListener;
|
import top.sunsetlab.event.EventListener;
|
||||||
import top.sunsetlab.utils.ActionManager;
|
import top.sunsetlab.utils.ActionManager;
|
||||||
|
import top.sunsetlab.utils.LangUtils;
|
||||||
import top.sunsetlab.utils.StructureManager;
|
import top.sunsetlab.utils.StructureManager;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件主类
|
||||||
|
*/
|
||||||
public class PluginMain extends JavaPlugin implements Listener {
|
public class PluginMain extends JavaPlugin implements Listener {
|
||||||
|
/// 插件版本
|
||||||
public static final String VERSION = "0.0.1-alpha";
|
public static final String VERSION = "0.0.1-alpha";
|
||||||
|
/// 插件语言
|
||||||
|
public static final String LANG = "zh_CN";
|
||||||
|
/// 调试模式
|
||||||
public static final boolean DEBUG = true;
|
public static final boolean DEBUG = true;
|
||||||
|
/// 日志类 - 仅在初始化后调用
|
||||||
public static Logger LOGGER;
|
public static Logger LOGGER;
|
||||||
|
/// 结构管理器,用于加载/匹配预设的结构
|
||||||
public static StructureManager structureManager;
|
public static StructureManager structureManager;
|
||||||
|
/// 动作管理器,用于加载/调用预设的动作
|
||||||
public static ActionManager actionManager;
|
public static ActionManager actionManager;
|
||||||
|
/// 插件实例
|
||||||
public static JavaPlugin plugin;
|
public static JavaPlugin plugin;
|
||||||
|
/// 语言管理,本地化用
|
||||||
|
public static LangUtils langUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件启用时调用
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
// 初始化
|
||||||
plugin = this;
|
plugin = this;
|
||||||
LOGGER = getLogger();
|
LOGGER = getLogger();
|
||||||
|
langUtils = new LangUtils();
|
||||||
|
langUtils.init(LANG);
|
||||||
structureManager = new StructureManager();
|
structureManager = new StructureManager();
|
||||||
structureManager.load();
|
structureManager.load();
|
||||||
actionManager = new ActionManager();
|
actionManager = new ActionManager();
|
||||||
actionManager.load();
|
actionManager.load();
|
||||||
getLogger().info("Plugin ver" + VERSION + " loaded." + (DEBUG?"(DEBUG)":""));
|
getLogger().info("Plugin ver" + VERSION + " loaded." + (DEBUG?"(DEBUG)":""));
|
||||||
|
// 注册时间监听器
|
||||||
getServer().getPluginManager().registerEvents(new EventListener(), this);
|
getServer().getPluginManager().registerEvents(new EventListener(), this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,14 @@ package top.sunsetlab.actions;
|
|||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/// 打雷动作
|
||||||
public class ActionLightning implements IActionBase{
|
public class ActionLightning implements IActionBase{
|
||||||
|
/**
|
||||||
|
* 调用动作
|
||||||
|
* @param location 动作执行位置
|
||||||
|
* @param caller 动作执行者
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean call(Location location, Player caller) {
|
public boolean call(Location location, Player caller) {
|
||||||
location.getWorld().strikeLightning(location);
|
location.getWorld().strikeLightning(location);
|
||||||
|
|||||||
35
src/main/java/top/sunsetlab/actions/CastDelay.java
Normal file
35
src/main/java/top/sunsetlab/actions/CastDelay.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/main/java/top/sunsetlab/actions/CheckGlowDust.java
Normal file
32
src/main/java/top/sunsetlab/actions/CheckGlowDust.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,13 @@ package top.sunsetlab.actions;
|
|||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/// 动作基类
|
||||||
public interface IActionBase {
|
public interface IActionBase {
|
||||||
|
/**
|
||||||
|
* 调用动作
|
||||||
|
* @param location 动作执行位置
|
||||||
|
* @param caller 动作执行者
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
boolean call(Location location, Player caller);
|
boolean call(Location location, Player caller);
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/main/java/top/sunsetlab/actions/PlaceFire.java
Normal file
34
src/main/java/top/sunsetlab/actions/PlaceFire.java
Normal file
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/main/java/top/sunsetlab/actions/PlayAnvilSound.java
Normal file
20
src/main/java/top/sunsetlab/actions/PlayAnvilSound.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/main/java/top/sunsetlab/actions/Transformation.java
Normal file
33
src/main/java/top/sunsetlab/actions/Transformation.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package top.sunsetlab.event;
|
package top.sunsetlab.event;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
@@ -11,21 +13,27 @@ import top.sunsetlab.utils.JsonStructure;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/// 事件监听器
|
||||||
public class EventListener implements Listener {
|
public class EventListener implements Listener {
|
||||||
|
/**
|
||||||
|
* 当玩家与世界交互时触发
|
||||||
|
* @param event 事件实例
|
||||||
|
*/
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void clickEvent(PlayerInteractEvent event) {
|
public void clickEvent(PlayerInteractEvent event) {
|
||||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.getPlayer().getInventory().getItemInMainHand().getType() != Material.GLOWSTONE_DUST) {
|
Player player = event.getPlayer();
|
||||||
|
if (player.getInventory().getItemInMainHand().getType() != Material.GLOWSTONE_DUST) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.getClickedBlock() != null && event.getClickedBlock().getType() != Material.REDSTONE_WIRE) {
|
if (event.getClickedBlock() != null && event.getClickedBlock().getType() != Material.REDSTONE_WIRE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.plugin, () -> {
|
Location location = event.getClickedBlock().getLocation();
|
||||||
String structid = PluginMain.structureManager.match(event.getClickedBlock().getLocation());
|
String structid = PluginMain.structureManager.match(location);
|
||||||
if (structid == null) {
|
if (structid == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -33,9 +41,19 @@ public class EventListener implements Listener {
|
|||||||
if (structure == null) {
|
if (structure == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (structure.getPreConditionTask() != null
|
||||||
|
&& !PluginMain.actionManager.call(structure.getPreConditionTask(), location, player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
structure.breakStructure(location);
|
||||||
|
|
||||||
|
// 异步执行动作
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.plugin, () -> {
|
||||||
ArrayList<String> actions = structure.getActions();
|
ArrayList<String> actions = structure.getActions();
|
||||||
for (String action : actions) {
|
for (String action : actions) {
|
||||||
PluginMain.actionManager.call(action, event.getClickedBlock().getLocation(), event.getPlayer());
|
PluginMain.actionManager.call(action, location, player);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|||||||
@@ -16,20 +16,29 @@ class ActionList {
|
|||||||
ArrayList<String> locations;
|
ArrayList<String> locations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动作管理器
|
||||||
|
*/
|
||||||
public class ActionManager {
|
public class ActionManager {
|
||||||
private final HashMap<String, JsonAction> actions;
|
private final HashMap<String, JsonAction> actions;
|
||||||
public ActionManager() {
|
public ActionManager() {
|
||||||
actions = new HashMap<>();
|
actions = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
public void load() {
|
public void load() {
|
||||||
|
// 从本地文件读取
|
||||||
InputStream is = ActionManager.class.getResourceAsStream("/actions.json");
|
InputStream is = ActionManager.class.getResourceAsStream("/actions.json");
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
throw new RuntimeException("actions.json file not found!");
|
throw new RuntimeException("actions.json file not found!");
|
||||||
}
|
}
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||||
|
// 解析json
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
ActionList actionList = gson.fromJson(reader, ActionList.class);
|
ActionList actionList = gson.fromJson(reader, ActionList.class);
|
||||||
|
// 加载单个动作
|
||||||
for (String location : actionList.locations) {
|
for (String location : actionList.locations) {
|
||||||
JsonAction action = new JsonAction(location);
|
JsonAction action = new JsonAction(location);
|
||||||
actions.put(action.getId(), action);
|
actions.put(action.getId(), action);
|
||||||
@@ -37,7 +46,15 @@ public class ActionManager {
|
|||||||
PluginMain.LOGGER.info("Loaded " + actions.size() + " actions.");
|
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) {
|
public boolean call(String actionId, Location location, Player caller) {
|
||||||
|
// 获取动作
|
||||||
JsonAction action = actions.get(actionId);
|
JsonAction action = actions.get(actionId);
|
||||||
if (action == null) {
|
if (action == null) {
|
||||||
throw new RuntimeException("Invalid action id " + actionId);
|
throw new RuntimeException("Invalid action id " + actionId);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package top.sunsetlab.utils;
|
package top.sunsetlab.utils;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import top.sunsetlab.PluginMain;
|
||||||
import top.sunsetlab.actions.IActionBase;
|
import top.sunsetlab.actions.IActionBase;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -14,11 +16,19 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
class ActionData {
|
class ActionData {
|
||||||
String id;
|
String id;
|
||||||
String classname;
|
String classname;
|
||||||
|
boolean sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Json定义的动作
|
||||||
|
*/
|
||||||
public class JsonAction {
|
public class JsonAction {
|
||||||
private final ActionData data;
|
private final ActionData data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造器
|
||||||
|
* @param location 资源文件(json)的位置
|
||||||
|
*/
|
||||||
public JsonAction(String location) {
|
public JsonAction(String location) {
|
||||||
InputStream is = JsonAction.class.getResourceAsStream("/" + location);
|
InputStream is = JsonAction.class.getResourceAsStream("/" + location);
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
@@ -29,15 +39,32 @@ public class JsonAction {
|
|||||||
data = gson.fromJson(br, ActionData.class);
|
data = gson.fromJson(br, ActionData.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用动作
|
||||||
|
* @param location 调用位置
|
||||||
|
* @param caller 执行者
|
||||||
|
* @return 动作是否成功运行,sync动作始终为true
|
||||||
|
*/
|
||||||
public boolean run(Location location, Player caller) {
|
public boolean run(Location location, Player caller) {
|
||||||
try {
|
try {
|
||||||
|
// 通过反射加载动作类
|
||||||
Class<?> clazz = Class.forName(data.classname);
|
Class<?> clazz = Class.forName(data.classname);
|
||||||
if (!IActionBase.class.isAssignableFrom(clazz)) {
|
if (!IActionBase.class.isAssignableFrom(clazz)) {
|
||||||
throw new RuntimeException(data.classname + " is not a Action");
|
throw new RuntimeException(data.classname + " is not a Action");
|
||||||
}
|
}
|
||||||
|
// 获取构造器
|
||||||
Constructor<?> constructor = clazz.getConstructor();
|
Constructor<?> constructor = clazz.getConstructor();
|
||||||
IActionBase action = (IActionBase) constructor.newInstance();
|
IActionBase action = (IActionBase) constructor.newInstance();
|
||||||
|
if (data.sync) {
|
||||||
|
// 在Minecraft线程内执行,一般用于世界交互
|
||||||
|
Bukkit.getScheduler().runTask(PluginMain.plugin, () -> {
|
||||||
|
action.call(location, caller);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}else {
|
||||||
|
// 异步执行
|
||||||
return action.call(location, caller);
|
return action.call(location, caller);
|
||||||
|
}
|
||||||
}catch (ClassNotFoundException
|
}catch (ClassNotFoundException
|
||||||
| NoSuchMethodException
|
| NoSuchMethodException
|
||||||
| SecurityException
|
| SecurityException
|
||||||
@@ -51,6 +78,10 @@ public class JsonAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取动作id
|
||||||
|
* @return 动作id
|
||||||
|
*/
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return data.id;
|
return data.id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package top.sunsetlab.utils;
|
package top.sunsetlab.utils;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.*;
|
||||||
import org.bukkit.NamespacedKey;
|
|
||||||
import org.bukkit.Registry;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.block.BlockType;
|
import org.bukkit.block.BlockType;
|
||||||
|
import org.jspecify.annotations.NonNull;
|
||||||
import top.sunsetlab.PluginMain;
|
import top.sunsetlab.PluginMain;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -22,12 +20,22 @@ class JsonStructureData {
|
|||||||
int[] center;
|
int[] center;
|
||||||
String id;
|
String id;
|
||||||
ArrayList<String> actions;
|
ArrayList<String> actions;
|
||||||
|
String precondition_task;
|
||||||
|
ArrayList<String> noclear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Json定义的结构
|
||||||
public class JsonStructure {
|
public class JsonStructure {
|
||||||
|
/// 结构数据
|
||||||
private final JsonStructureData data;
|
private final JsonStructureData data;
|
||||||
|
/// 结构资源文件位置
|
||||||
private final String structure_loc;
|
private final String structure_loc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param location 资源文件的位置
|
||||||
|
* @throws RuntimeException 在无法读取资源文件时抛出
|
||||||
|
*/
|
||||||
public JsonStructure(String location) throws RuntimeException {
|
public JsonStructure(String location) throws RuntimeException {
|
||||||
InputStream file = JsonStructure.class.getResourceAsStream("/" + location);
|
InputStream file = JsonStructure.class.getResourceAsStream("/" + location);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
@@ -40,7 +48,13 @@ public class JsonStructure {
|
|||||||
structure_loc = location;
|
structure_loc = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试匹配结构
|
||||||
|
* @param pos 结构中心点位置
|
||||||
|
* @return 结构是否匹配?
|
||||||
|
*/
|
||||||
public boolean match(Location pos) {
|
public boolean match(Location pos) {
|
||||||
|
// 确定起始点,终点
|
||||||
World world = pos.getWorld();
|
World world = pos.getWorld();
|
||||||
Location currentpos = new Location(
|
Location currentpos = new Location(
|
||||||
world,
|
world,
|
||||||
@@ -59,7 +73,14 @@ public class JsonStructure {
|
|||||||
PluginMain.LOGGER.log(Level.INFO, "Matching structure " + structure_loc
|
PluginMain.LOGGER.log(Level.INFO, "Matching structure " + structure_loc
|
||||||
+ "; From " + currentpos + " To " + endpos);
|
+ "; From " + currentpos + " To " + endpos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录方块种类 - 仅在需要时生成
|
||||||
|
ArrayList<BlockType> types = null;
|
||||||
|
|
||||||
|
// 循环匹配每个方块
|
||||||
|
// TODO 有没有更好的方法
|
||||||
while (!currentpos.equals(endpos)) {
|
while (!currentpos.equals(endpos)) {
|
||||||
|
// 相对西北角的位置
|
||||||
int rx = currentpos.getBlockX() - startpos.getBlockX();
|
int rx = currentpos.getBlockX() - startpos.getBlockX();
|
||||||
int rz = currentpos.getBlockZ() - startpos.getBlockZ();
|
int rz = currentpos.getBlockZ() - startpos.getBlockZ();
|
||||||
// if (PluginMain.DEBUG) {
|
// if (PluginMain.DEBUG) {
|
||||||
@@ -67,19 +88,16 @@ public class JsonStructure {
|
|||||||
// + currentpos
|
// + currentpos
|
||||||
// + "(relative (" + rx + "," + rz + "))");
|
// + "(relative (" + rx + "," + rz + "))");
|
||||||
// }
|
// }
|
||||||
|
// 应该存在的方块
|
||||||
String mark = String.valueOf(data.structure.get(rz).charAt(rx));
|
String mark = String.valueOf(data.structure.get(rz).charAt(rx));
|
||||||
String type = data.marks.get(mark);
|
String type = data.marks.get(mark);
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new RuntimeException("In Structure "+ structure_loc +"; Undefined mark: " + mark);
|
throw new RuntimeException("In Structure "+ structure_loc +"; Undefined mark: " + mark);
|
||||||
}
|
}
|
||||||
NamespacedKey key = NamespacedKey.fromString(type);
|
|
||||||
if (key == null) {
|
if (!type.equals("any")) {
|
||||||
throw new RuntimeException("In Structure "+ structure_loc +"; Invalid key: " + type);
|
// 匹配特定方块
|
||||||
}
|
BlockType blockType = getBlockType(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 (!Objects.equals(world.getBlockAt(currentpos).getType().asBlockType(), blockType)) {
|
||||||
if (PluginMain.DEBUG) {
|
if (PluginMain.DEBUG) {
|
||||||
PluginMain.LOGGER.log(Level.INFO, "Block Mismatch at " + currentpos
|
PluginMain.LOGGER.log(Level.INFO, "Block Mismatch at " + currentpos
|
||||||
@@ -89,6 +107,31 @@ public class JsonStructure {
|
|||||||
}
|
}
|
||||||
return false;
|
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);
|
currentpos.add(1,0,0);
|
||||||
if (currentpos.getBlockX() == endpos.getBlockX() + 1) {
|
if (currentpos.getBlockX() == endpos.getBlockX() + 1) {
|
||||||
currentpos.setX(startpos.getBlockX());
|
currentpos.setX(startpos.getBlockX());
|
||||||
@@ -101,11 +144,96 @@ public class JsonStructure {
|
|||||||
return true;
|
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() {
|
public String getId() {
|
||||||
return data.id;
|
return data.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取要执行的动作列表
|
||||||
|
* @return 动作列表
|
||||||
|
*/
|
||||||
public ArrayList<String> getActions() {
|
public ArrayList<String> getActions() {
|
||||||
return data.actions;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/main/java/top/sunsetlab/utils/LangUtils.java
Normal file
51
src/main/java/top/sunsetlab/utils/LangUtils.java
Normal file
@@ -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<String,String> 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<HashMap<String, String>>(){}.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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,14 +16,25 @@ class StructureList {
|
|||||||
ArrayList<String> locations = new ArrayList<>();
|
ArrayList<String> locations = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 呜呜呜补文档补的快哭了
|
||||||
|
|
||||||
|
/// 结构管理器
|
||||||
public class StructureManager {
|
public class StructureManager {
|
||||||
|
/// 又是一个好用的键值对
|
||||||
private final HashMap<String,JsonStructure> structures;
|
private final HashMap<String,JsonStructure> structures;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
*/
|
||||||
public StructureManager() {
|
public StructureManager() {
|
||||||
structures = new HashMap<>();
|
structures = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化函数
|
||||||
|
*/
|
||||||
public void load() {
|
public void load() {
|
||||||
InputStream is = StructureList.class.getResourceAsStream("/structures.json");
|
InputStream is = StructureManager.class.getResourceAsStream("/structures.json");
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
throw new RuntimeException("structures.json not found");
|
throw new RuntimeException("structures.json not found");
|
||||||
}
|
}
|
||||||
@@ -37,6 +48,11 @@ public class StructureManager {
|
|||||||
PluginMain.LOGGER.log(Level.INFO, "Loaded " + structures.size() + " structures");
|
PluginMain.LOGGER.log(Level.INFO, "Loaded " + structures.size() + " structures");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在所有结构中尝试匹配
|
||||||
|
* @param location 结构的中心位置
|
||||||
|
* @return 匹配到的id,没有匹配到则为null
|
||||||
|
*/
|
||||||
public @Nullable String match(Location location) {
|
public @Nullable String match(Location location) {
|
||||||
for (JsonStructure structure : structures.values()) {
|
for (JsonStructure structure : structures.values()) {
|
||||||
if (structure.match(location)) {
|
if (structure.match(location)) {
|
||||||
@@ -46,7 +62,25 @@ public class StructureManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id获取结构
|
||||||
|
* @param id 结构id
|
||||||
|
* @return 结构对象
|
||||||
|
*/
|
||||||
public @Nullable JsonStructure getStructure(String id) {
|
public @Nullable JsonStructure getStructure(String id) {
|
||||||
return structures.get(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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
{
|
{
|
||||||
"locations": [
|
"locations": [
|
||||||
"actions/lightning.json"
|
"actions/lightning.json",
|
||||||
|
"actions/castdelay.json",
|
||||||
|
"actions/checkglowdust.json",
|
||||||
|
"actions/transformation.json",
|
||||||
|
"actions/placefire.json",
|
||||||
|
"actions/playanvilsound.json"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
5
src/main/resources/actions/castdelay.json
Normal file
5
src/main/resources/actions/castdelay.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "castdelay",
|
||||||
|
"classname": "top.sunsetlab.actions.CastDelay",
|
||||||
|
"sync": false
|
||||||
|
}
|
||||||
5
src/main/resources/actions/checkglowdust.json
Normal file
5
src/main/resources/actions/checkglowdust.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "checkglowdust",
|
||||||
|
"classname": "top.sunsetlab.actions.CheckGlowDust",
|
||||||
|
"sync": false
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"id": "lightning",
|
"id": "lightning",
|
||||||
"classname": "top.sunsetlab.actions.ActionLightning"
|
"classname": "top.sunsetlab.actions.ActionLightning",
|
||||||
|
"sync": true
|
||||||
}
|
}
|
||||||
5
src/main/resources/actions/placefire.json
Normal file
5
src/main/resources/actions/placefire.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "placefire",
|
||||||
|
"classname": "top.sunsetlab.actions.PlaceFire",
|
||||||
|
"sync": true
|
||||||
|
}
|
||||||
5
src/main/resources/actions/playanvilsound.json
Normal file
5
src/main/resources/actions/playanvilsound.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "playanvilsound",
|
||||||
|
"classname": "top.sunsetlab.actions.PlayAnvilSound",
|
||||||
|
"sync": false
|
||||||
|
}
|
||||||
5
src/main/resources/actions/transformation.json
Normal file
5
src/main/resources/actions/transformation.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "transformation",
|
||||||
|
"classname": "top.sunsetlab.actions.Transformation",
|
||||||
|
"sync": true
|
||||||
|
}
|
||||||
3
src/main/resources/assets/lang/en_US.json
Normal file
3
src/main/resources/assets/lang/en_US.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"starlight.message.glowdust_lack": "Seems i cannot afford this spell"
|
||||||
|
}
|
||||||
3
src/main/resources/assets/lang/zh_CN.json
Normal file
3
src/main/resources/assets/lang/zh_CN.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"starlight.message.glowdust_lack": "貌似我无法承受这个法阵的消耗"
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"locations": [
|
"locations": [
|
||||||
"structures/01.json"
|
"structures/01.json",
|
||||||
|
"structures/transformation.json"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -16,11 +16,12 @@
|
|||||||
" xxx "
|
" xxx "
|
||||||
],
|
],
|
||||||
"marks": {
|
"marks": {
|
||||||
" ": "minecraft:air",
|
" ": "any",
|
||||||
"x": "minecraft:redstone_wire"
|
"x": "minecraft:redstone_wire"
|
||||||
},
|
},
|
||||||
"center": [6,6],
|
"center": [6,6],
|
||||||
"actions": [
|
"actions": [
|
||||||
|
"castdelay",
|
||||||
"lightning"
|
"lightning"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
31
src/main/resources/structures/transformation.json
Normal file
31
src/main/resources/structures/transformation.json
Normal file
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user