Compare commits

..

2 Commits
1.3.0 ... 1.3.2

30 changed files with 766 additions and 295 deletions

4
.gitignore vendored
View File

@@ -1,11 +1,13 @@
# #
# LambdAurora's ignore file # LambdAurora's ignore file
# #
# v0.12 # v0.13
# JetBrains # JetBrains
.idea/ .idea/
*.iml *.iml
*.ipr
*.iws
## Intellij IDEA ## Intellij IDEA
out/ out/
## CLion ## CLion

View File

@@ -21,12 +21,14 @@ This mod adds a controller support (and an experimental touchscreen support).
- Touchscreen support (very experimental and buggy). - Touchscreen support (very experimental and buggy).
- Keyboard controls to look around. - Keyboard controls to look around.
- Toggleable on screen button indicator (like in Bedrock Edition). - Toggleable on screen button indicator (like in Bedrock Edition).
- Vertical reacharound.
- Many Bedrock Edition features: - Many Bedrock Edition features:
- Toggleable fly drifting - Toggleable fly drifting
- Front block placing (be careful with this one) - Front block placing (be careful with this one)
- New controls settings! - New controls settings!
- Many options in config to change to your liking. - Many options in config to change to your liking.
- Many controllers supported and in a simply way your own controller mappings. - Many controllers supported and in a simply way your own controller mappings.
- An easy API for developers to add their own button bindings.
## 🎮 Supported Controllers: ## 🎮 Supported Controllers:

View File

