1
0
forked from Clones/Controlify

Only allow handpicked bindings for radial menu (and all modded binds) with hand-picked icons for all.

This commit is contained in:
isXander
2023-07-28 23:40:33 +01:00
parent dd058d3983
commit 2048a09477
8 changed files with 75 additions and 46 deletions

View File

@ -3,12 +3,14 @@ package dev.isxander.controlify.api.bind;
import com.google.gson.JsonObject;
import dev.isxander.controlify.bindings.BindContext;
import dev.isxander.controlify.bindings.IBind;
import dev.isxander.controlify.bindings.RadialIcons;
import dev.isxander.yacl3.api.Option;
import net.minecraft.client.KeyMapping;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.Set;
import java.util.function.BooleanSupplier;
@ -70,6 +72,8 @@ public interface ControllerBinding {
void tick();
Optional<ResourceLocation> radialIcon();
record KeyMappingOverride(KeyMapping keyMapping, BooleanSupplier toggleable) {
}
}

View File

@ -1,9 +1,6 @@
package dev.isxander.controlify.api.bind;
import dev.isxander.controlify.bindings.BindContext;
import dev.isxander.controlify.bindings.ControllerBindingImpl;
import dev.isxander.controlify.bindings.GamepadBinds;
import dev.isxander.controlify.bindings.IBind;
import dev.isxander.controlify.bindings.*;
import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.controller.ControllerState;
import net.minecraft.client.KeyMapping;
@ -76,6 +73,8 @@ public interface ControllerBindingBuilder<T extends ControllerState> {
ControllerBindingBuilder<T> context(BindContext... contexts);
ControllerBindingBuilder<T> radialCandidate(ResourceLocation icon);
/**
* Specifies are vanilla override for the binding.
* Will emulate presses of the vanilla keybind when the controller binding is pressed.

View File

@ -25,10 +25,7 @@ import net.minecraft.resources.ResourceLocation;
import org.apache.commons.lang3.Validate;
import org.jetbrains.annotations.ApiStatus;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.function.BooleanSupplier;
public class ControllerBindingImpl<T extends ControllerState> implements ControllerBinding {
@ -39,13 +36,14 @@ public class ControllerBindingImpl<T extends ControllerState> implements Control
private final ResourceLocation id;
private final Component name, description, category;
private final Set<BindContext> contexts;
private final ResourceLocation radialIcon;
private final KeyMappingOverride override;
private static final Map<Controller<?, ?>, Set<IBind<?>>> pressedBinds = new HashMap<>();
private int fakePressState = 0;
private ControllerBindingImpl(Controller<T, ?> controller, IBind<T> defaultBind, ResourceLocation id, KeyMappingOverride vanillaOverride, Component name, Component description, Component category, Set<BindContext> contexts) {
private ControllerBindingImpl(Controller<T, ?> controller, IBind<T> defaultBind, ResourceLocation id, KeyMappingOverride vanillaOverride, Component name, Component description, Component category, Set<BindContext> contexts, ResourceLocation icon) {
this.controller = controller;
this.bind = this.defaultBind = defaultBind;
this.renderer = new BindRendererImpl(bind);
@ -55,6 +53,7 @@ public class ControllerBindingImpl<T extends ControllerState> implements Control
this.description = description;
this.category = category;
this.contexts = ImmutableSet.copyOf(contexts);
this.radialIcon = icon;
}
@Override
@ -118,6 +117,11 @@ public class ControllerBindingImpl<T extends ControllerState> implements Control
fakePressState = 0;
}
@Override
public Optional<ResourceLocation> radialIcon() {
return Optional.ofNullable(this.radialIcon);
}
public IBind<T> currentBind() {
return bind;
}
@ -233,6 +237,7 @@ public class ControllerBindingImpl<T extends ControllerState> implements Control
private Component name = null, description = null, category = null;
private KeyMappingOverride override = null;
private final Set<BindContext> contexts = new HashSet<>();
private ResourceLocation radialIcon = null;
public ControllerBindingBuilderImpl(Controller<T, ?> controller) {
this.controller = controller;
@ -290,6 +295,12 @@ public class ControllerBindingImpl<T extends ControllerState> implements Control
return this;
}
@Override
public ControllerBindingBuilder<T> radialCandidate(ResourceLocation icon) {
this.radialIcon = icon;
return this;
}
@Override
public ControllerBindingBuilder<T> vanillaOverride(KeyMapping keyMapping, BooleanSupplier toggleable) {
this.override = new KeyMappingOverride(keyMapping, toggleable);
@ -318,7 +329,7 @@ public class ControllerBindingImpl<T extends ControllerState> implements Control
}
}
return new ControllerBindingImpl<>(controller, bind, id, override, name, description, category, contexts);
return new ControllerBindingImpl<>(controller, bind, id, override, name, description, category, contexts, radialIcon);
}
}

View File

@ -20,6 +20,8 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.ToggleKeyMapping;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.item.Items;
import java.util.*;
import java.util.function.BooleanSupplier;
@ -140,6 +142,7 @@ public class ControllerBindings<T extends ControllerState> {
.defaultBind(GamepadBinds.A_BUTTON)
.category(MOVEMENT_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getEffect(MobEffects.JUMP))
.build());
register(SPRINT = ControllerBindingBuilder.create(controller)
.identifier("controlify", "sprint")
@ -173,12 +176,14 @@ public class ControllerBindings<T extends ControllerState> {
.defaultBind(GamepadBinds.DPAD_DOWN)
.category(GAMEPLAY_CATEGORY)
.context(BindContexts.INGAME, BindContexts.INVENTORY)
.radialCandidate(RadialIcons.getItem(Items.BARRIER))
.build());
register(DROP_STACK = ControllerBindingBuilder.create(controller)
.identifier("controlify", "drop_stack")
.defaultBind(new EmptyBind<>())
.category(GAMEPLAY_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.TNT))
.build());
register(NEXT_SLOT = ControllerBindingBuilder.create(controller)
.identifier("controlify", "next_slot")
@ -197,30 +202,35 @@ public class ControllerBindings<T extends ControllerState> {
.defaultBind(GamepadBinds.START)
.category(GAMEPLAY_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.STRUCTURE_VOID))
.build());
register(INVENTORY = ControllerBindingBuilder.create(controller)
.identifier("controlify", "inventory")
.defaultBind(GamepadBinds.Y_BUTTON)
.category(INVENTORY_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.CHEST))
.build());
register(CHANGE_PERSPECTIVE = ControllerBindingBuilder.create(controller)
.identifier("controlify", "change_perspective")
.defaultBind(GamepadBinds.BACK)
.category(GAMEPLAY_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.PAINTING))
.build());
register(SWAP_HANDS = ControllerBindingBuilder.create(controller)
.identifier("controlify", "swap_hands")
.defaultBind(GamepadBinds.X_BUTTON)
.category(INVENTORY_CATEGORY)
.context(BindContexts.INGAME, BindContexts.INVENTORY)
.radialCandidate(RadialIcons.getItem(Items.BONE))
.build());
register(OPEN_CHAT = ControllerBindingBuilder.create(controller)
.identifier("controlify", "open_chat")
.defaultBind(GamepadBinds.DPAD_UP)
.category(MISC_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.WRITABLE_BOOK))
.vanillaOverride(options.keyChat, () -> false)
.build());
register(GUI_PRESS = ControllerBindingBuilder.create(controller)
@ -282,6 +292,7 @@ public class ControllerBindings<T extends ControllerState> {
.defaultBind(GamepadBinds.DPAD_LEFT)
.category(GAMEPLAY_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.STICK))
.vanillaOverride(options.keyPickItem, () -> false)
.build());
register(TOGGLE_HUD_VISIBILITY = ControllerBindingBuilder.create(controller)
@ -289,12 +300,14 @@ public class ControllerBindings<T extends ControllerState> {
.defaultBind(new EmptyBind<>())
.category(MISC_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getEffect(MobEffects.INVISIBILITY))
.build());
register(SHOW_PLAYER_LIST = ControllerBindingBuilder.create(controller)
.identifier("controlify", "show_player_list")
.defaultBind(GamepadBinds.DPAD_RIGHT)
.category(MISC_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.PLAYER_HEAD))
.build());
register(RADIAL_MENU = ControllerBindingBuilder.create(controller)
.identifier("controlify", "radial_menu")
@ -520,6 +533,7 @@ public class ControllerBindings<T extends ControllerState> {
.name(Component.translatable(keyMapping.getName()))
.description(Component.translatable("controlify.custom_binding.vanilla_description").withStyle(ChatFormatting.GRAY))
.category(Component.translatable(keyMapping.getCategory()))
.radialCandidate(RadialIcons.FABRIC_ICON)
.vanillaOverride(keyMapping, toggleOverride)
.build();

View File

@ -1,11 +0,0 @@
package dev.isxander.controlify.bindings;
import dev.isxander.controlify.gui.screen.RadialMenuScreen;
import net.minecraft.resources.ResourceLocation;
public record RadialAction(ResourceLocation binding, ResourceLocation icon) {
public static final RadialAction EMPTY = new RadialAction(
RadialMenuScreen.EMPTY_ACTION,
RadialIcons.EMPTY
);
}

View File

@ -5,15 +5,11 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.MobEffectTextureManager;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import java.util.HashMap;
@ -23,11 +19,19 @@ public final class RadialIcons {
private static final Minecraft minecraft = Minecraft.getInstance();
public static final ResourceLocation EMPTY = new ResourceLocation("controlify", "empty");
public static final ResourceLocation FABRIC_ICON = new ResourceLocation("fabricloader", "icon");
private static final Map<ResourceLocation, Icon> icons = Util.make(() -> {
Map<ResourceLocation, Icon> map = new HashMap<>();
map.put(EMPTY, (graphics, x, y) -> {});
map.put(FABRIC_ICON, ((graphics, x, y) -> {
graphics.pose().pushPose();
graphics.pose().translate(x, y, 0);
graphics.pose().scale(0.5f, 0.5f, 1f);
graphics.blit(FABRIC_ICON, 0, 0, 0, 0, 32, 32);
graphics.pose().popPose();
}));
addItems(map);
addPotionEffects(map);
@ -38,6 +42,14 @@ public final class RadialIcons {
return icons;
}
public static ResourceLocation getItem(Item item) {
return prefixLocation("item", BuiltInRegistries.ITEM.getKey(item));
}
public static ResourceLocation getEffect(MobEffect effect) {
return prefixLocation("effect", BuiltInRegistries.MOB_EFFECT.getKey(effect));
}
private static void addItems(Map<ResourceLocation, Icon> map) {
BuiltInRegistries.ITEM.entrySet().forEach(entry -> {
ResourceKey<Item> key = entry.getKey();

View File

@ -2,7 +2,6 @@ package dev.isxander.controlify.controller;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import dev.isxander.controlify.bindings.RadialAction;
import dev.isxander.controlify.gui.screen.RadialMenuScreen;
import dev.isxander.controlify.rumble.RumbleSource;
import net.minecraft.resources.ResourceLocation;
@ -39,15 +38,15 @@ public abstract class ControllerConfig implements Serializable {
public boolean mixedInput = false;
public RadialAction[] radialActions = new RadialAction[]{
RadialAction.EMPTY,
RadialAction.EMPTY,
RadialAction.EMPTY,
RadialAction.EMPTY,
RadialAction.EMPTY,
RadialAction.EMPTY,
RadialAction.EMPTY,
RadialAction.EMPTY,
public ResourceLocation[] radialActions = new ResourceLocation[]{
RadialMenuScreen.EMPTY_ACTION,
RadialMenuScreen.EMPTY_ACTION,
RadialMenuScreen.EMPTY_ACTION,
RadialMenuScreen.EMPTY_ACTION,
RadialMenuScreen.EMPTY_ACTION,
RadialMenuScreen.EMPTY_ACTION,
RadialMenuScreen.EMPTY_ACTION,
RadialMenuScreen.EMPTY_ACTION,
};
public abstract void setDeadzone(int axis, float deadzone);

View File

@ -2,7 +2,6 @@ package dev.isxander.controlify.gui.screen;
import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.api.bind.ControllerBinding;
import dev.isxander.controlify.bindings.RadialAction;
import dev.isxander.controlify.bindings.RadialIcons;
import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.controller.gamepad.GamepadState;
@ -36,6 +35,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class RadialMenuScreen extends Screen implements ScreenControllerEventListener {
@ -188,15 +188,16 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
this.x = x;
this.y = y;
RadialAction action = controller.config().radialActions[index];
if (!EMPTY_ACTION.equals(action.binding())) {
this.binding = controller.bindings().get(action.binding());
ResourceLocation binding = controller.config().radialActions[index];
if (!EMPTY_ACTION.equals(binding)) {
this.binding = controller.bindings().get(binding);
this.icon = RadialIcons.getIcons().get(this.binding.radialIcon().orElseThrow());
this.name = MultiLineLabel.create(font, this.binding.name(), 76);
} else {
this.binding = null;
this.name = MultiLineLabel.EMPTY;
this.icon = RadialIcons.getIcons().get(RadialIcons.EMPTY);
}
this.icon = RadialIcons.getIcons().get(action.icon());
}
@Override
@ -305,11 +306,12 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
this.width = width;
this.height = height;
controller.bindings().registry().forEach((id, binding) -> {
children.add(new ActionEntry(id));
});
controller.bindings().registry().entrySet().stream()
.filter(entry -> entry.getValue().radialIcon().isPresent())
.map(Map.Entry::getKey)
.forEach(id -> children.add(new ActionEntry(id)));
var selectedBind = controller.config().radialActions[radialIndex].binding();
var selectedBind = controller.config().radialActions[radialIndex];
children.stream()
.filter(action -> action.binding.equals(selectedBind))
.findAny()
@ -447,8 +449,7 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
public boolean overrideControllerButtons(ScreenProcessor<?> screen, Controller<?, ?> controller) {
if (controller == RadialMenuScreen.this.controller) {
if (controller.bindings().GUI_PRESS.justPressed()) {
var icon = RadialIcons.getIcons().keySet().toArray(new ResourceLocation[0])[minecraft.level.random.nextInt(RadialIcons.getIcons().size())];
controller.config().radialActions[radialIndex] = new RadialAction(binding, icon);
controller.config().radialActions[radialIndex] = binding;
Controlify.instance().config().setDirty();
playClickSound();