diff --git a/.gitignore b/.gitignore index 1a2b7a06..5f5fc937 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .gradle .settings /.idea/ +/.vscode/ /run/ /build/ /eclipse/ @@ -25,6 +26,12 @@ whitelist.json *.iml *.ipr *.iws -src/main/resources/mixins.*.json +src/main/resources/mixins.*([!.]).json *.bat -.DS_Store +*.DS_Store +!gradlew.bat +.factorypath +addon.local.gradle +addon.local.gradle.kts +addon.late.local.gradle +addon.late.local.gradle.kts diff --git a/build.gradle b/build.gradle index 39309904..bd6289cf 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -//version: 1685785062 +//version: 1689409577 /* DO NOT CHANGE THIS FILE! Also, you may replace this file at any time if there is an update available. @@ -69,7 +69,7 @@ plugins { id 'com.diffplug.spotless' version '6.13.0' apply false // 6.13.0 is the last jvm8 supporting version id 'com.modrinth.minotaur' version '2.+' apply false id 'com.matthewprenger.cursegradle' version '1.4.0' apply false - id 'com.gtnewhorizons.retrofuturagradle' version '1.3.14' + id 'com.gtnewhorizons.retrofuturagradle' version '1.3.19' } print("You might want to check out './gradlew :faq' if your build fails.\n") @@ -115,6 +115,8 @@ propertyDefaultIfUnset("usesMixinDebug", project.usesMixins) propertyDefaultIfUnset("forceEnableMixins", false) propertyDefaultIfUnset("channel", "stable") propertyDefaultIfUnset("mappingsVersion", "12") +propertyDefaultIfUnset("usesMavenPublishing", true) +propertyDefaultIfUnset("mavenPublishUrl", "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases") propertyDefaultIfUnset("modrinthProjectId", "") propertyDefaultIfUnset("modrinthRelations", "") propertyDefaultIfUnset("curseForgeProjectId", "") @@ -357,7 +359,27 @@ catch (Exception ignored) { String identifiedVersion String versionOverride = System.getenv("VERSION") ?: null try { - identifiedVersion = versionOverride == null ? gitVersion() : versionOverride + // Produce a version based on the tag, or for branches something like 0.2.2-configurable-maven-and-extras.38+43090270b6-dirty + if (versionOverride == null) { + def gitDetails = versionDetails() + def isDirty = gitVersion().endsWith(".dirty") // No public API for this, isCleanTag has a different meaning + String branchName = gitDetails.branchName ?: (System.getenv('GIT_BRANCH') ?: 'git') + if (branchName.startsWith('origin/')) { + branchName = branchName.minus('origin/') + } + branchName = branchName.replaceAll("[^a-zA-Z0-9-]+", "-") // sanitize branch names for semver + identifiedVersion = gitDetails.lastTag ?: '${gitDetails.gitHash}' + if (gitDetails.commitDistance > 0) { + identifiedVersion += "-${branchName}.${gitDetails.commitDistance}+${gitDetails.gitHash}" + if (isDirty) { + identifiedVersion += "-dirty" + } + } else if (isDirty) { + identifiedVersion += "-${branchName}+${gitDetails.gitHash}-dirty" + } + } else { + identifiedVersion = versionOverride + } } catch (Exception ignored) { out.style(Style.Failure).text( @@ -465,10 +487,19 @@ sourceSets { } } -if (file('addon.gradle').exists()) { +if (file('addon.gradle.kts').exists()) { + apply from: 'addon.gradle.kts' +} else if (file('addon.gradle').exists()) { apply from: 'addon.gradle' } +// File for local tweaks not commited to Git +if (file('addon.local.gradle.kts').exists()) { + apply from: 'addon.local.gradle.kts' +} else if (file('addon.local.gradle').exists()) { + apply from: 'addon.local.gradle' +} + // Allow unsafe repos but warn repositories.configureEach { repo -> if (repo instanceof org.gradle.api.artifacts.repositories.UrlArtifactRepository) { @@ -479,7 +510,14 @@ repositories.configureEach { repo -> } } -apply from: 'repositories.gradle' +if (file('repositories.gradle.kts').exists()) { + apply from: 'repositories.gradle.kts' +} else if (file('repositories.gradle').exists()) { + apply from: 'repositories.gradle' +} else { + logger.error("Neither repositories.gradle.kts nor repositories.gradle was found, make sure you extracted the full ExampleMod template.") + throw new RuntimeException("Missing repositories.gradle[.kts]") +} configurations { runtimeClasspath.extendsFrom(runtimeOnlyNonPublishable) @@ -611,7 +649,32 @@ configurations.all { } } -apply from: 'dependencies.gradle' +dependencies { + constraints { + def minGtnhLibVersion = "0.0.13" + implementation("com.github.GTNewHorizons:GTNHLib:${minGtnhLibVersion}") { + because("fixes duplicate mod errors in java 17 configurations using old gtnhlib") + } + runtimeOnly("com.github.GTNewHorizons:GTNHLib:${minGtnhLibVersion}") { + because("fixes duplicate mod errors in java 17 configurations using old gtnhlib") + } + devOnlyNonPublishable("com.github.GTNewHorizons:GTNHLib:${minGtnhLibVersion}") { + because("fixes duplicate mod errors in java 17 configurations using old gtnhlib") + } + runtimeOnlyNonPublishable("com.github.GTNewHorizons:GTNHLib:${minGtnhLibVersion}") { + because("fixes duplicate mod errors in java 17 configurations using old gtnhlib") + } + } +} + +if (file('dependencies.gradle.kts').exists()) { + apply from: 'dependencies.gradle.kts' +} else if (file('dependencies.gradle').exists()) { + apply from: 'dependencies.gradle' +} else { + logger.error("Neither dependencies.gradle.kts nor dependencies.gradle was found, make sure you extracted the full ExampleMod template.") + throw new RuntimeException("Missing dependencies.gradle[.kts]") +} def mixingConfigRefMap = 'mixins.' + modId + '.refmap.json' def mixinTmpDir = buildDir.path + File.separator + 'tmp' + File.separator + 'mixins' @@ -724,13 +787,13 @@ ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies" } dependencies { - def lwjgl3ifyVersion = '1.3.5' + def lwjgl3ifyVersion = '1.4.0' def asmVersion = '9.4' if (modId != 'lwjgl3ify') { java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}") } if (modId != 'hodgepodge') { - java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.2.13') + java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.2.19') } java17PatchDependencies('net.minecraft:launchwrapper:1.15') {transitive = false} @@ -979,6 +1042,9 @@ idea { } } runConfigurations { + "0. Build and Test"(Gradle) { + taskNames = ["build"] + } "1. Run Client"(Gradle) { taskNames = ["runClient"] } @@ -1098,6 +1164,11 @@ tasks.named("processIdeaSettings").configure { dependsOn("injectTags") } +tasks.named("ideVirtualMainClasses").configure { + // Make IntelliJ "Build project" build the mod jars + dependsOn("jar", "reobfJar", "spotlessCheck") +} + // workaround variable hiding in pom processing def projectConfigs = project.configurations @@ -1118,12 +1189,14 @@ publishing { } repositories { - maven { - url = "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases" - allowInsecureProtocol = true - credentials { - username = System.getenv("MAVEN_USER") ?: "NONE" - password = System.getenv("MAVEN_PASSWORD") ?: "NONE" + if (usesMavenPublishing.toBoolean()) { + maven { + url = mavenPublishUrl + allowInsecureProtocol = mavenPublishUrl.startsWith("http://") // Mostly for the GTNH maven + credentials { + username = System.getenv("MAVEN_USER") ?: "NONE" + password = System.getenv("MAVEN_PASSWORD") ?: "NONE" + } } } } @@ -1344,8 +1417,14 @@ boolean isNewBuildScriptVersionAvailable() { String currentBuildScript = getFile("build.gradle").getText() String currentBuildScriptHash = getVersionHash(currentBuildScript) - String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText() - String availableBuildScriptHash = getVersionHash(availableBuildScript) + String availableBuildScriptHash + try { + String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText() + availableBuildScriptHash = getVersionHash(availableBuildScript) + } catch (IOException e) { + logger.warn("Could not check for buildscript update availability: {}", e.message) + return false + } boolean isUpToDate = currentBuildScriptHash.empty || availableBuildScriptHash.empty || currentBuildScriptHash == availableBuildScriptHash return !isUpToDate @@ -1510,3 +1589,17 @@ def getSecondaryArtifacts() { if (apiPackage) secondaryArtifacts += [apiJar] return secondaryArtifacts } + +// For easier scripting of things that require variables defined earlier in the buildscript +if (file('addon.late.gradle.kts').exists()) { + apply from: 'addon.late.gradle.kts' +} else if (file('addon.late.gradle').exists()) { + apply from: 'addon.late.gradle' +} + +// File for local tweaks not commited to Git +if (file('addon.late.local.gradle.kts').exists()) { + apply from: 'addon.late.local.gradle.kts' +} else if (file('addon.late.local.gradle').exists()) { + apply from: 'addon.late.local.gradle' +} diff --git a/src/main/java/codechicken/nei/ItemsGrid.java b/src/main/java/codechicken/nei/ItemsGrid.java index 29479233..9459b59d 100644 --- a/src/main/java/codechicken/nei/ItemsGrid.java +++ b/src/main/java/codechicken/nei/ItemsGrid.java @@ -16,12 +16,14 @@ import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.shader.Framebuffer; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; import codechicken.lib.vec.Rectangle4i; import codechicken.nei.ItemPanel.ItemPanelSlot; @@ -354,8 +356,14 @@ public class ItemsGrid { } else { gui = null; } + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); + RenderHelper.disableStandardItemLighting(); recipeTooltipGui.drawGuiContainerBackgroundLayer(0.0f, -100, -100); + GL11.glPopAttrib(); if (recipeTooltipGui.slotcontainer != null) { + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); + RenderHelper.enableGUIStandardItemLighting(); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); @SuppressWarnings("unchecked") List slots = (List) recipeTooltipGui.slotcontainer.inventorySlots; for (Slot slot : slots) { @@ -363,6 +371,7 @@ public class ItemsGrid { GuiContainerManager.drawItem(slot.xDisplayPosition, slot.yDisplayPosition, slot.getStack()); } } + GL11.glPopAttrib(); } recipeTooltipGui.drawGuiContainerForegroundLayer(-100, -100); for (GuiButton btn : recipeTooltipGui.getOverlayButtons()) { diff --git a/src/main/java/codechicken/nei/recipe/GuiCraftingRecipe.java b/src/main/java/codechicken/nei/recipe/GuiCraftingRecipe.java index 59f20489..83b90db8 100644 --- a/src/main/java/codechicken/nei/recipe/GuiCraftingRecipe.java +++ b/src/main/java/codechicken/nei/recipe/GuiCraftingRecipe.java @@ -105,6 +105,7 @@ public class GuiCraftingRecipe extends GuiRecipe { public static void registerRecipeHandler(ICraftingHandler handler) { final String handlerId = handler.getHandlerId(); + if (craftinghandlers.stream().anyMatch(h -> h.getHandlerId().equals(handlerId)) || serialCraftingHandlers.stream().anyMatch(h -> h.getHandlerId().equals(handlerId))) return; diff --git a/src/main/java/codechicken/nei/recipe/GuiRecipe.java b/src/main/java/codechicken/nei/recipe/GuiRecipe.java index 0b12499e..71cf6d73 100644 --- a/src/main/java/codechicken/nei/recipe/GuiRecipe.java +++ b/src/main/java/codechicken/nei/recipe/GuiRecipe.java @@ -13,7 +13,6 @@ import java.util.regex.Matcher; import java.util.stream.Collectors; import java.util.stream.IntStream; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; @@ -108,7 +107,7 @@ public abstract class GuiRecipe extends GuiContainer i /** * This will only be true iff height hacking has been configured for the current recipe handler AND we are currently - * within the scope of an active {@link HeightHack} instance. + * within the scope of an active {@link CompatibilityHacks} instance. */ private boolean isHeightHackApplied = false; @@ -139,19 +138,25 @@ public abstract class GuiRecipe extends GuiContainer i * property's value so that these old mods' calculations return the correct value for the new height. * *

