Compare commits

..

27 Commits
1.2.0 ... 1.5.0

Author SHA1 Message Date
LambdAurora
deccb758ea Fix compilation crash. 2020-09-01 14:30:40 +02:00
LambdAurora
b7c60f8651 🔖 LambdaControls v1.5.0: Update to Minecraft 1.16.2. 2020-09-01 14:29:06 +02:00
LambdAurora
1ee75bc4e5 Fix issues, improve REI compat and horizontal reach-around, WIP on ring. 2020-08-25 16:06:38 +02:00
LambdAurora
1f0ddab36b Fix lot of bugs and update to 1.16.2. 2020-08-19 17:58:50 +02:00
LambdAurora
8a919934e2 Merge pull request #24 from joaoh1/1.16
👽 Fix compatibility with Ok Zoomer 4.0.0 betas
2020-08-14 17:47:08 +02:00
joaoh1
0178f5e684 👽 Fix compatibility with Ok Zoomer 4.0.0 betas 2020-08-14 12:40:45 -03:00
LambdAurora
c495e2ae0c Merge pull request #22 from FlashyReese/1.16
Add es_mx localization
2020-08-03 11:23:02 +02:00
Yao Chung Hu
3ecce09775 fix: use of words 2020-08-02 18:59:59 -05:00
Yao Chung Hu
e94d2eb240 new: added es_mx localization 2020-08-02 18:54:35 -05:00
LambdAurora
7571a2aa1b Merge pull request #21 from joaoh1/1.16
🚸 Hide Ok Zoomer's extra keybinds when disabled
2020-07-31 21:40:44 +02:00
joaoh1
d09a225518 🚸 Hide Ok Zoomer's extra keybinds when disabled 2020-07-31 15:55:43 -03:00
LambdAurora
4290d79bd0 Merge pull request #18 from Hambaka/1.16
🌐 Add Simplified Chinese localization.
2020-07-20 21:09:30 +02:00
Hambaka
f9f0a7a18d 🌐 Add Simplified Chinese localization. 2020-07-21 02:49:01 +08:00
LambdAurora
f889fc6367 Fix chording problem. 2020-07-20 19:22:18 +02:00
LambdAurora
7dcbda7e57 Update CHANGELOG. 2020-07-19 00:11:43 +02:00
LambdAurora
bd065f7b5b 🔖 LambdaControls v1.4.1: Fix crash with REI. 2020-07-19 00:10:22 +02:00
LambdAurora
2785d634dc Fix jar builds. 2020-07-18 18:55:44 +02:00
LambdAurora
257f01ec19 🔖 LambdaControls v1.4.0: Analog movements, 1.16.2 compat, better API, etc. 2020-07-18 18:41:46 +02:00
LambdAurora
127c44a046 Update CHANGELOG. 2020-07-01 01:06:48 +02:00
LambdAurora
272ef6b1dd Fix bad mixin. 2020-07-01 00:59:26 +02:00
LambdAurora
155278130f Add analog movements and WIP action ring. 2020-06-30 19:19:29 +02:00
LambdAurora
3f221feb26 Add mouse4 as back in GUIs. 2020-06-30 00:28:27 +02:00
LambdAurora
7cfd8c9b77 Update mappings. 2020-06-29 17:03:04 +02:00
LambdAurora
2c53575d17 🔖 LambdaControls v1.3.2: Fix things, add vertical reacharound and internal API. 2020-06-29 16:06:15 +02:00
LambdAurora
24f7054eff 🔖 LambdaControls v1.3.1: Fix broken inventory interactions and virtual mouse bug. 2020-06-28 22:22:19 +02:00
LambdAurora
4669e446dc 🔖 LambdaControls v1.3.0: Update to Minecraft 1.16.1. 2020-06-27 19:05:20 +02:00
LambdAurora
e676a37c7f Update to 1.16. 2020-06-27 16:08:10 +02:00
80 changed files with 3250 additions and 967 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

