莫斯图迪
本帖最后由 azbh111 于 2018-8-19 12:06 编辑

关于本插件

本人开发各种插件时,发现总是会做很多重复烦人的工作

以下列举一些重复烦人的工作,并提供框架下优化后的代码(学霸食用,学渣直接看帖子结尾吧)

?    配置文件的 生成/读取/重载/保存

  1. // 一个自定义配置文件
  2. @Inject(args = "{.}/plugins/Clann/configItem.conf")
  3. ConfigWrapper configWrapper;
  4. // 配置采用注入的方式
  5. @Configure(value = "modules.autoSave.interval", comment = "间隔(s)")
  6. private long saveInterval = 600; //10分钟保存一次
  7. // 重载插件时的回调
  8. @ReLoad
  9. public void reload() {
  10.     // doSomething
  11. }
复制代码

?    自定义数据的 创建/读取/保存

  1. // 定义一个数据文件
  2. @Ignore
  3. @Inject(args = {"{.}/data/clann/blocklog"})
  4. FileDataHolder dataFile;

  5. // 读取数据
  6. @Load
  7. public void load() {
  8.     if (!dataFile.exist()) {
  9.         dataFile.save(this);
  10.     } else {
  11.         dataFile.fill(this);
  12.     }
  13. }

  14. // 保存数据
  15. public void save() {
  16.     dataFile.save(this);
  17. }
复制代码

?    数据库连接的....

  1. // 创建一个数据库连接,(本框架使用h2数据库)
  2. @Inject(id = AutoBackup.dataSourceId, args = "${Clann:modules.backupInv.jdbcUrl}")
  3. SqlSource sqlSource;

  4. // 创建一个PreparedStatement
  5. @Inject(depends = {AutoBackup.dataSourceId}, args = {AutoBackup.dataSourceId
  6.     , "SELECT id,created,player,temp,invId FROM " + BackupTable.tableName
  7.     + " where player=? and temp=1 order by id desc limit 1"})
  8. private PreparedStatement getTemp;

  9. // 创建一个数据库表
  10. @Inject(id = BackupTable.tableName, depends = AutoBackup.dataSourceId)
  11. @Table(BackupTable.tableName)
  12. public class BackupTable implements Pojo {
  13.     public static final String tableName = "clann_invbackup";
  14.     // some column define
  15. }
复制代码

?    插件加载时,各种java对象的初始化,装配....

  1. // 依赖注入,实现Listener的Service会自动注册监听器
  2. @Service(successMsg = "检测到MOD:应用能源,监听器**"
  3.         , needClass = "appeng.core.AppEng"
  4.         , enableConfigPath = "enable"
  5.         , comment = "是否启用")
  6. public class Appliedenergistics2 implements Listener {
  7.     // 依赖注入
  8.     @Inject
  9.     AEFixer plugin;
  10.     @Inject
  11.     WorldUtils worldUtils;
  12.     @Inject
  13.     TileEntityUtils tileEntityUtils;
  14.     @Inject
  15.     NBTCompoundUtils nbtCompoundUtils;

  16.     // 配置注入
  17.     @Configure(value = "singleController", comment = "是否禁止CPU相邻放置(防止网络规模过大)")
  18.     private boolean singleController = true;
  19.     @Configure(value = "protectWorkingCPU", comment = "是否禁止破坏正在工作的CPU(总感觉有问题)")
  20.     private boolean protectWorkingCPU = true;
  21.     @Configure(value = "safeCPU", comment = "是否禁止CPU跨区块放置(刷物品)")
  22.     private boolean safeCPU = true;

  23.     // 插件生命周期
  24.     @Load
  25.     private void load(){
  26.         // do something
  27.     }

  28.     // 插件生命周期
  29.     @Reload
  30.     private void reload(){
  31.         // do something
  32.     }

  33.     // 插件生命周期
  34.     @UnLoad
  35.     private void unload(){
  36.         // do something
  37.     }

  38. }
复制代码

?    根据各种条件判断是启用某个功能

  1. // Class.forName("appeng.core.AppEng")不抛异常
  2. // 配置文件中 enable为true
  3. // 插件Essentials存在
  4. // 物品DIAMOND存在(可用来判断mod是否存在)
  5. // AEFixer实例化的Service存在
  6. // 满足以上条件才会加载此Service
  7. @Service(successMsg = "检测到MOD:应用能源,监听器**"
  8.         , needClass = "appeng.core.AppEng"
  9.         , enableConfigPath = "enable"
  10.         , comment = "是否启用"
  11.         , needPlugin = "Essentials"
  12.         , needItemType = "DIAMOND"
  13.         , depend = AEFixer.class)
  14. public class Appliedenergistics2 {
  15. }
复制代码

