diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 67a553a..da8df26 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,9 +7,21 @@ on: - '1.19.2' tags-ignore: - '**' + paths: + - 'gradle/**' + - '**.java' + - '**.kts' + - '**.properties' + - '**/build.yml' pull_request: branches: - '1.19.2' + paths: + - 'gradle/**' + - '**.java' + - '**.kts' + - '**.properties' + - '**/build.yml' env: JAVA_DIST: 'zulu' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1930957..f0d72a5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -97,7 +97,7 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "# Build Information" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "- JAR files: $(find output -maxdepth 1 -type f -name '*.jar' | wc -c)" >> $GITHUB_STEP_SUMMARY + echo "- JAR files: $(find output -maxdepth 1 -type f -name '*.jar' | wc -l)" >> $GITHUB_STEP_SUMMARY echo "- Folder size: $(du -sh output | cut -f1)" >> $GITHUB_STEP_SUMMARY echo "- Archive size: $(du -sh build.tar.gz | cut -f1)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY @@ -198,7 +198,9 @@ jobs: version-type: ${{ needs.build.outputs.RELEASE_TYPE }} changelog-file: output/changelog.md - loaders: forge + loaders: | + forge + neoforge game-versions: ${{ needs.build.outputs.MINECRAFT_VERSION }} java: ${{ env.JAVA_VERSION }} @@ -232,7 +234,9 @@ jobs: version-type: ${{ needs.build.outputs.RELEASE_TYPE }} changelog-file: output/changelog.md - loaders: forge + loaders: | + forge + neoforge game-versions: ${{ needs.build.outputs.MINECRAFT_VERSION }} java: ${{ env.JAVA_VERSION }} diff --git a/Common/build.gradle.kts b/Common/build.gradle.kts index 946c4ae..ea2de95 100644 --- a/Common/build.gradle.kts +++ b/Common/build.gradle.kts @@ -1,18 +1,15 @@ val enabledPlatforms: String by project -val fabricLoaderVersion: String by project +val minecraftVersion: String by project +val modPackage: String by project val modId: String by project val modName: String by project -val modPackage: String by project -val reiVersion: String by project -val jeiVersion: String by project -val kubejsVersion: String by project -val mappingsChannel: String by project -val mappingsVersion: String by project val junitVersion: String by project -val minecraftVersion: String by project +val fabricLoaderVersion: String by project +val jeiVersion: String by project +val reiVersion: String by project plugins { - id("com.github.gmazzo.buildconfig") version ("4.0.4") + id("com.github.gmazzo.buildconfig") version "4.0.4" } architectury { @@ -20,25 +17,27 @@ architectury { } loom { - if (project.findProperty("enableAccessWidener") == "true") { // Optional property for `gradle.properties` to enable access wideners. + if (project.findProperty("enableAccessWidener") == "true") { // optional property for `gradle.properties` accessWidenerPath.set(file("src/main/resources/$modId.accesswidener")) println("Access widener enabled for project ${project.name}. Access widener path: ${loom.accessWidenerPath.get()}") } } dependencies { - // loader - // required here for the @Environment annotations and the mixin dependencies - // Do NOT use other classes from the Fabric loader! + /** + * loader + * required here for the @Environment annotations and the mixin dependencies + * do NOT use other classes from the Fabric loader + */ modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") // compile time mods - modCompileOnly("dev.latvian.mods:kubejs:$kubejsVersion") // required for common kubejs plugin | common has remapping issues - modCompileOnly("me.shedaniel:RoughlyEnoughItems-api:$reiVersion") // required for common rei plugin - compileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // required to disable rei compat layer on jei plugin - testCompileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // don't question this, it's required for compiling - modCompileOnly("mezz.jei:jei-$minecraftVersion-lib:$jeiVersion") // required for common jei plugin and mixin - modCompileOnly("mezz.jei:jei-$minecraftVersion-common-api:$jeiVersion") // required for common jei plugin and mixin + modCompileOnly("mezz.jei:jei-$minecraftVersion-common-api:$jeiVersion") // required for jei plugin + modCompileOnly("mezz.jei:jei-$minecraftVersion-lib:$jeiVersion") // required for jei mixin + modCompileOnly("me.shedaniel:RoughlyEnoughItems-api:$reiVersion") // required for rei plugin + + // compile time dependencies + compileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // required to disable rei compat layer // tests testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion") @@ -53,7 +52,6 @@ buildConfig { useJavaOutput() } -// TODO reactivate when specific mod is not annoying anymore //tasks { // withType { // useJUnitPlatform() diff --git a/Common/src/main/java/com/almostreliable/unified/AlmostUnified.java b/Common/src/main/java/com/almostreliable/unified/AlmostUnified.java index febf640..f9aa885 100644 --- a/Common/src/main/java/com/almostreliable/unified/AlmostUnified.java +++ b/Common/src/main/java/com/almostreliable/unified/AlmostUnified.java @@ -3,13 +3,21 @@ package com.almostreliable.unified; import com.almostreliable.unified.config.Config; import com.almostreliable.unified.config.ServerConfigs; import com.almostreliable.unified.config.StartupConfig; +import com.almostreliable.unified.config.UnifyConfig; +import com.almostreliable.unified.recipe.unifier.RecipeHandlerFactory; import com.almostreliable.unified.utils.TagOwnerships; +import com.almostreliable.unified.utils.TagReloadHandler; import com.google.common.base.Preconditions; -import net.minecraft.tags.TagManager; +import com.google.gson.JsonElement; +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Map; @SuppressWarnings("UtilityClassWithoutPrivateConstructor") public final class AlmostUnified { @@ -18,16 +26,6 @@ public final class AlmostUnified { @Nullable private static AlmostUnifiedRuntime RUNTIME; @Nullable private static StartupConfig STARTUP_CONFIG; - @Nullable private static ServerConfigs SERVER_CONFIGS; - @Nullable private static TagManager TAG_MANAGER; - @Nullable private static TagOwnerships TAG_OWNERSHIPS; - - public static StartupConfig getStartupConfig() { - if (STARTUP_CONFIG == null) { - STARTUP_CONFIG = Config.load(StartupConfig.NAME, new StartupConfig.Serializer()); - } - return STARTUP_CONFIG; - } public static boolean isRuntimeLoaded() { return RUNTIME != null; @@ -40,18 +38,59 @@ public final class AlmostUnified { return RUNTIME; } - public static void onTagManagerReload(TagManager tagManager) { - SERVER_CONFIGS = ServerConfigs.load(); - TAG_MANAGER = tagManager; - var unifyConfig = SERVER_CONFIGS.getUnifyConfig(); - TAG_OWNERSHIPS = new TagOwnerships(unifyConfig.bakeTags(), unifyConfig.getTagOwnerships()); + public static StartupConfig getStartupConfig() { + if (STARTUP_CONFIG == null) { + STARTUP_CONFIG = Config.load(StartupConfig.NAME, new StartupConfig.Serializer()); + } + return STARTUP_CONFIG; } - public static void onReloadRecipeManager() { - Preconditions.checkNotNull(SERVER_CONFIGS, "ServerConfigs were not loaded correctly"); - Preconditions.checkNotNull(TAG_MANAGER, "TagManager was not loaded correctly"); - Preconditions.checkNotNull(TAG_OWNERSHIPS, "TagOwnerships were not loaded correctly"); + public static void onTagLoaderReload(Map>> tags) { + RecipeHandlerFactory recipeHandlerFactory = new RecipeHandlerFactory(); + AlmostUnifiedPlatform.INSTANCE.bindRecipeHandlers(recipeHandlerFactory); - RUNTIME = AlmostUnifiedRuntimeImpl.create(SERVER_CONFIGS, TAG_MANAGER, TAG_OWNERSHIPS); + ServerConfigs serverConfigs = ServerConfigs.load(); + UnifyConfig unifyConfig = serverConfigs.getUnifyConfig(); + + TagOwnerships tagOwnerships = new TagOwnerships( + unifyConfig.bakeAndValidateTags(tags), + unifyConfig.getTagOwnerships() + ); + tagOwnerships.applyOwnerships(tags); + + ReplacementData replacementData = loadReplacementData(tags, unifyConfig, tagOwnerships); + + RUNTIME = new AlmostUnifiedRuntimeImpl( + serverConfigs, + replacementData.filteredTagMap(), + replacementData.replacementMap(), + recipeHandlerFactory + ); + } + + public static void onRecipeManagerReload(Map recipes) { + Preconditions.checkNotNull(RUNTIME, "AlmostUnifiedRuntime was not loaded correctly"); + RUNTIME.run(recipes, getStartupConfig().isServerOnly()); + } + + /** + * Loads the required data for the replacement logic. + *

