Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

Commit

Permalink
feat: Add YACLOptionListWidgetMixin and YACLStringControllerMixin
Browse files Browse the repository at this point in the history
  • Loading branch information
Steveplays28 committed Jan 14, 2024
1 parent e38a969 commit b059917
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 8 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ dependencies {
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"

// Mixin Extras
include(implementation(annotationProcessor("io.github.llamalad7:mixinextras-fabric:${project.mixin_extras_version}")))

// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"

Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ archives_base_name=blendium
supported_minecraft_version=1.20.x

# Dependencies
mixin_extras_version=0.2.2
fabric_api_version=0.91.0+1.20.1
modmenu_version=7.2.1
sodium_version=mc1.20.1-0.5.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import net.minecraft.text.Text;

import java.util.AbstractMap;
import java.util.Collections;

/**
* Blendium config screen builder, uses YACL to generate the config screen.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.steveplays28.blendium.client.compat.yacl.extension;

import io.github.steveplays28.blendium.client.compat.yacl.option.MapOption;

public interface YACLOptionListWidgetExtension {
void blendium$setMapOption(MapOption<?, ?> mapOption);
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void render(DrawContext graphics, int mouseX, int mouseY, float delta) {
removeButton.render(graphics, mouseX, mouseY, delta);
moveUpButton.render(graphics, mouseX, mouseY, delta);
moveDownButton.render(graphics, mouseX, mouseY, delta);
// entryWidget.render(graphics, mouseX, mouseY, delta);
entryWidget.render(graphics, mouseX, mouseY, delta);
}

protected void updateButtonStates() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;

public class MapOptionEntryImpl<S, T> implements MapOptionEntry<S, T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import dev.isxander.yacl3.impl.utils.YACLConstants;
import io.github.steveplays28.blendium.client.compat.yacl.option.MapOption;
import io.github.steveplays28.blendium.client.compat.yacl.option.MapOptionEntry;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.text.Text;
import org.apache.commons.lang3.Validate;
import org.jetbrains.annotations.NotNull;
Expand All @@ -18,6 +17,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public final class MapOptionImpl<S, T> implements MapOption<S, T> {
private final Text name;
Expand All @@ -31,7 +31,6 @@ public final class MapOptionImpl<S, T> implements MapOption<S, T> {
private final int maximumNumberOfEntries;
private final boolean insertEntriesAtEnd;
private final ImmutableSet<OptionFlag> flags;
@SuppressWarnings("rawtypes")
private final EntryFactory entryFactory;

private final List<BiConsumer<Option<Map<S, T>>, Map<S, T>>> listeners;
Expand Down Expand Up @@ -88,7 +87,6 @@ public int minimumNumberOfEntries() {
return minimumNumberOfEntries;
}

@SuppressWarnings("unchecked")
@Override
public MapOptionEntry<S, T> insertNewEntry() {
MapOptionEntry<S, T> newEntry = entryFactory.create(initialValue.get());
Expand Down Expand Up @@ -226,7 +224,7 @@ public boolean isRoot() {
}

private List<MapOptionEntry<S, T>> createEntries(Map<S, T> values) {
return values.entrySet().stream().filter(Objects::nonNull).map(entryFactory::create).toList();
return values.entrySet().stream().filter(Objects::nonNull).map(entryFactory::create).collect(Collectors.toList());
}

void callListeners(boolean bypass) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package io.github.steveplays28.blendium.mixin.yacl;

import com.llamalad7.mixinextras.injector.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import dev.isxander.yacl3.api.ConfigCategory;
import dev.isxander.yacl3.api.ListOption;
import dev.isxander.yacl3.api.OptionGroup;
import dev.isxander.yacl3.api.utils.Dimension;
import dev.isxander.yacl3.gui.*;
import dev.isxander.yacl3.impl.utils.YACLConstants;
import io.github.steveplays28.blendium.client.compat.yacl.extension.YACLOptionListWidgetExtension;
import io.github.steveplays28.blendium.client.compat.yacl.option.MapOption;
import io.github.steveplays28.blendium.client.compat.yacl.option.MapOptionEntry;
import io.github.steveplays28.blendium.mixin.yacl.accessor.OptionListWidgetGroupSeparatorEntryAccessor;
import io.github.steveplays28.blendium.mixin.yacl.accessor.YACLOptionListWidgetAccessor;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.MultilineText;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.EntryListWidget;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.function.Consumer;

@Environment(EnvType.CLIENT)
@Mixin(value = OptionListWidget.class, remap = false)
public abstract class YACLOptionListWidgetMixin extends ElementListWidgetExt<OptionListWidget.Entry> {
public YACLOptionListWidgetMixin(MinecraftClient client, int x, int y, int width, int height, boolean smoothScrolling) {
super(client, x, y, width, height, smoothScrolling);
}

@Shadow
public abstract void addEntryBelow(OptionListWidget.Entry below, OptionListWidget.Entry entry);

@Shadow
@Final
private YACLScreen yaclScreen;

@Shadow
public abstract Dimension<Integer> getDefaultEntryDimension();

@Inject(method = "<init>", at = @At(value = "TAIL"))
private void blendium$constructorInject(YACLScreen screen, ConfigCategory category, MinecraftClient client, int x, int y, int width, int height, Consumer<DescriptionWithName> hoverEvent, CallbackInfo ci) {
for (OptionGroup group : category.groups()) {
if (group instanceof MapOption<?, ?> mapOption) {
mapOption.addRefreshListener(() -> refreshMapEntries(mapOption, category));
}
}
}

@WrapWithCondition(method = "refreshOptions", at = @At(value = "INVOKE", target = "Ldev/isxander/yacl3/gui/OptionListWidget;addEntry(Lnet/minecraft/client/gui/widget/EntryListWidget$Entry;)I"))
private boolean blendium$refreshOptionsAddMapSupport(OptionListWidget instance, EntryListWidget.Entry<?> entry, @Local OptionGroup group, @Local LocalRef<OptionListWidget.GroupSeparatorEntry> groupSeparatorEntry) {
if (group instanceof MapOption<?, ?> mapOption) {
try {
var listGroupSeparatorEntryConstructor = OptionListWidget.ListGroupSeparatorEntry.class.getDeclaredConstructors()[0];
listGroupSeparatorEntryConstructor.setAccessible(true);
var listGroupSeparatorEntry = (OptionListWidget.Entry) listGroupSeparatorEntryConstructor.newInstance(null, yaclScreen);
((YACLOptionListWidgetExtension) listGroupSeparatorEntry).blendium$setMapOption(mapOption);

addEntry(listGroupSeparatorEntry);
} catch (Exception ex) {
// TODO: Add exception logging
return false;
}
}

return true;
}

@Unique
private void refreshMapEntries(MapOption<?, ?> mapOption, ConfigCategory category) {
// Find group separator for group
OptionListWidget.ListGroupSeparatorEntry groupSeparator = super.children().stream().filter(
entry -> entry instanceof OptionListWidget.ListGroupSeparatorEntry listGroupSeparatorEntry && ((OptionListWidgetGroupSeparatorEntryAccessor) listGroupSeparatorEntry).getGroup() == mapOption).map(
OptionListWidget.ListGroupSeparatorEntry.class::cast).findAny().orElse(null);

if (groupSeparator == null) {
YACLConstants.LOGGER.warn("Can't find group separator to refresh map option entries for map option " + mapOption.name());
return;
}

var groupSeparatorChildEntries = ((OptionListWidgetGroupSeparatorEntryAccessor) groupSeparator).getChildEntries();
for (OptionListWidget.Entry entry : groupSeparatorChildEntries)
super.removeEntry(entry);
groupSeparatorChildEntries.clear();

var parentInstance = (OptionListWidget) (Object) this;

// If no entries, below loop won't run where addEntryBelow() reaches viewable children
if (mapOption.options().isEmpty()) {
OptionListWidget.EmptyListLabel emptyListLabel = parentInstance.new EmptyListLabel(groupSeparator, category);

addEntryBelow(groupSeparator, emptyListLabel);
groupSeparatorChildEntries.add(emptyListLabel);

return;
}

OptionListWidget.Entry lastEntry = groupSeparator;
for (MapOptionEntry<?, ?> mapOptionEntry : mapOption.options()) {
OptionListWidget.OptionEntry optionEntry = parentInstance.new OptionEntry(mapOptionEntry, category, mapOption, groupSeparator,
mapOptionEntry.controller().provideWidget(yaclScreen, getDefaultEntryDimension())
);

addEntryBelow(lastEntry, optionEntry);
groupSeparatorChildEntries.add(optionEntry);
lastEntry = optionEntry;
}
}

@Mixin(value = OptionListWidget.ListGroupSeparatorEntry.class, remap = false)
public abstract static class YACLOptionListWidgetListGroupSeparatorEntryMixin extends OptionListWidget.GroupSeparatorEntry implements YACLOptionListWidgetExtension {
@Mutable
@Shadow
@Final
private TextScaledButtonWidget resetListButton;

@Shadow
public abstract void setExpanded(boolean expanded);

@Shadow
protected abstract void updateExpandMinimizeText();

@Shadow
protected abstract void minimizeIfUnavailable();

@Mutable
@Shadow
@Final
private TooltipButtonWidget addListButton;

@Unique
private MapOption<?, ?> blendium$mapOption;

private YACLOptionListWidgetListGroupSeparatorEntryMixin(ListOption<?> group, Screen screen, @NotNull OptionListWidget outer) {
outer.super(group, screen);
}

@SuppressWarnings("UnnecessaryUnicodeEscape")
@Inject(method = "<init>", at = @At(value = "RETURN"))
private void blendium$constructorInject(OptionListWidget this$0, ListOption<?> group, Screen screen, CallbackInfo ci) {
this.resetListButton = new TextScaledButtonWidget(screen, this$0.getRowRight(), -20, -50, 20, 2f, Text.literal("\u21BB"),
button -> blendium$mapOption.requestSetDefault()
);
blendium$mapOption.addListener((opt, val) -> this.resetListButton.active = !opt.isPendingValueDefault() && opt.available());
this.resetListButton.active = !blendium$mapOption.isPendingValueDefault() && blendium$mapOption.available();

this.addListButton = new TooltipButtonWidget(((YACLOptionListWidgetAccessor) this$0).getYaclScreen(), resetListButton.getX() - 20,
-50, 20, 20, Text.literal("+"), Text.translatable("yacl.list.add_top"), btn -> {
blendium$mapOption.insertNewEntry();
setExpanded(true);
}
);

updateExpandMinimizeText();
minimizeIfUnavailable();
}

@Inject(method = "updateExpandMinimizeText", at = @At(value = "TAIL"))
private void blendium$updateExpandMinimizeTextInject(CallbackInfo ci) {
expandMinimizeButton.active = blendium$mapOption == null || blendium$mapOption.available();
if (addListButton != null)
addListButton.active = expandMinimizeButton.active && blendium$mapOption.numberOfEntries() < blendium$mapOption.maximumNumberOfEntries();
}

@Override
public void blendium$setMapOption(MapOption<?, ?> mapOption) {
blendium$mapOption = mapOption;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.github.steveplays28.blendium.mixin.yacl;

import dev.isxander.yacl3.api.Option;
import dev.isxander.yacl3.gui.controllers.string.StringController;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Map;

@Pseudo
@Environment(EnvType.CLIENT)
@Mixin(value = StringController.class, remap = false)
public abstract class YACLStringControllerMixin {
@Shadow
public abstract Option<String> option();

// @Inject(method = "getString", at = @At(value = "HEAD"), cancellable = true)
// private void blendium$getStringInject(@NotNull CallbackInfoReturnable<String> cir) {
// var optionValue = option().pendingValue();
//
//// if ((Object) optionValue instanceof Map.Entry<?, ?>) {
// var e = option().pendingValue();
// cir.setReturnValue(((Map.Entry<?, ?>) (Object) optionValue).getKey().toString());
//// }
// }

@Overwrite
public String getString() {
return ((Map.Entry<?, ?>) (Object) option().pendingValue()).getKey().toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.steveplays28.blendium.mixin.yacl.accessor;

import dev.isxander.yacl3.api.OptionGroup;
import dev.isxander.yacl3.gui.OptionListWidget;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

import java.util.List;

@Environment(EnvType.CLIENT)
@Mixin(value = OptionListWidget.GroupSeparatorEntry.class, remap = false)
public interface OptionListWidgetGroupSeparatorEntryAccessor {
@Accessor
OptionGroup getGroup();

@Accessor
List<OptionListWidget.Entry> getChildEntries();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.github.steveplays28.blendium.mixin.yacl.accessor;

import dev.isxander.yacl3.gui.OptionListWidget;
import dev.isxander.yacl3.gui.YACLScreen;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Environment(EnvType.CLIENT)
@Mixin(OptionListWidget.class)
public interface YACLOptionListWidgetAccessor {
@Accessor
YACLScreen getYaclScreen();
}
7 changes: 6 additions & 1 deletion src/main/resources/blendium.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
"sodium.ShaderLoaderMixin"
],
"client": [
"RenderLayersMixin"
"RenderLayersMixin",
"yacl.YACLOptionListWidgetMixin",
"yacl.YACLOptionListWidgetMixin$YACLOptionListWidgetListGroupSeparatorEntryMixin",
"yacl.YACLStringControllerMixin",
"yacl.accessor.OptionListWidgetGroupSeparatorEntryAccessor",
"yacl.accessor.YACLOptionListWidgetAccessor"
],
"injectors": {
"defaultRequire": 1
Expand Down

0 comments on commit b059917

Please sign in to comment.