forked from Clones/Controlify
compound joysticks, button guide in screens, improve API
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
package dev.isxander.controlify.mixins.feature.guide;
|
||||
package dev.isxander.controlify.mixins.feature.guide.ingame;
|
||||
|
||||
import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.InputMode;
|
@ -1,4 +1,4 @@
|
||||
package dev.isxander.controlify.mixins.feature.guide;
|
||||
package dev.isxander.controlify.mixins.feature.guide.ingame;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dev.isxander.controlify.Controlify;
|
@ -0,0 +1,86 @@
|
||||
package dev.isxander.controlify.mixins.feature.guide.screen;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.InputMode;
|
||||
import dev.isxander.controlify.api.buttonguide.ButtonRenderPosition;
|
||||
import dev.isxander.controlify.bindings.IBind;
|
||||
import dev.isxander.controlify.gui.ButtonGuideRenderer;
|
||||
import dev.isxander.controlify.screenop.ComponentProcessor;
|
||||
import dev.isxander.controlify.screenop.ComponentProcessorProvider;
|
||||
import dev.isxander.controlify.screenop.compat.vanilla.AbstractButtonComponentProcessor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.components.AbstractButton;
|
||||
import net.minecraft.network.chat.CommonComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.contents.TranslatableContents;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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 java.util.Set;
|
||||
|
||||
@Mixin(AbstractButton.class)
|
||||
public abstract class AbstractButtonMixin extends AbstractWidgetMixin implements ButtonGuideRenderer<AbstractButton> {
|
||||
@Unique private RenderData<AbstractButton> renderData = null;
|
||||
|
||||
@Inject(method = "renderString", at = @At("RETURN"))
|
||||
private void renderButtonGuide(PoseStack matrices, Font renderer, int color, CallbackInfo ci) {
|
||||
if (shouldRender()) {
|
||||
switch (renderData.position()) {
|
||||
case LEFT -> getBind().draw(matrices, getX() - getBind().drawSize().width() - 1, getY() + getHeight() / 2);
|
||||
case RIGHT -> getBind().draw(matrices, getX() + getWidth() + 1, getY() + getHeight() / 2);
|
||||
case TEXT -> {
|
||||
Font font = Minecraft.getInstance().font;
|
||||
int x;
|
||||
if (font.width(getMessage()) > getWidth()) {
|
||||
x = getX();
|
||||
} else {
|
||||
x = getX() + getWidth() / 2 - font.width(getMessage()) / 2 - getBind().drawSize().width();
|
||||
}
|
||||
|
||||
getBind().draw(matrices, x, getY() + getHeight() / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "renderString", at = @At("HEAD"))
|
||||
private void shiftXOffset(PoseStack matrices, Font renderer, int color, CallbackInfo ci) {
|
||||
matrices.pushPose();
|
||||
if (!shouldRender() || Minecraft.getInstance().font.width(getMessage()) > getWidth() || renderData.position() != ButtonRenderPosition.TEXT) return;
|
||||
matrices.translate(getBind().drawSize().width() / 2f, 0, 0);
|
||||
}
|
||||
|
||||
@Inject(method = "renderString", at = @At("RETURN"))
|
||||
private void finishShiftXOffset(PoseStack matrices, Font renderer, int color, CallbackInfo ci) {
|
||||
matrices.popPose();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int shiftDrawSize(int x) {
|
||||
if (!shouldRender() || Minecraft.getInstance().font.width(getMessage()) < getWidth() || renderData.position() != ButtonRenderPosition.TEXT) return x;
|
||||
return x + getBind().drawSize().width();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setButtonGuide(RenderData<AbstractButton> renderData) {
|
||||
this.renderData = renderData;
|
||||
}
|
||||
|
||||
private boolean shouldRender() {
|
||||
return renderData != null
|
||||
&& this.isActive()
|
||||
&& Controlify.instance().currentInputMode() == InputMode.CONTROLLER
|
||||
&& Controlify.instance().currentController().config().showScreenGuide
|
||||
&& !renderData.binding().apply(Controlify.instance().currentController().bindings()).unbound()
|
||||
&& renderData.renderPredicate().shouldDisplay((AbstractButton) (Object) this);
|
||||
}
|
||||
|
||||
private IBind<?> getBind() {
|
||||
return renderData.binding().apply(Controlify.instance().currentController().bindings()).currentBind();
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package dev.isxander.controlify.mixins.feature.guide.screen;
|
||||
|
||||
import dev.isxander.controlify.gui.DrawSize;
|
||||
import net.minecraft.client.gui.GuiComponent;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
@Mixin(AbstractWidget.class)
|
||||
public abstract class AbstractWidgetMixin extends GuiComponent {
|
||||
@Shadow public abstract int getX();
|
||||
|
||||
@Shadow public abstract int getY();
|
||||
|
||||
@Shadow public abstract int getHeight();
|
||||
|
||||
@Shadow public abstract Component getMessage();
|
||||
|
||||
@Shadow public abstract int getWidth();
|
||||
|
||||
@Shadow public abstract boolean isActive();
|
||||
|
||||
@ModifyArg(method = "renderScrollingString(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/gui/Font;II)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/components/AbstractWidget;renderScrollingString(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/gui/Font;Lnet/minecraft/network/chat/Component;IIIII)V"), index = 3)
|
||||
protected int shiftDrawSize(int x) {
|
||||
return x;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package dev.isxander.controlify.mixins.feature.guide.screen;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.InputMode;
|
||||
import dev.isxander.controlify.bindings.IBind;
|
||||
import dev.isxander.controlify.compatibility.ControlifyCompat;
|
||||
import dev.isxander.controlify.controller.Controller;
|
||||
import dev.isxander.controlify.gui.DrawSize;
|
||||
import net.minecraft.client.gui.components.TabButton;
|
||||
import net.minecraft.client.gui.components.tabs.TabNavigationBar;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.CallbackInfo;
|
||||
|
||||
@Mixin(TabNavigationBar.class)
|
||||
public class TabNavigationBarMixin {
|
||||
@Shadow @Final private ImmutableList<TabButton> tabButtons;
|
||||
|
||||
@Shadow private int width;
|
||||
|
||||
@Inject(method = "render", at = @At("RETURN"))
|
||||
private void renderControllerButtonOverlay(PoseStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) {
|
||||
if (Controlify.instance().currentInputMode() == InputMode.CONTROLLER) {
|
||||
var controller = Controlify.instance().currentController();
|
||||
if (controller.config().showScreenGuide) {
|
||||
this.renderControllerButtonOverlay(matrices, controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void renderControllerButtonOverlay(PoseStack matrices, Controller<?, ?> controller) {
|
||||
ControlifyCompat.ifBeginHudBatching();
|
||||
|
||||
TabButton firstTab = tabButtons.get(0);
|
||||
TabButton lastTab = tabButtons.get(tabButtons.size() - 1);
|
||||
|
||||
IBind<?> prevBind = controller.bindings().GUI_PREV_TAB.currentBind();
|
||||
DrawSize prevBindDrawSize = prevBind.drawSize();
|
||||
int firstButtonX = Math.max(firstTab.getX() - 2 - prevBindDrawSize.width(), firstTab.getX() / 2 - prevBindDrawSize.width() / 2);
|
||||
int firstButtonY = 12;
|
||||
prevBind.draw(matrices, firstButtonX, firstButtonY);
|
||||
|
||||
IBind<?> nextBind = controller.bindings().GUI_NEXT_TAB.currentBind();
|
||||
DrawSize nextBindDrawSize = nextBind.drawSize();
|
||||
int lastButtonEnd = lastTab.getX() + lastTab.getWidth();
|
||||
int lastButtonX = Math.min(lastTab.getX() + lastTab.getWidth() + 2, lastButtonEnd + (width - lastButtonEnd) / 2 - nextBindDrawSize.width() / 2);
|
||||
int lastButtonY = 12;
|
||||
nextBind.draw(matrices, lastButtonX, lastButtonY);
|
||||
|
||||
ControlifyCompat.ifEndHudBatching();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package dev.isxander.controlify.mixins.feature.screenop.vanilla;
|
||||
|
||||
import dev.isxander.controlify.api.buttonguide.ButtonGuidePredicate;
|
||||
import dev.isxander.controlify.api.buttonguide.ButtonRenderPosition;
|
||||
import dev.isxander.controlify.gui.ButtonGuideRenderer;
|
||||
import dev.isxander.controlify.screenop.ScreenProcessor;
|
||||
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
||||
import dev.isxander.controlify.screenop.compat.vanilla.CreateWorldScreenProcessor;
|
||||
import net.minecraft.client.gui.components.AbstractButton;
|
||||
import net.minecraft.client.gui.layouts.LayoutElement;
|
||||
import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
|
||||
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.ModifyArg;
|
||||
|
||||
@Mixin(CreateWorldScreen.class)
|
||||
public abstract class CreateWorldScreenMixin implements ScreenProcessorProvider {
|
||||
@Shadow protected abstract void onCreate();
|
||||
|
||||
@Unique private final ScreenProcessor<CreateWorldScreen> processor = new CreateWorldScreenProcessor((CreateWorldScreen) (Object) this, this::onCreate);
|
||||
|
||||
@ModifyArg(method = "init()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/layouts/GridLayout$RowHelper;addChild(Lnet/minecraft/client/gui/layouts/LayoutElement;)Lnet/minecraft/client/gui/layouts/LayoutElement;", ordinal = 1))
|
||||
private LayoutElement modifyCancelButton(LayoutElement button) {
|
||||
ButtonGuideRenderer.registerBindingForButton((AbstractButton) button, bindings -> bindings.GUI_BACK, ButtonRenderPosition.TEXT, ButtonGuidePredicate.ALWAYS);
|
||||
return button;
|
||||
}
|
||||
|
||||
@ModifyArg(method = "init()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/layouts/GridLayout$RowHelper;addChild(Lnet/minecraft/client/gui/layouts/LayoutElement;)Lnet/minecraft/client/gui/layouts/LayoutElement;", ordinal = 0))
|
||||
private LayoutElement modifyCreateButton(LayoutElement button) {
|
||||
ButtonGuideRenderer.registerBindingForButton((AbstractButton) button, bindings -> bindings.GUI_ABSTRACT_ACTION_1, ButtonRenderPosition.TEXT, ButtonGuidePredicate.ALWAYS);
|
||||
return button;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenProcessor<?> screenProcessor() {
|
||||
return processor;
|
||||
}
|
||||
}
|
@ -1,10 +1,18 @@
|
||||
package dev.isxander.controlify.mixins.feature.screenop.vanilla;
|
||||
|
||||
import dev.isxander.controlify.api.buttonguide.ButtonGuidePredicate;
|
||||
import dev.isxander.controlify.api.buttonguide.ButtonRenderPosition;
|
||||
import dev.isxander.controlify.gui.ButtonGuideRenderer;
|
||||
import dev.isxander.controlify.screenop.ScreenProcessor;
|
||||
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
||||
import dev.isxander.controlify.screenop.compat.vanilla.SelectWorldScreenProcessor;
|
||||
import net.minecraft.client.gui.components.AbstractButton;
|
||||
import net.minecraft.client.gui.components.Renderable;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
|
||||
@Mixin(SelectWorldScreen.class)
|
||||
public class SelectWorldScreenMixin implements ScreenProcessorProvider {
|
||||
@ -14,4 +22,16 @@ public class SelectWorldScreenMixin implements ScreenProcessorProvider {
|
||||
public ScreenProcessor<?> screenProcessor() {
|
||||
return controlify$processor;
|
||||
}
|
||||
|
||||
@ModifyArg(method = "init()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/worldselection/SelectWorldScreen;addRenderableWidget(Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener;", ordinal = 5))
|
||||
private <T extends GuiEventListener & Renderable> T modifyCancelButton(T button) {
|
||||
ButtonGuideRenderer.registerBindingForButton((AbstractButton) button, bindings -> bindings.GUI_BACK, ButtonRenderPosition.TEXT, ButtonGuidePredicate.ALWAYS);
|
||||
return button;
|
||||
}
|
||||
|
||||
@ModifyArg(method = "init()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/worldselection/SelectWorldScreen;addRenderableWidget(Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener;", ordinal = 1))
|
||||
private <T extends GuiEventListener & Renderable> T modifyCreateButton(T button) {
|
||||
ButtonGuideRenderer.registerBindingForButton((AbstractButton) button, bindings -> bindings.GUI_ABSTRACT_ACTION_1, ButtonRenderPosition.TEXT, ButtonGuidePredicate.ALWAYS);
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user