• 欢迎加入MineBBS QQ讨论群:点击查看所有的官方讨论群
  • 我们将于近期对服务器进行迁移,服务可能中断至多2日。请各位安排好自己的访问计划,造成不便敬请谅解!
  • MineBBS入站考试已经上线!想要成为【正式会员】解锁更多功能吗?快来参与吧!【点我去看】
[饰品背包]SuperInventory-1.12.2-1.21.4

原创 闭源 [饰品背包]SuperInventory-1.12.2-1.21.4 2.0.2

请登录后获取
修复了当玩家进入服务器时,若穿戴饰品过多,则会出现的饰品加载不完全的问题
填坑了填坑了填坑了
超级背包也加上模块功能了,配置方式与旧版的饰品背包有点区别
内置三个基础模块:飞行、药水、指令
示例JS模块:跳跃
模块的触发方式与旧版也有些区别,改为了触发器的形式
默认触发器有:左键、右键、Q(丢弃物品)、F(交换手中物品)、破坏方块、定时触发

接下来就是重头戏了
JS脚本扩展
插件现在添加了NashornJS插件作为软依赖,若不使用js模块,则可以不安装
这里提供一个下载地址:https://wwaos.lanzouu.com/iDmdv3rieved

安装后,插件会读取models文件夹中的JS脚本,作为模块添加到超级背包中
编写的方式也很简单,如果不会写,就把示例的两个JS脚本都丢给AI吧,AI是人类的好帮手

API拓展
另外一种拓展模块的方式为编写插件,插件提供了注册模块的API
这里给一个示例的挖矿模块

配置方式如下
YAML:
# 测试挖矿戒指
testMining:
  checkName: "&a测试挖矿戒指"
  special:
    onEquip:
      cooldown: 0
      models:
        - model: "mining"
          content: "GRASS_BLOCK:player:say 我挖掘了草方块"
        - model: "mining"
          content: "DIRT:player:say 我挖掘了土方块"
    # 移除时需填写对应content,防止监听器移除失败
    onUnequip:
      cooldown: 0
      models:
        - model: "mining"
          content: "GRASS_BLOCK:player:say 我挖掘了草方块"
        - model: "mining"
          content: "DIRT:player:say 我挖掘了土方块"
Java:
// 在主类中注册模块
@Override
public void onEnable() {
    if (Bukkit.getPluginManager().getPlugin("SuperInventory") != null) {
        SuperInventory si = (SuperInventory) Bukkit.getPluginManager().getPlugin("SuperInventory");
        miningModule = new MiningModule(this);
        miningModule.register();
        si.getSpecialManager().registerModule(miningModule);
        getLogger().info("已注册特殊模块: mining");
   } else {
        getLogger().warning("SuperInventory 未加载,挖矿模块注册失败");
   }
}

// 模块类,按需重写 onActivate(装备饰品时触发)、onTrigger(激活时触发)、onTrigger(拆卸饰品时触发)
public class MiningModule implements SpecialModule, Listener {

    private final JavaPlugin plugin;

    // Player UUID -> list of (material, executorType, command)
    private final Map<UUID, List<MiningConfig>> playerConfigs = new HashMap<>();

    public MiningModule(JavaPlugin plugin) {
        this.plugin = plugin;
    }

    /**
     * 注册事件监听,需在模块注册后调用一次
     */
    public void register() {
        plugin.getServer().getPluginManager().registerEvents(this, plugin);
    }
   
    @Override
    public String getType() {
        // 模块名
        return "mining";
    }

    @Override
    public void onActivate(Player player, SpecialModel model, String triggerType) {
        addConfig(player, model.getContent());
    }

    @Override
    public void onTrigger(Player player, SpecialModel model, String triggerType) {
        // onBreak 由 BlockBreakEvent 处理器处理,此处不重复处理
    }

    @Override
    public void onDeactivate(Player player, SpecialModel model, String triggerType) {
        removeConfig(player, model.getContent());
    }

    @EventHandler
    public void onBlockBreak(BlockBreakEvent event) {
        Player player = event.getPlayer();
        List<MiningConfig> configs = playerConfigs.get(player.getUniqueId());
        if (configs == null || configs.isEmpty()) return;

        Material brokenType = event.getBlock().getType();
        for (MiningConfig config : configs) {
            if (config.material == brokenType) {
                executeCommand(player, config);
            }
        }
    }

    private void addConfig(Player player, String content) {
        MiningConfig config = parseContent(content);
        if (config == null) return;

        playerConfigs.computeIfAbsent(player.getUniqueId(), k -> new ArrayList<>()).add(config);
        plugin.getLogger().info("玩家 " + player.getName() + " 激活了挖矿模块: " + content);
    }

    private void removeConfig(Player player, String content) {
        List<MiningConfig> configs = playerConfigs.get(player.getUniqueId());
        if (configs == null) return;

        configs.removeIf(c -> c.content.equals(content));
        if (configs.isEmpty()) {
            playerConfigs.remove(player.getUniqueId());
            plugin.getLogger().info("玩家 " + player.getName() + " 清除所有挖矿模块");
        }
    }

