Compare commits

...

2 Commits

Author SHA1 Message Date
Johannes Frohnmeyer 1e93e0f793
fix: comment out unneeded special case
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/jfmod Pipeline was successful Details
2024-04-10 13:58:37 +02:00
Johannes Frohnmeyer 763f3c6ed4
feat!: initial forge support
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/jfmod Pipeline was successful Details
2024-03-25 16:18:18 +01:00
20 changed files with 256 additions and 52 deletions

View File

@ -1,8 +1,6 @@
package io.gitlab.jfronny.libjf;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.metadata.CustomValue;
import io.gitlab.jfronny.gson.JsonElement;
import org.jetbrains.annotations.ApiStatus;
import java.util.LinkedHashSet;
@ -23,17 +21,14 @@ public class Flags {
(source, value) -> new BooleanFlag(source, value.getAsBoolean()));
}
private static <T> Set<T> getFlags(String name, BiFunction<String, String, T> makeFromProp, BiFunction<String, CustomValue, T> makeFromFmj) {
private static <T> Set<T> getFlags(String name, BiFunction<String, String, T> makeFromProp, BiFunction<String, JsonElement, T> makeFromMod) {
Set<T> flags = new LinkedHashSet<>();
String propName = "libjf." + name;
if (System.getProperty(propName) != null)
flags.add(makeFromProp.apply("System Property", System.getProperty(propName)));
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
if (!mod.getMetadata().containsCustomValue("libjf")) continue;
CustomValue.CvObject co = mod.getMetadata().getCustomValue("libjf").getAsObject();
if (!co.containsKey(name)) continue;
flags.add(makeFromFmj.apply("Mod: " + mod.getMetadata().getId(), co.get(name)));
}
LoaderGlue.INSTANCE.obtainFlags(name, (id, data) -> {
flags.add(makeFromMod.apply("Mod: " + id, data));
});
return flags;
}

View File