?    制作指令时,无限if else,各种参数解析,权限判断简直烦死,

  1. // 指令/pluginloader reload [<plugin>]的实现类
  2. @Service
  3. public class LoaderCommand extends ICommand {

  4.     public LoaderCommand() {
  5.         super("PluginLoader", "pluginloader");
  6.     }

  7.     // @CommandAnnotation可以控制这条指令执行所需权限,是否要OP,是否必须玩家才能执行
  8.     // 会自动解析参数
  9.     // 这只是个例子
  10.     // 实现指令,不需要op权限,有mplayer的玩家才能执行 /pluginloader tp <x> <y> <z> [<world>]
  11.     // 没有world参数时,为当前世界
  12.     @CommandAnnotation(permission = "mplayer", needOp = false, mustPlayer = true, args = "<x> <y> <z> [<world>]", des = "重载插件")
  13.     public void tp(@Sender Player sender, int x, int y, int z, @OptionalParam World world) {
  14.         if (world == null) {
  15.             world = sender.getWorld();
  16.         }
  17.         // do something
  18.     }

  19.     // 实现/pluginloader reload [<plugin>]
  20.     @CommandAnnotation(args = "[<plugin>]", des = "重载插件")
  21.     public void reload(@Sender CommandSender sender, @OptionalParam String plugin) {
  22.         if (plugin == null) {
  23.             plugin = "";
  24.         }
  25.         logger.info("开始重载插件{}", plugin);
  26.         sender.sendMessage("开始重载插件" + plugin);

  27.         Stopwatch watch = Stopwatch.createStarted();
  28.         List<ServiceHolder> services = BeanContext.getServices();

  29.         String pluginId = plugin;

  30.         services.stream()
  31.                 .forEach(s -> {
  32.                     if (!StringUtils.isEmpty(pluginId) && !s.getPlugin().getId().equalsIgnoreCase(pluginId)) {
  33.                         return;
  34.                     }
  35.                     try {
  36.                         //重载默认配置文件
  37.                         s.getPlugin().setConfigNode(s.getPlugin().getConfigLoader().load());
  38.                         long count = ConfigUtils.injectConfigure(s.getPlugin().getConfigNode(), s.getHandle());
  39.                         if (count > 0) {
  40.                             logger.info("重载配置:" + s.getId());
  41.                         }
  42.                     } catch (Throwable e) {
  43.                         logger.error("配置注入失败:" + s.getId(), e);
  44.                     }
  45.                 });
  46.         LoaderUtils.invokeMethods(services, Reload.class, "reload");
  47.         this.plugin.saveConfig();
  48.         watch.stop();
  49.         sender.sendMessage("重载完毕,耗时" + watch.elapsed(TimeUnit.MILLISECONDS) + "ms");
  50.     }
  51. }
复制代码

?    mns的混淆名查找,记不住啊。。。神烦

  1. // 假设服务器是多线,怎么能知道玩家连接的是服务器的哪个ip呢
  2. // 这里使用反射拿到玩家对应的nettyChannel,反射使用的名字全是为混淆的名字,会根据1.7.10的混淆规则自动映射混淆的方法
  3. public String getServerIp(Player p) {
  4.          //常规方式
  5.         WrapClass<? extends Player> wc = ClassUtils.wrap(p.getClass());
  6.         WrapField wentity = wc.getField("entity");
  7.         WrapField wplayerNetServerHandler = ClassUtils.wrap(wentity.getType()).getField("playerNetServerHandler");
  8.         WrapField wnetManager = ClassUtils.wrap(wplayerNetServerHandler.getType()).getField("netManager");
  9.         WrapMethod wchannel = ClassUtils.wrap(wnetManager.getType()).getMethod("channel");
  10.         io.netty.channel.Channel channel0 = (Channel) wchannel.invoke(wnetManager.get(wplayerNetServerHandler.get(wentity.get(p))));

  11.         //快捷方式,链式调用
  12.         io.netty.channel.Channel channel = Invoker.of(p)
  13.                 .get("entity")
  14.                 .get("playerNetServerHandler")
  15.                 .get("netManager")
  16.                 .invoke("channel")
  17.                 .get();
  18.         return channel.localAddress().toString().replaceFirst("/", "").split(":", 2)[0];
  19. }
复制代码

?    等等。。。。。

鉴于以上情况,特开发了这个插件框架来加快插件开发速度,并最大程度优化以上情况

ps:此后本人所有其他插件均会直接依赖此插件

关于Minecraft版本

因为本人只在1.7.10下开服,所以目前只支持1.7.10

指令

只有一个指令 /pluginloader reload [<plugin>]    用于重载所有/指定插件的插件(当然前提是在此框架下开发的插件)

下载

因为打包了很多类库,所以很大Orz。。

最近很穷啊,希望各位大佬在笑纳时顺便评分赏赏金粒吧

地址
链接:https://pan.baidu.com/s/1saTd4ADpyT7D-uIJGJLEAg  密码:7a88

余枫
非优秀禁止使用回复可见

xiaoQQQa
网盘炸了呀

xiaoQQQa

好像是我的问题......
没事了非常优秀

dafd
非常不错的插件

play7770
66666666666666666

play7770
6666666666666666666666666

youqing123
有个有没有UTF-8呢

莫斯图迪
youqing123 发表于 2019-7-8 13:43
有个有没有UTF-8呢

和编码没关系
此插件已弃坑
用新的SpringBootPlugin

虎牙安言
bbs有你更精彩

第一页 上一页 下一页 最后一页