@@ -45,3 +45,68 @@ This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAur
- Added reset settings button. - Added reset settings button.
- HUD side affects button indicators now. - HUD side affects button indicators now.
- Added support for Advancements tabs. - Added support for Advancements tabs.
### v1.1.1
## v1.2.0-1.3.0
- Improved rotation algorithm ([#11](https://github.com/LambdAurora/LambdaControls/issues/11)).
- Added virtual mouse.
- Added outline on front block placing.
- Added fast block placement ([#8](https://github.com/LambdAurora/LambdaControls/issues/8)).
- Added [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items) compatibility.
- Improved HUD.
- Added recipe book control.
- And more!
- v1.3.0 specific: Updated to Minecraft 1.16.1
### v1.3.1
- Fixed broken inventory interactions ([#13](https://github.com/LambdAurora/LambdaControls/issues/13))
- Fixed virtual mouse preventing continuous attack (thus making breaking blocks impossible).
- Added support for [ModUpdater](https://gitea.thebrokenrail.com/TheBrokenRail/ModUpdater) hopefully.
- Updated [SpruceUI](https://github.com/LambdAurora/SpruceUI) to 1.5.2.
### v1.3.2
- Added vertical reacharound.
- Added more API for compatibility handlers.
- Improved reacharound API.
- Improved [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items) compatibility.
## v1.4.0
- Added analog movements ([#10](https://github.com/LambdAurora/LambdaControls/issues/10)).
- Improved Ok Zoomer compability.
- Updated [SpruceUI](https://github.com/LambdAurora/SpruceUI) to 1.5.8 to ensure 1.16.2 compability.
- Internal changes:
- Added analog input value to button bindings.
- Replace lot of strings with Texts.
- Improved block outline rendering injection.
- Shadow library jars instead of Jar-in-Jar.
- Fixed crash in inventory ([#16](https://github.com/LambdAurora/LambdaControls/issues/16))
- WIP:
- Started to work on action ring.
- Will allow for better compability with other mods.
- Might be interesting for keyboard users too.
### v1.4.1
- Fixed crash with [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items).
## v1.5.0
- Added mappings string editor screen.
- Added Simplified Chinese translations ([#18](https://github.com/LambdAurora/LambdaControls/pull/18)).
- Added Mexican Spanish translations ([#22](https://github.com/LambdAurora/LambdaControls/pull/22)).
- Added Xbox 360 button skin and overhauled Xbox button skin.
- Added debug option.
- Respect toggle setting in Accessibility screen.
- Tweaked rotation speeds.
- Updated to Minecraft 1.16.2.
- Updated [SpruceUI](https://github.com/LambdAurora/SpruceUI) to 1.6.4.
- Overhauled REI compatibility.
- Improved horizontal reach-around.
- Fixed crashes with Ok Zoomer.
- Fixed crashes with key unbinding.
- More WIP on keybind ring.

View File

@@ -7,13 +7,15 @@
![Version](https://img.shields.io/github/v/tag/LambdAurora/LambdaControls?label=version&style=flat-square) ![Version](https://img.shields.io/github/v/tag/LambdAurora/LambdaControls?label=version&style=flat-square)
[![CurseForge](http://cf.way2muchnoise.eu/title/354231.svg)](https://www.curseforge.com/minecraft/mc-mods/lambdacontrols) [![CurseForge](http://cf.way2muchnoise.eu/title/354231.svg)](https://www.curseforge.com/minecraft/mc-mods/lambdacontrols)
A Fabric Minecraft mod which adds better controls like controller support. A Fabric Minecraft mod which adds better controls, reach-around and controller support.
## What's this mod? ## What's this mod?
This mod adds better controls, reach-around features, etc.
Haven't you dreamed to travel in your modded Minecraft world with your controller? Yes? Then this mod is made for you! Haven't you dreamed to travel in your modded Minecraft world with your controller? Yes? Then this mod is made for you!
This mod adds a controller support (and an experimental touchscreen support). This mod also adds controller support.
## ✅ Features: ## ✅ Features:
@@ -21,12 +23,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 reach-around.
- 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:
@@ -38,4 +42,4 @@ This mod adds a controller support (and an experimental touchscreen support).
## Build ## Build
Just do `./gradlew :fabric:build` and everything should build just fine! Just do `./gradlew :fabric:shadowRemapJar` and everything should build just fine!

View File

@@ -20,12 +20,18 @@ allprojects {
options.encoding = "UTF-8" options.encoding = "UTF-8"
} }
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task publishing {
// if it is present. repositories {
// If you remove this task, sources will not be generated. mavenLocal()
task sourcesJar(type: Jar, dependsOn: classes) { maven {
classifier = "sources" name = "GithubPackages"
from sourceSets.main.allSource 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,17 +1,32 @@
plugins { plugins {
id 'java-library' id 'java-library'
id 'maven-publish'
} }
archivesBaseName = project.archives_base_name + "-core" archivesBaseName = project.archives_base_name + "-core"
dependencies { dependencies {
api "org.jetbrains:annotations:17.0.0" api "org.jetbrains:annotations:17.0.0"
api "org.aperlambda:lambdajcommon:1.8.0" api "org.aperlambda:lambdajcommon:1.8.1"
api "com.electronwill.night-config:core:3.5.3"
api "com.electronwill.night-config:toml:3.5.3"
} }
java { java {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
withSourcesJar()
}
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.5.0
* @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 HORIZONTAL_REACHAROUND = new LambdaControlsFeature("horizontal_reacharound", 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(HORIZONTAL_REACHAROUND);
FEATURES.add(VERTICAL_REACHAROUND);
} }
} }

View File

@@ -1,9 +1,12 @@
import net.fabricmc.loom.task.RemapJarTask
plugins { plugins {
id 'fabric-loom' version '0.4-SNAPSHOT' id 'fabric-loom' version '0.4-SNAPSHOT'
id 'java-library' id 'java-library'
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 {
@@ -17,48 +20,40 @@ repositories {
repositories { repositories {
maven { url = "https://jitpack.io" } maven { url = "https://jitpack.io" }
} }
// OkZoomer
ivy {
url 'https://github.com/joaoh1/OkZoomer/releases/download/'
patternLayout {
artifact '[revision]/[module]-[revision].[ext]'
}
metadataSources() {
artifact()
}
}
} }
configurations { configurations {
shadowInternal
shadow shadow
api.extendsFrom shadow
} }
dependencies { dependencies {
//to change the versions see the gradle.properties file //to change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}" minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modCompile "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// Fabric API. This is technically optional, but you probably want it anyway. // Fabric API. This is technically optional, but you probably want it anyway.
modApi "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modCompile "io.github.prospector:modmenu:${project.modmenu_version}" modImplementation "io.github.prospector:modmenu:${project.modmenu_version}"
modCompile "com.github.lambdaurora:spruceui:${project.spruceui_version}" modImplementation "com.github.lambdaurora:spruceui:${project.spruceui_version}"
include "com.github.lambdaurora:spruceui:${project.spruceui_version}" include "com.github.lambdaurora:spruceui:${project.spruceui_version}"
// Compatibility mods // Compatibility mods
modCompile "io.github.joaoh1:okzoomer:2.1.0-beta.2" modImplementation "com.github.joaoh1:okzoomer:e13183c59b"
modCompile "me.shedaniel:RoughlyEnoughItems:3.4.5" modImplementation "me.shedaniel:RoughlyEnoughItems:5.2.3"
api project(":core") api project(":core")
shadow project(":core") shadowInternal project(":core")
include "org.jetbrains:annotations:17.0.0" shadow("org.aperlambda:lambdajcommon:1.8.1") {
include("org.aperlambda:lambdajcommon:1.8.0") { // Minecraft already has all that google crap.
exclude group: 'com.google.code.gson' exclude group: 'com.google.code.gson'
exclude group: 'com.google.guava' exclude group: 'com.google.guava'
} }
include "com.electronwill.night-config:core:3.5.3" shadow "com.electronwill.night-config:core:3.5.3"
include "com.electronwill.night-config:toml:3.5.3" shadow "com.electronwill.night-config:toml:3.5.3"
} }
processResources { processResources {
@@ -77,18 +72,56 @@ processResources {
java { java {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
withSourcesJar()
} }
jar { jar {
from "../LICENSE" from "../LICENSE"
}
task shadowJar(type: Jar) {
archiveClassifier.set("dev")
from sourceSets.main.output
from { from {
configurations.shadow.filter { configurations.shadowInternal.filter {
it.getName().contains("lambdacontrols") it.getName().contains("lambdacontrols")
}.collect { }.collect {
it.isDirectory() ? it : zipTree(it) it.isDirectory() ? it : zipTree(it)
} }
} }
from {
configurations.shadow.collect {
it.isDirectory() ? it : zipTree(it)
}
}
} }
task shadowRemapJar(type: RemapJarTask) {
dependsOn shadowJar
input = file("${project.buildDir}/libs/$archivesBaseName-$version-dev.jar")
archiveName = "${archivesBaseName}-${version}.jar"
addNestedDependencies = true
}
// 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
}
}
}
}
shadowJar.dependsOn(":core:jar")
build.dependsOn(":core:build") build.dependsOn(":core:build")
publish.dependsOn(":core:publish")

View File

@@ -15,8 +15,9 @@ import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.ModContainer;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -28,7 +29,7 @@ import java.util.Optional;
* Represents the LambdaControls mod. * Represents the LambdaControls mod.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.1.0 * @version 1.5.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class LambdaControls implements ModInitializer public class LambdaControls implements ModInitializer
@@ -38,6 +39,8 @@ public class LambdaControls implements ModInitializer
public static final Identifier FEATURE_CHANNEL = new Identifier(LambdaControlsConstants.FEATURE_CHANNEL.toString()); public static final Identifier FEATURE_CHANNEL = new Identifier(LambdaControlsConstants.FEATURE_CHANNEL.toString());
public static final Identifier HELLO_CHANNEL = new Identifier(LambdaControlsConstants.HELLO_CHANNEL.toString()); public static final Identifier HELLO_CHANNEL = new Identifier(LambdaControlsConstants.HELLO_CHANNEL.toString());
public static final TranslatableText NOT_BOUND_TEXT = new TranslatableText("lambdacontrols.not_bound");
public final Logger logger = LogManager.getLogger("LambdaControls"); public final Logger logger = LogManager.getLogger("LambdaControls");
@Override @Override
@@ -53,7 +56,7 @@ public class LambdaControls implements ModInitializer
.ifPresent(controlsMode -> context.getTaskQueue() .ifPresent(controlsMode -> context.getTaskQueue()
.execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(context.getPlayer(), controlsMode))); .execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(context.getPlayer(), controlsMode)));
context.getTaskQueue().execute(() -> context.getTaskQueue().execute(() ->
ServerSidePacketRegistry.INSTANCE.sendToPlayer(context.getPlayer(), FEATURE_CHANNEL, this.makeFeatureBuffer(LambdaControlsFeature.FRONT_BLOCK_PLACING))); ServerSidePacketRegistry.INSTANCE.sendToPlayer(context.getPlayer(), FEATURE_CHANNEL, this.makeFeatureBuffer(LambdaControlsFeature.HORIZONTAL_REACHAROUND)));
}); });
ServerSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL, ServerSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL,
(context, attachedData) -> ControlsMode.byId(attachedData.readString(32)) (context, attachedData) -> ControlsMode.byId(attachedData.readString(32))

View File

@@ -9,7 +9,9 @@
package me.lambdaurora.lambdacontrols.client; package me.lambdaurora.lambdacontrols.client;
import net.minecraft.client.resource.language.I18n; import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -20,7 +22,7 @@ import java.util.Optional;
* Represents a controller type. * Represents a controller type.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.0.0 * @version 1.4.3
* @since 1.0.0 * @since 1.0.0
*/ */
public enum ControllerType implements Nameable public enum ControllerType implements Nameable
@@ -28,15 +30,24 @@ public enum ControllerType implements Nameable
DEFAULT(0), DEFAULT(0),
DUALSHOCK(1), DUALSHOCK(1),
SWITCH(2), SWITCH(2),
XBOX(3), XBOX_360(3, new LiteralText("Xbox 360")),
STEAM(4), XBOX(4),
OUYA(5); STEAM(5),
OUYA(6);
private final int id; private final int id;
private final Text text;
ControllerType(int id) ControllerType(int id)
{ {
this.id = id; this.id = id;
this.text = new TranslatableText("lambdacontrols.controller_type." + this.getName());
}
ControllerType(int id, @NotNull Text text)
{
this.id = id;
this.text = text;
} }
/** /**
@@ -54,7 +65,7 @@ public enum ControllerType implements Nameable
* *
* @return The next available controller type. * @return The next available controller type.
*/ */
public ControllerType next() public @NotNull ControllerType next()
{ {
ControllerType[] v = values(); ControllerType[] v = values();
if (v.length == this.ordinal() + 1) if (v.length == this.ordinal() + 1)
@@ -63,13 +74,13 @@ public enum ControllerType implements Nameable
} }
/** /**
* Gets the translated name of this controller type. * Gets the translated text of this controller type.
* *
* @return The translated name of this controller type. * @return The translated text of this controller type.
*/ */
public String getTranslatedName() public @NotNull Text getTranslatedText()
{ {
return I18n.translate("lambdacontrols.controller_type." + this.getName()); return this.text;
} }
@Override @Override
@@ -84,7 +95,7 @@ public enum ControllerType implements Nameable
* @param id The identifier of the controller type. * @param id The identifier of the controller type.
* @return The controller type if found, else empty. * @return The controller type if found, else empty.
*/ */
public static Optional<ControllerType> byId(@NotNull String id) public static @NotNull Optional<ControllerType> byId(@NotNull String id)
{ {
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
} }

View File

@@ -10,6 +10,8 @@
package me.lambdaurora.lambdacontrols.client; package me.lambdaurora.lambdacontrols.client;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -20,7 +22,7 @@ import java.util.Optional;
* Represents the hud side which is the side where the movements buttons are. * Represents the hud side which is the side where the movements buttons are.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.0.0 * @version 1.4.0
* @since 1.0.0 * @since 1.0.0
*/ */
public enum HudSide implements Nameable public enum HudSide implements Nameable
@@ -28,12 +30,19 @@ public enum HudSide implements Nameable
LEFT, LEFT,
RIGHT; RIGHT;
private final Text text;
HudSide()
{
this.text = new TranslatableText(this.getTranslationKey());
}
/** /**
* Returns the next side available. * Returns the next side available.
* *
* @return The next available side. * @return The next available side.
*/ */
public HudSide next() public @NotNull HudSide next()
{ {
HudSide[] v = values(); HudSide[] v = values();
if (v.length == this.ordinal() + 1) if (v.length == this.ordinal() + 1)
@@ -42,13 +51,23 @@ public enum HudSide implements Nameable
} }
/** /**
* Gets the translated name of this hud side. * Returns the translation key of this hud side.
* *
* @return The translated name of this hud side. * @return The translation key of this hude side.
*/ */
public String getTranslatedName() public @NotNull String getTranslationKey()
{ {
return I18n.translate("lambdacontrols.hud_side." + this.getName()); return "lambdacontrols.hud_side." + this.getName();
}
/**
* Gets the translated text of this hud side.
*
* @return The translated text of this hud side.
*/
public @NotNull Text getTranslatedText()
{
return this.text;
} }
@Override @Override
@@ -63,7 +82,7 @@ public enum HudSide implements Nameable
* @param id The identifier of the hud side. * @param id The identifier of the hud side.
* @return The hud side if found, else empty. * @return The hud side if found, else empty.
*/ */
public static Optional<HudSide> byId(@NotNull String id) public static @NotNull Optional<HudSide> byId(@NotNull String id)
{ {
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
} }

View File

@@ -16,16 +16,20 @@ 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;
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsHud; import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsHud;
import me.lambdaurora.lambdacontrols.client.gui.RingScreen;
import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay; import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay;
import me.lambdaurora.lambdacontrols.client.ring.KeyBindingRingAction;
import me.lambdaurora.lambdacontrols.client.ring.LambdaRing;
import me.lambdaurora.spruceui.event.OpenScreenCallback; 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.keybinding.FabricKeyBinding; 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.event.client.ClientTickCallback;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.toast.SystemToast; import net.minecraft.client.toast.SystemToast;
import net.minecraft.client.util.InputUtil; import net.minecraft.client.util.InputUtil;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
@@ -34,29 +38,36 @@ import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import java.io.File;
/** /**
* Represents the LambdaControls client mod. * Represents the LambdaControls client mod.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.5.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsClient extends LambdaControls implements ClientModInitializer public class LambdaControlsClient extends LambdaControls implements ClientModInitializer
{ {
private static LambdaControlsClient INSTANCE; private static LambdaControlsClient INSTANCE;
public static final FabricKeyBinding BINDING_LOOK_UP = FabricKeyBinding.Builder.create(new Identifier(LambdaControlsConstants.NAMESPACE, "look_up"), public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_up"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement").build(); InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement");
public static final FabricKeyBinding BINDING_LOOK_RIGHT = FabricKeyBinding.Builder.create(new Identifier(LambdaControlsConstants.NAMESPACE, "look_right"), public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_right"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement").build(); InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement");
public static final FabricKeyBinding BINDING_LOOK_DOWN = FabricKeyBinding.Builder.create(new Identifier(LambdaControlsConstants.NAMESPACE, "look_down"), public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_down"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement").build(); InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement");
public static final FabricKeyBinding BINDING_LOOK_LEFT = FabricKeyBinding.Builder.create(new Identifier(LambdaControlsConstants.NAMESPACE, "look_left"), public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_left"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement").build(); InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement");
/*public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "ring"),
InputUtil.Type.MOUSE, GLFW.GLFW_MOUSE_BUTTON_5, "key.categories.misc");*/
public static final Identifier CONTROLLER_BUTTONS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png"); public static final Identifier CONTROLLER_BUTTONS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png");
public static final Identifier CONTROLLER_AXIS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_axis.png"); public static final Identifier CONTROLLER_AXIS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_axis.png");
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 static File MAPPINGS_FILE = new File("config/gamecontrollerdb.txt");
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 LambdaRing ring = new LambdaRing(this);
public final LambdaReacharound reacharound = new LambdaReacharound();
private LambdaControlsHud hud; private LambdaControlsHud hud;
private ControlsMode previousControlsMode; private ControlsMode previousControlsMode;
@@ -64,10 +75,13 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
public void onInitializeClient() public void onInitializeClient()
{ {
INSTANCE = this; INSTANCE = this;
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_UP); KeyBindingHelper.registerKeyBinding(BINDING_LOOK_UP);
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_RIGHT); KeyBindingHelper.registerKeyBinding(BINDING_LOOK_RIGHT);
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_DOWN); KeyBindingHelper.registerKeyBinding(BINDING_LOOK_DOWN);
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_LEFT); KeyBindingHelper.registerKeyBinding(BINDING_LOOK_LEFT);
//KeyBindingHelper.registerKeyBinding(BINDING_RING);
this.ring.registerAction("keybinding", KeyBindingRingAction.FACTORY);
ClientSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL, (context, attachedData) -> context.getTaskQueue() ClientSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL, (context, attachedData) -> context.getTaskQueue()
.execute(() -> ClientSidePacketRegistry.INSTANCE.sendToServer(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode())))); .execute(() -> ClientSidePacketRegistry.INSTANCE.sendToServer(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode()))));
@@ -77,7 +91,8 @@ 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)));
}); });
ClientTickCallback.EVENT.register(this::onTick); ClientTickEvents.START_CLIENT_TICK.register(this.reacharound::tick);
ClientTickEvents.END_CLIENT_TICK.register(this::onTick);
OpenScreenCallback.EVENT.register((client, screen) -> { OpenScreenCallback.EVENT.register((client, screen) -> {
if (screen == null && this.config.getControlsMode() == ControlsMode.TOUCHSCREEN) { if (screen == null && this.config.getControlsMode() == ControlsMode.TOUCHSCREEN) {
@@ -128,6 +143,10 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
this.input.onTick(client); this.input.onTick(client);
if (this.config.getControlsMode() == ControlsMode.CONTROLLER && (client.isWindowFocused() || this.config.hasUnfocusedInput())) if (this.config.getControlsMode() == ControlsMode.CONTROLLER && (client.isWindowFocused() || this.config.hasUnfocusedInput()))
this.input.onControllerTick(client); this.input.onControllerTick(client);
/*if (BINDING_RING.wasPressed()) {
client.openScreen(new RingScreen());
}*/
} }
public void onRender(MinecraftClient client) public void onRender(MinecraftClient client)

View File

@@ -34,25 +34,28 @@ import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y;
public class LambdaControlsConfig public class LambdaControlsConfig
{ {
// General // General
private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT; private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT;
private static final boolean DEFAULT_AUTO_SWITCH_MODE = false; private static final boolean DEFAULT_AUTO_SWITCH_MODE = false;
private static final boolean DEFAULT_DEBUG = false;
// HUD // HUD
private static final boolean DEFAULT_HUD_ENABLE = true; private static final boolean DEFAULT_HUD_ENABLE = true;
private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT; private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT;
// Gameplay // Gameplay
private static final boolean DEFAULT_FAST_BLOCK_INTERACTION = true; private static final boolean DEFAULT_FAST_BLOCK_INTERACTION = true;
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_HORIZONTAL_REACHAROUND = 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;
private static final double DEFAULT_ROTATION_SPEED = 40.0; private static final double DEFAULT_ROTATION_SPEED = 40.0;
private static final double DEFAULT_MOUSE_SPEED = 25.0; private static final double DEFAULT_MOUSE_SPEED = 25.0;
private static final boolean DEFAULT_UNFOCUSED_INPUT = false; private static final boolean DEFAULT_UNFOCUSED_INPUT = false;
private static final boolean DEFAULT_VIRTUAL_MOUSE = false; private static final boolean DEFAULT_VIRTUAL_MOUSE = false;
private static final VirtualMouseSkin DEFAULT_VIRTUAL_MOUSE_SKIN = VirtualMouseSkin.DEFAULT_LIGHT; private static final VirtualMouseSkin DEFAULT_VIRTUAL_MOUSE_SKIN = VirtualMouseSkin.DEFAULT_LIGHT;
private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?"); private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?");
@@ -61,8 +64,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 +96,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.HORIZONTAL_REACHAROUND.setEnabled(this.config.getOrElse("gameplay.reacharound.horizontal", DEFAULT_HORIZONTAL_REACHAROUND));
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);
@@ -106,6 +110,8 @@ public class LambdaControlsConfig
this.virtualMouseSkin = VirtualMouseSkin.byId(this.config.getOrElse("controller.virtual_mouse_skin", DEFAULT_VIRTUAL_MOUSE_SKIN.getName())).orElse(DEFAULT_VIRTUAL_MOUSE_SKIN); this.virtualMouseSkin = VirtualMouseSkin.byId(this.config.getOrElse("controller.virtual_mouse_skin", DEFAULT_VIRTUAL_MOUSE_SKIN.getName())).orElse(DEFAULT_VIRTUAL_MOUSE_SKIN);
// Controller controls. // Controller controls.
InputManager.loadButtonBindings(this); InputManager.loadButtonBindings(this);
this.mod.ring.load(this.config);
} }
/** /**
@@ -133,10 +139,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_HORIZONTAL_REACHAROUND));
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");
@@ -160,12 +175,14 @@ public class LambdaControlsConfig
// General // General
this.setControlsMode(DEFAULT_CONTROLS_MODE); this.setControlsMode(DEFAULT_CONTROLS_MODE);
this.setAutoSwitchMode(DEFAULT_AUTO_SWITCH_MODE); this.setAutoSwitchMode(DEFAULT_AUTO_SWITCH_MODE);
this.setDebug(DEFAULT_DEBUG);
// Gameplay // Gameplay
this.setFastBlockPlacing(DEFAULT_FAST_BLOCK_INTERACTION); this.setFastBlockPlacing(DEFAULT_FAST_BLOCK_INTERACTION);
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_HORIZONTAL_REACHAROUND);
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);
@@ -223,6 +240,26 @@ public class LambdaControlsConfig
this.config.set("auto_switch_mode", autoSwitchMode); this.config.set("auto_switch_mode", autoSwitchMode);
} }
/**
* Returns whether the mod has debug enabled or not.
*
* @return True if debug is enabled, else false.
*/
public boolean hasDebug()
{
return this.config.getOrElse("debug", DEFAULT_DEBUG);
}
/**
* Sets whether the mod has debug enabled or not.
*
* @param debug True if debug is enabled, else false.
*/
protected void setDebug(boolean debug)
{
this.config.set("debug", debug);
}
/* /*
HUD settings HUD settings
*/ */
@@ -341,7 +378,7 @@ public class LambdaControlsConfig
*/ */
public boolean hasFrontBlockPlacing() public boolean hasFrontBlockPlacing()
{ {
return LambdaControlsFeature.FRONT_BLOCK_PLACING.isEnabled(); return LambdaControlsFeature.HORIZONTAL_REACHAROUND.isEnabled();
} }
/** /**
@@ -351,8 +388,29 @@ public class LambdaControlsConfig
*/ */
public void setFrontBlockPlacing(boolean enable) public void setFrontBlockPlacing(boolean enable)
{ {
LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(enable); LambdaControlsFeature.HORIZONTAL_REACHAROUND.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 +418,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 +428,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 +440,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

@@ -11,24 +11,17 @@ package me.lambdaurora.lambdacontrols.client;
import io.github.prospector.modmenu.api.ConfigScreenFactory; import io.github.prospector.modmenu.api.ConfigScreenFactory;
import io.github.prospector.modmenu.api.ModMenuApi; import io.github.prospector.modmenu.api.ModMenuApi;
import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen; import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen;
/** /**
* Represents the API implementation of ModMenu for LambdaControls. * Represents the API implementation of ModMenu for LambdaControls.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.3.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsModMenu implements ModMenuApi public class LambdaControlsModMenu implements ModMenuApi
{ {
@Override
public String getModId()
{
return LambdaControlsConstants.NAMESPACE;
}
@Override @Override
public ConfigScreenFactory<?> getModConfigScreenFactory() public ConfigScreenFactory<?> getModConfigScreenFactory()
{ {

View File

@@ -9,7 +9,7 @@
package me.lambdaurora.lambdacontrols.client; package me.lambdaurora.lambdacontrols.client;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature; import com.google.common.collect.ImmutableSet;
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;
@@ -19,36 +19,29 @@ import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay;
import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor; import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor; import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor; import me.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor; 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;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.advancement.AdvancementTab; import net.minecraft.client.gui.screen.advancement.AdvancementTab;
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen; import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
import net.minecraft.client.gui.screen.ingame.ContainerScreen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget; import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
import net.minecraft.client.gui.screen.pack.PackScreen;
import net.minecraft.client.gui.screen.world.WorldListWidget; import net.minecraft.client.gui.screen.world.WorldListWidget;
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget; import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget; import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
import net.minecraft.client.gui.widget.EntryListWidget;
import net.minecraft.client.gui.widget.SliderWidget; import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.container.Slot;
import net.minecraft.container.SlotActionType;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem; import net.minecraft.screen.slot.Slot;
import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.text.TranslatableText;
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;
@@ -71,24 +64,25 @@ import static org.lwjgl.glfw.GLFW.*;
* Represents the LambdaControls' input handler. * Represents the LambdaControls' input handler.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.4.3
* @since 1.0.0 * @since 1.0.0
*/ */
public class LambdaInput public class LambdaInput
{ {
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>(); private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
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;
private float prevYAxis = 0.F; private float prevYAxis = 0.F;
private int targetMouseX = 0; private int targetMouseX = 0;
private int targetMouseY = 0; private int targetMouseY = 0;
private float mouseSpeedX = 0.F; private float mouseSpeedX = 0.F;
private float mouseSpeedY = 0.F; private float mouseSpeedY = 0.F;
private int inventoryInteractionCooldown = 0;
public LambdaInput(@NotNull LambdaControlsClient mod) public LambdaInput(@NotNull LambdaControlsClient mod)
{ {
@@ -155,9 +149,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) {
@@ -168,6 +159,9 @@ public class LambdaInput
screen.focusedBinding = null; screen.focusedBinding = null;
} }
} }
if (this.inventoryInteractionCooldown > 0)
this.inventoryInteractionCooldown--;
} }
/** /**
@@ -225,6 +219,7 @@ public class LambdaInput
((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), 0, 0); ((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), 0, 0);
INPUT_MANAGER.resetMouseTarget(client); INPUT_MANAGER.resetMouseTarget(client);
} }
this.inventoryInteractionCooldown = 5;
} }
private void fetchButtonInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon) private void fetchButtonInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon)
@@ -320,50 +315,123 @@ public class LambdaInput
} }
} }
if (client.currentScreen instanceof ContainerScreen && 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(); return;
Slot slot = ((ContainerScreenAccessor) client.currentScreen).lambdacontrols_getSlotAt(x, y); }
SlotActionType slotAction = SlotActionType.PICKUP;
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && slot != null) { if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
if (client.currentScreen instanceof CreativeInventoryScreen) {
if (((CreativeInventoryScreenAccessor) client.currentScreen).lambdacontrols_isCreativeInventorySlot(slot))
slotAction = SlotActionType.CLONE;
}
client.interactionManager.clickSlot(((ContainerScreen) client.currentScreen).getContainer().syncId, slot.id, GLFW.GLFW_MOUSE_BUTTON_1, slotAction, client.player);
client.player.playerContainer.sendContentUpdates();
this.actionGuiCooldown = 5;
return;
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
client.player.closeContainer();
return;
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_X && slot != null) {
client.interactionManager.clickSlot(((ContainerScreen) client.currentScreen).getContainer().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(((ContainerScreen) client.currentScreen).getContainer().syncId, slot.id, GLFW.GLFW_MOUSE_BUTTON_1, SlotActionType.QUICK_MOVE, client.player);
return;
}
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
if (client.currentScreen != null) { if (client.currentScreen != null) {
client.currentScreen.onClose(); if (!LambdaControlsCompat.handleMenuBack(client, client.currentScreen))
if (!this.tryGoBack(client.currentScreen))
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) {
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth(); if (!this.ignoreNextARelease) {
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight(); double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
if (action == 0) { double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
client.currentScreen.mouseClicked(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1); if (action == 0) {
} else if (action == 1) { Screen.wrapScreenError(() -> client.currentScreen.mouseClicked(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1),
client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1); "mouseClicked event handler", client.currentScreen.getClass().getCanonicalName());
} else if (action == 1) {
Screen.wrapScreenError(() -> client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1),
"mouseReleased event handler", client.currentScreen.getClass().getCanonicalName());
}
this.actionGuiCooldown = 5;
} else {
this.ignoreNextARelease = false;
} }
this.actionGuiCooldown = 5;
} }
} }
/**
* 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 (this.inventoryInteractionCooldown > 0)
return true;
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;
}
/**
* Tries to go back.
*
* @param screen The current screen.
* @return True if successful, else false.
*/
public boolean tryGoBack(@NotNull Screen screen)
{
ImmutableSet<String> set = ImmutableSet.of("gui.back", "gui.done", "gui.cancel", "gui.toTitle", "gui.toMenu");
return screen.children().stream().filter(element -> element instanceof AbstractPressableButtonWidget)
.map(element -> (AbstractPressableButtonWidget) element)
.filter(element -> element.getMessage() instanceof TranslatableText)
.anyMatch(element -> {
if (set.stream().anyMatch(key -> key.equals(((TranslatableText) element.getMessage()).getKey()))) {
element.onPress();
return true;
}
return false;
});
}
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)
{ {
int asButtonState = value > 0.5F ? 1 : (value < -0.5F ? 2 : 0); int asButtonState = value > 0.5F ? 1 : (value < -0.5F ? 2 : 0);
@@ -400,6 +468,17 @@ public class LambdaInput
BUTTON_COOLDOWNS.put(axisAsButton(axis, false), 5); BUTTON_COOLDOWNS.put(axisAsButton(axis, false), 5);
} }
} }
float axisValue = absValue < this.config.getDeadZone() ? 0.f : (float) (absValue - this.config.getDeadZone());
axisValue /= (1.0 - this.config.getDeadZone());
if (currentPlusState)
InputManager.BUTTON_VALUES.put(axisAsButton(axis, true), axisValue);
else
InputManager.BUTTON_VALUES.put(axisAsButton(axis, true), 0.f);
if (currentMinusState)
InputManager.BUTTON_VALUES.put(axisAsButton(axis, false), axisValue);
else
InputManager.BUTTON_VALUES.put(axisAsButton(axis, false), 0.f);
} }
double deadZone = this.config.getDeadZone(); double deadZone = this.config.getDeadZone();
@@ -424,6 +503,7 @@ public class LambdaInput
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) { if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
CreativeInventoryScreen screen = (CreativeInventoryScreen) client.currentScreen; CreativeInventoryScreen screen = (CreativeInventoryScreen) client.currentScreen;
CreativeInventoryScreenAccessor accessor = (CreativeInventoryScreenAccessor) screen; CreativeInventoryScreenAccessor accessor = (CreativeInventoryScreenAccessor) screen;
// @TODO allow rebinding to left stick
if (accessor.lambdacontrols_hasScrollbar() && absValue >= deadZone) { if (accessor.lambdacontrols_hasScrollbar() && absValue >= deadZone) {
screen.mouseScrolled(0.0, 0.0, -value); screen.mouseScrolled(0.0, 0.0, -value);
} }
@@ -562,7 +642,7 @@ public class LambdaInput
this.actionGuiCooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks. this.actionGuiCooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
return false; return false;
} else if (element instanceof AlwaysSelectedEntryListWidget) { } else if (element instanceof AlwaysSelectedEntryListWidget) {
((EntryListWidgetAccessor) element).lambdacontrols_moveSelection(right ? 1 : -1); ((EntryListWidgetAccessor) element).lambdacontrols_moveSelection(right ? EntryListWidget.MoveDirection.UP : EntryListWidget.MoveDirection.DOWN);
return false; return false;
} else if (element instanceof ParentElement) { } else if (element instanceof ParentElement) {
ParentElement entryList = (ParentElement) element; ParentElement entryList = (ParentElement) element;
@@ -589,16 +669,16 @@ public class LambdaInput
double powValue = Math.pow(value, 2.0); double powValue = Math.pow(value, 2.0);
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) { if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
if (state == 2) { if (state == 2) {
this.targetPitch = -this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; this.targetPitch = -this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D;
} else if (state == 1) { } else if (state == 1) {
this.targetPitch = this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; this.targetPitch = this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D;
} }
} }
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) { if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) {
if (state == 2) { if (state == 2) {
this.targetYaw = -this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; this.targetYaw = -this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D;
} else if (state == 1) { } else if (state == 1) {
this.targetYaw = this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; this.targetYaw = this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D;
} }
} }
} }
@@ -620,26 +700,26 @@ public class LambdaInput
public static boolean isScreenInteractive(@NotNull Screen screen) public static boolean isScreenInteractive(@NotNull Screen screen)
{ {
return !(screen instanceof AdvancementsScreen || screen instanceof ContainerScreen || LambdaControlsCompat.requireMouseOnScreen(screen)); return !(screen instanceof AdvancementsScreen || screen instanceof HandledScreen || screen instanceof PackScreen || LambdaControlsCompat.requireMouseOnScreen(screen));
} }
// Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686. // Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686.
private void moveMouseToClosestSlot(@NotNull MinecraftClient client, @Nullable Screen screen) private void moveMouseToClosestSlot(@NotNull MinecraftClient client, @Nullable Screen screen)
{ {
// Makes the mouse attracted to slots. This helps with selecting items when using a controller. // Makes the mouse attracted to slots. This helps with selecting items when using a controller.
if (screen instanceof ContainerScreen) { if (screen instanceof HandledScreen) {
ContainerScreen inventoryScreen = (ContainerScreen) screen; HandledScreen inventoryScreen = (HandledScreen) screen;
ContainerScreenAccessor accessor = (ContainerScreenAccessor) inventoryScreen; HandledScreenAccessor accessor = (HandledScreenAccessor) inventoryScreen;
int guiLeft = accessor.getX(); int guiLeft = accessor.getX();
int guiTop = accessor.getY(); int guiTop = accessor.getY();
int mouseX = (int) (targetMouseX * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()); int mouseX = (int) (targetMouseX * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
int mouseY = (int) (targetMouseY * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()); int mouseY = (int) (targetMouseY * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight());
// Finds the closest slot in the GUI within 14 pixels. // Finds the closest slot in the GUI within 14 pixels.
Optional<Pair<Slot, Double>> closestSlot = inventoryScreen.getContainer().slots.parallelStream() Optional<Pair<Slot, Double>> closestSlot = inventoryScreen.getScreenHandler().slots.parallelStream()
.map(slot -> { .map(slot -> {
int x = guiLeft + slot.xPosition + 8; int x = guiLeft + slot.x + 8;
int y = guiTop + slot.yPosition + 8; int y = guiTop + slot.y + 8;
// Distance between the slot and the cursor. // Distance between the slot and the cursor.
double distance = Math.sqrt(Math.pow(x - mouseX, 2) + Math.pow(y - mouseY, 2)); double distance = Math.sqrt(Math.pow(x - mouseX, 2) + Math.pow(y - mouseY, 2));
@@ -650,8 +730,8 @@ public class LambdaInput
if (closestSlot.isPresent()) { if (closestSlot.isPresent()) {
Slot slot = closestSlot.get().key; Slot slot = closestSlot.get().key;
if (slot.hasStack() || !client.player.inventory.getMainHandStack().isEmpty()) { if (slot.hasStack() || !client.player.inventory.getMainHandStack().isEmpty()) {
int slotCenterXScaled = guiLeft + slot.xPosition + 8; int slotCenterXScaled = guiLeft + slot.x + 8;
int slotCenterYScaled = guiTop + slot.yPosition + 8; int slotCenterYScaled = guiTop + slot.y + 8;
int slotCenterX = (int) (slotCenterXScaled / ((double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth())); int slotCenterX = (int) (slotCenterXScaled / ((double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()));
int slotCenterY = (int) (slotCenterYScaled / ((double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight())); int slotCenterY = (int) (slotCenterYScaled / ((double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()));
double deltaX = slotCenterX - targetMouseX; double deltaX = slotCenterX - targetMouseX;
@@ -679,71 +759,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.onGround && 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,174 @@
/*
* 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.RaycastContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents the reach-around API of LambdaControls.
*
* @version 1.5.0
* @since 1.3.2
*/
public class LambdaReacharound
{
private BlockHitResult lastReacharoundResult = null;
private boolean lastReacharoundVertical = false;
private boolean onSlab = false;
public void tick(@NotNull MinecraftClient client)
{
this.lastReacharoundResult = this.tryVerticalReachAround(client);
if (this.lastReacharoundResult == null) {
this.lastReacharoundResult = this.tryHorizontalReachAround(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.HORIZONTAL_REACHAROUND.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 reach-around is possible.
*
* @param client The client instance.
* @return A block hit result if vertical reach-around 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.raycast(new RaycastContext(pos, rayVec, RaycastContext.ShapeType.OUTLINE, RaycastContext.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 horizontal reach-around is possible.
*
* @param client The client instance.
* @return A block hit result if horizontal reach-around is possible.
*/
public @Nullable BlockHitResult tryHorizontalReachAround(@NotNull MinecraftClient client)
{
if (!LambdaControlsFeature.HORIZONTAL_REACHAROUND.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();
if (client.player.getY() - playerPos.getY() - 1.0 >= 0.25) {
playerPos = playerPos.up();
this.onSlab = true;
} else {
this.onSlab = false;
}
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 @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 @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @NotNull Block block)
{
if (block instanceof SlabBlock) {
if (this.onSlab) result = result.withSide(Direction.UP);
else result = result.withSide(Direction.DOWN);
}
return result;
}
}

View File

@@ -9,7 +9,8 @@
package me.lambdaurora.lambdacontrols.client; package me.lambdaurora.lambdacontrols.client;
import net.minecraft.client.resource.language.I18n; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -19,7 +20,7 @@ import java.util.Optional;
/** /**
* Represents the virtual mouse skins. * Represents the virtual mouse skins.
* *
* @version 1.2.0 * @version 1.4.0
* @since 1.2.0 * @since 1.2.0
*/ */
public enum VirtualMouseSkin implements Nameable public enum VirtualMouseSkin implements Nameable
@@ -29,10 +30,13 @@ public enum VirtualMouseSkin implements Nameable
SECOND_LIGHT("second_light"), SECOND_LIGHT("second_light"),
SECOND_DARK("second_dark"); SECOND_DARK("second_dark");
private String name; private final String name;
private final Text text;
VirtualMouseSkin(String name) { VirtualMouseSkin(String name)
{
this.name = name; this.name = name;
this.text = new TranslatableText(this.getTranslationKey());
} }
/** /**
@@ -40,7 +44,7 @@ public enum VirtualMouseSkin implements Nameable
* *
* @return The next available virtual mouse skin. * @return The next available virtual mouse skin.
*/ */
public VirtualMouseSkin next() public @NotNull VirtualMouseSkin next()
{ {
VirtualMouseSkin[] v = values(); VirtualMouseSkin[] v = values();
if (v.length == this.ordinal() + 1) if (v.length == this.ordinal() + 1)
@@ -49,13 +53,23 @@ public enum VirtualMouseSkin implements Nameable
} }
/** /**
* Gets the translated name of this controller type. * Returns the translation key of this virtual mouse skin.
* *
* @return The translated name of this controller type. * @return The virtual mouse skin's translation key.
*/ */
public String getTranslatedName() public @NotNull String getTranslationKey()
{ {
return I18n.translate("lambdacontrols.virtual_mouse.skin." + this.getName()); return "lambdacontrols.virtual_mouse.skin." + this.getName();
}
/**
* Gets the translated text of this virtual mouse skin.
*
* @return The translated text of this virtual mouse skin.
*/
public @NotNull Text getTranslatedText()
{
return this.text;
} }
@Override @Override
@@ -65,12 +79,12 @@ public enum VirtualMouseSkin implements Nameable
} }
/** /**
* Gets the controller type from its identifier. * Gets the virtual mouse skin from its identifier.
* *
* @param id The identifier of the controller type. * @param id The identifier of the virtual mouse skin.
* @return The controller type if found, else empty. * @return The virtual mouse skin if found, else empty.
*/ */
public static Optional<VirtualMouseSkin> byId(@NotNull String id) public static @NotNull Optional<VirtualMouseSkin> byId(@NotNull String id)
{ {
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
} }

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.screen.slot.Slot;
import net.minecraft.util.hit.BlockHitResult;
import org.aperlambda.lambdacommon.utils.Pair;
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.5.0
* @since 1.1.0 * @since 1.1.0
*/ */
public interface CompatHandler public interface CompatHandler
@@ -33,10 +39,72 @@ 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 a slot at the specified location if possible.
*
* @param screen The screen.
* @param mouseX The mouse X-coordinate.
* @param mouseY The mouse Y-coordinate.
* @return A slot if present, else null.
* @since 1.5.0
*/
default @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Screen screen, int mouseX, int mouseY)
{
return null;
}
/**
* 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.
* <p>
* 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,24 @@ 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.screen.slot.Slot;
import net.minecraft.util.hit.BlockHitResult;
import org.aperlambda.lambdacommon.utils.LambdaReflection; import org.aperlambda.lambdacommon.utils.LambdaReflection;
import org.aperlambda.lambdacommon.utils.Pair;
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.5.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsCompat public class LambdaControlsCompat
@@ -37,7 +43,7 @@ public class LambdaControlsCompat
*/ */
public static void init(@NotNull LambdaControlsClient mod) public static void init(@NotNull LambdaControlsClient mod)
{ {
if (FabricLoader.getInstance().isModLoaded("okzoomer") && LambdaReflection.doesClassExist(OkZoomerCompat.OKZOOMER_CLASS_PATH)) { if (FabricLoader.getInstance().isModLoaded("okzoomer")) {
mod.log("Adding okzoomer compatibility..."); mod.log("Adding okzoomer compatibility...");
HANDLERS.add(new OkZoomerCompat()); HANDLERS.add(new OkZoomerCompat());
} }
@@ -45,10 +51,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 +90,76 @@ public class LambdaControlsCompat
return HANDLERS.stream().anyMatch(handler -> handler.requireMouseOnScreen(screen)); return HANDLERS.stream().anyMatch(handler -> handler.requireMouseOnScreen(screen));
} }
/**
* Returns a slot at the specified location if possible.
*
* @param screen The screen.
* @param mouseX The mouse X-coordinate.
* @param mouseY The mouse Y-coordinate.
* @return A slot if present, else null.
*/
public static @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Screen screen, int mouseX, int mouseY)
{
for (CompatHandler handler : HANDLERS) {
Pair<Integer, Integer> slot = handler.getSlotAt(screen, mouseX, mouseY);
if (slot != null)
return slot;
}
return null;
}
/**
* 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

@@ -9,6 +9,7 @@
package me.lambdaurora.lambdacontrols.client.compat; package me.lambdaurora.lambdacontrols.client.compat;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo; import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
@@ -21,7 +22,7 @@ import java.util.Set;
* This plugin is only present for the conditional mixins. * This plugin is only present for the conditional mixins.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.5.0
* @since 1.2.0 * @since 1.2.0
*/ */
public class LambdaControlsMixinPlugin implements IMixinConfigPlugin public class LambdaControlsMixinPlugin implements IMixinConfigPlugin
@@ -30,8 +31,15 @@ public class LambdaControlsMixinPlugin implements IMixinConfigPlugin
public LambdaControlsMixinPlugin() public LambdaControlsMixinPlugin()
{ {
this.conditionalMixins.put("me.lambdaurora.lambdacontrols.client.compat.mixin.RecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent()); this.putConditionalMixin("EntryListWidgetAccessor", LambdaControlsCompat.isReiPresent());
this.conditionalMixins.put("me.lambdaurora.lambdacontrols.client.compat.mixin.VillagerRecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent()); this.putConditionalMixin("EntryWidgetAccessor", LambdaControlsCompat.isReiPresent());
this.putConditionalMixin("RecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent());
this.putConditionalMixin("VillagerRecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent());
}
private void putConditionalMixin(@NotNull String path, boolean condition)
{
this.conditionalMixins.put("me.lambdaurora.lambdacontrols.client.compat.mixin." + path, condition);
} }
@Override @Override

View File

@@ -9,7 +9,7 @@
package me.lambdaurora.lambdacontrols.client.compat; package me.lambdaurora.lambdacontrols.client.compat;
import io.github.joaoh1.okzoomer.OkZoomer; import io.github.joaoh1.okzoomer.client.keybinds.ZoomKeybinds;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -19,13 +19,11 @@ import org.lwjgl.glfw.GLFW;
* Represents a compatibility handler for OkZoomer. * Represents a compatibility handler for OkZoomer.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.1.0 * @version 1.4.3
* @since 1.1.0 * @since 1.1.0
*/ */
public class OkZoomerCompat implements CompatHandler public class OkZoomerCompat implements CompatHandler
{ {
public static final String OKZOOMER_CLASS_PATH = "io.github.joaoh1.okzoomer.OkZoomer";
@Override @Override
public void handle(@NotNull LambdaControlsClient mod) public void handle(@NotNull LambdaControlsClient mod)
{ {
@@ -34,7 +32,30 @@ public class OkZoomerCompat implements CompatHandler
.onlyInGame() .onlyInGame()
.cooldown(true) .cooldown(true)
.category(ButtonBinding.MISC_CATEGORY) .category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(OkZoomer.zoomKeyBinding) .linkKeybind(ZoomKeybinds.zoomKey)
.register(); .register();
if (ZoomKeybinds.areExtraKeybindsEnabled()) {
new ButtonBinding.Builder("zoom_in")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true))
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.increaseZoomKey)
.register();
new ButtonBinding.Builder("zoom_out")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true))
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.decreaseZoomKey)
.register();
new ButtonBinding.Builder("zoom_reset")
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.resetZoomKey)
.register();
}
} }
} }

View File

@@ -11,22 +11,32 @@ package me.lambdaurora.lambdacontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.ButtonState; import me.lambdaurora.lambdacontrols.client.ButtonState;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.compat.mixin.EntryListWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.compat.mixin.EntryWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.compat.mixin.RecipeViewingScreenAccessor; import me.lambdaurora.lambdacontrols.client.compat.mixin.RecipeViewingScreenAccessor;
import me.lambdaurora.lambdacontrols.client.compat.mixin.VillagerRecipeViewingScreenAccessor; import me.lambdaurora.lambdacontrols.client.compat.mixin.VillagerRecipeViewingScreenAccessor;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; 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.PressAction; import me.lambdaurora.lambdacontrols.client.controller.PressAction;
import me.shedaniel.rei.api.RecipeCategory; import me.shedaniel.rei.api.*;
import me.shedaniel.rei.gui.ContainerScreenOverlay; import me.shedaniel.rei.gui.ContainerScreenOverlay;
import me.shedaniel.rei.gui.PreRecipeViewingScreen;
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.EntryListEntryWidget;
import me.shedaniel.rei.gui.widget.EntryListWidget; import me.shedaniel.rei.gui.widget.EntryListWidget;
import me.shedaniel.rei.gui.widget.EntryWidget;
import me.shedaniel.rei.gui.widget.WidgetWithBounds;
import me.shedaniel.rei.impl.ScreenHelper; import me.shedaniel.rei.impl.ScreenHelper;
import me.shedaniel.rei.impl.widgets.ButtonWidget;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element;
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;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -37,68 +47,124 @@ import static org.lwjgl.glfw.GLFW.*;
* Represents a compatibility handler for REI. * Represents a compatibility handler for REI.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.5.0
* @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 final Pair<Integer, Integer> INVALID_SLOT = new Pair<>(-1, -1);
public static ButtonBinding TAB_BACK; private static EntryListWidget ENTRY_LIST_WIDGET;
@Override @Override
public void handle(@NotNull LambdaControlsClient mod) public void handle(@NotNull LambdaControlsClient mod)
{ {
InputManager.registerBinding(new ButtonBinding.Builder(new Identifier("rei", "category_back")) ButtonBinding.builder(new Identifier("rei", "category_back"))
.buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER) .buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.filter((client, binding) -> isViewingScreen(client.currentScreen)) .filter((client, binding) -> isViewingScreen(client.currentScreen))
.action(handleTab(false)) .action(handleTab(false))
.cooldown(true) .cooldown(true)
.build()); .register();
InputManager.registerBinding(new ButtonBinding.Builder(new Identifier("rei", "category_next")) ButtonBinding.builder(new Identifier("rei", "category_next"))
.buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER) .buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
.filter((client, binding) -> isViewingScreen(client.currentScreen)) .filter((client, binding) -> isViewingScreen(client.currentScreen))
.action(handleTab(true)) .action(handleTab(true))
.cooldown(true) .cooldown(true)
.build()); .register();
InputManager.registerBinding(new ButtonBinding.Builder(new Identifier("rei", "page_back")) ButtonBinding.builder(new Identifier("rei", "page_back"))
.buttons(ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_X, false)) .buttons(ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_X, false))
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen)) .filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
.action(handlePage(false)) .action(handlePage(false))
.cooldown(true) .cooldown(true)
.build()); .register();
InputManager.registerBinding(new ButtonBinding.Builder(new Identifier("rei", "page_next")) ButtonBinding.builder(new Identifier("rei", "page_next"))
.buttons(ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_X, true)) .buttons(ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_X, true))
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen)) .filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
.action(handlePage(true)) .action(handlePage(true))
.cooldown(true) .cooldown(true)
.build()); .register();
ButtonBinding.builder(new Identifier("rei", "recipe_back"))
.buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP)
.filter((client, binding) -> isViewingScreen(client.currentScreen))
.action(handleRecipe(false))
.cooldown(true)
.register();
ButtonBinding.builder(new Identifier("rei", "recipe_next"))
.buttons(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)
.filter((client, binding) -> isViewingScreen(client.currentScreen))
.action(handleRecipe(true))
.cooldown(true)
.register();
// For some reasons this is broken. // For some reasons this is broken.
InputManager.registerBinding(new ButtonBinding.Builder(new Identifier("rei", "show_usage")) ButtonBinding.builder(new Identifier("rei", "show_usage"))
.buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB) .buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen)) .filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
.action((client, button, action) -> { .action(handleShowRecipeUsage(true))
if (action != ButtonState.RELEASE)
return false;
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
if (!overlay.isPresent())
return false;
double mouseX = client.mouse.getX();
double mouseY = client.mouse.getY();
EntryListWidget widget = getEntryListWidget();
if (widget == null)
return false;
return widget.mouseClicked(mouseX, mouseY, GLFW_MOUSE_BUTTON_2);
})
.cooldown(true) .cooldown(true)
.build()); .register();
ButtonBinding.builder(new Identifier("rei", "show_recipe"))
.buttons(GLFW_GAMEPAD_BUTTON_LEFT_THUMB)
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
.action(handleShowRecipeUsage(false))
.cooldown(true)
.register();
} }
@Override @Override
public boolean requireMouseOnScreen(Screen screen) public boolean requireMouseOnScreen(Screen screen)
{ {
return isViewingScreen(screen); return isViewingScreen(screen) || screen instanceof PreRecipeViewingScreen;
}
@Override
public @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Screen screen, int mouseX, int mouseY)
{
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
if (overlay.isPresent() && overlay.get().isInside(mouseX, mouseY)) {
EntryListWidget widget = getEntryListWidget();
if (widget == null)
return null;
Pair<Integer, Integer> slot = this.getSlotAt(widget, mouseX, mouseY, false);
if (slot != null && slot != INVALID_SLOT)
return slot;
} else if (isViewingScreen(screen)) {
for (Element element : screen.children()) {
Pair<Integer, Integer> slot = this.getSlotAt(element, mouseX, mouseY, true);
if (slot != null && slot != INVALID_SLOT)
return slot;
}
}
return null;
}
private @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Element element, int mouseX, int mouseY, boolean allowEmpty)
{
if (element instanceof EntryWidget) {
EntryWidget entry = (EntryWidget) element;
if (entry.containsMouse(mouseX, mouseY)) {
if (!allowEmpty && entry.entries().isEmpty())
return INVALID_SLOT;
return Pair.of(entry.getBounds().getX() + 1, entry.getBounds().getY() + 1);
}
} else if (element instanceof EntryListWidget) {
List<EntryListEntryWidget> entries = ((EntryListWidgetAccessor) element).getEntries();
for (EntryListEntryWidget entry : entries) {
Pair<Integer, Integer> slot = this.getSlotAt(entry, mouseX, mouseY, allowEmpty);
if (slot != null && slot != INVALID_SLOT)
return slot;
}
} else if (!(element instanceof ButtonWidget) && element instanceof WidgetWithBounds) {
for (Element child : ((WidgetWithBounds) element).children()) {
Pair<Integer, Integer> slot = this.getSlotAt(child, mouseX, mouseY, allowEmpty);
if (slot != null && slot != INVALID_SLOT)
return slot;
}
}
return null;
} }
private static boolean isViewingScreen(Screen screen) private static boolean isViewingScreen(Screen screen)
@@ -106,6 +172,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) {
@@ -116,9 +193,79 @@ public class ReiCompat implements CompatHandler
return ENTRY_LIST_WIDGET; return ENTRY_LIST_WIDGET;
} }
private static @Nullable EntryStack getCurrentStack(@NotNull MinecraftClient client)
{
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();
if (isViewingScreen(client.currentScreen)) {
for (Element element : client.currentScreen.children()) {
EntryStack stack = getCurrentStack(element, x, y);
if (stack != null)
return stack;
}
}
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
if (!overlay.isPresent())
return RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
EntryListWidget widget = getEntryListWidget();
if (widget == null)
return RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
return getCurrentStack(widget, x, y);
}
private static @Nullable EntryStack getCurrentStack(@NotNull Element element, double mouseX, double mouseY)
{
if (element instanceof EntryWidget) {
EntryWidget entry = (EntryWidget) element;
if (entry.containsMouse(mouseX, mouseY))
return ((EntryWidgetAccessor) entry).lambdacontrols_getCurrentEntry();
} else if (element instanceof EntryListWidget) {
List<EntryListEntryWidget> entries = ((EntryListWidgetAccessor) element).getEntries();
for (EntryListEntryWidget entry : entries) {
if (entry.containsMouse(mouseX, mouseY)) {
return ((EntryWidgetAccessor) entry).lambdacontrols_getCurrentEntry();
}
}
} else if (!(element instanceof ButtonWidget) && element instanceof WidgetWithBounds) {
for (Element child : ((WidgetWithBounds) element).children()) {
EntryStack stack = getCurrentStack(child, mouseX, mouseY);
if (stack != null)
return stack;
}
}
return null;
}
private static PressAction handleShowRecipeUsage(boolean usage)
{
return (client, button, value, action) -> {
if (action.isUnpressed())
return false;
EntryStack stack = RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
if (stack == null) {
stack = getCurrentStack(client);
}
if (stack != null && !stack.isEmpty()) {
stack = stack.copy();
if (usage) {
return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addUsagesFor(stack).setInputNotice(stack).fillPreferredOpenedCategory());
} else {
return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addRecipesFor(stack).setOutputNotice(stack).fillPreferredOpenedCategory());
}
}
return false;
};
}
private static PressAction handlePage(boolean next) private static PressAction handlePage(boolean next)
{ {
return (client, button, action) -> { return (client, button, value, action) -> {
if (action == ButtonState.RELEASE) if (action == ButtonState.RELEASE)
return false; return false;
@@ -148,31 +295,81 @@ public class ReiCompat implements CompatHandler
*/ */
private static PressAction handleTab(boolean next) private static PressAction handleTab(boolean next)
{ {
return (client, button, action) -> { return (client, button, value, action) -> {
if (action != ButtonState.RELEASE) if (action != ButtonState.RELEASE)
return false; return false;
if (client.currentScreen instanceof RecipeViewingScreen) { if (client.currentScreen instanceof RecipeViewingScreen) {
RecipeViewingScreenAccessor screen = (RecipeViewingScreenAccessor) client.currentScreen; RecipeViewingScreenAccessor screen = (RecipeViewingScreenAccessor) client.currentScreen;
if (next) if (next)
screen.getCategoryNext().onPressed(); screen.getCategoryNext().onClick();
else else
screen.getCategoryBack().onPressed(); screen.getCategoryBack().onClick();
return true; return true;
} else if (client.currentScreen instanceof VillagerRecipeViewingScreen) { } else if (client.currentScreen instanceof VillagerRecipeViewingScreen) {
VillagerRecipeViewingScreenAccessor screen = (VillagerRecipeViewingScreenAccessor) client.currentScreen; VillagerRecipeViewingScreenAccessor screen = (VillagerRecipeViewingScreenAccessor) client.currentScreen;
List<RecipeCategory<?>> categories = screen.getCategories(); List<RecipeCategory<?>> categories = screen.getCategories();
int currentTab = screen.getSelectedCategoryIndex(); int currentTab = screen.getSelectedCategoryIndex();
int nextTab = currentTab + (next ? 1 : -1); screen.setSelectedCategoryIndex(getNextIndex(currentTab, categories.size(), next));
if (nextTab < 0) screen.setSelectedRecipeIndex(0);
nextTab = categories.size() - 1;
else if (nextTab >= categories.size())
nextTab = 0;
screen.setSelectedCategoryIndex(nextTab);
screen.lambdacontrols_init(); screen.lambdacontrols_init();
return true; return true;
} }
return false; return false;
}; };
} }
private static PressAction handleRecipe(boolean next)
{
return (client, button, value, action) -> {
if (action.isUnpressed())
return false;
if (client.currentScreen instanceof RecipeViewingScreen) {
RecipeViewingScreenAccessor screen = (RecipeViewingScreenAccessor) client.currentScreen;
if (next)
screen.getRecipeNext().onClick();
else
screen.getRecipeBack().onClick();
return true;
} else if (client.currentScreen instanceof VillagerRecipeViewingScreen) {
VillagerRecipeViewingScreenAccessor screen = (VillagerRecipeViewingScreenAccessor) client.currentScreen;
List<RecipeCategory<?>> categories = screen.getCategories();
int currentTab = screen.getSelectedCategoryIndex();
List<RecipeDisplay> recipes = screen.getCategoryMap().get(categories.get(currentTab));
if (recipes.size() == 0)
return true;
int currentRecipe = screen.getSelectedRecipeIndex();
int nextRecipe = getNextIndex(currentRecipe, recipes.size(), next);
if (nextRecipe == 0) {
screen.getScrolling().scrollTo(0.0, true);
} else if (nextRecipe == recipes.size() - 1) {
screen.getScrolling().scrollTo(screen.getScrolling().getMaxScroll(), true);
} else {
double scrollAmount = screen.getScrolling().getMaxScroll() / (float) recipes.size();
screen.getScrolling().offset(next ? scrollAmount : -scrollAmount, true);
}
screen.setSelectedRecipeIndex(nextRecipe);
screen.lambdacontrols_init();
return true;
}
return false;
};
}
private static int getNextIndex(int currentIndex, int size, boolean next)
{
int nextIndex = currentIndex + (next ? 1 : -1);
if (nextIndex < 0)
nextIndex = size - 1;
else if (nextIndex >= size)
nextIndex = 0;
return nextIndex;
}
} }

View File

@@ -0,0 +1,31 @@
/*
* 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.mixin;
import me.shedaniel.rei.gui.widget.EntryListEntryWidget;
import me.shedaniel.rei.gui.widget.EntryListWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
/**
* Represents an accessor to REI's EntryListWidget.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.5.0
*/
@Mixin(value = EntryListWidget.class, remap = false)
public interface EntryListWidgetAccessor
{
@Accessor(value = "entries")
List<EntryListEntryWidget> getEntries();
}

View File

@@ -0,0 +1,29 @@
/*
* 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.mixin;
import me.shedaniel.rei.api.EntryStack;
import me.shedaniel.rei.gui.widget.EntryWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
/**
* Represents an accessor to REI's EntryWidget.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.5.0
*/
@Mixin(value = EntryWidget.class, remap = false)
public interface EntryWidgetAccessor
{
@Invoker("getCurrentEntry")
EntryStack lambdacontrols_getCurrentEntry();
}

View File

@@ -9,8 +9,8 @@
package me.lambdaurora.lambdacontrols.client.compat.mixin; package me.lambdaurora.lambdacontrols.client.compat.mixin;
import me.shedaniel.rei.api.widgets.Button;
import me.shedaniel.rei.gui.RecipeViewingScreen; import me.shedaniel.rei.gui.RecipeViewingScreen;
import me.shedaniel.rei.gui.widget.ButtonWidget;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
@@ -18,15 +18,21 @@ import org.spongepowered.asm.mixin.gen.Accessor;
* Represents an accessor to REI's RecipeViewingScreen. * Represents an accessor to REI's RecipeViewingScreen.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.5.0
* @since 1.2.0 * @since 1.2.0
*/ */
@Mixin(RecipeViewingScreen.class) @Mixin(value = RecipeViewingScreen.class, remap = false)
public interface RecipeViewingScreenAccessor public interface RecipeViewingScreenAccessor
{ {
@Accessor("categoryBack") @Accessor("categoryBack")
ButtonWidget getCategoryBack(); Button getCategoryBack();
@Accessor("categoryNext") @Accessor("categoryNext")
ButtonWidget getCategoryNext(); Button getCategoryNext();
@Accessor("recipeBack")
Button getRecipeBack();
@Accessor("recipeNext")
Button getRecipeNext();
} }

View File

@@ -9,33 +9,48 @@
package me.lambdaurora.lambdacontrols.client.compat.mixin; package me.lambdaurora.lambdacontrols.client.compat.mixin;
import me.shedaniel.clothconfig2.api.ScrollingContainer;
import me.shedaniel.rei.api.RecipeCategory; import me.shedaniel.rei.api.RecipeCategory;
import me.shedaniel.rei.api.RecipeDisplay;
import me.shedaniel.rei.gui.VillagerRecipeViewingScreen; import me.shedaniel.rei.gui.VillagerRecipeViewingScreen;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
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 java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Represents an accessor to REI's VillagerRecipeViewingScreen. * Represents an accessor to REI's VillagerRecipeViewingScreen.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.5.0
* @since 1.2.0 * @since 1.2.0
*/ */
@Mixin(VillagerRecipeViewingScreen.class) @Mixin(VillagerRecipeViewingScreen.class)
public interface VillagerRecipeViewingScreenAccessor public interface VillagerRecipeViewingScreenAccessor
{ {
@Accessor("categories") @Accessor(value = "categoryMap", remap = false)
Map<RecipeCategory<?>, List<RecipeDisplay>> getCategoryMap();
@Accessor(value = "categories", remap = false)
List<RecipeCategory<?>> getCategories(); List<RecipeCategory<?>> getCategories();
@Accessor("selectedCategoryIndex") @Accessor(value = "selectedCategoryIndex", remap = false)
int getSelectedCategoryIndex(); int getSelectedCategoryIndex();
@Accessor("selectedCategoryIndex") @Accessor(value = "selectedCategoryIndex", remap = false)
void setSelectedCategoryIndex(int selectedCategoryIndex); void setSelectedCategoryIndex(int selectedCategoryIndex);
@Accessor(value = "selectedRecipeIndex", remap = false)
int getSelectedRecipeIndex();
@Accessor(value = "selectedRecipeIndex", remap = false)
void setSelectedRecipeIndex(int selectedRecipeIndex);
@Accessor(value = "scrolling", remap = false)
ScrollingContainer getScrolling();
@Invoker("init") @Invoker("init")
void lambdacontrols_init(); void lambdacontrols_init();
} }

View File

@@ -13,7 +13,8 @@ import me.lambdaurora.lambdacontrols.client.ButtonState;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.GameOptions; import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.resource.language.I18n; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.Identifier; import org.aperlambda.lambdacommon.Identifier;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.aperlambda.lambdacommon.utils.function.PairPredicate; import org.aperlambda.lambdacommon.utils.function.PairPredicate;
@@ -31,7 +32,7 @@ import static org.lwjgl.glfw.GLFW.*;
* Represents a button binding. * Represents a button binding.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.1.0 * @version 1.5.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class ButtonBinding implements Nameable public class ButtonBinding implements Nameable
@@ -43,41 +44,45 @@ public class ButtonBinding implements Nameable
public static final ButtonCategory MISC_CATEGORY; public static final ButtonCategory MISC_CATEGORY;
public static final ButtonBinding ATTACK = new Builder("attack").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true)).onlyInGame().register(); public static final ButtonBinding ATTACK = new Builder("attack").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true)).onlyInGame().register();
public static final ButtonBinding BACK = new Builder("back").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false)).onlyInGame().register(); public static final ButtonBinding BACK = new Builder("back").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false))
public static final ButtonBinding CHAT = new Builder("chat").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT).onlyInGame().cooldown(true).register(); .action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding DROP_ITEM = new Builder("drop_item").buttons(GLFW_GAMEPAD_BUTTON_B).onlyInGame().cooldown(true).register(); public static final ButtonBinding CHAT = new Builder("chat").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT).onlyInGame().cooldown().register();
public static final ButtonBinding FORWARD = new Builder("forward").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true)).onlyInGame().register(); public static final ButtonBinding DROP_ITEM = new Builder("drop_item").buttons(GLFW_GAMEPAD_BUTTON_B).onlyInGame().cooldown().register();
public static final ButtonBinding FORWARD = new Builder("forward").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding HOTBAR_LEFT = new Builder("hotbar_left").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER) public static final ButtonBinding HOTBAR_LEFT = new Builder("hotbar_left").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.action(InputHandlers.handleHotbar(false)).onlyInGame().cooldown(true).register(); .action(InputHandlers.handleHotbar(false)).onlyInGame().cooldown().register();
public static final ButtonBinding HOTBAR_RIGHT = new Builder("hotbar_right").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER) public static final ButtonBinding HOTBAR_RIGHT = new Builder("hotbar_right").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
.action(InputHandlers.handleHotbar(true)).onlyInGame().cooldown(true).register(); .action(InputHandlers.handleHotbar(true)).onlyInGame().cooldown().register();
public static final ButtonBinding INVENTORY = new Builder("inventory").buttons(GLFW_GAMEPAD_BUTTON_Y).onlyInGame().cooldown(true).register(); public static final ButtonBinding INVENTORY = new Builder("inventory").buttons(GLFW_GAMEPAD_BUTTON_Y).onlyInGame().cooldown().register();
public static final ButtonBinding JUMP = new Builder("jump").buttons(GLFW_GAMEPAD_BUTTON_A).onlyInGame().register(); public static final ButtonBinding JUMP = new Builder("jump").buttons(GLFW_GAMEPAD_BUTTON_A).onlyInGame().register();
public static final ButtonBinding LEFT = new Builder("left").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false)).onlyInGame().register(); public static final ButtonBinding LEFT = new Builder("left").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false))
public static final ButtonBinding PAUSE_GAME = new Builder("pause_game").buttons(GLFW_GAMEPAD_BUTTON_START).action(InputHandlers::handlePauseGame).cooldown(true).register(); .action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding PICK_BLOCK = new Builder("pick_block").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT).onlyInGame().cooldown(true).register(); public static final ButtonBinding PAUSE_GAME = new Builder("pause_game").buttons(GLFW_GAMEPAD_BUTTON_START).action(InputHandlers::handlePauseGame).cooldown().register();
public static final ButtonBinding PICK_BLOCK = new Builder("pick_block").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT).onlyInGame().cooldown().register();
public static final ButtonBinding PLAYER_LIST = new Builder("player_list").buttons(GLFW_GAMEPAD_BUTTON_BACK).onlyInGame().register(); public static final ButtonBinding PLAYER_LIST = new Builder("player_list").buttons(GLFW_GAMEPAD_BUTTON_BACK).onlyInGame().register();
public static final ButtonBinding RIGHT = new Builder("right").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true)).register(); public static final ButtonBinding RIGHT = new Builder("right").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding SCREENSHOT = new Builder("screenshot").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_A) public static final ButtonBinding SCREENSHOT = new Builder("screenshot").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_A)
.action(InputHandlers::handleScreenshot).cooldown(true).register(); .action(InputHandlers::handleScreenshot).cooldown().register();
public static final ButtonBinding SLOT_DOWN = new Builder("slot_down").buttons(GLFW_GAMEPAD_BUTTON_DPAD_DOWN) public static final ButtonBinding SLOT_DOWN = new Builder("slot_down").buttons(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)
.action(InputHandlers.handleInventorySlotPad(1)).onlyInInventory().cooldown(true).register(); .action(InputHandlers.handleInventorySlotPad(1)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_LEFT = new Builder("slot_left").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT) public static final ButtonBinding SLOT_LEFT = new Builder("slot_left").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT)
.action(InputHandlers.handleInventorySlotPad(3)).onlyInInventory().cooldown(true).register(); .action(InputHandlers.handleInventorySlotPad(3)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_RIGHT = new Builder("slot_right").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT) public static final ButtonBinding SLOT_RIGHT = new Builder("slot_right").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)
.action(InputHandlers.handleInventorySlotPad(2)).onlyInInventory().cooldown(true).register(); .action(InputHandlers.handleInventorySlotPad(2)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_UP = new Builder("slot_up").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP) public static final ButtonBinding SLOT_UP = new Builder("slot_up").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP)
.action(InputHandlers.handleInventorySlotPad(0)).onlyInInventory().cooldown(true).register(); .action(InputHandlers.handleInventorySlotPad(0)).onlyInInventory().cooldown().register();
public static final ButtonBinding SMOOTH_CAMERA = new Builder("toggle_smooth_camera").cooldown(true).register(); public static final ButtonBinding SMOOTH_CAMERA = new Builder("toggle_smooth_camera").onlyInGame().cooldown().register();
public static final ButtonBinding SNEAK = new Builder("sneak").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB) public static final ButtonBinding SNEAK = new Builder("sneak").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)
.actions(PressAction.DEFAULT_ACTION, InputHandlers::handleToggleSneak).onlyInGame().cooldown(true).register(); .actions(InputHandlers::handleToggleSneak).onlyInGame().cooldown().register();
public static final ButtonBinding SPRINT = new Builder("sprint").buttons(GLFW_GAMEPAD_BUTTON_LEFT_THUMB).register(); public static final ButtonBinding SPRINT = new Builder("sprint").buttons(GLFW_GAMEPAD_BUTTON_LEFT_THUMB).onlyInGame().register();
public static final ButtonBinding SWAP_HANDS = new Builder("swap_hands").buttons(GLFW_GAMEPAD_BUTTON_X).cooldown(true).register(); public static final ButtonBinding SWAP_HANDS = new Builder("swap_hands").buttons(GLFW_GAMEPAD_BUTTON_X).onlyInGame().cooldown().register();
public static final ButtonBinding TAB_LEFT = new Builder("tab_back").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER) public static final ButtonBinding TAB_LEFT = new Builder("tab_back").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.action(InputHandlers.handleHotbar(false)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown(true).register(); .action(InputHandlers.handleHotbar(false)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown().register();
public static final ButtonBinding TAB_RIGHT = new Builder("tab_next").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER) public static final ButtonBinding TAB_RIGHT = new Builder("tab_next").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
.action(InputHandlers.handleHotbar(true)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown(true).register(); .action(InputHandlers.handleHotbar(true)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown().register();
public static final ButtonBinding TOGGLE_PERSPECTIVE = new Builder("toggle_perspective").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_Y).cooldown(true).register(); public static final ButtonBinding TOGGLE_PERSPECTIVE = new Builder("toggle_perspective").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_Y).cooldown().register();
public static final ButtonBinding USE = new Builder("use").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true)).register(); public static final ButtonBinding USE = new Builder("use").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true)).register();
private int[] button; private int[] button;
@@ -227,7 +232,7 @@ public class ButtonBinding implements Nameable
* @param client The client instance. * @param client The client instance.
* @param state The state. * @param state The state.
*/ */
public void handle(@NotNull MinecraftClient client, @NotNull ButtonState state) public void handle(@NotNull MinecraftClient client, float value, @NotNull ButtonState state)
{ {
if (state == ButtonState.REPEAT && this.hasCooldown && this.cooldown != 0) if (state == ButtonState.REPEAT && this.hasCooldown && this.cooldown != 0)
return; return;
@@ -236,7 +241,7 @@ public class ButtonBinding implements Nameable
} }
for (int i = this.actions.size() - 1; i >= 0; i--) { for (int i = this.actions.size() - 1; i >= 0; i--) {
if (this.actions.get(i).press(client, this, state)) if (this.actions.get(i).press(client, this, value, state))
break; break;
} }
} }
@@ -252,8 +257,7 @@ public class ButtonBinding implements Nameable
* *
* @return The translation key. * @return The translation key.
*/ */
public @NotNull public @NotNull String getTranslationKey()
String getTranslationKey()
{ {
return "lambdacontrols.action." + this.getName(); return "lambdacontrols.action." + this.getName();
} }
@@ -263,12 +267,19 @@ public class ButtonBinding implements Nameable
* *
* @return The key binding equivalent. * @return The key binding equivalent.
*/ */
public @NotNull public @NotNull Optional<KeyBinding> asKeyBinding()
Optional<KeyBinding> asKeyBinding()
{ {
return Optional.ofNullable(this.mcKeyBinding); return Optional.ofNullable(this.mcKeyBinding);
} }
@Override
public String toString()
{
return "ButtonBinding{id=\"" + this.key + "\","
+ "hasCooldown=" + this.hasCooldown
+ "}";
}
/** /**
* Returns the specified axis as a button. * Returns the specified axis as a button.
* *
@@ -281,6 +292,18 @@ public class ButtonBinding implements Nameable
return positive ? 100 + axis : 200 + axis; return positive ? 100 + axis : 200 + axis;
} }
/**
* Returns whether the specified button is an axis or not.
*
* @param button The button.
* @return True if the button is an axis, else false.
*/
public static boolean isAxis(int button)
{
button %= 500;
return button >= 100;
}
/** /**
* Returns the second Joycon's specified button code. * Returns the second Joycon's specified button code.
* *
@@ -320,64 +343,63 @@ public class ButtonBinding implements Nameable
* @param button The button. * @param button The button.
* @return The localized name of the button. * @return The localized name of the button.
*/ */
public static @NotNull public static @NotNull Text getLocalizedButtonName(int button)
String getLocalizedButtonName(int button)
{ {
switch (button % 500) { switch (button % 500) {
case -1: case -1:
return I18n.translate("key.keyboard.unknown"); return new TranslatableText("key.keyboard.unknown");
case GLFW_GAMEPAD_BUTTON_A: case GLFW_GAMEPAD_BUTTON_A:
return I18n.translate("lambdacontrols.button.a"); return new TranslatableText("lambdacontrols.button.a");
case GLFW_GAMEPAD_BUTTON_B: case GLFW_GAMEPAD_BUTTON_B:
return I18n.translate("lambdacontrols.button.b"); return new TranslatableText("lambdacontrols.button.b");
case GLFW_GAMEPAD_BUTTON_X: case GLFW_GAMEPAD_BUTTON_X:
return I18n.translate("lambdacontrols.button.x"); return new TranslatableText("lambdacontrols.button.x");
case GLFW_GAMEPAD_BUTTON_Y: case GLFW_GAMEPAD_BUTTON_Y:
return I18n.translate("lambdacontrols.button.y"); return new TranslatableText("lambdacontrols.button.y");
case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER: case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
return I18n.translate("lambdacontrols.button.left_bumper"); return new TranslatableText("lambdacontrols.button.left_bumper");
case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER: case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
return I18n.translate("lambdacontrols.button.right_bumper"); return new TranslatableText("lambdacontrols.button.right_bumper");
case GLFW_GAMEPAD_BUTTON_BACK: case GLFW_GAMEPAD_BUTTON_BACK:
return I18n.translate("lambdacontrols.button.back"); return new TranslatableText("lambdacontrols.button.back");
case GLFW_GAMEPAD_BUTTON_START: case GLFW_GAMEPAD_BUTTON_START:
return I18n.translate("lambdacontrols.button.start"); return new TranslatableText("lambdacontrols.button.start");
case GLFW_GAMEPAD_BUTTON_GUIDE: case GLFW_GAMEPAD_BUTTON_GUIDE:
return I18n.translate("lambdacontrols.button.guide"); return new TranslatableText("lambdacontrols.button.guide");
case GLFW_GAMEPAD_BUTTON_LEFT_THUMB: case GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
return I18n.translate("lambdacontrols.button.left_thumb"); return new TranslatableText("lambdacontrols.button.left_thumb");
case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB: case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
return I18n.translate("lambdacontrols.button.right_thumb"); return new TranslatableText("lambdacontrols.button.right_thumb");
case GLFW_GAMEPAD_BUTTON_DPAD_UP: case GLFW_GAMEPAD_BUTTON_DPAD_UP:
return I18n.translate("lambdacontrols.button.dpad_up"); return new TranslatableText("lambdacontrols.button.dpad_up");
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT: case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT:
return I18n.translate("lambdacontrols.button.dpad_right"); return new TranslatableText("lambdacontrols.button.dpad_right");
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN: case GLFW_GAMEPAD_BUTTON_DPAD_DOWN:
return I18n.translate("lambdacontrols.button.dpad_down"); return new TranslatableText("lambdacontrols.button.dpad_down");
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT: case GLFW_GAMEPAD_BUTTON_DPAD_LEFT:
return I18n.translate("lambdacontrols.button.dpad_left"); return new TranslatableText("lambdacontrols.button.dpad_left");
case 100: case 100:
return I18n.translate("lambdacontrols.axis.left_x+"); return new TranslatableText("lambdacontrols.axis.left_x+");
case 101: case 101:
return I18n.translate("lambdacontrols.axis.left_y+"); return new TranslatableText("lambdacontrols.axis.left_y+");
case 102: case 102:
return I18n.translate("lambdacontrols.axis.right_x+"); return new TranslatableText("lambdacontrols.axis.right_x+");
case 103: case 103:
return I18n.translate("lambdacontrols.axis.right_y+"); return new TranslatableText("lambdacontrols.axis.right_y+");
case 104: case 104:
return I18n.translate("lambdacontrols.axis.left_trigger"); return new TranslatableText("lambdacontrols.axis.left_trigger");
case 105: case 105:
return I18n.translate("lambdacontrols.axis.right_trigger"); return new TranslatableText("lambdacontrols.axis.right_trigger");
case 200: case 200:
return I18n.translate("lambdacontrols.axis.left_x-"); return new TranslatableText("lambdacontrols.axis.left_x-");
case 201: case 201:
return I18n.translate("lambdacontrols.axis.left_y-"); return new TranslatableText("lambdacontrols.axis.left_y-");
case 202: case 202:
return I18n.translate("lambdacontrols.axis.right_x-"); return new TranslatableText("lambdacontrols.axis.right_x-");
case 203: case 203:
return I18n.translate("lambdacontrols.axis.right_y-"); return new TranslatableText("lambdacontrols.axis.right_y-");
default: default:
return I18n.translate("lambdacontrols.button.unknown", button); return new TranslatableText("lambdacontrols.button.unknown", button);
} }
} }
@@ -411,11 +433,36 @@ public class ButtonBinding implements Nameable
)); ));
} }
/**
* Returns a builder instance.
*
* @param identifier The identifier of the button binding.
* @return The builder instance
* @since 1.5.0
*/
public static Builder builder(@NotNull Identifier identifier)
{
return new Builder(identifier);
}
/**
* Returns a builder instance.
*
* @param identifier The identifier of the button binding.
* @return The builder instance.
* @since 1.5.0
*/
public static Builder builder(@NotNull net.minecraft.util.Identifier identifier)
{
return new Builder(identifier);
}
/** /**
* Represents a quick {@link ButtonBinding} builder. * Represents a quick {@link ButtonBinding} builder.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.1.0 * @version 1.5.0
* @since 1.1.0 * @since 1.1.0
*/ */
public static class Builder public static class Builder
@@ -543,6 +590,17 @@ public class ButtonBinding implements Nameable
return this; return this;
} }
/**
* Puts a cooldown on the {@link ButtonBinding}.
*
* @return The builder instance.
* @since 1.5.0
*/
public Builder cooldown()
{
return this.cooldown(true);
}
/** /**
* Sets the category of the {@link ButtonBinding}. * Sets the category of the {@link ButtonBinding}.
* *

View File

@@ -9,13 +9,20 @@
package me.lambdaurora.lambdacontrols.client.controller; package me.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWGamepadState; import org.lwjgl.glfw.GLFWGamepadState;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.Buffer; import java.nio.Buffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -34,7 +41,7 @@ import static org.lwjgl.BufferUtils.createByteBuffer;
* Represents a controller. * Represents a controller.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.0.0 * @version 1.4.3
* @since 1.0.0 * @since 1.0.0
*/ */
public class Controller implements Nameable public class Controller implements Nameable
@@ -167,14 +174,47 @@ public class Controller implements Nameable
public static void updateMappings() public static void updateMappings()
{ {
try { try {
File mappingsFile = new File("config/gamecontrollerdb.txt"); if (!LambdaControlsClient.MAPPINGS_FILE.exists())
if (!mappingsFile.exists())
return; return;
LambdaControlsClient.get().log("Updating controller mappings..."); LambdaControlsClient.get().log("Updating controller mappings...");
ByteBuffer buffer = ioResourceToBuffer(mappingsFile.getPath(), 1024); ByteBuffer buffer = ioResourceToBuffer(LambdaControlsClient.MAPPINGS_FILE.getPath(), 1024);
GLFW.glfwUpdateGamepadMappings(buffer); GLFW.glfwUpdateGamepadMappings(buffer);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
MemoryStack memoryStack = MemoryStack.stackPush();
try {
PointerBuffer pointerBuffer = memoryStack.mallocPointer(1);
int i = GLFW.glfwGetError(pointerBuffer);
if (i != 0) {
long l = pointerBuffer.get();
String string = l == 0L ? "" : MemoryUtil.memUTF8(l);
MinecraftClient client = MinecraftClient.getInstance();
if (client != null) {
client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT,
new TranslatableText("lambdacontrols.controller.mappings.error"), new LiteralText(string)));
}
}
} catch (Throwable e) {
/* Ignored :concern: */
} finally {
memoryStack.close();
}
if (LambdaControlsClient.get().config.hasDebug()) {
for (int i = GLFW.GLFW_JOYSTICK_1; i <= GLFW.GLFW_JOYSTICK_16; i++) {
Controller controller = byId(i);
if (!controller.isConnected())
continue;
LambdaControls.get().log(String.format("Controller #%d name: \"%s\"\n GUID: %s\n Gamepad: %s",
controller.id,
controller.getName(),
controller.getGuid(),
controller.isGamepad()));
}
}
} }
} }

