Skip to content

Commit e5b4309

Browse files
committed
✨ Deadzone for thumbsticks can now be configured separately
1 parent 9fbe7c3 commit e5b4309

File tree

13 files changed

+172
-19
lines changed

13 files changed

+172
-19
lines changed

common/src/main/java/com/mrcrayfish/controllable/Config.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public static class Options
7373
@ConfigProperty(name = "rotationSpeed", comment = "The speed which the camera turns in game")
7474
public final DoubleProperty rotationSpeed = DoubleProperty.create(50.0, 0.0, 150.0);
7575

76+
// TODO rotation curve option (linear, cubic, etc)
77+
7678
@ConfigProperty(name = "pitchSensitivity", comment = "The sensitivity of the camera's pitch rotation when applying the rotation speed. Setting to 1.0 would mean applying 100% of the rotation speed.")
7779
public final DoubleProperty pitchSensitivity = DoubleProperty.create(0.75, 0.0, 1.0);
7880

@@ -127,6 +129,8 @@ remote servers (read message below).
127129
servers (e.g Hypixel) as analog movement may be detected by anti-cheat software.""")
128130
public final EnumProperty<AnalogMovement> analogMovement = EnumProperty.create(AnalogMovement.LOCAL_ONLY);
129131

132+
// TODO movement curve option (linear, cubic, etc)
133+
130134
@ConfigProperty(name = "backgroundInput", comment = """
131135
If enabled, allows reading controller input even if the window is not in focus. This option will also
132136
prevent the game from auto pausing if the window loses focus.""")
@@ -135,6 +139,23 @@ remote servers (read message below).
135139
@ConfigProperty(name = "overlayTimeout", comment = """
136140
If enabled, after four seconds, any overlays related to the controller will be hidden if no input is detected""")
137141
public final BoolProperty overlayTimeout = BoolProperty.create(true);
142+
143+
@ConfigProperty(name = "advanced", comment = """
144+
Advanced related options. "advancedMode" option must be enabled""")
145+
public final Advanced advanced = new Advanced();
146+
147+
public static class Advanced
148+
{
149+
@ConfigProperty(name = "advancedMode", comment = """
150+
If enabled, shows more advanced options for finer tuning""")
151+
public final BoolProperty advancedMode = BoolProperty.create(true);
152+
153+
@ConfigProperty(name = "leftThumbstickDeadZone", comment = "The distance you have to move the left thumbstick before it's input is registered. This fixes drifting as some thumbsticks don't center to zero.")
154+
public final DoubleProperty leftThumbstickDeadZone = DoubleProperty.create(0.1, 0.0, 1.0);
155+
156+
@ConfigProperty(name = "rightThumbstickDeadZone", comment = "The distance you have to move the right thumbstick before it's input is registered. This fixes drifting as some thumbsticks don't center to zero.")
157+
public final DoubleProperty rightThumbstickDeadZone = DoubleProperty.create(0.1, 0.0, 1.0);
158+
}
138159
}
139160
}
140161
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.mrcrayfish.controllable.client.gui.components;
2+
3+
public interface FilteredItem
4+
{
5+
boolean isVisible();
6+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.mrcrayfish.controllable.client.gui.components;
2+
3+
import net.minecraft.client.Minecraft;
4+
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
5+
6+
import java.util.LinkedList;
7+
import java.util.List;
8+
9+
public class FilteredTabSelectionList<E extends ContainerObjectSelectionList.Entry<E>> extends TabSelectionList<E>
10+
{
11+
private final List<E> original = new LinkedList<>();
12+
13+
public FilteredTabSelectionList(Minecraft mc, int itemHeight)
14+
{
15+
super(mc, itemHeight);
16+
}
17+
18+
public void rebuildList(boolean scroll)
19+
{
20+
List<E> newEntries = this.original.stream().filter(e -> {
21+
if(e instanceof FilteredItem item) {
22+
return item.isVisible();
23+
}
24+
return true;
25+
}).toList();
26+
this.replaceEntries(newEntries);
27+
if(scroll)
28+
{
29+
this.setScrollAmount(this.maxScrollAmount());
30+
}
31+
}
32+
33+
@Override
34+
public int addEntry(E entry)
35+
{
36+
this.original.add(entry);
37+
return super.addEntry(entry);
38+
}
39+
40+
@Override
41+
protected void addEntryToTop(E entry)
42+
{
43+
this.original.addFirst(entry);
44+
super.addEntryToTop(entry);
45+
}
46+
}

common/src/main/java/com/mrcrayfish/controllable/client/gui/components/TabOptionBaseItem.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,46 @@
1818
import net.minecraft.network.chat.Component;
1919
import net.minecraft.network.chat.FormattedText;
2020
import net.minecraft.network.chat.Style;
21+
import org.jetbrains.annotations.Nullable;
2122

2223
import java.util.List;
24+
import java.util.function.Supplier;
2325

2426
/**
2527
* Author: MrCrayfish
2628
*/
27-
public abstract class TabOptionBaseItem extends TabSelectionList.BaseItem implements HideCursor
29+
public abstract class TabOptionBaseItem extends TabSelectionList.BaseItem implements HideCursor, FilteredItem
2830
{
2931
private int labelColor = 0xFFFFFFFF;
32+
protected @Nullable TabOptionBaseItem dependentOption;
33+
protected Supplier<Boolean> visibilityCondition = () -> true;
3034

3135
public TabOptionBaseItem(Component label)
3236
{
3337
super(label);
3438
}
3539

40+
public boolean isEnabled()
41+
{
42+
return true;
43+
}
44+
45+
public void setDependentOption(@Nullable TabOptionBaseItem required)
46+
{
47+
this.dependentOption = required;
48+
}
49+
50+
public void setVisibilityCondition(Supplier<Boolean> visibilityCondition)
51+
{
52+
this.visibilityCondition = visibilityCondition;
53+
}
54+
55+
@Override
56+
public boolean isVisible()
57+
{
58+
return this.visibilityCondition.get();
59+
}
60+
3661
public TabOptionBaseItem setLabel(Component label)
3762
{
3863
this.label = label;
@@ -79,7 +104,6 @@ public void updateNarration(NarrationElementOutput output)
79104
}
80105
});
81106
}
82-
83107
protected static Component createTooltipMessage(AbstractProperty<?> property)
84108
{
85109
String tooltipKey = property.getTranslationKey() + ".tooltip";

common/src/main/java/com/mrcrayfish/controllable/client/gui/components/TabOptionEnumItem.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,13 @@ public List<GuiEventListener> elements()
6969
public void render(GuiGraphics graphics, int slotIndex, int top, int left, int listWidth, int slotHeight, int mouseX, int mouseY, boolean hovered, float partialTick)
7070
{
7171
super.render(graphics, slotIndex, top, left, listWidth, slotHeight, mouseX, mouseY, hovered, partialTick);
72+
this.cycle.active = this.dependentOption == null || this.dependentOption.isEnabled();
7273
this.cycle.setX(left + listWidth - this.cycle.getWidth() - 20);
7374
this.cycle.setY(top);
7475
this.cycle.render(graphics, mouseX, mouseY, partialTick);
7576

7677
Controller controller = Controllable.getController();
77-
if(controller != null && controller.isBeingUsed() && ScreenHelper.isMouseWithin(left, top, listWidth, slotHeight, mouseX, mouseY))
78+
if(this.cycle.active && controller != null && controller.isBeingUsed() && ScreenHelper.isMouseWithin(left, top, listWidth, slotHeight, mouseX, mouseY))
7879
{
7980
ClientHelper.drawButton(graphics, left + listWidth - this.cycle.getWidth() - 20 - 17, top + (slotHeight - 11) / 2, ButtonBindings.NEXT_CREATIVE_TAB.getButton());
8081
ClientHelper.drawButton(graphics, left + listWidth - 16, top + (slotHeight - 11) / 2, ButtonBindings.PREVIOUS_CREATIVE_TAB.getButton());

common/src/main/java/com/mrcrayfish/controllable/client/gui/components/TabOptionSliderItem.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,13 @@ public List<GuiEventListener> elements()
5757
public void render(GuiGraphics graphics, int slotIndex, int top, int left, int listWidth, int slotHeight, int mouseX, int mouseY, boolean hovered, float partialTick)
5858
{
5959
super.render(graphics, slotIndex, top, left, listWidth, slotHeight, mouseX, mouseY, hovered, partialTick);
60+
this.slider.active = this.dependentOption == null || this.dependentOption.isEnabled();
6061
this.slider.setX(left + listWidth - this.slider.getWidth() - 20);
6162
this.slider.setY(top);
6263
this.slider.render(graphics, mouseX, mouseY, partialTick);
6364

6465
Controller controller = Controllable.getController();
65-
if(controller != null && controller.isBeingUsed() && ScreenHelper.isMouseWithin(left, top, listWidth, slotHeight, mouseX, mouseY))
66+
if(this.slider.active && controller != null && controller.isBeingUsed() && ScreenHelper.isMouseWithin(left, top, listWidth, slotHeight, mouseX, mouseY))
6667
{
6768
ClientHelper.drawButton(graphics, left + listWidth - this.slider.getWidth() - 20 - 17, top + (slotHeight - 11) / 2, ButtonBindings.NEXT_CREATIVE_TAB.getButton());
6869
ClientHelper.drawButton(graphics, left + listWidth - 16, top + (slotHeight - 11) / 2, ButtonBindings.PREVIOUS_CREATIVE_TAB.getButton());

common/src/main/java/com/mrcrayfish/controllable/client/gui/components/TabOptionToggleItem.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,13 @@ public List<GuiEventListener> elements()
8585
public void render(GuiGraphics graphics, int slotIndex, int top, int left, int listWidth, int slotHeight, int mouseX, int mouseY, boolean hovered, float partialTick)
8686
{
8787
super.render(graphics, slotIndex, top, left, listWidth, slotHeight, mouseX, mouseY, hovered, partialTick);
88+
this.toggle.active = this.dependentOption == null || this.dependentOption.isEnabled();
8889
this.toggle.setX(left + listWidth - this.toggle.getWidth() - 20);
8990
this.toggle.setY(top);
9091
this.toggle.render(graphics, mouseX, mouseY, partialTick);
9192

9293
Controller controller = Controllable.getController();
93-
if(controller != null && controller.isBeingUsed() && ScreenHelper.isMouseWithin(left, top, listWidth, slotHeight, mouseX, mouseY))
94+
if(this.toggle.active && controller != null && controller.isBeingUsed() && ScreenHelper.isMouseWithin(left, top, listWidth, slotHeight, mouseX, mouseY))
9495
{
9596
ClientHelper.drawButton(graphics, left + listWidth - 16, top + (slotHeight - 11) / 2, Buttons.A);
9697
}

common/src/main/java/com/mrcrayfish/controllable/client/gui/screens/SettingsScreen.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,9 @@
66
import com.mrcrayfish.controllable.client.binding.BindingRegistry;
77
import com.mrcrayfish.controllable.client.binding.ButtonBinding;
88
import com.mrcrayfish.controllable.client.gui.Icons;
9+
import com.mrcrayfish.controllable.client.gui.components.*;
910
import com.mrcrayfish.controllable.client.settings.SneakMode;
1011
import com.mrcrayfish.controllable.client.settings.SprintMode;
11-
import com.mrcrayfish.controllable.client.gui.components.ButtonBindingList;
12-
import com.mrcrayfish.controllable.client.gui.components.ControllerList;
13-
import com.mrcrayfish.controllable.client.gui.components.TabOptionEnumItem;
14-
import com.mrcrayfish.controllable.client.gui.components.TabOptionSliderItem;
15-
import com.mrcrayfish.controllable.client.gui.components.TabOptionTitleItem;
16-
import com.mrcrayfish.controllable.client.gui.components.TabOptionToggleItem;
17-
import com.mrcrayfish.controllable.client.gui.components.TabSelectionList;
1812
import com.mrcrayfish.controllable.client.gui.widget.TabListWidget;
1913
import com.mrcrayfish.controllable.client.input.AdaptiveControllerManager;
2014
import com.mrcrayfish.controllable.client.util.ClientHelper;
@@ -239,7 +233,7 @@ public SettingsTab()
239233
super(TITLE);
240234
Minecraft mc = Objects.requireNonNull(SettingsScreen.this.minecraft);
241235
GridLayout.RowHelper rootHelper = this.layout.rowSpacing(8).createRowHelper(1);
242-
TabSelectionList<TabSelectionList.BaseItem> optionsList = new TabSelectionList<>(SettingsScreen.this.minecraft, 24);
236+
FilteredTabSelectionList<TabSelectionList.BaseItem> optionsList = new FilteredTabSelectionList<>(SettingsScreen.this.minecraft, 24);
243237

244238
// Restore button
245239
// Update mappings and restore button
@@ -317,7 +311,19 @@ public SettingsTab()
317311
optionsList.addEntry(new TabOptionEnumItem<>(Config.CLIENT.options.analogMovement));
318312
optionsList.addEntry(new TabOptionToggleItem(Config.CLIENT.options.autoSelect));
319313
optionsList.addEntry(new TabOptionToggleItem(Config.CLIENT.options.backgroundInput));
320-
optionsList.addEntry(new TabOptionSliderItem(Config.CLIENT.options.thumbstickDeadZone, 0.01));
314+
315+
TabOptionSliderItem deadzoneOption = new TabOptionSliderItem(Config.CLIENT.options.thumbstickDeadZone, 0.01);
316+
deadzoneOption.setVisibilityCondition(() -> !Config.CLIENT.options.advanced.advancedMode.get());
317+
optionsList.addEntry(deadzoneOption);
318+
319+
TabOptionSliderItem leftDeadzoneOption = new TabOptionSliderItem(Config.CLIENT.options.advanced.leftThumbstickDeadZone, 0.01);
320+
leftDeadzoneOption.setVisibilityCondition(Config.CLIENT.options.advanced.advancedMode::get);
321+
optionsList.addEntry(leftDeadzoneOption);
322+
323+
TabOptionSliderItem rightDeadzoneOption = new TabOptionSliderItem(Config.CLIENT.options.advanced.rightThumbstickDeadZone, 0.01);
324+
rightDeadzoneOption.setVisibilityCondition(Config.CLIENT.options.advanced.advancedMode::get);
325+
optionsList.addEntry(rightDeadzoneOption);
326+
321327
optionsList.addEntry(new TabOptionSliderItem(Config.CLIENT.options.triggerDeadZone, 0.01));
322328
optionsList.addEntry(new TabOptionSliderItem(Config.CLIENT.options.cursorSpeed, 1.0));
323329
optionsList.addEntry(new TabOptionEnumItem<>(Config.CLIENT.options.cursorType));
@@ -331,8 +337,13 @@ public SettingsTab()
331337
optionsList.addEntry(new TabOptionTitleItem(Component.translatable("controllable.gui.title.other").withStyle(ChatFormatting.BOLD, ChatFormatting.YELLOW)));
332338
optionsList.addEntry(new TabOptionToggleItem(Config.CLIENT.options.navigateSound));
333339
optionsList.addEntry(new TabOptionToggleItem(Config.CLIENT.options.fpsPollingFix));
340+
TabOptionToggleItem advancedModeOption = new TabOptionToggleItem(Config.CLIENT.options.advanced.advancedMode);
341+
advancedModeOption.setChangeCallback(aBoolean -> optionsList.rebuildList(true));
342+
optionsList.addEntry(advancedModeOption);
334343

335344
rootHelper.addChild(new TabListWidget(() -> SettingsScreen.this.tabArea, optionsList));
345+
346+
optionsList.rebuildList(false);
336347
}
337348
}
338349

common/src/main/java/com/mrcrayfish/controllable/client/input/Controller.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.mrcrayfish.controllable.Config;
44
import com.mrcrayfish.controllable.Controllable;
55
import com.mrcrayfish.controllable.client.binding.ButtonBinding;
6+
import com.mrcrayfish.controllable.client.settings.Thumbstick;
67
import com.mrcrayfish.controllable.client.util.InputHelper;
78
import net.minecraft.Util;
89
import net.minecraft.client.Minecraft;
@@ -105,7 +106,7 @@ public final float getRTriggerValue()
105106
*/
106107
public final float getLThumbStickXValue()
107108
{
108-
return this.isAccessible() ? InputHelper.applyDeadzone(this.internalGetLThumbStickXValue(), this.getThumbstickDeadzone()) : 0;
109+
return this.isAccessible() ? InputHelper.applyDeadzone(this.internalGetLThumbStickXValue(), this.getThumbstickDeadzone(Thumbstick.LEFT)) : 0;
109110
}
110111

111112
protected abstract float internalGetLThumbStickXValue();
@@ -117,7 +118,7 @@ public final float getLThumbStickXValue()
117118
*/
118119
public final float getLThumbStickYValue()
119120
{
120-
return this.isAccessible() ? InputHelper.applyDeadzone(this.internalGetLThumbStickYValue(), this.getThumbstickDeadzone()) : 0;
121+
return this.isAccessible() ? InputHelper.applyDeadzone(this.internalGetLThumbStickYValue(), this.getThumbstickDeadzone(Thumbstick.LEFT)) : 0;
121122
}
122123

123124
protected abstract float internalGetLThumbStickYValue();
@@ -129,7 +130,7 @@ public final float getLThumbStickYValue()
129130
*/
130131
public final float getRThumbStickXValue()
131132
{
132-
return this.isAccessible() ? InputHelper.applyDeadzone(this.internalGetRThumbStickXValue(), this.getThumbstickDeadzone()) : 0;
133+
return this.isAccessible() ? InputHelper.applyDeadzone(this.internalGetRThumbStickXValue(), this.getThumbstickDeadzone(Thumbstick.RIGHT)) : 0;
133134
}
134135

135136
protected abstract float internalGetRThumbStickXValue();
@@ -141,7 +142,7 @@ public final float getRThumbStickXValue()
141142
*/
142143
public final float getRThumbStickYValue()
143144
{
144-
return this.isAccessible() ? InputHelper.applyDeadzone(this.internalGetRThumbStickYValue(), this.getThumbstickDeadzone()) : 0;
145+
return this.isAccessible() ? InputHelper.applyDeadzone(this.internalGetRThumbStickYValue(), this.getThumbstickDeadzone(Thumbstick.RIGHT)) : 0;
145146
}
146147

147148
protected abstract float internalGetRThumbStickYValue();
@@ -271,10 +272,27 @@ protected float getTriggerDeadzone()
271272
}
272273

273274
/**
274-
* @return The deadzone value for thumbsticks
275+
* @return The deadzone value for the thumbsticks
275276
*/
277+
@Deprecated
276278
protected float getThumbstickDeadzone()
277279
{
278280
return Config.CLIENT.options.thumbstickDeadZone.get().floatValue();
279281
}
282+
283+
/**
284+
* @return The deadzone value for a thumbstick
285+
*/
286+
protected float getThumbstickDeadzone(Thumbstick thumbstick)
287+
{
288+
if(Config.CLIENT.options.advanced.advancedMode.get())
289+
{
290+
return switch(thumbstick)
291+
{
292+
case LEFT -> Config.CLIENT.options.advanced.leftThumbstickDeadZone.get().floatValue();
293+
case RIGHT -> Config.CLIENT.options.advanced.rightThumbstickDeadZone.get().floatValue();
294+
};
295+
}
296+
return Config.CLIENT.options.thumbstickDeadZone.get().floatValue();
297+
}
280298
}

common/src/main/resources/assets/controllable/lang/en_gb.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@
188188
"controllable.toast.disconnected": "Disconnected",
189189
"controllable.tooltip.craft": "Click to Craft Item",
190190
"controllable.tooltip.more_recipes": "Press %s to View More",
191+
"framework_config.controllable.client.options.advanced.advancedMode": "Advanced Mode",
192+
"framework_config.controllable.client.options.advanced.advancedMode.tooltip": "If enabled, shows advanced options for finer tuning. Advanced mode must stay on for advanced options to be applied.",
193+
"framework_config.controllable.client.options.advanced.leftThumbstickDeadZone": "Left Thumbstick Dead Zone",
194+
"framework_config.controllable.client.options.advanced.leftThumbstickDeadZone.tooltip": "The distance you have to move the left thumbstick before it's input is registered. This fixes drifting as some thumbsticks don't center to zero.",
195+
"framework_config.controllable.client.options.advanced.rightThumbstickDeadZone": "Right Thumbstick Dead Zone",
196+
"framework_config.controllable.client.options.advanced.rightThumbstickDeadZone.tooltip": "The distance you have to move the right thumbstick before it's input is registered. This fixes drifting as some thumbsticks don't center to zero.",
191197
"framework_config.controllable.client.options.analogMovement": "Analog Movement",
192198
"framework_config.controllable.client.options.analogMovement.tooltip": "Allows you to control the settings of analog movement",
193199
"framework_config.controllable.client.options.autoSelect": "Auto Select",

0 commit comments

Comments
 (0)