@@ -27,6 +27,20 @@ allprojects {
classifier = "sources" classifier = "sources"
from sourceSets.main.allSource from sourceSets.main.allSource
} }
publishing {
repositories {
mavenLocal()
maven {
name = "GithubPackages"
url = uri("https://maven.pkg.github.com/LambdAurora/LambdaControls")
credentials {
username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") ?: System.getenv("TOKEN")
}
}
}
}
} }
/* /*

View File

@@ -1,5 +1,6 @@
plugins { plugins {
id 'java-library' id 'java-library'
id 'maven-publish'
} }
archivesBaseName = project.archives_base_name + "-core" archivesBaseName = project.archives_base_name + "-core"
@@ -15,3 +16,17 @@ java {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
publishing {
publications {
mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven
artifact(jar) {
builtBy jar
}
artifact(sourcesJar) {
builtBy sourcesJar
}
}
}
}

View File

@@ -21,14 +21,15 @@ import java.util.Optional;
* Represents a feature. * Represents a feature.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.3.2
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsFeature implements Nameable public class LambdaControlsFeature implements Nameable
{ {
private static final List<LambdaControlsFeature> FEATURES = new ArrayList<>(); private static final List<LambdaControlsFeature> FEATURES = new ArrayList<>();
public static final LambdaControlsFeature FRONT_BLOCK_PLACING = new LambdaControlsFeature("front_block_placing", true, false);
public static final LambdaControlsFeature FAST_BLOCK_PLACING = new LambdaControlsFeature("fast_block_placing", true, true); public static final LambdaControlsFeature FAST_BLOCK_PLACING = new LambdaControlsFeature("fast_block_placing", true, true);
public static final LambdaControlsFeature FRONT_BLOCK_PLACING = new LambdaControlsFeature("front_block_placing", true, false);
public static final LambdaControlsFeature VERTICAL_REACHAROUND = new LambdaControlsFeature("vertical_reacharound", true, false);
private final String key; private final String key;
private final boolean defaultAllowed; private final boolean defaultAllowed;
@@ -155,7 +156,8 @@ public class LambdaControlsFeature implements Nameable
} }
static { static {
FEATURES.add(FRONT_BLOCK_PLACING);
FEATURES.add(FAST_BLOCK_PLACING); FEATURES.add(FAST_BLOCK_PLACING);
FEATURES.add(FRONT_BLOCK_PLACING);
FEATURES.add(VERTICAL_REACHAROUND);
} }
} }

View File

@@ -4,6 +4,7 @@ plugins {
id 'maven-publish' id 'maven-publish'
} }
version = "${project.mod_version}+${project.minecraft_version}"
archivesBaseName = project.archives_base_name + "-fabric" archivesBaseName = project.archives_base_name + "-fabric"
minecraft { minecraft {
@@ -91,4 +92,20 @@ jar {
} }
} }
// configure the maven publication
publishing {
publications {
mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven
artifact(remapJar) {
builtBy remapJar
}
artifact(sourcesJar) {
builtBy remapSourcesJar
}
}
}
}
build.dependsOn(":core:build") build.dependsOn(":core:build")
publish.dependsOn(":core:publish")

View File

@@ -23,7 +23,6 @@ import me.lambdaurora.spruceui.event.OpenScreenCallback;
import me.lambdaurora.spruceui.hud.HudManager; import me.lambdaurora.spruceui.hud.HudManager;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@@ -40,7 +39,7 @@ import org.lwjgl.glfw.GLFW;
* Represents the LambdaControls client mod. * Represents the LambdaControls client mod.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.3.0 * @version 1.3.2
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsClient extends LambdaControls implements ClientModInitializer public class LambdaControlsClient extends LambdaControls implements ClientModInitializer
@@ -59,6 +58,7 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
public static final Identifier CURSOR_TEXTURE = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/cursor.png"); public static final Identifier CURSOR_TEXTURE = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/cursor.png");
public final LambdaControlsConfig config = new LambdaControlsConfig(this); public final LambdaControlsConfig config = new LambdaControlsConfig(this);
public final LambdaInput input = new LambdaInput(this); public final LambdaInput input = new LambdaInput(this);
public final LambdaReacharound reacharound = new LambdaReacharound();
private LambdaControlsHud hud; private LambdaControlsHud hud;
private ControlsMode previousControlsMode; private ControlsMode previousControlsMode;
@@ -79,6 +79,7 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
LambdaControlsFeature.fromName(name).ifPresent(feature -> context.getTaskQueue().execute(() -> feature.setAllowed(allowed))); LambdaControlsFeature.fromName(name).ifPresent(feature -> context.getTaskQueue().execute(() -> feature.setAllowed(allowed)));
}); });
ClientTickEvents.START_CLIENT_TICK.register(this.reacharound::tick);
ClientTickEvents.END_CLIENT_TICK.register(this::onTick); ClientTickEvents.END_CLIENT_TICK.register(this::onTick);
OpenScreenCallback.EVENT.register((client, screen) -> { OpenScreenCallback.EVENT.register((client, screen) -> {

View File

@@ -44,7 +44,9 @@ public class LambdaControlsConfig
private static final boolean DEFAULT_FLY_DRIFTING = false; private static final boolean DEFAULT_FLY_DRIFTING = false;
private static final boolean DEFAULT_FLY_VERTICAL_DRIFTING = true; private static final boolean DEFAULT_FLY_VERTICAL_DRIFTING = true;
private static final boolean DEFAULT_FRONT_BLOCK_PLACING = false; private static final boolean DEFAULT_FRONT_BLOCK_PLACING = false;
private static final boolean DEFAULT_FRONT_BLOCK_OUTLINE = true; private static final boolean DEFAULT_VERTICAL_REACHAROUND = false;
private static final boolean DEFAULT_REACHAROUND_OUTLINE = true;
private static final int[] DEFAULT_REACHAROUND_OUTLINE_COLOR = new int[]{255, 255, 255, 102};
// Controller // Controller
private static final ControllerType DEFAULT_CONTROLLER_TYPE = ControllerType.DEFAULT; private static final ControllerType DEFAULT_CONTROLLER_TYPE = ControllerType.DEFAULT;
private static final double DEFAULT_DEAD_ZONE = 0.25; private static final double DEFAULT_DEAD_ZONE = 0.25;
@@ -61,8 +63,8 @@ public class LambdaControlsConfig
private ControlsMode controlsMode; private ControlsMode controlsMode;
private ControllerType controllerType; private ControllerType controllerType;
// Gameplay. // Gameplay.
private boolean shouldRenderFrontBlockOutline; private boolean shouldRenderReacharoundOutline;
private int[] frontBlockOutlineColor; private int[] reacharoundOutlineColor;
// Controller settings // Controller settings
private double deadZone; private double deadZone;
private double rotationSpeed; private double rotationSpeed;
@@ -93,9 +95,10 @@ public class LambdaControlsConfig
this.hudSide = HudSide.byId(this.config.getOrElse("hud.side", DEFAULT_HUD_SIDE.getName())).orElse(DEFAULT_HUD_SIDE); this.hudSide = HudSide.byId(this.config.getOrElse("hud.side", DEFAULT_HUD_SIDE.getName())).orElse(DEFAULT_HUD_SIDE);
// Gameplay // Gameplay
LambdaControlsFeature.FAST_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.fast_block_placing", DEFAULT_FAST_BLOCK_INTERACTION)); LambdaControlsFeature.FAST_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.fast_block_placing", DEFAULT_FAST_BLOCK_INTERACTION));
LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.front_block_placing.enabled", DEFAULT_FRONT_BLOCK_PLACING)); LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.reacharound.horizontal", DEFAULT_FRONT_BLOCK_PLACING));
this.shouldRenderFrontBlockOutline = this.config.getOrElse("gameplay.front_block_placing.outline", DEFAULT_FRONT_BLOCK_OUTLINE); LambdaControlsFeature.VERTICAL_REACHAROUND.setEnabled(this.config.getOrElse("gameplay.reacharound.vertical", DEFAULT_VERTICAL_REACHAROUND));
this.frontBlockOutlineColor = this.config.getOptional("gameplay.front_block_placing.outline_color").map(hex -> parseColor((String) hex)).orElse(new int[]{255, 255, 255, 102}); this.shouldRenderReacharoundOutline = this.config.getOrElse("gameplay.reacharound.outline", DEFAULT_REACHAROUND_OUTLINE);
this.reacharoundOutlineColor = this.config.getOptional("gameplay.reacharound.outline_color").map(hex -> parseColor((String) hex)).orElse(DEFAULT_REACHAROUND_OUTLINE_COLOR);
// Controller settings. // Controller settings.
this.controllerType = ControllerType.byId(this.config.getOrElse("controller.type", DEFAULT_CONTROLLER_TYPE.getName())).orElse(DEFAULT_CONTROLLER_TYPE); this.controllerType = ControllerType.byId(this.config.getOrElse("controller.type", DEFAULT_CONTROLLER_TYPE.getName())).orElse(DEFAULT_CONTROLLER_TYPE);
this.deadZone = this.config.getOrElse("controller.dead_zone", DEFAULT_DEAD_ZONE); this.deadZone = this.config.getOrElse("controller.dead_zone", DEFAULT_DEAD_ZONE);
@@ -133,10 +136,19 @@ public class LambdaControlsConfig
} }
}); });
// This shouldn't happen if the configuration is new. if (this.config.contains("gameplay.front_block_placing.enabled")) {
if (!this.config.contains("gameplay.front_block_placing.enabled") && this.config.contains("gameplay.front_block_placing")) { this.setFrontBlockPlacing(this.config.getOrElse("gameplay.front_block_placing.enabled", DEFAULT_FRONT_BLOCK_PLACING));
this.config.remove("gameplay.front_block_placing"); this.config.remove("gameplay.front_block_placing.enabled");
this.config.set("gameplay.front_block_placing.enabled", DEFAULT_FRONT_BLOCK_PLACING); }
if (this.config.contains("gameplay.front_block_placing.outline")) {
this.setRenderReacharoundOutline(this.config.getOrElse("gameplay.front_block_placing.outline", DEFAULT_REACHAROUND_OUTLINE));
this.config.remove("gameplay.front_block_placing.outline");
}
if (this.config.contains("gameplay.front_block_placing.outline_color")) {
this.config.getOptional("gameplay.front_block_placing.outline_color").ifPresent(color -> this.config.set("gameplay.reacharound.outline_color", color));
this.config.remove("gameplay.front_block_placing.outline_color");
} }
this.renamed("controller.controls.tab_left", "controller.controls.tab_back"); this.renamed("controller.controls.tab_left", "controller.controls.tab_back");
@@ -165,7 +177,8 @@ public class LambdaControlsConfig
this.setFlyDrifting(DEFAULT_FLY_DRIFTING); this.setFlyDrifting(DEFAULT_FLY_DRIFTING);
this.setFlyVerticalDrifting(DEFAULT_FLY_VERTICAL_DRIFTING); this.setFlyVerticalDrifting(DEFAULT_FLY_VERTICAL_DRIFTING);
this.setFrontBlockPlacing(DEFAULT_FRONT_BLOCK_PLACING); this.setFrontBlockPlacing(DEFAULT_FRONT_BLOCK_PLACING);
this.setRenderFrontBlockOutline(DEFAULT_FRONT_BLOCK_OUTLINE); this.setVerticalReacharound(DEFAULT_VERTICAL_REACHAROUND);
this.setRenderReacharoundOutline(DEFAULT_REACHAROUND_OUTLINE);
// Controller // Controller
this.setControllerType(DEFAULT_CONTROLLER_TYPE); this.setControllerType(DEFAULT_CONTROLLER_TYPE);
this.setDeadZone(DEFAULT_DEAD_ZONE); this.setDeadZone(DEFAULT_DEAD_ZONE);
@@ -352,7 +365,28 @@ public class LambdaControlsConfig
public void setFrontBlockPlacing(boolean enable) public void setFrontBlockPlacing(boolean enable)
{ {
LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(enable); LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(enable);
this.config.set("gameplay.front_block_placing.enabled", enable); this.config.set("gameplay.reacharound.horizontal", enable);
}
/**
* Returns whether vertical reacharound is enabled or not.
*
* @return True if vertical reacharound is enabled, else false.
*/
public boolean hasVerticalReacharound()
{
return LambdaControlsFeature.VERTICAL_REACHAROUND.isEnabled();
}
/**
* Sets whether vertical reacharound is enabled or not.
*
* @param enable True if vertical reacharound is enabled, else false.
*/
public void setVerticalReacharound(boolean enable)
{
LambdaControlsFeature.VERTICAL_REACHAROUND.setEnabled(enable);
this.config.set("gameplay.reacharound.vertical", enable);
} }
/** /**
@@ -360,9 +394,9 @@ public class LambdaControlsConfig
* *
* @return True if front block placing outline is enabled, else false. * @return True if front block placing outline is enabled, else false.
*/ */
public boolean shouldRenderFrontBlockOutline() public boolean shouldRenderReacharoundOutline()
{ {
return this.shouldRenderFrontBlockOutline; return this.shouldRenderReacharoundOutline;
} }
/** /**
@@ -370,9 +404,9 @@ public class LambdaControlsConfig
* *
* @param render True if front block placing outline is enabled, else false. * @param render True if front block placing outline is enabled, else false.
*/ */
public void setRenderFrontBlockOutline(boolean render) public void setRenderReacharoundOutline(boolean render)
{ {
this.config.set("gameplay.front_block_placing.outline", this.shouldRenderFrontBlockOutline = render); this.config.set("gameplay.reacharound.outline", this.shouldRenderReacharoundOutline = render);
} }
/** /**
@@ -382,9 +416,9 @@ public class LambdaControlsConfig
* *
* @return The color as a RGBA integer array. * @return The color as a RGBA integer array.
*/ */
public int[] getFrontBlockOutlineColor() public int[] getReacharoundOutlineColor()
{ {
return this.frontBlockOutlineColor; return this.reacharoundOutlineColor;
} }
/* /*

View File

@@ -9,7 +9,6 @@
package me.lambdaurora.lambdacontrols.client; package me.lambdaurora.lambdacontrols.client;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.Controller; import me.lambdaurora.lambdacontrols.client.controller.Controller;
@@ -22,10 +21,6 @@ import me.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import me.lambdaurora.lambdacontrols.client.util.MouseAccessor; import me.lambdaurora.lambdacontrols.client.util.MouseAccessor;
import me.lambdaurora.spruceui.SpruceLabelWidget; import me.lambdaurora.spruceui.SpruceLabelWidget;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FluidBlock;
import net.minecraft.block.SlabBlock;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.ParentElement; import net.minecraft.client.gui.ParentElement;
@@ -42,14 +37,8 @@ import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
import net.minecraft.client.gui.widget.EntryListWidget; import net.minecraft.client.gui.widget.EntryListWidget;
import net.minecraft.client.gui.widget.SliderWidget; import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType; import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import org.aperlambda.lambdacommon.utils.Pair; import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -72,7 +61,7 @@ import static org.lwjgl.glfw.GLFW.*;
* Represents the LambdaControls' input handler. * Represents the LambdaControls' input handler.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.3.0 * @version 1.3.2
* @since 1.0.0 * @since 1.0.0
*/ */
public class LambdaInput public class LambdaInput
@@ -81,7 +70,7 @@ public class LambdaInput
private final LambdaControlsConfig config; private final LambdaControlsConfig config;
// Cooldowns // Cooldowns
private int actionGuiCooldown = 0; private int actionGuiCooldown = 0;
private int ignoreNextA = 0; private boolean ignoreNextARelease = false;
private double targetYaw = 0.0; private double targetYaw = 0.0;
private double targetPitch = 0.0; private double targetPitch = 0.0;
private float prevXAxis = 0.F; private float prevXAxis = 0.F;
@@ -156,9 +145,6 @@ public class LambdaInput
if (allowInput) if (allowInput)
InputManager.updateBindings(client); InputManager.updateBindings(client);
if (this.ignoreNextA > 0)
this.ignoreNextA--;
if (client.currentScreen instanceof ControllerControlsScreen && InputManager.STATES.entrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) { if (client.currentScreen instanceof ControllerControlsScreen && InputManager.STATES.entrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) {
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen; ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen;
if (screen.focusedBinding != null && !screen.waiting) { if (screen.focusedBinding != null && !screen.waiting) {
@@ -321,39 +307,22 @@ public class LambdaInput
} }
} }
if (client.currentScreen instanceof HandledScreen && client.interactionManager != null && client.player != null) { if (this.handleInventory(client, button)) {
double x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth(); this.ignoreNextARelease = true;
double y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
Slot slot = ((HandledScreenAccessor) client.currentScreen).lambdacontrols_getSlotAt(x, y);
SlotActionType slotAction = SlotActionType.PICKUP;
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && slot != null) {
if (client.currentScreen instanceof CreativeInventoryScreen) {
if (((CreativeInventoryScreenAccessor) client.currentScreen).lambdacontrols_isCreativeInventorySlot(slot))
slotAction = SlotActionType.CLONE;
}
client.interactionManager.clickSlot(((HandledScreen) client.currentScreen).getScreenHandler().syncId, slot.id, GLFW.GLFW_MOUSE_BUTTON_1, slotAction, client.player);
client.player.playerScreenHandler.sendContentUpdates();
this.actionGuiCooldown = 5;
return;
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
client.player.closeHandledScreen();
return;
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_X && slot != null) {
client.interactionManager.clickSlot(((HandledScreen) client.currentScreen).getScreenHandler().syncId, slot.id, GLFW.GLFW_MOUSE_BUTTON_2, SlotActionType.PICKUP, client.player);
return;
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_Y && slot != null) {
client.interactionManager.clickSlot(((HandledScreen) client.currentScreen).getScreenHandler().syncId, slot.id, GLFW.GLFW_MOUSE_BUTTON_1, SlotActionType.QUICK_MOVE, client.player);
return; return;
} }
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
if (client.currentScreen != null) { if (client.currentScreen != null) {
if (!LambdaControlsCompat.handleMenuBack(client, client.currentScreen))
client.currentScreen.onClose(); client.currentScreen.onClose();
return; return;
} }
} }
} }
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !isScreenInteractive(client.currentScreen) && this.actionGuiCooldown == 0 && this.ignoreNextA == 0) { if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !isScreenInteractive(client.currentScreen) && this.actionGuiCooldown == 0) {
if (!this.ignoreNextARelease) {
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth(); double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight(); double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
if (action == 0) { if (action == 0) {
@@ -362,8 +331,71 @@ public class LambdaInput
client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1); client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1);
} }
this.actionGuiCooldown = 5; this.actionGuiCooldown = 5;
} else {
this.ignoreNextARelease = false;
} }
} }
}
/**
* Handles inventory interaction.
*
* @param client The client instance.
* @param button The button pressed.
* @return True if an inventory interaction was done.
*/
private boolean handleInventory(@NotNull MinecraftClient client, int button)
{
if (!(client.currentScreen instanceof HandledScreen))
return false;
if (client.interactionManager == null || client.player == null)
return false;
if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
client.player.closeHandledScreen();
return true;
}
double x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
HandledScreen screen = (HandledScreen) client.currentScreen;
HandledScreenAccessor accessor = (HandledScreenAccessor) screen;
Slot slot = ((HandledScreenAccessor) client.currentScreen).lambdacontrols_getSlotAt(x, y);
int slotId;
if (slot == null) {
if (client.player.inventory.getCursorStack().isEmpty())
return false;
slotId = accessor.lambdacontrols_isClickOutsideBounds(x, y, accessor.getX(), accessor.getY(), GLFW_MOUSE_BUTTON_1) ? -999 : -1;
} else {
slotId = slot.id;
}
SlotActionType actionType = SlotActionType.PICKUP;
int clickData = GLFW.GLFW_MOUSE_BUTTON_1;
switch (button) {
case GLFW_GAMEPAD_BUTTON_A:
if (screen instanceof CreativeInventoryScreen)
if (((CreativeInventoryScreenAccessor) screen).lambdacontrols_isCreativeInventorySlot(slot))
actionType = SlotActionType.CLONE;
if (slot != null && LambdaControlsCompat.streamCompatHandlers().anyMatch(handler -> handler.isCreativeSlot(screen, slot)))
actionType = SlotActionType.CLONE;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_X:
clickData = GLFW_MOUSE_BUTTON_2;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_Y:
actionType = SlotActionType.QUICK_MOVE;
break;
default:
return false;
}
accessor.lambdacontrols_onMouseClick(slot, slotId, clickData, actionType);
return true;
}
private void handleAxe(@NotNull MinecraftClient client, int axis, float value, float absValue, int state) private void handleAxe(@NotNull MinecraftClient client, int axis, float value, float absValue, int state)
{ {
@@ -680,71 +712,4 @@ public class LambdaInput
this.mouseSpeedY = 0.F; this.mouseSpeedY = 0.F;
} }
} }
public static Direction getMoveDirection(@Nullable BlockPos lastPos, @NotNull BlockPos newPos)
{
if (lastPos == null)
return null;
BlockPos vector = newPos.subtract(lastPos);
if (vector.getX() > 0)
return Direction.EAST;
else if (vector.getX() < 0)
return Direction.WEST;
else if (vector.getZ() > 0)
return Direction.SOUTH;
else if (vector.getZ() < 0)
return Direction.NORTH;
else if (vector.getY() > 0)
return Direction.UP;
else if (vector.getY() < 0)
return Direction.DOWN;
return null;
}
/**
* Returns a nullable block hit result if front placing is possible.
*
* @param client The client instance.
* @return A block hit result if front placing is possible.
*/
public static @Nullable BlockHitResult tryFrontPlace(@NotNull MinecraftClient client)
{
if (!LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable())
return null;
if (client.player != null && client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.MISS && client.player.isOnGround() && client.player.pitch > 35.0F) {
if (client.player.isRiding())
return null;
BlockPos playerPos = client.player.getBlockPos().down();
BlockPos targetPos = new BlockPos(client.crosshairTarget.getPos()).subtract(playerPos);
BlockPos vector = new BlockPos(MathHelper.clamp(targetPos.getX(), -1, 1), 0, MathHelper.clamp(targetPos.getZ(), -1, 1));
BlockPos blockPos = playerPos.add(vector);
Direction direction = client.player.getHorizontalFacing();
BlockState state = client.world.getBlockState(blockPos);
if (!state.isAir())
return null;
BlockState adjacentBlockState = client.world.getBlockState(blockPos.offset(direction.getOpposite()));
if (adjacentBlockState.isAir() || adjacentBlockState.getBlock() instanceof FluidBlock || (vector.getX() == 0 && vector.getZ() == 0)) {
return null;
}
return new BlockHitResult(client.crosshairTarget.getPos(), direction, blockPos, false);
}
return null;
}
public static @NotNull BlockHitResult withSideForFrontPlace(@NotNull BlockHitResult result, @Nullable ItemStack stack)
{
if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem))
return result;
return withSideForFrontPlace(result, Block.getBlockFromItem(stack.getItem()));
}
public static @NotNull BlockHitResult withSideForFrontPlace(@NotNull BlockHitResult result, @NotNull Block block)
{
if (block instanceof SlabBlock)
result = result.withSide(Direction.DOWN);
return result;
}
} }