View File

@@ -10,21 +10,23 @@
package me.lambdaurora.lambdacontrols.client.controller; package me.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.client.ButtonState; import me.lambdaurora.lambdacontrols.client.ButtonState;
import me.lambdaurora.lambdacontrols.client.LambdaInput;
import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor; import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor; import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.RecipeBookWidgetAccessor; import me.lambdaurora.lambdacontrols.client.mixin.RecipeBookWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor; import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.advancement.AdvancementTab; import net.minecraft.client.gui.screen.advancement.AdvancementTab;
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen; import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
import net.minecraft.client.gui.screen.ingame.ContainerScreen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen; import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.client.gui.screen.recipebook.RecipeGroupButtonWidget; import net.minecraft.client.gui.screen.recipebook.RecipeGroupButtonWidget;
import net.minecraft.client.options.Option;
import net.minecraft.client.util.ScreenshotUtils; import net.minecraft.client.util.ScreenshotUtils;
import net.minecraft.container.Slot;
import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemGroup;
import net.minecraft.screen.slot.Slot;
import org.aperlambda.lambdacommon.utils.Pair; import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -38,7 +40,7 @@ import java.util.stream.Collectors;
* Represents some input handlers. * Represents some input handlers.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.4.3
* @since 1.1.0 * @since 1.1.0
*/ */
public class InputHandlers public class InputHandlers
@@ -49,7 +51,7 @@ public class InputHandlers
public static PressAction handleHotbar(boolean next) public static PressAction handleHotbar(boolean next)
{ {
return (client, button, action) -> { return (client, button, value, action) -> {
if (action == ButtonState.RELEASE) if (action == ButtonState.RELEASE)
return false; return false;
@@ -74,6 +76,8 @@ public class InputHandlers
RecipeBookWidgetAccessor recipeBook = (RecipeBookWidgetAccessor) ((InventoryScreen) client.currentScreen).getRecipeBookWidget(); RecipeBookWidgetAccessor recipeBook = (RecipeBookWidgetAccessor) ((InventoryScreen) client.currentScreen).getRecipeBookWidget();
List<RecipeGroupButtonWidget> tabs = recipeBook.getTabButtons(); List<RecipeGroupButtonWidget> tabs = recipeBook.getTabButtons();
RecipeGroupButtonWidget currentTab = recipeBook.getCurrentTab(); RecipeGroupButtonWidget currentTab = recipeBook.getCurrentTab();
if (currentTab == null)
return false;
int nextTab = tabs.indexOf(currentTab) + (next ? 1 : -1); int nextTab = tabs.indexOf(currentTab) + (next ? 1 : -1);
if (nextTab < 0) if (nextTab < 0)
nextTab = tabs.size() - 1; nextTab = tabs.size() - 1;
@@ -83,10 +87,13 @@ public class InputHandlers
recipeBook.setCurrentTab(currentTab = tabs.get(nextTab)); recipeBook.setCurrentTab(currentTab = tabs.get(nextTab));
currentTab.setToggled(true); currentTab.setToggled(true);
recipeBook.lambdacontrols_refreshResults(true); recipeBook.lambdacontrols_refreshResults(true);
return true;
} else if (client.currentScreen instanceof AdvancementsScreen) { } else if (client.currentScreen instanceof AdvancementsScreen) {
AdvancementsScreenAccessor screen = (AdvancementsScreenAccessor) client.currentScreen; AdvancementsScreenAccessor screen = (AdvancementsScreenAccessor) client.currentScreen;
List<AdvancementTab> tabs = screen.getTabs().values().stream().distinct().collect(Collectors.toList()); List<AdvancementTab> tabs = screen.getTabs().values().stream().distinct().collect(Collectors.toList());
AdvancementTab tab = screen.getSelectedTab(); AdvancementTab tab = screen.getSelectedTab();
if (tab == null)
return false;
for (int i = 0; i < tabs.size(); i++) { for (int i = 0; i < tabs.size(); i++) {
if (tabs.get(i).equals(tab)) { if (tabs.get(i).equals(tab)) {
int nextTab = i + (next ? 1 : -1); int nextTab = i + (next ? 1 : -1);
@@ -98,19 +105,20 @@ public class InputHandlers
break; break;
} }
} }
return true;
} }
return false; return false;
}; };
} }
public static boolean handlePauseGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, @NotNull ButtonState action) public static boolean handlePauseGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, float value, @NotNull ButtonState action)
{ {
if (action == ButtonState.PRESS) { if (action == ButtonState.PRESS) {
// If in game, then pause the game. // If in game, then pause the game.
if (client.currentScreen == null) if (client.currentScreen == null)
client.openPauseMenu(false); client.openPauseMenu(false);
else if (client.currentScreen instanceof ContainerScreen && client.player != null) // If the current screen is a container then close it. else if (client.currentScreen instanceof HandledScreen && client.player != null) // If the current screen is a container then close it.
client.player.closeContainer(); client.player.closeHandledScreen();
else // Else just close the current screen. else // Else just close the current screen.
client.currentScreen.onClose(); client.currentScreen.onClose();
} }
@@ -125,31 +133,35 @@ public class InputHandlers
* @param action The action done on the binding. * @param action The action done on the binding.
* @return True if handled, else false. * @return True if handled, else false.
*/ */
public static boolean handleScreenshot(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, @NotNull ButtonState action) public static boolean handleScreenshot(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, float value, @NotNull ButtonState action)
{ {
if (action == ButtonState.PRESS) if (action == ButtonState.RELEASE)
ScreenshotUtils.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(), ScreenshotUtils.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(),
text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text))); text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text)));
return true; return true;
} }
public static boolean handleToggleSneak(@NotNull MinecraftClient client, @NotNull ButtonBinding button, @NotNull ButtonState action) public static boolean handleToggleSneak(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action)
{ {
if (client.player != null && !client.player.abilities.flying) { button.asKeyBinding().ifPresent(binding -> {
button.asKeyBinding().filter(binding -> action == ButtonState.PRESS).ifPresent(binding -> ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(!binding.isPressed())); boolean sneakToggled = client.options.sneakToggled;
return true; if (client.player.abilities.flying && sneakToggled)
} client.options.sneakToggled = false;
return false; binding.setPressed(button.pressed);
if (client.player.abilities.flying && sneakToggled)
client.options.sneakToggled = true;
});
return true;
} }
public static PressAction handleInventorySlotPad(int direction) public static PressAction handleInventorySlotPad(int direction)
{ {
return (client, binding, action) -> { return (client, binding, value, action) -> {
if (!(client.currentScreen instanceof ContainerScreen && action != ButtonState.RELEASE)) if (!(client.currentScreen instanceof HandledScreen && action != ButtonState.RELEASE))
return false; return false;
ContainerScreen inventory = (ContainerScreen) client.currentScreen; HandledScreen inventory = (HandledScreen) client.currentScreen;
ContainerScreenAccessor accessor = (ContainerScreenAccessor) inventory; HandledScreenAccessor accessor = (HandledScreenAccessor) inventory;
int guiLeft = accessor.getX(); int guiLeft = accessor.getX();
int guiTop = accessor.getY(); int guiTop = accessor.getY();
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();
@@ -159,17 +171,17 @@ public class InputHandlers
Slot mouseSlot = accessor.lambdacontrols_getSlotAt(mouseX, mouseY); Slot mouseSlot = accessor.lambdacontrols_getSlotAt(mouseX, mouseY);
// Finds the closest slot in the GUI within 14 pixels. // Finds the closest slot in the GUI within 14 pixels.
Optional<Slot> closestSlot = inventory.getContainer().slots.parallelStream() Optional<Slot> closestSlot = inventory.getScreenHandler().slots.parallelStream()
.filter(Predicate.isEqual(mouseSlot).negate()) .filter(Predicate.isEqual(mouseSlot).negate())
.map(slot -> { .map(slot -> {
int posX = guiLeft + slot.xPosition + 8; int posX = guiLeft + slot.x + 8;
int posY = guiTop + slot.yPosition + 8; int posY = guiTop + slot.y + 8;
int otherPosX = (int) mouseX; int otherPosX = (int) mouseX;
int otherPosY = (int) mouseY; int otherPosY = (int) mouseY;
if (mouseSlot != null) { if (mouseSlot != null) {
otherPosX = guiLeft + mouseSlot.xPosition + 8; otherPosX = guiLeft + mouseSlot.x + 8;
otherPosY = guiTop + mouseSlot.yPosition + 8; otherPosY = guiTop + mouseSlot.y + 8;
} }
// Distance between the slot and the cursor. // Distance between the slot and the cursor.
@@ -177,13 +189,13 @@ public class InputHandlers
return Pair.of(slot, distance); return Pair.of(slot, distance);
}).filter(entry -> { }).filter(entry -> {
Slot slot = entry.key; Slot slot = entry.key;
int posX = guiLeft + slot.xPosition + 8; int posX = guiLeft + slot.x + 8;
int posY = guiTop + slot.yPosition + 8; int posY = guiTop + slot.y + 8;
int otherPosX = (int) mouseX; int otherPosX = (int) mouseX;
int otherPosY = (int) mouseY; int otherPosY = (int) mouseY;
if (mouseSlot != null) { if (mouseSlot != null) {
otherPosX = guiLeft + mouseSlot.xPosition + 8; otherPosX = guiLeft + mouseSlot.x + 8;
otherPosY = guiTop + mouseSlot.yPosition + 8; otherPosY = guiTop + mouseSlot.y + 8;
} }
if (direction == 0) if (direction == 0)
return posY < otherPosY; return posY < otherPosY;
@@ -201,8 +213,8 @@ public class InputHandlers
if (closestSlot.isPresent()) { if (closestSlot.isPresent()) {
Slot slot = closestSlot.get(); Slot slot = closestSlot.get();
int x = guiLeft + slot.xPosition + 8; int x = guiLeft + slot.x + 8;
int y = guiTop + slot.yPosition + 8; int y = guiTop + slot.y + 8;
InputManager.queueMousePosition(x * (double) client.getWindow().getWidth() / (double) client.getWindow().getScaledWidth(), InputManager.queueMousePosition(x * (double) client.getWindow().getWidth() / (double) client.getWindow().getScaledWidth(),
y * (double) client.getWindow().getHeight() / (double) client.getWindow().getScaledHeight()); y * (double) client.getWindow().getHeight() / (double) client.getWindow().getScaledHeight());
return true; return true;
@@ -235,6 +247,20 @@ public class InputHandlers
return client.currentScreen == null; return client.currentScreen == null;
} }
/**
* Returns whether the client is in a non-interactive screen (which means require mouse input) or not.
*
* @param client The client instance.
* @param binding The affected binding.
* @return True if the client is in a non-interactive screen, else false.
*/
public static boolean inNonInteractiveScreens(@NotNull MinecraftClient client, @NotNull ButtonBinding binding)
{
if (client.currentScreen == null)
return false;
return !LambdaInput.isScreenInteractive(client.currentScreen);
}
/** /**
* Returns whether the client is in an inventory or not. * Returns whether the client is in an inventory or not.
* *
@@ -244,7 +270,7 @@ public class InputHandlers
*/ */
public static boolean inInventory(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) public static boolean inInventory(@NotNull MinecraftClient client, @NotNull ButtonBinding binding)
{ {
return client.currentScreen instanceof ContainerScreen; return client.currentScreen instanceof HandledScreen;
} }
/** /**

View File

@@ -15,8 +15,11 @@ 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.MinecraftClient;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.util.InputUtil;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import org.aperlambda.lambdacommon.Identifier; import org.aperlambda.lambdacommon.Identifier;
import org.aperlambda.lambdacommon.utils.Pair;
import org.aperlambda.lambdacommon.utils.function.PairPredicate; import org.aperlambda.lambdacommon.utils.function.PairPredicate;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -30,19 +33,20 @@ import java.util.stream.Stream;
* Represents an input manager for controllers. * Represents an input manager for controllers.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.4.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class InputManager public class InputManager
{ {
public static final InputManager INPUT_MANAGER = new InputManager(); public static final InputManager INPUT_MANAGER = new InputManager();
private static final List<ButtonBinding> BINDINGS = new ArrayList<>(); private static final List<ButtonBinding> BINDINGS = new ArrayList<>();
private static final List<ButtonCategory> CATEGORIES = new ArrayList<>(); private static final List<ButtonCategory> CATEGORIES = new ArrayList<>();
public static final Map<Integer, ButtonState> STATES = new HashMap<>(); public static final Map<Integer, ButtonState> STATES = new HashMap<>();
private int prevTargetMouseX = 0; public static final Map<Integer, Float> BUTTON_VALUES = new HashMap<>();
private int prevTargetMouseY = 0; private int prevTargetMouseX = 0;
private int targetMouseX = 0; private int prevTargetMouseY = 0;
private int targetMouseY = 0; private int targetMouseX = 0;
private int targetMouseY = 0;
protected InputManager() protected InputManager()
{ {
@@ -242,6 +246,23 @@ public class InputManager
return state; return state;
} }
public static float getBindingValue(@NotNull ButtonBinding binding, @NotNull ButtonState state)
{
if (state.isUnpressed())
return 0.f;
float value = 0.f;
for (int btn : binding.getButton()) {
if (ButtonBinding.isAxis(btn)) {
value = BUTTON_VALUES.getOrDefault(btn, 1.f);
break;
} else {
value = 1.f;
}
}
return value;
}
/** /**
* Returns whether the button has duplicated bindings. * Returns whether the button has duplicated bindings.
* *
@@ -315,7 +336,7 @@ public class InputManager
public static void updateBindings(@NotNull MinecraftClient client) public static void updateBindings(@NotNull MinecraftClient client)
{ {
List<Integer> skipButtons = new ArrayList<>(); List<Integer> skipButtons = new ArrayList<>();
Map<ButtonBinding, ButtonState> states = new HashMap<>(); Map<ButtonBinding, Pair<ButtonState, Float>> states = new HashMap<>();
for (ButtonBinding binding : BINDINGS) { for (ButtonBinding binding : BINDINGS) {
ButtonState state = binding.isAvailable(client) ? getBindingState(binding) : ButtonState.NONE; ButtonState state = binding.isAvailable(client) ? getBindingState(binding) : ButtonState.NONE;
if (skipButtons.stream().anyMatch(btn -> containsButton(binding.getButton(), btn))) { if (skipButtons.stream().anyMatch(btn -> containsButton(binding.getButton(), btn))) {
@@ -324,16 +345,24 @@ public class InputManager
else else
state = ButtonState.NONE; state = ButtonState.NONE;
} }
if (state == ButtonState.RELEASE && !binding.pressed) {
state = ButtonState.NONE;
}
binding.pressed = state.isPressed(); binding.pressed = state.isPressed();
binding.update(); binding.update();
if (binding.pressed) if (binding.pressed)
Arrays.stream(binding.getButton()).forEach(skipButtons::add); Arrays.stream(binding.getButton()).forEach(skipButtons::add);
states.put(binding, state);
float value = getBindingValue(binding, state);
states.put(binding, Pair.of(state, value));
} }
states.forEach((binding, state) -> { states.forEach((binding, state) -> {
if (state != ButtonState.NONE) { if (state.key != ButtonState.NONE) {
binding.handle(client, state); binding.handle(client, state.value, state.key);
} }
}); });
} }
@@ -358,4 +387,34 @@ public class InputManager
{ {
return CATEGORIES.stream(); return CATEGORIES.stream();
} }
/**
* Returns a new key binding instance.
*
* @param id The identifier of the key binding.
* @param type The type.
* @param code The code.
* @param category The category of the key binding.
* @return The key binding.
* @see #makeKeyBinding(Identifier, InputUtil.Type, int, String)
*/
public static @NotNull KeyBinding makeKeyBinding(@NotNull net.minecraft.util.Identifier id, InputUtil.Type type, int code, @NotNull String category)
{
return makeKeyBinding(new Identifier(id.getNamespace(), id.getPath()), type, code, category);
}
/**
* Returns a new key binding instance.
*
* @param id The identifier of the key binding.
* @param type The type.
* @param code The code.
* @param category The category of the key binding.
* @return The key binding.
* @see #makeKeyBinding(net.minecraft.util.Identifier, InputUtil.Type, int, String)
*/
public static @NotNull KeyBinding makeKeyBinding(@NotNull Identifier id, InputUtil.Type type, int code, @NotNull String category)
{
return new KeyBinding(String.format("key.%s.%s", id.getNamespace(), id.getName()), type, code, category);
}
} }

View File

@@ -0,0 +1,98 @@
/*
* 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.controller;
import me.lambdaurora.lambdacontrols.client.ButtonState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import org.jetbrains.annotations.NotNull;
/**
* Represents the movement handler.
*
* @author LambdAurora
* @version 1.4.0
* @since 1.4.0
*/
public final class MovementHandler implements PressAction
{
public static final MovementHandler HANDLER = new MovementHandler();
private boolean shouldOverrideMovement = false;
private boolean pressingForward = false;
private boolean pressingBack = false;
private boolean pressingLeft = false;
private boolean pressingRight = false;
private float movementForward = 0.f;
private float movementSideways = 0.f;
private MovementHandler()
{
}
/**
* Applies movement input of this handler to the player's input.
*
* @param player The client player.
*/
public void applyMovement(@NotNull ClientPlayerEntity player)
{
if (!this.shouldOverrideMovement)
return;
player.input.pressingForward = this.pressingForward;
player.input.pressingBack = this.pressingBack;
player.input.pressingLeft = this.pressingLeft;
player.input.pressingRight = this.pressingRight;
player.input.movementForward = this.movementForward;
player.input.movementSideways = this.movementSideways;
this.shouldOverrideMovement = false;
}
@Override
public boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action)
{
if (client.currentScreen != null || client.player == null)
return this.shouldOverrideMovement = false;
int direction = 0;
if (button == ButtonBinding.FORWARD || button == ButtonBinding.LEFT)
direction = 1;
else if (button == ButtonBinding.BACK || button == ButtonBinding.RIGHT)
direction = -1;
if (direction == 0)
return false;
this.shouldOverrideMovement = true;
value = (float) Math.pow(value, 2);
if (button == ButtonBinding.FORWARD || button == ButtonBinding.BACK) {
// Handle forward movement.
this.pressingForward = direction > 0;
this.pressingBack = direction < 0;
this.movementForward = direction * value;
// Slowing down if sneaking.
if (client.player.input.sneaking)
this.movementForward *= 0.3D;
} else {
// Handle sideways movement.
this.pressingLeft = direction > 0;
this.pressingRight = direction < 0;
this.movementSideways = direction * value;
// Slowing down if sneaking.
if (client.player.input.sneaking)
this.movementSideways *= 0.3D;
}
return true;
}
}

View File

@@ -12,22 +12,28 @@ package me.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.client.ButtonState; import me.lambdaurora.lambdacontrols.client.ButtonState;
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.StickyKeyBinding;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Represents a press action callback. * Represents a press action callback.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.1.0 * @version 1.4.3
* @since 1.0.0 * @since 1.0.0
*/ */
@FunctionalInterface @FunctionalInterface
public interface PressAction public interface PressAction
{ {
PressAction DEFAULT_ACTION = (client, button, action) -> { PressAction DEFAULT_ACTION = (client, button, value, action) -> {
if (action == ButtonState.REPEAT || client.currentScreen != null) if (action == ButtonState.REPEAT || client.currentScreen != null)
return false; return false;
button.asKeyBinding().ifPresent(binding -> ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(button.isButtonDown())); button.asKeyBinding().ifPresent(binding -> {
if (binding instanceof StickyKeyBinding)
binding.setPressed(button.pressed);
else
((KeyBindingAccessor) binding).lambdacontrols_handlePressState(button.isButtonDown());
});
return true; return true;
}; };
@@ -37,5 +43,5 @@ public interface PressAction
* @param client The client instance. * @param client The client instance.
* @param action The action done. * @param action The action done.
*/ */
boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, @NotNull ButtonState action); boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action);
} }

View File

@@ -9,10 +9,13 @@
package me.lambdaurora.lambdacontrols.client.gui; package me.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.spruceui.AbstractIconButtonWidget; import me.lambdaurora.spruceui.AbstractIconButtonWidget;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import org.aperlambda.lambdacommon.utils.Pair; import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -33,25 +36,25 @@ public class ControllerButtonWidget extends AbstractIconButtonWidget
public void update() public void update()
{ {
int length = binding.getButton().length; int length = binding.getButton().length;
this.setMessage(this.binding.isNotBound() ? I18n.translate("lambdacontrols.not_bound") : this.setMessage(this.binding.isNotBound() ? LambdaControls.NOT_BOUND_TEXT :
(length > 0 ? ButtonBinding.getLocalizedButtonName(binding.getButton()[0]) : "<>")); (length > 0 ? ButtonBinding.getLocalizedButtonName(binding.getButton()[0]) : new LiteralText("<>")));
} }
@Override @Override
public String getMessage() public Text getMessage()
{ {
if (this.binding.getButton().length > 1) if (this.binding.getButton().length > 1)
return ""; return LiteralText.EMPTY;
return super.getMessage(); return super.getMessage();
} }
@Override @Override
protected int renderIcon(int mouseX, int mouseY, float delta, int x, int y) protected int renderIcon(MatrixStack matrices, int mouseX, int mouseY, float delta, int x, int y)
{ {
if (this.binding.getButton().length > 1) { if (this.binding.getButton().length > 1) {
x += (this.width / 2 - this.iconWidth / 2) - 4; x += (this.width / 2 - this.iconWidth / 2) - 4;
} }
Pair<Integer, Integer> size = LambdaControlsRenderer.drawButton(x, y, this.binding, MinecraftClient.getInstance()); Pair<Integer, Integer> size = LambdaControlsRenderer.drawButton(matrices, x, y, this.binding, MinecraftClient.getInstance());
this.iconWidth = size.key; this.iconWidth = size.key;
return size.value; return size.value;
} }

View File

@@ -13,16 +13,19 @@ import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.InputManager; import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.spruceui.SpruceButtonWidget; import me.lambdaurora.spruceui.SpruceButtonWidget;
import me.lambdaurora.spruceui.SpruceTexts;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen; import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.function.Predicates; import org.aperlambda.lambdacommon.utils.function.Predicates;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* Represents the controls screen. * Represents the controls screen.
@@ -56,26 +59,30 @@ public class ControllerControlsScreen extends Screen
@Override @Override
protected void init() protected void init()
{ {
this.addButton(new SpruceButtonWidget(this.width / 2 - 155, 18, this.hideSettings ? 310 : 150, 20, I18n.translate("lambdacontrols.menu.keyboard_controls"), this.addButton(new SpruceButtonWidget(this.width / 2 - 155, 18, this.hideSettings ? 310 : 150, 20,
btn -> this.minecraft.openScreen(new ControlsOptionsScreen(this, this.minecraft.options)))); new TranslatableText("lambdacontrols.menu.keyboard_controls"),
btn -> this.client.openScreen(new ControlsOptionsScreen(this, this.client.options))));
if (!this.hideSettings) if (!this.hideSettings)
this.addButton(new SpruceButtonWidget(this.width / 2 - 155 + 160, 18, 150, 20, I18n.translate("menu.options"), this.addButton(new SpruceButtonWidget(this.width / 2 - 155 + 160, 18, 150, 20,
btn -> this.minecraft.openScreen(new LambdaControlsSettingsScreen(this, true)))); SpruceTexts.MENU_OPTIONS,
this.bindingsListWidget = new ControlsListWidget(this, this.minecraft); btn -> this.client.openScreen(new LambdaControlsSettingsScreen(this, true))));
this.bindingsListWidget = new ControlsListWidget(this, this.client);
this.children.add(this.bindingsListWidget); this.children.add(this.bindingsListWidget);
this.resetButton = this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 150, 20, I18n.translate("controls.resetAll"), this.resetButton = this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 150, 20,
btn -> InputManager.streamBindings().forEach(binding -> this.mod.config.setButtonBinding(binding, binding.getDefaultButton())))); SpruceTexts.CONTROLS_RESET_ALL,
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20, I18n.translate("gui.done"), btn -> InputManager.streamBindings().collect(Collectors.toSet()).forEach(binding -> this.mod.config.setButtonBinding(binding, binding.getDefaultButton()))));
btn -> this.minecraft.openScreen(this.parent))); this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20,
SpruceTexts.GUI_DONE,
btn -> this.client.openScreen(this.parent)));
} }
@Override @Override
public void render(int mouseX, int mouseY, float delta) public void render(MatrixStack matrices, int mouseX, int mouseY, float delta)
{ {
this.renderBackground(); this.renderBackground(matrices);
this.bindingsListWidget.render(mouseX, mouseY, delta); this.bindingsListWidget.render(matrices, mouseX, mouseY, delta);
this.drawCenteredString(this.font, this.title.asFormattedString(), this.width / 2, 8, 16777215); drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 8, 16777215);
this.resetButton.active = InputManager.streamBindings().anyMatch(Predicates.not(ButtonBinding::isDefault)); this.resetButton.active = InputManager.streamBindings().anyMatch(Predicates.not(ButtonBinding::isDefault));
super.render(mouseX, mouseY, delta); super.render(matrices, mouseX, mouseY, delta);
} }
} }

