minecraft-multiloader
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMinecraft Multiloader Skill (Architectury)
Minecraft 多加载器 Skill(Architectury)
What Is Architectury?
什么是 Architectury?
Architectury is a framework that
lets you write one mod codebase that compiles to both NeoForge and Fabric JARs.
The common subproject has a shared API; platform subprojects implement
platform-specific behavior behind the abstraction.
@ExpectPlatformArchitectury 是一个框架,可让您只编写一套模组代码库,即可编译为 NeoForge 和 Fabric JAR。common 子项目提供共享 API;平台子项目通过 抽象实现平台特定行为。
@ExpectPlatformRouting Boundaries
适用边界
- : one shared codebase must build and ship both NeoForge and Fabric artifacts.
Use when - : the project is single-loader only (
Do not use whenfor NeoForge/Fabric, not both).minecraft-modding - : the task is Paper/Bukkit plugin development (
Do not use when).minecraft-plugin-dev
| Component | Purpose |
|---|---|
| Gradle plugin — extends Fabric Loom for multiloader support |
| Runtime library — abstractions over both platforms |
| Annotation marking methods with platform-specific implementations |
| Shared code (no loader-specific APIs) |
| Fabric-specific code + entrypoint |
| NeoForge-specific code + entrypoint |
- :必须使用一套共享代码库来构建并发布 NeoForge 和 Fabric 构件时。
Use when - :项目仅支持单一加载器时(对于 NeoForge/Fabric,使用
Do not use when,而不是本 Skill)。minecraft-modding - :任务是 Paper/Bukkit 插件开发时(
Do not use when)。minecraft-plugin-dev
| 组件 | 用途 |
|---|---|
| Gradle 插件——扩展 Fabric Loom 以支持多加载器 |
| 运行时库——为两个平台提供抽象 |
| 标注具有平台特定实现的方法的注解 |
| 共享代码(不包含加载器特定 API) |
| Fabric 特定代码和入口点 |
| NeoForge 特定代码和入口点 |
Versions (Minecraft 1.21.11)
版本(Minecraft 1.21.11)
properties
undefinedproperties
undefinedgradle.properties property names used by this skill's static helper.
gradle.properties property names used by this skill's static helper.
Get every tool version from the exact generated or known-working project.
Get every tool version from the exact generated or known-working project.
mod_version=1.0.0
minecraft_version=1.21.11
enabled_platforms=fabric,neoforge
architectury_version=<project pin>
fabric_loader_version=<project pin>
fabric_api_version=<project pin ending in +1.21.11>
neoforge_version=<project pin in the 21.11.x family>
loom_version=<project pin>
Pin `architectury_version`, the Architectury plugin version, and `loom_version`
from the same generated or known-working project line. This skill deliberately
does not publish a copyable dependency matrix: its static helper cannot resolve
whether a particular set of versions is compatible.
For Minecraft 26.x / Java 25, use the official
[Architectury Template Generator](https://generate.architectury.dev/) only when
its version selector offers the exact target. Generate a **Multiplatform**
project with Fabric and NeoForge, then preserve the generated Gradle layout and
pins as one set. If the generator does not offer the target, begin with an
already working project on that exact line and inspect its resolved build; do
not relabel a 1.21.11 template as 26.x. The published template downloads are
not a substitute for an exact-current scaffold.
Do not mechanically change only `minecraft_version` in the retained example:
26.x is unobfuscated and its Loom/remapping setup differs from 1.21.11.mod_version=1.0.0
minecraft_version=1.21.11
enabled_platforms=fabric,neoforge
architectury_version=<project pin>
fabric_loader_version=<project pin>
fabric_api_version=<project pin ending in +1.21.11>
neoforge_version=<project pin in the 21.11.x family>
loom_version=<project pin>
将 `architectury_version`、Architectury 插件版本和 `loom_version` 固定到同一个生成项目或已知可用项目系列中的版本。本 Skill 有意不提供可直接复制的依赖版本矩阵,因为其静态辅助程序无法解析特定版本组合是否兼容。
对于 Minecraft 26.x / Java 25,仅当官方 [Architectury Template Generator](https://generate.architectury.dev/) 的版本选择器提供精确的目标版本时才使用它。生成一个同时包含 Fabric 和 NeoForge 的 **Multiplatform** 项目,然后将生成的 Gradle 布局及版本固定项作为一套整体保留。如果生成器不提供目标版本,请从该精确版本系列中一个已经可用的项目开始,并检查其解析后的构建配置;不要将 1.21.11 模板重新标记为 26.x。已发布的模板下载不能替代与当前精确版本匹配的脚手架。
不要在保留的示例中只机械地修改 `minecraft_version`:26.x 未混淆,且其 Loom/remapping 设置与 1.21.11 不同。Bundled References And Helpers
内置参考资料和辅助工具
- Version alignment reference:
references/architectury-reference.md - Sanity checker:
./scripts/check-version-sanity.sh --root <project>
Run the sanity checker after editing . It is a static
syntax-and-version-family preflight: it catches missing keys, snapshot pins,
missing / platforms, and obvious version-family drift. It
does not resolve dependencies, prove loader compatibility, or replace the
project's Fabric and NeoForge build and smoke tests.
gradle.propertiesfabricneoforge- 版本对齐参考:
references/architectury-reference.md - 健全性检查器:
./scripts/check-version-sanity.sh --root <project>
编辑 后运行健全性检查器。它是一项静态语法和版本系列预检:能够发现缺失的键、快照版本固定、缺失的 / 平台,以及明显的版本系列偏移。它不能解析依赖关系、证明加载器兼容性,也不能替代项目的 Fabric 和 NeoForge 构建及冒烟测试。
gradle.propertiesfabricneoforgeRoot Project Layout
根项目布局
my-mod/
├── build.gradle ← root build (shared config)
├── settings.gradle
├── gradle.properties
├── common/
│ ├── build.gradle
│ └── src/main/java/com/example/mymod/
│ ├── MyMod.java ← shared init
│ ├── registry/
│ │ └── ModItems.java ← shared registry declarations
│ └── platform/
│ └── PlatformHelper.java ← @ExpectPlatform methods
├── fabric/
│ ├── build.gradle
│ └── src/main/
│ ├── java/com/example/mymod/fabric/
│ │ ├── MyModFabric.java ← Fabric entrypoint
│ ├── java/com/example/mymod/platform/
│ │ └── PlatformHelperImpl.java ← Fabric @ExpectPlatform implementation
│ └── resources/
│ ├── fabric.mod.json
│ └── assets/...
└── neoforge/
├── build.gradle
└── src/main/
├── java/com/example/mymod/neoforge/
│ ├── MyModNeoForge.java ← NeoForge @Mod entry
├── java/com/example/mymod/platform/
│ └── PlatformHelperImpl.java ← NeoForge @ExpectPlatform implementation
└── resources/
├── META-INF/neoforge.mods.toml
└── assets/...my-mod/
├── build.gradle ← root build (shared config)
├── settings.gradle
├── gradle.properties
├── common/
│ ├── build.gradle
│ └── src/main/java/com/example/mymod/
│ ├── MyMod.java ← shared init
│ ├── registry/
│ │ └── ModItems.java ← shared registry declarations
│ └── platform/
│ └── PlatformHelper.java ← @ExpectPlatform methods
├── fabric/
│ ├── build.gradle
│ └── src/main/
│ ├── java/com/example/mymod/fabric/
│ │ ├── MyModFabric.java ← Fabric entrypoint
│ ├── java/com/example/mymod/platform/
│ │ └── PlatformHelperImpl.java ← Fabric @ExpectPlatform implementation
│ └── resources/
│ ├── fabric.mod.json
│ └── assets/...
└── neoforge/
├── build.gradle
└── src/main/
├── java/com/example/mymod/neoforge/
│ ├── MyModNeoForge.java ← NeoForge @Mod entry
├── java/com/example/mymod/platform/
│ └── PlatformHelperImpl.java ← NeoForge @ExpectPlatform implementation
└── resources/
├── META-INF/neoforge.mods.toml
└── assets/...Legacy Build Template
旧版构建模板
The old fixed Gradle scripts were a 1.21.11 snapshot and are intentionally not
presented as a current scaffold. For either supported version, read
or
before changing generated build files. They preserve version anchors and
source-set boundaries without encouraging a partial build script to be copied
into a different Minecraft line.
references/legacy-1.21.11-template.mdreferences/architectury-reference.md旧的固定 Gradle 脚本基于 1.21.11 快照,因此有意不将其作为当前脚手架展示。对于任一受支持版本,在修改生成的构建文件之前,请阅读 或 。这些参考会保留版本锚点和 source set 边界,同时避免将部分构建脚本复制到其他 Minecraft 版本系列。
references/legacy-1.21.11-template.mdreferences/architectury-reference.mdShared Common Code
共享通用代码
common/.../MyMod.java
common/.../MyMod.javacommon/.../MyMod.java
common/.../MyMod.javajava
package com.example.mymod;
import dev.architectury.registry.registries.DeferredRegister;
import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.Item;
public class MyMod {
public static final String MOD_ID = "mymod";
// Architectury's DeferredRegister — works on both platforms
public static final DeferredRegister<Item> ITEMS =
DeferredRegister.create(MOD_ID, Registries.ITEM);
public static final RegistrySupplier<Item> MY_ITEM =
ITEMS.register("my_item", () -> new Item(new Item.Properties().setId(
ResourceKey.create(Registries.ITEM,
Identifier.fromNamespaceAndPath(MOD_ID, "my_item"))
)));
public static void init() {
ITEMS.register(); // registers with both platforms
}
}java
package com.example.mymod;
import dev.architectury.registry.registries.DeferredRegister;
import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.Item;
public class MyMod {
public static final String MOD_ID = "mymod";
// Architectury's DeferredRegister — works on both platforms
public static final DeferredRegister<Item> ITEMS =
DeferredRegister.create(MOD_ID, Registries.ITEM);
public static final RegistrySupplier<Item> MY_ITEM =
ITEMS.register("my_item", () -> new Item(new Item.Properties().setId(
ResourceKey.create(Registries.ITEM,
Identifier.fromNamespaceAndPath(MOD_ID, "my_item"))
)));
public static void init() {
ITEMS.register(); // registers with both platforms
}
}@ExpectPlatform
— platform-specific methods
@ExpectPlatform@ExpectPlatform
——平台特定方法
@ExpectPlatformDefine the contract in :
common/java
package com.example.mymod.platform;
import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraft.world.level.material.Fluid;
public class PlatformHelper {
@ExpectPlatform
public static boolean isModLoaded(String modId) {
// This body is replaced at compile time by the platform implementation
throw new AssertionError("ExpectPlatform implementation not found");
}
@ExpectPlatform
public static boolean isClient() {
throw new AssertionError();
}
}Keep each platform implementation in the same Java package as the common
class. Only the source set changes between ,
, and .
@ExpectPlatformcommon/fabric/neoforge/Implement in :
fabric/.../platform/PlatformHelperImpl.javajava
package com.example.mymod.platform;
import net.fabricmc.loader.api.FabricLoader;
// Class name must match: <common class name>Impl
public class PlatformHelperImpl {
public static boolean isModLoaded(String modId) {
return FabricLoader.getInstance().isModLoaded(modId);
}
public static boolean isClient() {
return FabricLoader.getInstance().getEnvironmentType() ==
net.fabricmc.api.EnvType.CLIENT;
}
}Implement in :
neoforge/.../platform/PlatformHelperImpl.javajava
package com.example.mymod.platform;
import net.neoforged.fml.ModList;
import net.neoforged.fml.loading.FMLEnvironment;
public class PlatformHelperImpl {
public static boolean isModLoaded(String modId) {
return ModList.get().isLoaded(modId);
}
public static boolean isClient() {
return FMLEnvironment.dist.isClient();
}
}在 中定义契约:
common/java
package com.example.mymod.platform;
import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraft.world.level.material.Fluid;
public class PlatformHelper {
@ExpectPlatform
public static boolean isModLoaded(String modId) {
// This body is replaced at compile time by the platform implementation
throw new AssertionError("ExpectPlatform implementation not found");
}
@ExpectPlatform
public static boolean isClient() {
throw new AssertionError();
}
}确保每个平台的实现与 common 中 类位于同一个 Java 包中。只有 source set 会因 、 和 而异。
@ExpectPlatformcommon/fabric/neoforge/在 中实现:
fabric/.../platform/PlatformHelperImpl.javajava
package com.example.mymod.platform;
import net.fabricmc.loader.api.FabricLoader;
// Class name must match: <common class name>Impl
public class PlatformHelperImpl {
public static boolean isModLoaded(String modId) {
return FabricLoader.getInstance().isModLoaded(modId);
}
public static boolean isClient() {
return FabricLoader.getInstance().getEnvironmentType() ==
net.fabricmc.api.EnvType.CLIENT;
}
}在 中实现:
neoforge/.../platform/PlatformHelperImpl.javajava
package com.example.mymod.platform;
import net.neoforged.fml.ModList;
import net.neoforged.fml.loading.FMLEnvironment;
public class PlatformHelperImpl {
public static boolean isModLoaded(String modId) {
return ModList.get().isLoaded(modId);
}
public static boolean isClient() {
return FMLEnvironment.dist.isClient();
}
}Fabric Entrypoint
Fabric 入口点
fabric/.../MyModFabric.java
fabric/.../MyModFabric.javafabric/.../MyModFabric.java
fabric/.../MyModFabric.javajava
package com.example.mymod.fabric;
import com.example.mymod.MyMod;
import net.fabricmc.api.ModInitializer;
public class MyModFabric implements ModInitializer {
@Override
public void onInitialize() {
MyMod.init();
}
}java
package com.example.mymod.fabric;
import com.example.mymod.MyMod;
import net.fabricmc.api.ModInitializer;
public class MyModFabric implements ModInitializer {
@Override
public void onInitialize() {
MyMod.init();
}
}fabric/.../resources/fabric.mod.json
fabric/.../resources/fabric.mod.jsonfabric/.../resources/fabric.mod.json
fabric/.../resources/fabric.mod.jsonThis retained-1.21.11 metadata example follows the minimum dependencies in the
upstream Architectury 1.21.11 branch.
Keep the generated project's exact ranges when they are stricter.
json
{
"schemaVersion": 1,
"id": "mymod",
"version": "${version}",
"name": "My Mod",
"description": "A multiloader example mod",
"license": "MIT",
"environment": "*",
"entrypoints": {
"main": ["com.example.mymod.fabric.MyModFabric"]
},
"depends": {
"fabricloader": ">=0.18.2",
"fabric-api": ">=0.139.4+1.21.11",
"architectury": ">=19.0",
"minecraft": "~1.21.11"
}
}此保留的 1.21.11 元数据示例遵循 上游 Architectury 1.21.11 分支 中的最低依赖项。如果生成项目中的版本范围更严格,请保留其精确范围。
json
{
"schemaVersion": 1,
"id": "mymod",
"version": "${version}",
"name": "My Mod",
"description": "A multiloader example mod",
"license": "MIT",
"environment": "*",
"entrypoints": {
"main": ["com.example.mymod.fabric.MyModFabric"]
},
"depends": {
"fabricloader": ">=0.18.2",
"fabric-api": ">=0.139.4+1.21.11",
"architectury": ">=19.0",
"minecraft": "~1.21.11"
}
}NeoForge Entrypoint
NeoForge 入口点
neoforge/.../MyModNeoForge.java
neoforge/.../MyModNeoForge.javaneoforge/.../MyModNeoForge.java
neoforge/.../MyModNeoForge.javajava
package com.example.mymod.neoforge;
import com.example.mymod.MyMod;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.common.Mod;
@Mod(MyMod.MOD_ID)
public class MyModNeoForge {
public MyModNeoForge(IEventBus modEventBus) {
MyMod.init();
}
}java
package com.example.mymod.neoforge;
import com.example.mymod.MyMod;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.common.Mod;
@Mod(MyMod.MOD_ID)
public class MyModNeoForge {
public MyModNeoForge(IEventBus modEventBus) {
MyMod.init();
}
}neoforge/.../resources/META-INF/neoforge.mods.toml
neoforge/.../resources/META-INF/neoforge.mods.tomlneoforge/.../resources/META-INF/neoforge.mods.toml
neoforge/.../resources/META-INF/neoforge.mods.tomltoml
modLoader = "javafml"
loaderVersion = "[1,)"
license = "MIT"
[[mods]]
modId = "mymod"
version = "${file.jarVersion}"
displayName = "My Mod"
description = "A multiloader example mod"
[[dependencies.mymod]]
modId = "neoforge"
type = "required"
versionRange = "[21.11,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.mymod]]
modId = "minecraft"
type = "required"
versionRange = "[1.21.11,1.22)"
ordering = "NONE"
side = "BOTH"toml
modLoader = "javafml"
loaderVersion = "[1,)"
license = "MIT"
[[mods]]
modId = "mymod"
version = "${file.jarVersion}"
displayName = "My Mod"
description = "A multiloader example mod"
[[dependencies.mymod]]
modId = "neoforge"
type = "required"
versionRange = "[21.11,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.mymod]]
modId = "minecraft"
type = "required"
versionRange = "[1.21.11,1.22)"
ordering = "NONE"
side = "BOTH"Build Commands
构建命令
bash
undefinedbash
undefinedBuild both JARs simultaneously
Build both JARs simultaneously
./gradlew build
./gradlew build
Inspect the project's actual outputs. Generated templates choose their own
Inspect the project's actual outputs. Generated templates choose their own
archive base name and version convention:
archive base name and version convention:
find fabric/build/libs neoforge/build/libs -maxdepth 1 -type f -name '.jar'
! -name '-sources.jar' ! -name '-dev.jar' ! -name '-javadoc.jar'
! -name '-sources.jar' ! -name '-dev.jar' ! -name '-javadoc.jar'
find fabric/build/libs neoforge/build/libs -maxdepth 1 -type f -name '.jar'
! -name '-sources.jar' ! -name '-dev.jar' ! -name '-javadoc.jar'
! -name '-sources.jar' ! -name '-dev.jar' ! -name '-javadoc.jar'
Run in dev environment
Run in dev environment
./gradlew :fabric:runClient
./gradlew :neoforge:runClient
./gradlew :neoforge:runServer
./gradlew :fabric:runClient
./gradlew :neoforge:runClient
./gradlew :neoforge:runServer
Datagen (if applicable)
Datagen (if applicable)
./gradlew :neoforge:runData
---./gradlew :neoforge:runData
---Common Pitfalls
常见问题
| Pitfall | Solution |
|---|---|
Using | Only use vanilla MC and Architectury APIs in common |
Direct field access on | Use Architectury's |
| Constructing a 26.x item without a registry key | Create its |
Forgetting | Both |
| Assets duplicated in fabric/ and neoforge/ | Keep assets in |
| A common Mixin imports a loader API or targets one loader's side | Put it in that platform subproject; loader-neutral Mixins may be common when both generated platform configurations include them |
| Accessing world/registry on mod init thread | Use |
| 常见问题 | 解决方案 |
|---|---|
在 | 在 common 中仅使用 Minecraft 原版 API 和 Architectury API |
在 common 中以 NeoForge 风格直接访问 | 使用 Architectury 的 |
| 创建 26.x 物品时未提供 registry key | 创建其 |
忘记 | |
在 | 将 assets 放在 |
| common Mixin 导入加载器 API 或仅针对某一个加载器 | 将其放入相应平台子项目;如果两个生成平台配置都包含该 Mixin,则与加载器无关的 Mixin 可以放在 common 中 |
| 在 mod init 线程访问 world/registry | 使用 mod bus 事件进行 setup;初始化时绝不访问 world |
References
参考资料
- Architectury API GitHub: https://github.com/architectury/architectury-api
- Architectury API 26.2 source branch: https://github.com/architectury/architectury-api/tree/26.2
- Architectury API 1.21.11 source branch: https://github.com/architectury/architectury-api/tree/1.21.11
- Architectury Loom: https://github.com/architectury/architectury-loom
- Architectury templates: https://github.com/architectury/architectury-templates
- Architectury Template Generator: https://generate.architectury.dev/
- Architectury docs: https://docs.architectury.dev/
- Architectury API GitHub:https://github.com/architectury/architectury-api
- Architectury API 26.2 源码分支:https://github.com/architectury/architectury-api/tree/26.2
- Architectury API 1.21.11 源码分支:https://github.com/architectury/architectury-api/tree/1.21.11
- Architectury Loom:https://github.com/architectury/architectury-loom
- Architectury 模板:https://github.com/architectury/architectury-templates
- Architectury Template Generator:https://generate.architectury.dev/
- Architectury 文档:https://docs.architectury.dev/