View File

@@ -0,0 +1,164 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FluidBlock;
import net.minecraft.block.SlabBlock;
import net.minecraft.client.MinecraftClient;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RayTraceContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents the reacharound API of LambdaControls.
*
* @version 1.3.2
* @since 1.3.2
*/
public class LambdaReacharound
{
private BlockHitResult lastReacharoundResult = null;
private boolean lastReacharoundVertical = false;
public void tick(@NotNull MinecraftClient client)
{
this.lastReacharoundResult = this.tryVerticalReachAround(client);
if (this.lastReacharoundResult == null) {
this.lastReacharoundResult = this.tryFrontPlace(client);
this.lastReacharoundVertical = false;
} else this.lastReacharoundVertical = true;
}
/**
* Returns the last reach around result.
*
* @return The last reach around result.
*/
public @Nullable BlockHitResult getLastReacharoundResult()
{
return this.lastReacharoundResult;
}
/**
* Returns whether the last reach around is vertical.
*
* @return True if the reach around is vertical.
*/
public boolean isLastReacharoundVertical()
{
return this.lastReacharoundVertical;
}
/**
* Returns whether reacharound is available or not.
*
* @return True if reacharound is available, else false.
*/
public boolean isReacharoundAvailable()
{
return LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable() || LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable();
}
private float getPlayerRange(@NotNull MinecraftClient client)
{
return client.interactionManager != null ? client.interactionManager.getReachDistance() : 0.f;
}
/**
* Returns a nullable block hit result if vertical reacharound is possible.
*
* @param client The client instance.
* @return A block hit result if vertical reacharound is possible, else null.
*/
public @Nullable BlockHitResult tryVerticalReachAround(@NotNull MinecraftClient client)
{
if (!LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable())
return null;
if (client.player == null || client.world == null || client.crosshairTarget == null || client.crosshairTarget.getType() != HitResult.Type.MISS
|| !client.player.isOnGround() || client.player.pitch < 80.0F
|| client.player.isRiding())
return null;
Vec3d pos = client.player.getCameraPosVec(1.0F);
Vec3d rotationVec = client.player.getRotationVec(1.0F);
float range = getPlayerRange(client);
Vec3d rayVec = pos.add(rotationVec.x * range, rotationVec.y * range, rotationVec.z * range).add(0, 0.75, 0);
BlockHitResult result = client.world.rayTrace(new RayTraceContext(pos, rayVec, RayTraceContext.ShapeType.OUTLINE, RayTraceContext.FluidHandling.NONE, client.player));
if (result.getType() == HitResult.Type.BLOCK) {
BlockPos blockPos = result.getBlockPos().down();
BlockState state = client.world.getBlockState(blockPos);
if (client.player.getBlockPos().getY() - blockPos.getY() > 1 && (client.world.isAir(blockPos) || state.getMaterial().isReplaceable())) {
return new BlockHitResult(result.getPos(), Direction.DOWN, blockPos, false);
}
}
return null;
}
/**
* Returns a nullable block hit result if front placing is possible.
*
* @param client The client instance.
* @return A block hit result if front placing is possible.
*/
public @Nullable BlockHitResult tryFrontPlace(@NotNull MinecraftClient client)
{
if (!LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable())
return null;
if (client.player != null && client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.MISS && client.player.isOnGround() && client.player.pitch > 35.0F) {
if (client.player.isRiding())
return null;
BlockPos playerPos = client.player.getBlockPos().down();
BlockPos targetPos = new BlockPos(client.crosshairTarget.getPos()).subtract(playerPos);
BlockPos vector = new BlockPos(MathHelper.clamp(targetPos.getX(), -1, 1), 0, MathHelper.clamp(targetPos.getZ(), -1, 1));
BlockPos blockPos = playerPos.add(vector);
Direction direction = client.player.getHorizontalFacing();
BlockState state = client.world.getBlockState(blockPos);
if (!state.isAir())
return null;
BlockState adjacentBlockState = client.world.getBlockState(blockPos.offset(direction.getOpposite()));
if (adjacentBlockState.isAir() || adjacentBlockState.getBlock() instanceof FluidBlock || (vector.getX() == 0 && vector.getZ() == 0)) {
return null;
}
return new BlockHitResult(client.crosshairTarget.getPos(), direction, blockPos, false);
}
return null;
}
public static @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @Nullable ItemStack stack)
{
if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem))
return result;
return withSideForReacharound(result, Block.getBlockFromItem(stack.getItem()));
}
public static @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @NotNull Block block)
{
if (block instanceof SlabBlock)
result = result.withSide(Direction.DOWN);
return result;
}
}