View File

@@ -12,6 +12,7 @@ package me.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.ButtonCategory; import me.lambdaurora.lambdacontrols.client.controller.ButtonCategory;
import me.lambdaurora.lambdacontrols.client.controller.InputManager; import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.spruceui.SpruceTexts;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@@ -20,6 +21,10 @@ import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ElementListWidget; import net.minecraft.client.gui.widget.ElementListWidget;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.MutableText;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -33,7 +38,7 @@ import java.util.List;
*/ */
public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Entry> public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Entry>
{ {
private static final int[] UNBOUND = new int[0]; private static final int[] UNBOUND = new int[]{-1};
private final ControllerControlsScreen gui; private final ControllerControlsScreen gui;
private int field_2733; private int field_2733;
@@ -48,7 +53,7 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
this.addEntry(new CategoryEntry(category)); this.addEntry(new CategoryEntry(category));
category.getBindings().forEach(binding -> { category.getBindings().forEach(binding -> {
int i = client.textRenderer.getStringWidth(I18n.translate(binding.getTranslationKey())); int i = client.textRenderer.getWidth(I18n.translate(binding.getTranslationKey()));
if (i > this.field_2733) { if (i > this.field_2733) {
this.field_2733 = i; this.field_2733 = i;
} }
@@ -59,9 +64,9 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
} }
@Override @Override
protected int getScrollbarPosition() protected int getScrollbarPositionX()
{ {
return super.getScrollbarPosition() + 15; return super.getScrollbarPositionX() + 15;
} }
@Override @Override
@@ -88,28 +93,28 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
gui.waiting = true; gui.waiting = true;
}) })
{ {
protected String getNarrationMessage() protected MutableText getNarrationMessage()
{ {
return binding.isNotBound() ? I18n.translate("narrator.controls.unbound", bindingName) : I18n.translate("narrator.controls.bound", bindingName, super.getNarrationMessage()); return binding.isNotBound() ? new TranslatableText("narrator.controls.unbound", bindingName) : new TranslatableText("narrator.controls.bound", bindingName, super.getNarrationMessage());
} }
}; };
this.resetButton = new ButtonWidget(0, 0, 50, 20, I18n.translate("controls.reset"), this.resetButton = new ButtonWidget(0, 0, 50, 20, new TranslatableText("controls.reset"),
btn -> gui.mod.config.setButtonBinding(binding, binding.getDefaultButton())) btn -> gui.mod.config.setButtonBinding(binding, binding.getDefaultButton()))
{ {
protected String getNarrationMessage() protected MutableText getNarrationMessage()
{ {
return I18n.translate("narrator.controls.reset", bindingName); return new TranslatableText("narrator.controls.reset", bindingName);
} }
}; };
this.unboundButton = new ButtonWidget(0, 0, 50, 20, I18n.translate("lambdacontrols.menu.unbound"), this.unboundButton = new ButtonWidget(0, 0, 50, 20, SpruceTexts.OPTIONS_GENERIC_UNBOUND,
btn -> { btn -> {
gui.mod.config.setButtonBinding(binding, UNBOUND); gui.mod.config.setButtonBinding(binding, UNBOUND);
gui.focusedBinding = null; gui.focusedBinding = null;
}) })
{ {
protected String getNarrationMessage() protected MutableText getNarrationMessage()
{ {
return I18n.translate("lambdacontrols.narrator.unbound", bindingName); return new TranslatableText("lambdacontrols.narrator.unbound", bindingName);
} }
}; };
} }
@@ -121,34 +126,38 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
} }
@Override @Override
public void render(int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovering, float delta) public void render(MatrixStack matrices, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovering, float delta)
{ {
boolean focused = gui.focusedBinding == this.binding; boolean focused = gui.focusedBinding == this.binding;
TextRenderer textRenderer = ControlsListWidget.this.minecraft.textRenderer; TextRenderer textRenderer = ControlsListWidget.this.client.textRenderer;
String bindingName = this.bindingName; String bindingName = this.bindingName;
float var10002 = (float) (x + 70 - ControlsListWidget.this.field_2733); float var10002 = (float) (x + 70 - ControlsListWidget.this.field_2733);
int var10003 = y + height / 2; int var10003 = y + height / 2;
textRenderer.draw(bindingName, var10002, (float) (var10003 - 9 / 2), 16777215); textRenderer.draw(matrices, bindingName, var10002, (float) (var10003 - 9 / 2), 16777215);
this.resetButton.x = this.unboundButton.x = x + 190; this.resetButton.x = this.unboundButton.x = x + 190;
this.resetButton.y = this.unboundButton.y = y; this.resetButton.y = this.unboundButton.y = y;
this.resetButton.active = !this.binding.isDefault(); this.resetButton.active = !this.binding.isDefault();
if (focused) if (focused)
this.unboundButton.render(mouseX, mouseY, delta); this.unboundButton.render(matrices, mouseX, mouseY, delta);
else else
this.resetButton.render(mouseX, mouseY, delta); this.resetButton.render(matrices, mouseX, mouseY, delta);
this.editButton.x = x + 75; this.editButton.x = x + 75;
this.editButton.y = y; this.editButton.y = y;
this.editButton.update(); this.editButton.update();
if (focused) { if (focused) {
this.editButton.setMessage(Formatting.WHITE + "> " + Formatting.YELLOW + this.editButton.getMessage() + Formatting.WHITE + " <"); MutableText text = new LiteralText("> ").formatted(Formatting.WHITE);
text.append(this.editButton.getMessage().copy().formatted(Formatting.YELLOW));
this.editButton.setMessage(text.append(new LiteralText(" <").formatted(Formatting.WHITE)));
} else if (!this.binding.isNotBound() && InputManager.hasDuplicatedBindings(this.binding)) { } else if (!this.binding.isNotBound() && InputManager.hasDuplicatedBindings(this.binding)) {
this.editButton.setMessage(Formatting.RED + this.editButton.getMessage()); MutableText text = this.editButton.getMessage().copy();
this.editButton.setMessage(text.formatted(Formatting.RED));
} else if (this.binding.isNotBound()) { } else if (this.binding.isNotBound()) {
this.editButton.setMessage(Formatting.GOLD + this.editButton.getMessage()); MutableText text = this.editButton.getMessage().copy();
this.editButton.setMessage(text.formatted(Formatting.GOLD));
} }
this.editButton.render(mouseX, mouseY, delta); this.editButton.render(matrices, mouseX, mouseY, delta);
} }
public boolean mouseClicked(double mouseX, double mouseY, int button) public boolean mouseClicked(double mouseX, double mouseY, int button)
@@ -175,13 +184,13 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
public CategoryEntry(@NotNull ButtonCategory category) public CategoryEntry(@NotNull ButtonCategory category)
{ {
this.name = category.getTranslatedName(); this.name = category.getTranslatedName();
this.nameWidth = ControlsListWidget.this.minecraft.textRenderer.getStringWidth(this.name); this.nameWidth = ControlsListWidget.this.client.textRenderer.getWidth(this.name);
} }
@Override @Override
public void render(int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovering, float delta) public void render(MatrixStack matrices, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovering, float delta)
{ {
ControlsListWidget.this.minecraft.textRenderer.draw(this.name, (float) (ControlsListWidget.this.minecraft.currentScreen.width / 2 - this.nameWidth / 2), ControlsListWidget.this.client.textRenderer.draw(matrices, this.name, (float) (ControlsListWidget.this.client.currentScreen.width / 2 - this.nameWidth / 2),
(float) ((y + height) - 9 - 1), 16777215); (float) ((y + height) - 9 - 1), 16777215);
} }

