使用 Scorge 编写基于 Scala 的 Mod
从 Minecraft 1.13 开始,Forge 不再自带 Scala 标准库作为依赖(作为一个 Scala 吹,这让我很不爽),但 Forge 也为 Scala 提供了一个名为 Scorge 的解决方案。
Scorge 这个项目相当低调,虽然我很快就从 GitHub 上找到了 Scorge 的源代码,但我翻遍了 CurseForge 都没有找到 Scorge 这个 Mod 本身的下载链接,最后通过对 URL 的连蒙带猜从 Forge 官网上找到了下载地址(目前的最新版本是 3.0.6):http://files.minecraftforge.net/maven/net/minecraftforge/Scorge
虽然说他们的代码仍然是基于 1.14 的,但事实上 1.15 也能用,本文将基于 Minecraft 1.15.2 和 Forge 31.2.0,使用的 Gradle 版本是 5.6.4。
构建文件
让我们先从 build.gradle
开始:
buildscript {
repositories {
maven {
url = 'https://files.minecraftforge.net/maven'
}
jcenter()
mavenCentral()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
}
}
apply plugin: 'scala'
apply plugin: 'net.minecraftforge.gradle'
version = '1.0.0'
group = 'com.github.ustc-zzzz'
archivesBaseName = 'ScorgeExampleMod'
sourceCompatibility = targetCompatibility = '1.8'
minecraft {
mappings channel: 'snapshot', version: '20200514-1.15.1'
runs {
client {
properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP'
properties 'forge.logging.console.level': 'debug'
workingDirectory project.file('run')
source sourceSets.main
}
server {
properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP,CLASSLOADING'
properties 'forge.logging.console.level': 'debug,trace'
workingDirectory project.file('run')
source sourceSets.main
}
}
}
dependencies {
minecraft 'net.minecraftforge:forge:1.15.2-31.2.0'
compile 'org.scala-lang:scala-library:2.13.1'
compile 'net.minecraftforge:Scorge:3.0.6'
}
jar {
manifest.attributes([
"Specification-Title" : "scorgeexamplemod",
"Specification-Vendor" : "scorgeexamplemodsareus",
"Specification-Version" : "1", // We are version 1 of ourselves
"Implementation-Title" : project.name,
"Implementation-Version" : project.version,
"Implementation-Vendor" : "scorgeexamplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
一方面,和基于 Java 的项目相比,基于 Scala 的项目需要 apply plugin: 'scala'
才行。
另一方面,我们需要留意 dependency
块的变化:
dependencies {
minecraft 'net.minecraftforge:forge:1.15.2-31.2.0'
compile 'org.scala-lang:scala-library:2.13.1'
compile 'net.minecraftforge:Scorge:3.0.6'
}
我们不仅要引入 Scorge 的依赖,还需要引入 Scala 标准库的依赖(请保证 Scala 标准库版本和 Scorge 所使用的版本一致,这里是 2.13.1)。
主类
然后我们随便写一个主类:
package com.github.ustc_zzzz
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
import net.minecraftforge.scorge.lang.ScorgeModLoadingContext
import org.apache.logging.log4j.LogManager
class ScorgeExampleMod {
ScorgeModLoadingContext.get.getModEventBus.addListener { _: FMLCommonSetupEvent =>
LogManager.getLogger(classOf[ScorgeExampleMod]).info("Hello Scorge Example Mod!")
}
}
这里有三点需要注意:
- 我们不需要为主类添加
@Mod
注解。 - 和 1.12 或更低版本不同,Scorge 要求主类是
class
而不是object
。 - 需要使用
ScorgeModLoadingContext
而非FMLJavaModLoadingContext
获取事件总线。
得益于 Scala 编译器从 2.12 开始能够将相关代码编译到 Lambda 表达式,我们可以直接使用 Lambda 表达式块的格式向事件总线注册监听器(1.12 或更低不行,因为使用的是 Scala 2.11)。
因为主类没有 @Mod
注解,所以如果想要在游戏启动的时候看到这句话,我们还需要修改 META_INF
目录下的 mods.toml
。
Mod 描述文件
只有我们在 mods.toml
中指定了主类名,我们才能让 Scorge 加载我们的 Mod 主类:
modLoader="scorge"
loaderVersion="[3,)"
[[mods]]
version="1.0.0"
authors="ustc-zzzz"
modId="scorgeexamplemod"
displayName="Scorge Example Mod"
description="Scorge Example Mod"
entryClass="com.github.ustc_zzzz.ScorgeExampleMod"
[[dependencies.watersprayer]]
modId="forge"
mandatory=true
versionRange="[31,)"
ordering="NONE"
side="BOTH"
[[dependencies.watersprayer]]
modId="minecraft"
mandatory=true
versionRange="[1.15.2]"
ordering="NONE"
side="BOTH"
注意以下两点:
modLoader
应取为scorge
,而loaderVersion
应使用 Scorge 版本。- 和基于 Java 的 Mod 相比,我们还需要额外指定一个
entryClass
描述主类的位置。
现在打开游戏就可以看到这句话了(别忘了把 Scorge 本体放进 mods
目录):