+ * New and old mods often assume that the handler is only drawn when {@link GuiRecipe} is the currently active + * screen in {@link net.minecraft.client.Minecraft}. This is no longer true since the addition of recipe tooltips + * which need to render the recipe in other containers on mouse hover, this class temporarily switches the active + * screen to {@code this} while rendering them to avoid ClassCastExceptions and other similar crashes. + * + *

* This class is an {@link AutoCloseable} so that it can be used with try-with-resources, which will ensure that - * {@link #height} is returned to the correct value afterwards. + * {@link #height} and {@link net.minecraft.client.Minecraft#currentScreen} is returned to the correct value + * afterwards. */ - private class HeightHack implements AutoCloseable { + private class CompatibilityHacks implements AutoCloseable { private final int trueHeight; private final int trueGuiTop; private final GuiScreen trueGui; - private HeightHack() { + private CompatibilityHacks() { trueHeight = height; trueGuiTop = guiTop; - trueGui = Minecraft.getMinecraft().currentScreen; isHeightHackApplied = NEIClientConfig.heightHackHandlerRegex.stream() .map(pattern -> pattern.matcher(handler.getHandlerId())).anyMatch(Matcher::matches); @@ -176,12 +181,13 @@ public abstract class GuiRecipe extends GuiContainer i // guiWidth (the x-value of the left edge of the NEI recipe screen). So if we wanted to override width // as well, we'd do this: // width = (2 * guiWidth) + 176; + } - // Recipe handlers may assume the current screen is the GuiRecipe object, which is not the case in - // recipe tooltips drawn on the bookmarks panel with the main inventory open. - if (limitToOneRecipe) { - Minecraft.getMinecraft().currentScreen = GuiRecipe.this; - } + // Recipe handlers may assume the current screen is the GuiRecipe object, which is not the case in + // recipe tooltips drawn on the bookmarks panel with the main inventory open. + trueGui = NEIClientUtils.mc().currentScreen; + if (limitToOneRecipe) { + NEIClientUtils.mc().currentScreen = GuiRecipe.this; } } @@ -189,7 +195,13 @@ public abstract class GuiRecipe extends GuiContainer i public void close() { guiTop = trueGuiTop; height = trueHeight; - Minecraft.getMinecraft().currentScreen = trueGui; + + // Only restore currentScreen if it hasn't been altered by a recipe handler (for example through + // Minecraft#displayGuiScreen). + if (limitToOneRecipe && NEIClientUtils.mc().currentScreen == GuiRecipe.this) { + NEIClientUtils.mc().currentScreen = trueGui; + } + isHeightHackApplied = false; } } @@ -207,7 +219,7 @@ public abstract class GuiRecipe extends GuiContainer i super.initGui(); } else { this.guiLeft = (this.width - this.xSize) / 2; - this.mc = Minecraft.getMinecraft(); + this.mc = NEIClientUtils.mc(); this.fontRendererObj = mc.fontRenderer; ScaledResolution scaledresolution = new ScaledResolution( this.mc, @@ -253,13 +265,14 @@ public abstract class GuiRecipe extends GuiContainer i final int recipesPerPage = getRecipesPerPage(); overlayButtons = new GuiButton[recipesPerPage]; final int xOffset = limitToOneRecipe ? ((xSize / 2) - 2) : (width / 2); + final int yOffset = limitToOneRecipe ? 0 : guiTop - 18; final String overlayKeyName = NEIClientConfig .getKeyName(NEIClientConfig.getKeyBinding("gui.overlay_use"), true); for (int i = 0; i < recipesPerPage; i++) { overlayButtons[i] = new GuiNEIButton( OVERLAY_BUTTON_ID_START + i, xOffset + 65, - 16 + (handlerInfo.getHeight() * (i + 1)) - 2, + yOffset + getRecipePosition(i).y + handlerInfo.getHeight(), buttonWidth, buttonHeight, "?"); @@ -389,7 +402,7 @@ public abstract class GuiRecipe extends GuiContainer i } if (GuiContainerManager.getManager(this).lastKeyTyped(i, c)) return; - try (HeightHack heightHack = new HeightHack()) { + try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) { for (int recipe : getRecipeIndices()) if (handler.keyTyped(this, c, i, recipe)) return; } @@ -411,7 +424,7 @@ public abstract class GuiRecipe extends GuiContainer i @Override protected void mouseClicked(int x, int y, int button) { - try (HeightHack heightHack = new HeightHack()) { + try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) { for (int recipe : getRecipeIndices()) if (handler.mouseClicked(this, button, recipe)) return; } @@ -488,7 +501,7 @@ public abstract class GuiRecipe extends GuiContainer i @Override public List handleTooltip(GuiContainer gui, int mousex, int mousey, List currenttip) { - try (HeightHack heightHack = new HeightHack()) { + try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) { for (int i : getRecipeIndices()) currenttip = handler.handleTooltip(this, currenttip, i); } recipeTabs.handleTooltip(mousex, mousey, currenttip); @@ -498,7 +511,7 @@ public abstract class GuiRecipe extends GuiContainer i @Override public List handleItemTooltip(GuiContainer gui, ItemStack stack, int mousex, int mousey, List currenttip) { - try (HeightHack heightHack = new HeightHack()) { + try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) { for (int i : getRecipeIndices()) currenttip = handler.handleItemTooltip(this, stack, currenttip, i); } @@ -656,7 +669,7 @@ public abstract class GuiRecipe extends GuiContainer i GL11.glPushMatrix(); GL11.glTranslatef(5, 32 - ySkip + yShift, 0); - try (HeightHack heightHack = new HeightHack()) { + try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) { for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) { handler.drawForeground(i); if (drawItemPresence && (isMouseOverOverlayButton(i - page * recipesPerPage) || limitToOneRecipe) @@ -711,7 +724,7 @@ public abstract class GuiRecipe extends GuiContainer i GL11.glPushMatrix(); GL11.glTranslatef(guiLeft + 5, guiTop - ySkip + 32 + yShift, 0); - try (HeightHack heightHack = new HeightHack()) { + try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) { for (int i = page * recipesPerPage; i < handler.numRecipes() && i < (page + 1) * recipesPerPage; i++) { handler.drawBackground(i); GL11.glTranslatef(0, handlerInfo.getHeight(), 0);