From 4c3e81570c05ef4b900675ea47843eb6255748b2 Mon Sep 17 00:00:00 2001 From: JFronny Date: Wed, 17 Jul 2024 21:45:20 +0200 Subject: [PATCH] feat(resource-pack-entry-widgets): add forge port --- .gitignore | 1 + gradle/libs.versions.toml | 2 + .../build.gradle.kts | 30 ++++++ .../api/v0/ResourcePackEntryWidget.java | 96 +++++++++++++++++++ .../entrywidgets/impl/EntryWidgetsMod.java | 8 ++ .../impl/EntrypointComparator.java | 13 +++ .../impl/mixin/ResourcePackEntryMixin.java | 52 ++++++++++ .../resources/META-INF/neoforge.mods.toml | 27 ++++++ ...ource_pack_entry_widgets_forge.mixins.json | 12 +++ settings.gradle.kts | 3 +- 10 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 libjf-resource-pack-entry-widgets-forge/build.gradle.kts create mode 100644 libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/api/v0/ResourcePackEntryWidget.java create mode 100644 libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/EntryWidgetsMod.java create mode 100644 libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/EntrypointComparator.java create mode 100644 libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/mixin/ResourcePackEntryMixin.java create mode 100644 libjf-resource-pack-entry-widgets-forge/src/main/resources/META-INF/neoforge.mods.toml create mode 100644 libjf-resource-pack-entry-widgets-forge/src/main/resources/libjf_resource_pack_entry_widgets_forge.mixins.json diff --git a/.gitignore b/.gitignore index 67e3666..8b155d3 100644 --- a/.gitignore +++ b/.gitignore @@ -114,6 +114,7 @@ gradle-app.setting # Common working directory run/ +runs/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 95f5ec9..54d21bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ minecraft = "1.21" yarn = "build.1" fabric-loader = "0.15.11" fabric-api = "0.100.1+1.21" +neoforge = "21.0.101-beta" jf-commons = "2.0.0-SNAPSHOT" modmenu = "11.0.0-beta.1" annotations = "24.1.0" @@ -22,6 +23,7 @@ commons-unsafe = { module = "io.gitlab.jfronny:commons-unsafe", version.ref="jf- modmenu = { module = "com.terraformersmc:modmenu", version.ref="modmenu" } annotations = { module = "org.jetbrains:annotations", version.ref="annotations" } javapoet = { module = "com.squareup:javapoet", version.ref="javapoet" } +neoforge = { module = "net.neoforged:neoforge", version.ref="neoforge" } [bundles] commons = ["commons", "commons-http-client", "commons-logger", "commons-io", "commons-serialize", "commons-serialize-databind", "commons-serialize-json"] \ No newline at end of file diff --git a/libjf-resource-pack-entry-widgets-forge/build.gradle.kts b/libjf-resource-pack-entry-widgets-forge/build.gradle.kts new file mode 100644 index 0000000..4e0a40f --- /dev/null +++ b/libjf-resource-pack-entry-widgets-forge/build.gradle.kts @@ -0,0 +1,30 @@ +import io.gitlab.jfronny.scripts.versionS + +plugins { + id("jf.maven-publish") + id("net.neoforged.gradle.userdev") version "7.0.145" +} + +base { + archivesName = "libjf-resource-pack-entry-widgets-forge" +} + +java { + toolchain.languageVersion = JavaLanguageVersion.of(21) +} + +dependencies { + implementation(libs.neoforge) +} + +tasks.processResources { + val map = mapOf( + "version" to project.versionS, + "minecraft_version" to libs.versions.minecraft.get(), + "loader_version" to libs.versions.neoforge.get() + ) + filesMatching("META-INF/neoforge.mods.toml") { + expand(map) + } + inputs.property("version", project.versionS) +} \ No newline at end of file diff --git a/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/api/v0/ResourcePackEntryWidget.java b/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/api/v0/ResourcePackEntryWidget.java new file mode 100644 index 0000000..f21ef79 --- /dev/null +++ b/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/api/v0/ResourcePackEntryWidget.java @@ -0,0 +1,96 @@ +package io.gitlab.jfronny.libjf.entrywidgets.api.v0; + +import io.gitlab.jfronny.libjf.entrywidgets.impl.EntrypointComparator; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.packs.PackSelectionModel; + +import java.util.List; +import java.util.ServiceLoader; + +/** + * Represents an additional widget inserted on the right hand side of a resource pack entry (in the resource pack or data pack screen) + */ +public interface ResourcePackEntryWidget { + /** + * Lists all known widgets from right to left. Immutable. + */ + List WIDGETS = ServiceLoader.load(ResourcePackEntryWidget.class) + .stream() + .sorted(new EntrypointComparator()) + .map(ServiceLoader.Provider::get) + .toList(); + + /** + * Checks whether the widget should be rendered for a given pack. + * + * @param pack the pack to render the widget for + * @param selectable whether the pack is selectable + * @return whether the widget is visible + */ + default boolean isVisible(PackSelectionModel.Entry pack, boolean selectable) { + return true; + } + + /** + * Gets the width of this widget. + * + * @param pack the pack to render the widget for + * @return the width of the widget + */ + default int getWidth(PackSelectionModel.Entry pack) { + return 20; + } + + /** + * Gets the height of this widget. + * + * @param pack the pack to render the widget for + * @param rowHeight the height of the row containing the widget + * @return the height of the widget + */ + default int getHeight(PackSelectionModel.Entry pack, int rowHeight) { + return 20; + } + + /** + * Gets the Y position of this widget relative to the top of the row. + * + * @param pack the pack to render the widget for + * @param rowHeight the height of the row containing the widget + * @return the relative y position of the widget + */ + default int getY(PackSelectionModel.Entry pack, int rowHeight) { + return (rowHeight - getHeight(pack, rowHeight)) / 2; + } + + /** + * Gets the X margin of the widget. + * Two widgets will be separated by the maximum of their X margins. + * Also, the rightmost widget will be separated from the edge of the entry by its margin. + * + * @param pack the pack to render the widget for + * @return the X margin of the widget + */ + default int getXMargin(PackSelectionModel.Entry pack) { + return 10; + } + + /** + * Renders the widget. + * + * @param pack the pack to render the widget for + * @param context the context to draw to + * @param x the absolute x coordinate at which to draw + * @param y the absolute y coordinate at which to draw + * @param hovered whether the widget is being hovered by the cursor + * @param tickDelta the time that has passed since the last call + */ + void render(PackSelectionModel.Entry pack, GuiGraphics context, int x, int y, boolean hovered, float tickDelta); + + /** + * Executed when a widget is clicked. + * + * @param pack the pack for which the widget was clicked + */ + void onClick(PackSelectionModel.Entry pack); +} diff --git a/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/EntryWidgetsMod.java b/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/EntryWidgetsMod.java new file mode 100644 index 0000000..adb7830 --- /dev/null +++ b/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/EntryWidgetsMod.java @@ -0,0 +1,8 @@ +package io.gitlab.jfronny.libjf.entrywidgets.impl; + +import net.neoforged.fml.common.Mod; + +@Mod(EntryWidgetsMod.MOD_ID) +public class EntryWidgetsMod { + public static final String MOD_ID = "libjf_resource_pack_entry_widgets_forge"; +} diff --git a/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/EntrypointComparator.java b/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/EntrypointComparator.java new file mode 100644 index 0000000..e3d553d --- /dev/null +++ b/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/EntrypointComparator.java @@ -0,0 +1,13 @@ +package io.gitlab.jfronny.libjf.entrywidgets.impl; + +import io.gitlab.jfronny.libjf.entrywidgets.api.v0.ResourcePackEntryWidget; + +import java.util.Comparator; +import java.util.ServiceLoader; + +public class EntrypointComparator implements Comparator> { + @Override + public int compare(ServiceLoader.Provider o1, ServiceLoader.Provider o2) { + return o1.type().getName().compareTo(o2.type().getName()); + } +} diff --git a/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/mixin/ResourcePackEntryMixin.java b/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/mixin/ResourcePackEntryMixin.java new file mode 100644 index 0000000..dda092b --- /dev/null +++ b/libjf-resource-pack-entry-widgets-forge/src/main/java/io/gitlab/jfronny/libjf/entrywidgets/impl/mixin/ResourcePackEntryMixin.java @@ -0,0 +1,52 @@ +package io.gitlab.jfronny.libjf.entrywidgets.impl.mixin; + +import io.gitlab.jfronny.libjf.entrywidgets.api.v0.ResourcePackEntryWidget; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.packs.PackSelectionModel; +import net.minecraft.client.gui.screens.packs.TransferableSelectionList; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(TransferableSelectionList.PackEntry.class) +public abstract class ResourcePackEntryMixin { + @Shadow protected abstract boolean showHoverOverlay(); + @Shadow @Final private PackSelectionModel.Entry pack; + @Unique int libjf$selected = -1; + + @Inject(at = @At("TAIL"), method = "render(Lnet/minecraft/client/gui/GuiGraphics;IIIIIIIZF)V") + private void render(GuiGraphics context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta, CallbackInfo info) { + int prevMargin = 0; + int deltaX = 2; + boolean selectable = showHoverOverlay(); + libjf$selected = -1; + for (int i = 0; i < ResourcePackEntryWidget.WIDGETS.size(); i++) { + ResourcePackEntryWidget widget = ResourcePackEntryWidget.WIDGETS.get(i); + if (!widget.isVisible(pack, selectable)) continue; + deltaX += Math.max(prevMargin, widget.getXMargin(pack)); + int width = widget.getWidth(pack); + int height = widget.getHeight(pack, entryHeight); + int entryX = x + entryWidth - deltaX - width; + int entryY = y + widget.getY(pack, entryHeight); + deltaX += width; + boolean widgetHovered = mouseX <= entryX + width && mouseX >= entryX && mouseY <= entryY + height && mouseY >= entryY; + widget.render(pack, context, entryX, entryY, widgetHovered, tickDelta); + if (widgetHovered) libjf$selected = i; + prevMargin = widget.getXMargin(pack); + } + } + + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/components/ObjectSelectionList$Entry;mouseClicked(DDI)Z"), method = "mouseClicked(DDI)Z", cancellable = true) + public void mouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable info) { + // Inject before super call + if (libjf$selected != -1) { + info.setReturnValue(true); + ResourcePackEntryWidget.WIDGETS.get(libjf$selected).onClick(pack); + } + } +} diff --git a/libjf-resource-pack-entry-widgets-forge/src/main/resources/META-INF/neoforge.mods.toml b/libjf-resource-pack-entry-widgets-forge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..5a21a91 --- /dev/null +++ b/libjf-resource-pack-entry-widgets-forge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,27 @@ +modLoader="javafml" +loaderVersion="[4,)" +license="MIT" + +[[mods]] +modId="libjf_resource_pack_entry_widgets_forge" +version="${version}" +displayName="LibJF Resource Pack Entry Widgets" +authors="JFronny" +description="Forge variant of libjf-resource-pack-entry-widgets" + +[[mixins]] +config="libjf_resource_pack_entry_widgets_forge.mixins.json" + +[[dependencies.libjf-resource-pack-entry-widgets-forge]] +modId="neoforge" +type="required" +versionRange="[loader_version,)" +ordering="NONE" +side="BOTH" + +[[dependencies.libjf-resource-pack-entry-widgets-forge]] +modId="minecraft" +type="required" +versionRange="[minecraft_version,)" +ordering="NONE" +side="BOTH" \ No newline at end of file diff --git a/libjf-resource-pack-entry-widgets-forge/src/main/resources/libjf_resource_pack_entry_widgets_forge.mixins.json b/libjf-resource-pack-entry-widgets-forge/src/main/resources/libjf_resource_pack_entry_widgets_forge.mixins.json new file mode 100644 index 0000000..886985e --- /dev/null +++ b/libjf-resource-pack-entry-widgets-forge/src/main/resources/libjf_resource_pack_entry_widgets_forge.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.gitlab.jfronny.libjf.entrywidgets.impl.mixin", + "compatibilityLevel": "JAVA_16", + "client": [ + "ResourcePackEntryMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index d247f6e..b32440f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,8 +2,8 @@ pluginManagement { repositories { maven("https://maven.fabricmc.net/") // FabricMC // maven("https://maven.architectury.dev/") // Architectury -// maven("https://files.minecraftforge.net/maven/") // Forge maven("https://maven.frohnmeyer-wds.de/artifacts") // scripts + maven("https://maven.neoforged.net/releases") // Forge gradlePluginPortal() } plugins { @@ -35,6 +35,7 @@ include("libjf-mainhttp-v0") include("libjf-web-v1") include("libjf-resource-pack-entry-widgets-v0") +include("libjf-resource-pack-entry-widgets-forge") include("libjf-bom") include("libjf-catalog")