View File

@@ -13,15 +13,13 @@ 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.render.Tessellator;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.Matrix4f; import net.minecraft.client.util.Window;
import net.minecraft.client.util.math.Rotation3; 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;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@@ -34,26 +32,27 @@ import org.jetbrains.annotations.Nullable;
* Represents the LambdaControls HUD. * Represents the LambdaControls HUD.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.2.0 * @version 1.3.2
* @since 1.0.0 * @since 1.0.0
*/ */
public class LambdaControlsHud extends Hud public class LambdaControlsHud extends Hud
{ {
private final LambdaControlsClient mod; private final LambdaControlsClient mod;
private MinecraftClient client; private MinecraftClient client;
private int attackWidth = 0; private int attackWidth = 0;
private int attackButtonWidth = 0; private int attackButtonWidth = 0;
private int dropItemWidth = 0; private int dropItemWidth = 0;
private int dropItemButtonWidth = 0; private int dropItemButtonWidth = 0;
private int inventoryWidth = 0; private int inventoryWidth = 0;
private int inventoryButtonWidth = 0; private int inventoryButtonWidth = 0;
private int swapHandsWidth = 0; private int swapHandsWidth = 0;
private int swapHandsButtonWidth = 0; private int swapHandsButtonWidth = 0;
private int useWidth = 0; private int useWidth = 0;
private int useButtonWidth = 0; private int useButtonWidth = 0;
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)
{ {
@@ -79,26 +78,37 @@ public class LambdaControlsHud extends Hud
/** /**
* Renders the LambdaControls' HUD. * Renders the LambdaControls' HUD.
*/ */
public void render(float tickDelta) @Override
public void render(MatrixStack matrices, float tickDelta)
{ {
if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER && this.client.currentScreen == null) { if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER && this.client.currentScreen == null) {
int y = bottom(2); int y = bottom(2);
this.renderFirstIcons(this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y); this.renderFirstIcons(matrices, this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y);
this.renderSecondIcons(this.mod.config.getHudSide() == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y); this.renderSecondIcons(matrices, this.mod.config.getHudSide() == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y);
VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); this.renderFirstSection(matrices, this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y);
Matrix4f matrix4f = Rotation3.identity().getMatrix(); this.renderSecondSection(matrices, this.mod.config.getHudSide() == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y);
this.renderFirstSection(this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y, immediate, matrix4f); }
this.renderSecondSection(this.mod.config.getHudSide() == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y, immediate, matrix4f);
immediate.draw(); 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(int x, int y) public void renderFirstIcons(MatrixStack matrices, int x, int y)
{ {
int offset = 2 + this.inventoryWidth + this.inventoryButtonWidth + 4; int offset = 2 + this.inventoryWidth + this.inventoryButtonWidth + 4;
int currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x : x - this.inventoryButtonWidth; int currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x : x - this.inventoryButtonWidth;
this.drawButton(currentX, y, ButtonBinding.INVENTORY, true); this.drawButton(matrices, currentX, y, ButtonBinding.INVENTORY, true);
this.drawButton(currentX += (this.mod.config.getHudSide() == HudSide.LEFT ? offset : -offset), y, ButtonBinding.SWAP_HANDS, true); this.drawButton(matrices, currentX += (this.mod.config.getHudSide() == HudSide.LEFT ? offset : -offset), y, ButtonBinding.SWAP_HANDS, true);
offset = 2 + this.swapHandsWidth + this.dropItemButtonWidth + 4; offset = 2 + this.swapHandsWidth + this.dropItemButtonWidth + 4;
if (this.client.options.showSubtitles && this.mod.config.getHudSide() == HudSide.RIGHT) { if (this.client.options.showSubtitles && this.mod.config.getHudSide() == HudSide.RIGHT) {
currentX += -offset; currentX += -offset;
@@ -106,17 +116,17 @@ public class LambdaControlsHud extends Hud
currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x : x - this.dropItemButtonWidth; currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x : x - this.dropItemButtonWidth;
y -= 24; y -= 24;
} }
this.drawButton(currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()); this.drawButton(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty());
} }
public void renderSecondIcons(int x, int y) public void renderSecondIcons(MatrixStack matrices, int x, int y)
{ {
int offset; int offset;
int currentX = x; int currentX = x;
if (!this.placeAction.isEmpty()) { if (!this.placeAction.isEmpty()) {
if (this.mod.config.getHudSide() == HudSide.LEFT) if (this.mod.config.getHudSide() == HudSide.LEFT)
currentX -= this.useButtonWidth; currentX -= this.useButtonWidth;
this.drawButton(currentX, y, ButtonBinding.USE, true); this.drawButton(matrices, currentX, y, ButtonBinding.USE, true);
offset = 2 + this.useWidth + 4; offset = 2 + this.useWidth + 4;
if (this.client.options.showSubtitles && this.mod.config.getHudSide() == HudSide.LEFT) { if (this.client.options.showSubtitles && this.mod.config.getHudSide() == HudSide.LEFT) {
currentX -= offset; currentX -= offset;
@@ -129,33 +139,33 @@ public class LambdaControlsHud extends Hud
if (this.mod.config.getHudSide() == HudSide.LEFT) if (this.mod.config.getHudSide() == HudSide.LEFT)
currentX -= this.attackButtonWidth; currentX -= this.attackButtonWidth;
this.drawButton(currentX, y, ButtonBinding.ATTACK, this.attackWidth != 0); this.drawButton(matrices, currentX, y, ButtonBinding.ATTACK, this.attackWidth != 0);
} }
public void renderFirstSection(int x, int y, @NotNull VertexConsumerProvider.Immediate immediate, @NotNull Matrix4f matrix4f) public void renderFirstSection(MatrixStack matrices, int x, int y)
{ {
int currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x + this.inventoryButtonWidth + 2 : x - this.inventoryButtonWidth - 2 - this.inventoryWidth; int currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x + this.inventoryButtonWidth + 2 : x - this.inventoryButtonWidth - 2 - this.inventoryWidth;
this.drawTip(currentX, y, ButtonBinding.INVENTORY, true, immediate, matrix4f); this.drawTip(matrices, currentX, y, ButtonBinding.INVENTORY, true);
currentX += this.mod.config.getHudSide() == HudSide.LEFT ? this.inventoryWidth + 4 + this.swapHandsButtonWidth + 2 currentX += this.mod.config.getHudSide() == HudSide.LEFT ? this.inventoryWidth + 4 + this.swapHandsButtonWidth + 2
: -this.swapHandsWidth - 2 - this.swapHandsButtonWidth - 4; : -this.swapHandsWidth - 2 - this.swapHandsButtonWidth - 4;
this.drawTip(currentX, y, ButtonBinding.SWAP_HANDS, true, immediate, matrix4f); this.drawTip(matrices, currentX, y, ButtonBinding.SWAP_HANDS, true);
if (this.client.options.showSubtitles && this.mod.config.getHudSide() == HudSide.RIGHT) { if (this.client.options.showSubtitles && this.mod.config.getHudSide() == HudSide.RIGHT) {
currentX += -this.dropItemWidth - 2 - this.dropItemButtonWidth - 4; currentX += -this.dropItemWidth - 2 - this.dropItemButtonWidth - 4;
} else { } else {
y -= 24; y -= 24;
currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x + this.dropItemButtonWidth + 2 : x - this.dropItemButtonWidth - 2 - this.dropItemWidth; currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x + this.dropItemButtonWidth + 2 : x - this.dropItemButtonWidth - 2 - this.dropItemWidth;
} }
this.drawTip(currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty(), immediate, matrix4f); this.drawTip(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty());
} }
public void renderSecondSection(int x, int y, @NotNull VertexConsumerProvider.Immediate immediate, @NotNull Matrix4f matrix4f) public void renderSecondSection(MatrixStack matrices, int x, int y)
{ {
int currentX = x; int currentX = x;
if (!this.placeAction.isEmpty()) { if (!this.placeAction.isEmpty()) {
currentX += this.mod.config.getHudSide() == HudSide.RIGHT ? this.useButtonWidth + 2 : -this.useButtonWidth - 2 - this.useWidth; currentX += this.mod.config.getHudSide() == HudSide.RIGHT ? this.useButtonWidth + 2 : -this.useButtonWidth - 2 - this.useWidth;
this.drawTip(currentX, y, this.placeAction, true, immediate, matrix4f); this.drawTip(matrices, currentX, y, this.placeAction, true);
if (this.client.options.showSubtitles && this.mod.config.getHudSide() == HudSide.LEFT) { if (this.client.options.showSubtitles && this.mod.config.getHudSide() == HudSide.LEFT) {
currentX -= 4; currentX -= 4;
@@ -167,7 +177,7 @@ public class LambdaControlsHud extends Hud
currentX += this.mod.config.getHudSide() == HudSide.RIGHT ? this.attackButtonWidth + 2 : -this.attackButtonWidth - 2 - this.attackWidth; currentX += this.mod.config.getHudSide() == HudSide.RIGHT ? this.attackButtonWidth + 2 : -this.attackButtonWidth - 2 - this.attackWidth;
this.drawTip(currentX, y, this.attackAction, this.attackWidth != 0, immediate, matrix4f); this.drawTip(matrices, currentX, y, this.attackAction, this.attackWidth != 0);
} }
@Override @Override
@@ -182,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 {
@@ -195,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) {
@@ -206,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.
@@ -236,27 +268,26 @@ public class LambdaControlsHud extends Hud
{ {
if (text == null || text.isEmpty()) if (text == null || text.isEmpty())
return 0; return 0;
return this.client.textRenderer.getStringWidth(I18n.translate(text)); return this.client.textRenderer.getWidth(I18n.translate(text));
} }
private void drawButton(int x, int y, @NotNull ButtonBinding button, boolean display) private void drawButton(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display)
{ {
if (display) if (display)
LambdaControlsRenderer.drawButton(x, y, button, this.client); LambdaControlsRenderer.drawButton(matrices, x, y, button, this.client);
} }
private void drawTip(int x, int y, @NotNull ButtonBinding button, boolean display, @NotNull VertexConsumerProvider.Immediate immediate, @NotNull Matrix4f matrix4f) private void drawTip(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display)
{ {
this.drawTip(x, y, button.getTranslationKey(), display, immediate, matrix4f); this.drawTip(matrices, x, y, button.getTranslationKey(), display);
} }
private void drawTip(int x, int y, @NotNull String action, boolean display, @NotNull VertexConsumerProvider.Immediate immediate, @NotNull Matrix4f matrix4f) private void drawTip(MatrixStack matrices, int x, int y, @NotNull String action, boolean display)
{ {
if (!display) if (!display)
return; return;
String translatedAction = I18n.translate(action); String translatedAction = I18n.translate(action);
int textY = (LambdaControlsRenderer.ICON_SIZE / 2 - this.client.textRenderer.fontHeight / 2) + 1; int textY = (LambdaControlsRenderer.ICON_SIZE / 2 - this.client.textRenderer.fontHeight / 2) + 1;
client.textRenderer.draw(translatedAction, (float) x, (float) (y + textY), 14737632, true, matrix4f, immediate, this.client.textRenderer.draw(matrices, translatedAction, (float) x, (float) (y + textY), 14737632);
false, 0, 15728880);
} }
} }

View File

@@ -11,27 +11,26 @@ 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.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor; import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.ingame.ContainerScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.container.Slot; import net.minecraft.screen.slot.Slot;
import org.aperlambda.lambdacommon.utils.Pair; 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.2.0 * @version 1.5.0
* @since 1.2.0 * @since 1.2.0
*/ */
public class LambdaControlsRenderer public class LambdaControlsRenderer
@@ -88,19 +87,19 @@ public class LambdaControlsRenderer
return width; return width;
} }
public static Pair<Integer, Integer> drawButton(int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient client) public static Pair<Integer, Integer> drawButton(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient client)
{ {
return drawButton(x, y, button.getButton(), client); return drawButton(matrices, x, y, button.getButton(), client);
} }
public static Pair<Integer, Integer> drawButton(int x, int y, int[] buttons, @NotNull MinecraftClient client) public static Pair<Integer, Integer> drawButton(MatrixStack matrices, int x, int y, int[] buttons, @NotNull MinecraftClient client)
{ {
int height = 0; int height = 0;
int length = 0; int length = 0;
int currentX = x; int currentX = x;
for (int i = 0; i < buttons.length; i++) { for (int i = 0; i < buttons.length; i++) {
int btn = buttons[i]; int btn = buttons[i];
int size = drawButton(currentX, y, btn, client); int size = drawButton(matrices, currentX, y, btn, client);
if (size > height) if (size > height)
height = size; height = size;
length += size; length += size;
@@ -113,7 +112,7 @@ public class LambdaControlsRenderer
} }
@SuppressWarnings("deprecated") @SuppressWarnings("deprecated")
public static int drawButton(int x, int y, int button, @NotNull MinecraftClient client) public static int drawButton(MatrixStack matrices, int x, int y, int button, @NotNull MinecraftClient client)
{ {
boolean second = false; boolean second = false;
if (button == -1) if (button == -1)
@@ -196,7 +195,7 @@ public class LambdaControlsRenderer
int assetSize = axis ? AXIS_SIZE : BUTTON_SIZE; int assetSize = axis ? AXIS_SIZE : BUTTON_SIZE;
RenderSystem.color4f(1.0F, second ? 0.0F : 1.0F, 1.0F, 1.0F); RenderSystem.color4f(1.0F, second ? 0.0F : 1.0F, 1.0F, 1.0F);
DrawableHelper.blit(x + (ICON_SIZE / 2 - assetSize / 2), y + (ICON_SIZE / 2 - assetSize / 2), DrawableHelper.drawTexture(matrices, x + (ICON_SIZE / 2 - assetSize / 2), y + (ICON_SIZE / 2 - assetSize / 2),
(float) buttonOffset, (float) (controllerType * (axis ? AXIS_SIZE : BUTTON_SIZE)), (float) buttonOffset, (float) (controllerType * (axis ? AXIS_SIZE : BUTTON_SIZE)),
assetSize, assetSize, assetSize, assetSize,
256, 256); 256, 256);
@@ -205,20 +204,20 @@ public class LambdaControlsRenderer
return ICON_SIZE; return ICON_SIZE;
} }
public static int drawButtonTip(int x, int y, @NotNull ButtonBinding button, boolean display, @NotNull MinecraftClient client) public static int drawButtonTip(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display, @NotNull MinecraftClient client)
{ {
return drawButtonTip(x, y, button.getButton(), button.getTranslationKey(), display, client); return drawButtonTip(matrices, x, y, button.getButton(), button.getTranslationKey(), display, client);
} }
public static int drawButtonTip(int x, int y, int[] button, @NotNull String action, boolean display, @NotNull MinecraftClient client) public static int drawButtonTip(MatrixStack matrices, int x, int y, int[] button, @NotNull String action, boolean display, @NotNull MinecraftClient client)
{ {
if (display) { if (display) {
int buttonWidth = drawButton(x, y, button, client).key; int buttonWidth = drawButton(matrices, x, y, button, client).key;
String translatedAction = I18n.translate(action); String translatedAction = I18n.translate(action);
int textY = (LambdaControlsRenderer.ICON_SIZE / 2 - client.textRenderer.fontHeight / 2) + 1; int textY = (LambdaControlsRenderer.ICON_SIZE / 2 - client.textRenderer.fontHeight / 2) + 1;
return client.textRenderer.drawWithShadow(translatedAction, (float) (x + buttonWidth + 2), (float) (y + textY), 14737632); return client.textRenderer.drawWithShadow(matrices, translatedAction, (float) (x + buttonWidth + 2), (float) (y + textY), 14737632);
} }
return -10; return -10;
@@ -226,12 +225,12 @@ public class LambdaControlsRenderer
private static int getButtonTipWidth(@NotNull String action, @NotNull TextRenderer textRenderer) private static int getButtonTipWidth(@NotNull String action, @NotNull TextRenderer textRenderer)
{ {
return 15 + 5 + textRenderer.getStringWidth(action); return 15 + 5 + textRenderer.getWidth(action);
} }
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());
@@ -239,30 +238,26 @@ public class LambdaControlsRenderer
boolean hoverSlot = false; boolean hoverSlot = false;
if (client.currentScreen instanceof ContainerScreen) { if (client.currentScreen instanceof HandledScreen) {
ContainerScreen inventoryScreen = (ContainerScreen) client.currentScreen; HandledScreenAccessor inventoryScreen = (HandledScreenAccessor) client.currentScreen;
ContainerScreenAccessor accessor = (ContainerScreenAccessor) 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.getContainer().slots.parallelStream()
.map(slot -> {
int x = guiLeft + slot.xPosition + 8;
int y = guiTop + slot.yPosition + 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)); mouseX = guiLeft + slot.x;
return Pair.of(slot, distance); mouseY = guiTop + slot.y;
}).filter(entry -> entry.value <= 9.0) hoverSlot = true;
.min(Comparator.comparingDouble(p -> p.value)); }
}
if (closestSlot.isPresent()) { if (!hoverSlot) {
Slot slot = closestSlot.get().key; Pair<Integer, Integer> slot = LambdaControlsCompat.getSlotAt(client.currentScreen, mouseX, mouseY);
mouseX = guiLeft + slot.xPosition;
mouseY = guiTop + slot.yPosition; if (slot != null) {
mouseX = slot.getFirst();
mouseY = slot.getSecond();
hoverSlot = true; hoverSlot = true;
} }
} }
@@ -291,7 +286,7 @@ public class LambdaControlsRenderer
RenderSystem.disableDepthTest(); RenderSystem.disableDepthTest();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
DrawableHelper.blit(x, y, hoverSlot ? 16.F : 0.F, LambdaControlsClient.get().config.getVirtualMouseSkin().ordinal() * 16.F, 16, 16, 32, 64); DrawableHelper.drawTexture(matrices, x, y, hoverSlot ? 16.F : 0.F, LambdaControlsClient.get().config.getVirtualMouseSkin().ordinal() * 16.F, 16, 16, 32, 64);
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
} }
} }

View File

@@ -15,16 +15,21 @@ import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.Controller; import me.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.spruceui.SpruceButtonWidget; import me.lambdaurora.spruceui.SpruceButtonWidget;
import me.lambdaurora.spruceui.SpruceLabelWidget; import me.lambdaurora.spruceui.SpruceLabelWidget;
import me.lambdaurora.spruceui.SpruceTexts;
import me.lambdaurora.spruceui.Tooltip; import me.lambdaurora.spruceui.Tooltip;
import me.lambdaurora.spruceui.option.*; import me.lambdaurora.spruceui.option.*;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen; import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonListWidget; import net.minecraft.client.gui.widget.ButtonListWidget;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.Option; import net.minecraft.client.options.Option;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.MutableText;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.Util; import net.minecraft.util.Util;
@@ -35,7 +40,7 @@ import org.lwjgl.glfw.GLFW;
*/ */
public class LambdaControlsSettingsScreen extends Screen public class LambdaControlsSettingsScreen extends Screen
{ {
public static final String GAMEPAD_TOOL_URL = "http://generalarcade.com/gamepadtool/"; public static final String GAMEPAD_TOOL_URL = "https://generalarcade.com/gamepadtool/";
final LambdaControlsClient mod; final LambdaControlsClient mod;
private final Screen parent; private final Screen parent;
private final boolean hideControls; private final boolean hideControls;
@@ -48,6 +53,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
@@ -63,7 +69,9 @@ public class LambdaControlsSettingsScreen extends Screen
// Hud options // Hud options
private final Option hudEnableOption; private final Option hudEnableOption;
private final Option hudSideOption; private final Option hudSideOption;
private final String controllerMappingsUrlText = I18n.translate("lambdacontrols.controller.mappings.2", Formatting.GOLD.toString(), GAMEPAD_TOOL_URL, Formatting.RESET.toString()); private final MutableText controllerMappingsUrlText = new LiteralText("(")
.append(new LiteralText(GAMEPAD_TOOL_URL).formatted(Formatting.GOLD))
.append("),");
private ButtonListWidget list; private ButtonListWidget list;
private SpruceLabelWidget gamepadToolUrlLabel; private SpruceLabelWidget gamepadToolUrlLabel;
@@ -76,19 +84,19 @@ public class LambdaControlsSettingsScreen extends Screen
// General options // General options
this.autoSwitchModeOption = new SpruceBooleanOption("lambdacontrols.menu.auto_switch_mode", this.mod.config::hasAutoSwitchMode, this.autoSwitchModeOption = new SpruceBooleanOption("lambdacontrols.menu.auto_switch_mode", this.mod.config::hasAutoSwitchMode,
this.mod.config::setAutoSwitchMode, new TranslatableText("lambdacontrols.tooltip.auto_switch_mode"), true); this.mod.config::setAutoSwitchMode, new TranslatableText("lambdacontrols.tooltip.auto_switch_mode"), true);
this.rotationSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.rotation_speed", 0.0, 150.0, 0.5F, this.mod.config::getRotationSpeed, this.rotationSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.rotation_speed", 0.0, 100.0, 0.5F, this.mod.config::getRotationSpeed,
newValue -> { newValue -> {
synchronized (this.mod.config) { synchronized (this.mod.config) {
this.mod.config.setRotationSpeed(newValue); this.mod.config.setRotationSpeed(newValue);
} }
}, option -> option.getDisplayPrefix() + option.get(), }, option -> option.getDisplayText(new LiteralText(String.valueOf(option.get()))),
new TranslatableText("lambdacontrols.tooltip.rotation_speed")); new TranslatableText("lambdacontrols.tooltip.rotation_speed"));
this.mouseSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.mouse_speed", 0.0, 150.0, 0.5F, this.mod.config::getMouseSpeed, this.mouseSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.mouse_speed", 0.0, 150.0, 0.5F, this.mod.config::getMouseSpeed,
newValue -> { newValue -> {
synchronized (this.mod.config) { synchronized (this.mod.config) {
this.mod.config.setMouseSpeed(newValue); this.mod.config.setMouseSpeed(newValue);
} }
}, option -> option.getDisplayPrefix() + option.get(), }, option -> option.getDisplayText(new LiteralText(String.valueOf(option.get()))),
new TranslatableText("lambdacontrols.tooltip.mouse_speed")); new TranslatableText("lambdacontrols.tooltip.mouse_speed"));
this.resetOption = new SpruceResetOption(btn -> { this.resetOption = new SpruceResetOption(btn -> {
this.mod.config.reset(); this.mod.config.reset();
@@ -99,8 +107,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,
@@ -115,11 +125,11 @@ public class LambdaControlsSettingsScreen extends Screen
}, option -> { }, option -> {
String controllerName = this.mod.config.getController().getName(); String controllerName = this.mod.config.getController().getName();
if (!this.mod.config.getController().isConnected()) if (!this.mod.config.getController().isConnected())
return option.getDisplayPrefix() + Formatting.RED + controllerName; return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.RED));
else if (!this.mod.config.getController().isGamepad()) else if (!this.mod.config.getController().isGamepad())
return option.getDisplayPrefix() + Formatting.GOLD + controllerName; return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.GOLD));
else else
return option.getDisplayPrefix() + controllerName; return option.getDisplayText(new LiteralText(controllerName));
}, null); }, null);
this.secondControllerOption = new SpruceCyclingOption("lambdacontrols.menu.controller2", this.secondControllerOption = new SpruceCyclingOption("lambdacontrols.menu.controller2",
amount -> { amount -> {
@@ -131,16 +141,16 @@ public class LambdaControlsSettingsScreen extends Screen
}, option -> this.mod.config.getSecondController().map(controller -> { }, option -> this.mod.config.getSecondController().map(controller -> {
String controllerName = controller.getName(); String controllerName = controller.getName();
if (!controller.isConnected()) if (!controller.isConnected())
return option.getDisplayPrefix() + Formatting.RED + controllerName; return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.RED));
else if (!controller.isGamepad()) else if (!controller.isGamepad())
return option.getDisplayPrefix() + Formatting.GOLD + controllerName; return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.GOLD));
else else
return option.getDisplayPrefix() + controllerName; return option.getDisplayText(new LiteralText(controllerName));
}).orElse(option.getDisplayPrefix() + Formatting.RED + I18n.translate("options.off")), }).orElse(option.getDisplayText(SpruceTexts.OPTIONS_OFF.shallowCopy().formatted(Formatting.RED))),
new TranslatableText("lambdacontrols.tooltip.controller2")); new TranslatableText("lambdacontrols.tooltip.controller2"));
this.controllerTypeOption = new SpruceCyclingOption("lambdacontrols.menu.controller_type", this.controllerTypeOption = new SpruceCyclingOption("lambdacontrols.menu.controller_type",
amount -> this.mod.config.setControllerType(this.mod.config.getControllerType().next()), amount -> this.mod.config.setControllerType(this.mod.config.getControllerType().next()),
option -> option.getDisplayPrefix() + this.mod.config.getControllerType().getTranslatedName(), option -> option.getDisplayText(this.mod.config.getControllerType().getTranslatedText()),
new TranslatableText("lambdacontrols.tooltip.controller_type")); new TranslatableText("lambdacontrols.tooltip.controller_type"));
this.deadZoneOption = new SpruceDoubleOption("lambdacontrols.menu.dead_zone", 0.05, 1.0, 0.05F, this.mod.config::getDeadZone, this.deadZoneOption = new SpruceDoubleOption("lambdacontrols.menu.dead_zone", 0.05, 1.0, 0.05F, this.mod.config::getDeadZone,
newValue -> { newValue -> {
@@ -149,7 +159,7 @@ public class LambdaControlsSettingsScreen extends Screen
} }
}, option -> { }, option -> {
String value = String.valueOf(option.get()); String value = String.valueOf(option.get());
return option.getDisplayPrefix() + value.substring(0, Math.min(value.length(), 5)); return option.getDisplayText(new LiteralText(value.substring(0, Math.min(value.length(), 5))));
}, new TranslatableText("lambdacontrols.tooltip.dead_zone")); }, new TranslatableText("lambdacontrols.tooltip.dead_zone"));
this.invertsRightXAxis = new SpruceBooleanOption("lambdacontrols.menu.invert_right_x_axis", this.mod.config::doesInvertRightXAxis, this.invertsRightXAxis = new SpruceBooleanOption("lambdacontrols.menu.invert_right_x_axis", this.mod.config::doesInvertRightXAxis,
newValue -> { newValue -> {
@@ -169,14 +179,14 @@ public class LambdaControlsSettingsScreen extends Screen
this.mod.config::setVirtualMouse, new TranslatableText("lambdacontrols.tooltip.virtual_mouse"), true); this.mod.config::setVirtualMouse, new TranslatableText("lambdacontrols.tooltip.virtual_mouse"), true);
this.virtualMouseSkinOption = new SpruceCyclingOption("lambdacontrols.menu.virtual_mouse.skin", this.virtualMouseSkinOption = new SpruceCyclingOption("lambdacontrols.menu.virtual_mouse.skin",
amount -> this.mod.config.setVirtualMouseSkin(this.mod.config.getVirtualMouseSkin().next()), amount -> this.mod.config.setVirtualMouseSkin(this.mod.config.getVirtualMouseSkin().next()),
option -> option.getDisplayPrefix() + this.mod.config.getVirtualMouseSkin().getTranslatedName(), option -> option.getDisplayText(this.mod.config.getVirtualMouseSkin().getTranslatedText()),
null); null);
// HUD options // HUD options
this.hudEnableOption = new SpruceBooleanOption("lambdacontrols.menu.hud_enable", this.mod.config::isHudEnabled, this.hudEnableOption = new SpruceBooleanOption("lambdacontrols.menu.hud_enable", this.mod.config::isHudEnabled,
this.mod::setHudEnabled, new TranslatableText("lambdacontrols.tooltip.hud_enable"), true); this.mod::setHudEnabled, new TranslatableText("lambdacontrols.tooltip.hud_enable"), true);
this.hudSideOption = new SpruceCyclingOption("lambdacontrols.menu.hud_side", this.hudSideOption = new SpruceCyclingOption("lambdacontrols.menu.hud_side",
amount -> this.mod.config.setHudSide(this.mod.config.getHudSide().next()), amount -> this.mod.config.setHudSide(this.mod.config.getHudSide().next()),
option -> option.getDisplayPrefix() + this.mod.config.getHudSide().getTranslatedName(), option -> option.getDisplayText(this.mod.config.getHudSide().getTranslatedText()),
new TranslatableText("lambdacontrols.tooltip.hud_side")); new TranslatableText("lambdacontrols.tooltip.hud_side"));
} }
@@ -196,7 +206,7 @@ public class LambdaControlsSettingsScreen extends Screen
private int getTextHeight() private int getTextHeight()
{ {
return (5 + this.font.fontHeight) * 3 + 5; return (5 + this.textRenderer.fontHeight) * 3 + 5;
} }
@Override @Override
@@ -205,39 +215,40 @@ public class LambdaControlsSettingsScreen extends Screen
super.init(); super.init();
int buttonHeight = 20; int buttonHeight = 20;
SpruceButtonWidget controlsModeBtn = new SpruceButtonWidget(this.width / 2 - 155, 18, this.hideControls ? 310 : 150, buttonHeight, SpruceButtonWidget controlsModeBtn = new SpruceButtonWidget(this.width / 2 - 155, 18, this.hideControls ? 310 : 150, buttonHeight,
I18n.translate("lambdacontrols.menu.controls_mode") + ": " + I18n.translate(this.mod.config.getControlsMode().getTranslationKey()), new TranslatableText("lambdacontrols.menu.controls_mode").append(": ").append(new TranslatableText(this.mod.config.getControlsMode().getTranslationKey())),
btn -> { btn -> {
ControlsMode next = this.mod.config.getControlsMode().next(); ControlsMode next = this.mod.config.getControlsMode().next();
btn.setMessage(I18n.translate("lambdacontrols.menu.controls_mode") + ": " + I18n.translate(next.getTranslationKey())); btn.setMessage(new TranslatableText("lambdacontrols.menu.controls_mode").append(": ").append(new TranslatableText(next.getTranslationKey())));
this.mod.config.setControlsMode(next); this.mod.config.setControlsMode(next);
this.mod.config.save(); this.mod.config.save();
if (this.minecraft.player != null) { if (this.client.player != null) {
ClientSidePacketRegistry.INSTANCE.sendToServer(LambdaControls.CONTROLS_MODE_CHANNEL, this.mod.makeControlsModeBuffer(next)); ClientSidePacketRegistry.INSTANCE.sendToServer(LambdaControls.CONTROLS_MODE_CHANNEL, this.mod.makeControlsModeBuffer(next));
} }
}); });
controlsModeBtn.setTooltip(new TranslatableText("lambdacontrols.tooltip.controls_mode")); controlsModeBtn.setTooltip(new TranslatableText("lambdacontrols.tooltip.controls_mode"));
this.addButton(controlsModeBtn); this.addButton(controlsModeBtn);
if (!this.hideControls) if (!this.hideControls)
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, 18, 150, buttonHeight, I18n.translate("options.controls"), this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, 18, 150, buttonHeight, new TranslatableText("options.controls"),
btn -> { btn -> {
if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER) if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER)
this.minecraft.openScreen(new ControllerControlsScreen(this, true)); this.client.openScreen(new ControllerControlsScreen(this, true));
else else
this.minecraft.openScreen(new ControlsOptionsScreen(this, this.minecraft.options)); this.client.openScreen(new ControlsOptionsScreen(this, this.client.options));
})); }));
this.list = new ButtonListWidget(this.minecraft, this.width, this.height, 43, this.height - 29 - this.getTextHeight(), 25); this.list = new ButtonListWidget(this.client, this.width, this.height, 43, this.height - 29 - this.getTextHeight(), 25);
// General options // General options
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.general", true, null)); this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.general", true, null));
this.list.addOptionEntry(this.rotationSpeedOption, this.mouseSpeedOption); this.list.addOptionEntry(this.rotationSpeedOption, this.mouseSpeedOption);
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);
this.list.addOptionEntry(Option.SNEAK_TOGGLED, Option.SPRINT_TOGGLED);
// Controller options // Controller options
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.controller", true, null)); this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.controller", true, null));
this.list.addSingleOptionEntry(this.controllerOption); this.list.addSingleOptionEntry(this.controllerOption);
@@ -247,32 +258,34 @@ public class LambdaControlsSettingsScreen extends Screen
this.list.addOptionEntry(this.unfocusedInputOption, this.virtualMouseOption); this.list.addOptionEntry(this.unfocusedInputOption, this.virtualMouseOption);
this.list.addSingleOptionEntry(this.virtualMouseSkinOption); this.list.addSingleOptionEntry(this.virtualMouseSkinOption);
this.list.addSingleOptionEntry(new ReloadControllerMappingsOption()); this.list.addSingleOptionEntry(new ReloadControllerMappingsOption());
this.list.addSingleOptionEntry(new SpruceSimpleActionOption("lambdacontrols.menu.mappings.open_input_str",
btn -> this.client.openScreen(new MappingsStringInputScreen(this))));
// HUD options // HUD options
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.hud", true, null)); this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.hud", true, null));
this.list.addOptionEntry(this.hudEnableOption, this.hudSideOption); this.list.addOptionEntry(this.hudEnableOption, this.hudSideOption);
this.children.add(this.list); this.children.add(this.list);
this.gamepadToolUrlLabel = new SpruceLabelWidget(this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 2, this.controllerMappingsUrlText, this.width, this.gamepadToolUrlLabel = new SpruceLabelWidget(this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight) * 2, this.controllerMappingsUrlText, this.width,
label -> Util.getOperatingSystem().open(GAMEPAD_TOOL_URL), true); label -> Util.getOperatingSystem().open(GAMEPAD_TOOL_URL), true);
this.gamepadToolUrlLabel.setTooltip(new TranslatableText("chat.link.open")); this.gamepadToolUrlLabel.setTooltip(new TranslatableText("chat.link.open"));
this.children.add(this.gamepadToolUrlLabel); this.children.add(this.gamepadToolUrlLabel);
this.addButton(this.resetOption.createButton(this.minecraft.options, this.width / 2 - 155, this.height - 29, 150)); this.addButton(this.resetOption.createButton(this.client.options, this.width / 2 - 155, this.height - 29, 150));
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, buttonHeight, I18n.translate("gui.done"), this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, buttonHeight, SpruceTexts.GUI_DONE,
(buttonWidget) -> this.minecraft.openScreen(this.parent))); btn -> this.client.openScreen(this.parent)));
} }
@Override @Override
public void render(int mouseX, int mouseY, float delta) public void render(MatrixStack matrices, int mouseX, int mouseY, float delta)
{ {
this.renderBackground(); this.renderBackground(matrices);
this.list.render(mouseX, mouseY, delta); this.list.render(matrices, mouseX, mouseY, delta);
super.render(mouseX, mouseY, delta); super.render(matrices, mouseX, mouseY, delta);
this.drawCenteredString(this.font, I18n.translate("lambdacontrols.menu.title"), this.width / 2, 8, 16777215); drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.menu.title"), this.width / 2, 8, 16777215);
this.drawCenteredString(this.font, I18n.translate("lambdacontrols.controller.mappings.1", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 3, 10526880); drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.controller.mappings.1", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight) * 3, 10526880);
this.gamepadToolUrlLabel.render(mouseX, mouseY, delta); this.gamepadToolUrlLabel.render(matrices, mouseX, mouseY, delta);
this.drawCenteredString(this.font, I18n.translate("lambdacontrols.controller.mappings.3", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.font.fontHeight), 10526880); drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.controller.mappings.3", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight), 10526880);
Tooltip.renderAll(); Tooltip.renderAll(matrices);
} }
} }