+ * This method applies tag inheritance and rebuilds the replacement data if the + * inheritance mutates the tags. + * + * @param tags The vanilla tag map provided by the TagManager + * @param unifyConfig The mod config to use for unifying + * @param tagOwnerships The tag ownerships to apply + * @return The loaded data + */ + private static ReplacementData loadReplacementData(Map>> tags, UnifyConfig unifyConfig, TagOwnerships tagOwnerships) { + ReplacementData replacementData = ReplacementData.load(tags, unifyConfig, tagOwnerships); + var needsRebuild = TagReloadHandler.applyInheritance(unifyConfig, replacementData); + if (needsRebuild) { + return ReplacementData.load(tags, unifyConfig, tagOwnerships); + } + + return replacementData; } } diff --git a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedFallbackRuntime.java b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedFallbackRuntime.java index f2940df..b4410ca 100644 --- a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedFallbackRuntime.java +++ b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedFallbackRuntime.java @@ -22,8 +22,7 @@ public class AlmostUnifiedFallbackRuntime implements AlmostUnifiedRuntime { @Nullable private static AlmostUnifiedFallbackRuntime INSTANCE; @Nullable private UnifyConfig unifyConfig; - @Nullable private TagMap filteredTagMap; - @Nullable private TagOwnerships tagOwnerships; + @Nullable private TagMap filteredTagMap; @Nullable private ReplacementMap replacementMap; public static AlmostUnifiedFallbackRuntime getInstance() { @@ -38,23 +37,22 @@ public class AlmostUnifiedFallbackRuntime implements AlmostUnifiedRuntime { public void reload() { unifyConfig = null; filteredTagMap = null; - tagOwnerships = null; replacementMap = null; build(); } - public void build() { + private void build() { unifyConfig = Config.load(UnifyConfig.NAME, new UnifyConfig.Serializer()); Set> unifyTags = unifyConfig.bakeTags(); filteredTagMap = TagMap.create(unifyTags).filtered($ -> true, unifyConfig::includeItem); StoneStrataHandler stoneStrataHandler = createStoneStrataHandler(unifyConfig); - tagOwnerships = new TagOwnerships(unifyTags, unifyConfig.getTagOwnerships()); + TagOwnerships tagOwnerships = new TagOwnerships(unifyTags, unifyConfig.getTagOwnerships()); replacementMap = new ReplacementMap(unifyConfig, filteredTagMap, stoneStrataHandler, tagOwnerships); } private static StoneStrataHandler createStoneStrataHandler(UnifyConfig config) { Set> stoneStrataTags = AlmostUnifiedPlatform.INSTANCE.getStoneStrataTags(config.getStoneStrata()); - TagMap stoneStrataTagMap = TagMap.create(stoneStrataTags); + TagMap stoneStrataTagMap = TagMap.create(stoneStrataTags); return StoneStrataHandler.create(config.getStoneStrata(), stoneStrataTags, stoneStrataTagMap); } @@ -64,7 +62,7 @@ public class AlmostUnifiedFallbackRuntime implements AlmostUnifiedRuntime { } @Override - public Optional getFilteredTagMap() { + public Optional> getFilteredTagMap() { return Optional.ofNullable(filteredTagMap); } @@ -77,9 +75,4 @@ public class AlmostUnifiedFallbackRuntime implements AlmostUnifiedRuntime { public Optional getUnifyConfig() { return Optional.ofNullable(unifyConfig); } - - @Override - public Optional getTagOwnerships() { - return Optional.ofNullable(tagOwnerships); - } } diff --git a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedLookupImpl.java b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedLookupImpl.java index 847af3e..7892b6f 100644 --- a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedLookupImpl.java +++ b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedLookupImpl.java @@ -8,8 +8,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.level.ItemLike; -import org.jetbrains.annotations.Nullable; +import javax.annotation.Nullable; import java.util.Set; import java.util.stream.Collectors; @@ -64,7 +64,7 @@ public class AlmostUnifiedLookupImpl implements AlmostUnifiedLookup { .getRuntime() .getFilteredTagMap() .map(tagMap -> tagMap - .getItemsByTag(asUnifyTag) + .getEntriesByTag(asUnifyTag) .stream() .flatMap(rl -> Registry.ITEM.getOptional(rl).stream()) .collect(Collectors.toSet())) diff --git a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatform.java b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatform.java index bfd5135..48e461b 100644 --- a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatform.java +++ b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatform.java @@ -6,11 +6,12 @@ import net.minecraft.world.item.Item; import java.nio.file.Path; import java.util.List; +import java.util.ServiceLoader; import java.util.Set; public interface AlmostUnifiedPlatform { - AlmostUnifiedPlatform INSTANCE = PlatformLoader.load(AlmostUnifiedPlatform.class); + AlmostUnifiedPlatform INSTANCE = load(AlmostUnifiedPlatform.class); /** * Gets the current platform @@ -27,13 +28,6 @@ public interface AlmostUnifiedPlatform { */ boolean isModLoaded(String modId); - /** - * Check if the game is currently in a development environment. - * - * @return True if in a development environment, false otherwise. - */ - boolean isDevelopmentEnvironment(); - boolean isClient(); Path getConfigPath(); @@ -43,4 +37,17 @@ public interface AlmostUnifiedPlatform { void bindRecipeHandlers(RecipeHandlerFactory factory); Set> getStoneStrataTags(List stoneStrataIds); + + static T load(Class clazz) { + T loadedService = ServiceLoader.load(clazz) + .findFirst() + .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + AlmostUnified.LOG.debug("Loaded {} for service {}", loadedService, clazz); + return loadedService; + } + + enum Platform { + FORGE, + FABRIC; + } } diff --git a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedRuntime.java b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedRuntime.java index 440449c..e96ae03 100644 --- a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedRuntime.java +++ b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedRuntime.java @@ -3,9 +3,9 @@ package com.almostreliable.unified; import com.almostreliable.unified.config.UnifyConfig; import com.almostreliable.unified.utils.ReplacementMap; import com.almostreliable.unified.utils.TagMap; -import com.almostreliable.unified.utils.TagOwnerships; import com.google.gson.JsonElement; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; import java.util.Map; import java.util.Optional; @@ -14,11 +14,9 @@ public interface AlmostUnifiedRuntime { void run(Map recipes, boolean skipClientTracking); - Optional getFilteredTagMap(); + Optional> getFilteredTagMap(); Optional getReplacementMap(); Optional getUnifyConfig(); - - Optional getTagOwnerships(); } diff --git a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedRuntimeImpl.java b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedRuntimeImpl.java index 0b99850..02ec99b 100644 --- a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedRuntimeImpl.java +++ b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedRuntimeImpl.java @@ -1,6 +1,5 @@ package com.almostreliable.unified; -import com.almostreliable.unified.api.StoneStrataHandler; import com.almostreliable.unified.config.DebugConfig; import com.almostreliable.unified.config.DuplicationConfig; import com.almostreliable.unified.config.ServerConfigs; @@ -8,16 +7,12 @@ import com.almostreliable.unified.config.UnifyConfig; import com.almostreliable.unified.recipe.RecipeDumper; import com.almostreliable.unified.recipe.RecipeTransformer; import com.almostreliable.unified.recipe.unifier.RecipeHandlerFactory; -import com.almostreliable.unified.utils.FileUtils; import com.almostreliable.unified.utils.ReplacementMap; import com.almostreliable.unified.utils.TagMap; -import com.almostreliable.unified.utils.TagOwnerships; import com.google.gson.JsonElement; import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagManager; +import net.minecraft.world.item.Item; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.Map; import java.util.Optional; @@ -26,62 +21,28 @@ public final class AlmostUnifiedRuntimeImpl implements AlmostUnifiedRuntime { private final UnifyConfig unifyConfig; private final DuplicationConfig duplicationConfig; private final DebugConfig debugConfig; - private final TagMap filteredTagMap; - private final TagOwnerships tagOwnerships; + private final TagMap tagMap; private final ReplacementMap replacementMap; private final RecipeHandlerFactory recipeHandlerFactory; - private AlmostUnifiedRuntimeImpl( - UnifyConfig unifyConfig, - DuplicationConfig duplicationConfig, - DebugConfig debugConfig, - TagMap filteredTagMap, - TagOwnerships tagOwnerships, - ReplacementMap replacementMap, + AlmostUnifiedRuntimeImpl( + ServerConfigs configs, + TagMap tagMap, + ReplacementMap repMap, RecipeHandlerFactory recipeHandlerFactory ) { - this.unifyConfig = unifyConfig; - this.duplicationConfig = duplicationConfig; - this.debugConfig = debugConfig; - this.filteredTagMap = filteredTagMap; - this.tagOwnerships = tagOwnerships; - this.replacementMap = replacementMap; + this.unifyConfig = configs.getUnifyConfig(); + this.duplicationConfig = configs.getDupConfig(); + this.debugConfig = configs.getDebugConfig(); + this.tagMap = tagMap; + this.replacementMap = repMap; this.recipeHandlerFactory = recipeHandlerFactory; } - public static AlmostUnifiedRuntimeImpl create(ServerConfigs serverConfigs, TagManager tagManager, TagOwnerships tagOwnerships) { - createGitIgnoreIfNotExists(); - - UnifyConfig unifyConfig = serverConfigs.getUnifyConfig(); - DuplicationConfig duplicationConfig = serverConfigs.getDupConfig(); - DebugConfig debugConfig = serverConfigs.getDebugConfig(); - - var unifyTags = unifyConfig.bakeTags(); - TagMap globalTagMap = TagMap.create(tagManager); - TagMap filteredTagMap = globalTagMap.filtered(unifyTags::contains, unifyConfig::includeItem); - - StoneStrataHandler stoneStrataHandler = StoneStrataHandler.create(unifyConfig.getStoneStrata(), - AlmostUnifiedPlatform.INSTANCE.getStoneStrataTags(unifyConfig.getStoneStrata()), globalTagMap); - var replacementMap = new ReplacementMap(unifyConfig, filteredTagMap, stoneStrataHandler, tagOwnerships); - - RecipeHandlerFactory recipeHandlerFactory = new RecipeHandlerFactory(); - AlmostUnifiedPlatform.INSTANCE.bindRecipeHandlers(recipeHandlerFactory); - - return new AlmostUnifiedRuntimeImpl( - unifyConfig, - duplicationConfig, - debugConfig, - filteredTagMap, - tagOwnerships, - replacementMap, - recipeHandlerFactory - ); - } - @Override public void run(Map recipes, boolean skipClientTracking) { debugConfig.logRecipes(recipes, "recipes_before_unification.txt"); - debugConfig.logUnifyTagDump(filteredTagMap); + debugConfig.logUnifyTagDump(tagMap); long startTime = System.currentTimeMillis(); RecipeTransformer.Result result = new RecipeTransformer( @@ -96,20 +57,9 @@ public final class AlmostUnifiedRuntimeImpl implements AlmostUnifiedRuntime { debugConfig.logRecipes(recipes, "recipes_after_unification.txt"); } - private static void createGitIgnoreIfNotExists() { - Path path = AlmostUnifiedPlatform.INSTANCE.getConfigPath(); - if (!(Files.exists(path) && Files.isDirectory(path))) { - FileUtils.write( - AlmostUnifiedPlatform.INSTANCE.getConfigPath(), - ".gitignore", - sb -> sb.append(DebugConfig.NAME).append(".json").append("\n") - ); - } - } - @Override - public Optional getFilteredTagMap() { - return Optional.of(filteredTagMap); + public Optional> getFilteredTagMap() { + return Optional.of(tagMap); } @Override @@ -121,9 +71,4 @@ public final class AlmostUnifiedRuntimeImpl implements AlmostUnifiedRuntime { public Optional getUnifyConfig() { return Optional.of(unifyConfig); } - - @Override - public Optional getTagOwnerships() { - return Optional.of(tagOwnerships); - } } diff --git a/Common/src/main/java/com/almostreliable/unified/Platform.java b/Common/src/main/java/com/almostreliable/unified/Platform.java deleted file mode 100644 index c56383e..0000000 --- a/Common/src/main/java/com/almostreliable/unified/Platform.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.almostreliable.unified; - -public enum Platform { - FORGE, - FABRIC -} diff --git a/Common/src/main/java/com/almostreliable/unified/PlatformLoader.java b/Common/src/main/java/com/almostreliable/unified/PlatformLoader.java deleted file mode 100644 index b3d578e..0000000 --- a/Common/src/main/java/com/almostreliable/unified/PlatformLoader.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.almostreliable.unified; - -import java.util.ServiceLoader; - -@SuppressWarnings("UtilityClassWithoutPrivateConstructor") -public final class PlatformLoader { - static T load(Class clazz) { - final T loadedService = ServiceLoader.load(clazz) - .findFirst() - .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); - AlmostUnified.LOG.debug("Loaded {} for service {}", loadedService, clazz); - return loadedService; - } -} diff --git a/Common/src/main/java/com/almostreliable/unified/ReplacementData.java b/Common/src/main/java/com/almostreliable/unified/ReplacementData.java new file mode 100644 index 0000000..6f8d714 --- /dev/null +++ b/Common/src/main/java/com/almostreliable/unified/ReplacementData.java @@ -0,0 +1,42 @@ +package com.almostreliable.unified; + +import com.almostreliable.unified.api.StoneStrataHandler; +import com.almostreliable.unified.config.UnifyConfig; +import com.almostreliable.unified.utils.ReplacementMap; +import com.almostreliable.unified.utils.TagMap; +import com.almostreliable.unified.utils.TagOwnerships; +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; + +import java.util.Collection; +import java.util.Map; + +/** + * Holder class for storing all the data needed for replacements in recipes. + * + * @param globalTagMap The global tag map, containing all tags. + * @param filteredTagMap The filtered tag map, containing only the tags that will be used for replacing. Determined by the unify config. + * @param stoneStrataHandler The stone strata handler, used for replacing stone strata. + * @param replacementMap The replacement map, used for replacing items. + */ +public record ReplacementData(TagMap globalTagMap, TagMap filteredTagMap, + StoneStrataHandler stoneStrataHandler, + ReplacementMap replacementMap) { + + public static ReplacementData load(Map>> tags, UnifyConfig unifyConfig, TagOwnerships tagOwnerships) { + var globalTagMap = TagMap.createFromItemTags(tags); + var unifyTags = unifyConfig.bakeAndValidateTags(tags); + var filteredTagMap = globalTagMap.filtered(unifyTags::contains, unifyConfig::includeItem); + + var stoneStrataHandler = StoneStrataHandler.create( + unifyConfig.getStoneStrata(), + AlmostUnifiedPlatform.INSTANCE.getStoneStrataTags(unifyConfig.getStoneStrata()), + globalTagMap + ); + + var replacementMap = new ReplacementMap(unifyConfig, filteredTagMap, stoneStrataHandler, tagOwnerships); + + return new ReplacementData(globalTagMap, filteredTagMap, stoneStrataHandler, replacementMap); + } +} diff --git a/Common/src/main/java/com/almostreliable/unified/api/ModConstants.java b/Common/src/main/java/com/almostreliable/unified/api/ModConstants.java index 8998d65..8cd55aa 100644 --- a/Common/src/main/java/com/almostreliable/unified/api/ModConstants.java +++ b/Common/src/main/java/com/almostreliable/unified/api/ModConstants.java @@ -13,6 +13,7 @@ public final class ModConstants { public static final String ARS_ELEMENTAL = "ars_elemental"; public static final String ARS_NOUVEAU = "ars_nouveau"; public static final String ARS_SCALAES = "ars_scalaes"; + public static final String CYCLIC = "cyclic"; public static final String IMMERSIVE_ENGINEERING = "immersiveengineering"; public static final String MEKANISM = "mekanism"; public static final String MODERN_INDUSTRIALIZATION = "modern_industrialization"; diff --git a/Common/src/main/java/com/almostreliable/unified/api/StoneStrataHandler.java b/Common/src/main/java/com/almostreliable/unified/api/StoneStrataHandler.java index 9e7ebdc..8d7df6a 100644 --- a/Common/src/main/java/com/almostreliable/unified/api/StoneStrataHandler.java +++ b/Common/src/main/java/com/almostreliable/unified/api/StoneStrataHandler.java @@ -9,18 +9,18 @@ import net.minecraft.world.item.Item; import java.util.*; import java.util.regex.Pattern; -public class StoneStrataHandler { +public final class StoneStrataHandler { private final List stoneStrata; private final Pattern tagMatcher; - private final TagMap stoneStrataTagMap; + private final TagMap stoneStrataTagMap; // don't clear the caches, so they are available for the runtime and KubeJS binding // the runtime holding this handler is automatically yeeted on reload private final Map, Boolean> stoneStrataTagCache; private final Map stoneStrataCache; - private StoneStrataHandler(List stoneStrata, Pattern tagMatcher, TagMap stoneStrataTagMap) { + private StoneStrataHandler(List stoneStrata, Pattern tagMatcher, TagMap stoneStrataTagMap) { this.stoneStrata = createSortedStoneStrata(stoneStrata); this.tagMatcher = tagMatcher; this.stoneStrataTagMap = stoneStrataTagMap; @@ -41,8 +41,8 @@ public class StoneStrataHandler { return stoneStrata.stream().sorted(Comparator.comparingInt(String::length).reversed()).toList(); } - public static StoneStrataHandler create(List stoneStrataIds, Set> stoneStrataTags, TagMap tagMap) { - TagMap stoneStrataTagMap = tagMap.filtered(stoneStrataTags::contains, item -> true); + public static StoneStrataHandler create(List stoneStrataIds, Set> stoneStrataTags, TagMap tagMap) { + var stoneStrataTagMap = tagMap.filtered(stoneStrataTags::contains, item -> true); Pattern tagMatcher = Pattern.compile(switch (AlmostUnifiedPlatform.INSTANCE.getPlatform()) { case FORGE -> "forge:ores/.+"; case FABRIC -> "(c:ores/.+|c:.+_ores)"; @@ -71,7 +71,7 @@ public class StoneStrataHandler { */ private String computeStoneStrata(ResourceLocation item) { String strata = stoneStrataTagMap - .getTagsByItem(item) + .getTagsByEntry(item) .stream() .findFirst() .map(UnifyTag::location) diff --git a/Common/src/main/java/com/almostreliable/unified/api/recipe/RecipeConstants.java b/Common/src/main/java/com/almostreliable/unified/api/recipe/RecipeConstants.java index 8230c36..ec3ec51 100644 --- a/Common/src/main/java/com/almostreliable/unified/api/recipe/RecipeConstants.java +++ b/Common/src/main/java/com/almostreliable/unified/api/recipe/RecipeConstants.java @@ -42,5 +42,8 @@ public final class RecipeConstants { public static final String ITEM_INPUTS = "item_inputs"; public static final String ITEM_OUTPUTS = "item_outputs"; + // cyclic + public static final String BONUS = "bonus"; + private RecipeConstants() {} } diff --git a/Common/src/main/java/com/almostreliable/unified/compat/HideHelper.java b/Common/src/main/java/com/almostreliable/unified/compat/HideHelper.java index e57ffe0..70bd0c7 100644 --- a/Common/src/main/java/com/almostreliable/unified/compat/HideHelper.java +++ b/Common/src/main/java/com/almostreliable/unified/compat/HideHelper.java @@ -3,7 +3,8 @@ package com.almostreliable.unified.compat; import com.almostreliable.unified.AlmostUnified; import com.almostreliable.unified.AlmostUnifiedRuntime; import com.almostreliable.unified.utils.ReplacementMap; -import com.almostreliable.unified.utils.TagMap; +import com.almostreliable.unified.utils.TagOwnerships; +import com.almostreliable.unified.utils.Utils; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; @@ -16,22 +17,23 @@ import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; -public class HideHelper { +public final class HideHelper { + + private HideHelper() {} public static Collection createHidingList(AlmostUnifiedRuntime runtime) { ReplacementMap repMap = runtime.getReplacementMap().orElse(null); - TagMap tagMap = runtime.getFilteredTagMap().orElse(null); + var tagMap = runtime.getFilteredTagMap().orElse(null); if (repMap == null || tagMap == null) return new ArrayList<>(); Set hidingList = new HashSet<>(); for (var unifyTag : tagMap.getTags()) { - var itemsByTag = tagMap.getItemsByTag(unifyTag); + var itemsByTag = tagMap.getEntriesByTag(unifyTag); - // avoid hiding single entries and tags that only contain the same namespace for all items - long namespaces = itemsByTag.stream().map(ResourceLocation::getNamespace).distinct().count(); - if (namespaces <= 1) continue; + // avoid handling single entries and tags that only contain the same namespace for all items + if (Utils.allSameNamespace(itemsByTag)) continue; Set replacements = new HashSet<>(); for (ResourceLocation item : itemsByTag) { @@ -89,8 +91,9 @@ public class HideHelper { */ private static Set getRefItems(ReplacementMap repMap) { Set hidingList = new HashSet<>(); + TagOwnerships ownerships = repMap.getTagOwnerships(); - AlmostUnified.getRuntime().getTagOwnerships().ifPresent(ownerships -> ownerships.getRefs().forEach(ref -> { + ownerships.getRefs().forEach(ref -> { var owner = ownerships.getOwnerByTag(ref); assert owner != null; @@ -114,7 +117,7 @@ public class HideHelper { ); hidingList.addAll(refItems); - })); + }); return hidingList; } diff --git a/Common/src/main/java/com/almostreliable/unified/compat/RecipeIndicator.java b/Common/src/main/java/com/almostreliable/unified/compat/RecipeIndicator.java index a072d40..e66c19c 100644 --- a/Common/src/main/java/com/almostreliable/unified/compat/RecipeIndicator.java +++ b/Common/src/main/java/com/almostreliable/unified/compat/RecipeIndicator.java @@ -52,6 +52,4 @@ public final class RecipeIndicator { GuiComponent.blit(poseStack, 0, 0, 0, 0, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE); poseStack.popPose(); } - - public record RenderEntry(int pX, int pY) {} } diff --git a/Common/src/main/java/com/almostreliable/unified/config/DebugConfig.java b/Common/src/main/java/com/almostreliable/unified/config/DebugConfig.java index 56e50fb..4e2e6e7 100644 --- a/Common/src/main/java/com/almostreliable/unified/config/DebugConfig.java +++ b/Common/src/main/java/com/almostreliable/unified/config/DebugConfig.java @@ -6,6 +6,7 @@ import com.almostreliable.unified.utils.TagMap; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; import org.apache.commons.lang3.StringUtils; import java.util.Comparator; @@ -29,7 +30,7 @@ public class DebugConfig extends Config { this.dumpRecipes = dumpRecipes; } - public void logUnifyTagDump(TagMap tagMap) { + public void logUnifyTagDump(TagMap tagMap) { if (!dumpTagMap) { return; } @@ -40,7 +41,7 @@ public class DebugConfig extends Config { .stream() .sorted(Comparator.comparing(t -> t.location().toString())) .map(t -> StringUtils.rightPad(t.location().toString(), 40) + " => " + tagMap - .getItemsByTag(t) + .getEntriesByTag(t) .stream() .map(ResourceLocation::toString) .sorted() diff --git a/Common/src/main/java/com/almostreliable/unified/config/Defaults.java b/Common/src/main/java/com/almostreliable/unified/config/Defaults.java index 77e995d..6eaeb2a 100644 --- a/Common/src/main/java/com/almostreliable/unified/config/Defaults.java +++ b/Common/src/main/java/com/almostreliable/unified/config/Defaults.java @@ -1,6 +1,6 @@ package com.almostreliable.unified.config; -import com.almostreliable.unified.Platform; +import com.almostreliable.unified.AlmostUnifiedPlatform; import com.almostreliable.unified.utils.JsonCompare; import net.minecraft.resources.ResourceLocation; @@ -70,7 +70,7 @@ public final class Defaults { private Defaults() {} - public static List getModPriorities(Platform platform) { + public static List getModPriorities(AlmostUnifiedPlatform.Platform platform) { return switch (platform) { case FORGE -> List.of( "minecraft", @@ -93,7 +93,7 @@ public final class Defaults { }; } - public static List getTags(Platform platform) { + public static List getTags(AlmostUnifiedPlatform.Platform platform) { return switch (platform) { case FORGE -> List.of( "forge:nuggets/{material}", @@ -129,17 +129,17 @@ public final class Defaults { }; } - public static List getIgnoredRecipeTypes(Platform platform) { + public static List getIgnoredRecipeTypes(AlmostUnifiedPlatform.Platform platform) { return switch (platform) { default -> List.of("cucumber:shaped_tag"); }; } - public static JsonCompare.CompareSettings getDefaultDuplicateRules(Platform platform) { + public static JsonCompare.CompareSettings getDefaultDuplicateRules(AlmostUnifiedPlatform.Platform platform) { JsonCompare.CompareSettings result = new JsonCompare.CompareSettings(); result.ignoreField(switch (platform) { case FORGE -> "conditions"; - case FABRIC -> "fabric:conditions"; + case FABRIC -> "fabric:load_conditions"; }); result.ignoreField("group"); result.addRule("cookingtime", new JsonCompare.HigherRule()); @@ -148,11 +148,11 @@ public final class Defaults { return result; } - public static LinkedHashMap getDefaultDuplicateOverrides(Platform platform) { + public static LinkedHashMap getDefaultDuplicateOverrides(AlmostUnifiedPlatform.Platform platform) { JsonCompare.CompareSettings result = new JsonCompare.CompareSettings(); result.ignoreField(switch (platform) { case FORGE -> "conditions"; - case FABRIC -> "fabric:conditions"; + case FABRIC -> "fabric:load_conditions"; }); result.ignoreField("group"); result.ignoreField("pattern"); diff --git a/Common/src/main/java/com/almostreliable/unified/config/ServerConfigs.java b/Common/src/main/java/com/almostreliable/unified/config/ServerConfigs.java index 7ba43a8..42ba7f7 100644 --- a/Common/src/main/java/com/almostreliable/unified/config/ServerConfigs.java +++ b/Common/src/main/java/com/almostreliable/unified/config/ServerConfigs.java @@ -1,5 +1,11 @@ package com.almostreliable.unified.config; +import com.almostreliable.unified.AlmostUnifiedPlatform; +import com.almostreliable.unified.utils.FileUtils; + +import java.nio.file.Files; +import java.nio.file.Path; + public class ServerConfigs { private final UnifyConfig unifyConfig; @@ -7,6 +13,7 @@ public class ServerConfigs { private final DebugConfig debugConfig; public static ServerConfigs load() { + createGitIgnoreIfNotExists(); UnifyConfig unifyConfig = Config.load(UnifyConfig.NAME, new UnifyConfig.Serializer()); DuplicationConfig dupConfig = Config.load(DuplicationConfig.NAME, new DuplicationConfig.Serializer()); DebugConfig debugConfig = Config.load(DebugConfig.NAME, new DebugConfig.Serializer()); @@ -19,6 +26,17 @@ public class ServerConfigs { this.debugConfig = debugConfig; } + private static void createGitIgnoreIfNotExists() { + Path path = AlmostUnifiedPlatform.INSTANCE.getConfigPath(); + if (!(Files.exists(path) && Files.isDirectory(path))) { + FileUtils.write( + AlmostUnifiedPlatform.INSTANCE.getConfigPath(), + ".gitignore", + sb -> sb.append(DebugConfig.NAME).append(".json").append("\n") + ); + } + } + public UnifyConfig getUnifyConfig() { return unifyConfig; } diff --git a/Common/src/main/java/com/almostreliable/unified/config/UnifyConfig.java b/Common/src/main/java/com/almostreliable/unified/config/UnifyConfig.java index c980046..a03c32f 100644 --- a/Common/src/main/java/com/almostreliable/unified/config/UnifyConfig.java +++ b/Common/src/main/java/com/almostreliable/unified/config/UnifyConfig.java @@ -5,11 +5,15 @@ import com.almostreliable.unified.AlmostUnifiedPlatform; import com.almostreliable.unified.utils.JsonUtils; import com.almostreliable.unified.utils.UnifyTag; import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import net.minecraft.core.Holder; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; import javax.annotation.Nullable; import java.util.*; +import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -22,6 +26,10 @@ public class UnifyConfig extends Config { private final List materials; private final Map priorityOverrides; private final Map> tagOwnerships; + private final Enum itemTagInheritanceMode; + private final Map> itemTagInheritance; + private final Enum blockTagInheritanceMode; + private final Map> blockTagInheritance; private final Set> ignoredTags; private final Set ignoredItems; private final Set ignoredRecipeTypes; @@ -38,6 +46,10 @@ public class UnifyConfig extends Config { List materials, Map priorityOverrides, Map> tagOwnerships, + Enum itemTagInheritanceMode, + Map> itemTagInheritance, + Enum blockTagInheritanceMode, + Map> blockTagInheritance, Set> ignoredTags, Set ignoredItems, Set ignoredRecipeTypes, @@ -50,6 +62,10 @@ public class UnifyConfig extends Config { this.materials = materials; this.priorityOverrides = priorityOverrides; this.tagOwnerships = tagOwnerships; + this.itemTagInheritanceMode = itemTagInheritanceMode; + this.itemTagInheritance = itemTagInheritance; + this.blockTagInheritanceMode = blockTagInheritanceMode; + this.blockTagInheritance = blockTagInheritance; this.ignoredTags = ignoredTags; this.ignoredItems = ignoredItems; this.ignoredRecipeTypes = ignoredRecipeTypes; @@ -67,11 +83,20 @@ public class UnifyConfig extends Config { } public Set> bakeTags() { + return bakeTags($ -> true); + } + + public Set> bakeAndValidateTags(Map>> tags) { + return bakeTags(tags::containsKey); + } + + private Set> bakeTags(Predicate tagValidator) { if (bakedTagsCache != null) { return bakedTagsCache; } Set> result = new HashSet<>(); + Set> wrongTags = new HashSet<>(); for (String tag : unbakedTags) { for (String material : materials) { @@ -83,12 +108,24 @@ public class UnifyConfig extends Config { } UnifyTag t = UnifyTag.item(asRL); - if (!ignoredTags.contains(t)) { - result.add(t); + if (ignoredTags.contains(t)) continue; + + if (!tagValidator.test(asRL)) { + wrongTags.add(t); + continue; } + + result.add(t); } } + if (!wrongTags.isEmpty()) { + AlmostUnified.LOG.warn( + "The following tags are invalid and will be ignored: {}", + wrongTags.stream().map(UnifyTag::location).collect(Collectors.toList()) + ); + } + bakedTagsCache = result; return result; } @@ -107,6 +144,45 @@ public class UnifyConfig extends Config { return Collections.unmodifiableMap(tagOwnerships); } + public boolean shouldInheritItemTag(UnifyTag itemTag, Set> dominantTags) { + var patterns = itemTagInheritance.get(itemTag.location()); + boolean result = checkPatterns(dominantTags, patterns); + // noinspection SimplifiableConditionalExpression + return itemTagInheritanceMode == TagInheritanceMode.ALLOW ? result : !result; + } + + public boolean shouldInheritBlockTag(UnifyTag itemTag, Set> dominantTags) { + var patterns = blockTagInheritance.get(itemTag.location()); + boolean result = checkPatterns(dominantTags, patterns); + // noinspection SimplifiableConditionalExpression + return blockTagInheritanceMode == TagInheritanceMode.ALLOW ? result : !result; + } + + /** + * Checks all patterns against all dominant tags. + *

+ * This implementation works based on the assumption that the mode is {@link TagInheritanceMode#ALLOW}. + * Flip the result if the mode is {@link TagInheritanceMode#DENY}. + * + * @param dominantTags The tags of the dominant item to check. + * @param patterns The patterns to check against. + * @param The type of the dominant tags. + * @return Whether the dominant tags match any of the patterns. + */ + private static boolean checkPatterns(Set> dominantTags, @Nullable Set patterns) { + if (patterns == null) return false; + + for (var pattern : patterns) { + for (var dominantTag : dominantTags) { + if (pattern.matcher(dominantTag.location().toString()).matches()) { + return true; + } + } + } + + return false; + } + public boolean includeItem(ResourceLocation item) { for (Pattern pattern : ignoredItems) { if (pattern.matcher(item.toString()).matches()) { @@ -152,6 +228,10 @@ public class UnifyConfig extends Config { public static final String MATERIALS = "materials"; public static final String PRIORITY_OVERRIDES = "priorityOverrides"; public static final String TAG_OWNERSHIPS = "tagOwnerships"; + public static final String ITEM_TAG_INHERITANCE_MODE = "itemTagInheritanceMode"; + public static final String ITEM_TAG_INHERITANCE = "itemTagInheritance"; + public static final String BLOCK_TAG_INHERITANCE_MODE = "blockTagInheritanceMode"; + public static final String BLOCK_TAG_INHERITANCE = "blockTagInheritance"; public static final String IGNORED_TAGS = "ignoredTags"; public static final String IGNORED_ITEMS = "ignoredItems"; public static final String IGNORED_RECIPE_TYPES = "ignoredRecipeTypes"; @@ -168,6 +248,7 @@ public class UnifyConfig extends Config { List tags = safeGet(() -> JsonUtils.toList(json.getAsJsonArray(TAGS)), Defaults.getTags(platform)); List materials = safeGet(() -> JsonUtils.toList(json.getAsJsonArray(MATERIALS)), Defaults.MATERIALS); + Map priorityOverrides = safeGet(() -> json.getAsJsonObject(PRIORITY_OVERRIDES) .entrySet() .stream() @@ -176,6 +257,7 @@ public class UnifyConfig extends Config { entry -> entry.getValue().getAsString(), (a, b) -> b, HashMap::new)), new HashMap<>()); + Map> tagOwnerships = safeGet(() -> json .getAsJsonObject(TAG_OWNERSHIPS) .entrySet() @@ -188,6 +270,17 @@ public class UnifyConfig extends Config { .collect(Collectors.toSet()), (a, b) -> b, HashMap::new)), new HashMap<>()); + + + Enum itemTagInheritanceMode = deserializeTagInheritanceMode(json, + ITEM_TAG_INHERITANCE_MODE); + Map> itemTagInheritance = deserializePatternsForLocations(json, + ITEM_TAG_INHERITANCE); + Enum blockTagInheritanceMode = deserializeTagInheritanceMode(json, + BLOCK_TAG_INHERITANCE_MODE); + Map> blockTagInheritance = deserializePatternsForLocations(json, + BLOCK_TAG_INHERITANCE); + Set> ignoredTags = safeGet(() -> JsonUtils .toList(json.getAsJsonArray(IGNORED_TAGS)) .stream() @@ -206,6 +299,10 @@ public class UnifyConfig extends Config { materials, priorityOverrides, tagOwnerships, + itemTagInheritanceMode, + itemTagInheritance, + blockTagInheritanceMode, + blockTagInheritance, ignoredTags, ignoredItems, ignoredRecipeTypes, @@ -214,6 +311,43 @@ public class UnifyConfig extends Config { ); } + private TagInheritanceMode deserializeTagInheritanceMode(JsonObject json, String key) { + return safeGet(() -> TagInheritanceMode.valueOf(json + .getAsJsonPrimitive(key) + .getAsString().toUpperCase()), TagInheritanceMode.ALLOW); + } + + /** + * Deserializes a list of patterns from a json object with a base key. Example json: + *

+         * {
+         *   "baseKey": {
+         *     "location1": [ pattern1, pattern2 ],
+         *     "location2": [ pattern3, pattern4 ]
+         *   }
+         * }
+         * 
+ * + * @param rawConfigJson The raw config json + * @param baseKey The base key + * @return The deserialized patterns separated by location + */ + private Map> unsafeDeserializePatternsForLocations(JsonObject rawConfigJson, String baseKey) { + JsonObject json = rawConfigJson.getAsJsonObject(baseKey); + return json + .keySet() + .stream() + .collect(Collectors.toMap( + ResourceLocation::new, + key -> deserializePatterns(json, key, List.of()), + (a, b) -> b, + HashMap::new)); + } + + private Map> deserializePatternsForLocations(JsonObject rawConfigJson, String baseKey) { + return safeGet(() -> unsafeDeserializePatternsForLocations(rawConfigJson, baseKey), new HashMap<>()); + } + @Override public JsonObject serialize(UnifyConfig config) { JsonObject json = new JsonObject(); @@ -232,6 +366,20 @@ public class UnifyConfig extends Config { JsonUtils.toArray(child.stream().map(ResourceLocation::toString).toList())); }); json.add(TAG_OWNERSHIPS, tagOwnerships); + JsonObject itemTagInheritance = new JsonObject(); + config.itemTagInheritance.forEach((tag, patterns) -> { + itemTagInheritance.add(tag.toString(), + JsonUtils.toArray(patterns.stream().map(Pattern::toString).toList())); + }); + json.add(ITEM_TAG_INHERITANCE_MODE, new JsonPrimitive(config.itemTagInheritanceMode.toString())); + json.add(ITEM_TAG_INHERITANCE, itemTagInheritance); + JsonObject blockTagInheritance = new JsonObject(); + config.blockTagInheritance.forEach((tag, patterns) -> { + blockTagInheritance.add(tag.toString(), + JsonUtils.toArray(patterns.stream().map(Pattern::toString).toList())); + }); + json.add(BLOCK_TAG_INHERITANCE_MODE, new JsonPrimitive(config.blockTagInheritanceMode.toString())); + json.add(BLOCK_TAG_INHERITANCE, blockTagInheritance); json.add(IGNORED_TAGS, JsonUtils.toArray(config.ignoredTags .stream() @@ -245,4 +393,9 @@ public class UnifyConfig extends Config { return json; } } + + public enum TagInheritanceMode { + ALLOW, + DENY + } } diff --git a/Common/src/main/java/com/almostreliable/unified/mixin/runtime/RecipeManagerMixin.java b/Common/src/main/java/com/almostreliable/unified/mixin/runtime/RecipeManagerMixin.java index 36c8de3..50c9138 100644 --- a/Common/src/main/java/com/almostreliable/unified/mixin/runtime/RecipeManagerMixin.java +++ b/Common/src/main/java/com/almostreliable/unified/mixin/runtime/RecipeManagerMixin.java @@ -20,8 +20,7 @@ public class RecipeManagerMixin { @Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At("HEAD")) private void runTransformation(Map recipes, ResourceManager resourceManager, ProfilerFiller profiler, CallbackInfo ci) { try { - AlmostUnified.onReloadRecipeManager(); - AlmostUnified.getRuntime().run(recipes, AlmostUnified.getStartupConfig().isServerOnly()); + AlmostUnified.onRecipeManagerReload(recipes); } catch (Exception e) { AlmostUnified.LOG.error(e.getMessage(), e); } diff --git a/Common/src/main/java/com/almostreliable/unified/mixin/runtime/TagLoaderMixin.java b/Common/src/main/java/com/almostreliable/unified/mixin/runtime/TagLoaderMixin.java index deab7bc..2a29334 100644 --- a/Common/src/main/java/com/almostreliable/unified/mixin/runtime/TagLoaderMixin.java +++ b/Common/src/main/java/com/almostreliable/unified/mixin/runtime/TagLoaderMixin.java @@ -1,11 +1,13 @@ package com.almostreliable.unified.mixin.runtime; import com.almostreliable.unified.AlmostUnified; +import com.almostreliable.unified.utils.TagReloadHandler; import com.almostreliable.unified.utils.Utils; import net.minecraft.core.Holder; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagLoader; import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -26,10 +28,20 @@ public class TagLoaderMixin { private void onCreateLoadResult(Map> map, CallbackInfoReturnable>> cir) { if (directory.equals("tags/items")) { try { - Map>> rawTags = Utils.cast(cir.getReturnValue()); - AlmostUnified.getRuntime().getTagOwnerships().ifPresent(to -> to.applyOwnershipToRawTags(rawTags)); + Map>> tags = Utils.cast(cir.getReturnValue()); + TagReloadHandler.initItemTags(tags); + TagReloadHandler.run(); } catch (Exception e) { - AlmostUnified.LOG.error("Error applying tag ownerships to raw tags", e); + AlmostUnified.LOG.error(e.getMessage(), e); + } + } + if (directory.equals("tags/blocks")) { + try { + Map>> tags = Utils.cast(cir.getReturnValue()); + TagReloadHandler.initBlockTags(tags); + TagReloadHandler.run(); + } catch (Exception e) { + AlmostUnified.LOG.error(e.getMessage(), e); } } } diff --git a/Common/src/main/java/com/almostreliable/unified/mixin/runtime/TagManagerMixin.java b/Common/src/main/java/com/almostreliable/unified/mixin/runtime/TagManagerMixin.java deleted file mode 100644 index 5093b3a..0000000 --- a/Common/src/main/java/com/almostreliable/unified/mixin/runtime/TagManagerMixin.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.almostreliable.unified.mixin.runtime; - -import com.almostreliable.unified.AlmostUnified; -import net.minecraft.server.packs.resources.PreparableReloadListener; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.tags.TagManager; -import net.minecraft.util.profiling.ProfilerFiller; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -@Mixin(TagManager.class) -public class TagManagerMixin { - - @Inject(method = "reload", at = @At("HEAD")) - private void onReload(PreparableReloadListener.PreparationBarrier preparationBarrier, ResourceManager resourceManager, ProfilerFiller profilerFiller, ProfilerFiller profilerFiller2, Executor executor, Executor executor2, CallbackInfoReturnable> cir) { - AlmostUnified.onTagManagerReload((TagManager) (Object) this); - } -} diff --git a/Common/src/main/java/com/almostreliable/unified/recipe/RecipeContextImpl.java b/Common/src/main/java/com/almostreliable/unified/recipe/RecipeContextImpl.java index 7703c04..b2398ae 100644 --- a/Common/src/main/java/com/almostreliable/unified/recipe/RecipeContextImpl.java +++ b/Common/src/main/java/com/almostreliable/unified/recipe/RecipeContextImpl.java @@ -1,6 +1,5 @@ package com.almostreliable.unified.recipe; -import com.almostreliable.unified.AlmostUnified; import com.almostreliable.unified.api.recipe.RecipeConstants; import com.almostreliable.unified.api.recipe.RecipeContext; import com.almostreliable.unified.utils.JsonUtils; @@ -83,11 +82,10 @@ public class RecipeContextImpl implements RecipeContext { if (object.get(RecipeConstants.TAG) instanceof JsonPrimitive primitive) { UnifyTag tag = Utils.toItemTag(primitive.getAsString()); - AlmostUnified.getRuntime() - .getTagOwnerships() - .map(o -> o.getOwnerByTag(tag)) - .ifPresent(ownerTag -> object.addProperty(RecipeConstants.TAG, - ownerTag.location().toString())); + var ownerTag = replacementMap.getTagOwnerships().getOwnerByTag(tag); + if (ownerTag != null) { + object.addProperty(RecipeConstants.TAG, ownerTag.location().toString()); + } } if (object.get(RecipeConstants.ITEM) instanceof JsonPrimitive primitive) { diff --git a/Common/src/main/java/com/almostreliable/unified/utils/ReplacementMap.java b/Common/src/main/java/com/almostreliable/unified/utils/ReplacementMap.java index 99adec6..b9da89b 100644 --- a/Common/src/main/java/com/almostreliable/unified/utils/ReplacementMap.java +++ b/Common/src/main/java/com/almostreliable/unified/utils/ReplacementMap.java @@ -17,12 +17,12 @@ import java.util.function.Predicate; public class ReplacementMap { private final UnifyConfig unifyConfig; - private final TagMap tagMap; + private final TagMap tagMap; private final StoneStrataHandler stoneStrataHandler; private final TagOwnerships tagOwnerships; private final Set warnings; - public ReplacementMap(UnifyConfig unifyConfig, TagMap tagMap, StoneStrataHandler stoneStrataHandler, TagOwnerships tagOwnerships) { + public ReplacementMap(UnifyConfig unifyConfig, TagMap tagMap, StoneStrataHandler stoneStrataHandler, TagOwnerships tagOwnerships) { this.tagMap = tagMap; this.unifyConfig = unifyConfig; this.stoneStrataHandler = stoneStrataHandler; @@ -32,7 +32,7 @@ public class ReplacementMap { @Nullable public UnifyTag getPreferredTagForItem(ResourceLocation item) { - Collection> tags = tagMap.getTagsByItem(item); + Collection> tags = tagMap.getTagsByEntry(item); if (tags.isEmpty()) { return null; @@ -71,7 +71,7 @@ public class ReplacementMap { if (tagToLookup == null) tagToLookup = tag; List items = tagMap - .getItemsByTag(tagToLookup) + .getEntriesByTag(tagToLookup) .stream() .filter(itemFilter) // Helps us to get the clean stone variant first in case of a stone strata tag @@ -143,4 +143,8 @@ public class ReplacementMap { } return null; } + + public TagOwnerships getTagOwnerships() { + return tagOwnerships; + } } diff --git a/Common/src/main/java/com/almostreliable/unified/utils/TagMap.java b/Common/src/main/java/com/almostreliable/unified/utils/TagMap.java index 66cb5b8..18d79b0 100644 --- a/Common/src/main/java/com/almostreliable/unified/utils/TagMap.java +++ b/Common/src/main/java/com/almostreliable/unified/utils/TagMap.java @@ -5,33 +5,34 @@ import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; -import net.minecraft.tags.TagManager; +import net.minecraft.tags.TagLoader; import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; import java.util.*; import java.util.function.Predicate; -public class TagMap { +public class TagMap { - private final Map, Set> tagsToItems = new HashMap<>(); - private final Map>> itemsToTags = new HashMap<>(); + private final Map, Set> tagsToEntries = new HashMap<>(); + private final Map>> entriesToTags = new HashMap<>(); protected TagMap() {} /** - * Creates a tag map from a set of unify tags. + * Creates an item tag map from a set of item unify tags. *

* This should only be used for client-side tag maps or for tests.
* It requires the registry to be loaded in order to validate the tags * and fetch the holder from it. *

- * For the server, use {@link #create(TagManager)} instead. + * For the server, use {@link #createFromItemTags(Map)} instead. * * @param unifyTags The unify tags. * @return A new tag map. */ - public static TagMap create(Set> unifyTags) { - TagMap tagMap = new TagMap(); + public static TagMap create(Set> unifyTags) { + TagMap tagMap = new TagMap<>(); unifyTags.forEach(ut -> { TagKey asTagKey = TagKey.create(Registry.ITEM_REGISTRY, ut.location()); @@ -45,104 +46,115 @@ public class TagMap { } /** - * Creates a tag map from the vanilla {@link TagManager}. + * Creates an item tag map from the vanilla item tag collection passed by the {@link TagLoader}. *

* This should only be used on the server.
- * It will fetch all tags and items from the manager and store them. This tag map should later - * be filtered by using {@link #filtered(Predicate, Predicate)}. + * This tag map should later be filtered by using {@link #filtered(Predicate, Predicate)}. *

* For the client, use {@link #create(Set)} instead. * - * @param tagManager The vanilla tag manager. - * @return A new tag map. + * @param tags The vanilla item tag collection. + * @return A new item tag map. */ - public static TagMap create(TagManager tagManager) { - var tags = unpackTagManager(tagManager); - TagMap tagMap = new TagMap(); + public static TagMap createFromItemTags(Map>> tags) { + TagMap tagMap = new TagMap<>(); for (var entry : tags.entrySet()) { UnifyTag unifyTag = UnifyTag.item(entry.getKey()); - for (Holder holder : entry.getValue()) { - holder - .unwrapKey() - .map(ResourceKey::location) - .filter(Registry.ITEM::containsKey) - .ifPresent(itemId -> tagMap.put(unifyTag, itemId)); - } + fillEntries(tagMap, entry.getValue(), unifyTag, Registry.ITEM); } return tagMap; } + /** + * Creates a block tag map from the vanilla block tag collection passed by the {@link TagLoader}. + *

+ * This should only be used on the server. + * + * @param tags The vanilla block tag collection. + * @return A new block tag map. + */ + public static TagMap createFromBlockTags(Map>> tags) { + TagMap tagMap = new TagMap<>(); + + for (var entry : tags.entrySet()) { + UnifyTag unifyTag = UnifyTag.block(entry.getKey()); + fillEntries(tagMap, entry.getValue(), unifyTag, Registry.BLOCK); + } + + return tagMap; + } + + /** + * Unwrap all holders, verify them and put them into the tag map. + * + * @param tagMap The tag map to fill. + * @param holders The holders to unwrap. + * @param unifyTag The unify tag to use. + * @param registry The registry to use. + */ + private static void fillEntries(TagMap tagMap, Collection> holders, UnifyTag unifyTag, Registry registry) { + for (var holder : holders) { + holder + .unwrapKey() + .map(ResourceKey::location) + .filter(registry::containsKey) + .ifPresent(id -> tagMap.put(unifyTag, id)); + } + } + /** * Creates a filtered tag map copy. * - * @param tagFilter A filter to determine which tags to include. - * @param itemFilter A filter to determine which items to include. + * @param tagFilter A filter to determine which tags to include. + * @param entryFilter A filter to determine which entries to include. * @return A filtered copy of this tag map. */ - public TagMap filtered(Predicate> tagFilter, Predicate itemFilter) { - TagMap tagMap = new TagMap(); + public TagMap filtered(Predicate> tagFilter, Predicate entryFilter) { + TagMap tagMap = new TagMap<>(); - tagsToItems.forEach((tag, items) -> { + tagsToEntries.forEach((tag, items) -> { if (!tagFilter.test(tag)) { return; } - items.stream().filter(itemFilter).forEach(item -> tagMap.put(tag, item)); + items.stream().filter(entryFilter).forEach(item -> tagMap.put(tag, item)); }); return tagMap; } public int tagSize() { - return tagsToItems.size(); + return tagsToEntries.size(); } public int itemSize() { - return itemsToTags.size(); + return entriesToTags.size(); } - public Set getItemsByTag(UnifyTag tag) { - return Collections.unmodifiableSet(tagsToItems.getOrDefault(tag, Collections.emptySet())); + public Set getEntriesByTag(UnifyTag tag) { + return Collections.unmodifiableSet(tagsToEntries.getOrDefault(tag, Collections.emptySet())); } - public Set> getTagsByItem(ResourceLocation items) { - return Collections.unmodifiableSet(itemsToTags.getOrDefault(items, Collections.emptySet())); + public Set> getTagsByEntry(ResourceLocation entry) { + return Collections.unmodifiableSet(entriesToTags.getOrDefault(entry, Collections.emptySet())); } - public Set> getTags() { - return Collections.unmodifiableSet(tagsToItems.keySet()); + public Set> getTags() { + return Collections.unmodifiableSet(tagsToEntries.keySet()); } /** - * Helper function to build a relationship between a tag and an item. + * Helper function to build a relationship between a tag and an entry. *

* If the entries don't exist in the internal maps yet, they will be created. That means - * it needs to be checked whether the tag or item is valid before calling this method. + * it needs to be checked whether the tag or entry is valid before calling this method. * - * @param tag The tag. - * @param item The item. + * @param tag The tag. + * @param entry The entry. */ - protected void put(UnifyTag tag, ResourceLocation item) { - tagsToItems.computeIfAbsent(tag, k -> new HashSet<>()).add(item); - itemsToTags.computeIfAbsent(item, k -> new HashSet<>()).add(tag); - } - - /** - * Helper function to fetch all item tags and their item holders from the tag manager. - * - * @param tagManager The tag manager. - * @return A map of all item tags and their item holders. - */ - private static Map>> unpackTagManager(TagManager tagManager) { - var tags = tagManager - .getResult() - .stream() - .filter(result -> result.key() == Registry.ITEM_REGISTRY) - .findFirst() - .map(TagManager.LoadResult::tags) - .orElseThrow(() -> new IllegalStateException("No item tag result found")); - - return Utils.cast(tags); + protected void put(UnifyTag tag, ResourceLocation entry) { + tagsToEntries.computeIfAbsent(tag, k -> new HashSet<>()).add(entry); + entriesToTags.computeIfAbsent(entry, k -> new HashSet<>()).add(tag); } } diff --git a/Common/src/main/java/com/almostreliable/unified/utils/TagOwnerships.java b/Common/src/main/java/com/almostreliable/unified/utils/TagOwnerships.java index a280d90..bc72299 100644 --- a/Common/src/main/java/com/almostreliable/unified/utils/TagOwnerships.java +++ b/Common/src/main/java/com/almostreliable/unified/utils/TagOwnerships.java @@ -78,7 +78,7 @@ public class TagOwnerships { * * @param rawTags The raw tags to apply ownerships to. */ - public void applyOwnershipToRawTags(Map>> rawTags) { + public void applyOwnerships(Map>> rawTags) { Multimap changedTags = HashMultimap.create(); ownerToRefs.asMap().forEach((owner, refs) -> { @@ -105,7 +105,7 @@ public class TagOwnerships { for (Holder holder : refHolders) { holders.add(holder); - holder.unwrapKey().ifPresent(key -> changedTags.put(ref.location(), key.location())); + holder.unwrapKey().ifPresent(key -> changedTags.put(owner.location(), key.location())); changed = true; } } diff --git a/Common/src/main/java/com/almostreliable/unified/utils/TagReloadHandler.java b/Common/src/main/java/com/almostreliable/unified/utils/TagReloadHandler.java new file mode 100644 index 0000000..3177ccd --- /dev/null +++ b/Common/src/main/java/com/almostreliable/unified/utils/TagReloadHandler.java @@ -0,0 +1,217 @@ +package com.almostreliable.unified.utils; + +import com.almostreliable.unified.AlmostUnified; +import com.almostreliable.unified.ReplacementData; +import com.almostreliable.unified.config.UnifyConfig; +import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public final class TagReloadHandler { + + private static final Object LOCK = new Object(); + + private static Map>> RAW_ITEM_TAGS; + private static Map>> RAW_BLOCK_TAGS; + + private TagReloadHandler() {} + + public static void initItemTags(Map>> rawItemTags) { + synchronized (LOCK) { + RAW_ITEM_TAGS = rawItemTags; + } + } + + public static void initBlockTags(Map>> rawBlockTags) { + synchronized (LOCK) { + RAW_BLOCK_TAGS = rawBlockTags; + } + } + + public static void run() { + if (RAW_ITEM_TAGS == null || RAW_BLOCK_TAGS == null) { + return; + } + + AlmostUnified.onTagLoaderReload(RAW_ITEM_TAGS); + + RAW_ITEM_TAGS = null; + RAW_BLOCK_TAGS = null; + } + + public static boolean applyInheritance(UnifyConfig unifyConfig, ReplacementData replacementData) { + Preconditions.checkNotNull(RAW_ITEM_TAGS, "Item tags were not loaded correctly"); + Preconditions.checkNotNull(RAW_BLOCK_TAGS, "Block tags were not loaded correctly"); + + Multimap changedItemTags = HashMultimap.create(); + Multimap changedBlockTags = HashMultimap.create(); + + var relations = resolveRelations(replacementData.filteredTagMap(), replacementData.replacementMap()); + if (relations.isEmpty()) return false; + + var blockTagMap = TagMap.createFromBlockTags(RAW_BLOCK_TAGS); + var globalTagMap = replacementData.globalTagMap(); + + for (TagRelation relation : relations) { + var dominant = relation.dominant; + var dominantItemHolder = findDominantItemHolder(relation); + var dominantBlockHolder = findDominantBlockHolder(blockTagMap, dominant); + + var dominantItemTags = globalTagMap.getTagsByEntry(dominant); + + for (var item : relation.items) { + if (dominantItemHolder != null) { + var changed = applyItemTags(unifyConfig, globalTagMap, dominantItemHolder, dominantItemTags, item); + changedItemTags.putAll(dominant, changed); + } + + if (dominantBlockHolder != null) { + var changed = applyBlockTags(unifyConfig, blockTagMap, dominantBlockHolder, dominantItemTags, item); + changedBlockTags.putAll(dominant, changed); + } + } + } + + if (!changedBlockTags.isEmpty()) { + changedBlockTags.asMap().forEach((dominant, tags) -> { + AlmostUnified.LOG.info("[TagInheritance] Added '{}' to block tags {}", dominant, tags); + }); + } + + if (!changedItemTags.isEmpty()) { + changedItemTags.asMap().forEach((dominant, tags) -> { + AlmostUnified.LOG.info("[TagInheritance] Added '{}' to item tags {}", dominant, tags); + }); + return true; + } + + return false; + } + + private static Set resolveRelations(TagMap filteredTagMap, ReplacementMap repMap) { + Set relations = new HashSet<>(); + + for (var unifyTag : filteredTagMap.getTags()) { + var itemsByTag = filteredTagMap.getEntriesByTag(unifyTag); + + // avoid handling single entries and tags that only contain the same namespace for all items + if (Utils.allSameNamespace(itemsByTag)) continue; + + ResourceLocation dominant = repMap.getPreferredItemForTag(unifyTag, $ -> true); + if (dominant == null || !Registry.ITEM.containsKey(dominant)) continue; + + Set items = getValidatedItems(itemsByTag, dominant); + + if (items.isEmpty()) continue; + relations.add(new TagRelation(unifyTag.location(), dominant, items)); + } + + return relations; + } + + /** + * Returns a set of all items that are not the dominant item and are valid by checking if they are registered. + * + * @param itemIds The set of all items that are in the tag + * @param dominant The dominant item + * @return A set of all items that are not the dominant item and are valid + */ + private static Set getValidatedItems(Set itemIds, ResourceLocation dominant) { + Set result = new HashSet<>(itemIds.size()); + for (ResourceLocation id : itemIds) { + if (!id.equals(dominant) && Registry.ITEM.containsKey(id)) { + result.add(id); + } + } + + return result; + } + + @SuppressWarnings("StaticVariableUsedBeforeInitialization") + @Nullable + private static Holder findDominantItemHolder(TagRelation relation) { + var tagHolders = RAW_ITEM_TAGS.get(relation.tag); + if (tagHolders == null) return null; + + return findDominantHolder(tagHolders, relation.dominant); + } + + @SuppressWarnings("StaticVariableUsedBeforeInitialization") + @Nullable + private static Holder findDominantBlockHolder(TagMap tagMap, ResourceLocation dominant) { + var blockTags = tagMap.getTagsByEntry(dominant); + if (blockTags.isEmpty()) return null; + + var tagHolders = RAW_BLOCK_TAGS.get(blockTags.iterator().next().location()); + if (tagHolders == null) return null; + + return findDominantHolder(tagHolders, dominant); + } + + @Nullable + private static Holder findDominantHolder(Collection> holders, ResourceLocation dominant) { + for (var tagHolder : holders) { + var holderKey = tagHolder.unwrapKey(); + if (holderKey.isPresent() && holderKey.get().location().equals(dominant)) { + return tagHolder; + } + } + + return null; + } + + private static Set applyItemTags(UnifyConfig unifyConfig, TagMap globalTagMap, Holder dominantItemHolder, Set> dominantItemTags, ResourceLocation item) { + var itemTags = globalTagMap.getTagsByEntry(item); + Set changed = new HashSet<>(); + + for (var itemTag : itemTags) { + if (!unifyConfig.shouldInheritItemTag(itemTag, dominantItemTags)) continue; + if (tryUpdatingRawTags(dominantItemHolder, itemTag, RAW_ITEM_TAGS)) { + changed.add(itemTag.location()); + } + } + + return changed; + } + + private static Set applyBlockTags(UnifyConfig unifyConfig, TagMap blockTagMap, Holder dominantBlockHolder, Set> dominantItemTags, ResourceLocation item) { + var blockTags = blockTagMap.getTagsByEntry(item); + Set changed = new HashSet<>(); + + for (var blockTag : blockTags) { + if (!unifyConfig.shouldInheritBlockTag(blockTag, dominantItemTags)) continue; + if (tryUpdatingRawTags(dominantBlockHolder, blockTag, RAW_BLOCK_TAGS)) { + changed.add(blockTag.location()); + } + } + + return changed; + } + + private static boolean tryUpdatingRawTags(Holder dominantHolder, UnifyTag tag, Map>> rawTags) { + var tagHolders = rawTags.get(tag.location()); + if (tagHolders == null) return false; + if (tagHolders.contains(dominantHolder)) return false; // already present, no need to add it again + + ImmutableSet.Builder> newHolders = ImmutableSet.builder(); + newHolders.addAll(tagHolders); + newHolders.add(dominantHolder); + + rawTags.put(tag.location(), newHolders.build()); + return true; + } + + private record TagRelation(ResourceLocation tag, ResourceLocation dominant, Set items) {} +} diff --git a/Common/src/main/java/com/almostreliable/unified/utils/UnifyTag.java b/Common/src/main/java/com/almostreliable/unified/utils/UnifyTag.java index fe33c19..3d1d5b5 100644 --- a/Common/src/main/java/com/almostreliable/unified/utils/UnifyTag.java +++ b/Common/src/main/java/com/almostreliable/unified/utils/UnifyTag.java @@ -2,12 +2,17 @@ package com.almostreliable.unified.utils; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; public record UnifyTag(Class boundType, ResourceLocation location) { public static UnifyTag item(ResourceLocation location) { return new UnifyTag<>(Item.class, location); } + public static UnifyTag block(ResourceLocation location) { + return new UnifyTag<>(Block.class, location); + } + @Override public String toString() { return "UnifyTag[" + boundType.getSimpleName().toLowerCase() + " / " + location + "]"; diff --git a/Common/src/main/java/com/almostreliable/unified/utils/Utils.java b/Common/src/main/java/com/almostreliable/unified/utils/Utils.java index ed48af3..c55e345 100644 --- a/Common/src/main/java/com/almostreliable/unified/utils/Utils.java +++ b/Common/src/main/java/com/almostreliable/unified/utils/Utils.java @@ -10,6 +10,7 @@ import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.item.Item; import javax.annotation.Nullable; +import java.util.Set; import java.util.ArrayList; import java.util.List; @@ -56,4 +57,23 @@ public final class Utils { } screen.renderTooltip(stack, formattedTooltip, mX, mY); } + + /** + * Checks if all ids have the same namespace + * + * @param ids set of ids + * @return true if all ids have the same namespace + */ + public static boolean allSameNamespace(Set ids) { + if (ids.size() <= 1) return true; + + var it = ids.iterator(); + var namespace = it.next().getNamespace(); + + while (it.hasNext()) { + if (!it.next().getNamespace().equals(namespace)) return false; + } + + return true; + } } diff --git a/Common/src/main/resources/almostunified-common.mixins.json b/Common/src/main/resources/almostunified-common.mixins.json index 1b57a7a..363932b 100644 --- a/Common/src/main/resources/almostunified-common.mixins.json +++ b/Common/src/main/resources/almostunified-common.mixins.json @@ -7,7 +7,6 @@ "mixins": [ "runtime.RecipeManagerMixin", "runtime.TagLoaderMixin", - "runtime.TagManagerMixin", "unifier.ArmorItemMixin", "unifier.TieredItemMixin" ], diff --git a/Common/src/test/java/com/almostreliable/unified/TestUtils.java b/Common/src/test/java/com/almostreliable/unified/TestUtils.java index c232ba2..d1d1396 100644 --- a/Common/src/test/java/com/almostreliable/unified/TestUtils.java +++ b/Common/src/test/java/com/almostreliable/unified/TestUtils.java @@ -38,10 +38,14 @@ public final class TestUtils { public static final UnifyConfig DEFAULT_UNIFY_CONFIG = new UnifyConfig( Defaults.STONE_STRATA, Defaults.MATERIALS, - Defaults.getTags(Platform.FORGE), + Defaults.getTags(AlmostUnifiedPlatform.Platform.FORGE), TEST_MOD_PRIORITIES, new HashMap<>(), new HashMap<>(), + UnifyConfig.TagInheritanceMode.ALLOW, + new HashMap<>(), + UnifyConfig.TagInheritanceMode.ALLOW, + new HashMap<>(), new HashSet<>(), new HashSet<>(), new HashSet<>(), @@ -55,11 +59,13 @@ public final class TestUtils { private TestUtils() {} public static JsonCompare.CompareSettings getDefaultCompareSettings() { - return Defaults.getDefaultDuplicateRules(Platform.FORGE); + return Defaults.getDefaultDuplicateRules(AlmostUnifiedPlatform.Platform.FORGE); } public static JsonCompare.CompareSettings getDefaultShapedCompareSettings() { - return Defaults.getDefaultDuplicateOverrides(Platform.FORGE).get(new ResourceLocation("crafting_shaped")); + return Defaults + .getDefaultDuplicateOverrides(AlmostUnifiedPlatform.Platform.FORGE) + .get(new ResourceLocation("crafting_shaped")); } public static final ResourceKey> FAKE_ITEM_REGISTRY = FakeResourceKeyRegistry.create("item"); diff --git a/Common/src/test/java/com/almostreliable/unified/utils/TagMapTests.java b/Common/src/test/java/com/almostreliable/unified/utils/TagMapTests.java index 66d4a97..f90bc2f 100644 --- a/Common/src/test/java/com/almostreliable/unified/utils/TagMapTests.java +++ b/Common/src/test/java/com/almostreliable/unified/utils/TagMapTests.java @@ -9,8 +9,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class TagMapTests { - public static TagMap testTagMap() { - TagMap tagMap = new TagMap(); + public static TagMap testTagMap() { + TagMap tagMap = new TagMap<>(); UnifyTag bronzeOreTag = UnifyTag.item(new ResourceLocation("forge:ores/bronze")); UnifyTag invarOreTag = UnifyTag.item(new ResourceLocation("forge:ores/invar")); UnifyTag tinOreTag = UnifyTag.item(new ResourceLocation("forge:ores/tin")); @@ -36,7 +36,7 @@ public class TagMapTests { @Test public void simpleCheck() { - TagMap tagMap = new TagMap(); + TagMap tagMap = new TagMap<>(); UnifyTag bronzeOreTag = UnifyTag.item(new ResourceLocation("forge:ores/bronze")); tagMap.put(bronzeOreTag, TestUtils.mod1RL("bronze_ore")); tagMap.put(bronzeOreTag, TestUtils.mod2RL("bronze_ore")); @@ -44,12 +44,12 @@ public class TagMapTests { tagMap.put(bronzeOreTag, TestUtils.mod4RL("bronze_ore")); tagMap.put(bronzeOreTag, TestUtils.mod5RL("bronze_ore")); - assertEquals(tagMap.getItemsByTag(bronzeOreTag).size(), 5); - assertEquals(tagMap.getTagsByItem(TestUtils.mod1RL("bronze_ore")).size(), 1); - assertEquals(tagMap.getTagsByItem(TestUtils.mod2RL("bronze_ore")).size(), 1); - assertEquals(tagMap.getTagsByItem(TestUtils.mod3RL("bronze_ore")).size(), 1); - assertEquals(tagMap.getTagsByItem(TestUtils.mod4RL("bronze_ore")).size(), 1); - assertEquals(tagMap.getTagsByItem(TestUtils.mod5RL("bronze_ore")).size(), 1); + assertEquals(tagMap.getEntriesByTag(bronzeOreTag).size(), 5); + assertEquals(tagMap.getTagsByEntry(TestUtils.mod1RL("bronze_ore")).size(), 1); + assertEquals(tagMap.getTagsByEntry(TestUtils.mod2RL("bronze_ore")).size(), 1); + assertEquals(tagMap.getTagsByEntry(TestUtils.mod3RL("bronze_ore")).size(), 1); + assertEquals(tagMap.getTagsByEntry(TestUtils.mod4RL("bronze_ore")).size(), 1); + assertEquals(tagMap.getTagsByEntry(TestUtils.mod5RL("bronze_ore")).size(), 1); tagMap.put(UnifyTag.item(new ResourceLocation("forge:ores/invar")), TestUtils.mod1RL("invar_ore")); diff --git a/Fabric/build.gradle.kts b/Fabric/build.gradle.kts index fb0f271..e72c5b0 100644 --- a/Fabric/build.gradle.kts +++ b/Fabric/build.gradle.kts @@ -2,12 +2,11 @@ val minecraftVersion: String by project val fabricLoaderVersion: String by project val fabricApiVersion: String by project val fabricRecipeViewer: String by project -val reiVersion: String by project val jeiVersion: String by project -val kubejsVersion: String by project +val reiVersion: String by project plugins { - id("com.github.johnrengelman.shadow") version ("8.1.1") + id("com.github.johnrengelman.shadow") version "8.1.1" } architectury { @@ -16,7 +15,7 @@ architectury { } loom { - if (project.findProperty("enableAccessWidener") == "true") { // Optional property for `gradle.properties` to enable access wideners. + if (project.findProperty("enableAccessWidener") == "true") { // optional property for `gradle.properties` accessWidenerPath.set(project(":Common").loom.accessWidenerPath) println("Access widener enabled for project ${project.name}. Access widener path: ${loom.accessWidenerPath.get()}") } @@ -24,6 +23,7 @@ loom { val common by configurations val shadowCommon by configurations + dependencies { // loader modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") @@ -34,23 +34,26 @@ dependencies { shadowCommon(project(":Common", "transformProductionFabric")) { isTransitive = false } // compile time mods - modCompileOnly("dev.latvian.mods:kubejs-fabric:$kubejsVersion") // required for common kubejs plugin + modCompileOnly("mezz.jei:jei-$minecraftVersion-fabric-api:$jeiVersion") // required for common jei plugin modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:$reiVersion") // required for common rei plugin - compileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // required to disable rei compat layer on jei plugin - testCompileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // don't question this, it's required for compiling - modCompileOnly("mezz.jei:jei-$minecraftVersion-fabric-api:$jeiVersion") // required for common jei plugin and mixin // runtime dependencies - modLocalRuntime("dev.latvian.mods:kubejs-fabric:$kubejsVersion") { - exclude("net.fabricmc", "fabric-loader") - } modLocalRuntime( when (fabricRecipeViewer) { - "rei" -> "me.shedaniel:RoughlyEnoughItems-fabric:$reiVersion" "jei" -> "mezz.jei:jei-$minecraftVersion-fabric:$jeiVersion" + "rei" -> "me.shedaniel:RoughlyEnoughItems-fabric:$reiVersion" else -> throw GradleException("Invalid fabricRecipeViewer value: $fabricRecipeViewer") } - ) { - exclude("net.fabricmc", "fabric-loader") + ) +} + +/** + * force the fabric loader and api versions that are defined in the project + * some mods ship another version which crashes the runtime + */ +configurations.all { + resolutionStrategy { + force("net.fabricmc:fabric-loader:$fabricLoaderVersion") + force("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion+$minecraftVersion") } } diff --git a/Fabric/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatformFabric.java b/Fabric/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatformFabric.java index 713a6df..8d5baee 100644 --- a/Fabric/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatformFabric.java +++ b/Fabric/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatformFabric.java @@ -28,11 +28,6 @@ public class AlmostUnifiedPlatformFabric implements AlmostUnifiedPlatform { return FabricLoader.getInstance().isModLoaded(modId); } - @Override - public boolean isDevelopmentEnvironment() { - return FabricLoader.getInstance().isDevelopmentEnvironment(); - } - @Override public boolean isClient() { return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT; diff --git a/Forge/build.gradle.kts b/Forge/build.gradle.kts index 0541ca1..47f4f5e 100644 --- a/Forge/build.gradle.kts +++ b/Forge/build.gradle.kts @@ -1,15 +1,15 @@ val minecraftVersion: String by project -val forgeVersion: String by project -val junitVersion: String by project val modId: String by project +val junitVersion: String by project +val forgeVersion: String by project val forgeRecipeViewer: String by project -val reiVersion: String by project val jeiVersion: String by project -val kubejsVersion: String by project +val reiVersion: String by project +val extraModsPrefix = "extra-mods" plugins { - id("com.github.johnrengelman.shadow") version ("8.1.1") + id("com.github.johnrengelman.shadow") version "8.1.1" } architectury { @@ -18,7 +18,7 @@ architectury { } loom { - if (project.findProperty("enableAccessWidener") == "true") { // Optional property for `gradle.properties` to enable access wideners. + if (project.findProperty("enableAccessWidener") == "true") { // optional property for `gradle.properties` accessWidenerPath.set(project(":Common").loom.accessWidenerPath) forge { convertAccessWideners.set(true) @@ -32,9 +32,17 @@ loom { } } +repositories { + flatDir { + name = extraModsPrefix + dir(file("$extraModsPrefix-$minecraftVersion")) + } +} + val common by configurations val shadowCommon by configurations val commonTests: SourceSetOutput = project(":Common").sourceSets["test"].output + dependencies { // loader forge("net.minecraftforge:forge:$minecraftVersion-$forgeVersion") @@ -44,22 +52,35 @@ dependencies { shadowCommon(project(":Common", "transformProductionForge")) { isTransitive = false } // compile time mods - modCompileOnly("dev.latvian.mods:kubejs-forge:$kubejsVersion") // required for common kubejs plugin - modCompileOnly("me.shedaniel:RoughlyEnoughItems-forge:$reiVersion") // required for common rei plugin | api does not work here - compileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // required to disable rei compat layer on jei plugin - testCompileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // don't question this, it's required for compiling - modCompileOnly("mezz.jei:jei-$minecraftVersion-forge-api:$jeiVersion") { // required for common jei plugin and mixin + modCompileOnly("mezz.jei:jei-$minecraftVersion-forge-api:$jeiVersion") { // required for common jei plugin isTransitive = false // prevents breaking the forge runtime } + modCompileOnly("me.shedaniel:RoughlyEnoughItems-forge:$reiVersion") // required for common rei plugin // runtime mods - modLocalRuntime("dev.latvian.mods:kubejs-forge:$kubejsVersion") when (forgeRecipeViewer) { - "rei" -> modLocalRuntime("me.shedaniel:RoughlyEnoughItems-forge:$reiVersion") "jei" -> modLocalRuntime("mezz.jei:jei-$minecraftVersion-forge:$jeiVersion") { isTransitive = false } + "rei" -> modLocalRuntime("me.shedaniel:RoughlyEnoughItems-forge:$reiVersion") else -> throw GradleException("Invalid forgeRecipeViewer value: $forgeRecipeViewer") } + /** + * helps to load mods in development through an extra directory + * sadly, this does not support transitive dependencies + */ + fileTree("$extraModsPrefix-$minecraftVersion") { include("**/*.jar") } + .forEach { f -> + val sepIndex = f.nameWithoutExtension.lastIndexOf('-') + if (sepIndex == -1) { + throw IllegalArgumentException("Invalid mod name: '${f.nameWithoutExtension}'. Expected format: 'modName-version.jar'") + } + val mod = f.nameWithoutExtension.substring(0, sepIndex) + val version = f.nameWithoutExtension.substring(sepIndex + 1) + println("Extra mod ${f.nameWithoutExtension} detected.") + "modLocalRuntime"("extra-mods:$mod:$version") + } + + // tests testImplementation(project(":Common")) testImplementation(commonTests) diff --git a/Forge/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatformForge.java b/Forge/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatformForge.java index 37ff0f1..7964985 100644 --- a/Forge/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatformForge.java +++ b/Forge/src/main/java/com/almostreliable/unified/AlmostUnifiedPlatformForge.java @@ -1,10 +1,7 @@ package com.almostreliable.unified; import com.almostreliable.unified.api.ModConstants; -import com.almostreliable.unified.compat.AdAstraRecipeUnifier; -import com.almostreliable.unified.compat.ArsNouveauRecipeUnifier; -import com.almostreliable.unified.compat.ImmersiveEngineeringRecipeUnifier; -import com.almostreliable.unified.compat.MekanismRecipeUnifier; +import com.almostreliable.unified.compat.*; import com.almostreliable.unified.recipe.unifier.RecipeHandlerFactory; import com.almostreliable.unified.utils.UnifyTag; import com.google.auto.service.AutoService; @@ -38,11 +35,6 @@ public class AlmostUnifiedPlatformForge implements AlmostUnifiedPlatform { return ModList.get().isLoaded(modId); } - @Override - public boolean isDevelopmentEnvironment() { - return !FMLLoader.isProduction(); - } - @Override public boolean isClient() { return FMLLoader.getDist() == Dist.CLIENT; @@ -67,6 +59,7 @@ public class AlmostUnifiedPlatformForge implements AlmostUnifiedPlatform { ModConstants.ARS_NOUVEAU, ModConstants.ARS_SCALAES ).forEach(modId -> factory.registerForMod(modId, new ArsNouveauRecipeUnifier())); + factory.registerForMod(ModConstants.CYCLIC, new CyclicRecipeUnifier()); factory.registerForMod(ModConstants.IMMERSIVE_ENGINEERING, new ImmersiveEngineeringRecipeUnifier()); factory.registerForMod(ModConstants.MEKANISM, new MekanismRecipeUnifier()); } diff --git a/Forge/src/main/java/com/almostreliable/unified/compat/CyclicRecipeUnifier.java b/Forge/src/main/java/com/almostreliable/unified/compat/CyclicRecipeUnifier.java new file mode 100644 index 0000000..2086481 --- /dev/null +++ b/Forge/src/main/java/com/almostreliable/unified/compat/CyclicRecipeUnifier.java @@ -0,0 +1,13 @@ +package com.almostreliable.unified.compat; + +import com.almostreliable.unified.api.recipe.RecipeConstants; +import com.almostreliable.unified.api.recipe.RecipeUnifier; +import com.almostreliable.unified.api.recipe.RecipeUnifierBuilder; + +public class CyclicRecipeUnifier implements RecipeUnifier { + + @Override + public void collectUnifier(RecipeUnifierBuilder builder) { + builder.put(RecipeConstants.BONUS, (json, ctx) -> ctx.createResultReplacement(json)); + } +} diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml index 91e0881..b2709af 100644 --- a/Forge/src/main/resources/META-INF/mods.toml +++ b/Forge/src/main/resources/META-INF/mods.toml @@ -39,13 +39,6 @@ versionRange = "[${reiVersion},)" ordering = "BEFORE" side = "BOTH" -[[dependencies."${modId}"]] -modId = "rei_plugin_compatibilities" -mandatory = false -versionRange = "[9.0.43,)" -ordering = "BEFORE" -side = "BOTH" - [[dependencies."${modId}"]] modId = "kubejs" mandatory = false diff --git a/build.gradle.kts b/build.gradle.kts index 94aa298..e199534 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,63 +5,49 @@ import net.fabricmc.loom.api.LoomGradleExtensionAPI import net.fabricmc.loom.task.RemapJarTask val license: String by project -val fabricLoaderVersion: String by project -val fabricApiVersion: String by project -val forgeVersion: String by project val minecraftVersion: String by project -val modPackage: String by project val modVersion: String by project val modId: String by project val modName: String by project val modDescription: String by project val modAuthor: String by project -val githubRepo: String by project -val githubUser: String by project -val sharedRunDir: String by project val autoServiceVersion: String by project val parchmentVersion: String by project +val fabricApiVersion: String by project +val forgeVersion: String by project val jeiVersion: String by project val reiVersion: String by project -val kubejsVersion: String by project +val githubRepo: String by project +val githubUser: String by project plugins { + id("architectury-plugin") version "3.4.+" + id("dev.architectury.loom") version "1.3.+" apply false + id("io.github.juuxel.loom-vineflower") version "1.11.0" apply false + id("com.github.johnrengelman.shadow") version "8.1.1" apply false java `maven-publish` - id("architectury-plugin") version ("3.4.+") - id("io.github.juuxel.loom-quiltflower") version "1.10.0" apply false - id("dev.architectury.loom") version ("1.2.+") apply false - id("com.github.johnrengelman.shadow") version "8.1.1" apply false } architectury { minecraft = minecraftVersion } -val extraModsPrefix = "extra-mods" - +/** + * configurations for all projects including the root project + */ allprojects { apply(plugin = "java") - apply(plugin = "architectury-plugin") - apply(plugin = "maven-publish") - - repositories { - mavenLocal() - mavenCentral() - maven("https://maven.parchmentmc.org") // Parchment - maven("https://maven.shedaniel.me") // REI - maven("https://maven.blamejared.com/") // JEI - maven("https://maven.saps.dev/minecraft") // KubeJS - flatDir { - name = extraModsPrefix - dir(file("$extraModsPrefix-$minecraftVersion")) - } - } tasks { withType { options.encoding = "UTF-8" options.release.set(17) } + + withType { + enabled = false + } } extensions.configure { @@ -70,24 +56,35 @@ allprojects { } } +/** + * configurations for all projects except the root project + */ subprojects { - apply(plugin = "java") + apply(plugin = "architectury-plugin") apply(plugin = "dev.architectury.loom") + apply(plugin = "io.github.juuxel.loom-vineflower") apply(plugin = "maven-publish") - apply(plugin = "io.github.juuxel.loom-quiltflower") - base.archivesName.set("$modId-${project.name.lowercase()}") - version = "$minecraftVersion-$modVersion" + base { + archivesName.set("$modId-${project.name.lowercase()}") + version = "$minecraftVersion-$modVersion" + } + + repositories { + maven("https://maven.parchmentmc.org") // Parchment + maven("https://maven.shedaniel.me") // REI + maven("https://maven.blamejared.com/") // JEI + mavenLocal() + } val loom = project.extensions.getByName("loom") loom.silentMojangMappingsLicense() - /** - * General dependencies used for all subprojects, e.g. mappings or the Minecraft version. - */ dependencies { /** - * Kotlin accessor methods are not generated in this gradle, they can be accessed through quoted names. + * Minecraft + * Kotlin accessor methods are not generated in this gradle + * they can be accessed through quoted names instead */ "minecraft"("com.mojang:minecraft:$minecraftVersion") "mappings"(loom.layered { @@ -96,61 +93,16 @@ subprojects { }) /** - * Helps to load mods in development through an extra directory. Sadly this does not support transitive dependencies. :-( - */ - fileTree("$extraModsPrefix-$minecraftVersion") { include("**/*.jar") } - .forEach { f -> - val sepIndex = f.nameWithoutExtension.lastIndexOf('-') - if (sepIndex == -1) { - throw IllegalArgumentException("Invalid mod name: '${f.nameWithoutExtension}'. Expected format: 'modName-version.jar'") - } - val mod = f.nameWithoutExtension.substring(0, sepIndex) - val version = f.nameWithoutExtension.substring(sepIndex + 1) - println("Extra mod ${f.nameWithoutExtension} detected.") - "modLocalRuntime"("extra-mods:$mod:$version") - } - - /** - * Non-Minecraft dependencies + * non-Minecraft dependencies */ compileOnly("com.google.auto.service:auto-service:$autoServiceVersion") annotationProcessor("com.google.auto.service:auto-service:$autoServiceVersion") } - /** - * Maven publishing - */ - publishing { - publications { - val mpm = project.properties["maven-publish-method"] as String - println("[Publish Task] Publishing method for project '${project.name}: $mpm") - register(mpm, MavenPublication::class) { - artifactId = base.archivesName.get() - from(components["java"]) - } - } - - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - maven("file://${System.getenv("local_maven")}") - } - } - - /** - * Disabling the runtime transformer from Architectury here. - * When the runtime transformer should be enabled again, remove this block and add the following to the respective subproject: - * - * configurations { - * "developmentFabric" { extendsFrom(configurations["common"]) } // or "developmentForge" for Forge - * } - */ - architectury { - compileOnly() - } - tasks { /** - * Resource processing for defined targets. This will replace `${key}` with the specified values from the map below. + * resource processing for defined targets + * will replace `${key}` with the specified values from the map below */ processResources { val resourceTargets = listOf("META-INF/mods.toml", "pack.mcmeta", "fabric.mod.json") @@ -165,15 +117,16 @@ subprojects { "modDescription" to modDescription, "fabricApiVersion" to fabricApiVersion, "forgeVersion" to forgeVersion, - "forgeFMLVersion" to forgeVersion.substringBefore("."), // Only use major version as FML error message sucks. The error message for wrong Forge version is way better. + // use major version for FML only because wrong Forge version error message + // is way better than FML error message + "forgeFMLVersion" to forgeVersion.substringBefore("."), "jeiVersion" to jeiVersion, "reiVersion" to reiVersion, - "kubejsVersion" to kubejsVersion, "githubUser" to githubUser, "githubRepo" to githubRepo ) - println("[Process Resources] Replacing properties in resources: ") + println("[Process Resources] Replacing resource properties for project '${project.name}': ") replaceProperties.forEach { (key, value) -> println("\t -> $key = $value") } inputs.properties(replaceProperties) @@ -182,10 +135,46 @@ subprojects { } } } + + /** + * Maven publishing + */ + publishing { + publications { + val mpm = project.properties["maven-publish-method"] as String + println("[Publish Task] Publishing method for project '${project.name}': $mpm") + register(mpm, MavenPublication::class) { + artifactId = base.archivesName.get() + from(components["java"]) + } + } + + /** + * information on how to set up publishing + * https://docs.gradle.org/current/userguide/publishing_maven.html + */ + repositories { + maven("file://${System.getenv("local_maven")}") + } + } + + /** + * disabling the runtime transformer from Architectury + * if the runtime transformer should be enabled again, remove this block and + * add the following to the respective subproject: + * + * configurations { + * "developmentFabric" { extendsFrom(configurations["common"]) } + * "developmentForge" { extendsFrom(configurations["common"]) } + * } + */ + architectury { + compileOnly() + } } /** - * Subproject configurations and tasks only applied to subprojects that are not the common project, e.g. Fabric or Forge. + * configurations for all subprojects except the common project */ subprojects { if (project.path == ":Common") { @@ -197,15 +186,19 @@ subprojects { extensions.configure { runs { forEach { - it.runDir(if (sharedRunDir.toBoolean()) "../run" else "run") - // Allows DCEVM hot-swapping when using the JetBrains Runtime (https://github.com/JetBrains/JetBrainsRuntime). + val dir = "../run/${project.name.lowercase()}_${it.environment}" + println("[${project.name}] Run config '${it.name}' directory set to: $dir") + it.runDir(dir) + // allows DCEVM hot-swapping when using the JBR (https://github.com/JetBrains/JetBrainsRuntime) it.vmArgs("-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AllowEnhancedClassRedefinition") } } /** - * "main" matches the default mod's name. Since `compileOnly()` is being used in Architectury, - * the local mods for the loaders need to be set up too. Otherwise, they won't recognize :Common. + * "main" matches the default mod name + * since `compileOnly()` is being used in Architectury, the local mods for the + * loaders need to be set up too + * otherwise, they won't recognize :Common. */ with(mods.maybeCreate("main")) { fun Project.sourceSets() = extensions.getByName("sourceSets") @@ -215,7 +208,7 @@ subprojects { } val common by configurations.creating - val shadowCommon by configurations.creating // Don't use shadow from the shadow plugin because IDEA isn't supposed to index this. + val shadowCommon by configurations.creating // don't use shadow from the plugin, IDEA shouldn't index this configurations { "compileClasspath" { extendsFrom(common) } "runtimeClasspath" { extendsFrom(common) } @@ -236,6 +229,7 @@ subprojects { inputFile.set(named("shadowJar").get().archiveFile) dependsOn("shadowJar") archiveClassifier.set(null as String?) + injectAccessWidener.set(true) } named("jar") { diff --git a/gradle.properties b/gradle.properties index 86d886c..12922ad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,9 +3,6 @@ group = com.almostreliable.mods license = GNU Lesser General Public License v3.0 enabledPlatforms = fabric,forge enableAccessWidener = false -sharedRunDir = false -extraModsDirectory = extra-mods -junitVersion = 5.9.0 # Minecraft minecraftVersion = 1.19.2 @@ -20,12 +17,12 @@ modDescription = Unify all resources. # Project Dependencies autoServiceVersion = 1.1.0 +junitVersion = 5.9.0 parchmentVersion = 2022.11.27 # Mod Dependencies -reiVersion = 9.1.580 jeiVersion = 11.6.0.1012 -kubejsVersion = 1902.6.0-build.132 +reiVersion = 9.1.580 # Fabric Dependencies fabricLoaderVersion = 0.14.19 diff --git a/settings.gradle.kts b/settings.gradle.kts index b917fc6..41d94b8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,7 +1,7 @@ pluginManagement { repositories { - maven("https://maven.fabricmc.net/") maven("https://maven.architectury.dev/") + maven("https://maven.fabricmc.net/") maven("https://maven.minecraftforge.net/") gradlePluginPortal() }