View File

@@ -10,14 +10,20 @@
package me.lambdaurora.lambdacontrols.client.compat; package me.lambdaurora.lambdacontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.screen.slot.Slot;
import net.minecraft.util.hit.BlockHitResult;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Represents a compatibility handler for a mod. * Represents a compatibility handler for a mod.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.3.2
* @since 1.1.0 * @since 1.1.0
*/ */
public interface CompatHandler public interface CompatHandler
@@ -33,10 +39,58 @@ public interface CompatHandler
* Returns whether the mouse is required on the specified screen. * Returns whether the mouse is required on the specified screen.
* *
* @param screen The screen. * @param screen The screen.
* @return True if the mouse is requried on the specified screen, else false. * @return True if the mouse is required on the specified screen, else false.
*/ */
default boolean requireMouseOnScreen(Screen screen) default boolean requireMouseOnScreen(Screen screen)
{ {
return false; return false;
} }
/**
* Returns whether the current slot is a creative slot or not.
*
* @param screen The screen.
* @param slot The slot to check.
* @return True if the slot is a creative slot, else false.
*/
default boolean isCreativeSlot(@NotNull HandledScreen screen, @NotNull Slot slot)
{
return false;
}
/**
* Returns a custom translation key to make custom attack action strings on the HUD.
*
* @param client The client instance.
* @param placeResult The last place block result.
* @return Null if untouched, else a translation key.
*/
default String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult)
{
return null;
}
/**
* Returns a custom translation key to make custom use action strings on the HUD.
*
* @param client The client instance.
* @param placeResult The last place block result.
* @return Null if untouched, else a translation key.
*/
default String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult)
{
return null;
}
/**
* Handles the menu back button.
*
* @param client The client instance.
* @param screen The screen.
* @return True if the handle was fired and succeed, else false.
*/
default boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen)
{
return false;
}
} }

View File

@@ -0,0 +1,44 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.gui.screen.Screen;
import org.aperlambda.lambdacommon.utils.LambdaReflection;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
/**
* Represents HQM compatibility handler.
*
* This is bad.
*
* @author LambdAurora
* @version 1.3.2
* @since 1.3.2
*/
public class HQMCompat implements CompatHandler
{
public static final String GUI_BASE_CLASS_PATH = "hardcorequesting.client.interfaces.GuiBase";
private Optional<Class<?>> guiBaseClass;
@Override
public void handle(@NotNull LambdaControlsClient mod)
{
this.guiBaseClass = LambdaReflection.getClass(GUI_BASE_CLASS_PATH);
}
@Override
public boolean requireMouseOnScreen(Screen screen)
{
return this.guiBaseClass.map(clazz -> clazz.isInstance(screen)).orElse(false);
}
}

View File