    private MiningConfig parseContent(String content) {
        if (content == null || content.isEmpty()) return null;

        String[] parts = content.split(":", 3);
        if (parts.length < 3) {
            plugin.getLogger().warning("挖矿模块配置格式错误,应为 BLOCK_TYPE:executor:command,实际: " + content);
            return null;
        }

        Material material = Material.matchMaterial(parts[0].toUpperCase());
        if (material == null) {
            plugin.getLogger().warning("未知的方块类型: " + parts[0]);
            return null;
        }

        String executor = parts[1].toLowerCase();
        if (!"player".equals(executor) && !"console".equals(executor)) {
            plugin.getLogger().warning("执行类型必须是 player 或 console,实际: " + parts[1]);
            return null;
        }

        String command = parts[2];
        if (command.isEmpty()) {
            plugin.getLogger().warning("指令不能为空");
            return null;
        }

        return new MiningConfig(material, executor, command, content);
    }

    private void executeCommand(Player player, MiningConfig config) {
        String cmd = config.command;
        switch (config.executor) {
            case "player":
                player.performCommand(cmd);
                break;
            case "console":
                Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd);
                break;
        }
    }

    private static class MiningConfig {
        final Material material;
        final String executor;
        final String command;
        final String content; // 原始 content,用于移除时匹配

        MiningConfig(Material material, String executor, String command, String content) {
            this.material = material;
            this.executor = executor;
            this.command = command;
            this.content = content;
        }
    }
}
新增page页面配置项 disableSame ,用于禁止同名饰品装备到同一个背包中

YAML:
# 背包设置
inventory:
  page: 2 #页数,可进行拓展分页
  size: 54 # 背包大小(9的倍数)
  #具体设置每一页的title,如果不设置则为默认的§6饰品背包(请注意,不同页面的title不建议相同,哪怕是新的背包文件)
  name:
    - "§6饰品背包 第一页"
    - "§6饰品背包 第二页"
  drop: false #开启饰品背包死亡掉落(当玩家死亡时,背包数据清空,饰品会掉落在原地
  #是否禁止同名饰品装备(默认false)
  #开启后,在该背包中,玩家不能装备同名的饰品
  disableSame: false

#消息设置
message:
  activeSuit: "§f[§6饰品背包§f] §a已激活套装: §6<套装名>§a-§b<件数>"
  drop: "§f[§6超级背包§f] §c饰品掉落了!"
  condition: "§f[§6饰品背包§f] §c条件不满足!"
  disableDismantle: "§f[§6饰品背包§f] §c禁止拆卸饰品"
  # 新增的信息配置项
  disableSame: "§f[§6饰品背包§f] §c禁止装备同名饰品"
隐藏槽位需要通过其他槽位装备了特定名字饰品进行解锁

据说灵感来源于诅咒饰品 :嘿嘿:

启用方法为在page的页面中,添加一个hideSlot节点,该节点于message、sound同级,所以直接写进去就好

YAML:
#槽位隐藏\显示
# 当玩家将特定的饰品装备后,才会显示隐藏的槽位(槽位隐藏后,不会读取属性)
hideSlot:
  example:
    # 当装备上该名字的饰品(包含匹配)后,才会显示隐藏的槽位
    itemName: "&e测试耳环"
    # 隐藏的槽位(格式:<页数>:<槽位名>)
    slot:
      - "1:ring"
  example2:
    # 当装备上该名字的饰品(包含匹配)后,才会显示隐藏的槽位
    itemName: "&e测试腰带"
    # 隐藏的槽位(格式:<页数>:<槽位名>)
    slot:
      - "2:ring"
  • 喜欢
反馈: a3
有用户反馈本插件的物品库可设置的选项太小了
于是我写了一个桥接的接口,可让用户自行编写物品来源 :开车:

给一个简单的Mythicmobs插件的物品库接口栗子
Java:
@Override
public void onEnable() {
    // 确保 SuperInventory 已加载
    if (Bukkit.getPluginManager().getPlugin("SuperInventory") != null) {
        SuperInventory plugin = (SuperInventory) Bukkit.getPluginManager().getPlugin("SuperInventory");
        plugin.getItemManager().registerItemLibrary(new MythicItemLibrary());
        getLogger().info("已注册物品库命名空间: mm");
    }
}

class MythicItemLibrary(private val logger: Logger) : ItemLibrary {

    override fun getNamespace(): String {
        return "mm"
    }

    override fun getItem(itemKey: String): ItemStack? {
        return try {
            MythicBukkit.inst().itemManager.getItemStack(itemKey)
        } catch (e: Exception) {
            logger.warning("获取MythicMobs物品失败: $itemKey - ${e.message}")
            null
        }
    }
}

写好之后编译成插件,就可以在游戏中使用 /superinventory set Drbiaodi example 1 10 mm:SkeletonKingSword (mm:key)

将玩家指定背包中的指定页数,指定槽位设置为mm中的物品
  • 喜欢
反馈: a3
新增拥有指定lore饰品不可拆卸功能

在主配置config中
setting:
# 是否开启debug信息
Debug: false
# 是否允许套装重复激活
SuitRepeat: true
# 禁止拆卸饰品
# 当饰品拥有其中以下任意一个lore时,禁止拆卸饰品
DisableDismantle:
- "禁止拆卸饰品"
  • 喜欢
反馈: a3
如题,需在配置文件修改后重启服务器
后退
顶部 底部