原生模组/NModAPI

From Minecraft基岩版开发Wiki

NModAPI文档涵盖了NModAPI的全部内容,且含有少许原生插件编写指南。它由ModelPart、int100和TimScriptov共同编写,支持中文、英文与俄文,使用Apache 2.0协议在GitHub上发布。

本页面是NModAPI的搬运,有少量修改[注 1]。经三位作者同意后,使用CC BY-NC-SA 4.0(即本Wiki的默认协议)授权。

文档中有些内容已经过时,仅供参考用。


NModAPI文档[edit]

其它语言[edit]

NMod是什么?[edit]

NMod的全称是Native-ModNative-Mod通过原生代码(C/C++)来修改Minecraft,所以被称为NMod。

众所周知,MCPE主要由C++编写。NMod比ModPE脚本有着更好的修改效果,为什么不学着去做NMod呢?

但是,制作NMod不是一件易事,因为C++语言比JavaScript更难,以及原生修改方法的操作不是那么容易理解的。以下的内容将告诉你如何开发NMod。

开发准备[edit]

  1. C++基础
  2. 一个支持NDK的Android IDE(如Android Studio, Eclipse, AIDE等)
  3. 知道如何构建Android原生库(*.so
  4. Json语法

链接库[edit]

NMod通过链接libsubstrate.so[注 2]libminecraftpe.so以执行对MCPE的修改。请确保你的NMod已链接至substrate模块与minecraftpe模块(你可以通过阅读我们的实例知悉如何链接这些库)。

事件监听器[edit]

NModAPI为NMod加载完毕、游戏启动与游戏退出三个事件提供了监听器,你只需定义这些方法。当事件发生时,NModAPI将会调用这些方法。

NMod加载完毕(OnLoad)[edit]

NMod_OnLoad(JavaVM* javaVM, JNIEnv* jniEnv, const char* minecraftVersion, const char* nmodApiVersion, const char* pathOflibminecraftpeso)
  • javaVM是一个指向JavaVM的指针。
  • jniEnv是一个指向JNIEnv的指针。
  • minecraftVersion是一个C风格的字符串,内容为当前Minecraft的版本名称。
  • nmodApiVersion是一个C风格的字符串,内容为NModAPI的版本名称。
  • pathOflibminecraftpeso是一个C风格字符串,内容为libminecraftpe.so的路径。你可以使用dlopen装载它:dlopen(pathOflibminecraftpeso, RTLD_LAZY)

游戏启动(OnActivityCreate)[edit]

NMod_OnActivityCreate(JNIEnv* env, jobject thiz, jobject savedInstanceState)
  • env是一个指向JNIEnv的指针。
  • thiz是一个jobject,Java类型签名为[Lcom/mojang/minecraftpe/MainActivity;]
  • savedInstanceState是一个jobject,Java类型签名为[Landroid/os/Bundle;]

游戏退出(OnActivityFinish)[edit]

NMod_OnActivityFinish(JNIEnv* env, jobject thiz)
  • env是一个指向JNIEnv的指针。
  • thiz是一个jobject,Java类型签名为[Lcom/mojang/minecraftpe/MainActivity;]

修改内置方法[edit]

经过以上的步骤后,我们该如何修改Minecraft中的内置方法?

Substrate框架提供了一个修改的方法——MSHookFunction,该方法可以用我们自己定义的方法替换libminecraftpe.so中定义的默认方法,也提供了一个调用默认方法的途径。

调用MSHookFunction方法需要三个参数:

MSHookFunction(
    (void*)& DefaultMethod,
    (void*)& ReplacementMethod,
    (void**)& MethodPointerOfDefaultMethod
);

例如,如果我们想要替换libminecraftpe.so中的Explosion::explode()方法,我们可以这样写:

// 定义默认方法(原方法)
class Explosion
{
    public:
        void explode();
}

// 定义一个函数指针
void (*explode_default)(Explosion*);
void explode_replacement(Explosion* self)
{
    // Do Something

    // 如果不想忽略这次爆炸,请调用函数指针:
    explode_default(self);
}

// 在 NMod_OnLoad 中注册 MSHookFunction 方法
extern "C" void NMod_OnLoad(JavaVM*,JNIEnv*,const char*,const char*,const char*)
{
    MSHookFunction((void*)& Explosion::explode,
                (void*)& explode_replacement,
                (void**)& explode_default);
}

NMod配置[edit]

NModAPI通过读取nmod_manifest.json来获取NMod配置。你也可以在配置中编辑assets下的Json与文本。[注 3]

{
  // 提示:你不用定义该配置文件中的所有内容。
  
  // NMod 名称
  "name" : "My NMod",
  
  // NMod 的包名,必须与 AndroidManifest.xml 中的包名一致。
  "package_name" : "my.nmod.package.name",
  
  // NMod 的作者,在此写下你的名字或组织名。
  "author" : "Me or My Company",
  
  // NMod 原生库
  "native_libs_info" :
  [
    {
      // 原生库名,必须与你的库名一致。
      "name" : "libmynmodlib.so",

      //  NMod 是否使用 NModAPI
      // 如果你使用了事件监听器(NMod_OnLoad, NMod_OnActivityCreate,
      //   NMod_OnActivityFinish),use_api 必须为 true 
      "use_api" : "true"
    }
    
    // 你还可以在此加载更多库
    //,
    //{
    //  "name" : "libmynmodlib2.so",
    //  "use_api" : false
    //}
  ],
  
  // NMod 版本号
  // 默认值为 -1 
  "version_code" : 1,
  
  // NMod 版本名
  "version_name" : "1.0",

  // Minecraft 版本名
  "minecraft_version_name" : "1.11.0.1",
  
  // NMod 描述
  "description" : "My NMod Description",
  
  // 更新内容
  "change_log" : "My NMod Change Log",
  
  
  // NMod Banner
  // NMod Banner 是在主界面展示的一张图像。
  
  // 图像下方的文本视图,默认值为 NMod 名称(name)。
  "banner_title" : "My NMod is the Best!",
  
  //  assets 文件夹内的图像路径
  // 图像大小必须为 1024(长) * 500(宽)。
  // 在当前设置下,NMod 将会寻找 assets/my_banner.png 
  "banner_image_path" : "my_banner.png"
  
  // 材质文本编辑 API
  // text_edit 允许你编辑 Minecraft PE 中材质的文本文件。
  
  /*
  ,
  "text_edit" :
  [
    {
      // assets 中要修改的的文本文件路径
      // 要替换的文件与默认文件(源文件)必须同时在 NMod  Minecraft PE  assets 中定义。

      // 在当前设置下,NModAPI 将会读取 assets/resource_packs/vanilla/texts/en_US.lang 
      "path" : "resource_packs/vanilla/texts/en_US.lang",
      
      // 有三种编辑模式:append(追加), prepend(前置), replace(替换),默认值为 replace 
      // 如果你定义了一种不存在的模式,编辑将不起作用。
      // append:在源文件后追加文本。
      // prepend:在源文件前追加文本。
      // replace:  NMod assets 中定义的新文本替换源文本。

      // 在当前设置下,NModAPI 将会在默认文本(源文本)后追加要替换的文本。
      "mode" : "append"
    },
    {
      "path" : "resource_packs/vanilla/texts/zh_CN.lang",
      "mode" : "append"
    }
  ]*/
  
  // 材质 Json 编辑 API
  // json_edit 允许你编辑 Minecraft PE 中材质的 Json 文件。
  
  /*
  ,
  "json_edit" :
  [
    {
      // assets 中要修改的 Json 文件路径。
      // 要替换的文件与默认文件(源文件)必须同时在 NMod  Minecraft PE  assets 中定义。
      // 在当前设置下,NModAPI 将会读取 resource_packs/vanilla/textures/item_texture.json
      "path" : "resource_packs/vanilla/textures/item_texture.json",
      
      // 有两种编辑模式:merge(合并),replace(替换),默认值为替换。
      // 如果你定义了一种不存在的模式,编辑将不起作用。
      // merge:合并两个 Json 文件。
      // replace:用 NMod assets 中定义的新 Json 替换源 Json
      // 在当前情况下,NModAPI 将会合并两个 Json 为一个。
      "mode" : "merge"
    }
    
    // 你还可以在此编辑更多的 Json
    //,
    //{
    //  "path" : "File Path",
    //  "mode" : "replace"
    //}
  ]
  */
}

打包你的NMod[edit]

打包成APK[edit]

如果你的NMod被打包成一个APK文件,它可以被Android软件包管理器安装且能被NModAPI读取。

在这种情况下,nmod_manifest.json应该放入assets文件夹内。原生库应该打包进lib/[对应的CPU架构]内。

提示:

  • NModAPI仅读取两种架构:armeabi-v7a以及x86
  • 安装新版本的NMod时,使用Android软件包管理器的NMod可以自动更新。所以这种方式大部分用于开发NMod。

注意:

  • nmod_manifest.json中定义的package_name必须与AndroidManifest.xml中定义的package属性一致。

打包成文件[edit]

不喜欢安装APK?你还可以将你的NMod打包成一个文件!它的扩展名可以为*.apk, *.zip, *.nmod, *.mcnmod

在这种情况下,nmod_manifest.json可以放入assets文件夹或NMod的根目录。

提示:

  • 打包成文件的NMod不能自动更新,所以这种方式大部分用于发布NMod。

注意:

  • 不要在不同路径中同时放置两个nmod_manifest.json

仍然不理解?[edit]


注解[edit]

  1. 修改仅限于使用wikitext排版、删去中英文间空格和添加注解。主要内容的修改应提交至GitHub。
  2. 请注意,Cydia Substrate不支持64位Android。
  3. minecraft_version_name仅在蓝版ModdedPE中可用。