@@ -12,18 +12,23 @@ package me.lambdaurora.lambdacontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.InputManager; import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.util.hit.BlockHitResult;
import org.aperlambda.lambdacommon.utils.LambdaReflection; import org.aperlambda.lambdacommon.utils.LambdaReflection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
/** /**
* Represents a compatibility handler. * Represents a compatibility handler.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.1.0 * @version 1.3.2
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsCompat public class LambdaControlsCompat
@@ -45,10 +50,34 @@ public class LambdaControlsCompat
mod.log("Adding REI compatiblity..."); mod.log("Adding REI compatiblity...");
HANDLERS.add(new ReiCompat()); HANDLERS.add(new ReiCompat());
} }
if (FabricLoader.getInstance().isModLoaded("hardcorequesting") && LambdaReflection.doesClassExist(HQMCompat.GUI_BASE_CLASS_PATH)) {
mod.log("Adding HQM compatibility...");
HANDLERS.add(new HQMCompat());
}
HANDLERS.forEach(handler -> handler.handle(mod)); HANDLERS.forEach(handler -> handler.handle(mod));
InputManager.loadButtonBindings(mod.config); InputManager.loadButtonBindings(mod.config);
} }
/**
* Registers a new compatibility handler.
*
* @param handler The compatibility handler to register.
*/
public static void registerCompatHandler(@NotNull CompatHandler handler)
{
HANDLERS.add(handler);
}
/**
* Streams through compatibility handlers.
*
* @return A stream of compatibility handlers.
*/
public static Stream<CompatHandler> streamCompatHandlers()
{
return HANDLERS.stream();
}
/** /**
* Returns whether the mouse is required on the specified screen. * Returns whether the mouse is required on the specified screen.
* *
@@ -60,6 +89,57 @@ public class LambdaControlsCompat
return HANDLERS.stream().anyMatch(handler -> handler.requireMouseOnScreen(screen)); return HANDLERS.stream().anyMatch(handler -> handler.requireMouseOnScreen(screen));
} }
/**
* Returns a custom translation key to make custom attack action strings on the HUD.
*
* @param client The client instance.
* @param placeResult The last place block result.
* @return Null if untouched, else a translation key.
*/
public static String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult)
{
for (CompatHandler handler : HANDLERS) {
String action = handler.getAttackActionAt(client, placeResult);
if (action != null) {
return action;
}
}
return null;
}
/**
* Returns a custom translation key to make custom use action strings on the HUD.
*
* @param client The client instance.
* @param placeResult The last place block result.
* @return Null if untouched, else a translation key.
*/
public static String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult)
{
for (CompatHandler handler : HANDLERS) {
String action = handler.getUseActionAt(client, placeResult);
if (action != null) {
return action;
}
}
return null;
}
/**
* Handles the menu back button.
*
* @param client The client instance.
* @param screen The screen.
* @return True if the handle was fired and succeed, else false.
*/
public static boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) {
for (CompatHandler handler : HANDLERS) {
if (handler.handleMenuBack(client, screen))
return true;
}
return false;
}
/** /**
* Returns whether Roughly Enough Items is present. * Returns whether Roughly Enough Items is present.
* *

View File

@@ -17,12 +17,14 @@ import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.InputHandlers; import me.lambdaurora.lambdacontrols.client.controller.InputHandlers;
import me.lambdaurora.lambdacontrols.client.controller.InputManager; import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.lambdacontrols.client.controller.PressAction; import me.lambdaurora.lambdacontrols.client.controller.PressAction;
import me.shedaniel.rei.api.REIHelper;
import me.shedaniel.rei.api.RecipeCategory; import me.shedaniel.rei.api.RecipeCategory;
import me.shedaniel.rei.gui.ContainerScreenOverlay; import me.shedaniel.rei.gui.ContainerScreenOverlay;
import me.shedaniel.rei.gui.RecipeViewingScreen; import me.shedaniel.rei.gui.RecipeViewingScreen;
import me.shedaniel.rei.gui.VillagerRecipeViewingScreen; import me.shedaniel.rei.gui.VillagerRecipeViewingScreen;
import me.shedaniel.rei.gui.widget.EntryListWidget; import me.shedaniel.rei.gui.widget.EntryListWidget;
import me.shedaniel.rei.impl.ScreenHelper; import me.shedaniel.rei.impl.ScreenHelper;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.aperlambda.lambdacommon.utils.LambdaReflection; import org.aperlambda.lambdacommon.utils.LambdaReflection;
@@ -37,13 +39,12 @@ import static org.lwjgl.glfw.GLFW.*;
* Represents a compatibility handler for REI. * Represents a compatibility handler for REI.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.3.0 * @version 1.3.2
* @since 1.2.0 * @since 1.2.0
*/ */
public class ReiCompat implements CompatHandler public class ReiCompat implements CompatHandler
{ {
private static EntryListWidget ENTRY_LIST_WIDGET; private static EntryListWidget ENTRY_LIST_WIDGET;
public static ButtonBinding TAB_BACK;
@Override @Override
public void handle(@NotNull LambdaControlsClient mod) public void handle(@NotNull LambdaControlsClient mod)
@@ -106,6 +107,17 @@ public class ReiCompat implements CompatHandler
return screen instanceof RecipeViewingScreen || screen instanceof VillagerRecipeViewingScreen; return screen instanceof RecipeViewingScreen || screen instanceof VillagerRecipeViewingScreen;
} }
@Override
public boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen)
{
if (!isViewingScreen(screen))
return false;
MinecraftClient.getInstance().openScreen(REIHelper.getInstance().getPreviousContainerScreen());
ScreenHelper.getLastOverlay().init();
return true;
}
private static EntryListWidget getEntryListWidget() private static EntryListWidget getEntryListWidget()
{ {
if (ENTRY_LIST_WIDGET == null) { if (ENTRY_LIST_WIDGET == null) {

View File

@@ -13,11 +13,12 @@ import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControlsConstants; import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
import me.lambdaurora.lambdacontrols.client.HudSide; import me.lambdaurora.lambdacontrols.client.HudSide;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaInput; import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.spruceui.hud.Hud; import me.lambdaurora.spruceui.hud.Hud;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.Window;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -31,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
* Represents the LambdaControls HUD. * Represents the LambdaControls HUD.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.3.0 * @version 1.3.2
* @since 1.0.0 * @since 1.0.0
*/ */
public class LambdaControlsHud extends Hud public class LambdaControlsHud extends Hud
@@ -51,6 +52,7 @@ public class LambdaControlsHud extends Hud
private BlockHitResult placeHitResult; private BlockHitResult placeHitResult;
private String attackAction = ""; private String attackAction = "";
private String placeAction = ""; private String placeAction = "";
private int ticksDisplayedCrosshair = 0;
public LambdaControlsHud(@NotNull LambdaControlsClient mod) public LambdaControlsHud(@NotNull LambdaControlsClient mod)
{ {
@@ -86,6 +88,19 @@ public class LambdaControlsHud extends Hud
this.renderFirstSection(matrices, this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y); this.renderFirstSection(matrices, this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y);
this.renderSecondSection(matrices, this.mod.config.getHudSide() == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y); this.renderSecondSection(matrices, this.mod.config.getHudSide() == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y);
} }
if (this.mod.reacharound.isLastReacharoundVertical()) {
// Render crosshair indicator.
Window window = this.client.getWindow();
String text = "[ ]";
float scale = Math.min(5, this.ticksDisplayedCrosshair + tickDelta) / 5F;
scale *= scale;
int opacity = ((int) (255 * scale)) << 24;
this.client.textRenderer.draw(matrices, text, window.getScaledWidth() / 2.f - this.client.textRenderer.getWidth(text) / 2.f,
window.getScaledHeight() / 2.f - 4, 0xCCCCCC | opacity);
}
} }
public void renderFirstIcons(MatrixStack matrices, int x, int y) public void renderFirstIcons(MatrixStack matrices, int x, int y)
@@ -177,7 +192,7 @@ public class LambdaControlsHud extends Hud
// Update "Use" tip status. // Update "Use" tip status.
if (this.client.crosshairTarget.getType() == HitResult.Type.MISS) { if (this.client.crosshairTarget.getType() == HitResult.Type.MISS) {
this.placeHitResult = LambdaInput.tryFrontPlace(this.client); this.placeHitResult = this.mod.reacharound.getLastReacharoundResult();
this.attackAction = ""; this.attackAction = "";
this.attackWidth = 0; this.attackWidth = 0;
} else { } else {
@@ -190,8 +205,26 @@ public class LambdaControlsHud extends Hud
this.attackWidth = this.width(attackAction); this.attackWidth = this.width(attackAction);
} }
ItemStack stack = this.client.player.getMainHandStack(); if (this.mod.reacharound.isLastReacharoundVertical()) {
if ((stack == null || stack.isEmpty()) && ((stack = this.client.player.getOffHandStack()) == null || stack.isEmpty())) { if (this.ticksDisplayedCrosshair < 5)
this.ticksDisplayedCrosshair++;
} else {
this.ticksDisplayedCrosshair = 0;
}
String customAttackAction = LambdaControlsCompat.getAttackActionAt(this.client, this.placeHitResult);
if (customAttackAction != null) {
this.attackAction = customAttackAction;
this.attackWidth = this.width(customAttackAction);
}
ItemStack stack = null;
if (this.client.player != null) {
stack = this.client.player.getMainHandStack();
if (stack == null || stack.isEmpty())
stack = this.client.player.getOffHandStack();
}
if (stack == null || stack.isEmpty()) {
placeAction = ""; placeAction = "";
} else { } else {
if (this.placeHitResult != null && stack.getItem() instanceof BlockItem) { if (this.placeHitResult != null && stack.getItem() instanceof BlockItem) {
@@ -201,6 +234,10 @@ public class LambdaControlsHud extends Hud
} }
} }
String customUseAction = LambdaControlsCompat.getUseActionAt(this.client, this.placeHitResult);
if (customUseAction != null)
placeAction = customUseAction;
this.placeAction = placeAction; this.placeAction = placeAction;
// Cache the "Use" tip width. // Cache the "Use" tip width.

View File

@@ -11,6 +11,7 @@ package me.lambdaurora.lambdacontrols.client.gui;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaInput;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@@ -24,14 +25,11 @@ import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import java.util.Comparator;
import java.util.Optional;
/** /**
* Represents the LambdaControls renderer. * Represents the LambdaControls renderer.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.3.0 * @version 1.3.2
* @since 1.2.0 * @since 1.2.0
*/ */
public class LambdaControlsRenderer public class LambdaControlsRenderer
@@ -231,7 +229,7 @@ public class LambdaControlsRenderer
public static void renderVirtualCursor(@NotNull MatrixStack matrices, @NotNull MinecraftClient client) public static void renderVirtualCursor(@NotNull MatrixStack matrices, @NotNull MinecraftClient client)
{ {
if (!LambdaControlsClient.get().config.hasVirtualMouse() || client.currentScreen == null) if (!LambdaControlsClient.get().config.hasVirtualMouse() || (client.currentScreen == null || LambdaInput.isScreenInteractive(client.currentScreen)))
return; return;
int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()); int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
@@ -240,27 +238,13 @@ public class LambdaControlsRenderer
boolean hoverSlot = false; boolean hoverSlot = false;
if (client.currentScreen instanceof HandledScreen) { if (client.currentScreen instanceof HandledScreen) {
HandledScreen inventoryScreen = (HandledScreen) client.currentScreen; HandledScreenAccessor inventoryScreen = (HandledScreenAccessor) client.currentScreen;
HandledScreenAccessor accessor = (HandledScreenAccessor) inventoryScreen; int guiLeft = inventoryScreen.getX();
int guiLeft = accessor.getX(); int guiTop = inventoryScreen.getY();
int guiTop = accessor.getY();
// Finds the closest slot in the GUI within 14 pixels. Slot slot = inventoryScreen.lambdacontrols_getSlotAt(mouseX, mouseY);
int finalMouseX = mouseX;
int finalMouseY = mouseY;
Optional<Pair<Slot, Double>> closestSlot = inventoryScreen.getScreenHandler().slots.parallelStream()
.map(slot -> {
int x = guiLeft + slot.x + 8;
int y = guiTop + slot.y + 8;
// Distance between the slot and the cursor. if (slot != null) {
double distance = Math.sqrt(Math.pow(x - finalMouseX, 2) + Math.pow(y - finalMouseY, 2));
return Pair.of(slot, distance);
}).filter(entry -> entry.value <= 9.0)
.min(Comparator.comparingDouble(p -> p.value));
if (closestSlot.isPresent()) {
Slot slot = closestSlot.get().key;
mouseX = guiLeft + slot.x; mouseX = guiLeft + slot.x;
mouseY = guiTop + slot.y; mouseY = guiTop + slot.y;
hoverSlot = true; hoverSlot = true;

View File

@@ -51,6 +51,7 @@ public class LambdaControlsSettingsScreen extends Screen
private final Option autoJumpOption; private final Option autoJumpOption;
private final Option fastBlockPlacingOption; private final Option fastBlockPlacingOption;
private final Option frontBlockPlacingOption; private final Option frontBlockPlacingOption;
private final Option verticalReacharoundOption;
private final Option flyDriftingOption; private final Option flyDriftingOption;
private final Option flyVerticalDriftingOption; private final Option flyVerticalDriftingOption;
// Controller options // Controller options
@@ -104,8 +105,10 @@ public class LambdaControlsSettingsScreen extends Screen
this.autoJumpOption = SpruceBooleanOption.fromVanilla("options.autoJump", Option.AUTO_JUMP, null, true); this.autoJumpOption = SpruceBooleanOption.fromVanilla("options.autoJump", Option.AUTO_JUMP, null, true);
this.fastBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.fast_block_placing", this.mod.config::hasFastBlockPlacing, this.fastBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.fast_block_placing", this.mod.config::hasFastBlockPlacing,
this.mod.config::setFastBlockPlacing, new TranslatableText("lambdacontrols.tooltip.fast_block_placing"), true); this.mod.config::setFastBlockPlacing, new TranslatableText("lambdacontrols.tooltip.fast_block_placing"), true);
this.frontBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.front_block_placing", this.mod.config::hasFrontBlockPlacing, this.frontBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.reacharound.horizontal", this.mod.config::hasFrontBlockPlacing,
this.mod.config::setFrontBlockPlacing, new TranslatableText("lambdacontrols.tooltip.front_block_placing"), true); this.mod.config::setFrontBlockPlacing, new TranslatableText("lambdacontrols.tooltip.reacharound.horizontal"), true);
this.verticalReacharoundOption = new SpruceBooleanOption("lambdacontrols.menu.reacharound.vertical", this.mod.config::hasVerticalReacharound,
this.mod.config::setVerticalReacharound, new TranslatableText("lambdacontrols.tooltip.reacharound.vertical"), true);
this.flyDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting", this.mod.config::hasFlyDrifting, this.flyDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting", this.mod.config::hasFlyDrifting,
this.mod.config::setFlyDrifting, new TranslatableText("lambdacontrols.tooltip.fly_drifting"), true); this.mod.config::setFlyDrifting, new TranslatableText("lambdacontrols.tooltip.fly_drifting"), true);
this.flyVerticalDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting_vertical", this.mod.config::hasFlyVerticalDrifting, this.flyVerticalDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting_vertical", this.mod.config::hasFlyVerticalDrifting,
@@ -239,8 +242,8 @@ public class LambdaControlsSettingsScreen extends Screen
this.list.addSingleOptionEntry(this.autoSwitchModeOption); this.list.addSingleOptionEntry(this.autoSwitchModeOption);
// Gameplay options // Gameplay options
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.gameplay", true, null)); this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.gameplay", true, null));
this.list.addSingleOptionEntry(this.autoJumpOption); this.list.addOptionEntry(this.autoJumpOption, this.fastBlockPlacingOption);
this.list.addOptionEntry(this.fastBlockPlacingOption, this.frontBlockPlacingOption); this.list.addOptionEntry(this.frontBlockPlacingOption, this.verticalReacharoundOption);
this.list.addSingleOptionEntry(this.flyDriftingOption); this.list.addSingleOptionEntry(this.flyDriftingOption);
this.list.addSingleOptionEntry(this.flyVerticalDriftingOption); this.list.addSingleOptionEntry(this.flyVerticalDriftingOption);
// Controller options // Controller options