View File

@@ -0,0 +1,128 @@
/*
* 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.gui;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.spruceui.SpruceTextAreaWidget;
import me.lambdaurora.spruceui.SpruceTexts;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.Option;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText;
import org.jetbrains.annotations.Nullable;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
/**
* Represents the controller mappings file editor screen.
*
* @author LambdAurora
* @version 1.4.3
* @since 1.4.3
*/
public class MappingsStringInputScreen extends Screen
{
private final Screen parent;
private final Option reloadMappingsOption;
private String mappings;
private SpruceTextAreaWidget textArea;
protected MappingsStringInputScreen(@Nullable Screen parent)
{
super(new TranslatableText("lambdacontrols.menu.title.mappings.string"));
this.parent = parent;
this.reloadMappingsOption = new ReloadControllerMappingsOption(btn -> {
this.writeMappings();
});
}
@Override
public void removed()
{
this.writeMappings();
Controller.updateMappings();
super.removed();
}
@Override
public void onClose()
{
this.removed();
super.onClose();
}
public void writeMappings()
{
if (this.textArea != null) {
this.mappings = this.textArea.getText();
System.out.println(this.mappings);
try {
FileWriter fw = new FileWriter(LambdaControlsClient.MAPPINGS_FILE, false);
fw.write(this.mappings);
fw.close();
} catch (IOException e) {
if (this.client != null)
this.client.getToastManager().add(SystemToast.create(this.client, SystemToast.Type.TUTORIAL_HINT,
new TranslatableText("lambdacontrols.controller.mappings.error.write"), LiteralText.EMPTY));
e.printStackTrace();
}
}
}
@Override
protected void init()
{
super.init();
if (this.textArea != null) {
this.mappings = this.textArea.getText();
}
String mappings = "";
if (this.mappings != null)
mappings = this.mappings;
else if (LambdaControlsClient.MAPPINGS_FILE.exists()) {
try {
mappings = String.join("\n", Files.readAllLines(LambdaControlsClient.MAPPINGS_FILE.toPath()));
this.mappings = mappings;
} catch (IOException e) {
/* Ignored */
}
}
int textFieldWidth = (int) (this.width * (3.0 / 4.0));
this.textArea = new SpruceTextAreaWidget(this.textRenderer, this.width / 2 - textFieldWidth / 2, 50, textFieldWidth, this.height - 100, new LiteralText(mappings));
this.textArea.setText(mappings);
// Display as many lines as possible
this.textArea.setDisplayedLines(this.textArea.getInnerHeight() / this.textRenderer.fontHeight);
this.addButton(this.textArea);
this.addButton(this.reloadMappingsOption.createButton(this.client.options, this.width / 2 - 155, this.height - 29, 150));
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20, SpruceTexts.GUI_DONE,
(buttonWidget) -> this.client.openScreen(this.parent)));
}
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta)
{
this.renderBackground(matrices);
super.render(matrices, mouseX, mouseY, delta);
drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 8, 16777215);
}
}

View File

@@ -10,46 +10,39 @@
package me.lambdaurora.lambdacontrols.client.gui; package me.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.client.controller.Controller; import me.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.spruceui.SpruceButtonWidget; import me.lambdaurora.spruceui.option.SpruceSimpleActionOption;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.Option;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.toast.SystemToast; import net.minecraft.client.toast.SystemToast;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
/** /**
* Represents the option to reload the controller mappings. * Represents the option to reload the controller mappings.
*/ */
public class ReloadControllerMappingsOption extends Option implements Nameable public class ReloadControllerMappingsOption extends SpruceSimpleActionOption
{ {
private static final String KEY = "lambdacontrols.menu.reload_controller_mappings"; private static final String KEY = "lambdacontrols.menu.reload_controller_mappings";
public ReloadControllerMappingsOption() public ReloadControllerMappingsOption()
{ {
super(KEY); this(null);
} }
@Override public ReloadControllerMappingsOption(@Nullable Consumer<AbstractButtonWidget> before)
public AbstractButtonWidget createButton(GameOptions options, int x, int y, int width)
{ {
SpruceButtonWidget button = new SpruceButtonWidget(x, y, width, 20, this.getName(), btn -> { super(KEY, btn -> {
MinecraftClient client = MinecraftClient.getInstance(); MinecraftClient client = MinecraftClient.getInstance();
if (before != null)
before.accept(btn);
Controller.updateMappings(); Controller.updateMappings();
if (client.currentScreen != null) if (client.currentScreen instanceof LambdaControlsSettingsScreen)
client.currentScreen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); client.currentScreen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.mappings.updated"), null)); client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT,
}); new TranslatableText("lambdacontrols.controller.mappings.updated"), LiteralText.EMPTY));
button.setTooltip(new TranslatableText("lambdacontrols.tooltip.reload_controller_mappings")); }, new TranslatableText("lambdacontrols.tooltip.reload_controller_mappings"));
return button;
}
@Override
public @NotNull String getName()
{
return I18n.translate(KEY);
} }
} }

View File

@@ -0,0 +1,60 @@
/*
* 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.gui;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.ring.RingPage;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.TranslatableText;
/**
* Represents the controls ring screen.
*
* @author LambdAurora
* @version 1.4.3
* @since 1.4.3
*/
public class RingScreen extends Screen
{
protected final LambdaControlsClient mod;
public RingScreen()
{
super(new TranslatableText("lambdacontrols.menu.title.ring"));
this.mod = LambdaControlsClient.get();
}
@Override
public boolean isPauseScreen()
{
return false;
}
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta)
{
super.render(matrices, mouseX, mouseY, delta);
RingPage page = this.mod.ring.getCurrentPage();
page.render(matrices, this.textRenderer, this.width, this.height, mouseX, mouseY, delta);
}
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button)
{
/*if (LambdaControlsClient.BINDING_RING.matchesMouse(button)) {
this.onClose();
return true;
}*/
return false;
}
}

View File

@@ -70,14 +70,14 @@ public class TouchscreenOverlay extends Screen
private void pauseGame(boolean bl) private void pauseGame(boolean bl)
{ {
if (this.minecraft == null) if (this.client == null)
return; return;
boolean bl2 = this.minecraft.isIntegratedServerRunning() && !this.minecraft.getServer().isRemote(); boolean bl2 = this.client.isIntegratedServerRunning() && !this.client.getServer().isRemote();
if (bl2) { if (bl2) {
this.minecraft.openScreen(new GameMenuScreen(!bl)); this.client.openScreen(new GameMenuScreen(!bl));
this.minecraft.getSoundManager().pauseAll(); this.client.getSoundManager().pauseAll();
} else { } else {
this.minecraft.openScreen(new GameMenuScreen(true)); this.client.openScreen(new GameMenuScreen(true));
} }
} }
@@ -99,9 +99,9 @@ public class TouchscreenOverlay extends Screen
*/ */
private void updateJumpButtons() private void updateJumpButtons()
{ {
if (this.minecraft == null) if (this.client == null)
return; return;
if (this.minecraft.player.abilities.allowFlying && this.minecraft.player.abilities.flying) { if (this.client.player.abilities.allowFlying && this.client.player.abilities.flying) {
boolean oldStateFly = this.flyButton.visible; boolean oldStateFly = this.flyButton.visible;
this.jumpButton.visible = false; this.jumpButton.visible = false;
this.flyButton.visible = true; this.flyButton.visible = true;
@@ -128,7 +128,7 @@ public class TouchscreenOverlay extends Screen
*/ */
private void handleJump(ButtonWidget btn, boolean state) private void handleJump(ButtonWidget btn, boolean state)
{ {
((KeyBindingAccessor) this.minecraft.options.keyJump).lambdacontrols_handlePressState(state); ((KeyBindingAccessor) this.client.options.keyJump).lambdacontrols_handlePressState(state);
} }
@Override @Override
@@ -149,27 +149,27 @@ public class TouchscreenOverlay extends Screen
protected void init() protected void init()
{ {
super.init(); super.init();
int scaledWidth = this.minecraft.getWindow().getScaledWidth(); int scaledWidth = this.client.getWindow().getScaledWidth();
int scaledHeight = this.minecraft.getWindow().getScaledHeight(); int scaledHeight = this.client.getWindow().getScaledHeight();
this.addButton(new TexturedButtonWidget(scaledWidth / 2 - 20, 0, 20, 20, 0, 106, 20, ButtonWidget.WIDGETS_LOCATION, 256, 256, this.addButton(new TexturedButtonWidget(scaledWidth / 2 - 20, 0, 20, 20, 0, 106, 20, ButtonWidget.WIDGETS_LOCATION, 256, 256,
btn -> this.minecraft.openScreen(new ChatScreen("")), "")); btn -> this.client.openScreen(new ChatScreen("")), LiteralText.EMPTY));
this.addButton(new TexturedButtonWidget(scaledWidth / 2, 0, 20, 20, 0, 0, 20, WIDGETS_LOCATION, 256, 256, this.addButton(new TexturedButtonWidget(scaledWidth / 2, 0, 20, 20, 0, 0, 20, WIDGETS_LOCATION, 256, 256,
btn -> this.pauseGame(false))); btn -> this.pauseGame(false)));
// Inventory buttons. // Inventory buttons.
int inventoryButtonX = scaledWidth / 2; int inventoryButtonX = scaledWidth / 2;
int inventoryButtonY = scaledHeight - 16 - 5; int inventoryButtonY = scaledHeight - 16 - 5;
if (this.minecraft.options.mainArm == Arm.LEFT) { if (this.client.options.mainArm == Arm.LEFT) {
inventoryButtonX = inventoryButtonX - 91 - 24; inventoryButtonX = inventoryButtonX - 91 - 24;
} else { } else {
inventoryButtonX = inventoryButtonX + 91 + 4; inventoryButtonX = inventoryButtonX + 91 + 4;
} }
this.addButton(new TexturedButtonWidget(inventoryButtonX, inventoryButtonY, 20, 20, 20, 0, 20, WIDGETS_LOCATION, 256, 256, this.addButton(new TexturedButtonWidget(inventoryButtonX, inventoryButtonY, 20, 20, 20, 0, 20, WIDGETS_LOCATION, 256, 256,
btn -> { btn -> {
if (this.minecraft.interactionManager.hasRidingInventory()) { if (this.client.interactionManager.hasRidingInventory()) {
this.minecraft.player.openRidingInventory(); this.client.player.openRidingInventory();
} else { } else {
this.minecraft.getTutorialManager().onInventoryOpened(); this.client.getTutorialManager().onInventoryOpened();
this.minecraft.openScreen(new InventoryScreen(this.minecraft.player)); this.client.openScreen(new InventoryScreen(this.client.player));
} }
})); }));
int jumpButtonX, swapHandsX, sneakButtonX; int jumpButtonX, swapHandsX, sneakButtonX;
@@ -187,31 +187,31 @@ public class TouchscreenOverlay extends Screen
this.addButton(new SpruceTexturedButtonWidget(swapHandsX, sneakButtonY, 20, 20, 0, 160, 20, WIDGETS_LOCATION, this.addButton(new SpruceTexturedButtonWidget(swapHandsX, sneakButtonY, 20, 20, 0, 160, 20, WIDGETS_LOCATION,
(btn, state) -> { (btn, state) -> {
if (state) { if (state) {
if (!this.minecraft.player.isSpectator()) { if (!this.client.player.isSpectator()) {
this.minecraft.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_HELD_ITEMS, BlockPos.ORIGIN, Direction.DOWN)); this.client.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN));
} }
} }
})); }));
// Drop // Drop
this.addButton(new SpruceTexturedButtonWidget(swapHandsX, sneakButtonY + 5 + 20, 20, 20, 20, 160, 20, WIDGETS_LOCATION, this.addButton(new SpruceTexturedButtonWidget(swapHandsX, sneakButtonY + 5 + 20, 20, 20, 20, 160, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keyDrop).lambdacontrols_handlePressState(state))); (btn, state) -> ((KeyBindingAccessor) this.client.options.keyDrop).lambdacontrols_handlePressState(state)));
// Jump keys // Jump keys
this.addButton(this.jumpButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY, 20, 20, 0, 40, 20, WIDGETS_LOCATION, this.addButton(this.jumpButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY, 20, 20, 0, 40, 20, WIDGETS_LOCATION,
this::handleJump)); this::handleJump));
this.addButton(this.flyButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY, 20, 20, 20, 40, 20, WIDGETS_LOCATION, this.addButton(this.flyButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY, 20, 20, 20, 40, 20, WIDGETS_LOCATION,
(btn, state) -> { (btn, state) -> {
if (this.flyButtonEnableTicks == 0) this.minecraft.player.abilities.flying = false; if (this.flyButtonEnableTicks == 0) this.client.player.abilities.flying = false;
})); }));
this.addButton(this.flyUpButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY - 5 - 20, 20, 20, 40, 40, 20, WIDGETS_LOCATION, this.addButton(this.flyUpButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY - 5 - 20, 20, 20, 40, 40, 20, WIDGETS_LOCATION,
this::handleJump)); this::handleJump));
this.addButton(this.flyDownButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY + 20 + 5, 20, 20, 60, 40, 20, WIDGETS_LOCATION, this.addButton(this.flyDownButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY + 20 + 5, 20, 20, 60, 40, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keySneak).lambdacontrols_handlePressState(state))); (btn, state) -> ((KeyBindingAccessor) this.client.options.keySneak).lambdacontrols_handlePressState(state)));
this.updateJumpButtons(); this.updateJumpButtons();
// Movements keys // Movements keys
this.addButton((this.startSneakButton = new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY, 20, 20, 0, 120, 20, WIDGETS_LOCATION, this.addButton((this.startSneakButton = new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY, 20, 20, 0, 120, 20, WIDGETS_LOCATION,
(btn, state) -> { (btn, state) -> {
if (state) { if (state) {
((KeyBindingAccessor) this.minecraft.options.keySneak).lambdacontrols_handlePressState(true); ((KeyBindingAccessor) this.client.options.keySneak).lambdacontrols_handlePressState(true);
this.startSneakButton.visible = false; this.startSneakButton.visible = false;
this.endSneakButton.visible = true; this.endSneakButton.visible = true;
} }
@@ -219,7 +219,7 @@ public class TouchscreenOverlay extends Screen
this.addButton((this.endSneakButton = new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY, 20, 20, 20, 120, 20, WIDGETS_LOCATION, this.addButton((this.endSneakButton = new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY, 20, 20, 20, 120, 20, WIDGETS_LOCATION,
(btn, state) -> { (btn, state) -> {
if (state) { if (state) {
((KeyBindingAccessor) this.minecraft.options.keySneak).lambdacontrols_handlePressState(false); ((KeyBindingAccessor) this.client.options.keySneak).lambdacontrols_handlePressState(false);
this.endSneakButton.visible = false; this.endSneakButton.visible = false;
this.startSneakButton.visible = true; this.startSneakButton.visible = true;
} }
@@ -227,49 +227,49 @@ public class TouchscreenOverlay extends Screen
this.endSneakButton.visible = false; this.endSneakButton.visible = false;
this.addButton(this.forwardLeftButton = new SpruceTexturedButtonWidget(sneakButtonX - 20 - 5, sneakButtonY - 5 - 20, 20, 20, 80, 80, 20, WIDGETS_LOCATION, this.addButton(this.forwardLeftButton = new SpruceTexturedButtonWidget(sneakButtonX - 20 - 5, sneakButtonY - 5 - 20, 20, 20, 80, 80, 20, WIDGETS_LOCATION,
(btn, state) -> { (btn, state) -> {
((KeyBindingAccessor) this.minecraft.options.keyForward).lambdacontrols_handlePressState(state); ((KeyBindingAccessor) this.client.options.keyForward).lambdacontrols_handlePressState(state);
((KeyBindingAccessor) this.minecraft.options.keyLeft).lambdacontrols_handlePressState(state); ((KeyBindingAccessor) this.client.options.keyLeft).lambdacontrols_handlePressState(state);
this.updateForwardButtonsState(state); this.updateForwardButtonsState(state);
})); }));
this.forwardLeftButton.visible = false; this.forwardLeftButton.visible = false;
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION, this.addButton(new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION,
(btn, state) -> { (btn, state) -> {
((KeyBindingAccessor) this.minecraft.options.keyForward).lambdacontrols_handlePressState(state); ((KeyBindingAccessor) this.client.options.keyForward).lambdacontrols_handlePressState(state);
this.updateForwardButtonsState(state); this.updateForwardButtonsState(state);
this.forwardLeftButton.visible = true; this.forwardLeftButton.visible = true;
this.forwardRightButton.visible = true; this.forwardRightButton.visible = true;
})); }));
this.addButton(this.forwardRightButton = new SpruceTexturedButtonWidget(sneakButtonX + 20 + 5, sneakButtonY - 5 - 20, 20, 20, 100, 80, 20, WIDGETS_LOCATION, this.addButton(this.forwardRightButton = new SpruceTexturedButtonWidget(sneakButtonX + 20 + 5, sneakButtonY - 5 - 20, 20, 20, 100, 80, 20, WIDGETS_LOCATION,
(btn, state) -> { (btn, state) -> {
((KeyBindingAccessor) this.minecraft.options.keyForward).lambdacontrols_handlePressState(state); ((KeyBindingAccessor) this.client.options.keyForward).lambdacontrols_handlePressState(state);
((KeyBindingAccessor) this.minecraft.options.keyRight).lambdacontrols_handlePressState(state); ((KeyBindingAccessor) this.client.options.keyRight).lambdacontrols_handlePressState(state);
this.updateForwardButtonsState(state); this.updateForwardButtonsState(state);
})); }));
this.forwardRightButton.visible = true; this.forwardRightButton.visible = true;
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX + 20 + 5, sneakButtonY, 20, 20, 20, 80, 20, WIDGETS_LOCATION, this.addButton(new SpruceTexturedButtonWidget(sneakButtonX + 20 + 5, sneakButtonY, 20, 20, 20, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keyRight).lambdacontrols_handlePressState(state))); (btn, state) -> ((KeyBindingAccessor) this.client.options.keyRight).lambdacontrols_handlePressState(state)));
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY + 20 + 5, 20, 20, 40, 80, 20, WIDGETS_LOCATION, this.addButton(new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY + 20 + 5, 20, 20, 40, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keyBack).lambdacontrols_handlePressState(state))); (btn, state) -> ((KeyBindingAccessor) this.client.options.keyBack).lambdacontrols_handlePressState(state)));
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX - 20 - 5, sneakButtonY, 20, 20, 60, 80, 20, WIDGETS_LOCATION, this.addButton(new SpruceTexturedButtonWidget(sneakButtonX - 20 - 5, sneakButtonY, 20, 20, 60, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keyLeft).lambdacontrols_handlePressState(state))); (btn, state) -> ((KeyBindingAccessor) this.client.options.keyLeft).lambdacontrols_handlePressState(state)));
}
@Override this.buttons.forEach(button -> {
public void render(int mouseX, int mouseY, float delta) if (button instanceof SpruceTexturedButtonWidget) {
{ ((SpruceTexturedButtonWidget) button).setSilent(true);
super.render(mouseX, mouseY, delta); }
});
} }
@Override @Override
public boolean mouseClicked(double mouseX, double mouseY, int button) public boolean mouseClicked(double mouseX, double mouseY, int button)
{ {
if (mouseY >= (double) (this.height - 22) && this.minecraft != null && this.minecraft.player != null) { if (mouseY >= (double) (this.height - 22) && this.client != null && this.client.player != null) {
int centerX = this.width / 2; int centerX = this.width / 2;
if (mouseX >= (double) (centerX - 90) && mouseX <= (double) (centerX + 90)) { if (mouseX >= (double) (centerX - 90) && mouseX <= (double) (centerX + 90)) {
for (int slot = 0; slot < 9; ++slot) { for (int slot = 0; slot < 9; ++slot) {
int slotX = centerX - 90 + slot * 20 + 2; int slotX = centerX - 90 + slot * 20 + 2;
if (mouseX >= (double) slotX && mouseX <= (double) (slotX + 20)) { if (mouseX >= (double) slotX && mouseX <= (double) (slotX + 20)) {
this.minecraft.player.inventory.selectedSlot = slot; this.client.player.inventory.selectedSlot = slot;
return true; return true;
} }
} }
@@ -281,16 +281,16 @@ public class TouchscreenOverlay extends Screen
@Override @Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY)
{ {
if (button == GLFW.GLFW_MOUSE_BUTTON_1 && this.minecraft != null) { if (button == GLFW.GLFW_MOUSE_BUTTON_1 && this.client != null) {
if (deltaY > 0.01) if (deltaY > 0.01)
this.mod.input.handleLook(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 2); this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 2);
else if (deltaY < 0.01) else if (deltaY < 0.01)
this.mod.input.handleLook(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 1); this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 1);
if (deltaX > 0.01) if (deltaX > 0.01)
this.mod.input.handleLook(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 2); this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 2);
else if (deltaX < 0.01) else if (deltaX < 0.01)
this.mod.input.handleLook(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 1); this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 1);
} }
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
} }

View File

@@ -11,6 +11,7 @@ package me.lambdaurora.lambdacontrols.client.mixin;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.MovementHandler;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.input.Input; import net.minecraft.client.input.Input;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
@@ -69,6 +70,12 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity
} }
} }
@Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick(Z)V", shift = At.Shift.AFTER))
public void onInputUpdate(CallbackInfo ci)
{
MovementHandler.HANDLER.applyMovement((ClientPlayerEntity) (Object) this);
}
@Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isCamera()Z")) @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isCamera()Z"))
public void onTickMovement(CallbackInfo ci) public void onTickMovement(CallbackInfo ci)
{ {

View File

@@ -17,8 +17,8 @@ import net.minecraft.client.gui.screen.options.GameOptionsScreen;
import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.GameOptions; import net.minecraft.client.options.GameOptions;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
@@ -40,7 +40,7 @@ public class ControlsOptionsScreenMixin extends GameOptionsScreen
if (this.parent instanceof ControllerControlsScreen) if (this.parent instanceof ControllerControlsScreen)
return this.addButton(btn); return this.addButton(btn);
else else
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).getHeight(), I18n.translate("menu.options"), return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).getHeight(), new TranslatableText("menu.options"),
b -> this.minecraft.openScreen(new LambdaControlsSettingsScreen(this, true)))); b -> this.client.openScreen(new LambdaControlsSettingsScreen(this, true))));
} }
} }

View File

@@ -10,8 +10,8 @@
package me.lambdaurora.lambdacontrols.client.mixin; package me.lambdaurora.lambdacontrols.client.mixin;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.container.Slot;
import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemGroup;
import net.minecraft.screen.slot.Slot;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;

View File

@@ -17,5 +17,5 @@ import org.spongepowered.asm.mixin.gen.Invoker;
public interface EntryListWidgetAccessor public interface EntryListWidgetAccessor
{ {
@Invoker("moveSelection") @Invoker("moveSelection")
void lambdacontrols_moveSelection(int amount); void lambdacontrols_moveSelection(EntryListWidget.MoveDirection direction);
} }

View File

