OracleLoadstar/SCE-Universe_Java_Edition
用户指南Mod加载器

Mod冲突

Mod加载器是SCE-Universe Java Edition系统的一个核心组件,它允许用户通过安装外部插件(Mods)来扩展游戏功能和内容。本文档将详细介绍Mod加载器如何工作,特别是它如何处理Mod冲突,以及用户和Mod开发者应如何理解和应对这些冲突。

概述

SCE-Universe Java Edition的Mod加载器提供了一种机制,用于在运行时动态发现、加载和集成外部JAR文件形式的Mod。这些Mod可以实现特定的接口并提供元数据,从而在系统中注册其功能。虽然这种机制为扩展性带来了便利,但同时也引入了Mod之间潜在冲突的风险。当前Mod加载器处理冲突的方式是“后来者居上”:如果多个Mod使用相同的唯一标识符(即Mod名称),则最后加载的Mod将覆盖之前加载的同名Mod。

架构

Mod加载器的核心组件是modlist类,它负责扫描指定目录下的Mod JAR包,并加载实现modloader_main接口的类。每个Mod通过@target注解提供其元数据,如名称、作者和版本。加载的Mod实例及其元数据分别存储在静态映射modlist_coremodlist_List中,供系统其他部分(如UI路由和Mod列表显示)访问。

加载图表中...

Sources:

架构解释: modlist类是Mod加载的核心,它负责从pluginsplugins/preload目录中识别并加载Mod。Mod必须是一个JAR文件,其中包含一个实现了modloader_main接口且被@target注解标记的主类。加载器会实例化这个主类并调用其onEnable()方法。Mod的实例被存储在modlist_core映射中,而其元数据(如Mod名称、作者、版本、描述)则存储在modlist_List映射中。其他系统组件(如router_core用于处理Mod的页面和输入,modlist_page用于显示已加载Mod的列表)通过这些静态映射来访问和使用Mod。

Mod冲突的检测与处理

当前的Mod加载器实现中,Mod冲突主要发生在Mod名称重复的情况下。当加载器发现一个Mod的@target注解中定义的name属性与已加载Mod的名称相同时,它不会抛出错误或进行复杂的冲突解决,而是直接用新加载的Mod覆盖掉旧的Mod。这意味着最后加载的同名Mod将是唯一生效的Mod。

冲突处理流程

加载图表中...

Source: modlist.java

流程解释:

  1. Mod加载器开始扫描Mod目录。
  2. 对于每个发现的Mod JAR文件,它会尝试解析出Mod的主类及其@target注解提供的Mod名称。
  3. 如果Mod名称已经在modlist_coremodlist_List映射中存在,那么当前的Mod将直接覆盖掉之前注册的同名Mod。这是一个“后来者居上”的策略,没有提供额外的冲突解决逻辑。
  4. 无论是否发生覆盖,Mod的onEnable()方法都会被调用。
  5. 这个过程会重复,直到所有Mod JAR文件都被处理完毕。

潜在的冲突类型

  • Mod名称冲突 (Name Collision): 最直接的冲突类型。如果两个不同的Mod在@target注解中定义了相同的name,则会发生覆盖。
  • 类名冲突 (Class Overwrites): 尽管modlist.java会过滤一些常见的系统库,但如果两个Mod包含相同包名和类名的自定义类,可能会导致URLClassLoader加载其中一个,而另一个被忽略,或者在运行时出现意外行为。
  • 资源冲突 (Resource Conflicts): 如果多个Mod尝试修改或访问相同的游戏内部资源(如数据文件、配置设置、游戏对象),这可能导致不可预测的行为、数据损坏或崩溃。Mod加载器本身不提供针对此类冲突的内置解决方案,这通常需要Mod开发者之间的协作或用户手动调整加载顺序。

解决与预防Mod冲突