View File

@@ -18,14 +18,19 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker; import org.spongepowered.asm.mixin.gen.Invoker;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Arrays;
/** /**
* Represents the mixin for the class ContainerScreen. * Represents the mixin for the class ContainerScreen.
*/ */
@@ -41,6 +46,12 @@ public abstract class HandledScreenMixin implements HandledScreenAccessor
@Invoker("getSlotAt") @Invoker("getSlotAt")
public abstract Slot lambdacontrols_getSlotAt(double posX, double posY); public abstract Slot lambdacontrols_getSlotAt(double posX, double posY);
@Invoker("isClickOutsideBounds")
public abstract boolean lambdacontrols_isClickOutsideBounds(double mouseX, double mouseY, int x, int y, int button);
@Invoker("onMouseClick")
public abstract void lambdacontrols_onMouseClick(@Nullable Slot slot, int slotId, int clickData, SlotActionType actionType);
@Inject(method = "render", at = @At("RETURN")) @Inject(method = "render", at = @At("RETURN"))
public void onRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) public void onRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci)
{ {

View File

@@ -11,9 +11,8 @@ package me.lambdaurora.lambdacontrols.client.mixin;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature; import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaInput; import me.lambdaurora.lambdacontrols.client.LambdaReacharound;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer; import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer;
import me.lambdaurora.lambdacontrols.client.util.FrontBlockPlaceResultAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerEntity;
@@ -40,7 +39,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(MinecraftClient.class) @Mixin(MinecraftClient.class)
public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAccessor public abstract class MinecraftClientMixin
{ {
@Shadow @Shadow
@Nullable @Nullable
@@ -65,18 +64,10 @@ public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAcces
@Shadow @Shadow
private int itemUseCooldown; private int itemUseCooldown;
private BlockHitResult lambdacontrols_frontBlockPlaceResult = null;
private BlockPos lambdacontrols_lastTargetPos; private BlockPos lambdacontrols_lastTargetPos;
private Vec3d lambdacontrols_lastPos; private Vec3d lambdacontrols_lastPos;
private Direction lambdacontrols_lastTargetSide; private Direction lambdacontrols_lastTargetSide;
@Override
public @Nullable BlockHitResult lambdacontrols_getFrontBlockPlaceResult()
{
return this.lambdacontrols_frontBlockPlaceResult;
}
@Inject(method = "<init>", at = @At("RETURN")) @Inject(method = "<init>", at = @At("RETURN"))
private void onInit(CallbackInfo ci) private void onInit(CallbackInfo ci)
{ {
@@ -88,7 +79,7 @@ public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAcces
{ {
if (this.player == null) if (this.player == null)
return; return;
this.lambdacontrols_frontBlockPlaceResult = LambdaInput.tryFrontPlace(((MinecraftClient) (Object) this));
if (!LambdaControlsFeature.FAST_BLOCK_PLACING.isAvailable()) if (!LambdaControlsFeature.FAST_BLOCK_PLACING.isAvailable())
return; return;
if (this.lambdacontrols_lastPos == null) if (this.lambdacontrols_lastPos == null)
@@ -131,7 +122,8 @@ public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAcces
} }
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V", shift = At.Shift.AFTER)) @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V", shift = At.Shift.AFTER))
private void renderVirtualCursor(boolean fullRender, CallbackInfo ci) { private void renderVirtualCursor(boolean fullRender, CallbackInfo ci)
{
LambdaControlsRenderer.renderVirtualCursor(new MatrixStack(), (MinecraftClient) (Object) this); LambdaControlsRenderer.renderVirtualCursor(new MatrixStack(), (MinecraftClient) (Object) this);
} }
@@ -144,15 +136,15 @@ public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAcces
@Inject(method = "doItemUse()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/hit/HitResult;getType()Lnet/minecraft/util/hit/HitResult$Type;"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true) @Inject(method = "doItemUse()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/hit/HitResult;getType()Lnet/minecraft/util/hit/HitResult$Type;"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true)
private void onItemUse(CallbackInfo ci, Hand[] hands, int handCount, int handIndex, Hand hand, ItemStack stackInHand) private void onItemUse(CallbackInfo ci, Hand[] hands, int handCount, int handIndex, Hand hand, ItemStack stackInHand)
{ {
if (!stackInHand.isEmpty() && this.player.pitch > 35.0F && LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable()) { if (!stackInHand.isEmpty() && this.player.pitch > 35.0F && LambdaControlsClient.get().reacharound.isReacharoundAvailable()) {
if (this.crosshairTarget != null && this.crosshairTarget.getType() == HitResult.Type.MISS && this.player.isOnGround()) { if (this.crosshairTarget != null && this.crosshairTarget.getType() == HitResult.Type.MISS && this.player.isOnGround()) {
if (!stackInHand.isEmpty() && stackInHand.getItem() instanceof BlockItem) { if (!stackInHand.isEmpty() && stackInHand.getItem() instanceof BlockItem) {
BlockHitResult hitResult = LambdaInput.tryFrontPlace(((MinecraftClient) (Object) this)); BlockHitResult hitResult = LambdaControlsClient.get().reacharound.getLastReacharoundResult();
if (hitResult == null) if (hitResult == null)
return; return;
hitResult = LambdaInput.withSideForFrontPlace(hitResult, stackInHand); hitResult = LambdaReacharound.withSideForReacharound(hitResult, stackInHand);
int previousStackCount = stackInHand.getCount(); int previousStackCount = stackInHand.getCount();
ActionResult result = this.interactionManager.interactBlock(this.player, this.world, hand, hitResult); ActionResult result = this.interactionManager.interactBlock(this.player, this.world, hand, hitResult);

View File

@@ -13,12 +13,16 @@ import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaControlsConfig; import me.lambdaurora.lambdacontrols.client.LambdaControlsConfig;
import me.lambdaurora.lambdacontrols.client.util.MouseAccessor; import me.lambdaurora.lambdacontrols.client.util.MouseAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse; import net.minecraft.client.Mouse;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Invoker; import org.spongepowered.asm.mixin.gen.Invoker;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/** /**
* Adds extra access to the mouse. * Adds extra access to the mouse.
@@ -26,14 +30,31 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Mouse.class) @Mixin(Mouse.class)
public abstract class MouseMixin implements MouseAccessor public abstract class MouseMixin implements MouseAccessor
{ {
@Shadow
@Final
private MinecraftClient client;
@Invoker("onCursorPos") @Invoker("onCursorPos")
public abstract void lambdacontrols_onCursorPos(long window, double x, double y); public abstract void lambdacontrols_onCursorPos(long window, double x, double y);
@Inject(method = "isCursorLocked", at = @At("HEAD"), cancellable = true)
private void isCursorLocked(CallbackInfoReturnable<Boolean> ci)
{
if (client.currentScreen == null) {
LambdaControlsConfig config = LambdaControlsClient.get().config;
if (config.getControlsMode() == ControlsMode.CONTROLLER && config.hasVirtualMouse()) {
ci.setReturnValue(true);
ci.cancel();
}
}
}
@Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true) @Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true)
private void onMouseLocked(CallbackInfo ci) private void onCursorLocked(CallbackInfo ci)
{ {
LambdaControlsConfig config = LambdaControlsClient.get().config; LambdaControlsConfig config = LambdaControlsClient.get().config;
if (config.getControlsMode() == ControlsMode.TOUCHSCREEN || config.hasVirtualMouse()) if (config.getControlsMode() == ControlsMode.TOUCHSCREEN
|| (config.getControlsMode() == ControlsMode.CONTROLLER && config.hasVirtualMouse()))
ci.cancel(); ci.cancel();
} }
} }

View File

@@ -10,8 +10,7 @@
package me.lambdaurora.lambdacontrols.client.mixin; package me.lambdaurora.lambdacontrols.client.mixin;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaInput; import me.lambdaurora.lambdacontrols.client.LambdaReacharound;
import me.lambdaurora.lambdacontrols.client.util.FrontBlockPlaceResultAccessor;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext; import net.minecraft.block.ShapeContext;
@@ -74,9 +73,9 @@ public abstract class WorldRendererMixin
Profiler profiler, Vec3d cameraPos, double x, double y, double z, Matrix4f modelMatrix, boolean bl, Frustum frustum2, boolean bl3, Profiler profiler, Vec3d cameraPos, double x, double y, double z, Matrix4f modelMatrix, boolean bl, Frustum frustum2, boolean bl3,
VertexConsumerProvider.Immediate immediate) VertexConsumerProvider.Immediate immediate)
{ {
if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS || !LambdaControlsClient.get().config.shouldRenderFrontBlockOutline()) if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS || !LambdaControlsClient.get().config.shouldRenderReacharoundOutline())
return; return;
BlockHitResult result = ((FrontBlockPlaceResultAccessor) client).lambdacontrols_getFrontBlockPlaceResult(); BlockHitResult result = LambdaControlsClient.get().reacharound.getLastReacharoundResult();
if (result == null) if (result == null)
return; return;
BlockPos blockPos = result.getBlockPos(); BlockPos blockPos = result.getBlockPos();
@@ -85,14 +84,14 @@ public abstract class WorldRendererMixin
if (stack == null || !(stack.getItem() instanceof BlockItem)) if (stack == null || !(stack.getItem() instanceof BlockItem))
return; return;
Block block = ((BlockItem) stack.getItem()).getBlock(); Block block = ((BlockItem) stack.getItem()).getBlock();
result = LambdaInput.withSideForFrontPlace(result, block); result = LambdaReacharound.withSideForReacharound(result, block);
ItemPlacementContext context = new ItemPlacementContext(new ItemUsageContext(this.client.player, Hand.MAIN_HAND, result)); ItemPlacementContext context = new ItemPlacementContext(new ItemUsageContext(this.client.player, Hand.MAIN_HAND, result));
VertexConsumer vertexConsumer = immediate.getBuffer(RenderLayer.getLines()); VertexConsumer vertexConsumer = immediate.getBuffer(RenderLayer.getLines());
BlockState placementState = block.getPlacementState(context); BlockState placementState = block.getPlacementState(context);
if (placementState == null) if (placementState == null)
return; return;
VoxelShape outlineShape = placementState.getOutlineShape(this.client.world, blockPos, ShapeContext.of(camera.getFocusedEntity())); VoxelShape outlineShape = placementState.getOutlineShape(this.client.world, blockPos, ShapeContext.of(camera.getFocusedEntity()));
int[] color = LambdaControlsClient.get().config.getFrontBlockOutlineColor(); int[] color = LambdaControlsClient.get().config.getReacharoundOutlineColor();
drawShapeOutline(matrices, vertexConsumer, outlineShape, (double) blockPos.getX() - x, (double) blockPos.getY() - y, (double) blockPos.getZ() - z, color[0] / 255.f, color[1] / 255.f, color[2] / 255.f, color[3] / 255.f); drawShapeOutline(matrices, vertexConsumer, outlineShape, (double) blockPos.getX() - x, (double) blockPos.getY() - y, (double) blockPos.getZ() - z, color[0] / 255.f, color[1] / 255.f, color[2] / 255.f, color[3] / 255.f);
} }
} }

View File

@@ -0,0 +1,22 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.ring;
/**
* Represents a key binding ring.
*
* @author LambdAurora
* @version 1.4.0
* @since 1.4.0
*/
public class KeyBindingRing
{
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.util;
import net.minecraft.util.hit.BlockHitResult;
import org.jetbrains.annotations.Nullable;
/**
* Represents an accessor of the BlockHitResult for the front block placing feature.
* <p>
* It is implemented by {@link net.minecraft.client.MinecraftClient}.
*
* @author LambdAurora
* @version 1.2.0
* @since 1.2.0
*/
public interface FrontBlockPlaceResultAccessor
{
/**
* Returns the {@link BlockHitResult} if a block can be placed with the front block placing feature.
*
* @return If possible a {@link BlockHitResult}, else a null value.
*/
@Nullable BlockHitResult lambdacontrols_getFrontBlockPlaceResult();
}

View File

@@ -10,6 +10,8 @@
package me.lambdaurora.lambdacontrols.client.util; package me.lambdaurora.lambdacontrols.client.util;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import org.jetbrains.annotations.Nullable;
/** /**
* Represents an accessor to AbstractContainerScreen. * Represents an accessor to AbstractContainerScreen.
@@ -38,4 +40,16 @@ public interface HandledScreenAccessor
* @return The slot at the specified position. * @return The slot at the specified position.
*/ */
Slot lambdacontrols_getSlotAt(double pos_x, double pos_y); Slot lambdacontrols_getSlotAt(double pos_x, double pos_y);
boolean lambdacontrols_isClickOutsideBounds(double mouseX, double mouseY, int x, int y, int button);
/**
* Handles a mouse click on the specified slot.
*
* @param slot The slot instance.
* @param slotId The slot id.
* @param clickData The click data.
* @param actionType The action type.
*/
void lambdacontrols_onMouseClick(@Nullable Slot slot, int slotId, int clickData, SlotActionType actionType);
} }

View File

@@ -82,13 +82,14 @@
"lambdacontrols.menu.fast_block_placing": "Fast Block Placing", "lambdacontrols.menu.fast_block_placing": "Fast Block Placing",
"lambdacontrols.menu.fly_drifting": "Fly Drifting", "lambdacontrols.menu.fly_drifting": "Fly Drifting",
"lambdacontrols.menu.fly_drifting_vertical": "Vertical Fly Drifting", "lambdacontrols.menu.fly_drifting_vertical": "Vertical Fly Drifting",
"lambdacontrols.menu.front_block_placing": "Front Block Placing",
"lambdacontrols.menu.hud_enable": "Enable HUD", "lambdacontrols.menu.hud_enable": "Enable HUD",
"lambdacontrols.menu.hud_side": "HUD Side", "lambdacontrols.menu.hud_side": "HUD Side",
"lambdacontrols.menu.invert_right_x_axis": "Invert Right X", "lambdacontrols.menu.invert_right_x_axis": "Invert Right X",
"lambdacontrols.menu.invert_right_y_axis": "Invert Right Y", "lambdacontrols.menu.invert_right_y_axis": "Invert Right Y",
"lambdacontrols.menu.keyboard_controls": "Keyboard Controls...", "lambdacontrols.menu.keyboard_controls": "Keyboard Controls...",
"lambdacontrols.menu.mouse_speed": "Mouse Speed", "lambdacontrols.menu.mouse_speed": "Mouse Speed",
"lambdacontrols.menu.reacharound.horizontal": "Front Block Placing",
"lambdacontrols.menu.reacharound.vertical": "Vertical Reacharound",
"lambdacontrols.menu.reload_controller_mappings": "Reload Controller Mappings", "lambdacontrols.menu.reload_controller_mappings": "Reload Controller Mappings",
"lambdacontrols.menu.rotation_speed": "Rotation Speed", "lambdacontrols.menu.rotation_speed": "Rotation Speed",
"lambdacontrols.menu.title": "LambdaControls - Settings", "lambdacontrols.menu.title": "LambdaControls - Settings",
@@ -111,12 +112,13 @@
"lambdacontrols.tooltip.fast_block_placing": "While flying in creative mode, enables fast block placing depending on your speed. §cOn some servers this might be considered as cheating.", "lambdacontrols.tooltip.fast_block_placing": "While flying in creative mode, enables fast block placing depending on your speed. §cOn some servers this might be considered as cheating.",
"lambdacontrols.tooltip.fly_drifting": "While flying, enables Vanilla drifting/inertia.", "lambdacontrols.tooltip.fly_drifting": "While flying, enables Vanilla drifting/inertia.",
"lambdacontrols.tooltip.fly_drifting_vertical": "While flying, enables Vanilla vertical drifting/intertia.", "lambdacontrols.tooltip.fly_drifting_vertical": "While flying, enables Vanilla vertical drifting/intertia.",
"lambdacontrols.tooltip.front_block_placing": "Enables front block placing, §cmight be considered cheating on some servers§r.",
"lambdacontrols.tooltip.hud_enable": "Toggles the on-screen controller button indicator.", "lambdacontrols.tooltip.hud_enable": "Toggles the on-screen controller button indicator.",
"lambdacontrols.tooltip.hud_side": "The position of the HUD.", "lambdacontrols.tooltip.hud_side": "The position of the HUD.",
"lambdacontrols.tooltip.mouse_speed": "The controller's emulated mouse speed.", "lambdacontrols.tooltip.mouse_speed": "The controller's emulated mouse speed.",
"lambdacontrols.tooltip.rotation_speed": "The camera rotation speed in controller mode.", "lambdacontrols.tooltip.reacharound.horizontal": "Enables front block placing, §cmight be considered cheating on some servers§r.",
"lambdacontrols.tooltip.reacharound.vertical": "Enables vertical reacharound, §cmight be considered cheating on some servers§r.",
"lambdacontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file.", "lambdacontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file.",
"lambdacontrols.tooltip.rotation_speed": "The camera rotation speed in controller mode.",
"lambdacontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused.", "lambdacontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused.",
"lambdacontrols.tooltip.virtual_mouse": "Enable the virtual mouse which is handful in the case of a splitscreen.", "lambdacontrols.tooltip.virtual_mouse": "Enable the virtual mouse which is handful in the case of a splitscreen.",
"lambdacontrols.virtual_mouse.skin.default_light": "Default Light", "lambdacontrols.virtual_mouse.skin.default_light": "Default Light",

View File

@@ -81,13 +81,14 @@
"lambdacontrols.menu.dead_zone": "Zone morte", "lambdacontrols.menu.dead_zone": "Zone morte",
"lambdacontrols.menu.fly_drifting": "Inertie de vol", "lambdacontrols.menu.fly_drifting": "Inertie de vol",
"lambdacontrols.menu.fly_drifting_vertical": "Inertie verticale de vol", "lambdacontrols.menu.fly_drifting_vertical": "Inertie verticale de vol",
"lambdacontrols.menu.front_block_placing": "Placement avant de bloc",
"lambdacontrols.menu.hud_enable": "Activer le HUD", "lambdacontrols.menu.hud_enable": "Activer le HUD",
"lambdacontrols.menu.hud_side": "Côté du HUD", "lambdacontrols.menu.hud_side": "Côté du HUD",
"lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)", "lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)",
"lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)", "lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)",
"lambdacontrols.menu.keyboard_controls": "Contrôles clavier...", "lambdacontrols.menu.keyboard_controls": "Contrôles clavier...",
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris", "lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
"lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc",
"lambdacontrols.menu.reacharound.vertical": "Placement vertical",
"lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes", "lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes",
"lambdacontrols.menu.rotation_speed": "Vitesse de rotation", "lambdacontrols.menu.rotation_speed": "Vitesse de rotation",
"lambdacontrols.menu.title": "LambdaControls - Paramètres", "lambdacontrols.menu.title": "LambdaControls - Paramètres",
@@ -107,14 +108,16 @@
"lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.", "lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.",
"lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.", "lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.",
"lambdacontrols.tooltip.dead_zone": "Zone morte des axes de la manette.", "lambdacontrols.tooltip.dead_zone": "Zone morte des axes de la manette.",
"lambdacontrols.tooltip.fast_block_placing": "Active le placement rapide de blocs en vol.",
"lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement Vanilla.", "lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement Vanilla.",
"lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical Vanilla.", "lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical Vanilla.",
"lambdacontrols.tooltip.front_block_placing": "Active le placement avant de blocs, §cpeut être considérer comme de la trice sur certains serveurs§r.",
"lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.", "lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.",
"lambdacontrols.tooltip.hud_side": "Change la position du HUD.", "lambdacontrols.tooltip.hud_side": "Change la position du HUD.",
"lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.", "lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.",
"lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.", "lambdacontrols.tooltip.reacharound.horizontal": "Active le placement avant de blocs, §cpeut être considérer comme de la triche sur certains serveurs§r.",
"lambdacontrols.tooltip.reacharound.vertical": "Active le placement vertical de blocs, c'est-à-dire de blocs en dessous du bloc sur lequel vous êtes placé, §cpeut être considérer comme de la triche sur certains serveurs§r.",
"lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes.", "lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes.",
"lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.",
"lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.", "lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.",
"lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.", "lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.",
"lambdacontrols.virtual_mouse.skin.default_light": "défaut clair", "lambdacontrols.virtual_mouse.skin.default_light": "défaut clair",

View File

@@ -81,13 +81,14 @@
"lambdacontrols.menu.dead_zone": "Zone morte", "lambdacontrols.menu.dead_zone": "Zone morte",
"lambdacontrols.menu.fly_drifting": "Inertie de vol", "lambdacontrols.menu.fly_drifting": "Inertie de vol",
"lambdacontrols.menu.fly_drifting_vertical": "Inertie verticale de vol", "lambdacontrols.menu.fly_drifting_vertical": "Inertie verticale de vol",
"lambdacontrols.menu.front_block_placing": "Placement avant de bloc",
"lambdacontrols.menu.hud_enable": "Activer le HUD", "lambdacontrols.menu.hud_enable": "Activer le HUD",
"lambdacontrols.menu.hud_side": "Côté du HUD", "lambdacontrols.menu.hud_side": "Côté du HUD",
"lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)", "lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)",
"lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)", "lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)",
"lambdacontrols.menu.keyboard_controls": "Contrôles clavier...", "lambdacontrols.menu.keyboard_controls": "Contrôles clavier...",
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris", "lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
"lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc",
"lambdacontrols.menu.reacharound.vertical": "Placement vertical",
"lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes", "lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes",
"lambdacontrols.menu.rotation_speed": "Vitesse de rotation", "lambdacontrols.menu.rotation_speed": "Vitesse de rotation",
"lambdacontrols.menu.title": "LambdaControls - Paramètres", "lambdacontrols.menu.title": "LambdaControls - Paramètres",
@@ -107,14 +108,16 @@
"lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.", "lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.",
"lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.", "lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.",
"lambdacontrols.tooltip.dead_zone": "Zone morte des axes de la manette.", "lambdacontrols.tooltip.dead_zone": "Zone morte des axes de la manette.",
"lambdacontrols.tooltip.fast_block_placing": "Active le placement rapide de blocs en vol.",
"lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement Vanilla.", "lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement Vanilla.",
"lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical Vanilla.", "lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical Vanilla.",
"lambdacontrols.tooltip.front_block_placing": "Active le placement avant de blocs, §cpeut être considérer comme de la trice sur certains serveurs§r.",
"lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.", "lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.",
"lambdacontrols.tooltip.hud_side": "Change la position du HUD.", "lambdacontrols.tooltip.hud_side": "Change la position du HUD.",
"lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.", "lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.",
"lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.", "lambdacontrols.tooltip.reacharound.horizontal": "Active le placement avant de blocs, §cpeut être considérer comme de la triche sur certains serveurs§r.",
"lambdacontrols.tooltip.reacharound.vertical": "Active le placement vertical de blocs, c'est-à-dire de blocs en dessous du bloc sur lequel vous êtes placé, §cpeut être considérer comme de la triche sur certains serveurs§r.",
"lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes.", "lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes.",
"lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.",
"lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.", "lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.",
"lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.", "lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.",
"lambdacontrols.virtual_mouse.skin.default_light": "défaut clair", "lambdacontrols.virtual_mouse.skin.default_light": "défaut clair",

View File

@@ -21,9 +21,11 @@ auto_switch_mode = false
drifting = false drifting = false
# Enables vertical fly drifting. # Enables vertical fly drifting.
vertical_drifting = true vertical_drifting = true
[gameplay.front_block_placing] [gameplay.reacharound]
# Enables front block placing like in Bedrock Edition. # Enables front block placing like in Bedrock Edition.
enabled = false horizontal = false
# Enables vertical reacharound.
vertical = false
# Enables front block placing outline. # Enables front block placing outline.
outline = true outline = true
# The color in a hexadecimal format of the outline. # The color in a hexadecimal format of the outline.

View File

@@ -34,21 +34,25 @@
"fabricloader": ">=0.8.0", "fabricloader": ">=0.8.0",
"fabric": "*", "fabric": "*",
"minecraft": ">=1.16", "minecraft": ">=1.16",
"spruceui": ">=1.5.1" "spruceui": ">=1.5.2"
}, },
"recommends": { "recommends": {
"modmenu": ">=1.12.2", "modmenu": ">=1.12.2"
"okzoomer": ">=4.0.0"
}, },
"suggests": { "suggests": {
"flamingo": "*", "flamingo": "*",
"roughlyenoughitems": ">=4.5.5" "roughlyenoughitems": ">=4.5.5",
"okzoomer": ">=4.0.0"
}, },
"breaks": { "breaks": {
"modmenu": "<1.12.2", "modmenu": "<1.12.2",
"optifabric": "*" "optifabric": "*"
}, },
"custom": { "custom": {
"modmenu:clientsideOnly": true "modmenu:clientsideOnly": true,
"modupdater": {
"strategy": "curseforge",
"projectID": 354231
}
} }
} }

View File

@@ -8,12 +8,12 @@ org.gradle.jvmargs=-Xmx1G
loader_version=0.8.8+build.202 loader_version=0.8.8+build.202
# Mod Properties # Mod Properties
mod_version = 1.3.0 mod_version = 1.3.2
maven_group = me.lambdaurora maven_group = me.lambdaurora.lambdacontrols
archives_base_name = lambdacontrols archives_base_name = lambdacontrols
# Dependencies # Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.14.0+build.371-1.16 fabric_version=0.14.0+build.371-1.16
spruceui_version=1.5.1 spruceui_version=1.5.2
modmenu_version=1.12.2+build.17 modmenu_version=1.12.2+build.17