Repository navigation
3.3 Preparing the Fabric Project Template
This task transforms the official Fabric example mod into a parameterized template that supports generating projects targeting Minecraft 26.2 or later. Key changes include: removing Yarn mappings, using the non-remapping Loom plugin, upgrading to Java 25, Gradle 9.5.1, replacing modImplementation with implementation, and removing all Mixin and client entrypoints (the current MVP only generates items, so these are not needed).
Note: This task only prepares the template. It does not generate item code, so the template does not call ModItemsGenerated, nor does it verify game execution. Full compilation and runtime verification will be done after Tasks 6, 7, and 8 are complete.
| Item | Value |
|---|---|
| Minecraft | 26.2 |
| Fabric Loader | 0.19.5 |
| Loom | 1.17-SNAPSHOT |
| Fabric API | 0.161.0+26.2 |
| Gradle | 9.5.1 |
| Java | 25 |
cd ~/modsmith
git clone https://github.com/FabricMC/fabric-example-mod.git \
modsmith/templates/fabric-project
rm -rf modsmith/templates/fabric-project/.gitVerify:
ls modsmith/templates/fabric-project/You should see build.gradle, gradle.properties, src/, etc.
Since the current ModSmith MVP only generates items, Mixin and client entrypoints are not needed. Delete the following:
# Delete the client source directory
rm -rf modsmith/templates/fabric-project/src/client
# Delete all Mixin config files
rm -f modsmith/templates/fabric-project/src/main/resources/*.mixins.json
# Delete the client entrypoint class (if present)
rm -f modsmith/templates/fabric-project/src/main/java/com/example/client/ExampleModClient.java
# Delete the empty client package directory
rm -rf modsmith/templates/fabric-project/src/main/java/com/example/clientOpen modsmith/templates/fabric-project/gradle.properties and replace with:
# Gradle
org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
# Fabric Properties
minecraft_version={{ minecraft_version }}
loader_version={{ fabric_loader_version }}
loom_version={{ loom_version }}
# Mod Properties
mod_version={{ mod_version }}
maven_group={{ package_name }}
archives_base_name={{ mod_id }}
# Dependencies
fabric_version={{ fabric_api_version }}Notes:
-
yarn_mappingshas been removed because 26.2 uses Mojang official mappings. - All version numbers use Jinja2 placeholders, filled by the
render_projectcontext.
Open modsmith/templates/fabric-project/build.gradle and replace the entire file with:
plugins {
id 'net.fabricmc.fabric-loom' version "${loom_version}"
id 'maven-publish'
}
version = project.mod_version
group = project.maven_group
base {
archivesName = project.archives_base_name
}
repositories {
// Add a domestic mirror here if needed
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
// 26.2+ no longer requires the mappings line
implementation "net.fabricmc:fabric-loader:${project.loader_version}"
implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
}
processResources {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
tasks.withType(JavaCompile).configureEach {
it.options.encoding = "UTF-8"
it.options.release = 25
}
java {
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
}
jar {
from("LICENSE") {
rename { "${it}_${project.base.archivesName.get()}" }
}
}Key changes:
- Plugin ID:
net.fabricmc.fabric-loom(non-remapping version). - Removed the
mappingsline. -
modImplementation→implementation. - Java version upgraded to 25.
Open modsmith/templates/fabric-project/gradle/wrapper/gradle-wrapper.properties and change distributionUrl to:
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zipOpen modsmith/templates/fabric-project/src/main/resources/fabric.mod.json and replace the entire file with:
{
"schemaVersion": 1,
"id": "{{ mod_id }}",
"version": "{{ mod_version }}",
"name": "{{ mod_name }}",
"description": "{{ mod_description }}",
"authors": [
"{{ author }}"
],
"contact": {},
"license": "MIT",
"icon": "assets/{{ mod_id }}/icon.png",
"environment": "*",
"entrypoints": {
"main": [
"{{ package_name }}.ExampleMod"
]
},
"depends": {
"fabricloader": ">={{ fabric_loader_version }}",
"minecraft": "~{{ minecraft_version }}",
"java": ">=25",
"fabric-api": "*"
}
}Key changes:
-
Removed the
cliententrypoint: the current MVP does not generate client classes. -
Removed the
mixinsfield: the current MVP does not need Mixin. -
javarequires>=25. -
minecraftuses~{{ minecraft_version }}.
Open modsmith/templates/fabric-project/src/main/java/com/example/ExampleMod.java and replace with:
package {{ package_name }};
import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExampleMod implements ModInitializer {
public static final String MOD_ID = "{{ mod_id }}";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
@Override
public void onInitialize() {
LOGGER.info("Hello Fabric world from {{ mod_name }}!");
// Note: ModItemsGenerated will be generated in a later task; do not call it here for now
// ModItemsGenerated.initialize();
}
}Key changes:
-
ModItemsGenerated.initialize()is commented out because the class has not been generated yet. - After Task 7 is complete, uncomment it or let the generator add it automatically.
Confirm that there are no Mixin-related files left in the template:
find modsmith/templates/fabric-project -name "*.mixins.json"There should be no output. If there are any, delete them.
Also check whether fabric.mod.json still contains a mixins field:
grep -i "mixin" modsmith/templates/fabric-project/src/main/resources/fabric.mod.jsonThere should be no output.
Once the template files are ready, you need to write a Python script to render them. Create modsmith/generator/project.py:
"""根据蓝图渲染 Fabric 项目模板。"""
import shutil
from pathlib import Path
from jinja2 import Environment, FileSystemLoader
TEMPLATE_DIR = Path(__file__).parent.parent / "templates" / "fabric-project"
def render_project(blueprint: dict, output_dir: Path) -> None:
"""将蓝图渲染到输出目录。
Args:
blueprint: 蓝图字典。
output_dir: 输出项目目录。
"""
# 准备 Jinja2 环境
env = Environment(
loader=FileSystemLoader(str(TEMPLATE_DIR)),
keep_trailing_newline=True,
)
# 准备渲染上下文
context = {
"mod_id": blueprint["mod_id"],
"mod_name": blueprint.get("mod_name", blueprint["mod_id"]),
"mod_description": blueprint.get("description", "A ModSmith generated mod"),
"mod_version": blueprint.get("version", "0.1.0"),
"package_name": blueprint["package_name"],
"package_path": blueprint["package_name"].replace(".", "/"),
"minecraft_version": blueprint["minecraft_version"],
"fabric_loader_version": blueprint["fabric_loader_version"],
"yarn_mappings": blueprint.get("yarn_mappings", "1.21.4+build.1"),
"loom_version": blueprint.get("loom_version", "1.10-SNAPSHOT"),
"fabric_api_version": blueprint.get("fabric_api_version", "0.119.2+1.21.4"),
"author": blueprint.get("author", "ModSmith User"),
}
# 如果输出目录已存在,先删除
if output_dir.exists():
shutil.rmtree(output_dir)
# 遍历模板目录,渲染每个文件
for template_path in TEMPLATE_DIR.rglob("*"):
if template_path.is_dir():
continue
# 计算相对路径
rel_path = template_path.relative_to(TEMPLATE_DIR)
rel_str = str(rel_path)
# 渲染文件路径(处理 {{ mod_id }} 等)
rendered_rel_str = env.from_string(rel_str).render(**context)
rendered_rel_path = Path(rendered_rel_str)
# 处理包名路径替换
if "src/main/java/com/example" in rendered_rel_str:
rendered_rel_str = rendered_rel_str.replace(
"src/main/java/com/example",
f"src/main/java/{context['package_path']}"
)
rendered_rel_path = Path(rendered_rel_str)
output_path = output_dir / rendered_rel_path
output_path.parent.mkdir(parents=True, exist_ok=True)
# 渲染文件内容
content = template_path.read_text(encoding="utf-8")
rendered_content = env.from_string(content).render(**context)
output_path.write_text(rendered_content, encoding="utf-8")
print(f"✅ 项目已生成到: {output_dir}") Create or reuse test_template.py:
from pathlib import Path
from modsmith.generator.project import render_project
blueprint = {
"mod_id": "test-mod",
"mod_name": "Test Mod",
"package_name": "com.testmod",
"minecraft_version": "26.2",
"fabric_loader_version": "0.19.5",
"fabric_api_version": "0.161.0+26.2",
"loom_version": "1.17-SNAPSHOT",
}
render_project(blueprint, Path("./test_output"))Run:
python test_template.pyVerify the generated output:
# Check that version numbers were replaced correctly
cat test_output/gradle.properties
# Check that fabric.mod.json has no mixins and no client
cat test_output/src/main/resources/fabric.mod.json
# Check that there are no .mixins.json files
find test_output -name "*.mixins.json"Compile verification:
cd test_output
./gradlew buildExpected: compilation passes (because ModItemsGenerated is commented out, no error).
Note: Do not run ./gradlew runClient at this point, because the project has no item registration code and lacks resource files; running the game is meaningless. Game runtime verification will be done after Tasks 6, 7, and 8 are complete.
| Problem | Cause | Solution |
|---|---|---|
ClassNotFoundException: ExampleModClient |
fabric.mod.json still declares the client entrypoint |
Remove the client entrypoint |
MixinInitialisationError |
fabric.mod.json still declares the mixins field |
Remove the mixins field and delete all .mixins.json files |
Cannot find symbol: ModItemsGenerated |
ExampleMod.java did not comment out the call |
Comment out ModItemsGenerated.initialize()
|
gradle.properties version not replaced |
Template has hardcoded values instead of placeholders | Confirm the template uses {{ minecraft_version }} etc. |
| Minecraft downloaded again | Cache cleared or version changed | Keep ~/.gradle/caches/fabric-loom and keep versions consistent |
- Template cloned and
.gitremoved. -
src/client/directory and all.mixins.jsonfiles deleted. -
gradle.propertiesversion variables parameterized, noyarn_mappings. -
build.gradleuses thenet.fabricmc.fabric-loomplugin, nomappingsline,implementationinstead ofmodImplementation, Java 25. -
gradle-wrapper.propertiesuses Gradle 9.5.1. -
fabric.mod.jsonhas nomixinsfield, nocliententrypoint,java >=25,minecraft ~26.2. -
ExampleMod.javapackage name andMOD_IDparameterized,ModItemsGenerated.initialize()commented out. -
project.py'srender_project()correctly renders the template and adds executable permission togradlew. -
test_outputgenerated bytest_template.pycompiles via./gradlew build(without running the game).
After completing these steps, your template can generate Fabric projects targeting Minecraft 26.2+, and will not fail to compile due to missing classes generated in later tasks. Next, you can proceed to Task 7 to complete the Java code generator.