[*] Introduce Fabric helper and adjust a bunch of stuff
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@ build/
|
|||||||
!gradle/wrapper/gradle-wrapper.jar
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
!**/src/main/**/build/
|
!**/src/main/**/build/
|
||||||
!**/src/test/**/build/
|
!**/src/test/**/build/
|
||||||
|
.kotlin/
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
### IntelliJ IDEA ###
|
||||||
.idea/
|
.idea/
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ plugins {
|
|||||||
group = "de.siphalor.tweed5"
|
group = "de.siphalor.tweed5"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":helpers"))
|
implementation(project(":tweed5-conventions-helpers"))
|
||||||
implementation(pluginMarker(libs.plugins.lombok))
|
implementation(pluginMarker(libs.plugins.lombok))
|
||||||
implementation(pluginMarker(libs.plugins.shadow))
|
implementation(pluginMarker(libs.plugins.shadow))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ plugins {
|
|||||||
`java-gradle-plugin`
|
`java-gradle-plugin`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group = "de.siphalor.tweed5"
|
||||||
|
|
||||||
gradlePlugin {
|
gradlePlugin {
|
||||||
plugins.register("minecraftModComponent") {
|
plugins.register("minecraftModComponent") {
|
||||||
id = "de.siphalor.tweed5.minecraft.mod.component"
|
id = "de.siphalor.tweed5.minecraft.mod.component"
|
||||||
|
|||||||
@@ -43,6 +43,20 @@ abstract class MinecraftModComponentPlugin : Plugin<Project> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val modApiElementsConfiguration = project.configurations.consumable("minecraftModApiElements") {
|
||||||
|
attributes {
|
||||||
|
attribute(MinecraftModded.MINECRAFT_MODDED_ATTRIBUTE, objectFactory.named(MinecraftModded.MODDED))
|
||||||
|
attribute(Category.CATEGORY_ATTRIBUTE, objectFactory.named(Category.LIBRARY))
|
||||||
|
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objectFactory.named(LibraryElements.JAR))
|
||||||
|
attribute(Bundling.BUNDLING_ATTRIBUTE, objectFactory.named(Bundling.SHADOWED))
|
||||||
|
attribute(Usage.USAGE_ATTRIBUTE, objectFactory.named(Usage.JAVA_API))
|
||||||
|
|
||||||
|
project.afterEvaluate {
|
||||||
|
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, targetJvmVersion.get().toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val apiConfiguration = project.configurations.named("api")
|
val apiConfiguration = project.configurations.named("api")
|
||||||
val modSourcesElementsConfiguration = project.configurations.consumable("minecraftModSourcesElements") {
|
val modSourcesElementsConfiguration = project.configurations.consumable("minecraftModSourcesElements") {
|
||||||
extendsFrom(apiConfiguration.get())
|
extendsFrom(apiConfiguration.get())
|
||||||
@@ -57,6 +71,9 @@ abstract class MinecraftModComponentPlugin : Plugin<Project> {
|
|||||||
modComponent.addVariantsFromConfiguration(modElementsConfiguration.get()) {
|
modComponent.addVariantsFromConfiguration(modElementsConfiguration.get()) {
|
||||||
mapToMavenScope("runtime")
|
mapToMavenScope("runtime")
|
||||||
}
|
}
|
||||||
|
modComponent.addVariantsFromConfiguration(modApiElementsConfiguration.get()) {
|
||||||
|
mapToMavenScope("compile")
|
||||||
|
}
|
||||||
modComponent.addVariantsFromConfiguration(modSourcesElementsConfiguration.get()) {
|
modComponent.addVariantsFromConfiguration(modSourcesElementsConfiguration.get()) {
|
||||||
mapToOptional()
|
mapToOptional()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
include("helpers")
|
include(":tweed5-conventions-helpers")
|
||||||
|
project(":tweed5-conventions-helpers").projectDir = file("helpers")
|
||||||
|
|
||||||
rootProject.name = "tweed5-conventions"
|
rootProject.name = "tweed5-conventions"
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.toVersion(libs.versions.java.main.get())
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
targetCompatibility = JavaVersion.toVersion(libs.versions.java.main.get())
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
val testAgent = configurations.dependencyScope("mockitoAgent")
|
val testAgent = configurations.dependencyScope("mockitoAgent")
|
||||||
|
|||||||
@@ -6,14 +6,40 @@ plugins {
|
|||||||
id("de.siphalor.tweed5.minecraft.mod.component")
|
id("de.siphalor.tweed5.minecraft.mod.component")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
tasks.shadowJar {
|
tasks.shadowJar {
|
||||||
relocate("org.apache.commons", "de.siphalor.tweed5.shadowed.org.apache.commons")
|
relocate("org.apache.commons", "de.siphalor.tweed5.shadowed.org.apache.commons")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val processMinecraftModResources = tasks.register<Sync>("processMinecraftModResources") {
|
||||||
|
inputs.property("id", project.name)
|
||||||
|
inputs.property("version", project.version)
|
||||||
|
inputs.property("name", properties["module.name"])
|
||||||
|
inputs.property("description", properties["module.description"])
|
||||||
|
inputs.property("repoUrl", properties["git.url"])
|
||||||
|
|
||||||
|
from(project.layout.settingsDirectory.dir("../tweed5-minecraft/mod-template/resources"))
|
||||||
|
expand(mapOf(
|
||||||
|
"id" to project.name.replace('-', '_'),
|
||||||
|
"version" to project.version,
|
||||||
|
"name" to properties["module.name"],
|
||||||
|
"description" to properties["module.description"],
|
||||||
|
"repoUrl" to properties["git.url"],
|
||||||
|
))
|
||||||
|
into(project.layout.buildDirectory.dir("minecraftModResources"))
|
||||||
|
}
|
||||||
|
|
||||||
val minecraftModJar = tasks.register<Jar>("minecraftModJar") {
|
val minecraftModJar = tasks.register<Jar>("minecraftModJar") {
|
||||||
group = LifecycleBasePlugin.BUILD_GROUP
|
group = LifecycleBasePlugin.BUILD_GROUP
|
||||||
|
|
||||||
|
dependsOn(processMinecraftModResources)
|
||||||
|
|
||||||
from(zipTree(tasks.shadowJar.get().archiveFile))
|
from(zipTree(tasks.shadowJar.get().archiveFile))
|
||||||
|
from(project.layout.buildDirectory.dir("minecraftModResources"))
|
||||||
|
|
||||||
destinationDirectory.set(layout.buildDirectory.dir("minecraftModLibs"))
|
destinationDirectory.set(layout.buildDirectory.dir("minecraftModLibs"))
|
||||||
}
|
}
|
||||||
@@ -24,11 +50,15 @@ tasks.assemble {
|
|||||||
val minecraftModSourcesJar = tasks.register<Jar>("minecraftModSourcesJar") {
|
val minecraftModSourcesJar = tasks.register<Jar>("minecraftModSourcesJar") {
|
||||||
group = LifecycleBasePlugin.BUILD_GROUP
|
group = LifecycleBasePlugin.BUILD_GROUP
|
||||||
|
|
||||||
|
dependsOn(processMinecraftModResources)
|
||||||
|
|
||||||
from(zipTree(tasks.named<Jar>("sourcesJar").get().archiveFile))
|
from(zipTree(tasks.named<Jar>("sourcesJar").get().archiveFile))
|
||||||
|
from(project.layout.buildDirectory.dir("minecraftModResources"))
|
||||||
|
|
||||||
archiveClassifier = "sources"
|
archiveClassifier = "sources"
|
||||||
destinationDirectory.set(layout.buildDirectory.dir("minecraftModLibs"))
|
destinationDirectory.set(layout.buildDirectory.dir("minecraftModLibs"))
|
||||||
}
|
}
|
||||||
|
|
||||||
artifacts.add("minecraftModElements", minecraftModJar)
|
artifacts.add("minecraftModElements", minecraftModJar)
|
||||||
|
artifacts.add("minecraftModApiElements", minecraftModJar)
|
||||||
artifacts.add("minecraftModSourcesElements", minecraftModSourcesJar)
|
artifacts.add("minecraftModSourcesElements", minecraftModSourcesJar)
|
||||||
|
|||||||
@@ -4,32 +4,6 @@ plugins {
|
|||||||
id("de.siphalor.tweed5.minecraft.mod.base")
|
id("de.siphalor.tweed5.minecraft.mod.base")
|
||||||
}
|
}
|
||||||
|
|
||||||
val processMinecraftModResources = tasks.register<Copy>("processMinecraftModResources") {
|
|
||||||
inputs.property("id", project.name)
|
|
||||||
inputs.property("version", project.version)
|
|
||||||
inputs.property("name", properties["module.name"])
|
|
||||||
inputs.property("description", properties["module.description"])
|
|
||||||
|
|
||||||
from(project.layout.settingsDirectory.dir("../tweed5-minecraft/mod-template/resources"))
|
|
||||||
expand(mapOf(
|
|
||||||
"id" to project.name,
|
|
||||||
"version" to project.version,
|
|
||||||
"name" to properties["module.name"],
|
|
||||||
"description" to properties["module.description"]
|
|
||||||
))
|
|
||||||
into(project.layout.buildDirectory.dir("minecraftModResources"))
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named<Jar>("minecraftModJar") {
|
|
||||||
from(project.layout.buildDirectory.dir("minecraftModResources"))
|
|
||||||
dependsOn(processMinecraftModResources)
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named<Jar>("minecraftModSourcesJar") {
|
|
||||||
from(project.layout.buildDirectory.dir("minecraftModResources"))
|
|
||||||
dependsOn(processMinecraftModResources)
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("minecraftMod") {
|
create<MavenPublication>("minecraftMod") {
|
||||||
|
|||||||
1
tweed5-minecraft/.gitignore
vendored
Normal file
1
tweed5-minecraft/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/*/run/
|
||||||
@@ -6,6 +6,8 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("de.siphalor.tweed5:tweed5-conventions")
|
implementation("de.siphalor.tweed5:tweed5-conventions")
|
||||||
|
implementation("de.siphalor.tweed5:tweed5-conventions-helpers")
|
||||||
implementation(pluginMarker(mcCommonLibs.plugins.fabric.loom))
|
implementation(pluginMarker(mcCommonLibs.plugins.fabric.loom))
|
||||||
implementation(pluginMarker(mcCommonLibs.plugins.jcyo))
|
implementation(pluginMarker(mcCommonLibs.plugins.jcyo))
|
||||||
|
implementation(pluginMarker(libs.plugins.lombok))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
|
import de.siphalor.tweed5.gradle.plugin.minecraft.mod.MinecraftModded
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
|
java
|
||||||
id("fabric-loom")
|
id("fabric-loom")
|
||||||
|
id("de.siphalor.tweed5.expanded-sources-jar")
|
||||||
id("de.siphalor.jcyo")
|
id("de.siphalor.jcyo")
|
||||||
|
id("io.freefair.lombok")
|
||||||
|
id("de.siphalor.tweed5.shadow.explicit")
|
||||||
id("de.siphalor.tweed5.minecraft.mod.base")
|
id("de.siphalor.tweed5.minecraft.mod.base")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,11 +28,20 @@ val shortVersion = project.property("tweed5.version").toString()
|
|||||||
val minecraftVersion = getMcCatalogVersion("minecraft")
|
val minecraftVersion = getMcCatalogVersion("minecraft")
|
||||||
version = "$shortVersion+mc$minecraftVersion"
|
version = "$shortVersion+mc$minecraftVersion"
|
||||||
|
|
||||||
sourceSets {
|
val testmod by sourceSets.creating {
|
||||||
create("testmod") {
|
|
||||||
compileClasspath += sourceSets.main.get().compileClasspath
|
compileClasspath += sourceSets.main.get().compileClasspath
|
||||||
runtimeClasspath += sourceSets.main.get().runtimeClasspath
|
runtimeClasspath += sourceSets.main.get().runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loom {
|
||||||
|
runs {
|
||||||
|
create("testmodClient") {
|
||||||
|
client()
|
||||||
|
name("${properties["module.name"]} Test Mod (client)")
|
||||||
|
source(testmod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createRemapConfigurations(testmod)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For some reason dependencyResolutionManagement from the settings.gradle doesn't seem to be passed through correctly,
|
// For some reason dependencyResolutionManagement from the settings.gradle doesn't seem to be passed through correctly,
|
||||||
@@ -49,6 +63,14 @@ repositories {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
named("testmodRuntimeClasspath") {
|
||||||
|
attributes {
|
||||||
|
attribute(MinecraftModded.MINECRAFT_MODDED_ATTRIBUTE, objects.named(MinecraftModded.MODDED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
minecraft(mcCatalog.findLibrary("minecraft").get())
|
minecraft(mcCatalog.findLibrary("minecraft").get())
|
||||||
mappings(loom.layered {
|
mappings(loom.layered {
|
||||||
@@ -56,6 +78,48 @@ dependencies {
|
|||||||
parchment("org.parchmentmc.data:parchment-$minecraftVersion:${getMcCatalogVersion("parchment")}@zip")
|
parchment("org.parchmentmc.data:parchment-$minecraftVersion:${getMcCatalogVersion("parchment")}@zip")
|
||||||
})
|
})
|
||||||
modImplementation(mcCommonLibs.fabric.loader)
|
modImplementation(mcCommonLibs.fabric.loader)
|
||||||
|
|
||||||
|
compileOnly(libs.jspecify.annotations)
|
||||||
|
|
||||||
|
"testmodImplementation"(sourceSets.main.map { it.output })
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
lombok {
|
||||||
|
version = libs.versions.lombok.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.jar {
|
||||||
|
dependsOn(tasks.processMinecraftModResources)
|
||||||
|
from(project.layout.buildDirectory.dir("minecraftModResources"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.sourcesJar {
|
||||||
|
dependsOn(tasks.processMinecraftModResources)
|
||||||
|
from(project.layout.buildDirectory.dir("minecraftModResources"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<Copy>("processTestmodResources") {
|
||||||
|
inputs.property("id", project.name)
|
||||||
|
inputs.property("version", project.version)
|
||||||
|
inputs.property("name", properties["module.name"])
|
||||||
|
inputs.property("description", properties["module.description"])
|
||||||
|
inputs.property("repoUrl", properties["git.url"])
|
||||||
|
|
||||||
|
from(project.layout.settingsDirectory.dir("../tweed5-minecraft/mod-template/resources")) {
|
||||||
|
expand(mapOf(
|
||||||
|
"id" to project.name.replace('-', '_') + "_testmod",
|
||||||
|
"version" to project.version,
|
||||||
|
"name" to properties["module.name"].toString() + " (test mod)",
|
||||||
|
"description" to properties["module.description"],
|
||||||
|
"repoUrl" to properties["git.url"],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMcCatalogVersion(name: String): String {
|
fun getMcCatalogVersion(name: String): String {
|
||||||
|
|||||||
21
tweed5-minecraft/fabric-helper/build.gradle.kts
Normal file
21
tweed5-minecraft/fabric-helper/build.gradle.kts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
plugins {
|
||||||
|
id("de.siphalor.tweed5.local-runtime-only")
|
||||||
|
id("de.siphalor.tweed5.minecraft.mod.cross-version")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
modCompileOnly(fabricApi.module("fabric-networking-api-v1", mcLibs.versions.fabric.api.get()))
|
||||||
|
compileOnly("de.siphalor.tweed5:tweed5-comment-loader-extension")
|
||||||
|
compileOnly("de.siphalor.tweed5:tweed5-core")
|
||||||
|
compileOnly("de.siphalor.tweed5:tweed5-default-extensions")
|
||||||
|
compileOnly("de.siphalor.tweed5:tweed5-serde-extension")
|
||||||
|
compileOnly("de.siphalor.tweed5:tweed5-serde-gson")
|
||||||
|
|
||||||
|
listOf("fabric-networking-api-v1", "fabric-lifecycle-events-v1").forEach {
|
||||||
|
modTestmodImplementation(fabricApi.module(it, mcLibs.versions.fabric.api.get()))
|
||||||
|
}
|
||||||
|
testmodImplementation(project(":tweed5-bundle", configuration = "minecraftModElements"))
|
||||||
|
testmodImplementation("de.siphalor.tweed5:tweed5-comment-loader-extension")
|
||||||
|
testmodImplementation("de.siphalor.tweed5:tweed5-serde-hjson")
|
||||||
|
testmodImplementation("de.siphalor.tweed5:tweed5-serde-gson")
|
||||||
|
}
|
||||||
2
tweed5-minecraft/fabric-helper/gradle.properties
Normal file
2
tweed5-minecraft/fabric-helper/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module.name = Tweed 5 Fabric Helper
|
||||||
|
module.description = A collection of utility classes to make working with Tweed 5 configurations easier on Fabric.
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package de.siphalor.tweed5.fabric.helper.api;
|
||||||
|
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import de.siphalor.tweed5.commentloaderextension.api.CommentLoaderExtension;
|
||||||
|
import de.siphalor.tweed5.commentloaderextension.api.CommentPathProcessor;
|
||||||
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.data.gson.GsonReader;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
@CommonsLog
|
||||||
|
@Builder
|
||||||
|
public class FabricConfigCommentLoader {
|
||||||
|
private final ConfigContainer<?> configContainer;
|
||||||
|
private final String modId;
|
||||||
|
/**
|
||||||
|
* The prefix of the language keys, <b>without the trailing dot!</b>
|
||||||
|
*/
|
||||||
|
private final String prefix;
|
||||||
|
/**
|
||||||
|
* An optional suffix of the language keys
|
||||||
|
*/
|
||||||
|
private final @Nullable String suffix;
|
||||||
|
|
||||||
|
public void loadCommentsFromLanguageFile(String languageCode) {
|
||||||
|
CommentLoaderExtension commentLoaderExtension = configContainer.extension(CommentLoaderExtension.class)
|
||||||
|
.orElseThrow(() -> new IllegalStateException("CommentLoaderExtension not declared on config"));
|
||||||
|
|
||||||
|
String langFilePath = "assets/" + modId + "/lang/" + languageCode + ".json";
|
||||||
|
|
||||||
|
InputStream langInputStream = getClass().getClassLoader().getResourceAsStream(langFilePath);
|
||||||
|
if (langInputStream == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (TweedDataReader reader = new GsonReader(new JsonReader(new InputStreamReader(langInputStream)))) {
|
||||||
|
commentLoaderExtension.loadComments(
|
||||||
|
reader, new CommentPathProcessor() {
|
||||||
|
@Override
|
||||||
|
public MatchStatus matches(String path) {
|
||||||
|
if (!path.startsWith(prefix)) {
|
||||||
|
return MatchStatus.NO;
|
||||||
|
} else if (path.length() == prefix.length()) {
|
||||||
|
if (suffix != null && !path.endsWith(suffix)) {
|
||||||
|
return MatchStatus.NO;
|
||||||
|
}
|
||||||
|
return MatchStatus.YES;
|
||||||
|
} else if (path.charAt(prefix.length()) != '.') {
|
||||||
|
return MatchStatus.NO;
|
||||||
|
} else if (suffix != null && !path.endsWith(suffix)) {
|
||||||
|
return MatchStatus.MAYBE_DEEPER;
|
||||||
|
} else {
|
||||||
|
return MatchStatus.YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String process(String path) {
|
||||||
|
if (path.equals(prefix)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
path = path.substring(prefix.length() + 1);
|
||||||
|
if (suffix != null) {
|
||||||
|
path = path.substring(0, path.length() - suffix.length());
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed to load comments from language file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
package de.siphalor.tweed5.fabric.helper.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
|
import de.siphalor.tweed5.core.api.container.ConfigContainerSetupPhase;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataWriter;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedSerde;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
||||||
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@CommonsLog
|
||||||
|
public class FabricConfigContainerHelper<T extends @Nullable Object> {
|
||||||
|
@Getter
|
||||||
|
private final ConfigContainer<T> configContainer;
|
||||||
|
private final ReadWriteExtension readWriteExtension;
|
||||||
|
private final @Nullable PatchExtension patchExtension;
|
||||||
|
private final TweedSerde serde;
|
||||||
|
@Getter
|
||||||
|
private final String modId;
|
||||||
|
|
||||||
|
private @Nullable Path tempConfigDirectory;
|
||||||
|
|
||||||
|
public static <T extends @Nullable Object> FabricConfigContainerHelper<T> create(
|
||||||
|
ConfigContainer<T> configContainer,
|
||||||
|
TweedSerde serde,
|
||||||
|
String modId
|
||||||
|
) {
|
||||||
|
if (configContainer.setupPhase() != ConfigContainerSetupPhase.INITIALIZED) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Config container must be fully initialized before creating helper. "
|
||||||
|
+ "Usually you're just missing a call to initialize()"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return new FabricConfigContainerHelper<>(configContainer, serde, modId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FabricConfigContainerHelper(ConfigContainer<T> configContainer, TweedSerde serde, String modId) {
|
||||||
|
this.configContainer = configContainer;
|
||||||
|
this.readWriteExtension = configContainer.extension(ReadWriteExtension.class)
|
||||||
|
.orElseThrow(() -> new IllegalStateException("ReadWriteExtension not declared in config container"));
|
||||||
|
this.patchExtension = configContainer.extension(PatchExtension.class).orElse(null);
|
||||||
|
this.serde = serde;
|
||||||
|
this.modId = modId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T loadAndUpdateInConfigDirectory(Supplier<T> defaultValueSupplier) {
|
||||||
|
T configValue = readConfigInConfigDirectory(defaultValueSupplier);
|
||||||
|
writeConfigInConfigDirectory(configValue);
|
||||||
|
return configValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readPartialConfigInConfigDirectory(T value, Consumer<Patchwork> readContextCustomizer) {
|
||||||
|
if (patchExtension == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"PatchExtension must be declared in config container for partially loading config"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
File configFile = getConfigFile();
|
||||||
|
if (!configFile.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (TweedDataReader reader = serde.createReader(new FileInputStream(configFile))) {
|
||||||
|
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
||||||
|
readContextCustomizer.accept(contextExtensionsData);
|
||||||
|
PatchInfo patchInfo = patchExtension.collectPatchInfo(contextExtensionsData);
|
||||||
|
|
||||||
|
T readValue = readWriteExtension.read(reader, configContainer().rootEntry(), contextExtensionsData);
|
||||||
|
|
||||||
|
patchExtension.patch(configContainer.rootEntry(), value, readValue, patchInfo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed loading config file " + configFile.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T readConfigInConfigDirectory(Supplier<T> defaultValueSupplier) {
|
||||||
|
File configFile = getConfigFile();
|
||||||
|
if (!configFile.exists()) {
|
||||||
|
return defaultValueSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
try (TweedDataReader reader = serde.createReader(new FileInputStream(configFile))) {
|
||||||
|
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
||||||
|
return readWriteExtension.read(reader, configContainer.rootEntry(), contextExtensionsData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed loading config file " + configFile.getAbsolutePath(), e);
|
||||||
|
return defaultValueSupplier.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeConfigInConfigDirectory(T configValue) {
|
||||||
|
File configFile = getConfigFile();
|
||||||
|
Path tempConfigDirectory = getOrCreateTempConfigDirectory();
|
||||||
|
File tempConfigFile = tempConfigDirectory.resolve(getConfigFileName()).toFile();
|
||||||
|
try (TweedDataWriter writer = serde.createWriter(new FileOutputStream(tempConfigFile))) {
|
||||||
|
Patchwork contextExtensionsData = readWriteExtension.createReadWriteContextExtensionsData();
|
||||||
|
|
||||||
|
readWriteExtension.write(
|
||||||
|
writer,
|
||||||
|
configValue,
|
||||||
|
configContainer.rootEntry(),
|
||||||
|
contextExtensionsData
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to write config file " + tempConfigFile.getAbsolutePath(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (configFile.exists()) {
|
||||||
|
if (!configFile.delete()) {
|
||||||
|
throw new IOException("Failed to overwrite old config file " + configFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Files.move(tempConfigFile.toPath(), configFile.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Failed to move temporary config file " + tempConfigFile.getAbsolutePath() + " to " + configFile.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getConfigFile() {
|
||||||
|
Path configDir = FabricLoader.getInstance().getConfigDir();
|
||||||
|
configDir.toFile().mkdirs();
|
||||||
|
return configDir.resolve(getConfigFileName()).toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConfigFileName() {
|
||||||
|
return modId + serde.getPreferredFileExtension();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path getOrCreateTempConfigDirectory() {
|
||||||
|
if (tempConfigDirectory == null) {
|
||||||
|
try {
|
||||||
|
tempConfigDirectory = Files.createTempDirectory("tweed5-config");
|
||||||
|
tempConfigDirectory.toFile().deleteOnExit();
|
||||||
|
return tempConfigDirectory;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Failed to create temporary config directory, using game directory instead");
|
||||||
|
}
|
||||||
|
tempConfigDirectory = FabricLoader.getInstance().getGameDir().resolve(".tweed5-tmp/").resolve(modId);
|
||||||
|
tempConfigDirectory.toFile().mkdirs();
|
||||||
|
}
|
||||||
|
return tempConfigDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@NullMarked
|
||||||
|
package de.siphalor.tweed5.fabric.helper.api;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package de.siphalor.tweed5.fabric.helper.testmod;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.attributesextension.api.serde.filter.AttributesReadWriteFilterExtension;
|
||||||
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
|
import de.siphalor.tweed5.data.hjson.HjsonSerde;
|
||||||
|
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
||||||
|
import de.siphalor.tweed5.fabric.helper.api.FabricConfigCommentLoader;
|
||||||
|
import de.siphalor.tweed5.fabric.helper.api.FabricConfigContainerHelper;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.impl.weaving.TweedPojoWeaverBootstrapper;
|
||||||
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||||
|
|
||||||
|
@CommonsLog
|
||||||
|
public class FabricHelperTestMod implements ModInitializer {
|
||||||
|
public static final String MOD_ID = "tweed5_fabric_helper_testmod";
|
||||||
|
|
||||||
|
private TestModConfig config;
|
||||||
|
private ConfigContainer<TestModConfig> configContainer;
|
||||||
|
private FabricConfigContainerHelper<TestModConfig> configContainerHelper;
|
||||||
|
private AttributesReadWriteFilterExtension configFilterExtension;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
configContainer = TweedPojoWeaverBootstrapper.create(TestModConfig.class).weave();
|
||||||
|
configContainer.extension(AttributesReadWriteFilterExtension.class)
|
||||||
|
.orElseThrow(() -> new IllegalStateException("AttributesReadWriteFilterExtension not found"))
|
||||||
|
.markAttributeForFiltering("reload");
|
||||||
|
configFilterExtension = configContainer.extension(AttributesReadWriteFilterExtension.class)
|
||||||
|
.orElseThrow(() -> new IllegalStateException("AttributesReadWriteFilterExtension not found"));
|
||||||
|
|
||||||
|
configContainer.initialize();
|
||||||
|
|
||||||
|
configContainerHelper = FabricConfigContainerHelper.create(
|
||||||
|
configContainer,
|
||||||
|
new HjsonSerde(new HjsonWriter.Options()),
|
||||||
|
MOD_ID
|
||||||
|
);
|
||||||
|
FabricConfigCommentLoader.builder()
|
||||||
|
.configContainer(configContainer)
|
||||||
|
.modId(MOD_ID)
|
||||||
|
.prefix(MOD_ID + ".config")
|
||||||
|
.build()
|
||||||
|
.loadCommentsFromLanguageFile("en_us");
|
||||||
|
|
||||||
|
config = configContainerHelper.loadAndUpdateInConfigDirectory(TestModConfig::new);
|
||||||
|
|
||||||
|
log.info("Hello " + config.helloStart() + config.helloEnd());
|
||||||
|
|
||||||
|
ServerLifecycleEvents.SERVER_STARTED.register(_server -> onServerStarted());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onServerStarted() {
|
||||||
|
configContainerHelper.readPartialConfigInConfigDirectory(config, patchwork ->
|
||||||
|
configFilterExtension.addFilter(patchwork, "scope", "game")
|
||||||
|
);
|
||||||
|
|
||||||
|
log.info("Hello " + config.helloInGame() + config.helloEnd());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package de.siphalor.tweed5.fabric.helper.testmod;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.attributesextension.api.AttributesExtension;
|
||||||
|
import de.siphalor.tweed5.attributesextension.api.serde.filter.AttributesReadWriteFilterExtension;
|
||||||
|
import de.siphalor.tweed5.commentloaderextension.api.CommentLoaderExtension;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.annotation.CompoundWeaving;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.annotation.DefaultWeavingExtensions;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeaving;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeavingExtension;
|
||||||
|
import de.siphalor.tweed5.weaver.pojoext.attributes.api.Attribute;
|
||||||
|
import de.siphalor.tweed5.weaver.pojoext.attributes.api.AttributesPojoWeavingProcessor;
|
||||||
|
import de.siphalor.tweed5.weaver.pojoext.serde.api.auto.AutoReadWritePojoWeavingProcessor;
|
||||||
|
import de.siphalor.tweed5.weaver.pojoext.serde.api.auto.DefaultReadWriteMappings;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@PojoWeaving(extensions = {
|
||||||
|
CommentLoaderExtension.class,
|
||||||
|
ReadWriteExtension.class,
|
||||||
|
PatchExtension.class,
|
||||||
|
AttributesExtension.class,
|
||||||
|
AttributesReadWriteFilterExtension.class,
|
||||||
|
})
|
||||||
|
@PojoWeavingExtension(AutoReadWritePojoWeavingProcessor.class)
|
||||||
|
@PojoWeavingExtension(AttributesPojoWeavingProcessor.class)
|
||||||
|
@DefaultWeavingExtensions
|
||||||
|
@DefaultReadWriteMappings
|
||||||
|
@CompoundWeaving(namingFormat = "kebab_case")
|
||||||
|
@Data
|
||||||
|
public class TestModConfig {
|
||||||
|
private String helloStart = "Minecraft";
|
||||||
|
@Attribute(key = "scope", values = "game")
|
||||||
|
private String helloInGame = "Game";
|
||||||
|
private String helloEnd = "!";
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"tweed5_fabric_helper_testmod.config.hello-start": "Whom to greet when the game starts",
|
||||||
|
"tweed5_fabric_helper_testmod.config.hello-in-game": "Whom to greet when the player joins a game"
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "tweed5_fabric_helper_testmod",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"entrypoints": {
|
||||||
|
"main": [
|
||||||
|
"de.siphalor.tweed5.fabric.helper.testmod.FabricHelperTestMod"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
[versions]
|
[versions]
|
||||||
coat = "1.0.0-beta.23"
|
coat = "1.0.0-beta.23"
|
||||||
|
fabric-api = "0.136.0+1.21.10"
|
||||||
minecraft = "1.21.10"
|
minecraft = "1.21.10"
|
||||||
parchment = "2025.10.12"
|
parchment = "2025.10.12"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
coat = { group = "de.siphalor.coat", name = "coat-mc1.21.10", version.ref = "coat" }
|
coat = { group = "de.siphalor.coat", name = "coat-mc1.21.10", version.ref = "coat" }
|
||||||
|
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
"license": "LGPL-3.0-only",
|
"license": "LGPL-3.0-only",
|
||||||
"contact": {
|
"contact": {
|
||||||
"email": "info@siphalor.de",
|
"email": "info@siphalor.de",
|
||||||
"issues": "https://gitea.siphalor.de/Siphalor/tweed5/issues",
|
"issues": "${repoUrl}/issues",
|
||||||
"sources": "https://gitea.siphalor.de/Siphalor/tweed5"
|
"sources": "${repoUrl}"
|
||||||
},
|
},
|
||||||
"custom": {
|
"custom": {
|
||||||
"modmenu": {
|
"modmenu": {
|
||||||
|
|||||||
@@ -27,6 +27,13 @@ pluginManagement {
|
|||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
name = "FabricMC"
|
||||||
|
url = uri("https://maven.fabricmc.net")
|
||||||
|
mavenContent {
|
||||||
|
includeGroupAndSubgroups("net.fabricmc")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
versionCatalogs {
|
versionCatalogs {
|
||||||
@@ -46,7 +53,7 @@ dependencyResolutionManagement {
|
|||||||
includeBuild("../tweed5")
|
includeBuild("../tweed5")
|
||||||
|
|
||||||
includeNormalModule("bundle")
|
includeNormalModule("bundle")
|
||||||
includeNormalModule("coat-bridge")
|
includeNormalModule("fabric-helper")
|
||||||
|
|
||||||
fun includeNormalModule(name: String) {
|
fun includeNormalModule(name: String) {
|
||||||
includeAs("tweed5-$name", name)
|
includeAs("tweed5-$name", name)
|
||||||
|
|||||||
Reference in New Issue
Block a user