@@ -13,11 +13,13 @@ import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer; import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer;
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor; import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.ContainerScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.container.Slot; import net.minecraft.client.util.math.MatrixStack;
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.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
@@ -29,8 +31,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/** /**
* Represents the mixin for the class ContainerScreen. * Represents the mixin for the class ContainerScreen.
*/ */
@Mixin(ContainerScreen.class) @Mixin(HandledScreen.class)
public abstract class ContainerScreenMixin implements ContainerScreenAccessor public abstract class HandledScreenMixin implements HandledScreenAccessor
{ {
@Accessor("x") @Accessor("x")
public abstract int getX(); public abstract int getX();
@@ -41,21 +43,27 @@ public abstract class ContainerScreenMixin implements ContainerScreenAccessor
@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(int mouseX, int mouseY, float delta, CallbackInfo ci) public void onRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci)
{ {
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) { if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
MinecraftClient client = MinecraftClient.getInstance(); MinecraftClient client = MinecraftClient.getInstance();
int x = 2, y = client.getWindow().getScaledHeight() - 2 - LambdaControlsRenderer.ICON_SIZE; int x = 2, y = client.getWindow().getScaledHeight() - 2 - LambdaControlsRenderer.ICON_SIZE;
x = LambdaControlsRenderer.drawButtonTip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, "lambdacontrols.action.pickup_all", true, client) + 2; x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, "lambdacontrols.action.pickup_all", true, client) + 2;
x = LambdaControlsRenderer.drawButtonTip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_B}, "lambdacontrols.action.exit", true, client) + 2; x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_B}, "lambdacontrols.action.exit", true, client) + 2;
if (LambdaControlsCompat.isReiPresent()) { if (LambdaControlsCompat.isReiPresent()) {
x = 2; x = 2;
y -= 24; y -= 24;
} }
x = LambdaControlsRenderer.drawButtonTip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_X}, "lambdacontrols.action.pickup", true, client) + 2; x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_X}, "lambdacontrols.action.pickup", true, client) + 2;
LambdaControlsRenderer.drawButtonTip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_Y}, "lambdacontrols.action.quick_move", true, client); LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_Y}, "lambdacontrols.action.quick_move", true, client);
} }
} }
} }

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)
@@ -115,7 +106,7 @@ public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAcces
} }
// Removed front placing sprinting as way too cheaty. // Removed front placing sprinting as way too cheaty.
/* else if (this.player.isSprinting()) { /* else if (this.player.isSprinting()) {
hitResult = this.lambdacontrols_frontBlockPlaceResult; hitResult = LambdaControlsClient.get().reacharound.getLastReacharoundResult();
if (hitResult != null) { if (hitResult != null) {
if (cooldown > 0) if (cooldown > 0)
this.itemUseCooldown = 0; this.itemUseCooldown = 0;
@@ -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,16 @@ 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()) { LambdaControlsClient mod = LambdaControlsClient.get();
if (this.crosshairTarget != null && this.crosshairTarget.getType() == HitResult.Type.MISS && this.player.onGround) { if (!stackInHand.isEmpty() && this.player.pitch > 35.0F && mod.reacharound.isReacharoundAvailable()) {
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 = mod.reacharound.getLastReacharoundResult();
if (hitResult == null) if (hitResult == null)
return; return;
hitResult = LambdaInput.withSideForFrontPlace(hitResult, stackInHand); hitResult = mod.reacharound.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,17 @@ 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.lwjgl.glfw.GLFW;
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 +31,41 @@ 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 = "method_1605", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/client/gui/screen/Screen;mouseReleased(DDI)Z"))
private void onMouseBackButton(boolean[] result, double mouseX, double mouseY, int button, CallbackInfo ci)
{
if (!result[0] && button == GLFW.GLFW_MOUSE_BUTTON_4 && this.client.currentScreen != null) {
if (LambdaControlsClient.get().input.tryGoBack(this.client.currentScreen)) {
result[0] = true;
}
}
}
@Inject(method = "isCursorLocked", at = @At("HEAD"), cancellable = true)
private void isCursorLocked(CallbackInfoReturnable<Boolean> ci)
{
if (this.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

@@ -13,7 +13,7 @@ import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen; import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.SettingsScreen; import net.minecraft.client.gui.screen.options.OptionsScreen;
import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -24,20 +24,20 @@ import org.spongepowered.asm.mixin.injection.Redirect;
/** /**
* Injects the new controls settings button. * Injects the new controls settings button.
*/ */
@Mixin(SettingsScreen.class) @Mixin(OptionsScreen.class)
public class SettingsScreenMixin extends Screen public class OptionsScreenMixin extends Screen
{ {
protected SettingsScreenMixin(Text title) protected OptionsScreenMixin(Text title)
{ {
super(title); super(title);
} }
@Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/SettingsScreen;addButton(Lnet/minecraft/client/gui/widget/AbstractButtonWidget;)Lnet/minecraft/client/gui/widget/AbstractButtonWidget;", ordinal = 7)) @Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/options/OptionsScreen;addButton(Lnet/minecraft/client/gui/widget/AbstractButtonWidget;)Lnet/minecraft/client/gui/widget/AbstractButtonWidget;", ordinal = 7))
private AbstractButtonWidget lambdacontrols_onInit(SettingsScreen screen, AbstractButtonWidget btn) private AbstractButtonWidget lambdacontrols_onInit(OptionsScreen screen, AbstractButtonWidget btn)
{ {
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) { if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).getHeight(), btn.getMessage(), return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).getHeight(), btn.getMessage(),
b -> this.minecraft.openScreen(new ControllerControlsScreen(this, false)))); b -> this.client.openScreen(new ControllerControlsScreen(this, false))));
} else { } else {
return this.addButton(btn); return this.addButton(btn);
} }

View File

@@ -10,16 +10,14 @@
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.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.util.math.Matrix4f;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.EntityContext;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -28,8 +26,8 @@ import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult; import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.profiler.Profiler;
import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@@ -42,7 +40,7 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/** /**
* Represents a mixin to WorldRenderer. * Represents a mixin to WorldRenderer.
* <p> * <p>
* Handles the rendering of the block outline of the front block placing. * Handles the rendering of the block outline of the reach-around features.
*/ */
@Mixin(WorldRenderer.class) @Mixin(WorldRenderer.class)
public abstract class WorldRendererMixin public abstract class WorldRendererMixin
@@ -54,6 +52,10 @@ public abstract class WorldRendererMixin
@Shadow @Shadow
private ClientWorld world; private ClientWorld world;
@Shadow
@Final
private BufferBuilderStorage bufferBuilders;
@Shadow @Shadow
private static void drawShapeOutline(MatrixStack matrixStack, VertexConsumer vertexConsumer, VoxelShape voxelShape, double d, double e, double f, float g, float h, float i, float j) private static void drawShapeOutline(MatrixStack matrixStack, VertexConsumer vertexConsumer, VoxelShape voxelShape, double d, double e, double f, float g, float h, float i, float j)
{ {
@@ -66,17 +68,14 @@ public abstract class WorldRendererMixin
target = "Lnet/minecraft/client/MinecraftClient;crosshairTarget:Lnet/minecraft/util/hit/HitResult;", target = "Lnet/minecraft/client/MinecraftClient;crosshairTarget:Lnet/minecraft/util/hit/HitResult;",
ordinal = 1, ordinal = 1,
shift = At.Shift.AFTER shift = At.Shift.AFTER
), )
locals = LocalCapture.CAPTURE_FAILEXCEPTION
) )
private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer,
LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci)
Profiler profiler, Vec3d cameraPos, double x, double y, double z, Matrix4f modelMatrix, boolean bl, Frustum frustum2, boolean bl3,
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();
@@ -84,16 +83,25 @@ public abstract class WorldRendererMixin
ItemStack stack = this.client.player.getStackInHand(Hand.MAIN_HAND); ItemStack stack = this.client.player.getStackInHand(Hand.MAIN_HAND);
if (stack == null || !(stack.getItem() instanceof BlockItem)) if (stack == null || !(stack.getItem() instanceof BlockItem))
return; return;
LambdaControlsClient mod = LambdaControlsClient.get();
Block block = ((BlockItem) stack.getItem()).getBlock(); Block block = ((BlockItem) stack.getItem()).getBlock();
result = LambdaInput.withSideForFrontPlace(result, block); result = mod.reacharound.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());
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, EntityContext.of(camera.getFocusedEntity())); Vec3d pos = camera.getPos();
int[] color = LambdaControlsClient.get().config.getFrontBlockOutlineColor();
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); VoxelShape outlineShape = placementState.getOutlineShape(this.client.world, blockPos, ShapeContext.of(camera.getFocusedEntity()));
int[] color = mod.config.getReacharoundOutlineColor();
VertexConsumer vertexConsumer = this.bufferBuilders.getEntityVertexConsumers().getBuffer(RenderLayer.getLines());
drawShapeOutline(matrices, vertexConsumer, outlineShape,
(double) blockPos.getX() - pos.getX(), (double) blockPos.getY() - pos.getY(), (double) blockPos.getZ() - pos.getZ(),
color[0] / 255.f, color[1] / 255.f, color[2] / 255.f, color[3] / 255.f);
} }
} }
} }

View File

@@ -0,0 +1,41 @@
/*
* 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;
import com.electronwill.nightconfig.core.Config;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.util.math.MatrixStack;
import org.jetbrains.annotations.NotNull;
public class DummyRingAction extends RingAction
{
public DummyRingAction(@NotNull Config config)
{
super(config);
}
@Override
public @NotNull String getName()
{
return "dummy";
}
@Override
public void onAction(@NotNull RingButtonMode mode)
{
}
@Override
public void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered)
{
drawCenteredString(matrices, textRenderer, this.getName(), x + 25, y + 25 - textRenderer.fontHeight / 2, 0xffffff);
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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;
import com.electronwill.nightconfig.core.Config;
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.TranslatableText;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
public class KeyBindingRingAction extends RingAction
{
public static final Factory FACTORY = new Factory();
public final KeyBinding binding;
public KeyBindingRingAction(@NotNull Config config, @NotNull KeyBinding binding)
{
super(config);
this.binding = binding;
}
@Override
public @NotNull String getName()
{
return this.binding.getTranslationKey();
}
@Override
public void onAction(@NotNull RingButtonMode mode)
{
KeyBindingAccessor accessor = (KeyBindingAccessor) this.binding;
switch (mode) {
case PRESS:
case HOLD:
accessor.lambdacontrols_handlePressState(this.activated);
break;
case TOGGLE:
accessor.lambdacontrols_handlePressState(!this.binding.isPressed());
this.activated = !this.binding.isPressed();
break;
}
}
@Override
public void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered)
{
drawCenteredText(matrices, textRenderer, new TranslatableText(this.getName()), x + 25, y + 25 - textRenderer.fontHeight / 2, 0xffffff);
}
protected static class Factory implements RingAction.Factory
{
@Override
public @NotNull Supplier<RingAction> newFromGui(@NotNull Screen screen)
{
return () -> null;
}
@Override
public @Nullable RingAction parse(@NotNull Config config)
{
return null;
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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;
import com.electronwill.nightconfig.core.Config;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.IntStream;
/**
* Represents a key binding ring.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.4.0
*/
public final class LambdaRing
{
public static final int ELEMENT_SIZE = 50;
private final Object2ObjectMap<String, RingAction.Factory> actionFactories = new Object2ObjectOpenHashMap<>();
private final List<RingPage> pages = new ArrayList<>(Collections.singletonList(RingPage.DEFAULT));
private final LambdaControlsClient mod;
private int currentPage = 0;
public LambdaRing(@NotNull LambdaControlsClient mod)
{
this.mod = mod;
}
public void registerAction(@NotNull String name, @NotNull RingAction.Factory factory)
{
if (this.actionFactories.containsKey(name)) {
this.mod.warn("Tried to register twice a ring action: \"" + name + "\".");
return;
}
this.actionFactories.put(name, factory);
}
/**
* Loads the ring from configuration.
*
* @param config The configuration.
*/
public void load(@NotNull Config config)
{
List<Config> configPages = config.get("ring.pages");
if (configPages != null) {
this.pages.clear();
for (Config configPage : configPages) {
RingPage.parseRingPage(configPage).ifPresent(this.pages::add);
}
}
if (this.pages.isEmpty()) {
this.pages.add(RingPage.DEFAULT);
}
}
public @NotNull RingPage getCurrentPage()
{
if (this.currentPage >= this.pages.size())
this.currentPage = this.pages.size() - 1;
else if (this.currentPage < 0)
this.currentPage = 0;
return this.pages.get(this.currentPage);
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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;
import com.electronwill.nightconfig.core.Config;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
/**
* Represents a ring action.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.4.0
*/
public abstract class RingAction extends DrawableHelper implements Nameable
{
protected Config config;
protected boolean activated = false;
public RingAction(@NotNull Config config)
{
this.config = config;
}
/**
* Gets the text name of the ring action.
*
* @return The text name.
*/
public Text getTextName()
{
return new TranslatableText(this.getName());
}
/**
* Returns whether the action is activated or not.
*
* @return True if the action is activated, else false.
*/
public boolean isActivated()
{
return this.activated;
}
public void activate(@NotNull RingButtonMode mode)
{
this.activated = !this.activated;
this.onAction(mode);
}
public abstract void onAction(@NotNull RingButtonMode mode);
public void render(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered)
{
fill(matrices, x, y, x + LambdaRing.ELEMENT_SIZE, y + LambdaRing.ELEMENT_SIZE, hovered ? 0xbb777777 : 0xbb000000);
drawIcon(matrices, textRenderer, x, y, hovered);
}
public abstract void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered);
/**
* Represents a factory for {@link RingAction}.
*
* @version 1.4.3
* @since 1.4.3
*/
public interface Factory
{
@NotNull Supplier<RingAction> newFromGui(@NotNull Screen screen);
@Nullable RingAction parse(@NotNull Config config);
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull;
/**
* Represents the mode of a ring button.
*
* @author LambdAurora
* @version 1.4.0
* @since 1.4.0
*/
public enum RingButtonMode implements Nameable
{
PRESS("press"),
HOLD("hold"),
TOGGLE("toggle");
private final String name;
private final Text text;
RingButtonMode(@NotNull String name)
{
this.name = name;
this.text = new TranslatableText(this.getTranslationKey());
}
/**
* Returns the next ring button mode available.
*
* @return The next ring button mode.
*/
public @NotNull RingButtonMode next()
{
RingButtonMode[] v = values();
if (v.length == this.ordinal() + 1)
return v[0];
return v[this.ordinal() + 1];
}
/**
* Returns the translation key of this ring button mode.
*
* @return The translation key of this ring button mode.
*/
public @NotNull String getTranslationKey()
{
return "lambdacontrols.ring.button_mode." + this.getName();
}
/**
* Gets the translated name of this ring button mode.
*
* @return The translated name of this ring button mode.
*/
public @NotNull Text getTranslatedText()
{
return this.text;
}
@Override
public @NotNull String getName()
{
return this.name;
}
}

View File

@@ -0,0 +1,110 @@
/*
* 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;
import com.electronwill.nightconfig.core.Config;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.util.math.MatrixStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
/**
* Represents a ring page.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.4.0
*/
public class RingPage extends DrawableHelper
{
public static final RingPage DEFAULT = new RingPage("Default");
public final String name;
private RingAction[] actions = new RingAction[8];
public RingPage(@NotNull String name)
{
this.name = name;
for (int i = 0; i < 8; i++) {
this.actions[i] = null;
}
}
/**
* Renders the ring page.
*
* @param matrices The matrices.
* @param width The screen width.
* @param height The screen height.
* @param mouseX The mouse X-coordinate.
* @param mouseY The mouse Y-coordinate.
* @param tickDelta The tick delta.
*/
public void render(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int width, int height, int mouseX, int mouseY, float tickDelta)
{
int centerX = width / 2;
int centerY = height / 2;
int offset = LambdaRing.ELEMENT_SIZE + (LambdaRing.ELEMENT_SIZE / 2) + 5;
int y = centerY - offset;
int x = centerX - offset;
for (int i = 0; i < 3; i++) {
RingAction ringAction = this.actions[i];
if (ringAction != null)
ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY));
x += 55;
}
y += 55;
x = centerX - offset;
for (int i = 3; i < 5; i++) {
RingAction ringAction = this.actions[i];
if (ringAction != null)
ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY));
x += 55 * 2;
}
y += 55;
x = centerX - offset;
for (int i = 5; i < 8; i++) {
RingAction ringAction = this.actions[i];
if (ringAction != null)
ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY));
x += 55;
}
}
private static boolean isHovered(int x, int y, int mouseX, int mouseY)
{
return mouseX >= x && mouseY >= y && mouseX <= x + LambdaRing.ELEMENT_SIZE && mouseY <= y + LambdaRing.ELEMENT_SIZE;
}
/**
* Tries to parse a ring page configuration.
*
* @param config The configuration.
* @return An optional ring page.
*/
public static @NotNull Optional<RingPage> parseRingPage(@NotNull Config config)
{
String name = config.get("name");
if (name == null)
return Optional.empty();
RingPage page = new RingPage(name);
List<Config> actionConfigs = config.get("actions");
return Optional.of(page);
}
}

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

