From f68048d955f0fe5119ce8b2605b084086e3547d9 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Fri, 6 Sep 2024 21:44:34 +0200 Subject: [PATCH] Architectury port, EMI compat --- .gitignore | 47 ++--- build.gradle | 170 ++++++------------ common/build.gradle | 25 +++ .../main/java/eu/midnightdust/blur/Blur.java | 37 ++-- .../java/eu/midnightdust/blur/BlurInfo.java | 28 +++ .../midnightdust/blur/config/BlurConfig.java | 11 +- .../blur/mixin/BlurMixinPlugin.java | 57 ++++++ .../blur/mixin/MixinGameRenderer.java | 7 +- .../blur/mixin/MixinHandledScreen.java | 0 .../blur/mixin/MixinInGameHud.java | 9 +- .../blur/mixin/MixinMinecraftClient.java | 12 +- .../midnightdust/blur/mixin/MixinScreen.java | 34 ++-- .../blur/mixin/ScreenAccessor.java | 11 ++ .../blur/mixin/emi/MixinRecipeScreen.java | 25 +++ .../midnightdust/blur/util/RainbowColor.java | 3 +- .../src}/main/resources/assets/blur/icon.png | Bin .../resources/assets/blur/lang/de_de.json | 0 .../resources/assets/blur/lang/en_gb.json | 0 .../resources/assets/blur/lang/en_us.json | 5 +- .../resources/assets/blur/lang/es_mx.json | 0 .../resources/assets/blur/lang/fr_fr.json | 0 .../resources/assets/blur/lang/ko_kr.json | 0 .../resources/assets/blur/lang/pt_br.json | 0 .../resources/assets/blur/lang/ru_ru.json | 0 .../resources/assets/blur/lang/sv_se.json | 0 .../resources/assets/blur/lang/uk_ua.json | 0 .../resources/assets/blur/lang/zh_cn.json | 0 .../resources/assets/blur/lang/zh_tw.json | 0 .../src/main/resources/blur.mixins.json | 3 +- .../main/resources/blur_compat.mixins.json | 12 ++ fabric/build.gradle | 100 +++++++++++ .../midnightdust/blur/fabric/BlurFabric.java | 14 ++ .../src}/main/resources/fabric.mod.json | 5 +- gradle.properties | 43 +++-- gradle/wrapper/gradle-wrapper.properties | 2 +- .../midnightlib-fabric-1.5.3-24w09a.jar | Bin 55552 -> 0 bytes neoforge/build.gradle | 113 ++++++++++++ neoforge/gradle.properties | 1 + .../blur/neoforge/BlurNeoForge.java | 24 +++ .../resources/META-INF/neoforge.mods.toml | 33 ++++ settings.gradle | 14 +- 41 files changed, 611 insertions(+), 234 deletions(-) create mode 100644 common/build.gradle rename {src => common/src}/main/java/eu/midnightdust/blur/Blur.java (67%) create mode 100644 common/src/main/java/eu/midnightdust/blur/BlurInfo.java rename {src => common/src}/main/java/eu/midnightdust/blur/config/BlurConfig.java (84%) create mode 100644 common/src/main/java/eu/midnightdust/blur/mixin/BlurMixinPlugin.java rename {src => common/src}/main/java/eu/midnightdust/blur/mixin/MixinGameRenderer.java (66%) rename {src => common/src}/main/java/eu/midnightdust/blur/mixin/MixinHandledScreen.java (100%) rename {src => common/src}/main/java/eu/midnightdust/blur/mixin/MixinInGameHud.java (76%) rename {src => common/src}/main/java/eu/midnightdust/blur/mixin/MixinMinecraftClient.java (65%) rename {src => common/src}/main/java/eu/midnightdust/blur/mixin/MixinScreen.java (62%) create mode 100644 common/src/main/java/eu/midnightdust/blur/mixin/ScreenAccessor.java create mode 100644 common/src/main/java/eu/midnightdust/blur/mixin/emi/MixinRecipeScreen.java rename {src => common/src}/main/java/eu/midnightdust/blur/util/RainbowColor.java (81%) rename {src => common/src}/main/resources/assets/blur/icon.png (100%) rename {src => common/src}/main/resources/assets/blur/lang/de_de.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/en_gb.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/en_us.json (82%) rename {src => common/src}/main/resources/assets/blur/lang/es_mx.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/fr_fr.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/ko_kr.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/pt_br.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/ru_ru.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/sv_se.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/uk_ua.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/zh_cn.json (100%) rename {src => common/src}/main/resources/assets/blur/lang/zh_tw.json (100%) rename src/main/resources/mixins.blur.json => common/src/main/resources/blur.mixins.json (82%) create mode 100644 common/src/main/resources/blur_compat.mixins.json create mode 100644 fabric/build.gradle create mode 100644 fabric/src/main/java/eu/midnightdust/blur/fabric/BlurFabric.java rename {src => fabric/src}/main/resources/fabric.mod.json (86%) delete mode 100644 localMaven/midnightlib-fabric-1.5.3-24w09a.jar create mode 100644 neoforge/build.gradle create mode 100644 neoforge/gradle.properties create mode 100644 neoforge/src/main/java/eu/midnightdust/blur/neoforge/BlurNeoForge.java create mode 100644 neoforge/src/main/resources/META-INF/neoforge.mods.toml diff --git a/.gitignore b/.gitignore index 52c7cf2..7f9474b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,20 @@ -/download -/eclipseBin +build/ +*.ipr +run/ +*.iws +out/ +*.iml +.gradle/ +output/ +bin/ +libs/ -## gradle -/.gradle -/build - -## ForgeGradle -/run -/*.launch - -## eclipse -/eclipse -/.settings -/.metadata -/.classpath -/.project -/bin - -## intellij -/out -/.idea -/*.iml -/*.ipr -/*.iws -/atlassian-ide-plugin.xml - -## gedit -*~ +.classpath +.project +.idea/ +classes/ +.metadata +.vscode +.settings +*.launch +.architectury-transformer/debug.log diff --git a/build.gradle b/build.gradle index 2948a60..a3292bb 100755 --- a/build.gradle +++ b/build.gradle @@ -1,131 +1,73 @@ +import groovy.json.JsonSlurper +import groovy.json.JsonOutput + plugins { - id 'fabric-loom' version '1.6-SNAPSHOT' - id 'maven-publish' - id "me.shedaniel.unified-publishing" version "0.1.+" + id "architectury-plugin" version "3.4-SNAPSHOT" + id "dev.architectury.loom" version "1.7-SNAPSHOT" apply false + id "me.shedaniel.unified-publishing" version "0.1.+" apply false + id 'com.github.johnrengelman.shadow' version '8.1.1' apply false } -sourceCompatibility = JavaVersion.VERSION_21 -targetCompatibility = JavaVersion.VERSION_21 +architectury { + minecraft = rootProject.minecraft_version +} -archivesBaseName = project.archives_base_name -version = project.mod_version -group = project.maven_group - -repositories { - maven { - name = 'Ladysnake Mods' - url = 'https://maven.ladysnake.org/releases' - content { - includeGroup 'org.ladysnake' - includeGroupByRegex 'dev\\.onyxstudios.*' +subprojects { + apply plugin: "dev.architectury.loom" + repositories { + maven { + url = "https://api.modrinth.com/maven" } } - maven { - url = 'https://maven.terraformersmc.com/releases' - content { - includeGroup 'com.terraformersmc' - } - } - maven { - url = "https://api.modrinth.com/maven" - } - flatDir { - dirs("localMaven") - } -} -dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - //modImplementation "org.ladysnake:satin:${satin_version}" - //include "org.ladysnake:satin:${satin_version}" - - implementation 'com.google.code.findbugs:jsr305:3.0.2' - modImplementation "maven.modrinth:midnightlib:${project.midnightlib_version}" - include "maven.modrinth:midnightlib:${project.midnightlib_version}" -} - -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -tasks.withType(JavaCompile).configureEach { - // Minecraft 1.20.5 upwards uses Java 21. - it.options.release = 21 -} - -java { - withSourcesJar() -} - -jar { - from "LICENSE" -} - -// configure the maven publication -publishing { - publications { - mavenJava(MavenPublication) { - from components.java + dependencies { + minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" + // The following line declares the yarn mappings you may select this one as well. + mappings loom.layered { + it.mappings("net.fabricmc:yarn:$rootProject.yarn_mappings:v2") + it.mappings("dev.architectury:yarn-mappings-patch-neoforge:$rootProject.yarn_mappings_patch_neoforge_version") } } } -ext { - releaseChangelog = { - def changes = new StringBuilder() - changes << "## Blur+ v$project.version for $project.minecraft_version\n[View the changelog](https://www.github.com/Motschen/Blur/commits/)" - def proc = "git log --max-count=1 --pretty=format:%s".execute() - proc.in.eachLine { line -> - def processedLine = line.toString() - if (!processedLine.contains("New translations") && !processedLine.contains("Merge") && !processedLine.contains("branch")) { - changes << "\n- ${processedLine.capitalize()}" +allprojects { + apply plugin: "java" + apply plugin: "architectury-plugin" + apply plugin: "maven-publish" + + archivesBaseName = rootProject.archives_base_name + version = rootProject.mod_version + group = rootProject.maven_group + + tasks.withType(JavaCompile) { + options.encoding = "UTF-8" + options.release = 21 + } + ext { + releaseChangelog = { + def changes = new StringBuilder() + changes << "## Blur+ v$project.version for $project.minecraft_version\n[View the changelog](https://www.github.com/Motschen/Blur/commits/)" + def proc = "git log --max-count=1 --pretty=format:%s".execute() + proc.in.eachLine { line -> + def processedLine = line.toString() + if (!processedLine.contains("New translations") && !processedLine.contains("Merge") && !processedLine.contains("branch")) { + changes << "\n- ${processedLine.capitalize()}" + } } + proc.waitFor() + return changes.toString() } - proc.waitFor() - return changes.toString() } -} - -unifiedPublishing { - project { - displayName = "Blur+ $project.version - Fabric $project.minecraft_version" - releaseType = "$project.release_type" - changelog = releaseChangelog() - gameVersions = [] - gameLoaders = ["fabric","quilt"] - mainPublication remapJar - relations { - includes { - curseforge = "midnightlib" - modrinth = "midnightlib" - } - } - - var CURSEFORGE_TOKEN = project.findProperty("CURSEFORGE_TOKEN") ?: System.getenv("CURSEFORGE_TOKEN") - if (CURSEFORGE_TOKEN != null) { - curseforge { - token = CURSEFORGE_TOKEN - id = rootProject.curseforge_id - gameVersions.addAll "Java 21", project.minecraft_version - } - } - - var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN") - if (MODRINTH_TOKEN != null) { - modrinth { - token = MODRINTH_TOKEN - id = rootProject.modrinth_id - version = "$project.version" - gameVersions.addAll project.minecraft_version + processResources { + // Minify json resources + doLast { + fileTree(dir: outputs.files.asPath, include: "**/*.json").each { + File file -> file.text = JsonOutput.toJson(new JsonSlurper().parse(file)) } } } -} \ No newline at end of file + + java { + withSourcesJar() + } +} diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 0000000..88ed66f --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,25 @@ +architectury { + common(rootProject.enabled_platforms.split(",")) +} + +dependencies { + // We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies + // Do NOT use other classes from fabric loader + modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" + modCompileOnly "maven.modrinth:midnightlib:${rootProject.midnightlib_version}-fabric" + modCompileOnly "maven.modrinth:emi:${rootProject.emi_version}+fabric" +} + +publishing { + publications { + mavenCommon(MavenPublication) { + artifactId = rootProject.archives_base_name + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + } +} diff --git a/src/main/java/eu/midnightdust/blur/Blur.java b/common/src/main/java/eu/midnightdust/blur/Blur.java similarity index 67% rename from src/main/java/eu/midnightdust/blur/Blur.java rename to common/src/main/java/eu/midnightdust/blur/Blur.java index c4936e3..c154b1a 100644 --- a/src/main/java/eu/midnightdust/blur/Blur.java +++ b/common/src/main/java/eu/midnightdust/blur/Blur.java @@ -3,36 +3,20 @@ package eu.midnightdust.blur; import eu.midnightdust.blur.config.BlurConfig; import eu.midnightdust.blur.util.RainbowColor; import eu.midnightdust.lib.util.MidnightColorUtil; -import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.minecraft.client.gui.DrawContext; import org.joml.Math; +import org.joml.Matrix4f; -import java.awt.*; +import java.awt.Color; import java.lang.Double; +import static eu.midnightdust.blur.BlurInfo.*; import static eu.midnightdust.blur.util.RainbowColor.hue; import static eu.midnightdust.blur.util.RainbowColor.hue2; -public class Blur implements ClientModInitializer { - - public static long start; - public static float progress; - - public static boolean prevScreenHasBlur; - public static boolean screenHasBlur; - - public static boolean prevScreenHasBackground; - public static boolean screenHasBackground; - - public static boolean doTest = true; - public static boolean screenChanged = true; - public static long lastScreenChange = System.currentTimeMillis(); - - @Override - public void onInitializeClient() { +public class Blur { + public static void init() { BlurConfig.init("blur", BlurConfig.class); - ClientTickEvents.END_CLIENT_TICK.register(RainbowColor::tick); } public static boolean doFade = false; @@ -66,7 +50,7 @@ public class Blur implements ClientModInitializer { x = BlurConfig.animationCurve.apply(x, fadeIn); x = Math.clamp(0, 1, x); - Blur.progress = Double.valueOf(x).floatValue(); + progress = Double.valueOf(x).floatValue(); } public static int getBackgroundColor(boolean second) { @@ -91,10 +75,11 @@ public class Blur implements ClientModInitializer { float diagonal = Math.sqrt((float) width*width + height*height); int smallestDimension = Math.min(width, height); - context.getMatrices().peek().getPositionMatrix().rotationZ(Math.toRadians(getRotation())); - context.getMatrices().peek().getPositionMatrix().setTranslation(width / 2f, height / 2f, 0); // Make the gradient's center the pivot point - context.getMatrices().peek().getPositionMatrix().scale(diagonal / smallestDimension); // Scales the gradient to the maximum diagonal value needed + Matrix4f posMatrix = context.getMatrices().peek().getPositionMatrix(); + posMatrix.rotationZ(Math.toRadians(getRotation())); + posMatrix.setTranslation(width / 2f, height / 2f, 0); // Make the gradient's center the pivot point + posMatrix.scale(diagonal / smallestDimension); // Scales the gradient to the maximum diagonal value needed context.fillGradient(-width / 2, -height / 2, width / 2, height / 2, Blur.getBackgroundColor(false), Blur.getBackgroundColor(true)); // Actually draw the gradient - context.getMatrices().peek().getPositionMatrix().rotationZ(0); + posMatrix.rotationZ(0); } } diff --git a/common/src/main/java/eu/midnightdust/blur/BlurInfo.java b/common/src/main/java/eu/midnightdust/blur/BlurInfo.java new file mode 100644 index 0000000..2050542 --- /dev/null +++ b/common/src/main/java/eu/midnightdust/blur/BlurInfo.java @@ -0,0 +1,28 @@ +package eu.midnightdust.blur; + +public class BlurInfo { + public static long start; + public static float progress; + + public static boolean prevScreenHasBlur; + public static boolean screenHasBlur; + + public static boolean prevScreenHasBackground; + public static boolean screenHasBackground; + + public static boolean doTest = true; + public static boolean screenChanged = true; + public static long lastScreenChange = System.currentTimeMillis(); + + public static void reset() { + // Here, we reset all tests, to check if the new screen has blur and/or a background + prevScreenHasBlur = screenHasBlur; + prevScreenHasBackground = screenHasBackground; + screenHasBlur = false; + screenHasBackground = false; + doTest = true; + screenChanged = true; + start = -1; + lastScreenChange = System.currentTimeMillis(); + } +} diff --git a/src/main/java/eu/midnightdust/blur/config/BlurConfig.java b/common/src/main/java/eu/midnightdust/blur/config/BlurConfig.java similarity index 84% rename from src/main/java/eu/midnightdust/blur/config/BlurConfig.java rename to common/src/main/java/eu/midnightdust/blur/config/BlurConfig.java index 193c4e4..d374f67 100644 --- a/src/main/java/eu/midnightdust/blur/config/BlurConfig.java +++ b/common/src/main/java/eu/midnightdust/blur/config/BlurConfig.java @@ -11,9 +11,10 @@ import static java.lang.Math.*; public class BlurConfig extends MidnightConfig { public static final String ANIMATIONS = "animations"; public static final String STYLE = "style"; + public static final String SCREENS = "screens"; @Entry @Hidden public static int configVersion = 2; - @Entry(category = STYLE) + @Entry(category = SCREENS) public static boolean blurContainers = true; @Entry(category = ANIMATIONS, min = 0, max = 2000, isSlider = true) public static int fadeTimeMillis = 300; @@ -35,12 +36,16 @@ public class BlurConfig extends MidnightConfig { public static int gradientRotation = 0; @Entry(category = STYLE) public static boolean rainbowMode = false; - @Entry(category = STYLE) + @Entry(category = SCREENS) // Screens where Blur+ should not apply transition effects (mostly dynamically blurred screens) public static List excludedScreens = Lists.newArrayList("net.irisshaders.iris.gui.screen.ShaderPackScreen"); + @Entry(category = SCREENS) // Screens where the vanilla blur effect should be force enabled + public static List forceEnabledScreens = Lists.newArrayList(); + @Entry(category = SCREENS) // Screens where the vanilla blur effect should be force disabled + public static List forceDisabledScreens = Lists.newArrayList(); public enum Easing { // Based on https://gist.github.com/dev-hydrogen/21a66f83f0386123e0c0acf107254843 - // Thanks you very much! + // Thank you very much! FLAT(x -> x, x -> x), SINE(x -> 1 - cos(x * PI) / 2, x -> sin(x * PI) / 2), diff --git a/common/src/main/java/eu/midnightdust/blur/mixin/BlurMixinPlugin.java b/common/src/main/java/eu/midnightdust/blur/mixin/BlurMixinPlugin.java new file mode 100644 index 0000000..73aa8ee --- /dev/null +++ b/common/src/main/java/eu/midnightdust/blur/mixin/BlurMixinPlugin.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2021 LambdAurora + * + * This file is part of midnightcontrols. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package eu.midnightdust.blur.mixin; + +import eu.midnightdust.lib.util.PlatformFunctions; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class BlurMixinPlugin implements IMixinConfigPlugin { + private String mixinPackage; + + @Override + public void onLoad(String mixinPackage) { + this.mixinPackage = mixinPackage + "."; + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + final String mixinName = mixinClassName.substring(this.mixinPackage.length()); + final String packageName = mixinName.substring(0, mixinName.lastIndexOf('.')); + + if (packageName.startsWith("emi") && !PlatformFunctions.isModLoaded("emi")) + return false; + + return true; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) {} + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} +} diff --git a/src/main/java/eu/midnightdust/blur/mixin/MixinGameRenderer.java b/common/src/main/java/eu/midnightdust/blur/mixin/MixinGameRenderer.java similarity index 66% rename from src/main/java/eu/midnightdust/blur/mixin/MixinGameRenderer.java rename to common/src/main/java/eu/midnightdust/blur/mixin/MixinGameRenderer.java index da8131d..8ec9aad 100644 --- a/src/main/java/eu/midnightdust/blur/mixin/MixinGameRenderer.java +++ b/common/src/main/java/eu/midnightdust/blur/mixin/MixinGameRenderer.java @@ -1,6 +1,7 @@ package eu.midnightdust.blur.mixin; import eu.midnightdust.blur.Blur; +import eu.midnightdust.blur.BlurInfo; import net.minecraft.client.render.GameRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -10,8 +11,8 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable; public class MixinGameRenderer { @ModifyVariable(method = "renderBlur", at = @At("STORE"), ordinal = 1) private float blur$modifyRadius(float radius) { // Modify the radius based on the animation progress - if (!Blur.screenChanged && Blur.start >= 0) // Only update the progress after all tests have been completed - Blur.updateProgress(Blur.screenHasBlur); - return radius * Blur.progress; + if (!BlurInfo.screenChanged && BlurInfo.start >= 0) // Only update the progress after all tests have been completed + Blur.updateProgress(BlurInfo.screenHasBlur); + return radius * BlurInfo.progress; } } diff --git a/src/main/java/eu/midnightdust/blur/mixin/MixinHandledScreen.java b/common/src/main/java/eu/midnightdust/blur/mixin/MixinHandledScreen.java similarity index 100% rename from src/main/java/eu/midnightdust/blur/mixin/MixinHandledScreen.java rename to common/src/main/java/eu/midnightdust/blur/mixin/MixinHandledScreen.java diff --git a/src/main/java/eu/midnightdust/blur/mixin/MixinInGameHud.java b/common/src/main/java/eu/midnightdust/blur/mixin/MixinInGameHud.java similarity index 76% rename from src/main/java/eu/midnightdust/blur/mixin/MixinInGameHud.java rename to common/src/main/java/eu/midnightdust/blur/mixin/MixinInGameHud.java index 3924da2..966498c 100644 --- a/src/main/java/eu/midnightdust/blur/mixin/MixinInGameHud.java +++ b/common/src/main/java/eu/midnightdust/blur/mixin/MixinInGameHud.java @@ -1,6 +1,7 @@ package eu.midnightdust.blur.mixin; import eu.midnightdust.blur.Blur; +import eu.midnightdust.blur.BlurInfo; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; @@ -18,13 +19,13 @@ public class MixinInGameHud { @Inject(at = @At("TAIL"), method = "render") public void blur$renderFadeOut(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { // Adds a fade-out effect when a player is in a world and closes all screens - if (client.currentScreen == null && client.world != null && Blur.start >= 0 && Blur.prevScreenHasBlur) { - Blur.doTest = false; - Blur.screenChanged = false; + if (client.currentScreen == null && client.world != null && BlurInfo.start >= 0 && BlurInfo.prevScreenHasBlur) { + BlurInfo.doTest = false; + BlurInfo.screenChanged = false; this.client.gameRenderer.renderBlur(tickCounter.getTickDelta(true)); this.client.getFramebuffer().beginWrite(false); - if (Blur.prevScreenHasBackground) Blur.renderRotatedGradient(context, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); + if (BlurInfo.prevScreenHasBackground) Blur.renderRotatedGradient(context, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); } } } diff --git a/src/main/java/eu/midnightdust/blur/mixin/MixinMinecraftClient.java b/common/src/main/java/eu/midnightdust/blur/mixin/MixinMinecraftClient.java similarity index 65% rename from src/main/java/eu/midnightdust/blur/mixin/MixinMinecraftClient.java rename to common/src/main/java/eu/midnightdust/blur/mixin/MixinMinecraftClient.java index 1cd09fc..d668eb7 100755 --- a/src/main/java/eu/midnightdust/blur/mixin/MixinMinecraftClient.java +++ b/common/src/main/java/eu/midnightdust/blur/mixin/MixinMinecraftClient.java @@ -1,6 +1,7 @@ package eu.midnightdust.blur.mixin; import eu.midnightdust.blur.Blur; +import eu.midnightdust.blur.BlurInfo; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -18,17 +19,10 @@ public class MixinMinecraftClient { target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", opcode = Opcodes.PUTFIELD)) private void blur$onScreenOpen(Screen newScreen, CallbackInfo info) { - if (Blur.lastScreenChange < System.currentTimeMillis() - 100) { // For some reason, in certain scenarios the screen is set to a new one multiple times in a tick. We want to avoid that. + if (BlurInfo.lastScreenChange < System.currentTimeMillis() - 100) { // For some reason, in certain scenarios the screen is set to a new one multiple times in a tick. We want to avoid that. // Here, we reset all tests, to check if the new screen has blur and/or a background - Blur.prevScreenHasBlur = Blur.screenHasBlur; - Blur.prevScreenHasBackground = Blur.screenHasBackground; - Blur.screenHasBlur = false; - Blur.screenHasBackground = false; - Blur.doTest = true; - Blur.screenChanged = true; - Blur.start = -1; - Blur.lastScreenChange = System.currentTimeMillis(); + BlurInfo.reset(); // Manually activate the onScreenChange method when all screens are closed (in-game) if (newScreen == null) Blur.onScreenChange(); diff --git a/src/main/java/eu/midnightdust/blur/mixin/MixinScreen.java b/common/src/main/java/eu/midnightdust/blur/mixin/MixinScreen.java similarity index 62% rename from src/main/java/eu/midnightdust/blur/mixin/MixinScreen.java rename to common/src/main/java/eu/midnightdust/blur/mixin/MixinScreen.java index 99fdf57..089b47d 100755 --- a/src/main/java/eu/midnightdust/blur/mixin/MixinScreen.java +++ b/common/src/main/java/eu/midnightdust/blur/mixin/MixinScreen.java @@ -1,5 +1,6 @@ package eu.midnightdust.blur.mixin; +import eu.midnightdust.blur.BlurInfo; import eu.midnightdust.blur.config.BlurConfig; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; @@ -17,40 +18,38 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Screen.class) public abstract class MixinScreen { - - @Shadow protected MinecraftClient client; - @Shadow @Final protected Text title; - + @Shadow protected MinecraftClient client; @Shadow public abstract void renderInGameBackground(DrawContext context); - @Shadow public int width; - @Shadow public int height; @Inject(at = @At("HEAD"), method = "render") public void blur$processScreenChange(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (!Blur.doTest && Blur.screenChanged) { // After the tests for blur and background color have been completed + if (!BlurInfo.doTest && BlurInfo.screenChanged) { // After the tests for blur and background color have been completed Blur.onScreenChange(); - Blur.screenChanged = false; + BlurInfo.screenChanged = false; } - if (Blur.start >= 0 && !Blur.screenHasBlur && Blur.prevScreenHasBlur) { // Fade out in non-blurred screens + if (BlurInfo.start >= 0 && !BlurInfo.screenHasBlur && BlurInfo.prevScreenHasBlur) { // Fade out in non-blurred screens this.client.gameRenderer.renderBlur(delta); this.client.getFramebuffer().beginWrite(false); - if (Blur.prevScreenHasBackground) Blur.renderRotatedGradient(context, width, height); + if (BlurInfo.prevScreenHasBackground) Blur.renderRotatedGradient(context, width, height); } - Blur.doTest = false; // Set the test state to completed, as tests will happen in the same tick. + BlurInfo.doTest = false; // Set the test state to completed, as tests will happen in the same tick. } @Inject(at = @At("HEAD"), method = "renderInGameBackground") public void blur$getBackgroundEnabled(DrawContext context, CallbackInfo ci) { - Blur.screenHasBackground = true; // Test if the screen has a background + BlurInfo.screenHasBackground = true; // Test if the screen has a background } - @Inject(at = @At("HEAD"), method = "applyBlur") + @Inject(at = @At("HEAD"), method = "applyBlur", cancellable = true) public void blur$getBlurEnabled(float delta, CallbackInfo ci) { + if (BlurConfig.forceDisabledScreens.contains(this.getClass().toString())) { + ci.cancel(); return; + } if (!BlurConfig.excludedScreens.contains(this.getClass().toString())) - Blur.screenHasBlur = true; // Test if the screen has blur + BlurInfo.screenHasBlur = true; // Test if the screen has blur } @Inject(at = @At("HEAD"), method = "renderDarkening(Lnet/minecraft/client/gui/DrawContext;IIII)V", cancellable = true) @@ -62,8 +61,11 @@ public abstract class MixinScreen { } @Inject(at = @At("HEAD"), method = "renderInGameBackground", cancellable = true) - public void blur$rotatedGradient(DrawContext context, CallbackInfo ci) { // Replaces the default gradient with our rotated one - Blur.renderRotatedGradient(context, width, height); + public void blur$rotatedGradient(DrawContext context, CallbackInfo ci) { + if (BlurConfig.forceEnabledScreens.contains(this.getClass().toString())) + (((ScreenAccessor)this)).forceApplyBlur(client.getRenderTickCounter().getTickDelta(true)); // Applies the blur effect in force-enabled screens + + Blur.renderRotatedGradient(context, width, height); // Replaces the default gradient with our rotated one ci.cancel(); } } diff --git a/common/src/main/java/eu/midnightdust/blur/mixin/ScreenAccessor.java b/common/src/main/java/eu/midnightdust/blur/mixin/ScreenAccessor.java new file mode 100644 index 0000000..68d123c --- /dev/null +++ b/common/src/main/java/eu/midnightdust/blur/mixin/ScreenAccessor.java @@ -0,0 +1,11 @@ +package eu.midnightdust.blur.mixin; + +import net.minecraft.client.gui.screen.Screen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Screen.class) +public interface ScreenAccessor { + @Invoker("applyBlur") + void forceApplyBlur(float delta); +} diff --git a/common/src/main/java/eu/midnightdust/blur/mixin/emi/MixinRecipeScreen.java b/common/src/main/java/eu/midnightdust/blur/mixin/emi/MixinRecipeScreen.java new file mode 100644 index 0000000..572baca --- /dev/null +++ b/common/src/main/java/eu/midnightdust/blur/mixin/emi/MixinRecipeScreen.java @@ -0,0 +1,25 @@ +package eu.midnightdust.blur.mixin.emi; + +import dev.emi.emi.screen.RecipeScreen; +import eu.midnightdust.blur.config.BlurConfig; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; +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.CallbackInfo; + +@Mixin(RecipeScreen.class) +public class MixinRecipeScreen extends Screen { + + protected MixinRecipeScreen(Text title) { + super(title); + } + + @Inject(at = @At("HEAD"), method = "render") + public void blur$addBlurEffect(DrawContext raw, int mouseX, int mouseY, float delta, CallbackInfo ci) { + if (BlurConfig.blurContainers) this.applyBlur(delta); + } + +} diff --git a/src/main/java/eu/midnightdust/blur/util/RainbowColor.java b/common/src/main/java/eu/midnightdust/blur/util/RainbowColor.java similarity index 81% rename from src/main/java/eu/midnightdust/blur/util/RainbowColor.java rename to common/src/main/java/eu/midnightdust/blur/util/RainbowColor.java index 57ced40..6222aec 100644 --- a/src/main/java/eu/midnightdust/blur/util/RainbowColor.java +++ b/common/src/main/java/eu/midnightdust/blur/util/RainbowColor.java @@ -1,14 +1,13 @@ package eu.midnightdust.blur.util; import eu.midnightdust.blur.config.BlurConfig; -import net.minecraft.client.MinecraftClient; public class RainbowColor { public static int rotation; public static float hue; public static float hue2 = 0.35f; - public static void tick(MinecraftClient ignoredClient) { + public static void tick() { if (BlurConfig.rainbowMode) { if (hue >= 1) hue = 0f; hue += 0.01f; diff --git a/src/main/resources/assets/blur/icon.png b/common/src/main/resources/assets/blur/icon.png similarity index 100% rename from src/main/resources/assets/blur/icon.png rename to common/src/main/resources/assets/blur/icon.png diff --git a/src/main/resources/assets/blur/lang/de_de.json b/common/src/main/resources/assets/blur/lang/de_de.json similarity index 100% rename from src/main/resources/assets/blur/lang/de_de.json rename to common/src/main/resources/assets/blur/lang/de_de.json diff --git a/src/main/resources/assets/blur/lang/en_gb.json b/common/src/main/resources/assets/blur/lang/en_gb.json similarity index 100% rename from src/main/resources/assets/blur/lang/en_gb.json rename to common/src/main/resources/assets/blur/lang/en_gb.json diff --git a/src/main/resources/assets/blur/lang/en_us.json b/common/src/main/resources/assets/blur/lang/en_us.json similarity index 82% rename from src/main/resources/assets/blur/lang/en_us.json rename to common/src/main/resources/assets/blur/lang/en_us.json index a307a4f..9772ba8 100755 --- a/src/main/resources/assets/blur/lang/en_us.json +++ b/common/src/main/resources/assets/blur/lang/en_us.json @@ -2,6 +2,7 @@ "blur.midnightconfig.title": "Blur+ Config", "blur.midnightconfig.category.animations": "Animations", "blur.midnightconfig.category.style": "Style", + "blur.midnightconfig.category.screens": "Screens", "blur.midnightconfig.blurContainers": "Apply Blur to Containers", "blur.midnightconfig.fadeTimeMillis": "Fade Time (in milliseconds)", "blur.midnightconfig.fadeOutTimeMillis": "Fade Out Time (in milliseconds)", @@ -24,5 +25,7 @@ "blur.midnightconfig.gradientStartAlpha": "Gradient Start Alpha", "blur.midnightconfig.gradientEndAlpha": "Gradient End Alpha", "blur.midnightconfig.gradientRotation": "Gradient Rotation", - "blur.midnightconfig.excludedScreens": "Excluded Screens" + "blur.midnightconfig.excludedScreens": "Excluded Screens", + "blur.midnightconfig.forceEnabledScreens": "Screens where blur should be force-enabled", + "blur.midnightconfig.forceDisabledScreens": "Screens where blur should be force-disabled" } \ No newline at end of file diff --git a/src/main/resources/assets/blur/lang/es_mx.json b/common/src/main/resources/assets/blur/lang/es_mx.json similarity index 100% rename from src/main/resources/assets/blur/lang/es_mx.json rename to common/src/main/resources/assets/blur/lang/es_mx.json diff --git a/src/main/resources/assets/blur/lang/fr_fr.json b/common/src/main/resources/assets/blur/lang/fr_fr.json similarity index 100% rename from src/main/resources/assets/blur/lang/fr_fr.json rename to common/src/main/resources/assets/blur/lang/fr_fr.json diff --git a/src/main/resources/assets/blur/lang/ko_kr.json b/common/src/main/resources/assets/blur/lang/ko_kr.json similarity index 100% rename from src/main/resources/assets/blur/lang/ko_kr.json rename to common/src/main/resources/assets/blur/lang/ko_kr.json diff --git a/src/main/resources/assets/blur/lang/pt_br.json b/common/src/main/resources/assets/blur/lang/pt_br.json similarity index 100% rename from src/main/resources/assets/blur/lang/pt_br.json rename to common/src/main/resources/assets/blur/lang/pt_br.json diff --git a/src/main/resources/assets/blur/lang/ru_ru.json b/common/src/main/resources/assets/blur/lang/ru_ru.json similarity index 100% rename from src/main/resources/assets/blur/lang/ru_ru.json rename to common/src/main/resources/assets/blur/lang/ru_ru.json diff --git a/src/main/resources/assets/blur/lang/sv_se.json b/common/src/main/resources/assets/blur/lang/sv_se.json similarity index 100% rename from src/main/resources/assets/blur/lang/sv_se.json rename to common/src/main/resources/assets/blur/lang/sv_se.json diff --git a/src/main/resources/assets/blur/lang/uk_ua.json b/common/src/main/resources/assets/blur/lang/uk_ua.json similarity index 100% rename from src/main/resources/assets/blur/lang/uk_ua.json rename to common/src/main/resources/assets/blur/lang/uk_ua.json diff --git a/src/main/resources/assets/blur/lang/zh_cn.json b/common/src/main/resources/assets/blur/lang/zh_cn.json similarity index 100% rename from src/main/resources/assets/blur/lang/zh_cn.json rename to common/src/main/resources/assets/blur/lang/zh_cn.json diff --git a/src/main/resources/assets/blur/lang/zh_tw.json b/common/src/main/resources/assets/blur/lang/zh_tw.json similarity index 100% rename from src/main/resources/assets/blur/lang/zh_tw.json rename to common/src/main/resources/assets/blur/lang/zh_tw.json diff --git a/src/main/resources/mixins.blur.json b/common/src/main/resources/blur.mixins.json similarity index 82% rename from src/main/resources/mixins.blur.json rename to common/src/main/resources/blur.mixins.json index 516dc8c..95d1835 100644 --- a/src/main/resources/mixins.blur.json +++ b/common/src/main/resources/blur.mixins.json @@ -2,9 +2,10 @@ "required": true, "minVersion": "0.8", "package": "eu.midnightdust.blur.mixin", - "compatibilityLevel": "JAVA_17", + "compatibilityLevel": "JAVA_21", "client": [ "MixinScreen", + "ScreenAccessor", "MixinHandledScreen", "MixinMinecraftClient", "MixinGameRenderer", diff --git a/common/src/main/resources/blur_compat.mixins.json b/common/src/main/resources/blur_compat.mixins.json new file mode 100644 index 0000000..37082fd --- /dev/null +++ b/common/src/main/resources/blur_compat.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "package": "eu.midnightdust.blur.mixin", + "plugin": "eu.midnightdust.blur.mixin.BlurMixinPlugin", + "compatibilityLevel": "JAVA_21", + "client": [ + "emi.MixinRecipeScreen" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric/build.gradle b/fabric/build.gradle new file mode 100644 index 0000000..a78ec20 --- /dev/null +++ b/fabric/build.gradle @@ -0,0 +1,100 @@ +plugins { + id 'com.github.johnrengelman.shadow' + id "me.shedaniel.unified-publishing" +} + +architectury { + platformSetupLoomIde() + fabric() +} + +configurations { + common + shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files. + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentFabric.extendsFrom common + archivesBaseName = rootProject.archives_base_name + "-fabric" + version = rootProject.mod_version + "+" + rootProject.minecraft_version +} + +dependencies { + modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" + modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" + modImplementation include ("maven.modrinth:midnightlib:${rootProject.midnightlib_version}-fabric") + + common(project(path: ":common", configuration: "namedElements")) { transitive false } + shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false } +} + +processResources { + inputs.property "version", rootProject.version + + filesMatching("fabric.mod.json") { + expand "version": rootProject.version + } +} + +shadowJar { + exclude "architectury.common.json" + + configurations = [project.configurations.shadowCommon] + archiveClassifier = "dev-shadow" +} + +remapJar { + input.set shadowJar.archiveFile + dependsOn shadowJar +} + +sourcesJar { + def commonSources = project(":common").sourcesJar + dependsOn commonSources + from commonSources.archiveFile.map { zipTree(it) } +} + +components.java { + withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { + skip() + } +} + +unifiedPublishing { + project { + displayName = "Blur+ $rootProject.version - Fabric $project.minecraft_version" + releaseType = "$project.release_type" + changelog = releaseChangelog() + gameVersions = [] + gameLoaders = ["fabric","quilt"] + mainPublication remapJar + relations { + depends { + curseforge = "fabric-api" + modrinth = "fabric-api" + } + includes { + curseforge = "midnightlib" + modrinth = "midnightlib" + } + } + + var CURSEFORGE_TOKEN = project.findProperty("CURSEFORGE_TOKEN") ?: System.getenv("CURSEFORGE_TOKEN") + if (CURSEFORGE_TOKEN != null) { + curseforge { + token = CURSEFORGE_TOKEN + id = rootProject.curseforge_id + gameVersions.addAll "Java 21", project.minecraft_version, project.supported_versions + } + } + + var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN") + if (MODRINTH_TOKEN != null) { + modrinth { + token = MODRINTH_TOKEN + id = rootProject.modrinth_id + version = "$rootProject.version-$project.name" + gameVersions.addAll project.minecraft_version, project.supported_versions + } + } + } +} \ No newline at end of file diff --git a/fabric/src/main/java/eu/midnightdust/blur/fabric/BlurFabric.java b/fabric/src/main/java/eu/midnightdust/blur/fabric/BlurFabric.java new file mode 100644 index 0000000..5a55cee --- /dev/null +++ b/fabric/src/main/java/eu/midnightdust/blur/fabric/BlurFabric.java @@ -0,0 +1,14 @@ +package eu.midnightdust.blur.fabric; + +import eu.midnightdust.blur.Blur; +import eu.midnightdust.blur.util.RainbowColor; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; + +public class BlurFabric implements ClientModInitializer { + @Override + public void onInitializeClient() { + Blur.init(); + ClientTickEvents.END_CLIENT_TICK.register(client -> RainbowColor.tick()); + } +} diff --git a/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json similarity index 86% rename from src/main/resources/fabric.mod.json rename to fabric/src/main/resources/fabric.mod.json index 35eab58..470f881 100755 --- a/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -8,7 +8,7 @@ "icon": "assets/blur/icon.png", "entrypoints": { "client": [ - "eu.midnightdust.blur.Blur" + "eu.midnightdust.blur.fabric.BlurFabric" ] }, "contact": { @@ -25,7 +25,8 @@ ], "description": "Various enhancements for the blur effect behind Minecraft GUIs", "mixins": [ - "mixins.blur.json" + "blur.mixins.json", + "blur_compat.mixins.json" ], "depends": { "minecraft": ">=1.20.5" diff --git a/gradle.properties b/gradle.properties index afa5ce2..a22760f 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,22 +1,29 @@ # Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx1G +org.gradle.jvmargs=-Xmx2G org.gradle.parallel=true -# Fabric Properties - # check these on https://fabricmc.net/develop - minecraft_version=1.21 - yarn_mappings=1.21+build.2 - loader_version=0.15.11 - -# Mod Properties - mod_version=4.1.0 - maven_group=eu.midnightdust.blur - archives_base_name=blur - release_type=release - curseforge_id=393563 - modrinth_id=NK39zBp2 +minecraft_version=1.21 +supported_versions=1.21.1 +yarn_mappings=1.21+build.2 +enabled_platforms=fabric,neoforge -# Dependencies - # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api - fabric_version=0.100.1+1.21 - midnightlib_version=1.5.7-fabric +# Mod Properties +mod_version=5.0.0 +maven_group=eu.midnightdust.blur +archives_base_name=blur +release_type=release +curseforge_id=393563 +modrinth_id=NK39zBp2 + +# Modloaders +fabric_loader_version=0.15.11 +fabric_api_version=0.100.1+1.21 + +neoforge_version=21.0.143 +yarn_mappings_patch_neoforge_version = 1.21+build.4 + +# Libraries +midnightlib_version = 1.6.3 +modmenu_version = 11.0.2 + +emi_version=1.1.12+1.21 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 81c736b..e4a5f61 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/localMaven/midnightlib-fabric-1.5.3-24w09a.jar b/localMaven/midnightlib-fabric-1.5.3-24w09a.jar deleted file mode 100644 index b0f97f95bd9fd608120166efae8ec796fab78be2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55552 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 diff --git a/neoforge/build.gradle b/neoforge/build.gradle new file mode 100644 index 0000000..7c6325b --- /dev/null +++ b/neoforge/build.gradle @@ -0,0 +1,113 @@ +plugins { + id 'com.github.johnrengelman.shadow' + id "me.shedaniel.unified-publishing" +} + +repositories { + maven { + name = 'NeoForged' + url = 'https://maven.neoforged.net/releases' + } +} + + +architectury { + platformSetupLoomIde() + neoForge() +} + +loom { + accessWidenerPath = project(":common").loom.accessWidenerPath +} + +configurations { + common { + canBeResolved = true + canBeConsumed = false + } + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentNeoForge.extendsFrom common + + // Files in this configuration will be bundled into your mod using the Shadow plugin. + // Don't use the `shadow` configuration from the plugin itself as it's meant for excluding files. + shadowBundle { + canBeResolved = true + canBeConsumed = false + } + archivesBaseName = rootProject.archives_base_name + "-neoforge" + version = rootProject.mod_version + "+" + rootProject.minecraft_version +} + +dependencies { + neoForge "net.neoforged:neoforge:$rootProject.neoforge_version" + modImplementation ("maven.modrinth:midnightlib:${rootProject.midnightlib_version}-neoforge") + + common(project(path: ':common', configuration: 'namedElements')) { transitive false } + shadowBundle project(path: ':common', configuration: 'transformProductionNeoForge') +} + +processResources { + inputs.property 'version', rootProject.version + + filesMatching('META-INF/neoforge.mods.toml') { + expand version: rootProject.version + } +} + +shadowJar { + configurations = [project.configurations.shadowBundle] + archiveClassifier = 'dev-shadow' +} + +remapJar { + input.set shadowJar.archiveFile +} + +sourcesJar { + def commonSources = project(":common").sourcesJar + dependsOn commonSources + from commonSources.archiveFile.map { zipTree(it) } +} + +components.java { + withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { + skip() + } +} + +unifiedPublishing { + project { + displayName = "Blur+ $rootProject.version - NeoForge $project.minecraft_version" + releaseType = "$project.release_type" + changelog = releaseChangelog() + gameVersions = [] + gameLoaders = ["neoforge"] + mainPublication remapJar + relations { + depends { + curseforge = "midnightlib" + modrinth = "midnightlib" + } + } + + var CURSEFORGE_TOKEN = project.findProperty("CURSEFORGE_TOKEN") ?: System.getenv("CURSEFORGE_TOKEN") + if (CURSEFORGE_TOKEN != null) { + curseforge { + token = CURSEFORGE_TOKEN + id = rootProject.curseforge_id + gameVersions.addAll "Java 21", project.minecraft_version, project.supported_versions + } + } + + var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN") + if (MODRINTH_TOKEN != null) { + modrinth { + token = MODRINTH_TOKEN + id = rootProject.modrinth_id + version = "$rootProject.version-$project.name" + gameVersions.addAll project.minecraft_version, project.supported_versions + } + } + } +} diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties new file mode 100644 index 0000000..2914393 --- /dev/null +++ b/neoforge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge \ No newline at end of file diff --git a/neoforge/src/main/java/eu/midnightdust/blur/neoforge/BlurNeoForge.java b/neoforge/src/main/java/eu/midnightdust/blur/neoforge/BlurNeoForge.java new file mode 100644 index 0000000..4f99669 --- /dev/null +++ b/neoforge/src/main/java/eu/midnightdust/blur/neoforge/BlurNeoForge.java @@ -0,0 +1,24 @@ +package eu.midnightdust.blur.neoforge; + +import eu.midnightdust.blur.Blur; +import eu.midnightdust.blur.util.RainbowColor; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.client.event.ClientTickEvent; + +@Mod(value = "blur", dist = Dist.CLIENT) +public class BlurNeoForge { + public BlurNeoForge() { + Blur.init(); + } + + @EventBusSubscriber(modid = "blur", bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) + public static class ClientGameEvents { + @SubscribeEvent + public static void endClientTick(ClientTickEvent.Post event) { + RainbowColor.tick(); + } + } +} diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..b871078 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,33 @@ +modLoader = "javafml" +loaderVersion = "[2,)" +#issueTrackerURL = "" +license = "MIT License" + +[[mods]] +modId = "blur" +version = "${version}" +displayName = "Blur+" +logoFile = "blur.png" +authors = "Motschen, tterrag1098, Pyrofab, backryun, byquanton" +description = ''' +Various enhancements for the blur effect behind Minecraft GUIs +''' + +[[mixins]] +config = "blur.mixins.json" +[[mixins]] +config = "blur_compat.mixins.json" + +[[dependencies.blur]] +modId = "neoforge" +mandatory = true +versionRange = "[21.0,)" +ordering = "NONE" +side = "CLIENT" + +[[dependencies.blur]] +modId = "minecraft" +mandatory = true +versionRange = "[1.21,)" +ordering = "NONE" +side = "CLIENT" \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 2e9d858..1ea6c73 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,13 +1,15 @@ pluginManagement { repositories { - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } + maven { url "https://maven.fabricmc.net/" } maven { url "https://maven.architectury.dev/" } - mavenCentral() + maven { url "https://maven.neoforged.net/releases" } gradlePluginPortal() } } -rootProject.name = "blur" \ No newline at end of file +include("common") +include("fabric") +include("neoforge") +//include("quilt") + +rootProject.name = "blur"