使用Scala为Minecraft的Forge Mod编写

我将简单记录如何使用Scala在2021/04/07时点上开发Minecraft 1.16.5的Mod(FML)。我只会创建一个简单的消息输出部分。基本上按照Minecraft Wiki上的Java方法进行操作。如有遗漏或更正之处,请不吝指正。

环境Minecraft 1.16.5
Forge 1.16.5-36.1.0
JDK 1.8.0_281
Scala 2.13.4

我的世界版本是1.16.5
Forge版本是1.16.5-36.1.0
JDK版本是1.8.0_281
Scala版本是2.13.4

sbtは使わずgradleでビルドします。

安装根据Minecraft Wiki页面的指导,使用IntelliJ IDEA搭建环境。如果不需要,可以跳过附加说明并整理概述。

需要您已经安装了IntelliJ IDEA。

1. 准备MDK您可以从 Forge 的发布网站的“显示所有版本”页面下载 Forge 的 MDK(Mod Development Kit),并解压缩zip文件中的内容。

    • gradle/

 

    • src/

 

    • build.gradle

 

    • gradlew

 

    gradlew.bat

将其放置在项目文件夹中。

请按照以下方式更改build.gradle文件。我认为这是解除混淆时的名称映射(没有详细研究)。

mappings channel: 'official', version: '1.16.5'
mappings channel: 'snapshot', version: '20210309-1.16.5'

将项目导入IntelliJ IDEA打开IntelliJ IDEA,并从“打开文件或项目”选项中选择build.gradle文件进行导入。初次导入可能需要一些时间。当导入完成后,屏幕的右侧将会出现Gradle标签,然后执行Tasks/fg_runs/genIntellijRuns。

随着1的地图更改,将”src/main/ExampleMod.java”文件修改如下。

LOGGER.info("Got game settings {}", event.getMinecraftSupplier().get().options);
LOGGER.info("Got game settings {}", event.getMinecraftSupplier().get().gameSettings);

3. 更改名字由于采用了 ExampleMod,我们将更改名称。截至2021年4月7日,Minecraft Wiki页面正在编写中,因此我们将进行记录。

更改Mod名字和ModID我将编辑mods.toml文件。将会修改[[mods]]中的modId。其他关于mod的信息在[[mods]]中,您可以根据需要进行修改或添加。下面是一个例子。

折叠

然后,编辑ExampleMod.java文件。

将@Mod注解的参数部分与mods.toml相同。同时更改类名。建议如下(我已查看了IronChests的源码)。

@Mod(Chalcedony.MODID)
class Chalcedony{
    public static final String MODID =  "MOD ID";

    // ... 処理

}
更改包名尽情使用
在Scala中,尽管包名和目录结构不一致也没有问题,但按照Java的习惯来保持一致似乎是惯例。

让您能够使用Scala因为如果保持原样,将无法使用Scala进行编码,所以要进行一些设置。如果将整个程序都用Scala编写,就无法从FML进行引用1,因此只在被FML调用的部分使用Java进行编写2。

在IntelliJ IDEA中添加Scala插件。请在”文件”->”设置”->”插件”中搜索并安装Scala插件。安装完成后需要重新启动编辑器。

编辑build.gradle我在这个地方踌躇了一下(第一步是寻找无法全部用Scala编写的原因)。

添加Scala插件将以下内容添加到根目录下。在一开始就应用了net.minecraftforge.gradle和maven-publish的地方,可以在那里添加。

apply plugin: 'scala'
Java文件和Scala文件的联合
这里是关键。大约在第114行左右。

sourceSets.main.resources { srcDir 'src/generated/resources' }

以中国本土语言进行改写,仅需要一种选项:

sourceSets {
    main {
        scala {
            srcDirs = ['src/main/scala', 'src/main/java']
        }
        java {
            srcDirs = []
        }
        resources {
            srcDir 'src/generated/resources'
        }
    }
}

我会进行如下的更改: 3。

样本
在Scala中编写逻辑以显示已登录用户的消息,并在主类中进行注册。

package ex.client

// import省略

class LoginMessage(){
  @SubscribeEvent
  def onPlayerLoggedIn(event: PlayerEvent.PlayerLoggedInEvent): Unit = {
    val player = event.getPlayer
    val pos = player.getPosition
    val message = s"""
                     |Hello, World
                     |name = [${player.getName.getString}]
                     |pos  = [${pos.getX}. ${pos.getY}, pos.getZ]
    """.stripMargin
    player.sendMessage(new StringTextComponent(message), player.getUniqueID)
  }
}
package ex

// import省略
import ex.client.LoginMessage;

@Mod(TestMod.MODID)
class TestMod{
    public static final String MODID =  "testmod";
    private static final Logger LOGGER = LogManager.getLogger();

    public Chalcedony() {
        final IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
        bus.addListener(this::setup);
        bus.addListener(this::enqueueIMC);
        bus.addListener(this::processIMC);
        bus.addListener(this::doClientStuff);

        MinecraftForge.EVENT_BUS.register(this);
        MinecraftForge.EVENT_BUS.register(new LoginMessage());
    }

    // ... 処理
}

引用的文章参考:https://qiita.com/niwasawa/items/ca565091468abce48f53

Note: The provided link cannot be accessed for paraphrasing as it is against OpenAI’s use case policy to browse the internet. However, I can help with other requests or answer any questions you may have.

据参考:https://stackoverflow.com/questions/17401565/instantiating-a-scala-class-using-reflection-javas-newinstance 和 https://github.com/scala/bug/issues/3276 ,当将Scala编译为JVM的中间语言时,由于会在名称后添加$后缀,因此无法引用单例对象(伴生类)的构造函数,并会抛出IllegalAccessException异常。

此外,似乎还有一些支持Scala的MDK和Scorge等工具,但貌似不必使用它们也可以进行开发。

我们将src/main/java目录下的文件作为Scala而不是Java进行加载(由于Scala只是Java的扩展,所以Java代码可以被解释为Scala),从而解决了包的依赖关系。

bannerAds