1
0
forked from Clones/Controlify

✏️ Finishing touches on radial screen

This commit is contained in:
isXander
2023-08-06 21:56:56 +01:00
parent 0d487c780d
commit efc08f9923
8 changed files with 146 additions and 43 deletions

View File

@ -39,6 +39,7 @@ public class ControllerBindings<T extends ControllerState> {
public static final Component VMOUSE_CATEGORY = Component.translatable("controlify.binding_category.vmouse");
public static final Component GUI_CATEGORY = Component.translatable("controlify.binding_category.gui");
public static final Component MISC_CATEGORY = Component.translatable("key.categories.misc");
public static final Component RADIAL_CATEGORY = Component.translatable("controlify.gui.radial_menu");
public final ControllerBinding
WALK_FORWARD, WALK_BACKWARD, WALK_LEFT, WALK_RIGHT,
@ -61,7 +62,7 @@ public class ControllerBindings<T extends ControllerState> {
PICK_BLOCK,
TOGGLE_HUD_VISIBILITY,
SHOW_PLAYER_LIST,
RADIAL_MENU,
RADIAL_MENU, RADIAL_AXIS_UP, RADIAL_AXIS_DOWN, RADIAL_AXIS_LEFT, RADIAL_AXIS_RIGHT,
VMOUSE_MOVE_UP, VMOUSE_MOVE_DOWN, VMOUSE_MOVE_LEFT, VMOUSE_MOVE_RIGHT,
VMOUSE_LCLICK, VMOUSE_RCLICK, VMOUSE_SHIFT_CLICK,
VMOUSE_SCROLL_UP, VMOUSE_SCROLL_DOWN,
@ -222,7 +223,7 @@ public class ControllerBindings<T extends ControllerState> {
.identifier("controlify", "swap_hands")
.defaultBind(GamepadBinds.X_BUTTON)
.category(INVENTORY_CATEGORY)
.context(BindContexts.INGAME, BindContexts.INVENTORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.BONE))
.build());
register(OPEN_CHAT = ControllerBindingBuilder.create(controller)
@ -304,17 +305,41 @@ public class ControllerBindings<T extends ControllerState> {
.build());
register(SHOW_PLAYER_LIST = ControllerBindingBuilder.create(controller)
.identifier("controlify", "show_player_list")
.defaultBind(GamepadBinds.DPAD_RIGHT)
.defaultBind(new EmptyBind<>())
.category(MISC_CATEGORY)
.context(BindContexts.INGAME)
.radialCandidate(RadialIcons.getItem(Items.PLAYER_HEAD))
.build());
register(RADIAL_MENU = ControllerBindingBuilder.create(controller)
.identifier("controlify", "radial_menu")
.defaultBind(GamepadBinds.DPAD_DOWN)
.category(MISC_CATEGORY)
.defaultBind(GamepadBinds.DPAD_RIGHT)
.category(RADIAL_CATEGORY)
.context(BindContexts.INGAME)
.build());
register(RADIAL_AXIS_UP = ControllerBindingBuilder.create(controller)
.identifier("controlify", "radial_axis_up")
.defaultBind(GamepadBinds.RIGHT_STICK_FORWARD)
.category(RADIAL_CATEGORY)
.context(BindContexts.GUI)
.build());
register(RADIAL_AXIS_DOWN = ControllerBindingBuilder.create(controller)
.identifier("controlify", "radial_axis_down")
.defaultBind(GamepadBinds.RIGHT_STICK_BACKWARD)
.category(RADIAL_CATEGORY)
.context(BindContexts.GUI)
.build());
register(RADIAL_AXIS_LEFT = ControllerBindingBuilder.create(controller)
.identifier("controlify", "radial_axis_left")
.defaultBind(GamepadBinds.RIGHT_STICK_LEFT)
.category(RADIAL_CATEGORY)
.context(BindContexts.GUI)
.build());
register(RADIAL_AXIS_RIGHT = ControllerBindingBuilder.create(controller)
.identifier("controlify", "radial_axis_right")
.defaultBind(GamepadBinds.RIGHT_STICK_RIGHT)
.category(RADIAL_CATEGORY)
.context(BindContexts.GUI)
.build());
register(VMOUSE_MOVE_UP = ControllerBindingBuilder.create(controller)
.identifier("controlify", "vmouse_move_up")
.defaultBind(GamepadBinds.LEFT_STICK_FORWARD)

View File

@ -19,19 +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("fabric", "icon");
public static final ResourceLocation FABRIC_ICON = new ResourceLocation("fabric-resource-loader-v0", "icon.png");
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) -> {
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);

View File

@ -155,8 +155,8 @@ public class ControlifyConfig {
private void applyControllerConfig(Controller<?, ?> controller, JsonObject object) {
try {
controller.setConfig(GSON, object.getAsJsonObject("config"));
dirty |= !controller.bindings().fromJson(object.getAsJsonObject("bindings"));
controller.setConfig(GSON, object.getAsJsonObject("config"));
} catch (Exception e) {
Log.LOGGER.error("Failed to load controller data for " + controller.uid() + ". Resetting to default!", e);
controller.resetConfig();

View File

@ -120,6 +120,7 @@ public abstract class AbstractController<S extends ControllerState, C extends Co
this.config = SerializationUtils.clone(defaultConfig());
Controlify.instance().config().setDirty();
}
this.config.validateRadialActions(bindings);
}
@Override

View File

@ -2,6 +2,8 @@ package dev.isxander.controlify.controller;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.bindings.ControllerBindings;
import dev.isxander.controlify.gui.screen.RadialMenuScreen;
import dev.isxander.controlify.rumble.RumbleSource;
import net.minecraft.resources.ResourceLocation;
@ -39,14 +41,7 @@ public abstract class ControllerConfig implements Serializable {
public boolean mixedInput = false;
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,
null, null, null, null, null, null, null, null,
};
public abstract void setDeadzone(int axis, float deadzone);
@ -59,4 +54,33 @@ public abstract class ControllerConfig implements Serializable {
public void setRumbleStrength(RumbleSource source, float strength) {
vibrationStrengths.addProperty(source.id().toString(), strength);
}
public boolean validateRadialActions(ControllerBindings<?> bindings) {
boolean changed = false;
for (int i = 0; i < radialActions.length; i++) {
ResourceLocation action = radialActions[i];
if (!RadialMenuScreen.EMPTY_ACTION.equals(action) && (action == null || !bindings.registry().containsKey(action) || bindings.registry().get(action).radialIcon().isEmpty())) {
setDefaultRadialAction(bindings, i);
changed = true;
}
}
if (changed)
Controlify.instance().config().setDirty();
return !changed;
}
private void setDefaultRadialAction(ControllerBindings<?> bindings, int index) {
radialActions[index] = switch (index) {
case 0 -> bindings.TOGGLE_HUD_VISIBILITY.id();
case 1 -> bindings.CHANGE_PERSPECTIVE.id();
case 2 -> bindings.DROP_STACK.id();
case 3 -> bindings.OPEN_CHAT.id();
case 4 -> bindings.SWAP_HANDS.id();
case 5 -> bindings.PICK_BLOCK.id();
case 6 -> bindings.PAUSE.id();
case 7 -> bindings.SHOW_PLAYER_LIST.id();
default -> RadialMenuScreen.EMPTY_ACTION;
};
}
}

View File

@ -193,6 +193,11 @@ public class InGameButtonGuide implements IngameGuideRegistry {
return Optional.of(Component.translatable("controlify.guide.ingame.inventory"));
return Optional.empty();
});
registerGuideAction(controller.bindings().RADIAL_MENU, ActionLocation.RIGHT, ctx -> {
if (ctx.client().screen == null)
return Optional.of(Component.translatable("controlify.gui.radial_menu"));
return Optional.empty();
});
registerGuideAction(controller.bindings().ATTACK, ActionLocation.RIGHT, (ctx) -> {
var hitResult = ctx.hitResult();
if (hitResult.getType() == HitResult.Type.ENTITY)

View File

@ -1,10 +1,10 @@
package dev.isxander.controlify.gui.screen;
import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.api.bind.BindRenderer;
import dev.isxander.controlify.api.bind.ControllerBinding;
import dev.isxander.controlify.bindings.RadialIcons;
import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.controller.gamepad.GamepadState;
import dev.isxander.controlify.gui.guide.GuideAction;
import dev.isxander.controlify.gui.guide.GuideActionRenderer;
import dev.isxander.controlify.gui.layout.AnchorPoint;
@ -12,9 +12,11 @@ import dev.isxander.controlify.gui.layout.PositionedComponent;
import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.ScreenControllerEventListener;
import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
import dev.isxander.controlify.sound.ControlifySounds;
import dev.isxander.controlify.utils.Animator;
import dev.isxander.controlify.utils.Easings;
import dev.isxander.controlify.virtualmouse.VirtualMouseBehaviour;
import net.minecraft.client.gui.ComponentPath;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.MultiLineLabel;
@ -22,6 +24,7 @@ import net.minecraft.client.gui.components.Renderable;
import net.minecraft.client.gui.components.events.ContainerEventHandler;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.narration.NarratedElementType;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.gui.navigation.FocusNavigationEvent;
import net.minecraft.client.gui.navigation.ScreenRectangle;
@ -39,7 +42,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
public class RadialMenuScreen extends Screen implements ScreenControllerEventListener {
public class RadialMenuScreen extends Screen implements ScreenControllerEventListener, ScreenProcessorProvider {
public static final ResourceLocation EMPTY_ACTION = new ResourceLocation("controlify", "empty_action");
private final Controller<?, ?> controller;
@ -53,6 +56,8 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
private ActionSelectList actionSelectList;
private final Processor processor = new Processor(this);
public RadialMenuScreen(Controller<?, ?> controller, boolean editMode, Screen parent) {
super(Component.empty());
this.controller = controller;
@ -114,9 +119,13 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
onClose();
}
if (!isEditing && controller.state() instanceof GamepadState state) {
float x = state.gamepadAxes().rightStickX();
float y = state.gamepadAxes().rightStickY();
if (editMode && controller.bindings().GUI_BACK.justPressed()) {
onClose();
}
if (!isEditing) {
float x = controller.bindings().RADIAL_AXIS_RIGHT.state() - controller.bindings().RADIAL_AXIS_LEFT.state();
float y = controller.bindings().RADIAL_AXIS_DOWN.state() - controller.bindings().RADIAL_AXIS_UP.state();
float threshold = controller.config().buttonActivationThreshold;
if (Math.abs(x) >= threshold || Math.abs(y) >= threshold) {
@ -152,13 +161,19 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
if (minecraft.level == null)
if (editMode)
renderDirtBackground(graphics);
super.render(graphics, mouseX, mouseY, delta);
if (!editMode) {
graphics.drawCenteredString(font, Component.translatable("controlify.radial_menu.configure_hint"), width / 2, height - 10 - font.lineHeight, -1);
graphics.drawCenteredString(
font,
Component.translatable("controlify.radial_menu.configure_hint"),
width / 2,
height - 39,
-1
);
}
}
@ -178,6 +193,16 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
minecraft.setScreen(parent);
}
@Override
public boolean isPauseScreen() {
return editMode;
}
@Override
public ScreenProcessor<?> screenProcessor() {
return this.processor;
}
public class RadialButton implements Renderable, GuiEventListener, NarratableEntry, ComponentProcessor {
public static final ResourceLocation TEXTURE = Controlify.id("textures/gui/radial-buttons.png");
@ -199,15 +224,24 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
graphics.pose().pushPose();
graphics.pose().translate(x + translateX, y + translateY, 0);
graphics.pose().pushPose();
graphics.pose().scale(2, 2, 1);
graphics.blit(TEXTURE, 0, 0, focused ? 16 : 0, 0, 16, 16, 32, 16);
graphics.pose().popPose();
if (!editMode || !focused) {
graphics.pose().pushPose();
graphics.pose().translate(x + translateX + 4, y + translateY + 4, 0);
graphics.pose().translate(4, 4, 0);
graphics.pose().scale(1.5f, 1.5f, 1);
this.icon.draw(graphics, 0, 0);
graphics.pose().popPose();
} else {
BindRenderer renderer = controller.bindings().GUI_PRESS.renderer();
renderer.render(graphics, 16 - renderer.size().width() / 2, 16);
}
graphics.pose().popPose();
if (focused)
name.renderCentered(graphics, width / 2, height / 2 - font.lineHeight / 2 - ((name.getLineCount() - 1) * font.lineHeight / 2));
@ -263,8 +297,7 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
@Override
public boolean overrideControllerButtons(ScreenProcessor<?> screen, Controller<?, ?> controller) {
if (controller == RadialMenuScreen.this.controller) {
if (controller.bindings().GUI_PRESS.justPressed()) {
if (editMode && controller == RadialMenuScreen.this.controller && controller.bindings().GUI_PRESS.justPressed()) {
RadialButton button = buttons[selectedButton];
int x = button.x < width / 2 ? button.x - 110 : button.x + 42;
actionSelectList = new ActionSelectList(selectedButton, x, button.y, 100, 80);
@ -273,7 +306,6 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
isEditing = true;
return true;
}
}
return false;
}
@ -284,7 +316,8 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
@Override
public void updateNarration(NarrationElementOutput builder) {
if (binding != null)
builder.add(NarratedElementType.TITLE, binding.name());
}
@Override
@ -370,7 +403,7 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
@Nullable
@Override
public GuiEventListener getFocused() {
public ActionEntry getFocused() {
return focusedEntry;
}
@ -408,7 +441,9 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
@Override
public void updateNarration(NarrationElementOutput builder) {
if (getFocused() != null) {
builder.add(NarratedElementType.TITLE, getFocused().name);
}
}
public class ActionEntry implements GuiEventListener, ComponentProcessor {
@ -471,4 +506,15 @@ public class RadialMenuScreen extends Screen implements ScreenControllerEventLis
}
}
}
public static class Processor extends ScreenProcessor<RadialMenuScreen> {
public Processor(RadialMenuScreen screen) {
super(screen);
}
@Override
public VirtualMouseBehaviour virtualMouseBehaviour() {
return VirtualMouseBehaviour.DISABLED;
}
}
}

View File

@ -106,7 +106,9 @@ public class InGameInputHandler {
minecraft.options.hideGui = !minecraft.options.hideGui;
}
shouldShowPlayerList = controller.bindings().SHOW_PLAYER_LIST.held();
if (controller.bindings().SHOW_PLAYER_LIST.justPressed()) {
shouldShowPlayerList = !shouldShowPlayerList;
}
if (controller.bindings().RADIAL_MENU.justPressed()) {
minecraft.setScreen(new RadialMenuScreen(controller, false, null));