对于Mod开发者

  1. 使用唯一Mod名称: 确保您的Mod在@target注解中使用的name是全局唯一的。推荐使用类似Java包名的命名规范,如yourcompany.yourmodname

    java
    1// 示例:定义一个Mod的主类 2@target(name = "cn.oraclestar.mod.MyUniqueMod", author = "YourName", version = "1.0.0", Description = "这是一个独特的Mod") 3public class MyUniqueMod implements modloader_main { 4 // ... 实现方法 5}

    Source: target.java (用于@target注解定义) Source: modlist.java (用于获取Mod信息和实例化)

  2. 避免全局变量和静态状态的滥用: 尽量将Mod的逻辑封装在实例中,并最小化对全局共享资源的直接修改,以减少与其他Mod的隐式冲突。

  3. 提供配置选项: 允许用户通过配置文件调整Mod的行为,以便在与其他Mod冲突时进行兼容性调整。

  4. 清晰的文档: 为您的Mod提供清晰的文档,说明其功能、依赖项以及已知的兼容性问题。

对于用户

  1. 注意Mod名称: 如果您安装了多个Mod,请检查它们的名称。如果发现同名Mod,系统将只加载最后一个。

  2. 利用“preload”目录: Mod加载器会优先加载plugins/preload目录下的Mod,然后再加载plugins目录下的Mod。

    java
    1// modlist.java中的加载顺序 2// _loadmod() (加载 plugins/preload) --> loadmod() (加载 plugins) 3// 如果 plugins/preload 中的 Mod A 与 plugins 中的 Mod A' 名称相同, 4// 则 Mod A' (plugins 中的 Mod) 会覆盖 Mod A (preload 中的 Mod)。 5// 若希望 preload 中的 Mod 优先,需要确保 plugins 中没有同名 Mod, 6// 或者 Mod 具有不同的名称。 7public void loadmod(){ 8 // ... 从 "plugins" 目录加载 Mod 9} 10public void _loadmod(){ 11 // ... 从 "plugins/preload" 目录加载 Mod 12}

    Source: modlist.java (loadmod方法) Source: modlist.java (_loadmod方法)

  3. 少量Mod测试: 逐步添加Mod并测试,以便在出现问题时更容易识别是哪个Mod导致了冲突。

  4. 查阅Mod文档: 许多Mod会提供关于兼容性和已知冲突的信息。

Mod加载器核心接口

cn.oraclestar.sce.system.modloader.modloader_main

Mod主类必须实现的接口,定义了Mod的生命周期方法。

java
1package cn.oraclestar.sce.system.modloader; 2 3public interface modloader_main { 4 final String pluginName = ""; // 注意:在接口中,final String 字段必须初始化,但在实现中通常被忽略 5 final String version = ""; // 在接口中定义时,它们是常量,不是Mod的实际动态信息 6 void onEnable(); 7 void onDisable(); 8 void innerToPage(cn.oraclestar.sce.system.UI.UI_core ui_core,int now_page); 9 int innerHandle(String Input,int now_page); 10}

Source: modloader_main.java

方法:

  • onEnable(): Mod加载时调用的方法。Mod开发者应在此处执行初始化逻辑。
  • onDisable(): Mod卸载时调用的方法。Mod开发者应在此处执行清理逻辑。
  • innerToPage(UI_core ui_core, int now_page): 允许Mod在特定UI页面上进行渲染或交互。
  • innerHandle(String Input, int now_page): 允许Mod处理特定UI页面的用户输入。

@cn.oraclestar.sce.system.modloader.target

用于为modloader_main实现类提供元数据的注解。Mod的唯一名称、作者、版本和描述都通过此注解定义。

java
1package cn.oraclestar.sce.system.modloader; 2 3import java.lang.annotation.ElementType; 4import java.lang.annotation.Retention; 5import java.lang.annotation.RetentionPolicy; 6import java.lang.annotation.Target; 7 8@Target(ElementType.TYPE) 9@Retention(RetentionPolicy.RUNTIME) 10public @interface target { 11 String name(); 12 String author() default "未知"; 13 String version() default "未知版本"; 14 String Description() default "未知描述"; 15}

Source: target.java

属性:

  • name() (String): Mod的唯一标识符。这是决定Mod是否会与其他Mod冲突的关键属性。强烈建议使用唯一名称。
  • author() (String): Mod的作者。默认为"未知"。
  • version() (String): Mod的版本。默认为"未知版本"。
  • Description() (String): Mod的描述。默认为"未知描述"。

相关链接

On this page