@ -7,10 +7,9 @@ import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders;
import io.gitlab.jfronny.libjf.gson.HiddenAnnotationExclusionStrategy;
import io.gitlab.jfronny.libjf.log.JULBridge;
import io.gitlab.jfronny.libjf.log.SLF4JPlatformLogger;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
import org.slf4j.LoggerFactory;
public class LibJf implements PreLaunchEntrypoint {
public class LibJf {
public static final String MOD_ID = "libjf";
public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName(MOD_ID);
@ -19,11 +18,6 @@ public class LibJf implements PreLaunchEntrypoint {
GsonHolders.registerSerializer();
}
@Override
public void onPreLaunch() {
setup();
}
private static boolean setup = false;
private static boolean bootstrapped = false;
public static void setup() {

View File

@ -0,0 +1,27 @@
package io.gitlab.jfronny.libjf;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import io.gitlab.jfronny.commons.throwable.Try;
import io.gitlab.jfronny.gson.JsonElement;
import java.util.function.BiConsumer;
public interface LoaderGlue {
LoaderGlue INSTANCE = Try.orThrow(() -> {
boolean isFabric = false;
try {
Class.forName("net.fabricmc.loader.api.FabricLoader");
isFabric = true;
} catch (Throwable t) {
}
if (isFabric) {
return (LoaderGlue) Class.forName("io.gitlab.jfronny.libjf.fabric.FabricGlue").getConstructor().newInstance();
} else {
return (LoaderGlue) Class.forName("io.gitlab.jfronny.libjf.forge.ForgeGlue").getConstructor().newInstance();
}
});
void obtainFlags(String name, BiConsumer<String, JsonElement> out);
SystemLoggerPlus getEarlyLogger(String name);
boolean isClient();
}

View File

@ -1,32 +1,32 @@
package io.gitlab.jfronny.libjf.coprocess;
import io.gitlab.jfronny.libjf.LibJf;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader;
import java.io.Closeable;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class CoProcessManager implements ModInitializer {
private final List<CoProcess> coProcesses = new ArrayList<>();
@Override
public void onInitialize() {
coProcesses.addAll(FabricLoader.getInstance().getEntrypoints(LibJf.MOD_ID + ":coprocess", CoProcess.class));
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) ServerLifecycleEvents.SERVER_STOPPED.register(server -> this.stop());
public class CoProcessManager {
private static final List<CoProcess> coProcesses = new ArrayList<>();
public static void initialize() {
Runtime.getRuntime().addShutdownHook(new Thread(CoProcessManager::stop));
start();
}
private void start() {
public static void add(CoProcess coProcess) {
coProcesses.add(coProcess);
}
private static void start() {
for (CoProcess coProcess : coProcesses) {
coProcess.start();
}
}
private void stop() {
public static void stop() {
for (Iterator<CoProcess> iter = coProcesses.iterator(); iter.hasNext(); ) {
CoProcess coProcess = iter.next();
coProcess.stop();

View File

@ -0,0 +1,53 @@
package io.gitlab.jfronny.libjf.fabric;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.LoaderGlue;
import io.gitlab.jfronny.libjf.coprocess.CoProcess;
import io.gitlab.jfronny.libjf.coprocess.CoProcessManager;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
import net.fabricmc.loader.api.metadata.CustomValue;
import java.util.function.BiConsumer;
public class FabricGlue implements LoaderGlue, PreLaunchEntrypoint, ModInitializer {
@Override
public void onPreLaunch() {
LibJf.setup();
}
@Override
public void onInitialize() {
for (CoProcess entrypoint : FabricLoader.getInstance().getEntrypoints(LibJf.MOD_ID + ":coprocess", CoProcess.class)) {
CoProcessManager.add(entrypoint);
}
if (!LoaderGlue.INSTANCE.isClient()) ServerLifecycleEvents.SERVER_STOPPED.register(server -> CoProcessManager.stop());
CoProcessManager.initialize();
}
@Override
public void obtainFlags(String name, BiConsumer<String, JsonElement> out) {
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
if (!mod.getMetadata().containsCustomValue("libjf")) continue;
CustomValue.CvObject co = mod.getMetadata().getCustomValue("libjf").getAsObject();
if (!co.containsKey(name)) continue;
out.accept(mod.getMetadata().getId(), FabricLoaderGsonGenerator.toGson(co.get(name)));
}
}
@Override
public SystemLoggerPlus getEarlyLogger(String name) {
return new LoaderPlatformLogger(name);
}
@Override
public boolean isClient() {
return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT;
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.gson;
package io.gitlab.jfronny.libjf.fabric;
import io.gitlab.jfronny.gson.*;
import net.fabricmc.loader.api.metadata.CustomValue;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.log;
package io.gitlab.jfronny.libjf.fabric;
import io.gitlab.jfronny.commons.logger.CompactLogger;
import net.fabricmc.loader.impl.util.log.Log;

View File

@ -3,15 +3,15 @@ package io.gitlab.jfronny.libjf.gson;
import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders;
import io.gitlab.jfronny.gson.ExclusionStrategy;
import io.gitlab.jfronny.gson.FieldAttributes;
import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.FabricLoader;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.LoaderGlue;
public class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT
return LoaderGlue.INSTANCE.isClient()
? fieldAttributes.getAnnotation(ServerOnly.class) != null
: fieldAttributes.getAnnotation(ClientOnly.class) != null;
}

View File

@ -3,6 +3,7 @@ package io.gitlab.jfronny.libjf.log;
import io.gitlab.jfronny.commons.logger.HotswapLoggerFinder;
import io.gitlab.jfronny.commons.logger.LeveledLoggerFinder;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import io.gitlab.jfronny.libjf.LoaderGlue;
import org.jetbrains.annotations.Nullable;
public class EarlyLoggerSetup extends LeveledLoggerFinder {
@ -10,7 +11,7 @@ public class EarlyLoggerSetup extends LeveledLoggerFinder {
// When a logger is used before the game is initialized, SLF4J is not yet available.
// To support that, this implementation which redirects to Fabric Loader's internal logging abstraction is used instead.
// After the game is initialized, something calls LibJF.setup (usually preEntry), which replaces this factory with a SLF4J-based one.
HotswapLoggerFinder.updateAllStrategies((name, module, level) -> new LoaderPlatformLogger(name));
HotswapLoggerFinder.updateAllStrategies((name, module, level) -> LoaderGlue.INSTANCE.getEarlyLogger(name));
}
private final LeveledLoggerFinder delegate = new HotswapLoggerFinder();

View File

@ -18,8 +18,8 @@
"fabric-lifecycle-events-v1": "*"
},
"entrypoints": {
"main": ["io.gitlab.jfronny.libjf.coprocess.CoProcessManager"],
"preLaunch": ["io.gitlab.jfronny.libjf.LibJf"]
"main": ["io.gitlab.jfronny.libjf.fabric.FabricGlue"],
"preLaunch": ["io.gitlab.jfronny.libjf.fabric.FabricGlue"]
},
"custom": {
"modmenu": {

View File

@ -1,19 +1,16 @@
package io.gitlab.jfronny.libjf.config.impl;
import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.LoaderGlue;
import io.gitlab.jfronny.libjf.config.api.v2.Category;
import io.gitlab.jfronny.libjf.config.api.v2.JfConfig;
import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder;
import io.gitlab.jfronny.libjf.gson.FabricLoaderGsonGenerator;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.metadata.CustomValue;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedList;
import java.util.List;
import static io.gitlab.jfronny.libjf.config.impl.ConfigCore.MODULE_ID;
public class AuxiliaryMetadata {
public static AuxiliaryMetadata of(Category category) {
AuxiliaryMetadata meta = new AuxiliaryMetadata();
@ -35,15 +32,10 @@ public class AuxiliaryMetadata {
var metaRef = new Object() {
AuxiliaryMetadata meta = null;
};
FabricLoader.getInstance().getModContainer(modId).ifPresent(container -> {
CustomValue cv = container.getMetadata().getCustomValue(MODULE_ID);
if (cv == null) {
cv = container.getMetadata().getCustomValue("libjf");
if (cv != null) {
cv = cv.getAsObject().get("config");
}
LoaderGlue.INSTANCE.obtainFlags("config", (id, data) -> {
if (id.equals(modId)) {
metaRef.meta = GsonHolders.API.getGson().fromJson(data, AuxiliaryMetadata.class);
}
if (cv != null) metaRef.meta = GsonHolders.API.getGson().fromJson(FabricLoaderGsonGenerator.toGson(cv), AuxiliaryMetadata.class);
});
return metaRef.meta;
}

View File

@ -0,0 +1,51 @@
import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import org.codehaus.plexus.util.IOUtil
import java.io.ByteArrayOutputStream
plugins {
id("jfmod.module")
}
repositories {
maven("https://maven.neoforged.net/releases")
}
base {
archivesName = "libjf-forge"
}
lom {
loaderVersion = "20.4.210"
}
dependencies {
//TODO this dependency setup has only been tested in dev.
// It may not work in a production environment.
"loomDevelopmentDependencies"(project(":libjf-base")) {
isTransitive = false
}
shadow(project(":libjf-base", "dev")) {
isTransitive = false
}
include(modImplementation("net.fabricmc.fabric-api:fabric-lifecycle-events-v1")!!)
shadow(libs.bundles.commons)
}
// workaround to ensure our custom System.LoggerFinder is initialized early
// ideally, we would use the configuration API, but that seems to cause a class loading issue with fabric loader
//tasks.shadowJar {
// val path = "META-INF/services/io.gitlab.jfronny.libjf.LoaderGlue"
// val field = ServiceFileTransformer::class.java.getDeclaredField("serviceEntries").apply { isAccessible = true }
// exclude(path)
// transform(object: ServiceFileTransformer() {
// private val serviceEntries get() = field.get(this) as MutableMap<String, Any>
// override fun transform(context: TransformerContext?) {
// super.transform(context)
// (serviceEntries[path] as ByteArrayOutputStream).run {
// reset()
// file("src/main/resources/$path").inputStream().use { IOUtil.copy(it, this) }
// }
// }
// })
//}

View File

@ -0,0 +1 @@
loom.platform=neoforge

View File

@ -0,0 +1,36 @@
package io.gitlab.jfronny.libjf.forge;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.LoaderGlue;
import io.gitlab.jfronny.libjf.log.SLF4JPlatformLogger;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.loading.FMLEnvironment;
import org.slf4j.LoggerFactory;
import java.util.ServiceLoader;
import java.util.function.BiConsumer;
public class ForgeGlue implements LoaderGlue {
@Override
public void obtainFlags(String name, BiConsumer<String, JsonElement> out) {
ServiceLoader.load(ModFlagSource.class).stream().forEach(provider -> {
JsonElement element = provider.get().obtain();
if (element != null) {
out.accept(provider.type().getName(), element);
}
});
}
@Override
public SystemLoggerPlus getEarlyLogger(String name) {
return new SLF4JPlatformLogger(LoggerFactory.getLogger(name));
}
@Override
public boolean isClient() {
return FMLEnvironment.dist == Dist.CLIENT;
}
}

View File

@ -0,0 +1,11 @@
package io.gitlab.jfronny.libjf.forge;
import io.gitlab.jfronny.libjf.LibJf;
import net.neoforged.fml.common.Mod;
@Mod(LibJf.MOD_ID)
public class LibJfForge {
public LibJfForge() {
LibJf.setup();
}
}

View File

@ -0,0 +1,7 @@
package io.gitlab.jfronny.libjf.forge;
import io.gitlab.jfronny.gson.JsonElement;
public interface ModFlagSource {
JsonElement obtain();
}

View File

@ -0,0 +1,27 @@
modLoader = "javafml"
loaderVersion = "[2.0,)"
issueTrackerURL = "https://git.frohnmeyer-wds.de/JfMods/LibJF/issues"
license = "MIT"
[[mods]]
modId = "libjf"
version = "${version}"
displayName = "LibJF for Forge"
authors = "JFronny"
description = '''
Library mod by JFronny, ported to NeoForge
'''
[[dependencies.libjf]]
modId = "neoforge"
type = "required"
versionRange = "[${loader_version},)"
ordering = "NONE"
side = "BOTH"
[[dependencies.libjf]]
modId = "minecraft"
type = "required"
versionRange = "${minecraft_version}"
ordering = "NONE"
side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,6 @@
{
"pack": {
"description": "LibJF",
"pack_format": 8
}
}

View File

@ -36,3 +36,6 @@ include("libjf-web-v1")
include("libjf-bom")
include("libjf-catalog")
include("libjf-forge")