@@ -9,12 +9,14 @@
package me.lambdaurora.lambdacontrols.client.util; package me.lambdaurora.lambdacontrols.client.util;
import net.minecraft.container.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.
*/ */
public interface ContainerScreenAccessor public interface HandledScreenAccessor
{ {
/** /**
* Gets the left coordinate of the GUI. * Gets the left coordinate of the GUI.
@@ -38,4 +40,16 @@ public interface ContainerScreenAccessor
* @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

@@ -3,6 +3,7 @@
"key.lambdacontrols.look_left": "Look left", "key.lambdacontrols.look_left": "Look left",
"key.lambdacontrols.look_right": "Look right", "key.lambdacontrols.look_right": "Look right",
"key.lambdacontrols.look_up": "Look up", "key.lambdacontrols.look_up": "Look up",
"key.lambdacontrols.ring": "Show controls ring",
"lambdacontrols.action.attack": "Attack", "lambdacontrols.action.attack": "Attack",
"lambdacontrols.action.back": "Back", "lambdacontrols.action.back": "Back",
"lambdacontrols.action.chat": "Open Chat", "lambdacontrols.action.chat": "Open Chat",
@@ -31,6 +32,9 @@
"lambdacontrols.action.toggle_smooth_camera": "Toggle Cinematic Camera", "lambdacontrols.action.toggle_smooth_camera": "Toggle Cinematic Camera",
"lambdacontrols.action.use": "Use", "lambdacontrols.action.use": "Use",
"lambdacontrols.action.zoom": "Zoom", "lambdacontrols.action.zoom": "Zoom",
"lambdacontrols.action.zoom.in": "Increase Zoom",
"lambdacontrols.action.zoom.out": "Decrease Zoom",
"lambdacontrols.action.zoom.reset": "Reset Zoom",
"lambdacontrols.button.a": "A", "lambdacontrols.button.a": "A",
"lambdacontrols.button.b": "B", "lambdacontrols.button.b": "B",
"lambdacontrols.button.x": "X", "lambdacontrols.button.x": "X",
@@ -60,8 +64,9 @@
"lambdacontrols.controller.connected": "Controller %d connected.", "lambdacontrols.controller.connected": "Controller %d connected.",
"lambdacontrols.controller.disconnected": "Controller %d disconnected.", "lambdacontrols.controller.disconnected": "Controller %d disconnected.",
"lambdacontrols.controller.mappings.1": "To configure the controller mappings, please use %sSDL2 Gamepad Tool%s", "lambdacontrols.controller.mappings.1": "To configure the controller mappings, please use %sSDL2 Gamepad Tool%s",
"lambdacontrols.controller.mappings.2": "(%s%s%s),",
"lambdacontrols.controller.mappings.3": "and put the mapping in `%s.minecraft/config/gamecontrollerdb.txt%s`.", "lambdacontrols.controller.mappings.3": "and put the mapping in `%s.minecraft/config/gamecontrollerdb.txt%s`.",
"lambdacontrols.controller.mappings.error": "Error while loading mappings.",
"lambdacontrols.controller.mappings.error.write": "Error while writing mappings to file.",
"lambdacontrols.controller.mappings.updated": "Updated mappings!", "lambdacontrols.controller.mappings.updated": "Updated mappings!",
"lambdacontrols.controller_type.default": "default", "lambdacontrols.controller_type.default": "default",
"lambdacontrols.controller_type.dualshock": "DualShock", "lambdacontrols.controller_type.dualshock": "DualShock",
@@ -83,13 +88,15 @@
"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.mappings.open_input_str": "Open Mappings File Editor",
"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",
@@ -98,7 +105,7 @@
"lambdacontrols.menu.title.gameplay": "Gameplay Options", "lambdacontrols.menu.title.gameplay": "Gameplay Options",
"lambdacontrols.menu.title.general": "General Options", "lambdacontrols.menu.title.general": "General Options",
"lambdacontrols.menu.title.hud": "HUD Options", "lambdacontrols.menu.title.hud": "HUD Options",
"lambdacontrols.menu.unbound": "Unbound", "lambdacontrols.menu.title.mappings.string": "Mappings File Editor",
"lambdacontrols.menu.unfocused_input": "Unfocused Input", "lambdacontrols.menu.unfocused_input": "Unfocused Input",
"lambdacontrols.menu.virtual_mouse": "Virtual Mouse", "lambdacontrols.menu.virtual_mouse": "Virtual Mouse",
"lambdacontrols.menu.virtual_mouse.skin": "Virtual Mouse Skin", "lambdacontrols.menu.virtual_mouse.skin": "Virtual Mouse Skin",
@@ -112,12 +119,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

@@ -0,0 +1,130 @@
{
"key.lambdacontrols.look_down": "Mira hacia abajo",
"key.lambdacontrols.look_left": "Mira a la izquierda",
"key.lambdacontrols.look_right": "Mira a la derecha",
"key.lambdacontrols.look_up": "Mira a la arriba",
"lambdacontrols.action.attack": "Ataque",
"lambdacontrols.action.back": "Caminar hacia atrás",
"lambdacontrols.action.chat": "Abrir chat",
"lambdacontrols.action.drop_item": "Tirar ítem",
"lambdacontrols.action.exit": "Salir",
"lambdacontrols.action.forward": "Caminar hacia delante",
"lambdacontrols.action.hit": "Golpear",
"lambdacontrols.action.hotbar_left": "Hotbar a la izquierda",
"lambdacontrols.action.hotbar_right": "Hotbar a la derecha",
"lambdacontrols.action.inventory": "Inventario",
"lambdacontrols.action.jump": "Saltar",
"lambdacontrols.action.left": "Caminar hacia la izquierda",
"lambdacontrols.action.pause_game": "Pausar juego",
"lambdacontrols.action.pick_block": "Recoger bloque",
"lambdacontrols.action.pickup": "Recoger",
"lambdacontrols.action.pickup_all": "Recoger todo",
"lambdacontrols.action.place": "Poner",
"lambdacontrols.action.player_list": "Lista de jugadores",
"lambdacontrols.action.quick_move": "Mover items rápidamente",
"lambdacontrols.action.right": "Caminar hacia la derecha",
"lambdacontrols.action.screenshot": "Tomar captura de pantalla",
"lambdacontrols.action.sneak": "Agacharse",
"lambdacontrols.action.sprint": "Correr",
"lambdacontrols.action.swap_hands": "Intercambiar manos",
"lambdacontrols.action.toggle_perspective": "Cambiar perspectiva",
"lambdacontrols.action.toggle_smooth_camera": "Cambiar cámara cinematográfica",
"lambdacontrols.action.use": "Usar",
"lambdacontrols.action.zoom": "Zoom",
"lambdacontrols.action.zoom.in": "Aumentar zoom",
"lambdacontrols.action.zoom.out": "Disminuir zoom",
"lambdacontrols.action.zoom.reset": "Restablecer zoom",
"lambdacontrols.button.a": "A",
"lambdacontrols.button.b": "B",
"lambdacontrols.button.x": "X",
"lambdacontrols.button.y": "Y",
"lambdacontrols.button.left_bumper": "Bumper izquierda",
"lambdacontrols.button.right_bumper": "Bumper derecha",
"lambdacontrols.button.back": "Regresar",
"lambdacontrols.button.start": "Iniciar",
"lambdacontrols.button.guide": "Guía",
"lambdacontrols.button.left_thumb": "Joystick izquierda",
"lambdacontrols.button.right_thumb": "Joystick derecha",
"lambdacontrols.button.dpad_up": "Cruceta arriba",
"lambdacontrols.button.dpad_right": "Cruceta derecha",
"lambdacontrols.button.dpad_down": "Cruceta abajo",
"lambdacontrols.button.dpad_left": "Cruceta izquierda",
"lambdacontrols.axis.left_x+": "Izquierda X+",
"lambdacontrols.axis.left_y+": "Izquierda Y+",
"lambdacontrols.axis.right_x+": "Derecha X+",
"lambdacontrols.axis.right_y+": "Derecha Y+",
"lambdacontrols.axis.left_trigger": "Gatillo izquierda",
"lambdacontrols.axis.right_trigger": "Gatillo derecha",
"lambdacontrols.axis.left_x-": "Izquierda X-",
"lambdacontrols.axis.left_y-": "Izquierda Y-",
"lambdacontrols.axis.right_x-": "Derecha X-",
"lambdacontrols.axis.right_y-": "Derecha Y-",
"lambdacontrols.button.unknown": "Desconocido (%d)",
"lambdacontrols.controller.connected": "Controlador %d conectado.",
"lambdacontrols.controller.disconnected": "Controlador %d desconectado.",
"lambdacontrols.controller.mappings.1": "Para configurar las asignaciones del controlador, utilice %sSDL2 Gamepad Tool%s",
"lambdacontrols.controller.mappings.3": "y poner el mapeo de asignaciones en `%s.minecraft/config/gamecontrollerdb.txt%s`.",
"lambdacontrols.controller.mappings.updated": "Mapeo actualizados!",
"lambdacontrols.controller_type.default": "por defecto",
"lambdacontrols.controller_type.dualshock": "DualShock",
"lambdacontrols.controller_type.switch": "Switch",
"lambdacontrols.controller_type.xbox": "Xbox",
"lambdacontrols.controller_type.steam": "Steam",
"lambdacontrols.controller_type.ouya": "OUYA",
"lambdacontrols.controls_mode.default": "Teclado/Ratón",
"lambdacontrols.controls_mode.controller": "Controlador",
"lambdacontrols.controls_mode.touchscreen": "Pantalla táctil",
"lambdacontrols.hud_side.left": "izquierda",
"lambdacontrols.hud_side.right": "derecha",
"lambdacontrols.menu.auto_switch_mode": "Modo de cambio automático",
"lambdacontrols.menu.controller": "Controlador",
"lambdacontrols.menu.controller2": "Segundo controlador",
"lambdacontrols.menu.controller_type": "Tipo de controlador",
"lambdacontrols.menu.controls_mode": "Modo",
"lambdacontrols.menu.dead_zone": "Zona muerta",
"lambdacontrols.menu.fast_block_placing": "Colocación rápida de bloques",
"lambdacontrols.menu.fly_drifting": "Fly Drifting",
"lambdacontrols.menu.fly_drifting_vertical": "Vertical Fly Drifting",
"lambdacontrols.menu.hud_enable": "Habilitar HUD",
"lambdacontrols.menu.hud_side": "Lado de HUD",
"lambdacontrols.menu.invert_right_x_axis": "Invertir derecha X",
"lambdacontrols.menu.invert_right_y_axis": "Invertir derecha Y",
"lambdacontrols.menu.keyboard_controls": "Controles del teclado...",
"lambdacontrols.menu.mouse_speed": "Velocidad del ratón",
"lambdacontrols.menu.reacharound.horizontal": "Colocación de bloque frontal",
"lambdacontrols.menu.reacharound.vertical": "Alcance vertical",
"lambdacontrols.menu.reload_controller_mappings": "Recargar asignaciones de controlador",
"lambdacontrols.menu.rotation_speed": "Velocidad de rotación",
"lambdacontrols.menu.title": "LambdaControls - Configuraciones",
"lambdacontrols.menu.title.controller": "Opciones de controlador",
"lambdacontrols.menu.title.controller_controls": "Controles de controlador",
"lambdacontrols.menu.title.gameplay": "Opciones de juego",
"lambdacontrols.menu.title.general": "Opciones generales",
"lambdacontrols.menu.title.hud": "Opciones de HUD",
"lambdacontrols.menu.unfocused_input": "Entrada desenfocada",
"lambdacontrols.menu.virtual_mouse": "Ratón virtual",
"lambdacontrols.menu.virtual_mouse.skin": "Piel de ratón virtual",
"lambdacontrols.narrator.unbound": "Resetear %s",
"lambdacontrols.not_bound": "No ligado",
"lambdacontrols.tooltip.auto_switch_mode": "Si el modo de controles debe cambiarse a Controlador automáticamente si hay uno conectado.",
"lambdacontrols.tooltip.controller2": "Segundo controlador a uso, que permite el soporte de Joy-Cons por ejemplo.",
"lambdacontrols.tooltip.controller_type": "El tipo de controlador para mostrar los botones correctos.",
"lambdacontrols.tooltip.controls_mode": "El modo de controles.",
"lambdacontrols.tooltip.dead_zone": "La zona muerta para los sticks analógicos del controlador.",
"lambdacontrols.tooltip.fast_block_placing": "Mientras vuela en modo creativo, permite la colocación rápida de bloques dependiendo su velocidad. §cEn algunos servidores, esto podría considerarse como trampa.",
"lambdacontrols.tooltip.fly_drifting": "Mientras vuela, habilita la deriva/inercia de vainilla.",
"lambdacontrols.tooltip.fly_drifting_vertical": "Mientras vuela, habilita la deriva/inercia vertical de vainilla.",
"lambdacontrols.tooltip.hud_enable": "Alterna el indicador del botón del controlador en pantalla.",
"lambdacontrols.tooltip.hud_side": "La posición del HUD.",
"lambdacontrols.tooltip.mouse_speed": "La velocidad del ratón emulada del controlador.",
"lambdacontrols.tooltip.reacharound.horizontal": "Habilita la colocación del bloque frontal, §cpodría considerarse trampa en algunos servidores§r.",
"lambdacontrols.tooltip.reacharound.vertical": "Habilita el alcance vertical, §cpodría considerarse trampa en algunos servidores§r.",
"lambdacontrols.tooltip.reload_controller_mappings": "Vuelve a cargar el archivo de asignaciones del controlador.",
"lambdacontrols.tooltip.rotation_speed": "La velocidad de rotación de la cámara en modo controlador.",
"lambdacontrols.tooltip.unfocused_input": "Habilita entrada del controlador cuando la ventana no está enfocada.",
"lambdacontrols.tooltip.virtual_mouse": "Habilite el ratón virtual que es útil en el caso de una pantalla dividida.",
"lambdacontrols.virtual_mouse.skin.default_light": "Ligera por defecto",
"lambdacontrols.virtual_mouse.skin.default_dark": "Oscura por defecto",
"lambdacontrols.virtual_mouse.skin.second_light": "Ligera segundario",
"lambdacontrols.virtual_mouse.skin.second_dark": "Oscura segundario"
}

View File

@@ -3,6 +3,7 @@
"key.lambdacontrols.look_left": "Regarder à gauche", "key.lambdacontrols.look_left": "Regarder à gauche",
"key.lambdacontrols.look_right": "Regarder à droite", "key.lambdacontrols.look_right": "Regarder à droite",
"key.lambdacontrols.look_up": "Regarder en haut", "key.lambdacontrols.look_up": "Regarder en haut",
"key.lambdacontrols.ring": "Affiche l'anneau de contrôle",
"lambdacontrols.action.attack": "Attaquer", "lambdacontrols.action.attack": "Attaquer",
"lambdacontrols.action.back": "Reculer", "lambdacontrols.action.back": "Reculer",
"lambdacontrols.action.chat": "Ouvrir le tchat", "lambdacontrols.action.chat": "Ouvrir le tchat",
@@ -31,12 +32,15 @@
"lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique", "lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique",
"lambdacontrols.action.use": "Utiliser", "lambdacontrols.action.use": "Utiliser",
"lambdacontrols.action.zoom": "Zoom", "lambdacontrols.action.zoom": "Zoom",
"lambdacontrols.action.zoom.in": "Augmenter le zoom",
"lambdacontrols.action.zoom.out": "Diminuer le zoom",
"lambdacontrols.action.zoom.reset": "Remettre le zoom à zéro",
"lambdacontrols.button.a": "A", "lambdacontrols.button.a": "A",
"lambdacontrols.button.b": "B", "lambdacontrols.button.b": "B",
"lambdacontrols.button.x": "X", "lambdacontrols.button.x": "X",
"lambdacontrols.button.y": "Y", "lambdacontrols.button.y": "Y",
"lambdacontrols.button.left_bumper": "Gâchette haute gauche", "lambdacontrols.button.left_bumper": "Gâchette gauche",
"lambdacontrols.button.right_bumper": "Gâchette haute droite", "lambdacontrols.button.right_bumper": "Gâchette droite",
"lambdacontrols.button.back": "Retour", "lambdacontrols.button.back": "Retour",
"lambdacontrols.button.start": "Touche Menu", "lambdacontrols.button.start": "Touche Menu",
"lambdacontrols.button.guide": "Guide", "lambdacontrols.button.guide": "Guide",
@@ -60,8 +64,9 @@
"lambdacontrols.controller.connected": "Manette %d connecté.", "lambdacontrols.controller.connected": "Manette %d connecté.",
"lambdacontrols.controller.disconnected": "Manette %d déconnecté.", "lambdacontrols.controller.disconnected": "Manette %d déconnecté.",
"lambdacontrols.controller.mappings.1": "Pour configurer les correspondances de la manette, veuillez utiliser %sSDL2 Gamepad Tool%s", "lambdacontrols.controller.mappings.1": "Pour configurer les correspondances de la manette, veuillez utiliser %sSDL2 Gamepad Tool%s",
"lambdacontrols.controller.mappings.2": "(%s%s%s),",
"lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.", "lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.",
"lambdacontrols.controller.mappings.error": "Une erreur est apparue pendant le chargement des manettes.",
"lambdacontrols.controller.mappings.error.write": "Une erreur est apparue pendant l'écriture des manettes au fichier.",
"lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!", "lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!",
"lambdacontrols.controller_type.default": "default", "lambdacontrols.controller_type.default": "default",
"lambdacontrols.controller_type.dualshock": "DualShock", "lambdacontrols.controller_type.dualshock": "DualShock",
@@ -80,16 +85,19 @@
"lambdacontrols.menu.controller_type": "Type de manette", "lambdacontrols.menu.controller_type": "Type de manette",
"lambdacontrols.menu.controls_mode": "Mode", "lambdacontrols.menu.controls_mode": "Mode",
"lambdacontrols.menu.dead_zone": "Zone morte", "lambdacontrols.menu.dead_zone": "Zone morte",
"lambdacontrols.menu.fast_block_placing": "Placement rapide de blocs",
"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.mappings.open_input_str": "Ouvrir l'éditeur de fichier des manettes",
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris", "lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
"lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes", "lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc",
"lambdacontrols.menu.reacharound.vertical": "Placement vertical",
"lambdacontrols.menu.reload_controller_mappings": "Recharger les 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",
"lambdacontrols.menu.title.controller": "Options de manettes", "lambdacontrols.menu.title.controller": "Options de manettes",
@@ -97,7 +105,7 @@
"lambdacontrols.menu.title.gameplay": "Options de Gameplay", "lambdacontrols.menu.title.gameplay": "Options de Gameplay",
"lambdacontrols.menu.title.general": "Options générales", "lambdacontrols.menu.title.general": "Options générales",
"lambdacontrols.menu.title.hud": "Options du HUD", "lambdacontrols.menu.title.hud": "Options du HUD",
"lambdacontrols.menu.unbound": "Délier", "lambdacontrols.menu.title.mappings.string": "Éditeur du fichier des manettes",
"lambdacontrols.menu.unfocused_input": "Entrée en fond", "lambdacontrols.menu.unfocused_input": "Entrée en fond",
"lambdacontrols.menu.virtual_mouse": "Souris virtuelle", "lambdacontrols.menu.virtual_mouse": "Souris virtuelle",
"lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle", "lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle",
@@ -108,14 +116,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

@@ -3,6 +3,7 @@
"key.lambdacontrols.look_left": "Regarder à gauche", "key.lambdacontrols.look_left": "Regarder à gauche",
"key.lambdacontrols.look_right": "Regarder à droite", "key.lambdacontrols.look_right": "Regarder à droite",
"key.lambdacontrols.look_up": "Regarder en haut", "key.lambdacontrols.look_up": "Regarder en haut",
"key.lambdacontrols.ring": "Affiche l'anneau de contrôle",
"lambdacontrols.action.attack": "Attaquer", "lambdacontrols.action.attack": "Attaquer",
"lambdacontrols.action.back": "Reculer", "lambdacontrols.action.back": "Reculer",
"lambdacontrols.action.chat": "Ouvrir le tchat", "lambdacontrols.action.chat": "Ouvrir le tchat",
@@ -31,12 +32,15 @@
"lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique", "lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique",
"lambdacontrols.action.use": "Utiliser", "lambdacontrols.action.use": "Utiliser",
"lambdacontrols.action.zoom": "Zoom", "lambdacontrols.action.zoom": "Zoom",
"lambdacontrols.action.zoom.in": "Augmenter le zoom",
"lambdacontrols.action.zoom.out": "Diminuer le zoom",
"lambdacontrols.action.zoom.reset": "Remettre le zoom à zéro",
"lambdacontrols.button.a": "A", "lambdacontrols.button.a": "A",
"lambdacontrols.button.b": "B", "lambdacontrols.button.b": "B",
"lambdacontrols.button.x": "X", "lambdacontrols.button.x": "X",
"lambdacontrols.button.y": "Y", "lambdacontrols.button.y": "Y",
"lambdacontrols.button.left_bumper": "Gâchette haute gauche", "lambdacontrols.button.left_bumper": "Gâchette gauche",
"lambdacontrols.button.right_bumper": "Gâchette haute droite", "lambdacontrols.button.right_bumper": "Gâchette droite",
"lambdacontrols.button.back": "Retour", "lambdacontrols.button.back": "Retour",
"lambdacontrols.button.start": "Touche Menu", "lambdacontrols.button.start": "Touche Menu",
"lambdacontrols.button.guide": "Guide", "lambdacontrols.button.guide": "Guide",
@@ -60,8 +64,9 @@
"lambdacontrols.controller.connected": "Manette %d connecté.", "lambdacontrols.controller.connected": "Manette %d connecté.",
"lambdacontrols.controller.disconnected": "Manette %d déconnecté.", "lambdacontrols.controller.disconnected": "Manette %d déconnecté.",
"lambdacontrols.controller.mappings.1": "Pour configurer les correspondances de la manette, veuillez utiliser %sSDL2 Gamepad Tool%s", "lambdacontrols.controller.mappings.1": "Pour configurer les correspondances de la manette, veuillez utiliser %sSDL2 Gamepad Tool%s",
"lambdacontrols.controller.mappings.2": "(%s%s%s),",
"lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.", "lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.",
"lambdacontrols.controller.mappings.error": "Une erreur est apparue pendant le chargement des manettes.",
"lambdacontrols.controller.mappings.error.write": "Une erreur est apparue pendant l'écriture des manettes au fichier.",
"lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!", "lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!",
"lambdacontrols.controller_type.default": "default", "lambdacontrols.controller_type.default": "default",
"lambdacontrols.controller_type.dualshock": "DualShock", "lambdacontrols.controller_type.dualshock": "DualShock",
@@ -80,16 +85,19 @@
"lambdacontrols.menu.controller_type": "Type de manette", "lambdacontrols.menu.controller_type": "Type de manette",
"lambdacontrols.menu.controls_mode": "Mode", "lambdacontrols.menu.controls_mode": "Mode",
"lambdacontrols.menu.dead_zone": "Zone morte", "lambdacontrols.menu.dead_zone": "Zone morte",
"lambdacontrols.menu.fast_block_placing": "Placement rapide de blocs",
"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.mappings.open_input_str": "Ouvrir l'éditeur de fichier des manettes",
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris", "lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
"lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes", "lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc",
"lambdacontrols.menu.reacharound.vertical": "Placement vertical",
"lambdacontrols.menu.reload_controller_mappings": "Recharger les 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",
"lambdacontrols.menu.title.controller": "Options de manettes", "lambdacontrols.menu.title.controller": "Options de manettes",
@@ -97,7 +105,7 @@
"lambdacontrols.menu.title.gameplay": "Options de Gameplay", "lambdacontrols.menu.title.gameplay": "Options de Gameplay",
"lambdacontrols.menu.title.general": "Options générales", "lambdacontrols.menu.title.general": "Options générales",
"lambdacontrols.menu.title.hud": "Options du HUD", "lambdacontrols.menu.title.hud": "Options du HUD",
"lambdacontrols.menu.unbound": "Délier", "lambdacontrols.menu.title.mappings.string": "Éditeur du fichier des manettes",
"lambdacontrols.menu.unfocused_input": "Entrée en fond", "lambdacontrols.menu.unfocused_input": "Entrée en fond",
"lambdacontrols.menu.virtual_mouse": "Souris virtuelle", "lambdacontrols.menu.virtual_mouse": "Souris virtuelle",
"lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle", "lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle",
@@ -108,14 +116,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

@@ -0,0 +1,130 @@
{
"key.lambdacontrols.look_down": "视角下移",
"key.lambdacontrols.look_left": "视角左移",
"key.lambdacontrols.look_right": "视角右移",
"key.lambdacontrols.look_up": "视角上移",
"lambdacontrols.action.attack": "攻击",
"lambdacontrols.action.back": "向后移动",
"lambdacontrols.action.chat": "打开聊天栏",
"lambdacontrols.action.drop_item": "丢弃所选物品",
"lambdacontrols.action.exit": "退出",
"lambdacontrols.action.forward": "向前移动",
"lambdacontrols.action.hit": "挖掘",
"lambdacontrols.action.hotbar_left": "向左循环选择快捷栏",
"lambdacontrols.action.hotbar_right": "向右循环选择快捷栏",
"lambdacontrols.action.inventory": "物品栏",
"lambdacontrols.action.jump": "跳跃",
"lambdacontrols.action.left": "向左移动",
"lambdacontrols.action.pause_game": "暂停游戏",
"lambdacontrols.action.pick_block": "选取方块",
"lambdacontrols.action.pickup": "拿取一个/拿取一半",
"lambdacontrols.action.pickup_all": "拿取一组/拿取全部",
"lambdacontrols.action.place": "放置方块",
"lambdacontrols.action.player_list": "玩家列表",
"lambdacontrols.action.quick_move": "快速移动物品",
"lambdacontrols.action.right": "向右移动",
"lambdacontrols.action.screenshot": "截图",
"lambdacontrols.action.sneak": "潜行",
"lambdacontrols.action.sprint": "疾跑",
"lambdacontrols.action.swap_hands": "与副手交换",
"lambdacontrols.action.toggle_perspective": "切换视角",
"lambdacontrols.action.toggle_smooth_camera": "切换电影视角",
"lambdacontrols.action.use": "使用物品/放置方块",
"lambdacontrols.action.zoom": "视野缩放",
"lambdacontrols.action.zoom.in": "缩放时将视野推近",
"lambdacontrols.action.zoom.out": "缩放时将视野拉远",
"lambdacontrols.action.zoom.reset": "缩放时重置缩放距离",
"lambdacontrols.button.a": "A",
"lambdacontrols.button.b": "B",
"lambdacontrols.button.x": "X",
"lambdacontrols.button.y": "Y",
"lambdacontrols.button.left_bumper": "左肩键",
"lambdacontrols.button.right_bumper": "右肩键",
"lambdacontrols.button.back": "选择键",
"lambdacontrols.button.start": "开始键",
"lambdacontrols.button.guide": "功能键",
"lambdacontrols.button.left_thumb": "左摇杆(按压)",
"lambdacontrols.button.right_thumb": "右摇杆(按压)",
"lambdacontrols.button.dpad_up": "十字键上",
"lambdacontrols.button.dpad_right": "十字键右",
"lambdacontrols.button.dpad_down": "十字键下",
"lambdacontrols.button.dpad_left": "十字键左",
"lambdacontrols.axis.left_x+": "左摇杆右X轴正向",
"lambdacontrols.axis.left_y+": "左摇杆上Y轴正向",
"lambdacontrols.axis.right_x+": "右摇杆右X轴正向",
"lambdacontrols.axis.right_y+": "右摇杆上Y轴正向",
"lambdacontrols.axis.left_trigger": "左扳机键",
"lambdacontrols.axis.right_trigger": "右扳机键",
"lambdacontrols.axis.left_x-": "左摇杆左X轴负向",
"lambdacontrols.axis.left_y-": "左摇杆下Y轴负向",
"lambdacontrols.axis.right_x-": "右摇杆左X轴负向",
"lambdacontrols.axis.right_y-": "右摇杆下Y轴负向",
"lambdacontrols.button.unknown": "未知(%d",
"lambdacontrols.controller.connected": "手柄%d已连接。",
"lambdacontrols.controller.disconnected": "手柄%d已断开。",
"lambdacontrols.controller.mappings.1": "请使用%sSDL2 Gamepad Tool%s配置手柄键位映射",
"lambdacontrols.controller.mappings.3": "并将键位映射文件放入此路径:`%s.minecraft/config/gamecontrollerdb.txt%s`。",
"lambdacontrols.controller.mappings.updated": "键位映射已更新!",
"lambdacontrols.controller_type.default": "默认",
"lambdacontrols.controller_type.dualshock": "DualShock",
"lambdacontrols.controller_type.switch": "Switch",
"lambdacontrols.controller_type.xbox": "Xbox",
"lambdacontrols.controller_type.steam": "Steam",
"lambdacontrols.controller_type.ouya": "OUYA",
"lambdacontrols.controls_mode.default": "键鼠",
"lambdacontrols.controls_mode.controller": "手柄",
"lambdacontrols.controls_mode.touchscreen": "触摸屏",
"lambdacontrols.hud_side.left": "左侧",
"lambdacontrols.hud_side.right": "右侧",
"lambdacontrols.menu.auto_switch_mode": "自动切换模式",
"lambdacontrols.menu.controller": "手柄",
"lambdacontrols.menu.controller2": "额外手柄",
"lambdacontrols.menu.controller_type": "手柄类型",
"lambdacontrols.menu.controls_mode": "模式",
"lambdacontrols.menu.dead_zone": "摇杆死区",
"lambdacontrols.menu.fast_block_placing": "方块快速放置",
"lambdacontrols.menu.fly_drifting": "水平方向飞行惯性",
"lambdacontrols.menu.fly_drifting_vertical": "垂直方向飞行惯性",
"lambdacontrols.menu.hud_enable": "启用HUD",
"lambdacontrols.menu.hud_side": "HUD位置",
"lambdacontrols.menu.invert_right_x_axis": "反转右摇杆X轴",
"lambdacontrols.menu.invert_right_y_axis": "反转右摇杆Y轴",
"lambdacontrols.menu.keyboard_controls": "键盘控制...",
"lambdacontrols.menu.mouse_speed": "鼠标移动速度",
"lambdacontrols.menu.reacharound.horizontal": "水平方向方块放置辅助",
"lambdacontrols.menu.reacharound.vertical": "垂直方向方块放置辅助",
"lambdacontrols.menu.reload_controller_mappings": "重新加载手柄键位映射",
"lambdacontrols.menu.rotation_speed": "镜头旋转速度",
"lambdacontrols.menu.title": "LambdaControls - 设置",
"lambdacontrols.menu.title.controller": "手柄选项",
"lambdacontrols.menu.title.controller_controls": "手柄控制",
"lambdacontrols.menu.title.gameplay": "游戏内容选项",
"lambdacontrols.menu.title.general": "通用选项",
"lambdacontrols.menu.title.hud": "HUD选项",
"lambdacontrols.menu.unfocused_input": "非活动状态输入",
"lambdacontrols.menu.virtual_mouse": "虚拟鼠标",
"lambdacontrols.menu.virtual_mouse.skin": "虚拟鼠标指针样式",
"lambdacontrols.narrator.unbound": "取消绑定 %s",
"lambdacontrols.not_bound": "未绑定",
"lambdacontrols.tooltip.auto_switch_mode": "如果已有手柄连接,则自动切换为手柄操作模式。",
"lambdacontrols.tooltip.controller2": "使用额外的手柄比如将一左一右的两个Joy-Con合为一个功能完全的手柄。",
"lambdacontrols.tooltip.controller_type": "选择手柄类型,以显示对应的按键图标。",
"lambdacontrols.tooltip.controls_mode": "操作模式",
"lambdacontrols.tooltip.dead_zone": "手柄摇杆的死区,死区决定摇杆要偏移中心位置多远才能让摇杆输入有效。",
"lambdacontrols.tooltip.fast_block_placing": "在创造模式中处于飞行状态时可以根据你飞行的速度快速放置方块。§c在部分服务器可能会被认定为作弊。",
"lambdacontrols.tooltip.fly_drifting": "处于飞行状态时,启用原版的水平方向飞行惯性(缓停滑行)。",
"lambdacontrols.tooltip.fly_drifting_vertical": "处于飞行状态时,启用原版的垂直方向飞行惯性(缓停滑行)。",
"lambdacontrols.tooltip.hud_enable": "显示手柄按键操作提示。",
"lambdacontrols.tooltip.hud_side": "HUD的位置位于画面的哪一侧。",
"lambdacontrols.tooltip.mouse_speed": "手柄模拟的鼠标的移动速度。",
"lambdacontrols.tooltip.reacharound.horizontal": "启用水平方向方块放置辅助可在脚下方块的前方放置方块。§c在部分服务器可能会被认定为作弊。",
"lambdacontrols.tooltip.reacharound.vertical": "启用垂直方向方块放置辅助可在脚下方块的下方放置方块。§c在部分服务器可能会被认定为作弊。",
"lambdacontrols.tooltip.reload_controller_mappings": "重新加载手柄的按键映射文件。",
"lambdacontrols.tooltip.rotation_speed": "手柄操作模式下的镜头旋转速度。",
"lambdacontrols.tooltip.unfocused_input": "即使游戏窗口处于非活动状态,也允许手柄进行按键输入。",
"lambdacontrols.tooltip.virtual_mouse": "启用虚拟鼠标,在分屏的情况下很有用。",
"lambdacontrols.virtual_mouse.skin.default_light": "默认样式(白色)",
"lambdacontrols.virtual_mouse.skin.default_dark": "默认样式(黑色)",
"lambdacontrols.virtual_mouse.skin.second_light": "额外样式(白色)",
"lambdacontrols.virtual_mouse.skin.second_dark": "额外样式(黑色)"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -4,6 +4,8 @@
controls = "default" controls = "default"
# Auto switch mode. # Auto switch mode.
auto_switch_mode = false auto_switch_mode = false
# Debug mode
debug = false
[hud] [hud]
# Enables the HUD. # Enables the HUD.
@@ -21,9 +23,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.
@@ -40,7 +44,7 @@ auto_switch_mode = false
# Controller's dead zone. # Controller's dead zone.
dead_zone = 0.20 dead_zone = 0.20
# Rotation speed for look directions. # Rotation speed for look directions.
rotation_speed = 40.0 rotation_speed = 10.0
# Mouse speed in GUI. # Mouse speed in GUI.
mouse_speed = 30.0 mouse_speed = 30.0
# Inverts the right X axis. # Inverts the right X axis.

View File

@@ -31,23 +31,27 @@
"lambdacontrols_compat.mixins.json" "lambdacontrols_compat.mixins.json"
], ],
"depends": { "depends": {
"fabricloader": ">=0.4.0", "fabricloader": ">=0.9.0",
"fabric": "*", "fabric": ">=0.4.0",
"minecraft": ">=1.15", "minecraft": ">=1.16.2",
"spruceui": ">=1.3.5" "spruceui": ">=1.6.3"
}, },
"recommends": { "recommends": {
"modmenu": ">=1.9.0", "modmenu": ">=1.12.2"
"okzoomer": ">=1.0.4"
}, },
"suggests": { "suggests": {
"flamingo": "*", "flamingo": "*",
"roughlyenoughitems": ">=3.4.5" "roughlyenoughitems": ">=4.5.5",
"okzoomer": ">=4.0.0"
}, },
"breaks": { "breaks": {
"modmenu": "<1.9.0" "modmenu": "<1.12.2",
"optifabric": "*"
}, },
"custom": { "custom": {
"modmenu:clientsideOnly": true "modupdater": {
"strategy": "curseforge",
"projectID": 354231
}
} }
} }

View File

@@ -5,7 +5,6 @@
"client": [ "client": [
"AbstractButtonWidgetAccessor", "AbstractButtonWidgetAccessor",
"AdvancementsScreenAccessor", "AdvancementsScreenAccessor",
"ContainerScreenMixin",
"ClientPlayerEntityMixin", "ClientPlayerEntityMixin",
"ClientPlayNetworkHandlerMixin", "ClientPlayNetworkHandlerMixin",
"ControlsOptionsScreenMixin", "ControlsOptionsScreenMixin",
@@ -13,11 +12,12 @@
"EntryListWidgetAccessor", "EntryListWidgetAccessor",
"GameOptionsMixin", "GameOptionsMixin",
"GameRendererMixin", "GameRendererMixin",
"HandledScreenMixin",
"KeyBindingMixin", "KeyBindingMixin",
"MinecraftClientMixin", "MinecraftClientMixin",
"MouseMixin", "MouseMixin",
"OptionsScreenMixin",
"RecipeBookWidgetAccessor", "RecipeBookWidgetAccessor",
"SettingsScreenMixin",
"WorldRendererMixin" "WorldRendererMixin"
], ],
"injectors": { "injectors": {

View File

@@ -4,6 +4,8 @@
"plugin": "me.lambdaurora.lambdacontrols.client.compat.LambdaControlsMixinPlugin", "plugin": "me.lambdaurora.lambdacontrols.client.compat.LambdaControlsMixinPlugin",
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"client": [ "client": [
"EntryListWidgetAccessor",
"EntryWidgetAccessor",
"RecipeViewingScreenAccessor", "RecipeViewingScreenAccessor",
"VillagerRecipeViewingScreenAccessor" "VillagerRecipeViewingScreenAccessor"
], ],

View File

@@ -2,18 +2,18 @@
org.gradle.jvmargs=-Xmx1G org.gradle.jvmargs=-Xmx1G
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/use # check these on https://fabricmc.net/use
minecraft_version=1.15.2 minecraft_version=1.16.2
yarn_mappings=1.15.2+build.14:v2 yarn_mappings=1.16.2+build.25
loader_version=0.7.6+build.180 loader_version=0.9.1+build.205
# Mod Properties # Mod Properties
mod_version = 1.2.0 mod_version = 1.5.0
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.4.29+build.290-1.15 fabric_version=0.17.2+build.396-1.16
spruceui_version=1.3.5 spruceui_version=1.6.4
modmenu_version=1.10.1+build.30 modmenu_version=1.14.6+build.31

Binary file not shown.

View File

@@ -1,6 +1,5 @@
#Mon Oct 28 18:23:18 CET 2019
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip

35
gradlew vendored
View File

@@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -125,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if $cygwin ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
@@ -154,19 +156,19 @@ if $cygwin ; then
else else
eval `echo args$i`="\"$arg\"" eval `echo args$i`="\"$arg\""
fi fi
i=$((i+1)) i=`expr $i + 1`
done done
case $i in case $i in
(0) set -- ;; 0) set -- ;;
(1) set -- "$args0" ;; 1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;; 2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;; 3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
@@ -175,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " " echo " "
} }
APP_ARGS=$(save "$@") APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules # Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

204
gradlew.bat vendored
View File

@@ -1,100 +1,104 @@
@rem @rem
@rem Copyright 2015 the original author or authors. @rem Copyright 2015 the original author or authors.
@rem @rem
@rem Licensed under the Apache License, Version 2.0 (the "License"); @rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License. @rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at @rem You may obtain a copy of the License at
@rem @rem
@rem https://www.apache.org/licenses/LICENSE-2.0 @rem https://www.apache.org/licenses/LICENSE-2.0
@rem @rem
@rem Unless required by applicable law or agreed to in writing, software @rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS, @rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@rem @rem
@rem ########################################################################## @rem ##########################################################################
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Resolve any "." and ".." in APP_HOME to make it shorter.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Find java.exe @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
if defined JAVA_HOME goto findJavaFromJavaHome set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
set JAVA_EXE=java.exe @rem Find java.exe
%JAVA_EXE% -version >NUL 2>&1 if defined JAVA_HOME goto findJavaFromJavaHome
if "%ERRORLEVEL%" == "0" goto init
set JAVA_EXE=java.exe
echo. %JAVA_EXE% -version >NUL 2>&1
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if "%ERRORLEVEL%" == "0" goto init
echo.
echo Please set the JAVA_HOME variable in your environment to match the echo.
echo location of your Java installation. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
goto fail echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=% goto fail
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
:findJavaFromJavaHome
if exist "%JAVA_EXE%" goto init set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% if exist "%JAVA_EXE%" goto init
echo.
echo Please set the JAVA_HOME variable in your environment to match the echo.
echo location of your Java installation. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
goto fail echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
:init
@rem Get command-line arguments, handling Windows variants goto fail
if not "%OS%" == "Windows_NT" goto win9xME_args :init
@rem Get command-line arguments, handling Windows variants
:win9xME_args
@rem Slurp the command line arguments. if not "%OS%" == "Windows_NT" goto win9xME_args
set CMD_LINE_ARGS=
set _SKIP=2 :win9xME_args
@rem Slurp the command line arguments.
:win9xME_args_slurp set CMD_LINE_ARGS=
if "x%~1" == "x" goto execute set _SKIP=2
set CMD_LINE_ARGS=%* :win9xME_args_slurp
if "x%~1" == "x" goto execute
:execute
@rem Setup the command line set CMD_LINE_ARGS=%*
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell @rem Execute Gradle
if "%ERRORLEVEL%"=="0" goto mainEnd "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:fail :end
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of @rem End local scope for the variables with windows NT shell
rem the _cmd.exe /c_ return code! if "%ERRORLEVEL%"=="0" goto mainEnd
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1 :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
:mainEnd rem the _cmd.exe /c_ return code!
if "%OS%"=="Windows_NT" endlocal if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:omega
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -21,6 +21,8 @@ dependencies {
} }
api 'org.spigotmc:spigot-api:1.15.1-R0.1-SNAPSHOT' api 'org.spigotmc:spigot-api:1.15.1-R0.1-SNAPSHOT'
api 'io.netty:netty-all:4.1.28.Final' api 'io.netty:netty-all:4.1.28.Final'
implementation "com.electronwill.night-config:core:3.5.3"
implementation "com.electronwill.night-config:toml:3.5.3"
} }
processResources { processResources {

View File

@@ -36,6 +36,6 @@ public class LambdaControlsConfig
configDir.mkdirs(); configDir.mkdirs();
this.config.load(); this.config.load();
this.plugin.log("Configuration loaded."); this.plugin.log("Configuration loaded.");
LambdaControlsFeature.FRONT_BLOCK_PLACING.setAllowed(this.config.getOrElse("gameplay.front_block_placing", DEFAULT_FRONT_BLOCK_PLACING)); LambdaControlsFeature.HORIZONTAL_REACHAROUND.setAllowed(this.config.getOrElse("gameplay.front_block_placing", DEFAULT_FRONT_BLOCK_PLACING));
} }
} }

View File

@@ -57,7 +57,7 @@ public class LambdaControlsSpigot extends JavaPlugin implements PluginMessageLis
PLAYERS_CONTROLS_MODE.put(player, ControlsMode.DEFAULT); PLAYERS_CONTROLS_MODE.put(player, ControlsMode.DEFAULT);
this.requestPlayerControlsMode(player); this.requestPlayerControlsMode(player);
this.updatePlayerFeature(player, LambdaControlsFeature.FRONT_BLOCK_PLACING); this.updatePlayerFeature(player, LambdaControlsFeature.HORIZONTAL_REACHAROUND);
}); });
} }
@@ -108,7 +108,7 @@ public class LambdaControlsSpigot extends JavaPlugin implements PluginMessageLis
PlayerChangeControlsModeEvent event = new PlayerChangeControlsModeEvent(player, controlsMode); PlayerChangeControlsModeEvent event = new PlayerChangeControlsModeEvent(player, controlsMode);
this.getServer().getPluginManager().callEvent(event); this.getServer().getPluginManager().callEvent(event);
}); });
this.updatePlayerFeature(player, LambdaControlsFeature.FRONT_BLOCK_PLACING); this.updatePlayerFeature(player, LambdaControlsFeature.HORIZONTAL_REACHAROUND);
} else if (channel.equals(CONTROLS_MODE_CHANNEL.toString())) { } else if (channel.equals(CONTROLS_MODE_CHANNEL.toString())) {
NettyPacketBuffer buffer = new NettyPacketBuffer(Unpooled.copiedBuffer(message)); NettyPacketBuffer buffer = new NettyPacketBuffer(Unpooled.copiedBuffer(message));
ControlsMode.byId(buffer.readString(32)).ifPresent(controlsMode -> { ControlsMode.byId(buffer.readString(32)).ifPresent(controlsMode -> {