feat(resource-pack-entry-widgets): add forge port
All checks were successful
ci/woodpecker/push/docs Pipeline was successful
ci/woodpecker/push/jfmod Pipeline was successful

This commit is contained in:
Johannes Frohnmeyer 2024-07-17 21:45:20 +02:00
parent c271ac5c10
commit 4c3e81570c
Signed by: Johannes
GPG Key ID: E76429612C2929F4
10 changed files with 243 additions and 1 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -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"]

View File

@ -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)
}

View File

@ -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<ResourcePackEntryWidget> 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);
}

View File

@ -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";
}

View File

@ -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<ServiceLoader.Provider<ResourcePackEntryWidget>> {
@Override
public int compare(ServiceLoader.Provider<ResourcePackEntryWidget> o1, ServiceLoader.Provider<ResourcePackEntryWidget> o2) {
return o1.type().getName().compareTo(o2.type().getName());
}
}

View File

@ -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<Boolean> info) {
// Inject before super call
if (libjf$selected != -1) {
info.setReturnValue(true);
ResourcePackEntryWidget.WIDGETS.get(libjf$selected).onClick(pack);
}
}
}

View File

@ -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"

View File

@ -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
}
}

View File

@ -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")