Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47b0cfdad4 | ||
|
|
f56eb9e0ad | ||
|
|
bc712f138b | ||
|
|
66721b00b9 | ||
|
|
e0762b16ee | ||
|
|
7bfff00841 | ||
|
|
a8c969b176 | ||
|
|
f1607fe1bf | ||
|
|
d52a630cb4 | ||
|
|
502e9ff15e | ||
|
|
32e4ad1b7c | ||
|
|
4ae6404ad2 | ||
|
|
185d5e4303 | ||
|
|
0d02e56134 | ||
|
|
738d094fb1 | ||
|
|
7c06afb4a4 | ||
|
|
647e03134f | ||
|
|
1b5a0e470e | ||
|
|
e6da7adf89 | ||
|
|
46d43c6f46 | ||
|
|
9ae1bc2a3b |
47
CHANGELOG.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Changelog
|
||||
|
||||
## v1.0.0
|
||||
|
||||
:tada: First release! :tada:
|
||||
|
||||
- Added controller support.
|
||||
- Added new controls settings GUI.
|
||||
- Added experimental touchscreen support.
|
||||
- Added controller controls GUI.
|
||||
- Added a lot of options.
|
||||
- Added key bindings for look around.
|
||||
- And more!
|
||||
|
||||
### v1.0.1
|
||||
|
||||
- Fixed tutorial toast to look around not affected by camera movement done with a controller. ([#2](https://github.com/LambdAurora/LambdaControls/issues/2))
|
||||
|
||||
### v1.0.2 (Unofficial)
|
||||
|
||||
This update was never pushed but was aiming to fix [#4](https://github.com/LambdAurora/LambdaControls/issues/4).
|
||||
|
||||
- Fixed the toggle sneak button binding.
|
||||
- Fixed broken chat arrow keys.
|
||||
- Optimized a little bit the button indicator. (need more work)
|
||||
|
||||
## v1.1.0 - Chording update
|
||||
|
||||
This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAurora/LambdaControls/issues/9)).
|
||||
|
||||
- Rewrote everything (almost).
|
||||
- Added [networking](https://github.com/LambdAurora/LambdaControls/wiki/LambdaControls-Networking) for some features.
|
||||
- Added second controller support (Joycons supported now hopefully).
|
||||
- Added chording.
|
||||
- Added better developer API
|
||||
- Added hover messages ([#5](https://github.com/LambdAurora/LambdaControls/issues/5)).
|
||||
- Added hotbar button bindings ([#7](https://github.com/LambdAurora/LambdaControls/issues/7)).
|
||||
- Added front block placing feature ([#8](https://github.com/LambdAurora/LambdaControls/issues/8)).
|
||||
- Added no creative fly drifting ([#8](https://github.com/LambdAurora/LambdaControls/issues/8)).
|
||||
- Added option to enable controller focus.
|
||||
- Added [OkZoomer](https://github.com/joaoh1/OkZoomer) compatibility.
|
||||
- Added D-pad movements in inventories.
|
||||
- Increased max speed ranges.
|
||||
- Added [SpruceUI](https://github.com/LambdAurora/SpruceUI) for cleaner custom UI widgets.
|
||||
- Added reset settings button.
|
||||
- HUD side affects button indicators now.
|
||||
- Added support for Advancements tabs.
|
||||
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
37
README.md
@@ -3,6 +3,39 @@
|
||||

|
||||
[](https://raw.githubusercontent.com/LambdAurora/LambdaControls/master/LICENSE)
|
||||

|
||||

|
||||

|
||||
[](https://www.curseforge.com/minecraft/mc-mods/lambdacontrols)
|
||||
|
||||
A Fabric Minecraft mod which add better controls.
|
||||
It allows the use of a controller or the touchscreen.
|
||||
A Fabric Minecraft mod which adds better controls like controller support.
|
||||
|
||||
## What's this mod?
|
||||
|
||||
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).
|
||||
|
||||
## ✅ Features:
|
||||
|
||||
- Controller support
|
||||
- Touchscreen support (very experimental and buggy).
|
||||
- Keyboard controls to look around.
|
||||
- Toggleable on screen button indicator (like in Bedrock Edition).
|
||||
- Many Bedrock Edition features:
|
||||
- Toggleable fly drifting
|
||||
- Front block placing (be careful with this one)
|
||||
- New controls settings!
|
||||
- Many options in config to change to your liking.
|
||||
- Many controllers supported and in a simply way your own controller mappings.
|
||||
|
||||
## 🎮 Supported Controllers:
|
||||
|
||||
- Dualshock controllers
|
||||
- Xbox controllers
|
||||
- Switch Pro controllers
|
||||
- Joycons
|
||||
- And many more!
|
||||
|
||||
## Build
|
||||
|
||||
Just do `./gradlew :fabric:build` and everything should build just fine!
|
||||
|
||||
63
build.gradle
@@ -1,72 +1,21 @@
|
||||
plugins {
|
||||
id 'fabric-loom' version '0.2.6-SNAPSHOT'
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
archivesBaseName = project.archives_base_name
|
||||
version = project.mod_version
|
||||
allprojects {
|
||||
group = project.maven_group
|
||||
|
||||
minecraft {
|
||||
}
|
||||
version = project.mod_version
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven { url = 'https://aperlambda.github.io/maven' }
|
||||
maven {
|
||||
name = 'CottonMC'
|
||||
url = 'http://server.bbkr.space:8081/artifactory/libs-snapshot'
|
||||
}
|
||||
repositories {
|
||||
maven { url = "https://jitpack.io" }
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//to change the versions see the gradle.properties file
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}"
|
||||
modCompile "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modApi "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
|
||||
modCompile "io.github.prospector:modmenu:1.8.0+build.16"
|
||||
//modCompile "io.github.cottonmc:cotton-client-commands:0.4.2+1.14.3-SNAPSHOT"
|
||||
|
||||
implementation "org.jetbrains:annotations:17.0.0"
|
||||
implementation "org.aperlambda:lambdajcommon:1.7.2"
|
||||
implementation "com.electronwill.night-config:core:3.5.3"
|
||||
implementation "com.electronwill.night-config:toml:3.5.3"
|
||||
include "org.jetbrains:annotations:17.0.0"
|
||||
include "org.aperlambda:lambdajcommon:1.7.2"
|
||||
include "com.electronwill.night-config:core:3.5.3"
|
||||
include "com.electronwill.night-config:toml:3.5.3"
|
||||
|
||||
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
||||
// You may need to force-disable transitiveness on them.
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include "fabric.mod.json"
|
||||
expand "version": project.version
|
||||
}
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
exclude "fabric.mod.json"
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
@@ -78,11 +27,9 @@ task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier = "sources"
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
jar {
|
||||
from "LICENSE"
|
||||
}
|
||||
|
||||
/*
|
||||
// configure the maven publication
|
||||
publishing {
|
||||
publications {
|
||||
@@ -101,4 +48,4 @@ publishing {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
17
core/build.gradle
Normal file
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
archivesBaseName = project.archives_base_name + "-core"
|
||||
|
||||
dependencies {
|
||||
api "org.jetbrains:annotations:17.0.0"
|
||||
api "org.aperlambda:lambdajcommon:1.8.0"
|
||||
api "com.electronwill.night-config:core:3.5.3"
|
||||
api "com.electronwill.night-config:toml:3.5.3"
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
package me.lambdaurora.lambdacontrols;
|
||||
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -18,6 +17,10 @@ import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents the controls mode.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public enum ControlsMode implements Nameable
|
||||
{
|
||||
@@ -39,17 +42,18 @@ public enum ControlsMode implements Nameable
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translated name of this controls mode.
|
||||
* Gets the translation key of this controls mode.
|
||||
*
|
||||
* @return The translated name of this controls mode.
|
||||
* @return The translated key of this controls mode.
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public String get_translated_name()
|
||||
public String getTranslationKey()
|
||||
{
|
||||
return I18n.translate("lambdacontrols.controls_mode." + this.get_name());
|
||||
return "lambdacontrols.controls_mode." + this.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String get_name()
|
||||
public @NotNull String getName()
|
||||
{
|
||||
return this.name().toLowerCase();
|
||||
}
|
||||
@@ -60,8 +64,8 @@ public enum ControlsMode implements Nameable
|
||||
* @param id The identifier of the controls mode.
|
||||
* @return The controls mode if found, else empty.
|
||||
*/
|
||||
public static Optional<ControlsMode> by_id(@NotNull String id)
|
||||
public static Optional<ControlsMode> byId(@NotNull String id)
|
||||
{
|
||||
return Arrays.stream(values()).filter(mode -> mode.get_name().equalsIgnoreCase(id)).findFirst();
|
||||
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.aperlambda.lambdacommon.Identifier;
|
||||
|
||||
/**
|
||||
* Represents the constants used by LambdaControls.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class LambdaControlsConstants
|
||||
{
|
||||
public static final String NAMESPACE = "lambdacontrols";
|
||||
public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(NAMESPACE, "controls_mode");
|
||||
public static final Identifier FEATURE_CHANNEL = new Identifier(NAMESPACE, "feature");
|
||||
public static final Identifier HELLO_CHANNEL = new Identifier(NAMESPACE, "hello");
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a feature.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class LambdaControlsFeature implements Nameable
|
||||
{
|
||||
private static final List<LambdaControlsFeature> FEATURES = new ArrayList<>();
|
||||
public static final LambdaControlsFeature FRONT_BLOCK_PLACING = new LambdaControlsFeature("front_block_placing", true, false);
|
||||
|
||||
private final String key;
|
||||
private final boolean defaultAllowed;
|
||||
private boolean allowed;
|
||||
private final boolean defaultEnabled;
|
||||
private boolean enabled;
|
||||
|
||||
public LambdaControlsFeature(@NotNull String key, boolean allowed, boolean enabled)
|
||||
{
|
||||
Objects.requireNonNull(key, "Feature key cannot be null.");
|
||||
this.key = key;
|
||||
this.setAllowed(this.defaultAllowed = allowed);
|
||||
this.setEnabled(this.defaultEnabled = enabled);
|
||||
}
|
||||
|
||||
public LambdaControlsFeature(@NotNull String key)
|
||||
{
|
||||
this(key, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the feature.
|
||||
*/
|
||||
public void allow()
|
||||
{
|
||||
this.setAllowed(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this feature is allowed.
|
||||
*
|
||||
* @return True if this feature is allowed, else false.
|
||||
*/
|
||||
public boolean isAllowed()
|
||||
{
|
||||
return this.allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this feature is allowed.
|
||||
*
|
||||
* @param allowed True if this feature is allowed, else false.
|
||||
*/
|
||||
public void setAllowed(boolean allowed)
|
||||
{
|
||||
this.allowed = allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets allowed state to default.
|
||||
*/
|
||||
public void resetAllowed()
|
||||
{
|
||||
this.setAllowed(this.defaultAllowed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this feature is enabled.
|
||||
*
|
||||
* @return True if this feature is enabled, else false.
|
||||
*/
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this feature is enabled.
|
||||
*
|
||||
* @param enabled True if this feature is enabled, else false.
|
||||
*/
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this feature is available or not.
|
||||
*
|
||||
* @return True if this feature is available, else false.
|
||||
* @see #isAllowed()
|
||||
* @see #isEnabled()
|
||||
*/
|
||||
public boolean isAvailable()
|
||||
{
|
||||
return this.isAllowed() && this.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the feature to its default values.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
this.resetAllowed();
|
||||
this.setEnabled(this.defaultEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName()
|
||||
{
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public static @NotNull Optional<LambdaControlsFeature> fromName(@NotNull String key)
|
||||
{
|
||||
Objects.requireNonNull(key, "Cannot find features with a null name.");
|
||||
return FEATURES.parallelStream().filter(feature -> feature.getName().equals(key)).findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all features to their default values.
|
||||
*/
|
||||
public static void resetAll()
|
||||
{
|
||||
FEATURES.parallelStream().forEach(LambdaControlsFeature::reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all features to allow state.
|
||||
*/
|
||||
public static void resetAllAllowed()
|
||||
{
|
||||
FEATURES.parallelStream().forEach(LambdaControlsFeature::resetAllowed);
|
||||
}
|
||||
|
||||
static {
|
||||
FEATURES.add(FRONT_BLOCK_PLACING);
|
||||
}
|
||||
}
|
||||
21
elytra/build.gradle
Normal file
@@ -0,0 +1,21 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
archivesBaseName = project.archives_base_name + "-elytra"
|
||||
|
||||
repositories {
|
||||
maven { url = 'https://hub.spigotmc.org/nexus/content/groups/public/' }
|
||||
maven { url = 'https://mcelytra.github.io/maven/' }
|
||||
maven { url = 'https://libraries.minecraft.net/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(":core")
|
||||
implementation "org.mcelytra:elytra-core:1.0.0-SNAPSHOT"
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.event;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
|
||||
import org.aperlambda.lambdacommon.Identifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mcelytra.core.entity.EntityPlayer;
|
||||
import org.mcelytra.core.event.HandlerList;
|
||||
import org.mcelytra.core.event.player.PlayerEvent;
|
||||
|
||||
/**
|
||||
* Represents an event which is fired when a player change their controls mode.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class PlayerControlsModeEvent extends PlayerEvent
|
||||
{
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private final ControlsMode controlsMode;
|
||||
|
||||
public PlayerControlsModeEvent(@NotNull EntityPlayer player, @NotNull ControlsMode controlsMode)
|
||||
{
|
||||
super(new Identifier(LambdaControlsConstants.NAMESPACE, "player_controls_mode"), player, true);
|
||||
this.controlsMode = controlsMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the controls mode of the player.
|
||||
*
|
||||
* @return The player's controls mode.
|
||||
*/
|
||||
public ControlsMode getControlsMode()
|
||||
{
|
||||
return this.controlsMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers()
|
||||
{
|
||||
return HANDLERS;
|
||||
}
|
||||
}
|
||||
93
fabric/build.gradle
Normal file
@@ -0,0 +1,93 @@
|
||||
plugins {
|
||||
id 'fabric-loom' version '0.2.6-SNAPSHOT'
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
archivesBaseName = project.archives_base_name + "-fabric"
|
||||
|
||||
minecraft {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = 'CottonMC'
|
||||
url = 'http://server.bbkr.space:8081/artifactory/libs-snapshot'
|
||||
}
|
||||
repositories {
|
||||
maven { url = "https://jitpack.io" }
|
||||
}
|
||||
// OkZoomer
|
||||
ivy {
|
||||
url 'https://github.com/joaoh1/OkZoomer/releases/download/'
|
||||
patternLayout {
|
||||
artifact '[revision]/[module]-[revision].[ext]'
|
||||
}
|
||||
metadataSources() {
|
||||
artifact()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
shadow
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//to change the versions see the gradle.properties file
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}"
|
||||
modCompile "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modApi "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
|
||||
modCompile "io.github.prospector:modmenu:1.8.5+build.23"
|
||||
modCompile "com.github.lambdaurora:spruceui:${project.spruceui_version}"
|
||||
include "com.github.lambdaurora:spruceui:${project.spruceui_version}"
|
||||
|
||||
// Compatibility mods
|
||||
modCompile "io.github.joaoh1:okzoomer:2.1.0-beta.2"
|
||||
|
||||
api project(":core")
|
||||
shadow project(":core")
|
||||
include "org.jetbrains:annotations:17.0.0"
|
||||
include("org.aperlambda:lambdajcommon:1.8.0") {
|
||||
exclude group: 'com.google.code.gson'
|
||||
exclude group: 'com.google.guava'
|
||||
}
|
||||
include "com.electronwill.night-config:core:3.5.3"
|
||||
include "com.electronwill.night-config:toml:3.5.3"
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include "fabric.mod.json"
|
||||
expand "version": project.version
|
||||
}
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
exclude "fabric.mod.json"
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
jar {
|
||||
from "../LICENSE"
|
||||
|
||||
from {
|
||||
configurations.shadow.filter {
|
||||
it.getName().contains("lambdacontrols")
|
||||
}.collect {
|
||||
it.isDirectory() ? it : zipTree(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
build.dependsOn(":core:build")
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import me.lambdaurora.lambdacontrols.event.PlayerChangeControlsModeCallback;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.PacketByteBuf;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls mod.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class LambdaControls implements ModInitializer
|
||||
{
|
||||
private static LambdaControls INSTANCE;
|
||||
public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(LambdaControlsConstants.CONTROLS_MODE_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 final Logger logger = LogManager.getLogger("LambdaControls");
|
||||
|
||||
@Override
|
||||
public void onInitialize()
|
||||
{
|
||||
INSTANCE = this;
|
||||
this.log("Initializing LambdaControls...");
|
||||
|
||||
ServerSidePacketRegistry.INSTANCE.register(HELLO_CHANNEL,
|
||||
(context, attachedData) -> {
|
||||
String version = attachedData.readString(16);
|
||||
ControlsMode.byId(attachedData.readString(32))
|
||||
.ifPresent(controlsMode -> context.getTaskQueue()
|
||||
.execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(context.getPlayer(), controlsMode)));
|
||||
context.getTaskQueue().execute(() ->
|
||||
ServerSidePacketRegistry.INSTANCE.sendToPlayer(context.getPlayer(), FEATURE_CHANNEL, this.makeFeatureBuffer(LambdaControlsFeature.FRONT_BLOCK_PLACING)));
|
||||
});
|
||||
ServerSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL,
|
||||
(context, attachedData) -> ControlsMode.byId(attachedData.readString(32))
|
||||
.ifPresent(controlsMode -> context.getTaskQueue()
|
||||
.execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(context.getPlayer(), controlsMode))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message to the terminal.
|
||||
*
|
||||
* @param info The message to print.
|
||||
*/
|
||||
public void log(String info)
|
||||
{
|
||||
this.logger.info("[LambdaControls] " + info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a warning to the terminal.
|
||||
*
|
||||
* @param warning The warning to print.
|
||||
*/
|
||||
public void warn(String warning)
|
||||
{
|
||||
this.logger.info("[LambdaControls] " + warning);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a packet byte buffer made for the lambdacontrols:controls_mode plugin message.
|
||||
*
|
||||
* @param controlsMode The controls mode to send.
|
||||
* @return The packet byte buffer.
|
||||
*/
|
||||
public PacketByteBuf makeControlsModeBuffer(@NotNull ControlsMode controlsMode)
|
||||
{
|
||||
Objects.requireNonNull(controlsMode, "Controls mode cannot be null.");
|
||||
return new PacketByteBuf(Unpooled.buffer()).writeString(controlsMode.getName(), 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a packet byte buffer made for the lambdacontrols:feature plugin message.
|
||||
*
|
||||
* @param feature The feature data to send.
|
||||
* @return The packet byte buffer.
|
||||
*/
|
||||
public PacketByteBuf makeFeatureBuffer(@NotNull LambdaControlsFeature feature)
|
||||
{
|
||||
Objects.requireNonNull(feature, "Feature cannot be null.");
|
||||
PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()).writeString(feature.getName(), 64);
|
||||
buffer.writeBoolean(feature.isAllowed());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public PacketByteBuf makeHello(@NotNull ControlsMode controlsMode)
|
||||
{
|
||||
String version = "";
|
||||
Optional<ModContainer> container;
|
||||
if ((container = FabricLoader.getInstance().getModContainer(LambdaControlsConstants.NAMESPACE)).isPresent()) {
|
||||
version = container.get().getMetadata().getVersion().getFriendlyString();
|
||||
}
|
||||
return new PacketByteBuf(Unpooled.buffer()).writeString(version, 16).writeString(controlsMode.getName(), 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the LambdaControls instance.
|
||||
*
|
||||
* @return The LambdaControls instance.
|
||||
*/
|
||||
public static LambdaControls get()
|
||||
{
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Represents a button state.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public enum ButtonState
|
||||
{
|
||||
NONE(0),
|
||||
PRESS(1),
|
||||
RELEASE(2),
|
||||
REPEAT(3);
|
||||
|
||||
public final int id;
|
||||
|
||||
ButtonState(int id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this state is a pressed state.
|
||||
*
|
||||
* @return True if this state is a pressed state, else false.
|
||||
*/
|
||||
public boolean isPressed()
|
||||
{
|
||||
return this == PRESS || this == REPEAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this state is an unpressed state.
|
||||
*
|
||||
* @return True if this state is an unpressed state, else false.
|
||||
*/
|
||||
public boolean isUnpressed()
|
||||
{
|
||||
return this == RELEASE || this == NONE;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,7 +7,7 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols;
|
||||
package me.lambdaurora.lambdacontrols.client;
|
||||
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
@@ -18,6 +18,10 @@ import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a controller type.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public enum ControllerType implements Nameable
|
||||
{
|
||||
@@ -40,7 +44,7 @@ public enum ControllerType implements Nameable
|
||||
*
|
||||
* @return The controller type's identifier.
|
||||
*/
|
||||
public int get_id()
|
||||
public int getId()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
@@ -63,13 +67,13 @@ public enum ControllerType implements Nameable
|
||||
*
|
||||
* @return The translated name of this controller type.
|
||||
*/
|
||||
public String get_translated_name()
|
||||
public String getTranslatedName()
|
||||
{
|
||||
return I18n.translate("lambdacontrols.controller_type." + this.get_name());
|
||||
return I18n.translate("lambdacontrols.controller_type." + this.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String get_name()
|
||||
public @NotNull String getName()
|
||||
{
|
||||
return this.name().toLowerCase();
|
||||
}
|
||||
@@ -80,8 +84,8 @@ public enum ControllerType implements Nameable
|
||||
* @param id The identifier of the controller type.
|
||||
* @return The controller type if found, else empty.
|
||||
*/
|
||||
public static Optional<ControllerType> by_id(@NotNull String id)
|
||||
public static Optional<ControllerType> byId(@NotNull String id)
|
||||
{
|
||||
return Arrays.stream(values()).filter(mode -> mode.get_name().equalsIgnoreCase(id)).findFirst();
|
||||
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,7 +7,7 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols;
|
||||
package me.lambdaurora.lambdacontrols.client;
|
||||
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
@@ -18,6 +18,10 @@ import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents the hud side which is the side where the movements buttons are.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public enum HudSide implements Nameable
|
||||
{
|
||||
@@ -42,13 +46,13 @@ public enum HudSide implements Nameable
|
||||
*
|
||||
* @return The translated name of this hud side.
|
||||
*/
|
||||
public String get_translated_name()
|
||||
public String getTranslatedName()
|
||||
{
|
||||
return I18n.translate("lambdacontrols.hud_side." + this.get_name());
|
||||
return I18n.translate("lambdacontrols.hud_side." + this.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String get_name()
|
||||
public @NotNull String getName()
|
||||
{
|
||||
return this.name().toLowerCase();
|
||||
}
|
||||
@@ -59,8 +63,8 @@ public enum HudSide implements Nameable
|
||||
* @param id The identifier of the hud side.
|
||||
* @return The hud side if found, else empty.
|
||||
*/
|
||||
public static Optional<HudSide> by_id(@NotNull String id)
|
||||
public static Optional<HudSide> byId(@NotNull String id)
|
||||
{
|
||||
return Arrays.stream(values()).filter(mode -> mode.get_name().equalsIgnoreCase(id)).findFirst();
|
||||
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* 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 com.mojang.blaze3d.platform.GlStateManager;
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
|
||||
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.Controller;
|
||||
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsHud;
|
||||
import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay;
|
||||
import me.lambdaurora.spruceui.event.OpenScreenCallback;
|
||||
import me.lambdaurora.spruceui.hud.HudManager;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.keybinding.FabricKeyBinding;
|
||||
import net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry;
|
||||
import net.fabricmc.fabric.api.event.client.ClientTickCallback;
|
||||
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.client.toast.SystemToast;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.aperlambda.lambdacommon.utils.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls client mod.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class LambdaControlsClient extends LambdaControls implements ClientModInitializer
|
||||
{
|
||||
private static LambdaControlsClient INSTANCE;
|
||||
public static final FabricKeyBinding BINDING_LOOK_UP = FabricKeyBinding.Builder.create(new Identifier(LambdaControlsConstants.NAMESPACE, "look_up"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement").build();
|
||||
public static final FabricKeyBinding BINDING_LOOK_RIGHT = FabricKeyBinding.Builder.create(new Identifier(LambdaControlsConstants.NAMESPACE, "look_right"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement").build();
|
||||
public static final FabricKeyBinding BINDING_LOOK_DOWN = FabricKeyBinding.Builder.create(new Identifier(LambdaControlsConstants.NAMESPACE, "look_down"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement").build();
|
||||
public static final FabricKeyBinding BINDING_LOOK_LEFT = FabricKeyBinding.Builder.create(new Identifier(LambdaControlsConstants.NAMESPACE, "look_left"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement").build();
|
||||
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 final LambdaControlsConfig config = new LambdaControlsConfig(this);
|
||||
public final LambdaInput input = new LambdaInput(this);
|
||||
private LambdaControlsHud hud;
|
||||
private ControlsMode previousControlsMode;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient()
|
||||
{
|
||||
INSTANCE = this;
|
||||
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_UP);
|
||||
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_RIGHT);
|
||||
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_DOWN);
|
||||
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_LEFT);
|
||||
|
||||
ClientSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL, (context, attachedData) -> context.getTaskQueue()
|
||||
.execute(() -> ClientSidePacketRegistry.INSTANCE.sendToServer(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode()))));
|
||||
ClientSidePacketRegistry.INSTANCE.register(FEATURE_CHANNEL, (context, attachedData) -> {
|
||||
String name = attachedData.readString(64);
|
||||
boolean allowed = attachedData.readBoolean();
|
||||
LambdaControlsFeature.fromName(name).ifPresent(feature -> context.getTaskQueue().execute(() -> feature.setAllowed(allowed)));
|
||||
});
|
||||
|
||||
ClientTickCallback.EVENT.register(this::onTick);
|
||||
|
||||
OpenScreenCallback.EVENT.register((client, screen) -> {
|
||||
if (screen == null && this.config.getControlsMode() == ControlsMode.TOUCHSCREEN) {
|
||||
screen = new TouchscreenOverlay(this);
|
||||
screen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
|
||||
client.skipGameRender = false;
|
||||
client.currentScreen = screen;
|
||||
} else if (screen != null) {
|
||||
this.input.onScreenOpen(client, client.getWindow().getWidth(), client.getWindow().getHeight());
|
||||
}
|
||||
});
|
||||
|
||||
HudManager.register(this.hud = new LambdaControlsHud(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when Minecraft is initializing.
|
||||
*/
|
||||
public void onMcInit(@NotNull MinecraftClient client)
|
||||
{
|
||||
ButtonBinding.init(client.options);
|
||||
this.config.load();
|
||||
this.hud.setVisible(this.config.isHudEnabled());
|
||||
Controller.updateMappings();
|
||||
GLFW.glfwSetJoystickCallback((jid, event) -> {
|
||||
if (event == GLFW.GLFW_CONNECTED) {
|
||||
Controller controller = Controller.byId(jid);
|
||||
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.connected", jid),
|
||||
new LiteralText(controller.getName())));
|
||||
} else if (event == GLFW.GLFW_DISCONNECTED) {
|
||||
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.disconnected", jid),
|
||||
null));
|
||||
}
|
||||
|
||||
this.switchControlsMode();
|
||||
});
|
||||
|
||||
LambdaControlsCompat.init(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called every Minecraft tick.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void onTick(@NotNull MinecraftClient client)
|
||||
{
|
||||
this.input.onTick(client);
|
||||
if (this.config.getControlsMode() == ControlsMode.CONTROLLER && (client.isWindowFocused() || this.config.hasUnfocusedInput()))
|
||||
this.input.onControllerTick(client);
|
||||
}
|
||||
|
||||
public void onRender(MinecraftClient client)
|
||||
{
|
||||
this.input.onRender(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when leaving a server.
|
||||
*/
|
||||
public void onLeave()
|
||||
{
|
||||
LambdaControlsFeature.resetAllAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the controls mode if the auto switch is enabled.
|
||||
*/
|
||||
public void switchControlsMode()
|
||||
{
|
||||
if (this.config.hasAutoSwitchMode()) {
|
||||
if (this.config.getController().isGamepad()) {
|
||||
this.previousControlsMode = this.config.getControlsMode();
|
||||
this.config.setControlsMode(ControlsMode.CONTROLLER);
|
||||
} else {
|
||||
if (this.previousControlsMode == null) {
|
||||
this.previousControlsMode = ControlsMode.DEFAULT;
|
||||
}
|
||||
|
||||
this.config.setControlsMode(this.previousControlsMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the HUD is enabled or not.
|
||||
*
|
||||
* @param enabled True if the HUD is enabled, else false.
|
||||
*/
|
||||
public void setHudEnabled(boolean enabled)
|
||||
{
|
||||
this.config.setHudEnabled(enabled);
|
||||
this.hud.setVisible(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the LambdaControls client instance.
|
||||
*
|
||||
* @return The LambdaControls client instance.
|
||||
*/
|
||||
public static LambdaControlsClient get()
|
||||
{
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static Pair<Integer, Integer> drawButton(int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient client)
|
||||
{
|
||||
return drawButton(x, y, button.getButton(), client);
|
||||
}
|
||||
|
||||
public static Pair<Integer, Integer> drawButton(int x, int y, int[] buttons, @NotNull MinecraftClient client)
|
||||
{
|
||||
int height = 0;
|
||||
int length = 0;
|
||||
int currentX = x;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
int btn = buttons[i];
|
||||
Pair<Integer, Integer> size = drawButton(currentX, y, btn, client);
|
||||
if (size.key > height)
|
||||
height = size.key;
|
||||
length += size.key;
|
||||
if (i + 1 < buttons.length) {
|
||||
length += 2;
|
||||
currentX = x + length;
|
||||
}
|
||||
}
|
||||
return Pair.of(length, height);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecated")
|
||||
public static Pair<Integer, Integer> drawButton(int x, int y, int button, @NotNull MinecraftClient client)
|
||||
{
|
||||
boolean second = false;
|
||||
if (button == -1)
|
||||
return Pair.of(0, 0);
|
||||
else if (button >= 500) {
|
||||
button -= 1000;
|
||||
second = true;
|
||||
}
|
||||
|
||||
int controllerType = get().config.getControllerType().getId();
|
||||
boolean axis = false;
|
||||
int buttonOffset = button * 15;
|
||||
switch (button) {
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
|
||||
buttonOffset = 7 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
|
||||
buttonOffset = 8 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_BACK:
|
||||
buttonOffset = 4 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_START:
|
||||
buttonOffset = 6 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_GUIDE:
|
||||
buttonOffset = 5 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
|
||||
buttonOffset = 15 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
|
||||
buttonOffset = 16 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 100:
|
||||
buttonOffset = 0;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 100:
|
||||
buttonOffset = 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 100:
|
||||
buttonOffset = 2 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 100:
|
||||
buttonOffset = 3 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 200:
|
||||
buttonOffset = 4 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 200:
|
||||
buttonOffset = 5 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 200:
|
||||
buttonOffset = 6 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 200:
|
||||
buttonOffset = 7 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 100:
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 200:
|
||||
buttonOffset = 9 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 100:
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 200:
|
||||
buttonOffset = 10 * 15;
|
||||
break;
|
||||
}
|
||||
|
||||
client.getTextureManager().bindTexture(axis ? LambdaControlsClient.CONTROLLER_AXIS : LambdaControlsClient.CONTROLLER_BUTTONS);
|
||||
GlStateManager.disableDepthTest();
|
||||
|
||||
GlStateManager.color4f(1.0F, second ? 0.0F : 1.0F, 1.0F, 1.0F);
|
||||
DrawableHelper.blit(x, y, (float) buttonOffset, (float) (controllerType * (axis ? 18 : 15)), axis ? 18 : 15, axis ? 18 : 15, 256, 256);
|
||||
GlStateManager.enableDepthTest();
|
||||
|
||||
return axis ? Pair.of(18, 18) : Pair.of(15, 15);
|
||||
}
|
||||
|
||||
public static int drawButtonTip(int x, int y, @NotNull ButtonBinding button, boolean display, @NotNull MinecraftClient client)
|
||||
{
|
||||
return drawButtonTip(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)
|
||||
{
|
||||
if (display) {
|
||||
int buttonWidth = drawButton(x, y, button, client).key;
|
||||
|
||||
String translatedAction = I18n.translate(action);
|
||||
int textY = (15 - client.textRenderer.fontHeight) / 2;
|
||||
client.textRenderer.drawWithShadow(translatedAction, (float) (x + buttonWidth + 5), (float) (y + textY), 14737632);
|
||||
|
||||
return getButtonTipWidth(translatedAction, client.textRenderer);
|
||||
}
|
||||
|
||||
return -10;
|
||||
}
|
||||
|
||||
private static int getButtonTipWidth(@NotNull String action, @NotNull TextRenderer textRenderer)
|
||||
{
|
||||
return 15 + 5 + textRenderer.getStringWidth(action);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* 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 com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.Controller;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_X;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y;
|
||||
|
||||
/**
|
||||
* Represents LambdaControls configuration.
|
||||
*/
|
||||
public class LambdaControlsConfig
|
||||
{
|
||||
// General
|
||||
private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT;
|
||||
private static final boolean DEFAULT_AUTO_SWITCH_MODE = false;
|
||||
// HUD
|
||||
private static final boolean DEFAULT_HUD_ENABLE = true;
|
||||
private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT;
|
||||
// Gameplay
|
||||
private static final boolean DEFAULT_FRONT_BLOCK_PLACING = false;
|
||||
private static final boolean DEFAULT_FLY_DRIFTING = false;
|
||||
private static final boolean DEFAULT_FLY_VERTICAL_DRIFTING = true;
|
||||
// Controller
|
||||
private static final ControllerType DEFAULT_CONTROLLER_TYPE = ControllerType.DEFAULT;
|
||||
private static final double DEFAULT_DEAD_ZONE = 0.25;
|
||||
private static final double DEFAULT_ROTATION_SPEED = 40.0;
|
||||
private static final double DEFAULT_MOUSE_SPEED = 25.0;
|
||||
private static final boolean DEFAULT_UNFOCUSED_INPUT = false;
|
||||
|
||||
private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?");
|
||||
|
||||
protected final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/config.toml").build();
|
||||
private final LambdaControlsClient mod;
|
||||
private ControlsMode controlsMode;
|
||||
private ControllerType controllerType;
|
||||
// HUD settings.
|
||||
private boolean hudEnable;
|
||||
private HudSide hudSide;
|
||||
// Controller settings
|
||||
private double deadZone;
|
||||
private double rotationSpeed;
|
||||
private double mouseSpeed;
|
||||
private boolean unfocusedInput;
|
||||
|
||||
public LambdaControlsConfig(@NotNull LambdaControlsClient mod)
|
||||
{
|
||||
this.mod = mod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configuration
|
||||
*/
|
||||
public void load()
|
||||
{
|
||||
this.config.load();
|
||||
this.checkAndFix();
|
||||
this.mod.log("Configuration loaded.");
|
||||
this.controlsMode = ControlsMode.byId(this.config.getOrElse("controls", DEFAULT_CONTROLS_MODE.getName())).orElse(DEFAULT_CONTROLS_MODE);
|
||||
// HUD settings.
|
||||
this.hudEnable = this.config.getOrElse("hud.enable", DEFAULT_HUD_ENABLE);
|
||||
this.hudSide = HudSide.byId(this.config.getOrElse("hud.side", DEFAULT_HUD_SIDE.getName())).orElse(DEFAULT_HUD_SIDE);
|
||||
// Gameplay
|
||||
LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.front_block_placing", DEFAULT_FRONT_BLOCK_PLACING));
|
||||
// Controller settings.
|
||||
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.rotationSpeed = this.config.getOrElse("controller.rotation_speed", DEFAULT_ROTATION_SPEED);
|
||||
this.mouseSpeed = this.config.getOrElse("controller.mouse_speed", DEFAULT_MOUSE_SPEED);
|
||||
this.unfocusedInput = this.config.getOrElse("controller.unfocused_input", DEFAULT_UNFOCUSED_INPUT);
|
||||
// Controller controls.
|
||||
InputManager.loadButtonBindings(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the configuration.
|
||||
*/
|
||||
public void save()
|
||||
{
|
||||
this.config.set("controller.dead_zone", this.deadZone);
|
||||
this.config.set("controller.rotation_speed", this.rotationSpeed);
|
||||
this.config.set("controller.mouse_speed", this.mouseSpeed);
|
||||
this.config.set("controller.unfocused_input", this.unfocusedInput);
|
||||
this.config.save();
|
||||
this.mod.log("Configuration saved.");
|
||||
}
|
||||
|
||||
public void checkAndFix()
|
||||
{
|
||||
InputManager.streamBindings().forEach(binding -> {
|
||||
String path = "controller.controls." + binding.getName();
|
||||
Object raw = this.config.getRaw(path);
|
||||
if (raw instanceof Number) {
|
||||
this.mod.warn("Invalid data at \"" + path + "\", fixing...");
|
||||
this.config.set(path, String.valueOf(raw));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the configuration to default values.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
// General
|
||||
this.setControlsMode(DEFAULT_CONTROLS_MODE);
|
||||
this.setAutoSwitchMode(DEFAULT_AUTO_SWITCH_MODE);
|
||||
// HUD
|
||||
this.setHudEnabled(DEFAULT_HUD_ENABLE);
|
||||
this.setHudSide(DEFAULT_HUD_SIDE);
|
||||
// Gameplay
|
||||
this.setFrontBlockPlacing(DEFAULT_FRONT_BLOCK_PLACING);
|
||||
this.setFlyDrifting(DEFAULT_FLY_DRIFTING);
|
||||
this.setFlyVerticalDrifting(DEFAULT_FLY_VERTICAL_DRIFTING);
|
||||
// Controller
|
||||
this.setControllerType(DEFAULT_CONTROLLER_TYPE);
|
||||
this.setDeadZone(DEFAULT_DEAD_ZONE);
|
||||
this.setRotationSpeed(DEFAULT_ROTATION_SPEED);
|
||||
this.setMouseSpeed(DEFAULT_MOUSE_SPEED);
|
||||
this.setUnfocusedInput(DEFAULT_UNFOCUSED_INPUT);
|
||||
|
||||
// Collect prevents concurrent modification.
|
||||
InputManager.streamBindings().collect(Collectors.toList()).forEach(binding -> this.setButtonBinding(binding, binding.getDefaultButton()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controls mode from the configuration.
|
||||
*
|
||||
* @return The controls mode.
|
||||
*/
|
||||
public @NotNull ControlsMode getControlsMode()
|
||||
{
|
||||
return this.controlsMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controls mode in the configuration.
|
||||
*
|
||||
* @param controlsMode The controls mode.
|
||||
*/
|
||||
public void setControlsMode(@NotNull ControlsMode controlsMode)
|
||||
{
|
||||
this.controlsMode = controlsMode;
|
||||
this.config.set("controls", controlsMode.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the auto switch mode is enabled or not.
|
||||
*
|
||||
* @return True if the auto switch mode is enabled, else false.
|
||||
*/
|
||||
public boolean hasAutoSwitchMode()
|
||||
{
|
||||
return this.config.getOrElse("auto_switch_mode", DEFAULT_AUTO_SWITCH_MODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the auto switch mode is enabled or not.
|
||||
*
|
||||
* @param autoSwitchMode True if the auto switch mode is enabled, else false.
|
||||
*/
|
||||
public void setAutoSwitchMode(boolean autoSwitchMode)
|
||||
{
|
||||
this.config.set("auto_switch_mode", autoSwitchMode);
|
||||
}
|
||||
|
||||
/*
|
||||
HUD settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns whether the HUD is enabled.
|
||||
*
|
||||
* @return True if the HUD is enabled, else false.
|
||||
*/
|
||||
public boolean isHudEnabled()
|
||||
{
|
||||
return this.hudEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the HUD is enabled.
|
||||
*
|
||||
* @param enable True if the HUD is enabled, else false.
|
||||
*/
|
||||
public void setHudEnabled(boolean enable)
|
||||
{
|
||||
this.hudEnable = enable;
|
||||
this.config.set("hud.enable", this.hudEnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the HUD side from the configuration.
|
||||
*
|
||||
* @return The HUD side.
|
||||
*/
|
||||
public @NotNull HudSide getHudSide()
|
||||
{
|
||||
return this.hudSide;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HUD side in the configuration.
|
||||
*
|
||||
* @param hudSide The HUD side.
|
||||
*/
|
||||
public void setHudSide(@NotNull HudSide hudSide)
|
||||
{
|
||||
this.hudSide = hudSide;
|
||||
this.config.set("hud.side", hudSide.getName());
|
||||
}
|
||||
|
||||
/*
|
||||
Gameplay settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns whether front block placing is enabled or not.
|
||||
*
|
||||
* @return True if front block placing is enabled, else false.
|
||||
*/
|
||||
public boolean hasFrontBlockPlacing()
|
||||
{
|
||||
return LambdaControlsFeature.FRONT_BLOCK_PLACING.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether front block placing is enabled or not.
|
||||
*
|
||||
* @param enable True if front block placing is enabled, else false.
|
||||
*/
|
||||
public void setFrontBlockPlacing(boolean enable)
|
||||
{
|
||||
LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(enable);
|
||||
this.config.set("gameplay.front_block_placing", enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether fly drifting is enabled or not.
|
||||
*
|
||||
* @return True if fly drifting is enabled, else false.
|
||||
*/
|
||||
public boolean hasFlyDrifting()
|
||||
{
|
||||
return this.config.getOrElse("gameplay.fly.drifting", DEFAULT_FLY_DRIFTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether fly drifting is enabled or not.
|
||||
*
|
||||
* @param flyDrifting True if fly drifting is enabled, else false.
|
||||
*/
|
||||
public void setFlyDrifting(boolean flyDrifting)
|
||||
{
|
||||
this.config.set("gameplay.fly.drifting", flyDrifting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether vertical fly drifting is enabled or not.
|
||||
*
|
||||
* @return True if vertical fly drifting is enabled, else false.
|
||||
*/
|
||||
public boolean hasFlyVerticalDrifting()
|
||||
{
|
||||
return this.config.getOrElse("gameplay.fly.vertical_drifting", DEFAULT_FLY_VERTICAL_DRIFTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether vertical fly drifting is enabled or not.
|
||||
*
|
||||
* @param flyDrifting True if vertical fly drifting is enabled, else false.
|
||||
*/
|
||||
public void setFlyVerticalDrifting(boolean flyDrifting)
|
||||
{
|
||||
this.config.set("gameplay.fly.vertical_drifting", flyDrifting);
|
||||
}
|
||||
|
||||
/*
|
||||
Controller settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the used controller.
|
||||
*
|
||||
* @return The used controller.
|
||||
*/
|
||||
public @NotNull Controller getController()
|
||||
{
|
||||
Object raw = this.config.getRaw("controller.id");
|
||||
if (raw instanceof Number) {
|
||||
return Controller.byId((Integer) raw);
|
||||
} else if (raw instanceof String) {
|
||||
return Controller.byGuid((String) raw).orElse(Controller.byId(GLFW.GLFW_JOYSTICK_1));
|
||||
}
|
||||
return Controller.byId(GLFW.GLFW_JOYSTICK_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the used controller.
|
||||
*
|
||||
* @param controller The used controller.
|
||||
*/
|
||||
public void setController(@NotNull Controller controller)
|
||||
{
|
||||
this.config.set("controller.id", controller.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second controller (for Joy-Con supports).
|
||||
*
|
||||
* @return The second controller.
|
||||
*/
|
||||
public @NotNull Optional<Controller> getSecondController()
|
||||
{
|
||||
Object raw = this.config.getRaw("controller.id2");
|
||||
if (raw instanceof Number) {
|
||||
if ((int) raw == -1)
|
||||
return Optional.empty();
|
||||
return Optional.of(Controller.byId((Integer) raw));
|
||||
} else if (raw instanceof String) {
|
||||
return Optional.of(Controller.byGuid((String) raw).orElse(Controller.byId(GLFW.GLFW_JOYSTICK_1)));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the second controller.
|
||||
*
|
||||
* @param controller The second controller.
|
||||
*/
|
||||
public void setSecondController(@Nullable Controller controller)
|
||||
{
|
||||
this.config.set("controller.id2", controller == null ? -1 : controller.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's type.
|
||||
*
|
||||
* @return The controller's type.
|
||||
*/
|
||||
public @NotNull ControllerType getControllerType()
|
||||
{
|
||||
return this.controllerType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller's type.
|
||||
*
|
||||
* @param controllerType The controller's type.
|
||||
*/
|
||||
public void setControllerType(@NotNull ControllerType controllerType)
|
||||
{
|
||||
this.controllerType = controllerType;
|
||||
this.config.set("controller.type", controllerType.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's dead zone from the configuration.
|
||||
*
|
||||
* @return The controller's dead zone value.
|
||||
*/
|
||||
public double getDeadZone()
|
||||
{
|
||||
return this.deadZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller's dead zone in the configuration.
|
||||
*
|
||||
* @param deadZone The new controller's dead zone value.
|
||||
*/
|
||||
public void setDeadZone(double deadZone)
|
||||
{
|
||||
this.deadZone = deadZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's rotation speed.
|
||||
*
|
||||
* @return The rotation speed.
|
||||
*/
|
||||
public double getRotationSpeed()
|
||||
{
|
||||
return this.rotationSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller's rotation speed.
|
||||
*
|
||||
* @param rotationSpeed The rotation speed.
|
||||
*/
|
||||
public void setRotationSpeed(double rotationSpeed)
|
||||
{
|
||||
this.rotationSpeed = rotationSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's mouse speed.
|
||||
*
|
||||
* @return The mouse speed.
|
||||
*/
|
||||
public double getMouseSpeed()
|
||||
{
|
||||
return this.mouseSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller's mouse speed.
|
||||
*
|
||||
* @param mouseSpeed The mouse speed.
|
||||
*/
|
||||
public void setMouseSpeed(double mouseSpeed)
|
||||
{
|
||||
this.mouseSpeed = mouseSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the right X axis is inverted or not.
|
||||
*
|
||||
* @return True if the right X axis is inverted, else false.
|
||||
*/
|
||||
public boolean doesInvertRightXAxis()
|
||||
{
|
||||
return this.config.getOrElse("controller.invert_right_x_axis", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the right X axis is inverted or not.
|
||||
*
|
||||
* @param invert True if the right X axis is inverted, else false.
|
||||
*/
|
||||
public void setInvertRightXAxis(boolean invert)
|
||||
{
|
||||
this.config.set("controller.invert_right_x_axis", invert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the right Y axis is inverted or not.
|
||||
*
|
||||
* @return True if the right Y axis is inverted, else false.
|
||||
*/
|
||||
public boolean doesInvertRightYAxis()
|
||||
{
|
||||
return this.config.getOrElse("controller.invert_right_y_axis", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the right Y axis is inverted or not.
|
||||
*
|
||||
* @param invert True if the right Y axis is inverted, else false.
|
||||
*/
|
||||
public void setInvertRightYAxis(boolean invert)
|
||||
{
|
||||
this.config.set("controller.invert_right_y_axis", invert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether unfocused controller input is allowed or not.
|
||||
*
|
||||
* @return True if unfocused controller input is allowed, else false.
|
||||
*/
|
||||
public boolean hasUnfocusedInput()
|
||||
{
|
||||
return this.unfocusedInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether unfocused controller input is allowed or not.
|
||||
*
|
||||
* @param unfocusedInput True if unfocused controller input is allowed, else false.
|
||||
*/
|
||||
public void setUnfocusedInput(boolean unfocusedInput)
|
||||
{
|
||||
this.unfocusedInput = unfocusedInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the right X axis sign.
|
||||
*
|
||||
* @return The right X axis sign.
|
||||
*/
|
||||
public double getRightXAxisSign()
|
||||
{
|
||||
return this.doesInvertRightXAxis() ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the right Y axis sign.
|
||||
*
|
||||
* @return The right Y axis sign.
|
||||
*/
|
||||
public double getRightYAxisSign()
|
||||
{
|
||||
return this.doesInvertRightYAxis() ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the button binding from configuration.
|
||||
*
|
||||
* @param button The button binding.
|
||||
*/
|
||||
public void loadButtonBinding(@NotNull ButtonBinding button)
|
||||
{
|
||||
button.setButton(button.getDefaultButton());
|
||||
String code = this.config.getOrElse("controller.controls." + button.getName(), button.getButtonCode());
|
||||
|
||||
Matcher matcher = BUTTON_BINDING_PATTERN.matcher(code);
|
||||
|
||||
try {
|
||||
int[] buttons = new int[1];
|
||||
int count = 0;
|
||||
while (matcher.find()) {
|
||||
count++;
|
||||
if (count > buttons.length)
|
||||
buttons = Arrays.copyOf(buttons, count);
|
||||
String current;
|
||||
if (!this.checkValidity(button, code, current = matcher.group(1)))
|
||||
return;
|
||||
buttons[count - 1] = Integer.parseInt(current);
|
||||
}
|
||||
if (count == 0) {
|
||||
this.mod.warn("Malformed config value \"" + code + "\" for binding \"" + button.getName() + "\".");
|
||||
this.setButtonBinding(button, new int[]{-1});
|
||||
}
|
||||
|
||||
button.setButton(buttons);
|
||||
} catch (Exception e) {
|
||||
this.mod.warn("Malformed config value \"" + code + "\" for binding \"" + button.getName() + "\".");
|
||||
this.config.set("controller.controls." + button.getName(), button.getButtonCode());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkValidity(@NotNull ButtonBinding binding, @NotNull String input, String group)
|
||||
{
|
||||
if (group == null) {
|
||||
this.mod.warn("Malformed config value \"" + input + "\" for binding \"" + binding.getName() + "\".");
|
||||
this.config.set("controller.controls." + binding.getName(), binding.getButtonCode());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the button binding in configuration.
|
||||
*
|
||||
* @param binding The button binding.
|
||||
* @param button The button.
|
||||
*/
|
||||
public void setButtonBinding(@NotNull ButtonBinding binding, int[] button)
|
||||
{
|
||||
binding.setButton(button);
|
||||
this.config.set("controller.controls." + binding.getName(), binding.getButtonCode());
|
||||
}
|
||||
|
||||
public boolean isBackButton(int btn, boolean isBtn, int state)
|
||||
{
|
||||
if (!isBtn && state == 0)
|
||||
return false;
|
||||
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false) == ButtonBinding.axisAsButton(btn, state == 1);
|
||||
}
|
||||
|
||||
public boolean isForwardButton(int btn, boolean isBtn, int state)
|
||||
{
|
||||
if (!isBtn && state == 0)
|
||||
return false;
|
||||
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true) == ButtonBinding.axisAsButton(btn, state == 1);
|
||||
}
|
||||
|
||||
public boolean isLeftButton(int btn, boolean isBtn, int state)
|
||||
{
|
||||
if (!isBtn && state == 0)
|
||||
return false;
|
||||
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false) == ButtonBinding.axisAsButton(btn, state == 1);
|
||||
}
|
||||
|
||||
public boolean isRightButton(int btn, boolean isBtn, int state)
|
||||
{
|
||||
if (!isBtn && state == 0)
|
||||
return false;
|
||||
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true) == ButtonBinding.axisAsButton(btn, state == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified axis is an axis used for movements.
|
||||
*
|
||||
* @param axis The axis index.
|
||||
* @return True if the axis is used for movements, else false.
|
||||
*/
|
||||
public boolean isMovementAxis(int axis)
|
||||
{
|
||||
return axis == GLFW_GAMEPAD_AXIS_LEFT_Y || axis == GLFW_GAMEPAD_AXIS_LEFT_X;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 io.github.prospector.modmenu.api.ModMenuApi;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
|
||||
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Represents the API implementation of ModMenu for LambdaControls.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class LambdaControlsModMenu implements ModMenuApi
|
||||
{
|
||||
@Override
|
||||
public String getModId()
|
||||
{
|
||||
return LambdaControlsConstants.NAMESPACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Screen, ? extends Screen> getConfigScreenFactory()
|
||||
{
|
||||
return screen -> new LambdaControlsSettingsScreen(screen, MinecraftClient.getInstance().options, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* 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.client.controller.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.Controller;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
|
||||
import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen;
|
||||
import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor;
|
||||
import me.lambdaurora.spruceui.SpruceLabelWidget;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.gui.ParentElement;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
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.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
|
||||
import net.minecraft.client.gui.screen.world.WorldListWidget;
|
||||
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
|
||||
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
|
||||
import net.minecraft.client.gui.widget.SliderWidget;
|
||||
import net.minecraft.container.Slot;
|
||||
import net.minecraft.container.SlotActionType;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.aperlambda.lambdacommon.utils.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWGamepadState;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static me.lambdaurora.lambdacontrols.client.controller.ButtonBinding.axisAsButton;
|
||||
import static me.lambdaurora.lambdacontrols.client.controller.InputManager.INPUT_MANAGER;
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls' input handler.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class LambdaInput
|
||||
{
|
||||
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
|
||||
private final LambdaControlsConfig config;
|
||||
// Cooldowns
|
||||
private int actionGuiCooldown = 0;
|
||||
private int ignoreNextA = 0;
|
||||
// Sneak state.
|
||||
private double prevTargetYaw = 0.0;
|
||||
private double prevTargetPitch = 0.0;
|
||||
private double targetYaw = 0.0;
|
||||
private double targetPitch = 0.0;
|
||||
private float prevXAxis = 0.F;
|
||||
private float prevYAxis = 0.F;
|
||||
private int targetMouseX = 0;
|
||||
private int targetMouseY = 0;
|
||||
private float mouseSpeedX = 0.F;
|
||||
private float mouseSpeedY = 0.F;
|
||||
|
||||
public LambdaInput(@NotNull LambdaControlsClient mod)
|
||||
{
|
||||
this.config = mod.config;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called every Minecraft tick.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void onTick(@NotNull MinecraftClient client)
|
||||
{
|
||||
this.prevTargetYaw = this.targetYaw;
|
||||
this.prevTargetPitch = this.targetPitch;
|
||||
|
||||
// Handles the key bindings.
|
||||
if (LambdaControlsClient.BINDING_LOOK_UP.isPressed()) {
|
||||
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_Y, 0.8F, 2);
|
||||
} else if (LambdaControlsClient.BINDING_LOOK_DOWN.isPressed()) {
|
||||
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_Y, 0.8F, 1);
|
||||
}
|
||||
if (LambdaControlsClient.BINDING_LOOK_LEFT.isPressed()) {
|
||||
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_X, 0.8F, 2);
|
||||
} else if (LambdaControlsClient.BINDING_LOOK_RIGHT.isPressed()) {
|
||||
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_X, 0.8F, 1);
|
||||
}
|
||||
|
||||
INPUT_MANAGER.tick(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called every Minecraft tick for controller input update.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void onControllerTick(@NotNull MinecraftClient client)
|
||||
{
|
||||
BUTTON_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0).forEach(entry -> BUTTON_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
|
||||
// Decreases the cooldown for GUI actions.
|
||||
if (this.actionGuiCooldown > 0)
|
||||
--this.actionGuiCooldown;
|
||||
|
||||
InputManager.updateStates();
|
||||
|
||||
Controller controller = this.config.getController();
|
||||
if (controller.isConnected()) {
|
||||
GLFWGamepadState state = controller.getState();
|
||||
this.fetchButtonInput(client, state, false);
|
||||
this.fetchAxeInput(client, state, false);
|
||||
}
|
||||
this.config.getSecondController().filter(Controller::isConnected)
|
||||
.ifPresent(joycon -> {
|
||||
GLFWGamepadState state = joycon.getState();
|
||||
this.fetchButtonInput(client, state, true);
|
||||
this.fetchAxeInput(client, state, true);
|
||||
});
|
||||
|
||||
boolean allowInput = true;
|
||||
|
||||
if (client.currentScreen instanceof ControllerControlsScreen && ((ControllerControlsScreen) client.currentScreen).focusedBinding != null)
|
||||
allowInput = false;
|
||||
|
||||
if (allowInput)
|
||||
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)) {
|
||||
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen;
|
||||
if (screen.focusedBinding != null && !screen.waiting) {
|
||||
int[] buttons = new int[screen.currentButtons.size()];
|
||||
for (int i = 0; i < screen.currentButtons.size(); i++)
|
||||
buttons[i] = screen.currentButtons.get(i);
|
||||
screen.focusedBinding.setButton(buttons);
|
||||
screen.focusedBinding = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before the screen is rendered.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param screen The screen to render.
|
||||
*/
|
||||
public void onPreRenderScreen(@NotNull MinecraftClient client, @NotNull Screen screen)
|
||||
{
|
||||
if (!isScreenInteractive(screen)) {
|
||||
INPUT_MANAGER.updateMousePosition(client);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when Minecraft renders.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void onRender(@NotNull MinecraftClient client)
|
||||
{
|
||||
if ((client.currentScreen == null || client.currentScreen instanceof TouchscreenOverlay) &&
|
||||
(this.prevTargetYaw != this.targetYaw || this.prevTargetPitch != this.targetPitch)) {
|
||||
float deltaYaw = (float) ((this.targetYaw - client.player.prevYaw) * client.getTickDelta());
|
||||
float deltaPitch = (float) ((this.targetPitch - client.player.prevPitch) * client.getTickDelta());
|
||||
float rotationYaw = client.player.prevYaw + deltaYaw;
|
||||
float rotationPitch = client.player.prevPitch + deltaPitch;
|
||||
client.player.yaw = rotationYaw;
|
||||
client.player.pitch = MathHelper.clamp(rotationPitch, -90.F, 90.F);
|
||||
if (client.player.isRiding()) {
|
||||
client.player.getVehicle().copyPositionAndRotation(client.player);
|
||||
}
|
||||
client.getTutorialManager().onUpdateMouse(deltaPitch, deltaYaw);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when a Screen is opened.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param windowWidth The window width.
|
||||
* @param windowHeight The window height.
|
||||
*/
|
||||
public void onScreenOpen(@NotNull MinecraftClient client, int windowWidth, int windowHeight)
|
||||
{
|
||||
if (client.currentScreen == null) {
|
||||
this.mouseSpeedX = this.mouseSpeedY = 0.0F;
|
||||
INPUT_MANAGER.resetMousePosition(windowWidth, windowHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchButtonInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon)
|
||||
{
|
||||
ByteBuffer buffer = gamepadState.buttons();
|
||||
for (int i = 0; i < buffer.limit(); i++) {
|
||||
int btn = leftJoycon ? ButtonBinding.controller2Button(i) : i;
|
||||
boolean btnState = buffer.get() == (byte) 1;
|
||||
ButtonState state = ButtonState.NONE;
|
||||
ButtonState previousState = InputManager.STATES.getOrDefault(btn, ButtonState.NONE);
|
||||
|
||||
if (btnState != previousState.isPressed()) {
|
||||
state = btnState ? ButtonState.PRESS : ButtonState.RELEASE;
|
||||
this.handleButton(client, btn, btnState ? 0 : 1, btnState);
|
||||
if (btnState)
|
||||
BUTTON_COOLDOWNS.put(btn, 5);
|
||||
} else if (btnState) {
|
||||
state = ButtonState.REPEAT;
|
||||
if (BUTTON_COOLDOWNS.getOrDefault(btn, 0) == 0) {
|
||||
BUTTON_COOLDOWNS.put(btn, 5);
|
||||
this.handleButton(client, btn, 2, true);
|
||||
}
|
||||
}
|
||||
|
||||
InputManager.STATES.put(btn, state);
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchAxeInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon)
|
||||
{
|
||||
FloatBuffer buffer = gamepadState.axes();
|
||||
for (int i = 0; i < buffer.limit(); i++) {
|
||||
int axis = leftJoycon ? ButtonBinding.controller2Button(i) : i;
|
||||
float value = buffer.get();
|
||||
float absValue = Math.abs(value);
|
||||
|
||||
if (i == GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y)
|
||||
value *= -1.0F;
|
||||
|
||||
int state = value > this.config.getDeadZone() ? 1 : (value < -this.config.getDeadZone() ? 2 : 0);
|
||||
this.handleAxe(client, axis, value, absValue, state);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleButton(@NotNull MinecraftClient client, int button, int action, boolean state)
|
||||
{
|
||||
if (client.currentScreen instanceof ControllerControlsScreen) {
|
||||
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen;
|
||||
if (screen.focusedBinding != null) {
|
||||
if (action == 0 && !screen.currentButtons.contains(button)) {
|
||||
screen.currentButtons.add(button);
|
||||
|
||||
int[] buttons = new int[screen.currentButtons.size()];
|
||||
for (int i = 0; i < screen.currentButtons.size(); i++)
|
||||
buttons[i] = screen.currentButtons.get(i);
|
||||
screen.focusedBinding.setButton(buttons);
|
||||
|
||||
screen.waiting = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (action == 0 || action == 2) {
|
||||
if (client.currentScreen != null && isScreenInteractive(client.currentScreen)
|
||||
&& (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN
|
||||
|| button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)) {
|
||||
if (this.actionGuiCooldown == 0) {
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP) {
|
||||
this.changeFocus(client.currentScreen, false);
|
||||
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN) {
|
||||
this.changeFocus(client.currentScreen, true);
|
||||
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT) {
|
||||
this.handleLeftRight(client.currentScreen, false);
|
||||
} else {
|
||||
this.handleLeftRight(client.currentScreen, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (action == 1) {
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null) {
|
||||
if (this.actionGuiCooldown == 0) {
|
||||
Element focused = client.currentScreen.getFocused();
|
||||
if (focused != null && isScreenInteractive(client.currentScreen)) {
|
||||
if (this.handleAButton(client.currentScreen, focused)) {
|
||||
this.actionGuiCooldown = 5; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (client.currentScreen instanceof ContainerScreen && client.interactionManager != null && client.player != null) {
|
||||
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();
|
||||
Slot slot = ((ContainerScreenAccessor) client.currentScreen).lambdacontrols_getSlotAt(x, y);
|
||||
SlotActionType slotAction = SlotActionType.PICKUP;
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && slot != null) {
|
||||
if (client.currentScreen instanceof CreativeInventoryScreen) {
|
||||
if (((CreativeInventoryScreenAccessor) client.currentScreen).lambdacontrols_isCreativeInventorySlot(slot))
|
||||
slotAction = SlotActionType.CLONE;
|
||||
}
|
||||
client.interactionManager.clickSlot(((ContainerScreen) client.currentScreen).getContainer().syncId, slot.id, GLFW.GLFW_MOUSE_BUTTON_1, slotAction, client.player);
|
||||
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) {
|
||||
client.currentScreen.onClose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !isScreenInteractive(client.currentScreen) && this.actionGuiCooldown == 0 && this.ignoreNextA == 0) {
|
||||
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
|
||||
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
|
||||
if (action == 0) {
|
||||
client.currentScreen.mouseClicked(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1);
|
||||
} else if (action == 1) {
|
||||
client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1);
|
||||
}
|
||||
this.actionGuiCooldown = 5;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (axis == GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axis == GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER || axis == ButtonBinding.controller2Button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER) ||
|
||||
axis == ButtonBinding.controller2Button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER))
|
||||
if (asButtonState == 2)
|
||||
asButtonState = 0;
|
||||
|
||||
{
|
||||
boolean currentPlusState = asButtonState == 1;
|
||||
boolean currentMinusState = asButtonState == 2;
|
||||
ButtonState previousPlusState = InputManager.STATES.getOrDefault(axisAsButton(axis, true), ButtonState.NONE);
|
||||
ButtonState previousMinusState = InputManager.STATES.getOrDefault(axisAsButton(axis, false), ButtonState.NONE);
|
||||
|
||||
if (currentPlusState != previousPlusState.isPressed()) {
|
||||
InputManager.STATES.put(axisAsButton(axis, true), currentPlusState ? ButtonState.PRESS : ButtonState.RELEASE);
|
||||
if (currentPlusState)
|
||||
BUTTON_COOLDOWNS.put(axisAsButton(axis, true), 5);
|
||||
} else if (currentPlusState) {
|
||||
InputManager.STATES.put(axisAsButton(axis, true), ButtonState.REPEAT);
|
||||
if (BUTTON_COOLDOWNS.getOrDefault(axisAsButton(axis, true), 0) == 0) {
|
||||
BUTTON_COOLDOWNS.put(axisAsButton(axis, true), 5);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMinusState != previousMinusState.isPressed()) {
|
||||
InputManager.STATES.put(axisAsButton(axis, false), currentMinusState ? ButtonState.PRESS : ButtonState.RELEASE);
|
||||
if (currentMinusState)
|
||||
BUTTON_COOLDOWNS.put(axisAsButton(axis, false), 5);
|
||||
} else if (currentMinusState) {
|
||||
InputManager.STATES.put(axisAsButton(axis, false), ButtonState.REPEAT);
|
||||
if (BUTTON_COOLDOWNS.getOrDefault(axisAsButton(axis, false), 0) == 0) {
|
||||
BUTTON_COOLDOWNS.put(axisAsButton(axis, false), 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (client.currentScreen instanceof ControllerControlsScreen) {
|
||||
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen;
|
||||
if (screen.focusedBinding != null) {
|
||||
if (asButtonState != 0 && !screen.currentButtons.contains(axisAsButton(axis, asButtonState == 1))) {
|
||||
|
||||
screen.currentButtons.add(axisAsButton(axis, asButtonState == 1));
|
||||
|
||||
int[] buttons = new int[screen.currentButtons.size()];
|
||||
for (int i = 0; i < screen.currentButtons.size(); i++)
|
||||
buttons[i] = screen.currentButtons.get(i);
|
||||
screen.focusedBinding.setButton(buttons);
|
||||
|
||||
screen.waiting = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
double deadZone = this.config.getDeadZone();
|
||||
if (client.currentScreen == null) {
|
||||
// Handles the look direction.
|
||||
this.handleLook(client, axis, (float) (absValue / (1.0 - this.config.getDeadZone())), state);
|
||||
} else {
|
||||
boolean allowMouseControl = true;
|
||||
|
||||
if (this.actionGuiCooldown == 0 && this.config.isMovementAxis(axis) && isScreenInteractive(client.currentScreen)) {
|
||||
if (this.config.isForwardButton(axis, false, asButtonState)) {
|
||||
allowMouseControl = this.changeFocus(client.currentScreen, false);
|
||||
} else if (this.config.isBackButton(axis, false, asButtonState)) {
|
||||
allowMouseControl = this.changeFocus(client.currentScreen, true);
|
||||
} else if (this.config.isLeftButton(axis, false, asButtonState)) {
|
||||
allowMouseControl = this.handleLeftRight(client.currentScreen, false);
|
||||
} else if (this.config.isRightButton(axis, false, asButtonState)) {
|
||||
allowMouseControl = this.handleLeftRight(client.currentScreen, true);
|
||||
}
|
||||
}
|
||||
|
||||
float movementX = 0.0F;
|
||||
float movementY = 0.0F;
|
||||
|
||||
if (this.config.isBackButton(axis, false, (value > 0 ? 1 : 2))) {
|
||||
movementY = absValue;
|
||||
} else if (this.config.isForwardButton(axis, false, (value > 0 ? 1 : 2))) {
|
||||
movementY = -absValue;
|
||||
} else if (this.config.isLeftButton(axis, false, (value > 0 ? 1 : 2))) {
|
||||
movementX = -absValue;
|
||||
} else if (this.config.isRightButton(axis, false, (value > 0 ? 1 : 2))) {
|
||||
movementX = absValue;
|
||||
}
|
||||
|
||||
if (client.currentScreen != null && allowMouseControl) {
|
||||
boolean moving = Math.abs(movementY) >= deadZone || Math.abs(movementX) >= deadZone;
|
||||
if (moving) {
|
||||
/*
|
||||
Updates the target mouse position when the initial movement stick movement is detected.
|
||||
It prevents the cursor to jump to the old target mouse position if the user moves the cursor with the mouse.
|
||||
*/
|
||||
if (Math.abs(prevXAxis) < deadZone && Math.abs(prevYAxis) < deadZone) {
|
||||
INPUT_MANAGER.resetMouseTarget(client);
|
||||
}
|
||||
|
||||
if (Math.abs(movementX) >= deadZone)
|
||||
this.mouseSpeedX = movementX;
|
||||
else
|
||||
this.mouseSpeedX = 0.F;
|
||||
|
||||
if (Math.abs(movementY) >= deadZone)
|
||||
this.mouseSpeedY = movementY;
|
||||
else
|
||||
this.mouseSpeedY = 0.F;
|
||||
} else {
|
||||
this.mouseSpeedX = 0.F;
|
||||
this.mouseSpeedY = 0.F;
|
||||
}
|
||||
|
||||
if (Math.abs(this.mouseSpeedX) >= .05F || Math.abs(this.mouseSpeedY) >= .05F) {
|
||||
InputManager.queueMoveMousePosition(this.mouseSpeedX * this.config.getMouseSpeed(), this.mouseSpeedY * this.config.getMouseSpeed());
|
||||
}
|
||||
|
||||
this.moveMouseToClosestSlot(client, client.currentScreen);
|
||||
}
|
||||
|
||||
this.prevXAxis = movementX;
|
||||
this.prevYAxis = movementY;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleAButton(@NotNull Screen screen, @NotNull Element focused)
|
||||
{
|
||||
if (focused instanceof AbstractPressableButtonWidget) {
|
||||
AbstractPressableButtonWidget widget = (AbstractPressableButtonWidget) focused;
|
||||
widget.playDownSound(MinecraftClient.getInstance().getSoundManager());
|
||||
widget.onPress();
|
||||
return true;
|
||||
} else if (focused instanceof SpruceLabelWidget) {
|
||||
((SpruceLabelWidget) focused).onPress();
|
||||
return true;
|
||||
} else if (focused instanceof WorldListWidget) {
|
||||
WorldListWidget list = (WorldListWidget) focused;
|
||||
list.method_20159().ifPresent(WorldListWidget.Entry::play);
|
||||
return true;
|
||||
} else if (focused instanceof MultiplayerServerListWidget) {
|
||||
MultiplayerServerListWidget list = (MultiplayerServerListWidget) focused;
|
||||
MultiplayerServerListWidget.Entry entry = list.getSelected();
|
||||
if (entry instanceof MultiplayerServerListWidget.LanServerEntry || entry instanceof MultiplayerServerListWidget.ServerEntry) {
|
||||
((MultiplayerScreen) screen).select(entry);
|
||||
((MultiplayerScreen) screen).connect();
|
||||
}
|
||||
} else if (focused instanceof ParentElement) {
|
||||
Element childFocused = ((ParentElement) focused).getFocused();
|
||||
if (childFocused != null)
|
||||
return this.handleAButton(screen, childFocused);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the left and right buttons.
|
||||
*
|
||||
* @param screen The current screen.
|
||||
* @param right True if the right button is pressed, else false.
|
||||
*/
|
||||
private boolean handleLeftRight(@NotNull Screen screen, boolean right)
|
||||
{
|
||||
Element focused = screen.getFocused();
|
||||
if (focused != null)
|
||||
if (this.handleRightLeftElement(focused, right))
|
||||
return this.changeFocus(screen, right);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleRightLeftElement(@NotNull Element element, boolean right)
|
||||
{
|
||||
if (element instanceof SliderWidget) {
|
||||
SliderWidget slider = (SliderWidget) element;
|
||||
slider.keyPressed(right ? 262 : 263, 0, 0);
|
||||
this.actionGuiCooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
|
||||
return false;
|
||||
} else if (element instanceof AlwaysSelectedEntryListWidget) {
|
||||
((EntryListWidgetAccessor) element).lambdacontrols_moveSelection(right ? 1 : -1);
|
||||
return false;
|
||||
} else if (element instanceof ParentElement) {
|
||||
ParentElement entryList = (ParentElement) element;
|
||||
Element focused = entryList.getFocused();
|
||||
if (focused == null)
|
||||
return true;
|
||||
return this.handleRightLeftElement(focused, right);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the look direction input.
|
||||
*
|
||||
* @param client The client isntance.
|
||||
* @param axis The axis to change.
|
||||
* @param value The value of the look.
|
||||
* @param state The state.
|
||||
*/
|
||||
public void handleLook(@NotNull MinecraftClient client, int axis, float value, int state)
|
||||
{
|
||||
// Handles the look direction.
|
||||
if (client.player != null) {
|
||||
double powValue = Math.pow(value, 4.0);
|
||||
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
|
||||
if (state == 2) {
|
||||
this.targetPitch = client.player.pitch - this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D;
|
||||
this.targetPitch = MathHelper.clamp(this.targetPitch, -90.0D, 90.0D);
|
||||
} else if (state == 1) {
|
||||
this.targetPitch = client.player.pitch + this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D;
|
||||
this.targetPitch = MathHelper.clamp(this.targetPitch, -90.0D, 90.0D);
|
||||
}
|
||||
}
|
||||
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) {
|
||||
if (state == 2) {
|
||||
this.targetYaw = client.player.yaw - this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D;
|
||||
} else if (state == 1) {
|
||||
this.targetYaw = client.player.yaw + this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean changeFocus(@NotNull Screen screen, boolean down)
|
||||
{
|
||||
if (!screen.changeFocus(down)) {
|
||||
if (screen.changeFocus(down)) {
|
||||
this.actionGuiCooldown = 5;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
this.actionGuiCooldown = 5;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isScreenInteractive(@NotNull Screen screen)
|
||||
{
|
||||
return !(screen instanceof AdvancementsScreen || screen instanceof ContainerScreen);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Makes the mouse attracted to slots. This helps with selecting items when using a controller.
|
||||
if (screen instanceof ContainerScreen) {
|
||||
ContainerScreen inventoryScreen = (ContainerScreen) screen;
|
||||
ContainerScreenAccessor accessor = (ContainerScreenAccessor) inventoryScreen;
|
||||
int guiLeft = accessor.lambdacontrols_getX();
|
||||
int guiTop = accessor.lambdacontrols_getY();
|
||||
int mouseX = (int) (targetMouseX * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
|
||||
int mouseY = (int) (targetMouseY * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight());
|
||||
|
||||
// Finds the closest slot in the GUI within 14 pixels.
|
||||
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.
|
||||
double distance = Math.sqrt(Math.pow(x - mouseX, 2) + Math.pow(y - mouseY, 2));
|
||||
return Pair.of(slot, distance);
|
||||
}).filter(entry -> entry.value <= 14.0)
|
||||
.min(Comparator.comparingDouble(p -> p.value));
|
||||
|
||||
if (closestSlot.isPresent()) {
|
||||
Slot slot = closestSlot.get().key;
|
||||
if (slot.hasStack() || !client.player.inventory.getMainHandStack().isEmpty()) {
|
||||
int slotCenterXScaled = guiLeft + slot.xPosition + 8;
|
||||
int slotCenterYScaled = guiTop + slot.yPosition + 8;
|
||||
int slotCenterX = (int) (slotCenterXScaled / ((double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()));
|
||||
int slotCenterY = (int) (slotCenterYScaled / ((double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()));
|
||||
double deltaX = slotCenterX - targetMouseX;
|
||||
double deltaY = slotCenterY - targetMouseY;
|
||||
|
||||
if (mouseX != slotCenterXScaled || mouseY != slotCenterYScaled) {
|
||||
this.targetMouseX += deltaX * 0.75;
|
||||
this.targetMouseY += deltaY * 0.75;
|
||||
} else {
|
||||
this.mouseSpeedX *= 0.3F;
|
||||
this.mouseSpeedY *= 0.3F;
|
||||
}
|
||||
this.mouseSpeedX *= .75F;
|
||||
this.mouseSpeedY *= .75F;
|
||||
} else {
|
||||
this.mouseSpeedX *= .1F;
|
||||
this.mouseSpeedY *= .1F;
|
||||
}
|
||||
} else {
|
||||
this.mouseSpeedX *= .3F;
|
||||
this.mouseSpeedY *= .3F;
|
||||
}
|
||||
} else {
|
||||
this.mouseSpeedX = 0.F;
|
||||
this.mouseSpeedY = 0.F;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a compatibility handler for a mod.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public interface CompatHandler
|
||||
{
|
||||
/**
|
||||
* Handles compatibility of a mod.
|
||||
*
|
||||
* @param mod This mod instance.
|
||||
*/
|
||||
void handle(@NotNull LambdaControlsClient mod);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 me.lambdaurora.lambdacontrols.client.controller.InputManager;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import org.aperlambda.lambdacommon.utils.LambdaReflection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a compatibility handler.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class LambdaControlsCompat
|
||||
{
|
||||
/**
|
||||
* Initializes compatibility with other mods if needed.
|
||||
*
|
||||
* @param mod The mod instance.
|
||||
*/
|
||||
public static void init(@NotNull LambdaControlsClient mod)
|
||||
{
|
||||
if (FabricLoader.getInstance().isModLoaded("okzoomer") && LambdaReflection.doesClassExist(OkZoomerCompat.OKZOOMER_CLASS_PATH)) {
|
||||
mod.log("Adding okzoomer compatibility...");
|
||||
new OkZoomerCompat().handle(mod);
|
||||
}
|
||||
InputManager.loadButtonBindings(mod.config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 io.github.joaoh1.okzoomer.OkZoomer;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
/**
|
||||
* Represents a compatibility handler for OkZoomer.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class OkZoomerCompat implements CompatHandler
|
||||
{
|
||||
public static final String OKZOOMER_CLASS_PATH = "io.github.joaoh1.okzoomer.OkZoomer";
|
||||
|
||||
@Override
|
||||
public void handle(@NotNull LambdaControlsClient mod)
|
||||
{
|
||||
new ButtonBinding.Builder("zoom")
|
||||
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW.GLFW_GAMEPAD_BUTTON_X)
|
||||
.onlyInGame()
|
||||
.cooldown(true)
|
||||
.category(ButtonBinding.MISC_CATEGORY)
|
||||
.linkKeybind(OkZoomer.zoomKeyBinding)
|
||||
.register();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* 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.options.GameOptions;
|
||||
import net.minecraft.client.options.KeyBinding;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import org.aperlambda.lambdacommon.Identifier;
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
import org.aperlambda.lambdacommon.utils.function.PairPredicate;
|
||||
import org.aperlambda.lambdacommon.utils.function.Predicates;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static me.lambdaurora.lambdacontrols.client.controller.InputManager.registerDefaultCategory;
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
|
||||
/**
|
||||
* Represents a button binding.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ButtonBinding implements Nameable
|
||||
{
|
||||
public static final ButtonCategory MOVEMENT_CATEGORY;
|
||||
public static final ButtonCategory GAMEPLAY_CATEGORY;
|
||||
public static final ButtonCategory INVENTORY_CATEGORY;
|
||||
public static final ButtonCategory MULTIPLAYER_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 BACK = new Builder("back").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false)).onlyInGame().register();
|
||||
public static final ButtonBinding CHAT = new Builder("chat").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding DROP_ITEM = new Builder("drop_item").buttons(GLFW_GAMEPAD_BUTTON_B).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding FORWARD = new Builder("forward").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true)).onlyInGame().register();
|
||||
public static final ButtonBinding HOTBAR_LEFT = new Builder("hotbar_left").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
|
||||
.action(InputHandlers.handleHotbar(false)).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding HOTBAR_RIGHT = new Builder("hotbar_right").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
|
||||
.action(InputHandlers.handleHotbar(true)).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding INVENTORY = new Builder("inventory").buttons(GLFW_GAMEPAD_BUTTON_Y).onlyInGame().cooldown(true).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 PAUSE_GAME = new Builder("pause_game").buttons(GLFW_GAMEPAD_BUTTON_START).action(InputHandlers::handlePauseGame).cooldown(true).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 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 SCREENSHOT = new Builder("screenshot").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_A)
|
||||
.action(InputHandlers::handleScreenshot).cooldown(true).register();
|
||||
public static final ButtonBinding SLOT_DOWN = new Builder("slot_down").buttons(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)
|
||||
.action(InputHandlers.handleInventorySlotPad(1)).onlyInInventory().cooldown(true).register();
|
||||
public static final ButtonBinding SLOT_LEFT = new Builder("slot_left").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT)
|
||||
.action(InputHandlers.handleInventorySlotPad(3)).onlyInInventory().cooldown(true).register();
|
||||
public static final ButtonBinding SLOT_RIGHT = new Builder("slot_right").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)
|
||||
.action(InputHandlers.handleInventorySlotPad(2)).onlyInInventory().cooldown(true).register();
|
||||
public static final ButtonBinding SLOT_UP = new Builder("slot_up").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP)
|
||||
.action(InputHandlers.handleInventorySlotPad(0)).onlyInInventory().cooldown(true).register();
|
||||
public static final ButtonBinding SMOOTH_CAMERA = new Builder("toggle_smooth_camera").cooldown(true).register();
|
||||
public static final ButtonBinding SNEAK = new Builder("sneak").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)
|
||||
.actions(PressAction.DEFAULT_ACTION, InputHandlers::handleToggleSneak).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding SPRINT = new Builder("sprint").buttons(GLFW_GAMEPAD_BUTTON_LEFT_THUMB).register();
|
||||
public static final ButtonBinding SWAP_HANDS = new Builder("swap_hands").buttons(GLFW_GAMEPAD_BUTTON_X).cooldown(true).register();
|
||||
public static final ButtonBinding TAB_LEFT = new Builder("tab_left").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
|
||||
.action(InputHandlers.handleHotbar(false)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown(true).register();
|
||||
public static final ButtonBinding TAB_RIGHT = new Builder("tab_right").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
|
||||
.action(InputHandlers.handleHotbar(true)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown(true).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 USE = new Builder("use").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true)).register();
|
||||
|
||||
private int[] button;
|
||||
private int[] defaultButton;
|
||||
private String key;
|
||||
private KeyBinding mcKeyBinding = null;
|
||||
protected PairPredicate<MinecraftClient, ButtonBinding> filter;
|
||||
private List<PressAction> actions = new ArrayList<>(Collections.singletonList(PressAction.DEFAULT_ACTION));
|
||||
private boolean hasCooldown;
|
||||
private int cooldown = 0;
|
||||
boolean pressed = false;
|
||||
|
||||
public ButtonBinding(@NotNull String key, int[] defaultButton, @NotNull List<PressAction> actions, PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown)
|
||||
{
|
||||
this.setButton(this.defaultButton = defaultButton);
|
||||
this.key = key;
|
||||
this.filter = filter;
|
||||
this.actions.addAll(actions);
|
||||
this.hasCooldown = hasCooldown;
|
||||
}
|
||||
|
||||
public ButtonBinding(@NotNull String key, int[] defaultButton, boolean hasCooldown)
|
||||
{
|
||||
this(key, defaultButton, Collections.emptyList(), Predicates.pairAlwaysTrue(), hasCooldown);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the button bound.
|
||||
*
|
||||
* @return The bound button.
|
||||
*/
|
||||
public int[] getButton()
|
||||
{
|
||||
return this.button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bound button.
|
||||
*
|
||||
* @param button The bound button.
|
||||
*/
|
||||
public void setButton(int[] button)
|
||||
{
|
||||
this.button = button;
|
||||
|
||||
if (InputManager.hasBinding(this))
|
||||
InputManager.sortBindings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the bound button is the specified button or not.
|
||||
*
|
||||
* @param button The button to check.
|
||||
* @return True if the bound button is the specified button, else false.
|
||||
*/
|
||||
public boolean isButton(int[] button)
|
||||
{
|
||||
return InputManager.areButtonsEquivalent(button, this.button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this button is down or not.
|
||||
*
|
||||
* @return True if the button is down, else false.
|
||||
*/
|
||||
public boolean isButtonDown()
|
||||
{
|
||||
return this.pressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this button binding is bound or not.
|
||||
*
|
||||
* @return True if this button binding is bound, else false.
|
||||
*/
|
||||
public boolean isNotBound()
|
||||
{
|
||||
return this.button.length == 0 || this.button[0] == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default button assigned to this binding.
|
||||
*
|
||||
* @return The default button.
|
||||
*/
|
||||
public int[] getDefaultButton()
|
||||
{
|
||||
return this.defaultButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the assigned button is the default button.
|
||||
*
|
||||
* @return True if the assigned button is the default button, else false.
|
||||
*/
|
||||
public boolean isDefault()
|
||||
{
|
||||
return this.button.length == this.defaultButton.length && InputManager.areButtonsEquivalent(this.button, this.defaultButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the button code.
|
||||
*
|
||||
* @return The button code.
|
||||
*/
|
||||
public @NotNull
|
||||
String getButtonCode()
|
||||
{
|
||||
return Arrays.stream(this.button)
|
||||
.mapToObj(btn -> Integer.valueOf(btn).toString())
|
||||
.collect(Collectors.joining("+"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key binding to emulate with this button binding.
|
||||
*
|
||||
* @param keyBinding The optional key binding.
|
||||
*/
|
||||
public void setKeyBinding(@Nullable KeyBinding keyBinding)
|
||||
{
|
||||
this.mcKeyBinding = keyBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the button binding is available in the current context.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @return True if the button binding is available, else false.
|
||||
*/
|
||||
public boolean isAvailable(@NotNull MinecraftClient client)
|
||||
{
|
||||
return this.filter.test(client, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the button binding cooldown.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
if (this.hasCooldown && this.cooldown > 0)
|
||||
this.cooldown--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the button binding.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param state The state.
|
||||
*/
|
||||
public void handle(@NotNull MinecraftClient client, @NotNull ButtonState state)
|
||||
{
|
||||
if (state == ButtonState.REPEAT && this.hasCooldown && this.cooldown != 0)
|
||||
return;
|
||||
if (this.hasCooldown && state.isPressed()) {
|
||||
this.cooldown = 5;
|
||||
|
||||
}
|
||||
for (int i = this.actions.size() - 1; i >= 0; i--) {
|
||||
if (this.actions.get(i).press(client, this, state))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName()
|
||||
{
|
||||
return this.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the translation key of this button binding.
|
||||
*
|
||||
* @return The translation key.
|
||||
*/
|
||||
public @NotNull
|
||||
String getTranslationKey()
|
||||
{
|
||||
return "lambdacontrols.action." + this.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key binding equivalent of this button binding.
|
||||
*
|
||||
* @return The key binding equivalent.
|
||||
*/
|
||||
public @NotNull
|
||||
Optional<KeyBinding> asKeyBinding()
|
||||
{
|
||||
return Optional.ofNullable(this.mcKeyBinding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified axis as a button.
|
||||
*
|
||||
* @param axis The axis.
|
||||
* @param positive True if the axis part is positive, else false.
|
||||
* @return The axis as a button.
|
||||
*/
|
||||
public static int axisAsButton(int axis, boolean positive)
|
||||
{
|
||||
return positive ? 100 + axis : 200 + axis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the second Joycon's specified button code.
|
||||
*
|
||||
* @param button The raw button code.
|
||||
* @return The second Joycon's button code.
|
||||
*/
|
||||
public static int controller2Button(int button)
|
||||
{
|
||||
return 500 + button;
|
||||
}
|
||||
|
||||
public static void init(@NotNull GameOptions options)
|
||||
{
|
||||
ATTACK.mcKeyBinding = options.keyAttack;
|
||||
BACK.mcKeyBinding = options.keyBack;
|
||||
CHAT.mcKeyBinding = options.keyChat;
|
||||
DROP_ITEM.mcKeyBinding = options.keyDrop;
|
||||
FORWARD.mcKeyBinding = options.keyForward;
|
||||
INVENTORY.mcKeyBinding = options.keyInventory;
|
||||
JUMP.mcKeyBinding = options.keyJump;
|
||||
LEFT.mcKeyBinding = options.keyLeft;
|
||||
PICK_BLOCK.mcKeyBinding = options.keyPickItem;
|
||||
PLAYER_LIST.mcKeyBinding = options.keyPlayerList;
|
||||
RIGHT.mcKeyBinding = options.keyRight;
|
||||
SCREENSHOT.mcKeyBinding = options.keyScreenshot;
|
||||
SMOOTH_CAMERA.mcKeyBinding = options.keySmoothCamera;
|
||||
SNEAK.mcKeyBinding = options.keySneak;
|
||||
SPRINT.mcKeyBinding = options.keySprint;
|
||||
SWAP_HANDS.mcKeyBinding = options.keySwapHands;
|
||||
TOGGLE_PERSPECTIVE.mcKeyBinding = options.keyTogglePerspective;
|
||||
USE.mcKeyBinding = options.keyUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized name of the specified button.
|
||||
*
|
||||
* @param button The button.
|
||||
* @return The localized name of the button.
|
||||
*/
|
||||
public static @NotNull
|
||||
String getLocalizedButtonName(int button)
|
||||
{
|
||||
switch (button % 500) {
|
||||
case -1:
|
||||
return I18n.translate("key.keyboard.unknown");
|
||||
case GLFW_GAMEPAD_BUTTON_A:
|
||||
return I18n.translate("lambdacontrols.button.a");
|
||||
case GLFW_GAMEPAD_BUTTON_B:
|
||||
return I18n.translate("lambdacontrols.button.b");
|
||||
case GLFW_GAMEPAD_BUTTON_X:
|
||||
return I18n.translate("lambdacontrols.button.x");
|
||||
case GLFW_GAMEPAD_BUTTON_Y:
|
||||
return I18n.translate("lambdacontrols.button.y");
|
||||
case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
|
||||
return I18n.translate("lambdacontrols.button.left_bumper");
|
||||
case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
|
||||
return I18n.translate("lambdacontrols.button.right_bumper");
|
||||
case GLFW_GAMEPAD_BUTTON_BACK:
|
||||
return I18n.translate("lambdacontrols.button.back");
|
||||
case GLFW_GAMEPAD_BUTTON_START:
|
||||
return I18n.translate("lambdacontrols.button.start");
|
||||
case GLFW_GAMEPAD_BUTTON_GUIDE:
|
||||
return I18n.translate("lambdacontrols.button.guide");
|
||||
case GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
|
||||
return I18n.translate("lambdacontrols.button.left_thumb");
|
||||
case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
|
||||
return I18n.translate("lambdacontrols.button.right_thumb");
|
||||
case GLFW_GAMEPAD_BUTTON_DPAD_UP:
|
||||
return I18n.translate("lambdacontrols.button.dpad_up");
|
||||
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT:
|
||||
return I18n.translate("lambdacontrols.button.dpad_right");
|
||||
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN:
|
||||
return I18n.translate("lambdacontrols.button.dpad_down");
|
||||
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT:
|
||||
return I18n.translate("lambdacontrols.button.dpad_left");
|
||||
case 100:
|
||||
return I18n.translate("lambdacontrols.axis.left_x+");
|
||||
case 101:
|
||||
return I18n.translate("lambdacontrols.axis.left_y+");
|
||||
case 102:
|
||||
return I18n.translate("lambdacontrols.axis.right_x+");
|
||||
case 103:
|
||||
return I18n.translate("lambdacontrols.axis.right_y+");
|
||||
case 104:
|
||||
return I18n.translate("lambdacontrols.axis.left_trigger");
|
||||
case 105:
|
||||
return I18n.translate("lambdacontrols.axis.right_trigger");
|
||||
case 200:
|
||||
return I18n.translate("lambdacontrols.axis.left_x-");
|
||||
case 201:
|
||||
return I18n.translate("lambdacontrols.axis.left_y-");
|
||||
case 202:
|
||||
return I18n.translate("lambdacontrols.axis.right_x-");
|
||||
case 203:
|
||||
return I18n.translate("lambdacontrols.axis.right_y-");
|
||||
default:
|
||||
return I18n.translate("lambdacontrols.button.unknown", button);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
MOVEMENT_CATEGORY = registerDefaultCategory("key.categories.movement", category -> category.registerAllBindings(
|
||||
ButtonBinding.FORWARD,
|
||||
ButtonBinding.BACK,
|
||||
ButtonBinding.LEFT,
|
||||
ButtonBinding.RIGHT,
|
||||
ButtonBinding.JUMP,
|
||||
ButtonBinding.SNEAK,
|
||||
ButtonBinding.SPRINT));
|
||||
GAMEPLAY_CATEGORY = registerDefaultCategory("key.categories.gameplay", category -> category.registerAllBindings(
|
||||
ButtonBinding.ATTACK,
|
||||
ButtonBinding.PICK_BLOCK,
|
||||
ButtonBinding.USE
|
||||
));
|
||||
INVENTORY_CATEGORY = registerDefaultCategory("key.categories.inventory", category -> category.registerAllBindings(
|
||||
ButtonBinding.DROP_ITEM,
|
||||
ButtonBinding.HOTBAR_LEFT,
|
||||
ButtonBinding.HOTBAR_RIGHT,
|
||||
ButtonBinding.INVENTORY,
|
||||
ButtonBinding.SWAP_HANDS
|
||||
));
|
||||
MULTIPLAYER_CATEGORY = registerDefaultCategory("key.categories.multiplayer",
|
||||
category -> category.registerAllBindings(ButtonBinding.CHAT, ButtonBinding.PLAYER_LIST));
|
||||
MISC_CATEGORY = registerDefaultCategory("key.categories.misc", category -> category.registerAllBindings(
|
||||
ButtonBinding.SCREENSHOT,
|
||||
//SMOOTH_CAMERA,
|
||||
ButtonBinding.TOGGLE_PERSPECTIVE
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a quick {@link ButtonBinding} builder.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static class Builder
|
||||
{
|
||||
private final String key;
|
||||
private int[] buttons = new int[0];
|
||||
private List<PressAction> actions = new ArrayList<>();
|
||||
private PairPredicate<MinecraftClient, ButtonBinding> filter = Predicates.pairAlwaysTrue();
|
||||
private boolean cooldown = false;
|
||||
private ButtonCategory category = null;
|
||||
private KeyBinding mcBinding = null;
|
||||
|
||||
/**
|
||||
* This constructor shouldn't be used for other mods.
|
||||
*
|
||||
* @param key The key with format {@code "<namespace>.<name>"}.
|
||||
*/
|
||||
public Builder(@NotNull String key)
|
||||
{
|
||||
this.key = key;
|
||||
this.unbound();
|
||||
}
|
||||
|
||||
public Builder(@NotNull Identifier identifier)
|
||||
{
|
||||
this(identifier.getNamespace() + "." + identifier.getName());
|
||||
}
|
||||
|
||||
public Builder(@NotNull net.minecraft.util.Identifier identifier)
|
||||
{
|
||||
this(new Identifier(identifier.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the default buttons of the {@link ButtonBinding}.
|
||||
*
|
||||
* @param buttons The default buttons.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder buttons(int... buttons)
|
||||
{
|
||||
this.buttons = buttons;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ButtonBinding} to unbound.
|
||||
*
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder unbound()
|
||||
{
|
||||
return this.buttons(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the actions to the {@link ButtonBinding}.
|
||||
*
|
||||
* @param actions The actions to add.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder actions(@NotNull PressAction... actions)
|
||||
{
|
||||
this.actions.addAll(Arrays.asList(actions));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action to the {@link ButtonBinding}.
|
||||
*
|
||||
* @param action The action to add.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder action(@NotNull PressAction action)
|
||||
{
|
||||
this.actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a filter for the {@link ButtonBinding}.
|
||||
*
|
||||
* @param filter The filter.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder filter(@NotNull PairPredicate<MinecraftClient, ButtonBinding> filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filter of {@link ButtonBinding} to only in game.
|
||||
*
|
||||
* @return The builder instance.
|
||||
* @see #filter(PairPredicate)
|
||||
* @see InputHandlers#inGame(MinecraftClient, ButtonBinding)
|
||||
*/
|
||||
public Builder onlyInGame()
|
||||
{
|
||||
return this.filter(InputHandlers::inGame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filter of {@link ButtonBinding} to only in inventory.
|
||||
*
|
||||
* @return The builder instance.
|
||||
* @see #filter(PairPredicate)
|
||||
* @see InputHandlers#inInventory(MinecraftClient, ButtonBinding)
|
||||
*/
|
||||
public Builder onlyInInventory()
|
||||
{
|
||||
return this.filter(InputHandlers::inInventory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the {@link ButtonBinding} has a cooldown or not.
|
||||
*
|
||||
* @param cooldown True if the {@link ButtonBinding} has a cooldown, else false.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder cooldown(boolean cooldown)
|
||||
{
|
||||
this.cooldown = cooldown;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the category of the {@link ButtonBinding}.
|
||||
*
|
||||
* @param category The category.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder category(@Nullable ButtonCategory category)
|
||||
{
|
||||
this.category = category;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the keybinding linked to the {@link ButtonBinding}.
|
||||
*
|
||||
* @param binding The keybinding to link.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder linkKeybind(@Nullable KeyBinding binding)
|
||||
{
|
||||
this.mcBinding = binding;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the {@link ButtonBinding}.
|
||||
*
|
||||
* @return The built {@link ButtonBinding}.
|
||||
*/
|
||||
public ButtonBinding build()
|
||||
{
|
||||
ButtonBinding binding = new ButtonBinding(this.key, this.buttons, this.actions, this.filter, this.cooldown);
|
||||
if (this.category != null)
|
||||
this.category.registerBinding(binding);
|
||||
if (this.mcBinding != null)
|
||||
binding.setKeyBinding(this.mcBinding);
|
||||
return binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and registers the {@link ButtonBinding}.
|
||||
*
|
||||
* @return The built {@link ButtonBinding}.
|
||||
* @see #build()
|
||||
*/
|
||||
public ButtonBinding register()
|
||||
{
|
||||
return InputManager.registerBinding(this.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 net.minecraft.client.resource.language.I18n;
|
||||
import org.aperlambda.lambdacommon.Identifier;
|
||||
import org.aperlambda.lambdacommon.utils.Identifiable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a button binding category
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class ButtonCategory implements Identifiable
|
||||
{
|
||||
private final List<ButtonBinding> bindings = new ArrayList<>();
|
||||
private final Identifier id;
|
||||
private int priority;
|
||||
|
||||
public ButtonCategory(@NotNull Identifier id, int priority)
|
||||
{
|
||||
this.id = id;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public ButtonCategory(@NotNull Identifier id)
|
||||
{
|
||||
this(id, 100);
|
||||
}
|
||||
|
||||
public void registerBinding(@NotNull ButtonBinding binding)
|
||||
{
|
||||
if (this.bindings.contains(binding))
|
||||
throw new IllegalStateException("Cannot register twice a button binding in the same category.");
|
||||
this.bindings.add(binding);
|
||||
}
|
||||
|
||||
public void registerAllBindings(@NotNull ButtonBinding... bindings)
|
||||
{
|
||||
this.registerAllBindings(Arrays.asList(bindings));
|
||||
}
|
||||
|
||||
public void registerAllBindings(@NotNull List<ButtonBinding> bindings)
|
||||
{
|
||||
bindings.forEach(this::registerBinding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bindings assigned to this category.
|
||||
*
|
||||
* @return The bindings assigned to this category.
|
||||
*/
|
||||
public @NotNull List<ButtonBinding> getBindings()
|
||||
{
|
||||
return Collections.unmodifiableList(this.bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translated name of this category.
|
||||
* <p>
|
||||
* The translation key should be `modid.identifier_name`.
|
||||
*
|
||||
* @return The translated name.
|
||||
*/
|
||||
public @NotNull String getTranslatedName()
|
||||
{
|
||||
if (this.id.getNamespace().equals("minecraft"))
|
||||
return I18n.translate(this.id.getName());
|
||||
else
|
||||
return I18n.translate(this.id.getNamespace() + "." + this.id.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the priority display of this category.
|
||||
* It will defines in which order the categories will display on the controls screen.
|
||||
*
|
||||
* @return The priority of this category.
|
||||
*/
|
||||
public int getPriority()
|
||||
{
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Identifier getIdentifier()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,8 +7,9 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols;
|
||||
package me.lambdaurora.lambdacontrols.client.controller;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
@@ -31,6 +32,10 @@ import static org.lwjgl.BufferUtils.createByteBuffer;
|
||||
|
||||
/**
|
||||
* Represents a controller.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Controller implements Nameable
|
||||
{
|
||||
@@ -47,7 +52,7 @@ public class Controller implements Nameable
|
||||
*
|
||||
* @return The identifier of this controller.
|
||||
*/
|
||||
public int get_id()
|
||||
public int getId()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
@@ -57,7 +62,7 @@ public class Controller implements Nameable
|
||||
*
|
||||
* @return The controller's GUID.
|
||||
*/
|
||||
public String get_guid()
|
||||
public String getGuid()
|
||||
{
|
||||
String guid = GLFW.glfwGetJoystickGUID(this.id);
|
||||
return guid == null ? "" : guid;
|
||||
@@ -68,7 +73,7 @@ public class Controller implements Nameable
|
||||
*
|
||||
* @return True if this controller is connected, else false.
|
||||
*/
|
||||
public boolean is_connected()
|
||||
public boolean isConnected()
|
||||
{
|
||||
return GLFW.glfwJoystickPresent(this.id);
|
||||
}
|
||||
@@ -78,9 +83,9 @@ public class Controller implements Nameable
|
||||
*
|
||||
* @return True if this controller is a gamepad, else false.
|
||||
*/
|
||||
public boolean is_gamepad()
|
||||
public boolean isGamepad()
|
||||
{
|
||||
return this.is_connected() && GLFW.glfwJoystickIsGamepad(this.id);
|
||||
return this.isConnected() && GLFW.glfwJoystickIsGamepad(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,10 +94,10 @@ public class Controller implements Nameable
|
||||
* @return The controller's name.
|
||||
*/
|
||||
@Override
|
||||
public @NotNull String get_name()
|
||||
public @NotNull String getName()
|
||||
{
|
||||
String name = this.is_gamepad() ? GLFW.glfwGetGamepadName(this.id) : GLFW.glfwGetJoystickName(this.id);
|
||||
return name == null ? String.valueOf(this.get_id()) : name;
|
||||
String name = this.isGamepad() ? GLFW.glfwGetGamepadName(this.id) : GLFW.glfwGetJoystickName(this.id);
|
||||
return name == null ? String.valueOf(this.getId()) : name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,18 +105,18 @@ public class Controller implements Nameable
|
||||
*
|
||||
* @return The state of the controller input.
|
||||
*/
|
||||
public GLFWGamepadState get_state()
|
||||
public GLFWGamepadState getState()
|
||||
{
|
||||
GLFWGamepadState state = GLFWGamepadState.create();
|
||||
if (this.is_gamepad())
|
||||
if (this.isGamepad())
|
||||
GLFW.glfwGetGamepadState(this.id, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
public static @NotNull Controller by_id(int id)
|
||||
public static @NotNull Controller byId(int id)
|
||||
{
|
||||
if (id > GLFW.GLFW_JOYSTICK_LAST) {
|
||||
LambdaControls.get().log("Controller '" + id + "' doesn't exist.");
|
||||
LambdaControlsClient.get().log("Controller '" + id + "' doesn't exist.");
|
||||
id = GLFW.GLFW_JOYSTICK_LAST;
|
||||
}
|
||||
Controller controller;
|
||||
@@ -124,22 +129,22 @@ public class Controller implements Nameable
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull Optional<Controller> by_guid(@NotNull String guid)
|
||||
public static @NotNull Optional<Controller> byGuid(@NotNull String guid)
|
||||
{
|
||||
return CONTROLLERS.values().stream().filter(Controller::is_connected)
|
||||
.filter(controller -> controller.get_guid().equals(guid))
|
||||
.max(Comparator.comparingInt(Controller::get_id));
|
||||
return CONTROLLERS.values().stream().filter(Controller::isConnected)
|
||||
.filter(controller -> controller.getGuid().equals(guid))
|
||||
.max(Comparator.comparingInt(Controller::getId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the specified resource and returns the raw data as a ByteBuffer.
|
||||
*
|
||||
* @param resource The resource to read.
|
||||
* @param buffer_size The initial buffer size.
|
||||
* @param bufferSize The initial buffer size.
|
||||
* @return The resource data.
|
||||
* @throws IOException If an IO error occurs.
|
||||
*/
|
||||
private static ByteBuffer io_resource_to_buffer(String resource, int buffer_size) throws IOException
|
||||
private static ByteBuffer ioResourceToBuffer(String resource, int bufferSize) throws IOException
|
||||
{
|
||||
ByteBuffer buffer = null;
|
||||
|
||||
@@ -159,14 +164,14 @@ public class Controller implements Nameable
|
||||
/**
|
||||
* Updates the controller mappings.
|
||||
*/
|
||||
public static void update_mappings()
|
||||
public static void updateMappings()
|
||||
{
|
||||
try {
|
||||
File mappings_file = new File("config/gamecontrollerdb.txt");
|
||||
if (!mappings_file.exists())
|
||||
File mappingsFile = new File("config/gamecontrollerdb.txt");
|
||||
if (!mappingsFile.exists())
|
||||
return;
|
||||
LambdaControls.get().log("Updating controller mappings...");
|
||||
ByteBuffer buffer = io_resource_to_buffer(mappings_file.getPath(), 1024);
|
||||
LambdaControlsClient.get().log("Updating controller mappings...");
|
||||
ByteBuffer buffer = ioResourceToBuffer(mappingsFile.getPath(), 1024);
|
||||
GLFW.glfwUpdateGamepadMappings(buffer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* 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 me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.advancement.AdvancementTab;
|
||||
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.util.ScreenshotUtils;
|
||||
import net.minecraft.container.Slot;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import org.aperlambda.lambdacommon.utils.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Represents some input handlers.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class InputHandlers
|
||||
{
|
||||
private InputHandlers()
|
||||
{
|
||||
}
|
||||
|
||||
public static PressAction handleHotbar(boolean right)
|
||||
{
|
||||
return (client, button, action) -> {
|
||||
if (action == ButtonState.RELEASE)
|
||||
return false;
|
||||
|
||||
// When ingame
|
||||
if (client.currentScreen == null && client.player != null) {
|
||||
if (right)
|
||||
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 8 ? 0 : client.player.inventory.selectedSlot + 1;
|
||||
else
|
||||
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 0 ? 8 : client.player.inventory.selectedSlot - 1;
|
||||
return true;
|
||||
} else if (client.currentScreen instanceof CreativeInventoryScreen) {
|
||||
CreativeInventoryScreenAccessor inventory = (CreativeInventoryScreenAccessor) client.currentScreen;
|
||||
int currentSelectedTab = inventory.lambdacontrols_getSelectedTab();
|
||||
int nextTab = currentSelectedTab + (right ? 1 : -1);
|
||||
if (nextTab < 0)
|
||||
nextTab = ItemGroup.GROUPS.length - 1;
|
||||
else if (nextTab >= ItemGroup.GROUPS.length)
|
||||
nextTab = 0;
|
||||
inventory.lambdacontrols_setSelectedTab(ItemGroup.GROUPS[nextTab]);
|
||||
return true;
|
||||
} else if (client.currentScreen instanceof AdvancementsScreen) {
|
||||
AdvancementsScreenAccessor screen = (AdvancementsScreenAccessor) client.currentScreen;
|
||||
List<AdvancementTab> tabs = screen.lambdacontrols_getTabs().values().stream().distinct().collect(Collectors.toList());
|
||||
AdvancementTab tab = screen.lambdacontrols_getSelectedTab();
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
if (tabs.get(i).equals(tab)) {
|
||||
int nextTab = i + (right ? 1 : -1);
|
||||
if (nextTab < 0)
|
||||
nextTab = tabs.size() - 1;
|
||||
else if (nextTab >= tabs.size())
|
||||
nextTab = 0;
|
||||
screen.lambdacontrols_getAdvancementManager().selectTab(tabs.get(nextTab).getRoot(), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean handlePauseGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, @NotNull ButtonState action)
|
||||
{
|
||||
if (action == ButtonState.PRESS) {
|
||||
// If in game, then pause the game.
|
||||
if (client.currentScreen == null)
|
||||
client.openPauseMenu(false);
|
||||
else if (client.currentScreen instanceof ContainerScreen && client.player != null) // If the current screen is a container then close it.
|
||||
client.player.closeContainer();
|
||||
else // Else just close the current screen.
|
||||
client.currentScreen.onClose();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the screenshot action.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param binding The binding which fired the action.
|
||||
* @param action The action done on the binding.
|
||||
* @return True if handled, else false.
|
||||
*/
|
||||
public static boolean handleScreenshot(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, @NotNull ButtonState action)
|
||||
{
|
||||
if (action == ButtonState.PRESS)
|
||||
ScreenshotUtils.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(),
|
||||
text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text)));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean handleToggleSneak(@NotNull MinecraftClient client, @NotNull ButtonBinding button, @NotNull ButtonState action)
|
||||
{
|
||||
if (client.player != null && !client.player.abilities.flying) {
|
||||
button.asKeyBinding().filter(binding -> action == ButtonState.PRESS).ifPresent(binding -> ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(!binding.isPressed()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static PressAction handleInventorySlotPad(int direction)
|
||||
{
|
||||
return (client, binding, action) -> {
|
||||
if (!(client.currentScreen instanceof ContainerScreen && action != ButtonState.RELEASE))
|
||||
return false;
|
||||
|
||||
ContainerScreen inventory = (ContainerScreen) client.currentScreen;
|
||||
ContainerScreenAccessor accessor = (ContainerScreenAccessor) inventory;
|
||||
int guiLeft = accessor.lambdacontrols_getX();
|
||||
int guiTop = accessor.lambdacontrols_getY();
|
||||
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
|
||||
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
|
||||
|
||||
// Finds the hovered slot.
|
||||
Slot mouseSlot = accessor.lambdacontrols_getSlotAt(mouseX, mouseY);
|
||||
|
||||
// Finds the closest slot in the GUI within 14 pixels.
|
||||
Optional<Slot> closestSlot = inventory.getContainer().slots.parallelStream()
|
||||
.filter(Predicate.isEqual(mouseSlot).negate())
|
||||
.map(slot -> {
|
||||
int posX = guiLeft + slot.xPosition + 8;
|
||||
int posY = guiTop + slot.yPosition + 8;
|
||||
|
||||
int otherPosX = (int) mouseX;
|
||||
int otherPosY = (int) mouseY;
|
||||
if (mouseSlot != null) {
|
||||
otherPosX = guiLeft + mouseSlot.xPosition + 8;
|
||||
otherPosY = guiTop + mouseSlot.yPosition + 8;
|
||||
}
|
||||
|
||||
// Distance between the slot and the cursor.
|
||||
double distance = Math.sqrt(Math.pow(posX - otherPosX, 2) + Math.pow(posY - otherPosY, 2));
|
||||
return Pair.of(slot, distance);
|
||||
}).filter(entry -> {
|
||||
Slot slot = entry.key;
|
||||
int posX = guiLeft + slot.xPosition + 8;
|
||||
int posY = guiTop + slot.yPosition + 8;
|
||||
int otherPosX = (int) mouseX;
|
||||
int otherPosY = (int) mouseY;
|
||||
if (mouseSlot != null) {
|
||||
otherPosX = guiLeft + mouseSlot.xPosition + 8;
|
||||
otherPosY = guiTop + mouseSlot.yPosition + 8;
|
||||
}
|
||||
if (direction == 0)
|
||||
return posY < otherPosY;
|
||||
else if (direction == 1)
|
||||
return posY > otherPosY;
|
||||
else if (direction == 2)
|
||||
return posX > otherPosX;
|
||||
else if (direction == 3)
|
||||
return posX < otherPosX;
|
||||
else
|
||||
return false;
|
||||
})
|
||||
.min(Comparator.comparingDouble(p -> p.value))
|
||||
.map(p -> p.key);
|
||||
|
||||
if (closestSlot.isPresent()) {
|
||||
Slot slot = closestSlot.get();
|
||||
int x = guiLeft + slot.xPosition + 8;
|
||||
int y = guiTop + slot.yPosition + 8;
|
||||
InputManager.queueMousePosition(x * (double) client.getWindow().getWidth() / (double) client.getWindow().getScaledWidth(),
|
||||
y * (double) client.getWindow().getHeight() / (double) client.getWindow().getScaledHeight());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns always true to the filter.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param binding The affected binding.
|
||||
* @return True.
|
||||
*/
|
||||
public static boolean always(@NotNull MinecraftClient client, @NotNull ButtonBinding binding)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the client is in game or not.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param binding The affected binding.
|
||||
* @return True if the client is in game, else false.
|
||||
*/
|
||||
public static boolean inGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding)
|
||||
{
|
||||
return client.currentScreen == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the client is in an inventory or not.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param binding The affected binding.
|
||||
* @return True if the client is in an inventory, else false.
|
||||
*/
|
||||
public static boolean inInventory(@NotNull MinecraftClient client, @NotNull ButtonBinding binding)
|
||||
{
|
||||
return client.currentScreen instanceof ContainerScreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the client is in the advancements screen or not.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param binding The affected binding.
|
||||
* @return True if the client is in the advancements screen, else false.
|
||||
*/
|
||||
public static boolean inAdvancements(@NotNull MinecraftClient client, @NotNull ButtonBinding binding)
|
||||
{
|
||||
return client.currentScreen instanceof AdvancementsScreen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* 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.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.client.ButtonState;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsConfig;
|
||||
import me.lambdaurora.lambdacontrols.client.util.MouseAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.aperlambda.lambdacommon.Identifier;
|
||||
import org.aperlambda.lambdacommon.utils.function.PairPredicate;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Represents an input manager for controllers.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class InputManager
|
||||
{
|
||||
public static final InputManager INPUT_MANAGER = new InputManager();
|
||||
private static final List<ButtonBinding> BINDINGS = new ArrayList<>();
|
||||
private static final List<ButtonCategory> CATEGORIES = new ArrayList<>();
|
||||
public static final Map<Integer, ButtonState> STATES = new HashMap<>();
|
||||
private int prevTargetMouseX = 0;
|
||||
private int prevTargetMouseY = 0;
|
||||
private int targetMouseX = 0;
|
||||
private int targetMouseY = 0;
|
||||
|
||||
protected InputManager()
|
||||
{
|
||||
}
|
||||
|
||||
public void tick(@NotNull MinecraftClient client)
|
||||
{
|
||||
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
|
||||
this.controllerTick(client);
|
||||
}
|
||||
}
|
||||
|
||||
public void controllerTick(@NotNull MinecraftClient client)
|
||||
{
|
||||
this.prevTargetMouseX = this.targetMouseX;
|
||||
this.prevTargetMouseY = this.targetMouseY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the mouse position. Should only be called on pre render of a screen.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void updateMousePosition(@NotNull MinecraftClient client)
|
||||
{
|
||||
Objects.requireNonNull(client, "Client instance cannot be null.");
|
||||
if (this.prevTargetMouseX != this.targetMouseX || this.prevTargetMouseY != this.targetMouseY) {
|
||||
double mouseX = this.prevTargetMouseX + (this.targetMouseX - this.prevTargetMouseX) * client.getTickDelta() + 0.5;
|
||||
double mouseY = this.prevTargetMouseY + (this.targetMouseY - this.prevTargetMouseY) * client.getTickDelta() + 0.5;
|
||||
GLFW.glfwSetCursorPos(client.getWindow().getHandle(), mouseX, mouseY);
|
||||
((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the mouse position.
|
||||
*
|
||||
* @param windowWidth The window width.
|
||||
* @param windowHeight The window height.
|
||||
*/
|
||||
public void resetMousePosition(int windowWidth, int windowHeight)
|
||||
{
|
||||
this.targetMouseX = this.prevTargetMouseX = (int) (windowWidth / 2.F);
|
||||
this.targetMouseY = this.prevTargetMouseY = (int) (windowHeight / 2.F);
|
||||
}
|
||||
|
||||
public void resetMouseTarget(@NotNull MinecraftClient client)
|
||||
{
|
||||
double mouseX = client.mouse.getX();
|
||||
double mouseY = client.mouse.getY();
|
||||
this.prevTargetMouseX = this.targetMouseX = (int) mouseX;
|
||||
this.prevTargetMouseY = this.targetMouseY = (int) mouseY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified binding is registered or not.
|
||||
*
|
||||
* @param binding The binding to check.
|
||||
* @return True if the binding is registered, else false.
|
||||
*/
|
||||
public static boolean hasBinding(@NotNull ButtonBinding binding)
|
||||
{
|
||||
return BINDINGS.contains(binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified binding is registered or not.
|
||||
*
|
||||
* @param name The name of the binding to check.
|
||||
* @return True if the binding is registered, else false.
|
||||
*/
|
||||
public static boolean hasBinding(@NotNull String name)
|
||||
{
|
||||
return BINDINGS.parallelStream().map(ButtonBinding::getName).anyMatch(binding -> binding.equalsIgnoreCase(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified binding is registered or not.
|
||||
*
|
||||
* @param identifier The identifier of the binding to check.
|
||||
* @return True if the binding is registered, else false.
|
||||
*/
|
||||
public static boolean hasBinding(@NotNull Identifier identifier)
|
||||
{
|
||||
return hasBinding(identifier.getNamespace() + "." + identifier.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a button binding.
|
||||
*
|
||||
* @param binding The binding to register.
|
||||
* @return The registered binding.
|
||||
*/
|
||||
public static @NotNull ButtonBinding registerBinding(@NotNull ButtonBinding binding)
|
||||
{
|
||||
if (hasBinding(binding))
|
||||
throw new IllegalStateException("Cannot register twice a button binding in the registry.");
|
||||
BINDINGS.add(binding);
|
||||
return binding;
|
||||
}
|
||||
|
||||
public static @NotNull ButtonBinding registerBinding(@NotNull Identifier id, int[] defaultButton, @NotNull List<PressAction> actions, @NotNull PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown)
|
||||
{
|
||||
return registerBinding(new ButtonBinding(id.getNamespace() + "." + id.getName(), defaultButton, actions, filter, hasCooldown));
|
||||
}
|
||||
|
||||
public static @NotNull ButtonBinding registerBinding(@NotNull Identifier id, int[] defaultButton, boolean hasCooldown)
|
||||
{
|
||||
return registerBinding(id, defaultButton, Collections.emptyList(), InputHandlers::always, hasCooldown);
|
||||
}
|
||||
|
||||
public static @NotNull ButtonBinding registerBinding(@NotNull net.minecraft.util.Identifier id, int[] defaultButton, @NotNull List<PressAction> actions, @NotNull PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown)
|
||||
{
|
||||
return registerBinding(new Identifier(id.getNamespace(), id.getPath()), defaultButton, actions, filter, hasCooldown);
|
||||
}
|
||||
|
||||
public static @NotNull ButtonBinding registerBinding(@NotNull net.minecraft.util.Identifier id, int[] defaultButton, boolean hasCooldown)
|
||||
{
|
||||
return registerBinding(id, defaultButton, Collections.emptyList(), InputHandlers::always, hasCooldown);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts bindings to get bindings with the higher button counts first.
|
||||
*/
|
||||
public static void sortBindings()
|
||||
{
|
||||
synchronized (BINDINGS) {
|
||||
List<ButtonBinding> sorted = BINDINGS.stream().sorted(Collections.reverseOrder(Comparator.comparingInt(binding -> binding.getButton().length)))
|
||||
.collect(Collectors.toList());
|
||||
BINDINGS.clear();
|
||||
BINDINGS.addAll(sorted);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a category of button bindings.
|
||||
*
|
||||
* @param category The category to register.
|
||||
* @return The registered category.
|
||||
*/
|
||||
public static ButtonCategory registerCategory(@NotNull ButtonCategory category)
|
||||
{
|
||||
CATEGORIES.add(category);
|
||||
return category;
|
||||
}
|
||||
|
||||
public static ButtonCategory registerCategory(@NotNull Identifier identifier, int priority)
|
||||
{
|
||||
return registerCategory(new ButtonCategory(identifier, priority));
|
||||
}
|
||||
|
||||
public static ButtonCategory registerCategory(@NotNull Identifier identifier)
|
||||
{
|
||||
return registerCategory(new ButtonCategory(identifier));
|
||||
}
|
||||
|
||||
protected static ButtonCategory registerDefaultCategory(@NotNull String key, @NotNull Consumer<ButtonCategory> keyAdder)
|
||||
{
|
||||
ButtonCategory category = registerCategory(new Identifier("minecraft", key), CATEGORIES.size());
|
||||
keyAdder.accept(category);
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the button bindings from configuration.
|
||||
*
|
||||
* @param config The configuration instance.
|
||||
*/
|
||||
public static void loadButtonBindings(@NotNull LambdaControlsConfig config)
|
||||
{
|
||||
List<ButtonBinding> queue = new ArrayList<>(BINDINGS);
|
||||
queue.forEach(config::loadButtonBinding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binding state.
|
||||
*
|
||||
* @param binding The binding.
|
||||
* @return The current state of the binding.
|
||||
*/
|
||||
public static @NotNull ButtonState getBindingState(@NotNull ButtonBinding binding)
|
||||
{
|
||||
ButtonState state = ButtonState.REPEAT;
|
||||
for (int btn : binding.getButton()) {
|
||||
ButtonState btnState = InputManager.STATES.getOrDefault(btn, ButtonState.NONE);
|
||||
if (btnState == ButtonState.PRESS)
|
||||
state = ButtonState.PRESS;
|
||||
else if (btnState == ButtonState.RELEASE) {
|
||||
state = ButtonState.RELEASE;
|
||||
break;
|
||||
} else if (btnState == ButtonState.NONE) {
|
||||
state = ButtonState.NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the button has duplicated bindings.
|
||||
*
|
||||
* @param button The button to check.
|
||||
* @return True if the button has duplicated bindings, else false.
|
||||
*/
|
||||
public static boolean hasDuplicatedBindings(int[] button)
|
||||
{
|
||||
return BINDINGS.parallelStream().filter(binding -> areButtonsEquivalent(binding.getButton(), button)).count() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the button has duplicated bindings.
|
||||
*
|
||||
* @param binding The binding to check.
|
||||
* @return True if the button has duplicated bindings, else false.
|
||||
*/
|
||||
public static boolean hasDuplicatedBindings(ButtonBinding binding)
|
||||
{
|
||||
return BINDINGS.parallelStream().filter(other -> areButtonsEquivalent(other.getButton(), binding.getButton()) && other.filter.equals(binding.filter)).count() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified buttons are equivalent or not.
|
||||
*
|
||||
* @param buttons1 First set of buttons.
|
||||
* @param buttons2 Second set of buttons.
|
||||
* @return True if the two sets of buttons are equivalent, else false.
|
||||
*/
|
||||
public static boolean areButtonsEquivalent(int[] buttons1, int[] buttons2)
|
||||
{
|
||||
if (buttons1.length != buttons2.length)
|
||||
return false;
|
||||
int count = 0;
|
||||
for (int btn : buttons1) {
|
||||
for (int btn2 : buttons2) {
|
||||
if (btn == btn2) {
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count == buttons1.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the button set contains the specified button or not.
|
||||
*
|
||||
* @param buttons The button set.
|
||||
* @param button The button to check.
|
||||
* @return True if the button set contains the specified button, else false.
|
||||
*/
|
||||
public static boolean containsButton(int[] buttons, int button)
|
||||
{
|
||||
return Arrays.stream(buttons).anyMatch(btn -> btn == button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the button states.
|
||||
*/
|
||||
public static void updateStates()
|
||||
{
|
||||
STATES.forEach((btn, state) -> {
|
||||
if (state == ButtonState.PRESS)
|
||||
STATES.put(btn, ButtonState.REPEAT);
|
||||
else if (state == ButtonState.RELEASE)
|
||||
STATES.put(btn, ButtonState.NONE);
|
||||
});
|
||||
}
|
||||
|
||||
public static void updateBindings(@NotNull MinecraftClient client)
|
||||
{
|
||||
List<Integer> skipButtons = new ArrayList<>();
|
||||
Map<ButtonBinding, ButtonState> states = new HashMap<>();
|
||||
for (ButtonBinding binding : BINDINGS) {
|
||||
ButtonState state = binding.isAvailable(client) ? getBindingState(binding) : ButtonState.NONE;
|
||||
if (skipButtons.stream().anyMatch(btn -> containsButton(binding.getButton(), btn))) {
|
||||
if (binding.pressed)
|
||||
state = ButtonState.RELEASE;
|
||||
else
|
||||
state = ButtonState.NONE;
|
||||
}
|
||||
binding.pressed = state.isPressed();
|
||||
binding.update();
|
||||
if (binding.pressed)
|
||||
Arrays.stream(binding.getButton()).forEach(skipButtons::add);
|
||||
states.put(binding, state);
|
||||
}
|
||||
|
||||
states.forEach((binding, state) -> {
|
||||
if (state != ButtonState.NONE) {
|
||||
binding.handle(client, state);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void queueMousePosition(double x, double y)
|
||||
{
|
||||
INPUT_MANAGER.targetMouseX = (int) MathHelper.clamp(x, 0, MinecraftClient.getInstance().getWindow().getWidth());
|
||||
INPUT_MANAGER.targetMouseY = (int) MathHelper.clamp(y, 0, MinecraftClient.getInstance().getWindow().getHeight());
|
||||
}
|
||||
|
||||
public static void queueMoveMousePosition(double x, double y)
|
||||
{
|
||||
queueMousePosition(INPUT_MANAGER.targetMouseX + x, INPUT_MANAGER.targetMouseY + y);
|
||||
}
|
||||
|
||||
public static @NotNull Stream<ButtonBinding> streamBindings()
|
||||
{
|
||||
return BINDINGS.stream();
|
||||
}
|
||||
|
||||
public static @NotNull Stream<ButtonCategory> streamCategories()
|
||||
{
|
||||
return CATEGORIES.stream();
|
||||
}
|
||||
}
|
||||
@@ -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.controller;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.client.ButtonState;
|
||||
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a press action callback.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PressAction
|
||||
{
|
||||
PressAction DEFAULT_ACTION = (client, button, action) -> {
|
||||
if (action == ButtonState.REPEAT || client.currentScreen != null)
|
||||
return false;
|
||||
button.asKeyBinding().ifPresent(binding -> ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(button.isButtonDown()));
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when there is a press action.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param action The action done.
|
||||
*/
|
||||
boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, @NotNull ButtonState action);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.ButtonBinding;
|
||||
import me.lambdaurora.spruceui.AbstractIconButtonWidget;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import org.aperlambda.lambdacommon.utils.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a controller button widget.
|
||||
*/
|
||||
public class ControllerButtonWidget extends AbstractIconButtonWidget
|
||||
{
|
||||
private ButtonBinding binding;
|
||||
private int iconWidth;
|
||||
|
||||
public ControllerButtonWidget(int x, int y, int width, @NotNull ButtonBinding binding, @NotNull PressAction action)
|
||||
{
|
||||
super(x, y, width, 20, ButtonBinding.getLocalizedButtonName(binding.getButton()[0]), action);
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
int length = binding.getButton().length;
|
||||
this.setMessage(this.binding.isNotBound() ? I18n.translate("lambdacontrols.not_bound") :
|
||||
(length > 0 ? ButtonBinding.getLocalizedButtonName(binding.getButton()[0]) : "<>"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
if (this.binding.getButton().length > 1)
|
||||
return "";
|
||||
return super.getMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int renderIcon(int mouseX, int mouseY, float delta, int x, int y)
|
||||
{
|
||||
if (this.binding.getButton().length > 1) {
|
||||
x += (this.width / 2 - this.iconWidth / 2) - 4;
|
||||
}
|
||||
Pair<Integer, Integer> size = LambdaControlsClient.drawButton(x, y, this.binding, MinecraftClient.getInstance());
|
||||
this.iconWidth = size.key;
|
||||
return size.value;
|
||||
}
|
||||
}
|
||||
@@ -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.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
|
||||
import me.lambdaurora.spruceui.SpruceButtonWidget;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import org.aperlambda.lambdacommon.utils.function.Predicates;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the controls screen.
|
||||
*/
|
||||
public class ControllerControlsScreen extends Screen
|
||||
{
|
||||
private final Screen parent;
|
||||
final LambdaControlsClient mod;
|
||||
private final boolean hideSettings;
|
||||
private ControlsListWidget bindingsListWidget;
|
||||
private ButtonWidget resetButton;
|
||||
public ButtonBinding focusedBinding;
|
||||
public boolean waiting = false;
|
||||
public List<Integer> currentButtons = new ArrayList<>();
|
||||
|
||||
public ControllerControlsScreen(@NotNull Screen parent, boolean hideSettings)
|
||||
{
|
||||
super(new TranslatableText("lambdacontrols.menu.title.controller_controls"));
|
||||
this.parent = parent;
|
||||
this.mod = LambdaControlsClient.get();
|
||||
this.hideSettings = hideSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed()
|
||||
{
|
||||
this.mod.config.save();
|
||||
super.removed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
this.addButton(new SpruceButtonWidget(this.width / 2 - 155, 18, this.hideSettings ? 310 : 150, 20, I18n.translate("lambdacontrols.menu.keyboard_controls"),
|
||||
btn -> this.minecraft.openScreen(new ControlsOptionsScreen(this, this.minecraft.options))));
|
||||
if (!this.hideSettings)
|
||||
this.addButton(new SpruceButtonWidget(this.width / 2 - 155 + 160, 18, 150, 20, I18n.translate("menu.options"),
|
||||
btn -> this.minecraft.openScreen(new LambdaControlsSettingsScreen(this, this.minecraft.options, true))));
|
||||
this.bindingsListWidget = new ControlsListWidget(this, this.minecraft);
|
||||
this.children.add(this.bindingsListWidget);
|
||||
this.resetButton = this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 150, 20, I18n.translate("controls.resetAll"),
|
||||
btn -> InputManager.streamBindings().forEach(binding -> this.mod.config.setButtonBinding(binding, binding.getDefaultButton()))));
|
||||
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20, I18n.translate("gui.done"),
|
||||
btn -> this.minecraft.openScreen(this.parent)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouseX, int mouseY, float delta)
|
||||
{
|
||||
this.renderBackground();
|
||||
this.bindingsListWidget.render(mouseX, mouseY, delta);
|
||||
this.drawCenteredString(this.font, this.title.asFormattedString(), this.width / 2, 8, 16777215);
|
||||
this.resetButton.active = InputManager.streamBindings().anyMatch(Predicates.not(ButtonBinding::isDefault));
|
||||
super.render(mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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.controller.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.ButtonCategory;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.gui.widget.ElementListWidget;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.util.Formatting;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a control list widget.
|
||||
*/
|
||||
public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Entry>
|
||||
{
|
||||
private static final int[] UNBOUND = new int[0];
|
||||
private final ControllerControlsScreen gui;
|
||||
private int field_2733;
|
||||
|
||||
public ControlsListWidget(@NotNull ControllerControlsScreen gui, @NotNull MinecraftClient client)
|
||||
{
|
||||
super(client, gui.width + 45, gui.height, 43, gui.height - 32, 24);
|
||||
this.gui = gui;
|
||||
|
||||
InputManager.streamCategories()
|
||||
.sorted(Comparator.comparingInt(ButtonCategory::getPriority))
|
||||
.forEach(category -> {
|
||||
this.addEntry(new CategoryEntry(category));
|
||||
|
||||
category.getBindings().forEach(binding -> {
|
||||
int i = client.textRenderer.getStringWidth(I18n.translate(binding.getTranslationKey()));
|
||||
if (i > this.field_2733) {
|
||||
this.field_2733 = i;
|
||||
}
|
||||
|
||||
this.addEntry(new ControlsListWidget.ButtonBindingEntry(binding));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getScrollbarPosition()
|
||||
{
|
||||
return super.getScrollbarPosition() + 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowWidth()
|
||||
{
|
||||
return super.getRowWidth() + 32;
|
||||
}
|
||||
|
||||
public class ButtonBindingEntry extends Entry
|
||||
{
|
||||
private final ButtonBinding binding;
|
||||
private final String bindingName;
|
||||
private final ControllerButtonWidget editButton;
|
||||
private final ButtonWidget resetButton;
|
||||
private final ButtonWidget unboundButton;
|
||||
|
||||
ButtonBindingEntry(@NotNull ButtonBinding binding)
|
||||
{
|
||||
this.binding = binding;
|
||||
this.bindingName = I18n.translate(this.binding.getTranslationKey());
|
||||
this.editButton = new ControllerButtonWidget(0, 0, 110, this.binding, btn -> {
|
||||
gui.focusedBinding = binding;
|
||||
gui.currentButtons.clear();
|
||||
gui.waiting = true;
|
||||
})
|
||||
{
|
||||
protected String getNarrationMessage()
|
||||
{
|
||||
return binding.isNotBound() ? I18n.translate("narrator.controls.unbound", bindingName) : I18n.translate("narrator.controls.bound", bindingName, super.getNarrationMessage());
|
||||
}
|
||||
};
|
||||
this.resetButton = new ButtonWidget(0, 0, 50, 20, I18n.translate("controls.reset"),
|
||||
btn -> gui.mod.config.setButtonBinding(binding, binding.getDefaultButton()))
|
||||
{
|
||||
protected String getNarrationMessage()
|
||||
{
|
||||
return I18n.translate("narrator.controls.reset", bindingName);
|
||||
}
|
||||
};
|
||||
this.unboundButton = new ButtonWidget(0, 0, 50, 20, I18n.translate("lambdacontrols.menu.unbound"),
|
||||
btn -> {
|
||||
gui.mod.config.setButtonBinding(binding, UNBOUND);
|
||||
gui.focusedBinding = null;
|
||||
})
|
||||
{
|
||||
protected String getNarrationMessage()
|
||||
{
|
||||
return I18n.translate("lambdacontrols.narrator.unbound", bindingName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Element> children()
|
||||
{
|
||||
return Collections.unmodifiableList(Arrays.asList(this.editButton, this.resetButton));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovering, float delta)
|
||||
{
|
||||
boolean focused = gui.focusedBinding == this.binding;
|
||||
TextRenderer textRenderer = ControlsListWidget.this.minecraft.textRenderer;
|
||||
String bindingName = this.bindingName;
|
||||
float var10002 = (float) (x + 70 - ControlsListWidget.this.field_2733);
|
||||
int var10003 = y + height / 2;
|
||||
textRenderer.draw(bindingName, var10002, (float) (var10003 - 9 / 2), 16777215);
|
||||
this.resetButton.x = this.unboundButton.x = x + 190;
|
||||
this.resetButton.y = this.unboundButton.y = y;
|
||||
this.resetButton.active = !this.binding.isDefault();
|
||||
if (focused)
|
||||
this.unboundButton.render(mouseX, mouseY, delta);
|
||||
else
|
||||
this.resetButton.render(mouseX, mouseY, delta);
|
||||
this.editButton.x = x + 75;
|
||||
this.editButton.y = y;
|
||||
this.editButton.update();
|
||||
|
||||
if (focused) {
|
||||
this.editButton.setMessage(Formatting.WHITE + "> " + Formatting.YELLOW + this.editButton.getMessage() + Formatting.WHITE + " <");
|
||||
} else if (!this.binding.isNotBound() && InputManager.hasDuplicatedBindings(this.binding)) {
|
||||
this.editButton.setMessage(Formatting.RED + this.editButton.getMessage());
|
||||
} else if (this.binding.isNotBound()) {
|
||||
this.editButton.setMessage(Formatting.GOLD + this.editButton.getMessage());
|
||||
}
|
||||
|
||||
this.editButton.render(mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button)
|
||||
{
|
||||
boolean focused = gui.focusedBinding == this.binding;
|
||||
if (this.editButton.mouseClicked(mouseX, mouseY, button))
|
||||
return true;
|
||||
else
|
||||
return focused ? this.unboundButton.mouseClicked(mouseX, mouseY, button) : this.resetButton.mouseClicked(mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
public boolean mouseReleased(double mouseX, double mouseY, int button)
|
||||
{
|
||||
return this.editButton.mouseReleased(mouseX, mouseY, button) || this.resetButton.mouseReleased(mouseX, mouseY, button)
|
||||
|| this.unboundButton.mouseReleased(mouseX, mouseY, button);
|
||||
}
|
||||
}
|
||||
|
||||
public class CategoryEntry extends Entry
|
||||
{
|
||||
private final String name;
|
||||
private final int nameWidth;
|
||||
|
||||
public CategoryEntry(@NotNull ButtonCategory category)
|
||||
{
|
||||
this.name = category.getTranslatedName();
|
||||
this.nameWidth = ControlsListWidget.this.minecraft.textRenderer.getStringWidth(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(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),
|
||||
(float) ((y + height) - 9 - 1), 16777215);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changeFocus(boolean bl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Element> children()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public abstract static class Entry extends ElementListWidget.Entry<Entry>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
|
||||
import me.lambdaurora.lambdacontrols.client.HudSide;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
|
||||
import me.lambdaurora.spruceui.hud.Hud;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls HUD.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class LambdaControlsHud extends Hud
|
||||
{
|
||||
private final LambdaControlsClient mod;
|
||||
private MinecraftClient client;
|
||||
private int widthBottom = 0;
|
||||
private int widthTop = 0;
|
||||
|
||||
public LambdaControlsHud(@NotNull LambdaControlsClient mod)
|
||||
{
|
||||
super(new Identifier(LambdaControlsConstants.NAMESPACE, "hud/button_indicator"));
|
||||
this.mod = mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(@NotNull MinecraftClient client, int screenWidth, int screenHeight)
|
||||
{
|
||||
super.init(client, screenWidth, screenHeight);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the LambdaControls' HUD.
|
||||
*/
|
||||
public void render(float tickDelta)
|
||||
{
|
||||
if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER && this.client.currentScreen == null) {
|
||||
int x = this.mod.config.getHudSide() == HudSide.LEFT ? 10 : client.getWindow().getScaledWidth() - 10 - this.widthBottom, y = bottom(10);
|
||||
x += (this.widthBottom = this.drawButtonTip(x, y, ButtonBinding.INVENTORY, true) + 10);
|
||||
this.widthBottom += this.drawButtonTip(x, y, ButtonBinding.SWAP_HANDS, true);
|
||||
x = this.mod.config.getHudSide() == HudSide.LEFT ? 10 : client.getWindow().getScaledWidth() - 10 - this.widthTop;
|
||||
x += (this.widthTop = this.drawButtonTip(x, (y -= 20), ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()) + 10);
|
||||
this.widthTop += this.drawButtonTip(x, y, ButtonBinding.ATTACK.getButton(),
|
||||
this.client.crosshairTarget.getType() == HitResult.Type.BLOCK ? "lambdacontrols.action.hit" : ButtonBinding.ATTACK.getTranslationKey(),
|
||||
this.client.crosshairTarget.getType() != HitResult.Type.MISS);
|
||||
}
|
||||
}
|
||||
|
||||
private int bottom(int y)
|
||||
{
|
||||
return this.client.getWindow().getScaledHeight() - y - 15;
|
||||
}
|
||||
|
||||
private int drawButtonTip(int x, int y, @NotNull ButtonBinding button, boolean display)
|
||||
{
|
||||
return LambdaControlsClient.drawButtonTip(x, y, button, display, this.client);
|
||||
}
|
||||
|
||||
private int drawButtonTip(int x, int y, int[] button, @NotNull String action, boolean display)
|
||||
{
|
||||
return LambdaControlsClient.drawButtonTip(x, y, button, action, display, this.client);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.Controller;
|
||||
import me.lambdaurora.spruceui.SpruceButtonWidget;
|
||||
import me.lambdaurora.spruceui.SpruceLabelWidget;
|
||||
import me.lambdaurora.spruceui.Tooltip;
|
||||
import me.lambdaurora.spruceui.option.*;
|
||||
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
|
||||
import net.minecraft.client.gui.widget.ButtonListWidget;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.options.GameOptions;
|
||||
import net.minecraft.client.options.Option;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Util;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls settings screen.
|
||||
*/
|
||||
public class LambdaControlsSettingsScreen extends Screen
|
||||
{
|
||||
public static final String GAMEPAD_TOOL_URL = "http://generalarcade.com/gamepadtool/";
|
||||
final LambdaControlsClient mod;
|
||||
private final Screen parent;
|
||||
private final boolean hideControls;
|
||||
// General options
|
||||
private final Option autoSwitchModeOption;
|
||||
private final Option rotationSpeedOption;
|
||||
private final Option mouseSpeedOption;
|
||||
private final Option resetOption;
|
||||
// Gameplay options
|
||||
private final Option frontBlockPlacingOption;
|
||||
private final Option flyDriftingOption;
|
||||
private final Option flyVerticalDriftingOption;
|
||||
// Controller options
|
||||
private final Option controllerOption;
|
||||
private final Option secondControllerOption;
|
||||
private final Option controllerTypeOption;
|
||||
private final Option deadZoneOption;
|
||||
private final Option invertsRightXAxis;
|
||||
private final Option invertsRightYAxis;
|
||||
private final Option unfocusedInputOption;
|
||||
// Hud options
|
||||
private final Option hudEnableOption;
|
||||
private final Option hudSideOption;
|
||||
private final String controllerMappingsUrlText = I18n.translate("lambdacontrols.controller.mappings.2", Formatting.GOLD.toString(), GAMEPAD_TOOL_URL, Formatting.RESET.toString());
|
||||
private ButtonListWidget list;
|
||||
private SpruceLabelWidget gamepadToolUrlLabel;
|
||||
|
||||
public LambdaControlsSettingsScreen(Screen parent, @NotNull GameOptions options, boolean hideControls)
|
||||
{
|
||||
super(new TranslatableText("lambdacontrols.title.settings"));
|
||||
this.mod = LambdaControlsClient.get();
|
||||
this.parent = parent;
|
||||
this.hideControls = hideControls;
|
||||
// General options
|
||||
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.rotationSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.rotation_speed", 0.0, 150.0, 0.5F, this.mod.config::getRotationSpeed,
|
||||
newValue -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.setRotationSpeed(newValue);
|
||||
}
|
||||
}, option -> option.getDisplayPrefix() + option.get(),
|
||||
new TranslatableText("lambdacontrols.tooltip.rotation_speed"));
|
||||
this.mouseSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.mouse_speed", 0.0, 150.0, 0.5F, this.mod.config::getMouseSpeed,
|
||||
newValue -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.setMouseSpeed(newValue);
|
||||
}
|
||||
}, option -> option.getDisplayPrefix() + option.get(),
|
||||
new TranslatableText("lambdacontrols.tooltip.mouse_speed"));
|
||||
this.resetOption = new SpruceResetOption(btn -> {
|
||||
this.mod.config.reset();
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
this.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
|
||||
});
|
||||
// Gameplay options
|
||||
this.frontBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.front_block_placing", this.mod.config::hasFrontBlockPlacing,
|
||||
this.mod.config::setFrontBlockPlacing, new TranslatableText("lambdacontrols.tooltip.front_block_placing"), true);
|
||||
this.flyDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting", this.mod.config::hasFlyDrifting,
|
||||
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.mod.config::setFlyVerticalDrifting, new TranslatableText("lambdacontrols.tooltip.fly_drifting_vertical"), true);
|
||||
// Controller options
|
||||
this.controllerOption = new SpruceCyclingOption("lambdacontrols.menu.controller", amount -> {
|
||||
int id = this.mod.config.getController().getId();
|
||||
id += amount;
|
||||
if (id > GLFW.GLFW_JOYSTICK_LAST)
|
||||
id = GLFW.GLFW_JOYSTICK_1;
|
||||
this.mod.config.setController(Controller.byId(id));
|
||||
}, option -> {
|
||||
String controllerName = this.mod.config.getController().getName();
|
||||
if (!this.mod.config.getController().isConnected())
|
||||
return option.getDisplayPrefix() + Formatting.RED + controllerName;
|
||||
else if (!this.mod.config.getController().isGamepad())
|
||||
return option.getDisplayPrefix() + Formatting.GOLD + controllerName;
|
||||
else
|
||||
return option.getDisplayPrefix() + controllerName;
|
||||
}, null);
|
||||
this.secondControllerOption = new SpruceCyclingOption("lambdacontrols.menu.controller2",
|
||||
amount -> {
|
||||
int id = this.mod.config.getSecondController().map(Controller::getId).orElse(-1);
|
||||
id += amount;
|
||||
if (id > GLFW.GLFW_JOYSTICK_LAST)
|
||||
id = -1;
|
||||
this.mod.config.setSecondController(id == -1 ? null : Controller.byId(id));
|
||||
}, option -> this.mod.config.getSecondController().map(controller -> {
|
||||
String controllerName = controller.getName();
|
||||
if (!controller.isConnected())
|
||||
return option.getDisplayPrefix() + Formatting.RED + controllerName;
|
||||
else if (!controller.isGamepad())
|
||||
return option.getDisplayPrefix() + Formatting.GOLD + controllerName;
|
||||
else
|
||||
return option.getDisplayPrefix() + controllerName;
|
||||
}).orElse(option.getDisplayPrefix() + Formatting.RED + I18n.translate("options.off")),
|
||||
new TranslatableText("lambdacontrols.tooltip.controller2"));
|
||||
this.controllerTypeOption = new SpruceCyclingOption("lambdacontrols.menu.controller_type",
|
||||
amount -> this.mod.config.setControllerType(this.mod.config.getControllerType().next()),
|
||||
option -> option.getDisplayPrefix() + this.mod.config.getControllerType().getTranslatedName(),
|
||||
new TranslatableText("lambdacontrols.tooltip.controller_type"));
|
||||
this.deadZoneOption = new SpruceDoubleOption("lambdacontrols.menu.dead_zone", 0.05, 1.0, 0.05F, this.mod.config::getDeadZone,
|
||||
newValue -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.setDeadZone(newValue);
|
||||
}
|
||||
}, option -> {
|
||||
String value = String.valueOf(option.get());
|
||||
return option.getDisplayPrefix() + value.substring(0, Math.min(value.length(), 5));
|
||||
}, new TranslatableText("lambdacontrols.tooltip.dead_zone"));
|
||||
this.invertsRightXAxis = new SpruceBooleanOption("lambdacontrols.menu.invert_right_x_axis", this.mod.config::doesInvertRightXAxis,
|
||||
newValue -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.setInvertRightXAxis(newValue);
|
||||
}
|
||||
}, null, true);
|
||||
this.invertsRightYAxis = new SpruceBooleanOption("lambdacontrols.menu.invert_right_y_axis", this.mod.config::doesInvertRightYAxis,
|
||||
newValue -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.setInvertRightYAxis(newValue);
|
||||
}
|
||||
}, null, true);
|
||||
this.unfocusedInputOption = new SpruceBooleanOption("lambdacontrols.menu.unfocused_input", this.mod.config::hasUnfocusedInput,
|
||||
this.mod.config::setUnfocusedInput, new TranslatableText("lambdacontrols.tooltip.unfocused_input"), true);
|
||||
// HUD options
|
||||
this.hudEnableOption = new SpruceBooleanOption("lambdacontrols.menu.hud_enable", this.mod.config::isHudEnabled,
|
||||
this.mod::setHudEnabled, new TranslatableText("lambdacontrols.tooltip.hud_enable"), true);
|
||||
this.hudSideOption = new SpruceCyclingOption("lambdacontrols.menu.hud_side",
|
||||
amount -> this.mod.config.setHudSide(this.mod.config.getHudSide().next()),
|
||||
option -> option.getDisplayPrefix() + this.mod.config.getHudSide().getTranslatedName(),
|
||||
new TranslatableText("lambdacontrols.tooltip.hud_side"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed()
|
||||
{
|
||||
this.mod.config.save();
|
||||
super.removed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
this.mod.config.save();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
private int getTextHeight()
|
||||
{
|
||||
return (5 + this.font.fontHeight) * 3 + 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init();
|
||||
int buttonHeight = 20;
|
||||
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()),
|
||||
btn -> {
|
||||
ControlsMode next = this.mod.config.getControlsMode().next();
|
||||
btn.setMessage(I18n.translate("lambdacontrols.menu.controls_mode") + ": " + I18n.translate(next.getTranslationKey()));
|
||||
this.mod.config.setControlsMode(next);
|
||||
this.mod.config.save();
|
||||
|
||||
if (this.minecraft.player != null) {
|
||||
ClientSidePacketRegistry.INSTANCE.sendToServer(LambdaControls.CONTROLS_MODE_CHANNEL, this.mod.makeControlsModeBuffer(next));
|
||||
}
|
||||
});
|
||||
controlsModeBtn.setTooltip(new TranslatableText("lambdacontrols.tooltip.controls_mode"));
|
||||
this.addButton(controlsModeBtn);
|
||||
if (!this.hideControls)
|
||||
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, 18, 150, buttonHeight, I18n.translate("options.controls"),
|
||||
btn -> {
|
||||
if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER)
|
||||
this.minecraft.openScreen(new ControllerControlsScreen(this, true));
|
||||
else
|
||||
this.minecraft.openScreen(new ControlsOptionsScreen(this, this.minecraft.options));
|
||||
}));
|
||||
|
||||
this.list = new ButtonListWidget(this.minecraft, this.width, this.height, 43, this.height - 29 - this.getTextHeight(), 25);
|
||||
// General options
|
||||
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.general", true, null));
|
||||
this.list.addOptionEntry(this.rotationSpeedOption, this.mouseSpeedOption);
|
||||
this.list.addSingleOptionEntry(this.autoSwitchModeOption);
|
||||
// Gameplay options
|
||||
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.gameplay", true, null));
|
||||
this.list.addSingleOptionEntry(this.frontBlockPlacingOption);
|
||||
this.list.addSingleOptionEntry(this.flyDriftingOption);
|
||||
this.list.addSingleOptionEntry(this.flyVerticalDriftingOption);
|
||||
// Controller options
|
||||
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.controller", true, null));
|
||||
this.list.addSingleOptionEntry(this.controllerOption);
|
||||
this.list.addSingleOptionEntry(this.secondControllerOption);
|
||||
this.list.addOptionEntry(this.controllerTypeOption, this.deadZoneOption);
|
||||
this.list.addOptionEntry(this.invertsRightXAxis, this.invertsRightYAxis);
|
||||
this.list.addSingleOptionEntry(this.unfocusedInputOption);
|
||||
this.list.addSingleOptionEntry(new ReloadControllerMappingsOption());
|
||||
// HUD options
|
||||
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.hud", true, null));
|
||||
this.list.addOptionEntry(this.hudEnableOption, this.hudSideOption);
|
||||
this.children.add(this.list);
|
||||
|
||||
this.gamepadToolUrlLabel = new SpruceLabelWidget(this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 2, this.controllerMappingsUrlText, this.width,
|
||||
label -> Util.getOperatingSystem().open(GAMEPAD_TOOL_URL), true);
|
||||
this.gamepadToolUrlLabel.setTooltip(new TranslatableText("chat.link.open"));
|
||||
this.children.add(this.gamepadToolUrlLabel);
|
||||
|
||||
this.addButton(this.resetOption.createButton(this.minecraft.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"),
|
||||
(buttonWidget) -> this.minecraft.openScreen(this.parent)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouseX, int mouseY, float delta)
|
||||
{
|
||||
this.renderBackground();
|
||||
this.list.render(mouseX, mouseY, delta);
|
||||
super.render(mouseX, mouseY, delta);
|
||||
this.drawCenteredString(this.font, 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);
|
||||
this.gamepadToolUrlLabel.render(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);
|
||||
|
||||
Tooltip.renderAll();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,12 +7,12 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.gui;
|
||||
package me.lambdaurora.lambdacontrols.client.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.Controller;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.Controller;
|
||||
import me.lambdaurora.spruceui.SpruceButtonWidget;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.options.GameOptions;
|
||||
import net.minecraft.client.options.Option;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
@@ -36,17 +36,19 @@ public class ReloadControllerMappingsOption extends Option implements Nameable
|
||||
@Override
|
||||
public AbstractButtonWidget createButton(GameOptions options, int x, int y, int width)
|
||||
{
|
||||
return new ButtonWidget(x, y, width, 20, this.get_name(), btn -> {
|
||||
SpruceButtonWidget button = new SpruceButtonWidget(x, y, width, 20, this.getName(), btn -> {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
Controller.update_mappings();
|
||||
Controller.updateMappings();
|
||||
if (client.currentScreen != null)
|
||||
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));
|
||||
});
|
||||
button.setTooltip(new TranslatableText("lambdacontrols.tooltip.reload_controller_mappings"));
|
||||
return button;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String get_name()
|
||||
public @NotNull String getName()
|
||||
{
|
||||
return I18n.translate(KEY);
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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.HudSide;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
|
||||
import me.lambdaurora.spruceui.SpruceTexturedButtonWidget;
|
||||
import net.minecraft.client.gui.screen.ChatScreen;
|
||||
import net.minecraft.client.gui.screen.GameMenuScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.gui.widget.TexturedButtonWidget;
|
||||
import net.minecraft.server.network.packet.PlayerActionC2SPacket;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Arm;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
|
||||
|
||||
/**
|
||||
* Represents the touchscreen overlay
|
||||
*/
|
||||
public class TouchscreenOverlay extends Screen
|
||||
{
|
||||
public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png");
|
||||
private LambdaControlsClient mod;
|
||||
private SpruceTexturedButtonWidget jumpButton;
|
||||
private SpruceTexturedButtonWidget flyButton;
|
||||
private SpruceTexturedButtonWidget flyUpButton;
|
||||
private SpruceTexturedButtonWidget flyDownButton;
|
||||
private int flyButtonEnableTicks = 0;
|
||||
private int forwardButtonTick = 0;
|
||||
private SpruceTexturedButtonWidget forwardLeftButton;
|
||||
private SpruceTexturedButtonWidget forwardRightButton;
|
||||
private SpruceTexturedButtonWidget startSneakButton;
|
||||
private SpruceTexturedButtonWidget endSneakButton;
|
||||
|
||||
public TouchscreenOverlay(@NotNull LambdaControlsClient mod)
|
||||
{
|
||||
super(new LiteralText("Touchscreen overlay"));
|
||||
this.mod = mod;
|
||||
this.passEvents = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPauseScreen()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private void pauseGame(boolean bl)
|
||||
{
|
||||
if (this.minecraft == null)
|
||||
return;
|
||||
boolean bl2 = this.minecraft.isIntegratedServerRunning() && !this.minecraft.getServer().isRemote();
|
||||
if (bl2) {
|
||||
this.minecraft.openScreen(new GameMenuScreen(!bl));
|
||||
this.minecraft.getSoundManager().pauseAll();
|
||||
} else {
|
||||
this.minecraft.openScreen(new GameMenuScreen(true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the forward button ticks cooldown.
|
||||
*
|
||||
* @param state The button state.
|
||||
*/
|
||||
private void updateForwardButtonsState(boolean state)
|
||||
{
|
||||
if (state)
|
||||
this.forwardButtonTick = -1;
|
||||
else
|
||||
this.forwardButtonTick = 20;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the jump buttons.
|
||||
*/
|
||||
private void updateJumpButtons()
|
||||
{
|
||||
if (this.minecraft == null)
|
||||
return;
|
||||
if (this.minecraft.player.abilities.allowFlying && this.minecraft.player.abilities.flying) {
|
||||
boolean oldStateFly = this.flyButton.visible;
|
||||
this.jumpButton.visible = false;
|
||||
this.flyButton.visible = true;
|
||||
this.flyUpButton.visible = true;
|
||||
this.flyDownButton.visible = true;
|
||||
if (oldStateFly != this.flyButton.visible) {
|
||||
this.flyButtonEnableTicks = 5;
|
||||
this.handleJump(null, false);
|
||||
} else if (this.flyButtonEnableTicks > 0)
|
||||
this.flyButtonEnableTicks--;
|
||||
} else {
|
||||
this.jumpButton.visible = true;
|
||||
this.flyButton.visible = false;
|
||||
this.flyUpButton.visible = false;
|
||||
this.flyDownButton.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the jump button.
|
||||
*
|
||||
* @param btn The pressed button.
|
||||
* @param state The state of the jump button.
|
||||
*/
|
||||
private void handleJump(ButtonWidget btn, boolean state)
|
||||
{
|
||||
((KeyBindingAccessor) this.minecraft.options.keyJump).lambdacontrols_handlePressState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick()
|
||||
{
|
||||
if (this.forwardButtonTick > 0) {
|
||||
this.forwardButtonTick--;
|
||||
} else if (this.forwardButtonTick == 0) {
|
||||
if (this.forwardLeftButton.visible)
|
||||
this.forwardLeftButton.visible = false;
|
||||
if (this.forwardRightButton.visible)
|
||||
this.forwardRightButton.visible = false;
|
||||
}
|
||||
this.updateJumpButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init();
|
||||
int scaledWidth = this.minecraft.getWindow().getScaledWidth();
|
||||
int scaledHeight = this.minecraft.getWindow().getScaledHeight();
|
||||
this.addButton(new TexturedButtonWidget(scaledWidth / 2 - 20, 0, 20, 20, 0, 106, 20, ButtonWidget.WIDGETS_LOCATION, 256, 256,
|
||||
btn -> this.minecraft.openScreen(new ChatScreen("")), ""));
|
||||
this.addButton(new TexturedButtonWidget(scaledWidth / 2, 0, 20, 20, 0, 0, 20, WIDGETS_LOCATION, 256, 256,
|
||||
btn -> this.pauseGame(false)));
|
||||
// Inventory buttons.
|
||||
int inventoryButtonX = scaledWidth / 2;
|
||||
int inventoryButtonY = scaledHeight - 16 - 5;
|
||||
if (this.minecraft.options.mainArm == Arm.LEFT) {
|
||||
inventoryButtonX = inventoryButtonX - 91 - 24;
|
||||
} else {
|
||||
inventoryButtonX = inventoryButtonX + 91 + 4;
|
||||
}
|
||||
this.addButton(new TexturedButtonWidget(inventoryButtonX, inventoryButtonY, 20, 20, 20, 0, 20, WIDGETS_LOCATION, 256, 256,
|
||||
btn -> {
|
||||
if (this.minecraft.interactionManager.hasRidingInventory()) {
|
||||
this.minecraft.player.openRidingInventory();
|
||||
} else {
|
||||
this.minecraft.getTutorialManager().onInventoryOpened();
|
||||
this.minecraft.openScreen(new InventoryScreen(this.minecraft.player));
|
||||
}
|
||||
}));
|
||||
int jumpButtonX, swapHandsX, sneakButtonX;
|
||||
int sneakButtonY = scaledHeight - 10 - 40 - 5;
|
||||
if (this.mod.config.getHudSide() == HudSide.LEFT) {
|
||||
jumpButtonX = scaledWidth - 20 - 20;
|
||||
swapHandsX = jumpButtonX - 5 - 40;
|
||||
sneakButtonX = 10 + 20 + 5;
|
||||
} else {
|
||||
jumpButtonX = 20;
|
||||
swapHandsX = jumpButtonX + 5 + 40;
|
||||
sneakButtonX = scaledWidth - 10 - 40 - 5;
|
||||
}
|
||||
// Swap items hand.
|
||||
this.addButton(new SpruceTexturedButtonWidget(swapHandsX, sneakButtonY, 20, 20, 0, 160, 20, WIDGETS_LOCATION,
|
||||
(btn, state) -> {
|
||||
if (state) {
|
||||
if (!this.minecraft.player.isSpectator()) {
|
||||
this.minecraft.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_HELD_ITEMS, BlockPos.ORIGIN, Direction.DOWN));
|
||||
}
|
||||
}
|
||||
}));
|
||||
// Drop
|
||||
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)));
|
||||
// Jump keys
|
||||
this.addButton(this.jumpButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY, 20, 20, 0, 40, 20, WIDGETS_LOCATION,
|
||||
this::handleJump));
|
||||
this.addButton(this.flyButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY, 20, 20, 20, 40, 20, WIDGETS_LOCATION,
|
||||
(btn, state) -> {
|
||||
if (this.flyButtonEnableTicks == 0) this.minecraft.player.abilities.flying = false;
|
||||
}));
|
||||
this.addButton(this.flyUpButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY - 5 - 20, 20, 20, 40, 40, 20, WIDGETS_LOCATION,
|
||||
this::handleJump));
|
||||
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)));
|
||||
this.updateJumpButtons();
|
||||
// Movements keys
|
||||
this.addButton((this.startSneakButton = new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY, 20, 20, 0, 120, 20, WIDGETS_LOCATION,
|
||||
(btn, state) -> {
|
||||
if (state) {
|
||||
((KeyBindingAccessor) this.minecraft.options.keySneak).lambdacontrols_handlePressState(true);
|
||||
this.startSneakButton.visible = false;
|
||||
this.endSneakButton.visible = true;
|
||||
}
|
||||
})));
|
||||
this.addButton((this.endSneakButton = new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY, 20, 20, 20, 120, 20, WIDGETS_LOCATION,
|
||||
(btn, state) -> {
|
||||
if (state) {
|
||||
((KeyBindingAccessor) this.minecraft.options.keySneak).lambdacontrols_handlePressState(false);
|
||||
this.endSneakButton.visible = false;
|
||||
this.startSneakButton.visible = true;
|
||||
}
|
||||
})));
|
||||
this.endSneakButton.visible = false;
|
||||
this.addButton(this.forwardLeftButton = new SpruceTexturedButtonWidget(sneakButtonX - 20 - 5, sneakButtonY - 5 - 20, 20, 20, 80, 80, 20, WIDGETS_LOCATION,
|
||||
(btn, state) -> {
|
||||
((KeyBindingAccessor) this.minecraft.options.keyForward).lambdacontrols_handlePressState(state);
|
||||
((KeyBindingAccessor) this.minecraft.options.keyLeft).lambdacontrols_handlePressState(state);
|
||||
this.updateForwardButtonsState(state);
|
||||
}));
|
||||
this.forwardLeftButton.visible = false;
|
||||
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION,
|
||||
(btn, state) -> {
|
||||
((KeyBindingAccessor) this.minecraft.options.keyForward).lambdacontrols_handlePressState(state);
|
||||
this.updateForwardButtonsState(state);
|
||||
this.forwardLeftButton.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,
|
||||
(btn, state) -> {
|
||||
((KeyBindingAccessor) this.minecraft.options.keyForward).lambdacontrols_handlePressState(state);
|
||||
((KeyBindingAccessor) this.minecraft.options.keyRight).lambdacontrols_handlePressState(state);
|
||||
this.updateForwardButtonsState(state);
|
||||
}));
|
||||
this.forwardRightButton.visible = true;
|
||||
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)));
|
||||
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)));
|
||||
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)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouseX, int mouseY, float delta)
|
||||
{
|
||||
super.render(mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button)
|
||||
{
|
||||
if (mouseY >= (double) (this.height - 22) && this.minecraft != null && this.minecraft.player != null) {
|
||||
int centerX = this.width / 2;
|
||||
if (mouseX >= (double) (centerX - 90) && mouseX <= (double) (centerX + 90)) {
|
||||
for (int slot = 0; slot < 9; ++slot) {
|
||||
int slotX = centerX - 90 + slot * 20 + 2;
|
||||
if (mouseX >= (double) slotX && mouseX <= (double) (slotX + 20)) {
|
||||
this.minecraft.player.inventory.selectedSlot = slot;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY)
|
||||
{
|
||||
if (button == GLFW.GLFW_MOUSE_BUTTON_1 && this.minecraft != null) {
|
||||
if (deltaY > 0.01)
|
||||
this.mod.input.handleLook(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 2);
|
||||
else if (deltaY < 0.01)
|
||||
this.mod.input.handleLook(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 1);
|
||||
|
||||
if (deltaX > 0.01)
|
||||
this.mod.input.handleLook(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 2);
|
||||
else if (deltaX < 0.01)
|
||||
this.mod.input.handleLook(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 1);
|
||||
}
|
||||
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,7 +7,7 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.mixin;
|
||||
package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -17,5 +17,5 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
public interface AbstractButtonWidgetAccessor
|
||||
{
|
||||
@Accessor("height")
|
||||
int get_height();
|
||||
int lambdacontrols_getHeight();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.mixin;
|
||||
|
||||
import net.minecraft.advancement.Advancement;
|
||||
import net.minecraft.client.gui.screen.advancement.AdvancementTab;
|
||||
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
|
||||
import net.minecraft.client.network.ClientAdvancementManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents an accessor of {@link AdvancementsScreen}.
|
||||
*/
|
||||
@Mixin(AdvancementsScreen.class)
|
||||
public interface AdvancementsScreenAccessor
|
||||
{
|
||||
@Accessor("advancementHandler")
|
||||
ClientAdvancementManager lambdacontrols_getAdvancementManager();
|
||||
|
||||
@Accessor("tabs")
|
||||
Map<Advancement, AdvancementTab> lambdacontrols_getTabs();
|
||||
|
||||
@Accessor("selectedTab")
|
||||
AdvancementTab lambdacontrols_getSelectedTab();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.packet.GameJoinS2CPacket;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ClientPlayNetworkHandler.class)
|
||||
public class ClientPlayNetworkHandlerMixin
|
||||
{
|
||||
@Inject(method = "onGameJoin", at = @At(value = "TAIL"))
|
||||
private void lambdacontrols_onConnect(GameJoinS2CPacket packet, CallbackInfo ci)
|
||||
{
|
||||
ClientSidePacketRegistry.INSTANCE.sendToServer(LambdaControls.HELLO_CHANNEL, LambdaControls.get().makeHello(LambdaControlsClient.get().config.getControlsMode()));
|
||||
ClientSidePacketRegistry.INSTANCE.sendToServer(LambdaControls.CONTROLS_MODE_CHANNEL,
|
||||
LambdaControls.get().makeControlsModeBuffer(LambdaControlsClient.get().config.getControlsMode()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.mixin;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.input.Input;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.MovementType;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Injects the anti fly drifting feature.
|
||||
*/
|
||||
@Mixin(ClientPlayerEntity.class)
|
||||
public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity
|
||||
{
|
||||
private boolean lambdacontrols_driftingPrevented = false;
|
||||
|
||||
@Shadow
|
||||
protected abstract boolean hasMovementInput();
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
protected MinecraftClient client;
|
||||
|
||||
@Shadow
|
||||
public Input input;
|
||||
|
||||
@Shadow
|
||||
protected abstract boolean isCamera();
|
||||
|
||||
public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile)
|
||||
{
|
||||
super(world, profile);
|
||||
}
|
||||
|
||||
@Inject(method = "move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V"))
|
||||
public void lambdacontrols_move(MovementType type, Vec3d movement, CallbackInfo ci)
|
||||
{
|
||||
LambdaControlsClient mod = LambdaControlsClient.get();
|
||||
if (type == MovementType.SELF) {
|
||||
if (this.abilities.flying && (!mod.config.hasFlyDrifting() || !mod.config.hasFlyVerticalDrifting())) {
|
||||
if (!this.hasMovementInput()) {
|
||||
if (!this.lambdacontrols_driftingPrevented) {
|
||||
if (!mod.config.hasFlyDrifting())
|
||||
this.setVelocity(this.getVelocity().multiply(0, 1.0, 0));
|
||||
}
|
||||
this.lambdacontrols_driftingPrevented = true;
|
||||
} else
|
||||
this.lambdacontrols_driftingPrevented = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isCamera()Z"))
|
||||
public void lambdacontrols_tickMovement(CallbackInfo ci)
|
||||
{
|
||||
if (this.abilities.flying && this.isCamera()) {
|
||||
if (LambdaControlsClient.get().config.hasFlyVerticalDrifting())
|
||||
return;
|
||||
int moving = 0;
|
||||
if (this.input.sneaking) {
|
||||
--moving;
|
||||
}
|
||||
|
||||
if (this.input.jumping) {
|
||||
++moving;
|
||||
}
|
||||
|
||||
if (moving == 0) {
|
||||
this.setVelocity(this.getVelocity().multiply(1.0, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.ingame.ContainerScreen;
|
||||
import net.minecraft.container.Slot;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Represents the mixin for the class ContainerScreen.
|
||||
*/
|
||||
@Mixin(ContainerScreen.class)
|
||||
public abstract class ContainerScreenMixin implements ContainerScreenAccessor
|
||||
{
|
||||
protected int x;
|
||||
protected int y;
|
||||
|
||||
@Override
|
||||
public int lambdacontrols_getX()
|
||||
{
|
||||
return this.x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lambdacontrols_getY()
|
||||
{
|
||||
return this.y;
|
||||
}
|
||||
|
||||
@Invoker("getSlotAt")
|
||||
public abstract Slot lambdacontrols_getSlotAt(double posX, double posY);
|
||||
|
||||
@Inject(method = "render", at = @At("RETURN"))
|
||||
public void render(int mouseX, int mouseY, float delta, CallbackInfo ci)
|
||||
{
|
||||
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
int x = 10, y = client.getWindow().getScaledHeight() - 10 - 15;
|
||||
|
||||
x += LambdaControlsClient.drawButtonTip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, "lambdacontrols.action.pickup_all", true, client) + 10;
|
||||
x += LambdaControlsClient.drawButtonTip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_B}, "lambdacontrols.action.exit", true, client) + 10;
|
||||
x += LambdaControlsClient.drawButtonTip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_X}, "lambdacontrols.action.pickup", true, client) + 10;
|
||||
LambdaControlsClient.drawButtonTip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_Y}, "lambdacontrols.action.quick_move", true, client);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen;
|
||||
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
|
||||
import net.minecraft.client.gui.screen.options.GameOptionsScreen;
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.options.GameOptions;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
/**
|
||||
* Injects the new controls settings button.
|
||||
*/
|
||||
@Mixin(ControlsOptionsScreen.class)
|
||||
public class ControlsOptionsScreenMixin extends GameOptionsScreen
|
||||
{
|
||||
public ControlsOptionsScreenMixin(Screen parent, GameOptions gameOptions, Text text)
|
||||
{
|
||||
super(parent, gameOptions, text);
|
||||
}
|
||||
|
||||
@Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/options/ControlsOptionsScreen;addButton(Lnet/minecraft/client/gui/widget/AbstractButtonWidget;)Lnet/minecraft/client/gui/widget/AbstractButtonWidget;", ordinal = 1))
|
||||
private AbstractButtonWidget on_init(ControlsOptionsScreen screen, AbstractButtonWidget btn)
|
||||
{
|
||||
if (this.parent instanceof ControllerControlsScreen)
|
||||
return this.addButton(btn);
|
||||
else
|
||||
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).lambdacontrols_getHeight(), I18n.translate("menu.options"),
|
||||
b -> this.minecraft.openScreen(new LambdaControlsSettingsScreen(this, this.gameOptions, true))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.mixin;
|
||||
|
||||
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
||||
import net.minecraft.container.Slot;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
/**
|
||||
* Represents an accessor to CreativeInventoryScreen.
|
||||
*/
|
||||
@Mixin(CreativeInventoryScreen.class)
|
||||
public interface CreativeInventoryScreenAccessor
|
||||
{
|
||||
/**
|
||||
* Gets the selected tab.
|
||||
*
|
||||
* @return The selected tab index.
|
||||
*/
|
||||
@Accessor("selectedTab")
|
||||
int lambdacontrols_getSelectedTab();
|
||||
|
||||
/**
|
||||
* Sets the selected tab.
|
||||
*
|
||||
* @param group The tab's item group.
|
||||
*/
|
||||
@Invoker("setSelectedTab")
|
||||
void lambdacontrols_setSelectedTab(@NotNull ItemGroup group);
|
||||
|
||||
/**
|
||||
* Returns whether the slot belongs to the creative inventory or not.
|
||||
*
|
||||
* @param slot The slot to check.
|
||||
* @return True if the slot is from the creative inventory, else false.
|
||||
*/
|
||||
@Invoker("isCreativeInventorySlot")
|
||||
boolean lambdacontrols_isCreativeInventorySlot(@Nullable Slot slot);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,7 +7,7 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.mixin;
|
||||
package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import net.minecraft.client.gui.widget.EntryListWidget;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -17,5 +17,5 @@ import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
public interface EntryListWidgetAccessor
|
||||
{
|
||||
@Invoker("moveSelection")
|
||||
void move_selection(int amount);
|
||||
void lambdacontrols_moveSelection(int amount);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,10 +7,10 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.mixin;
|
||||
package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -28,9 +28,9 @@ public class GameRendererMixin
|
||||
private MinecraftClient client;
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Mouse;getX()D"))
|
||||
private void on_render(float tick_delta, long start_time, boolean full_render, CallbackInfo ci)
|
||||
private void onRender(float tickDelta, long startTime, boolean fullRender, CallbackInfo ci)
|
||||
{
|
||||
if (this.client.currentScreen != null && LambdaControls.get().config.get_controls_mode() == ControlsMode.CONTROLLER)
|
||||
LambdaControls.get().input.on_pre_render_screen(this.client, this.client.currentScreen);
|
||||
if (this.client.currentScreen != null && LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER)
|
||||
LambdaControlsClient.get().input.onPreRenderScreen(this.client, this.client.currentScreen);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,12 +7,11 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.mixin;
|
||||
package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
|
||||
import net.minecraft.client.options.KeyBinding;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@@ -28,20 +27,14 @@ public class KeyBindingMixin implements KeyBindingAccessor
|
||||
@Shadow
|
||||
private boolean pressed;
|
||||
|
||||
@Override
|
||||
public @NotNull InputUtil.KeyCode get_key_code()
|
||||
{
|
||||
return this.keyCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lambdacontrols_press()
|
||||
{
|
||||
boolean old_pressed = this.pressed;
|
||||
boolean oldPressed = this.pressed;
|
||||
if (!this.pressed)
|
||||
this.pressed = true;
|
||||
++this.timesPressed;
|
||||
return old_pressed != this.pressed;
|
||||
return oldPressed != this.pressed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.FluidBlock;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.network.ClientPlayerInteractionManager;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
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 org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public abstract class MinecraftClientMixin
|
||||
{
|
||||
@Shadow
|
||||
@Nullable
|
||||
public HitResult crosshairTarget;
|
||||
|
||||
@Shadow
|
||||
@Nullable
|
||||
public ClientPlayerEntity player;
|
||||
|
||||
@Shadow
|
||||
@Nullable
|
||||
public ClientPlayerInteractionManager interactionManager;
|
||||
|
||||
@Shadow
|
||||
@Nullable
|
||||
public ClientWorld world;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
public GameRenderer gameRenderer;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void lambdacontrols_onInit(CallbackInfo ci)
|
||||
{
|
||||
LambdaControlsClient.get().onMcInit((MinecraftClient) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At("HEAD"))
|
||||
private void lambdacontrols_onRender(boolean fullRender, CallbackInfo ci)
|
||||
{
|
||||
LambdaControlsClient.get().onRender((MinecraftClient) (Object) (this));
|
||||
}
|
||||
|
||||
@Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At("RETURN"))
|
||||
private void lambdacontrols_onLeave(@Nullable Screen screen, CallbackInfo ci)
|
||||
{
|
||||
LambdaControlsClient.get().onLeave();
|
||||
}
|
||||
|
||||
@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 lambdacontrols_onItemUse(CallbackInfo ci, Hand[] hands, int handCount, int handIndex, Hand hand, ItemStack stackInHand)
|
||||
{
|
||||
if (!stackInHand.isEmpty() && this.player.pitch > 35.0F && LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable()) {
|
||||
if (this.crosshairTarget != null && this.crosshairTarget.getType() == HitResult.Type.MISS && this.player.onGround) {
|
||||
if (!stackInHand.isEmpty() && stackInHand.getItem() instanceof BlockItem) {
|
||||
BlockPos playerPos = this.player.getBlockPos().down();
|
||||
BlockPos targetPos = new BlockPos(this.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 = player.getHorizontalFacing();
|
||||
|
||||
BlockState adjacentBlockState = this.world.getBlockState(blockPos.offset(direction.getOpposite()));
|
||||
if (adjacentBlockState.isAir() || adjacentBlockState.getBlock() instanceof FluidBlock || (vector.getX() == 0 && vector.getZ() == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockHitResult hitResult = new BlockHitResult(this.crosshairTarget.getPos(), direction.getOpposite(), blockPos, false);
|
||||
|
||||
int previousStackCount = stackInHand.getCount();
|
||||
ActionResult result = this.interactionManager.interactBlock(this.player, this.world, hand, hitResult);
|
||||
if (result.isAccepted()) {
|
||||
if (result.shouldSwingHand()) {
|
||||
this.player.swingHand(hand);
|
||||
if (!stackInHand.isEmpty() && (stackInHand.getCount() != previousStackCount || this.interactionManager.hasCreativeInventory())) {
|
||||
this.gameRenderer.firstPersonRenderer.resetEquipProgress(hand);
|
||||
}
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
if (result == ActionResult.FAIL) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,11 +7,11 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.mixin;
|
||||
package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.util.MouseAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.util.MouseAccessor;
|
||||
import net.minecraft.client.Mouse;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -32,20 +32,14 @@ public abstract class MouseMixin implements MouseAccessor
|
||||
protected abstract void onMouseButton(long window, int button, int action, int mods);
|
||||
|
||||
@Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true)
|
||||
private void on_mouse_locked(CallbackInfo ci)
|
||||
private void lambdacontrols_onMouseLocked(CallbackInfo ci)
|
||||
{
|
||||
if (LambdaControls.get().config.get_controls_mode() == ControlsMode.TOUCHSCREEN)
|
||||
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.TOUCHSCREEN)
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void on_mouse_button(long window, int button, int action, int mods)
|
||||
{
|
||||
this.onMouseButton(window, button, action, mods);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void on_cursor_pos(long window, double x, double y)
|
||||
public void lambdacontrols_onCursorPos(long window, double x, double y)
|
||||
{
|
||||
this.onCursorPos(window, x, y);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,18 +7,17 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.mixin;
|
||||
package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.gui.LambdaControlsSettingsScreen;
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.SettingsScreen;
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.options.GameOptions;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@@ -28,19 +27,19 @@ import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
@Mixin(SettingsScreen.class)
|
||||
public class SettingsScreenMixin extends Screen
|
||||
{
|
||||
@Final
|
||||
@Shadow
|
||||
private GameOptions settings;
|
||||
|
||||
protected SettingsScreenMixin(Text 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))
|
||||
private AbstractButtonWidget on_init(SettingsScreen screen, AbstractButtonWidget btn)
|
||||
private AbstractButtonWidget lambdacontrols_onInit(SettingsScreen screen, AbstractButtonWidget btn)
|
||||
{
|
||||
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).get_height(), btn.getMessage(),
|
||||
b -> this.minecraft.openScreen(new LambdaControlsSettingsScreen(this, this.settings))));
|
||||
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
|
||||
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).lambdacontrols_getHeight(), btn.getMessage(),
|
||||
b -> this.minecraft.openScreen(new ControllerControlsScreen(this, false))));
|
||||
} else {
|
||||
return this.addButton(btn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,28 +7,28 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.util;
|
||||
package me.lambdaurora.lambdacontrols.client.util;
|
||||
|
||||
import net.minecraft.container.Slot;
|
||||
|
||||
/**
|
||||
* Represents an accessor to AbstractContainerScreen.
|
||||
*/
|
||||
public interface AbstractContainerScreenAccessor
|
||||
public interface ContainerScreenAccessor
|
||||
{
|
||||
/**
|
||||
* Gets the left coordinate of the GUI.
|
||||
*
|
||||
* @return The left coordinate of the GUI.
|
||||
*/
|
||||
int get_x();
|
||||
int lambdacontrols_getX();
|
||||
|
||||
/**
|
||||
* Gets the top coordinate of the GUI.
|
||||
*
|
||||
* @return The top coordinate of the GUI.
|
||||
*/
|
||||
int get_y();
|
||||
int lambdacontrols_getY();
|
||||
|
||||
/**
|
||||
* Gets the slot at position.
|
||||
@@ -37,5 +37,5 @@ public interface AbstractContainerScreenAccessor
|
||||
* @param pos_y The Y position to check.
|
||||
* @return The slot at the specified position.
|
||||
*/
|
||||
Slot get_slot_at(double pos_x, double pos_y);
|
||||
Slot lambdacontrols_getSlotAt(double pos_x, double pos_y);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
|
||||
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
|
||||
*
|
||||
* This file is part of LambdaControls.
|
||||
*
|
||||
@@ -7,23 +7,18 @@
|
||||
* see the LICENSE file.
|
||||
*/
|
||||
|
||||
package me.lambdaurora.lambdacontrols.util;
|
||||
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
package me.lambdaurora.lambdacontrols.client.util;
|
||||
|
||||
/**
|
||||
* Represents a Minecraft keybinding with extra access.
|
||||
*/
|
||||
public interface KeyBindingAccessor
|
||||
{
|
||||
@NotNull InputUtil.KeyCode get_key_code();
|
||||
|
||||
boolean lambdacontrols_press();
|
||||
|
||||
boolean lambdacontrols_unpress();
|
||||
|
||||
default boolean handle_press_state(boolean pressed)
|
||||
default boolean lambdacontrols_handlePressState(boolean pressed)
|
||||
{
|
||||
if (pressed)
|
||||
return this.lambdacontrols_press();
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Represents mouse's extra access.
|
||||
*/
|
||||
public interface MouseAccessor
|
||||
{
|
||||
void lambdacontrols_onCursorPos(long window, double x, double y);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.event;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents an event callback which is fired when a player changes the controls mode.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PlayerChangeControlsModeCallback
|
||||
{
|
||||
Event<PlayerChangeControlsModeCallback> EVENT = EventFactory.createArrayBacked(PlayerChangeControlsModeCallback.class, listeners -> (player, controlsMode) -> {
|
||||
for (PlayerChangeControlsModeCallback event : listeners) {
|
||||
event.apply(player, controlsMode);
|
||||
}
|
||||
});
|
||||
|
||||
void apply(@NotNull PlayerEntity player, @NotNull ControlsMode controlsMode);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
@@ -10,6 +10,8 @@
|
||||
"lambdacontrols.action.exit": "Exit",
|
||||
"lambdacontrols.action.forward": "Forward",
|
||||
"lambdacontrols.action.hit": "Hit",
|
||||
"lambdacontrols.action.hotbar_left": "Hotbar left",
|
||||
"lambdacontrols.action.hotbar_right": "Hotbar right",
|
||||
"lambdacontrols.action.inventory": "Inventory",
|
||||
"lambdacontrols.action.jump": "Jump",
|
||||
"lambdacontrols.action.left": "Left",
|
||||
@@ -27,6 +29,7 @@
|
||||
"lambdacontrols.action.toggle_perspective": "Toggle Perspective",
|
||||
"lambdacontrols.action.toggle_smooth_camera": "Toggle Cinematic Camera",
|
||||
"lambdacontrols.action.use": "Use",
|
||||
"lambdacontrols.action.zoom": "Zoom",
|
||||
"lambdacontrols.button.a": "A",
|
||||
"lambdacontrols.button.b": "B",
|
||||
"lambdacontrols.button.x": "X",
|
||||
@@ -70,18 +73,45 @@
|
||||
"lambdacontrols.controls_mode.touchscreen": "Touchscreen",
|
||||
"lambdacontrols.hud_side.left": "left",
|
||||
"lambdacontrols.hud_side.right": "right",
|
||||
"lambdacontrols.menu.auto_switch_mode": "Auto switch mode",
|
||||
"lambdacontrols.menu.auto_switch_mode": "Auto Switch Mode",
|
||||
"lambdacontrols.menu.controller": "Controller",
|
||||
"lambdacontrols.menu.controller_type": "Controller type",
|
||||
"lambdacontrols.menu.controller2": "Second Controller",
|
||||
"lambdacontrols.menu.controller_type": "Controller Type",
|
||||
"lambdacontrols.menu.controls_mode": "Mode",
|
||||
"lambdacontrols.menu.dead_zone": "Dead zone",
|
||||
"lambdacontrols.menu.dead_zone": "Dead Zone",
|
||||
"lambdacontrols.menu.fly_drifting": "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_side": "HUD side",
|
||||
"lambdacontrols.menu.invert_right_x_axis": "Invert right X",
|
||||
"lambdacontrols.menu.invert_right_y_axis": "Invert right Y",
|
||||
"lambdacontrols.menu.mouse_speed": "Mouse speed",
|
||||
"lambdacontrols.menu.reload_controller_mappings": "Reload controller mappings",
|
||||
"lambdacontrols.menu.rotation_speed": "Rotation speed",
|
||||
"lambdacontrols.menu.hud_side": "HUD Side",
|
||||
"lambdacontrols.menu.invert_right_x_axis": "Invert Right X",
|
||||
"lambdacontrols.menu.invert_right_y_axis": "Invert Right Y",
|
||||
"lambdacontrols.menu.keyboard_controls": "Keyboard Controls...",
|
||||
"lambdacontrols.menu.mouse_speed": "Mouse Speed",
|
||||
"lambdacontrols.menu.reload_controller_mappings": "Reload Controller Mappings",
|
||||
"lambdacontrols.menu.rotation_speed": "Rotation Speed",
|
||||
"lambdacontrols.menu.title": "LambdaControls - Settings",
|
||||
"lambdacontrols.menu.title.controller_controls": "Controller controls"
|
||||
"lambdacontrols.menu.title.controller": "Controller Options",
|
||||
"lambdacontrols.menu.title.controller_controls": "Controller Controls",
|
||||
"lambdacontrols.menu.title.gameplay": "Gameplay Options",
|
||||
"lambdacontrols.menu.title.general": "General Options",
|
||||
"lambdacontrols.menu.title.hud": "HUD Options",
|
||||
"lambdacontrols.menu.unbound": "Unbound",
|
||||
"lambdacontrols.menu.unfocused_input": "Unfocused Input",
|
||||
"lambdacontrols.narrator.unbound": "Unbound %s",
|
||||
"lambdacontrols.not_bound": "Not bound",
|
||||
"lambdacontrols.tooltip.auto_switch_mode": "If the controls mode should be switched to Controller automatically if one is connected.",
|
||||
"lambdacontrols.tooltip.controller2": "Second controller to use, which allows Joy-Cons support for example.",
|
||||
"lambdacontrols.tooltip.controller_type": "The controller type to display the correct buttons.",
|
||||
"lambdacontrols.tooltip.controls_mode": "The controls mode.",
|
||||
"lambdacontrols.tooltip.dead_zone": "The dead zone for the controller's analogue sticks.",
|
||||
"lambdacontrols.tooltip.fly_drifting": "While flying, enables drifting/inertia.",
|
||||
"lambdacontrols.tooltip.fly_drifting_vertical": "While flying, enables 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_side": "The position of the HUD.",
|
||||
"lambdacontrols.tooltip.mouse_speed": "The controller's emulated mouse speed.",
|
||||
"lambdacontrols.tooltip.rotation_speed": "The camera rotation speed in controller mode.",
|
||||
"lambdacontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file.",
|
||||
"lambdacontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused."
|
||||
}
|
||||
117
fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"key.lambdacontrols.look_down": "Regarder en bas",
|
||||
"key.lambdacontrols.look_left": "Regarder à gauche",
|
||||
"key.lambdacontrols.look_right": "Regarder à droite",
|
||||
"key.lambdacontrols.look_up": "Regarder en haut",
|
||||
"lambdacontrols.action.attack": "Attaquer",
|
||||
"lambdacontrols.action.back": "Reculer",
|
||||
"lambdacontrols.action.chat": "Ouvrir le tchat",
|
||||
"lambdacontrols.action.drop_item": "Jeter l'objet",
|
||||
"lambdacontrols.action.exit": "Sortir",
|
||||
"lambdacontrols.action.forward": "Avancer",
|
||||
"lambdacontrols.action.hit": "Taper",
|
||||
"lambdacontrols.action.hotbar_left": "Case à gauche de la barre d'action",
|
||||
"lambdacontrols.action.hotbar_right": "Case à droite de la barre d'action",
|
||||
"lambdacontrols.action.inventory": "Inventaire",
|
||||
"lambdacontrols.action.jump": "Sauter",
|
||||
"lambdacontrols.action.left": "Aller à gauche",
|
||||
"lambdacontrols.action.pause_game": "Mettre en pause le jeu",
|
||||
"lambdacontrols.action.pick_block": "Choisir le bloc",
|
||||
"lambdacontrols.action.pickup": "Prendre",
|
||||
"lambdacontrols.action.pickup_all": "Prendre tout",
|
||||
"lambdacontrols.action.player_list": "Afficher la liste des joueurs",
|
||||
"lambdacontrols.action.quick_move": "Mouvement rapide",
|
||||
"lambdacontrols.action.right": "Aller à droite",
|
||||
"lambdacontrols.action.screenshot": "Prendre une capture d'écran",
|
||||
"lambdacontrols.action.sneak": "S'accroupir",
|
||||
"lambdacontrols.action.sprint": "Courir",
|
||||
"lambdacontrols.action.swap_hands": "Échanger de mains",
|
||||
"lambdacontrols.action.toggle_perspective": "Changer de point de vue",
|
||||
"lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique",
|
||||
"lambdacontrols.action.use": "Utiliser",
|
||||
"lambdacontrols.action.zoom": "Zoom",
|
||||
"lambdacontrols.button.a": "A",
|
||||
"lambdacontrols.button.b": "B",
|
||||
"lambdacontrols.button.x": "X",
|
||||
"lambdacontrols.button.y": "Y",
|
||||
"lambdacontrols.button.left_bumper": "Gâchette haute gauche",
|
||||
"lambdacontrols.button.right_bumper": "Gâchette haute droite",
|
||||
"lambdacontrols.button.back": "Retour",
|
||||
"lambdacontrols.button.start": "Touche Menu",
|
||||
"lambdacontrols.button.guide": "Guide",
|
||||
"lambdacontrols.button.left_thumb": "Stick gauche",
|
||||
"lambdacontrols.button.right_thumb": "Stick droit",
|
||||
"lambdacontrols.button.dpad_up": "D-Pad haut",
|
||||
"lambdacontrols.button.dpad_right": "D-Pad droit",
|
||||
"lambdacontrols.button.dpad_down": "D-Pad bas",
|
||||
"lambdacontrols.button.dpad_left": "D-Pad gauche",
|
||||
"lambdacontrols.axis.left_x+": "X+ Gauche",
|
||||
"lambdacontrols.axis.left_y+": "Y+ Gauche",
|
||||
"lambdacontrols.axis.right_x+": "X+ Droit",
|
||||
"lambdacontrols.axis.right_y+": "Y+ Droit",
|
||||
"lambdacontrols.axis.left_trigger": "Gâchette gauche",
|
||||
"lambdacontrols.axis.right_trigger": "Gâchette droite",
|
||||
"lambdacontrols.axis.left_x-": "X- Gauche",
|
||||
"lambdacontrols.axis.left_y-": "Y- Gauche",
|
||||
"lambdacontrols.axis.right_x-": "X- Droit",
|
||||
"lambdacontrols.axis.right_y-": "Y- Droit",
|
||||
"lambdacontrols.button.unknown": "Inconnu (%d)",
|
||||
"lambdacontrols.controller.connected": "Manette %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.2": "(%s%s%s),",
|
||||
"lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.",
|
||||
"lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!",
|
||||
"lambdacontrols.controller_type.default": "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": "Clavier/Souris",
|
||||
"lambdacontrols.controls_mode.controller": "Manette",
|
||||
"lambdacontrols.controls_mode.touchscreen": "Tactile",
|
||||
"lambdacontrols.hud_side.left": "gauche",
|
||||
"lambdacontrols.hud_side.right": "droit",
|
||||
"lambdacontrols.menu.auto_switch_mode": "Changement auto de mode",
|
||||
"lambdacontrols.menu.controller": "Manette",
|
||||
"lambdacontrols.menu.controller2": "Deuxième manette",
|
||||
"lambdacontrols.menu.controller_type": "Type de manette",
|
||||
"lambdacontrols.menu.controls_mode": "Mode",
|
||||
"lambdacontrols.menu.dead_zone": "Zone morte",
|
||||
"lambdacontrols.menu.fly_drifting": "Inertie 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_side": "Côté du HUD",
|
||||
"lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)",
|
||||
"lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)",
|
||||
"lambdacontrols.menu.keyboard_controls": "Contrôles clavier...",
|
||||
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
|
||||
"lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes",
|
||||
"lambdacontrols.menu.rotation_speed": "Vitesse de rotation",
|
||||
"lambdacontrols.menu.title": "LambdaControls - Paramètres",
|
||||
"lambdacontrols.menu.title.controller": "Options de manettes",
|
||||
"lambdacontrols.menu.title.controller_controls": "Contrôles de la manette",
|
||||
"lambdacontrols.menu.title.gameplay": "Options de Gameplay",
|
||||
"lambdacontrols.menu.title.general": "Options générales",
|
||||
"lambdacontrols.menu.title.hud": "Options du HUD",
|
||||
"lambdacontrols.menu.unbound": "Délier",
|
||||
"lambdacontrols.menu.unfocused_input": "Entrée en fond",
|
||||
"lambdacontrols.narrator.unbound": "Délier %s",
|
||||
"lambdacontrols.not_bound": "Non défini",
|
||||
"lambdacontrols.tooltip.auto_switch_mode": "Détermine si le mode de contrôle doit automatiquement changer sur Manette si une manette est connectée et inversement.",
|
||||
"lambdacontrols.tooltip.controller2": "Défini une deuxième manette, utile dans le cas d'utilisation de Joy-Cons.",
|
||||
"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.dead_zone": "Zone morte des axes de la manette.",
|
||||
"lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement.",
|
||||
"lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical.",
|
||||
"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_side": "Change la position du HUD.",
|
||||
"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.reload_controller_mappings": "Recharge le fichier de configuration des manettes.",
|
||||
"lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée."
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
"lambdacontrols.action.exit": "Sortir",
|
||||
"lambdacontrols.action.forward": "Avancer",
|
||||
"lambdacontrols.action.hit": "Taper",
|
||||
"lambdacontrols.action.hotbar_left": "Case à gauche de la barre d'action",
|
||||
"lambdacontrols.action.hotbar_right": "Case à droite de la barre d'action",
|
||||
"lambdacontrols.action.inventory": "Inventaire",
|
||||
"lambdacontrols.action.jump": "Sauter",
|
||||
"lambdacontrols.action.left": "Aller à gauche",
|
||||
@@ -27,6 +29,7 @@
|
||||
"lambdacontrols.action.toggle_perspective": "Changer de point de vue",
|
||||
"lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique",
|
||||
"lambdacontrols.action.use": "Utiliser",
|
||||
"lambdacontrols.action.zoom": "Zoom",
|
||||
"lambdacontrols.button.a": "A",
|
||||
"lambdacontrols.button.b": "B",
|
||||
"lambdacontrols.button.x": "X",
|
||||
@@ -36,8 +39,8 @@
|
||||
"lambdacontrols.button.back": "Retour",
|
||||
"lambdacontrols.button.start": "Touche Menu",
|
||||
"lambdacontrols.button.guide": "Guide",
|
||||
"lambdacontrols.button.left_thumb": "Stick analogique gauche",
|
||||
"lambdacontrols.button.right_thumb": "Stick analogique droit",
|
||||
"lambdacontrols.button.left_thumb": "Stick gauche",
|
||||
"lambdacontrols.button.right_thumb": "Stick droit",
|
||||
"lambdacontrols.button.dpad_up": "D-Pad haut",
|
||||
"lambdacontrols.button.dpad_right": "D-Pad droit",
|
||||
"lambdacontrols.button.dpad_down": "D-Pad bas",
|
||||
@@ -72,16 +75,43 @@
|
||||
"lambdacontrols.hud_side.right": "droit",
|
||||
"lambdacontrols.menu.auto_switch_mode": "Changement auto de mode",
|
||||
"lambdacontrols.menu.controller": "Manette",
|
||||
"lambdacontrols.menu.controller2": "Deuxième manette",
|
||||
"lambdacontrols.menu.controller_type": "Type de manette",
|
||||
"lambdacontrols.menu.controls_mode": "Mode",
|
||||
"lambdacontrols.menu.dead_zone": "Zone morte",
|
||||
"lambdacontrols.menu.fly_drifting": "Inertie 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_side": "Côté du HUD",
|
||||
"lambdacontrols.menu.invert_right_x_axis": "Inverser le joystick droit (X)",
|
||||
"lambdacontrols.menu.invert_right_y_axis": "Inverser le joystick droit (Y)",
|
||||
"lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)",
|
||||
"lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)",
|
||||
"lambdacontrols.menu.keyboard_controls": "Contrôles clavier...",
|
||||
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
|
||||
"lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes",
|
||||
"lambdacontrols.menu.rotation_speed": "Vitesse de rotation",
|
||||
"lambdacontrols.menu.title": "LambdaControls - Paramètres",
|
||||
"lambdacontrols.menu.title.controller_controls": "Contrôles de la manette"
|
||||
"lambdacontrols.menu.title.controller": "Options de manettes",
|
||||
"lambdacontrols.menu.title.controller_controls": "Contrôles de la manette",
|
||||
"lambdacontrols.menu.title.gameplay": "Options de Gameplay",
|
||||
"lambdacontrols.menu.title.general": "Options générales",
|
||||
"lambdacontrols.menu.title.hud": "Options du HUD",
|
||||
"lambdacontrols.menu.unbound": "Délier",
|
||||
"lambdacontrols.menu.unfocused_input": "Entrée en fond",
|
||||
"lambdacontrols.narrator.unbound": "Délier %s",
|
||||
"lambdacontrols.not_bound": "Non défini",
|
||||
"lambdacontrols.tooltip.auto_switch_mode": "Détermine si le mode de contrôle doit automatiquement changer sur Manette si une manette est connectée et inversement.",
|
||||
"lambdacontrols.tooltip.controller2": "Défini une deuxième manette, utile dans le cas d'utilisation de Joy-Cons.",
|
||||
"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.dead_zone": "Zone morte des axes de la manette.",
|
||||
"lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement.",
|
||||
"lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical.",
|
||||
"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_side": "Change la position du HUD.",
|
||||
"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.reload_controller_mappings": "Recharge le fichier de configuration des manettes.",
|
||||
"lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée."
|
||||
}
|
||||
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
102
fabric/src/main/resources/config.toml
Normal file
@@ -0,0 +1,102 @@
|
||||
# LambdaControls configuration.
|
||||
|
||||
# The controls mode. Available modes: default, controller, touchscreen
|
||||
controls = "default"
|
||||
# Auto switch mode.
|
||||
auto_switch_mode = false
|
||||
|
||||
[hud]
|
||||
# Enables the HUD.
|
||||
enable = true
|
||||
# Dertermines where the movements buttons are.
|
||||
side = "left"
|
||||
|
||||
# Gameplay settings
|
||||
[gameplay]
|
||||
# Enables front block placing like in Bedrock Edition.
|
||||
front_block_placing = false
|
||||
# Fly behaviors
|
||||
[gameplay.fly]
|
||||
# Enables fly drifting.
|
||||
drifting = false
|
||||
# Enables vertical fly drifting.
|
||||
vertical_drifting = true
|
||||
|
||||
# Controller settings
|
||||
[controller]
|
||||
# Controller to use.
|
||||
id = 0
|
||||
# Second controller to use.
|
||||
id2 = -1
|
||||
# Controller's type.
|
||||
type = "default"
|
||||
# Controller's dead zone.
|
||||
dead_zone = 0.20
|
||||
# Rotation speed for look directions.
|
||||
rotation_speed = 40.0
|
||||
# Mouse speed in GUI.
|
||||
mouse_speed = 30.0
|
||||
# Inverts the right X axis.
|
||||
invert_right_x_axis = false
|
||||
# Inverts the right Y axis.
|
||||
invert_right_y_axis = false
|
||||
# Allow unfocused input.
|
||||
unfocused_input = false
|
||||
# Controller controls.
|
||||
[controller.controls]
|
||||
# Attack control.
|
||||
attack = "105"
|
||||
# Back control.
|
||||
back = "201"
|
||||
# Open chat control.
|
||||
chat = "12"
|
||||
# Drop item control.
|
||||
drop_item = "1"
|
||||
# Forward control.
|
||||
forward = "101"
|
||||
# Hot-bar left control.
|
||||
hotbar_left = "4"
|
||||
# Hot-bar right control.
|
||||
hotbar_right = "5"
|
||||
# Inventory control.
|
||||
inventory = "3"
|
||||
# Jump control.
|
||||
jump = "0"
|
||||
# Left movement control.
|
||||
left = "200"
|
||||
# Pause game control.
|
||||
pause_game = "7"
|
||||
# Pick block control.
|
||||
pick_block = "14"
|
||||
# Show player list control.
|
||||
player_list = "6"
|
||||
# Right movement control.
|
||||
right = "100"
|
||||
# Take screenshot control.
|
||||
screenshot = "11+0"
|
||||
# Down slot control.
|
||||
slot_down = "13"
|
||||
# Left slot control.
|
||||
slot_left = "14"
|
||||
# Right slot control.
|
||||
slot_right = "12"
|
||||
# Up slot control.
|
||||
slot_up = "11"
|
||||
# Sneak control.
|
||||
sneak = "10"
|
||||
# Sprint control.
|
||||
sprint = "9"
|
||||
# Swap hands control.
|
||||
swap_hands = "2"
|
||||
# Switch to left tab control.
|
||||
tab_left = "4"
|
||||
# Switch to right tab control.
|
||||
tab_right = "5"
|
||||
# Toggle perspective control.
|
||||
toggle_perspective = "11+3"
|
||||
# Toggle smooth camera control.
|
||||
toggle_smooth_camera = "-1"
|
||||
# Use control.
|
||||
use = "104"
|
||||
# Zoom control.
|
||||
zoom = "11+2"
|
||||
@@ -16,8 +16,14 @@
|
||||
"icon": "assets/lambdacontrols/icon.png",
|
||||
"environment": "client",
|
||||
"entrypoints": {
|
||||
"client": [
|
||||
"main": [
|
||||
"me.lambdaurora.lambdacontrols.LambdaControls"
|
||||
],
|
||||
"client": [
|
||||
"me.lambdaurora.lambdacontrols.client.LambdaControlsClient"
|
||||
],
|
||||
"modmenu": [
|
||||
"me.lambdaurora.lambdacontrols.client.LambdaControlsModMenu"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
@@ -26,7 +32,12 @@
|
||||
"depends": {
|
||||
"fabricloader": ">=0.4.0",
|
||||
"fabric": "*",
|
||||
"minecraft": "1.15.x"
|
||||
"minecraft": "1.15.x",
|
||||
"spruceui": ">=1.3.4"
|
||||
},
|
||||
"recommends": {
|
||||
"modmenu": ">=1.8.0+build.16",
|
||||
"okzoomer": ">=1.0.4"
|
||||
},
|
||||
"suggests": {
|
||||
"flamingo": "*"
|
||||
@@ -1,18 +1,20 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "me.lambdaurora.lambdacontrols.mixin",
|
||||
"package": "me.lambdaurora.lambdacontrols.client.mixin",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"client": [
|
||||
"AbstractButtonWidgetAccessor",
|
||||
"AbstractContainerScreenMixin",
|
||||
"CreativeInventoryScreenMixin",
|
||||
"AdvancementsScreenAccessor",
|
||||
"ContainerScreenMixin",
|
||||
"ClientPlayerEntityMixin",
|
||||
"ClientPlayNetworkHandlerMixin",
|
||||
"ControlsOptionsScreenMixin",
|
||||
"CreativeInventoryScreenAccessor",
|
||||
"EntryListWidgetAccessor",
|
||||
"GameRendererMixin",
|
||||
"InGameHudMixin",
|
||||
"KeyBindingMixin",
|
||||
"MinecraftClientMixin",
|
||||
"MouseMixin",
|
||||
"ScreenMixin",
|
||||
"SettingsScreenMixin"
|
||||
],
|
||||
"injectors": {
|
||||
@@ -3,16 +3,17 @@ org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Fabric Properties
|
||||
# check these on https://fabricmc.net/use
|
||||
minecraft_version=1.15.1
|
||||
yarn_mappings=1.15.1+build.3:v2
|
||||
loader_version=0.7.2+build.174
|
||||
minecraft_version=1.15.2
|
||||
yarn_mappings=1.15.2+build.9:v2
|
||||
loader_version=0.7.6+build.180
|
||||
|
||||
# Mod Properties
|
||||
mod_version = 1.0.1
|
||||
mod_version = 1.1.0
|
||||
maven_group = me.lambdaurora
|
||||
archives_base_name = lambdacontrols
|
||||
|
||||
# Dependencies
|
||||
# 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.25+build.282-1.15
|
||||
fabric_version=0.4.29+build.290-1.15
|
||||
spruceui_version=1.3.4
|
||||
|
||||
|
||||
@@ -8,3 +8,6 @@ pluginManagement {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'lambdacontrols'
|
||||
include 'core', 'fabric', 'spigot'
|
||||
|
||||
50
spigot/build.gradle
Normal file
@@ -0,0 +1,50 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
archivesBaseName = project.archives_base_name + "-spigot"
|
||||
|
||||
repositories {
|
||||
maven { url = 'https://hub.spigotmc.org/nexus/content/groups/public/' }
|
||||
maven { url = 'https://libraries.minecraft.net/' }
|
||||
}
|
||||
|
||||
configurations {
|
||||
include
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(":core")
|
||||
include(project(":core")) {
|
||||
exclude group: 'com.google.code.gson'
|
||||
exclude group: 'com.google.guava'
|
||||
}
|
||||
api 'org.spigotmc:spigot-api:1.15.1-R0.1-SNAPSHOT'
|
||||
api 'io.netty:netty-all:4.1.28.Final'
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include "plugin.yml"
|
||||
|
||||
expand 'version': project.version.toString().replace("#", "")
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
from '../LICENSE'
|
||||
|
||||
dependsOn configurations.include
|
||||
from {
|
||||
(configurations.include).collect {
|
||||
it.isDirectory() ? it : zipTree(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls Spigot configuration.
|
||||
*/
|
||||
public class LambdaControlsConfig
|
||||
{
|
||||
private static final boolean DEFAULT_FRONT_BLOCK_PLACING = true;
|
||||
|
||||
protected final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/server_config.toml").build();
|
||||
private final LambdaControlsSpigot plugin;
|
||||
|
||||
public LambdaControlsConfig(@NotNull LambdaControlsSpigot plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void load()
|
||||
{
|
||||
File configDir = new File("config/");
|
||||
if (!configDir.exists())
|
||||
configDir.mkdirs();
|
||||
this.config.load();
|
||||
this.plugin.log("Configuration loaded.");
|
||||
LambdaControlsFeature.FRONT_BLOCK_PLACING.setAllowed(this.config.getOrElse("gameplay.front_block_placing", DEFAULT_FRONT_BLOCK_PLACING));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import me.lambdaurora.lambdacontrols.event.PlayerChangeControlsModeEvent;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static me.lambdaurora.lambdacontrols.LambdaControlsConstants.*;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls spigot plugin which provides extra features for servers.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class LambdaControlsSpigot extends JavaPlugin implements PluginMessageListener, Listener
|
||||
{
|
||||
private static final Map<Player, ControlsMode> PLAYERS_CONTROLS_MODE = new HashMap<>();
|
||||
public final LambdaControlsConfig config = new LambdaControlsConfig(this);
|
||||
|
||||
@Override
|
||||
public void onEnable()
|
||||
{
|
||||
super.onEnable();
|
||||
|
||||
this.config.load();
|
||||
|
||||
// Note that Spigot has a bullshit channel size restriction as Minecraft SUPPORTS UP TO 32767 AS CHANNEL SIZE.
|
||||
// Please stop using that bad server software, move over Sponge or idk other things. REALLY.
|
||||
this.getServer().getMessenger().registerIncomingPluginChannel(this, CONTROLS_MODE_CHANNEL.toString(), this);
|
||||
this.getServer().getMessenger().registerOutgoingPluginChannel(this, CONTROLS_MODE_CHANNEL.toString());
|
||||
this.getServer().getMessenger().registerOutgoingPluginChannel(this, FEATURE_CHANNEL.toString());
|
||||
this.getServer().getMessenger().registerIncomingPluginChannel(this, HELLO_CHANNEL.toString(), this);
|
||||
this.getServer().getPluginManager().registerEvents(this, this);
|
||||
|
||||
this.getServer().getOnlinePlayers().forEach(player -> {
|
||||
PLAYERS_CONTROLS_MODE.put(player, ControlsMode.DEFAULT);
|
||||
|
||||
this.requestPlayerControlsMode(player);
|
||||
this.updatePlayerFeature(player, LambdaControlsFeature.FRONT_BLOCK_PLACING);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable()
|
||||
{
|
||||
super.onDisable();
|
||||
|
||||
this.getServer().getMessenger().unregisterIncomingPluginChannel(this, CONTROLS_MODE_CHANNEL.toString());
|
||||
this.getServer().getMessenger().unregisterOutgoingPluginChannel(this, CONTROLS_MODE_CHANNEL.toString());
|
||||
this.getServer().getMessenger().unregisterOutgoingPluginChannel(this, FEATURE_CHANNEL.toString());
|
||||
this.getServer().getMessenger().unregisterIncomingPluginChannel(this, HELLO_CHANNEL.toString());
|
||||
|
||||
PLAYERS_CONTROLS_MODE.clear();
|
||||
}
|
||||
|
||||
public void requestPlayerControlsMode(@NotNull Player player)
|
||||
{
|
||||
player.sendPluginMessage(this, CONTROLS_MODE_CHANNEL.toString(), new byte[0]);
|
||||
}
|
||||
|
||||
public void updatePlayerFeature(@NotNull Player player, @NotNull LambdaControlsFeature feature)
|
||||
{
|
||||
Objects.requireNonNull(player);
|
||||
Objects.requireNonNull(feature);
|
||||
|
||||
player.sendPluginMessage(this, FEATURE_CHANNEL.toString(), this.makeFeatureMessage(feature));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message to the terminal.
|
||||
*
|
||||
* @param info The message to print.
|
||||
*/
|
||||
public void log(String info)
|
||||
{
|
||||
this.getLogger().info(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message)
|
||||
{
|
||||
if (channel.equals(HELLO_CHANNEL.toString())) {
|
||||
NettyPacketBuffer buffer = new NettyPacketBuffer(Unpooled.copiedBuffer(message));
|
||||
String version = buffer.readString(16);
|
||||
ControlsMode.byId(buffer.readString(32)).ifPresent(controlsMode -> {
|
||||
PLAYERS_CONTROLS_MODE.put(player, controlsMode);
|
||||
PlayerChangeControlsModeEvent event = new PlayerChangeControlsModeEvent(player, controlsMode);
|
||||
this.getServer().getPluginManager().callEvent(event);
|
||||
});
|
||||
this.updatePlayerFeature(player, LambdaControlsFeature.FRONT_BLOCK_PLACING);
|
||||
} else if (channel.equals(CONTROLS_MODE_CHANNEL.toString())) {
|
||||
NettyPacketBuffer buffer = new NettyPacketBuffer(Unpooled.copiedBuffer(message));
|
||||
ControlsMode.byId(buffer.readString(32)).ifPresent(controlsMode -> {
|
||||
PLAYERS_CONTROLS_MODE.put(player, controlsMode);
|
||||
PlayerChangeControlsModeEvent event = new PlayerChangeControlsModeEvent(player, controlsMode);
|
||||
this.getServer().getPluginManager().callEvent(event);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a packet byte buffer made for the lambdacontrols:feature plugin message.
|
||||
*
|
||||
* @param feature The feature data to send.
|
||||
* @return The packet byte buffer.
|
||||
*/
|
||||
public byte[] makeFeatureMessage(@NotNull LambdaControlsFeature feature)
|
||||
{
|
||||
Objects.requireNonNull(feature, "Feature cannot be null.");
|
||||
NettyPacketBuffer buffer = new NettyPacketBuffer(Unpooled.buffer());
|
||||
buffer.writeString(feature.getName());
|
||||
buffer.writeBoolean(feature.isAllowed());
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(@NotNull PlayerJoinEvent event)
|
||||
{
|
||||
PLAYERS_CONTROLS_MODE.put(event.getPlayer(), ControlsMode.DEFAULT);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerLeave(@NotNull PlayerQuitEvent event)
|
||||
{
|
||||
PLAYERS_CONTROLS_MODE.remove(event.getPlayer());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package me.lambdaurora.lambdacontrols;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.codec.EncoderException;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class NettyPacketBuffer extends PacketBuffer
|
||||
{
|
||||
public NettyPacketBuffer(ByteBuf byteBuf)
|
||||
{
|
||||
super(byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readVarint()
|
||||
{
|
||||
int var1 = 0;
|
||||
int var2 = 0;
|
||||
byte var3;
|
||||
|
||||
do {
|
||||
var3 = this.readByte();
|
||||
var1 |= (var3 & 127) << var2++ * 7;
|
||||
|
||||
if (var2 > 5)
|
||||
throw new RuntimeException("VarInt too big");
|
||||
} while ((var3 & 128) == 128);
|
||||
|
||||
return var1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVarint(int input)
|
||||
{
|
||||
while ((input & -128) != 0) {
|
||||
this.writeByte(input & 127 | 128);
|
||||
input >>>= 7;
|
||||
}
|
||||
|
||||
this.writeByte(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString(int maxLength)
|
||||
{
|
||||
int var2 = this.readVarint();
|
||||
|
||||
if (var2 > maxLength * 4)
|
||||
throw new DecoderException("The received encoded string buffer length is longer than maximum allowed (" + var2 + " > " + maxLength * 4 + ")");
|
||||
else if (var2 < 0)
|
||||
throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!");
|
||||
else {
|
||||
String var3 = this.readCharSequence(var2, StandardCharsets.UTF_8).toString();
|
||||
|
||||
if (var3.length() > maxLength)
|
||||
throw new DecoderException("The received string length is longer than maximum allowed (" + var2 + " > " + maxLength + ")");
|
||||
else
|
||||
return var3;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeString(String string)
|
||||
{
|
||||
byte[] var2 = string.getBytes(Charset.forName("UTF-8"));
|
||||
|
||||
if (var2.length > 32767) {
|
||||
throw new EncoderException("String too big (was " + string.length() + " data encoded, max " + 32767 + ")");
|
||||
} else {
|
||||
this.writeVarint(var2.length);
|
||||
this.writeCharSequence(string, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
NettyPacketBuffer buffer = (NettyPacketBuffer) o;
|
||||
|
||||
return byteBuf.equals(buffer.byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ByteBuf buffer)
|
||||
{
|
||||
return this.byteBuf.compareTo(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return this.byteBuf.toString();
|
||||
}
|
||||
}
|
||||
1153
spigot/src/main/java/me/lambdaurora/lambdacontrols/PacketBuffer.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.event;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.player.PlayerEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents an event which is fired when a player change their controls mode.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class PlayerChangeControlsModeEvent extends PlayerEvent
|
||||
{
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private final ControlsMode controlsMode;
|
||||
|
||||
public PlayerChangeControlsModeEvent(@NotNull Player who, @NotNull ControlsMode controlsMode)
|
||||
{
|
||||
super(who);
|
||||
this.controlsMode = controlsMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the controls mode of the player.
|
||||
*
|
||||
* @return The player's controls mode.
|
||||
*/
|
||||
public ControlsMode getControlsMode()
|
||||
{
|
||||
return this.controlsMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "PlayerChangeControlsModeEvent{" +
|
||||
"player=" + this.player +
|
||||
", controls_mode=" + this.controlsMode +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers()
|
||||
{
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
public static @NotNull HandlerList getHandlerList()
|
||||
{
|
||||
return HANDLERS;
|
||||
}
|
||||
}
|
||||
6
spigot/src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
name: LambdaControls
|
||||
version: ${version}
|
||||
description: A quick Spigot plugin for LambdaControls which allow server admins to disable some features.
|
||||
|
||||
main: me.lambdaurora.lambdacontrols.LambdaControlsSpigot
|
||||
api-version: 1.13
|
||||
6
spigot/src/main/resources/server_config.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
# LambdaControls server configuration.
|
||||
|
||||
# Gameplay settings
|
||||
[gameplay]
|
||||
# Allows front block placing like in Bedrock Edition.
|
||||
front_block_placing = true
|
||||
@@ -1,507 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.options.GameOptions;
|
||||
import net.minecraft.client.options.KeyBinding;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.client.util.ScreenshotUtils;
|
||||
import org.aperlambda.lambdacommon.Identifier;
|
||||
import org.aperlambda.lambdacommon.utils.Identifiable;
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Represents a button binding.
|
||||
*
|
||||
* @author LambdAurora
|
||||
*/
|
||||
public class ButtonBinding implements Nameable
|
||||
{
|
||||
private static final List<ButtonBinding> BINDINGS = new ArrayList<>();
|
||||
private static final List<Category> CATEGORIES = new ArrayList<>();
|
||||
public static final Category MOVEMENT_CATEGORY;
|
||||
public static final Category GAMEPLAY_CATEGORY;
|
||||
public static final Category INVENTORY_CATEGORY;
|
||||
public static final Category MULTIPLAYER_CATEGORY;
|
||||
public static final Category MISC_CATEGORY;
|
||||
public static final ButtonBinding ATTACK = new ButtonBinding("attack", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true));
|
||||
public static final ButtonBinding BACK = new ButtonBinding("back", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, false));
|
||||
public static final ButtonBinding CHAT = new ButtonBinding("chat", GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT);
|
||||
public static final ButtonBinding DROP_ITEM = new ButtonBinding("drop_item", GLFW.GLFW_GAMEPAD_BUTTON_B);
|
||||
public static final ButtonBinding FORWARD = new ButtonBinding("forward", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, true));
|
||||
public static final ButtonBinding INVENTORY = new ButtonBinding("inventory", GLFW.GLFW_GAMEPAD_BUTTON_Y);
|
||||
public static final ButtonBinding JUMP = new ButtonBinding("jump", GLFW.GLFW_GAMEPAD_BUTTON_A);
|
||||
public static final ButtonBinding LEFT = new ButtonBinding("left", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_X, false));
|
||||
public static final ButtonBinding PAUSE_GAME = new ButtonBinding("pause_game", GLFW.GLFW_GAMEPAD_BUTTON_START);
|
||||
public static final ButtonBinding PICK_BLOCK = new ButtonBinding("pick_block", GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT);
|
||||
public static final ButtonBinding PLAYER_LIST = new ButtonBinding("player_list", GLFW.GLFW_GAMEPAD_BUTTON_BACK);
|
||||
public static final ButtonBinding RIGHT = new ButtonBinding("right", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_X, true));
|
||||
public static final ButtonBinding SCREENSHOT = new ButtonBinding("screenshot", GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN,
|
||||
Collections.singletonList((client, action) -> {
|
||||
if (action == 0)
|
||||
ScreenshotUtils.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(),
|
||||
text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text)));
|
||||
return true;
|
||||
}));
|
||||
public static final ButtonBinding SMOOTH_CAMERA = new ButtonBinding("toggle_smooth_camera", -1);
|
||||
public static final ButtonBinding SNEAK = new ButtonBinding("sneak", GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB);
|
||||
public static final ButtonBinding SPRINT = new ButtonBinding("sprint", GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB);
|
||||
public static final ButtonBinding SWAP_HANDS = new ButtonBinding("swap_hands", GLFW.GLFW_GAMEPAD_BUTTON_X);
|
||||
public static final ButtonBinding TOGGLE_PERSPECTIVE = new ButtonBinding("toggle_perspective", GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP);
|
||||
public static final ButtonBinding USE = new ButtonBinding("use", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true));
|
||||
|
||||
private int button;
|
||||
private int default_button;
|
||||
private String key;
|
||||
private KeyBinding minecraft_key_binding = null;
|
||||
private List<PressAction> actions = new ArrayList<>(Collections.singletonList((client, action) -> {
|
||||
this.as_key_binding().ifPresent(key_binding -> ((KeyBindingAccessor) key_binding).handle_press_state(this.is_button_down()));
|
||||
return true;
|
||||
}));
|
||||
private boolean pressed = false;
|
||||
|
||||
protected ButtonBinding(@NotNull String key, int default_button, @NotNull List<PressAction> actions)
|
||||
{
|
||||
this.default_button = this.button = default_button;
|
||||
this.key = key;
|
||||
this.actions.addAll(actions);
|
||||
BINDINGS.add(this);
|
||||
}
|
||||
|
||||
protected ButtonBinding(@NotNull String key, int default_button)
|
||||
{
|
||||
this(key, default_button, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the button bound.
|
||||
*
|
||||
* @return The bound button.
|
||||
*/
|
||||
public int get_button()
|
||||
{
|
||||
return this.button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bound button.
|
||||
*
|
||||
* @param button The bound button.
|
||||
*/
|
||||
public void set_button(int button)
|
||||
{
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the bound button is the specified button or not.
|
||||
*
|
||||
* @param button The button to check.
|
||||
* @return True if the bound button is the specified button, else false.
|
||||
*/
|
||||
public boolean is_button(int button)
|
||||
{
|
||||
return this.button == button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this button is down or not.
|
||||
*
|
||||
* @return True if the button is down, else false.
|
||||
*/
|
||||
public boolean is_button_down()
|
||||
{
|
||||
return this.pressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this button binding is bound or not.
|
||||
*
|
||||
* @return True if this button binding is bound, else false.
|
||||
*/
|
||||
public boolean is_not_bound()
|
||||
{
|
||||
return this.button == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default button assigned to this binding.
|
||||
*
|
||||
* @return The default button.
|
||||
*/
|
||||
public int get_default_button()
|
||||
{
|
||||
return this.default_button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the assigned button is the default button.
|
||||
*
|
||||
* @return True if the assigned button is the default button, else false.
|
||||
*/
|
||||
public boolean is_default()
|
||||
{
|
||||
return this.button == this.default_button;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String get_name()
|
||||
{
|
||||
return this.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the translation key of this button binding.
|
||||
*
|
||||
* @return The translation key.
|
||||
*/
|
||||
public @NotNull String get_translation_key()
|
||||
{
|
||||
return "lambdacontrols.action." + this.get_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key binding equivalent of this button binding.
|
||||
*
|
||||
* @return The key binding equivalent.
|
||||
*/
|
||||
public @NotNull Optional<KeyBinding> as_key_binding()
|
||||
{
|
||||
return Optional.ofNullable(this.minecraft_key_binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified axis as a button.
|
||||
*
|
||||
* @param axis The axis.
|
||||
* @param positive True if the axis part is positive, else false.
|
||||
* @return The axis as a button.
|
||||
*/
|
||||
public static int axis_as_button(int axis, boolean positive)
|
||||
{
|
||||
return positive ? 100 + axis : 200 + axis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the second Joycon's specified button code.
|
||||
*
|
||||
* @param button The raw button code.
|
||||
* @return The second Joycon's button code.
|
||||
*/
|
||||
public static int joycon2_button(int button)
|
||||
{
|
||||
return 300 + button;
|
||||
}
|
||||
|
||||
public static void init(@NotNull GameOptions options)
|
||||
{
|
||||
ATTACK.minecraft_key_binding = options.keyAttack;
|
||||
BACK.minecraft_key_binding = options.keyBack;
|
||||
CHAT.minecraft_key_binding = options.keyChat;
|
||||
DROP_ITEM.minecraft_key_binding = options.keyDrop;
|
||||
FORWARD.minecraft_key_binding = options.keyForward;
|
||||
INVENTORY.minecraft_key_binding = options.keyInventory;
|
||||
JUMP.minecraft_key_binding = options.keyJump;
|
||||
LEFT.minecraft_key_binding = options.keyLeft;
|
||||
PICK_BLOCK.minecraft_key_binding = options.keyPickItem;
|
||||
PLAYER_LIST.minecraft_key_binding = options.keyPlayerList;
|
||||
RIGHT.minecraft_key_binding = options.keyRight;
|
||||
SCREENSHOT.minecraft_key_binding = options.keyScreenshot;
|
||||
SMOOTH_CAMERA.minecraft_key_binding = options.keySmoothCamera;
|
||||
SNEAK.minecraft_key_binding = options.keySneak;
|
||||
SPRINT.minecraft_key_binding = options.keySprint;
|
||||
SWAP_HANDS.minecraft_key_binding = options.keySwapHands;
|
||||
TOGGLE_PERSPECTIVE.minecraft_key_binding = options.keyTogglePerspective;
|
||||
USE.minecraft_key_binding = options.keyUse;
|
||||
}
|
||||
|
||||
public static void load_from_config(@NotNull LambdaControlsConfig config)
|
||||
{
|
||||
BINDINGS.forEach(config::load_button_binding);
|
||||
}
|
||||
|
||||
public static void set_button_state(int button, boolean state)
|
||||
{
|
||||
BINDINGS.parallelStream().filter(binding -> Objects.equals(binding.button, button))
|
||||
.forEach(binding -> binding.pressed = state);
|
||||
}
|
||||
|
||||
public static void handle_button(@NotNull MinecraftClient client, int button, int action)
|
||||
{
|
||||
BINDINGS.parallelStream().filter(binding -> binding.button == button)
|
||||
.forEach(binding -> {
|
||||
for (int i = binding.actions.size() - 1; i >= 0; i--) {
|
||||
if (binding.actions.get(i).press(client, action))
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the button has duplicated bindings.
|
||||
*
|
||||
* @param button The button to check.
|
||||
* @return True if the button has duplicated bindings, else false.
|
||||
*/
|
||||
public static boolean has_duplicates(int button)
|
||||
{
|
||||
return BINDINGS.parallelStream().filter(binding -> binding.button == button).count() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized name of the specified button.
|
||||
*
|
||||
* @param button The button.
|
||||
* @return The localized name of the button.
|
||||
*/
|
||||
public static @NotNull String get_localized_button_name(int button)
|
||||
{
|
||||
switch (button) {
|
||||
case -1:
|
||||
return I18n.translate("key.keyboard.unknown");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_A:
|
||||
return I18n.translate("lambdacontrols.button.a");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_B:
|
||||
return I18n.translate("lambdacontrols.button.b");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_X:
|
||||
return I18n.translate("lambdacontrols.button.x");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_Y:
|
||||
return I18n.translate("lambdacontrols.button.y");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
|
||||
return I18n.translate("lambdacontrols.button.left_bumper");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
|
||||
return I18n.translate("lambdacontrols.button.right_bumper");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_BACK:
|
||||
return I18n.translate("lambdacontrols.button.back");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_START:
|
||||
return I18n.translate("lambdacontrols.button.start");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_GUIDE:
|
||||
return I18n.translate("lambdacontrols.button.guide");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
|
||||
return I18n.translate("lambdacontrols.button.left_thumb");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
|
||||
return I18n.translate("lambdacontrols.button.right_thumb");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP:
|
||||
return I18n.translate("lambdacontrols.button.dpad_up");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT:
|
||||
return I18n.translate("lambdacontrols.button.dpad_right");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN:
|
||||
return I18n.translate("lambdacontrols.button.dpad_down");
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT:
|
||||
return I18n.translate("lambdacontrols.button.dpad_left");
|
||||
case 100:
|
||||
return I18n.translate("lambdacontrols.axis.left_x+");
|
||||
case 101:
|
||||
return I18n.translate("lambdacontrols.axis.left_y+");
|
||||
case 102:
|
||||
return I18n.translate("lambdacontrols.axis.right_x+");
|
||||
case 103:
|
||||
return I18n.translate("lambdacontrols.axis.right_y+");
|
||||
case 104:
|
||||
return I18n.translate("lambdacontrols.axis.left_trigger");
|
||||
case 105:
|
||||
return I18n.translate("lambdacontrols.axis.right_trigger");
|
||||
case 200:
|
||||
return I18n.translate("lambdacontrols.axis.left_x-");
|
||||
case 201:
|
||||
return I18n.translate("lambdacontrols.axis.left_y-");
|
||||
case 202:
|
||||
return I18n.translate("lambdacontrols.axis.right_x-");
|
||||
case 203:
|
||||
return I18n.translate("lambdacontrols.axis.right_y-");
|
||||
default:
|
||||
return I18n.translate("lambdacontrols.button.unknown", button);
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull Stream<ButtonBinding> stream()
|
||||
{
|
||||
return BINDINGS.stream();
|
||||
}
|
||||
|
||||
public static @NotNull Stream<Category> stream_categories()
|
||||
{
|
||||
return CATEGORIES.stream();
|
||||
}
|
||||
|
||||
static {
|
||||
MOVEMENT_CATEGORY = register_default_category("key.categories.movement", category -> category.register_all_bindings(
|
||||
FORWARD,
|
||||
BACK,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
JUMP,
|
||||
SNEAK,
|
||||
SPRINT));
|
||||
GAMEPLAY_CATEGORY = register_default_category("key.categories.gameplay", category -> category.register_all_bindings(
|
||||
ATTACK,
|
||||
PICK_BLOCK,
|
||||
USE
|
||||
));
|
||||
INVENTORY_CATEGORY = register_default_category("key.categories.inventory", category -> category.register_all_bindings(
|
||||
DROP_ITEM,
|
||||
INVENTORY,
|
||||
SWAP_HANDS
|
||||
));
|
||||
MULTIPLAYER_CATEGORY = register_default_category("key.categories.multiplayer",
|
||||
category -> category.register_all_bindings(CHAT, PLAYER_LIST));
|
||||
MISC_CATEGORY = register_default_category("key.categories.misc", category -> category.register_all_bindings(
|
||||
SCREENSHOT,
|
||||
//SMOOTH_CAMERA,
|
||||
TOGGLE_PERSPECTIVE
|
||||
));
|
||||
}
|
||||
|
||||
public static ButtonBinding register(@NotNull Identifier binding_id, int default_button, @NotNull List<PressAction> actions)
|
||||
{
|
||||
return new ButtonBinding(binding_id.get_namespace() + "." + binding_id.get_name(), default_button, actions);
|
||||
}
|
||||
|
||||
public static ButtonBinding register(@NotNull Identifier binding_id, int default_button)
|
||||
{
|
||||
return register(binding_id, default_button, Collections.emptyList());
|
||||
}
|
||||
|
||||
public static ButtonBinding register(@NotNull net.minecraft.util.Identifier binding_id, int default_button, @NotNull List<PressAction> actions)
|
||||
{
|
||||
return register(new Identifier(binding_id.getNamespace(), binding_id.getPath()), default_button, actions);
|
||||
}
|
||||
|
||||
public static ButtonBinding register(@NotNull net.minecraft.util.Identifier binding_id, int default_button)
|
||||
{
|
||||
return register(binding_id, default_button, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a category of button bindings.
|
||||
*
|
||||
* @param category The category to register.
|
||||
* @return The registered category.
|
||||
*/
|
||||
public static Category register_category(@NotNull Category category)
|
||||
{
|
||||
CATEGORIES.add(category);
|
||||
return category;
|
||||
}
|
||||
|
||||
public static Category register_category(@NotNull Identifier identifier, int priority)
|
||||
{
|
||||
return register_category(new Category(identifier, priority));
|
||||
}
|
||||
|
||||
public static Category register_category(@NotNull Identifier identifier)
|
||||
{
|
||||
return register_category(new Category(identifier));
|
||||
}
|
||||
|
||||
private static Category register_default_category(@NotNull String key, @NotNull Consumer<Category> key_adder)
|
||||
{
|
||||
Category category = register_category(new Identifier("minecraft", key), CATEGORIES.size());
|
||||
key_adder.accept(category);
|
||||
return category;
|
||||
}
|
||||
|
||||
public static class Category implements Identifiable
|
||||
{
|
||||
private final List<ButtonBinding> bindings = new ArrayList<>();
|
||||
private final Identifier id;
|
||||
private int priority;
|
||||
|
||||
public Category(@NotNull Identifier id, int priority)
|
||||
{
|
||||
this.id = id;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public Category(@NotNull Identifier id)
|
||||
{
|
||||
this(id, 100);
|
||||
}
|
||||
|
||||
public void register_binding(@NotNull ButtonBinding binding)
|
||||
{
|
||||
if (this.bindings.contains(binding))
|
||||
throw new IllegalStateException("Cannot register twice a button binding in the same category.");
|
||||
this.bindings.add(binding);
|
||||
}
|
||||
|
||||
public void register_all_bindings(@NotNull ButtonBinding... bindings)
|
||||
{
|
||||
this.register_all_bindings(Arrays.asList(bindings));
|
||||
}
|
||||
|
||||
public void register_all_bindings(@NotNull List<ButtonBinding> bindings)
|
||||
{
|
||||
bindings.forEach(this::register_binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bindings assigned to this category.
|
||||
*
|
||||
* @return The bindings assigned to this category.
|
||||
*/
|
||||
public @NotNull List<ButtonBinding> get_bindings()
|
||||
{
|
||||
return Collections.unmodifiableList(this.bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translated name of this category.
|
||||
* <p>
|
||||
* The translation key should be `modid.identifier_name`.
|
||||
*
|
||||
* @return The translated name.
|
||||
*/
|
||||
public @NotNull String get_translated_name()
|
||||
{
|
||||
if (this.id.get_namespace().equals("minecraft"))
|
||||
return I18n.translate(this.id.get_name());
|
||||
else
|
||||
return I18n.translate(this.id.get_namespace() + "." + this.id.get_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the priority display of this category.
|
||||
* It will defines in which order the categories will display on the controls screen.
|
||||
*
|
||||
* @return The priority of this category.
|
||||
*/
|
||||
public int get_priority()
|
||||
{
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Identifier get_identifier()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public static interface PressAction
|
||||
{
|
||||
/**
|
||||
* Handles when there is a press action on the button.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param action The action done.
|
||||
*/
|
||||
boolean press(@NotNull MinecraftClient client, int action);
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.keybinding.FabricKeyBinding;
|
||||
import net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.client.toast.SystemToast;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls mod.
|
||||
*/
|
||||
public class LambdaControls implements ClientModInitializer
|
||||
{
|
||||
private static LambdaControls INSTANCE;
|
||||
public static final FabricKeyBinding BINDING_LOOK_UP = FabricKeyBinding.Builder.create(new Identifier("lambdacontrols", "look_up"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement").build();
|
||||
public static final FabricKeyBinding BINDING_LOOK_RIGHT = FabricKeyBinding.Builder.create(new Identifier("lambdacontrols", "look_right"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement").build();
|
||||
public static final FabricKeyBinding BINDING_LOOK_DOWN = FabricKeyBinding.Builder.create(new Identifier("lambdacontrols", "look_down"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement").build();
|
||||
public static final FabricKeyBinding BINDING_LOOK_LEFT = FabricKeyBinding.Builder.create(new Identifier("lambdacontrols", "look_left"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement").build();
|
||||
public static final Identifier CONTROLLER_BUTTONS = new Identifier("lambdacontrols", "textures/gui/controller_buttons.png");
|
||||
public static final Identifier CONTROLLER_AXIS = new Identifier("lambdacontrols", "textures/gui/controller_axis.png");
|
||||
public final Logger logger = LogManager.getLogger("LambdaControls");
|
||||
public final LambdaControlsConfig config = new LambdaControlsConfig(this);
|
||||
public final LambdaInput input = new LambdaInput(this);
|
||||
private ControlsMode previous_controls_mode;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient()
|
||||
{
|
||||
INSTANCE = this;
|
||||
this.log("Initializing LambdaControls...");
|
||||
this.config.load();
|
||||
|
||||
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_UP);
|
||||
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_RIGHT);
|
||||
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_DOWN);
|
||||
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when Minecraft is initializing.
|
||||
*/
|
||||
public void on_mc_init(@NotNull MinecraftClient client)
|
||||
{
|
||||
Controller.update_mappings();
|
||||
ButtonBinding.init(client.options);
|
||||
GLFW.glfwSetJoystickCallback((jid, event) -> {
|
||||
if (event == GLFW.GLFW_CONNECTED) {
|
||||
Controller controller = Controller.by_id(jid);
|
||||
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.connected", jid),
|
||||
new LiteralText(controller.get_name())));
|
||||
} else if (event == GLFW.GLFW_DISCONNECTED) {
|
||||
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.disconnected", jid),
|
||||
null));
|
||||
}
|
||||
|
||||
this.switch_controls_mode();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called every Minecraft tick.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void on_tick(@NotNull MinecraftClient client)
|
||||
{
|
||||
this.input.on_tick(client);
|
||||
if (this.config.get_controls_mode() == ControlsMode.CONTROLLER)
|
||||
this.input.on_controller_tick(client);
|
||||
}
|
||||
|
||||
public void on_render(MinecraftClient client)
|
||||
{
|
||||
this.input.on_render(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the controls mode if the auto switch is enabled.
|
||||
*/
|
||||
public void switch_controls_mode()
|
||||
{
|
||||
if (this.config.has_auto_switch_mode()) {
|
||||
if (this.config.get_controller().is_gamepad()) {
|
||||
this.previous_controls_mode = this.config.get_controls_mode();
|
||||
this.config.set_controls_mode(ControlsMode.CONTROLLER);
|
||||
} else {
|
||||
if (this.previous_controls_mode == null) {
|
||||
this.previous_controls_mode = ControlsMode.DEFAULT;
|
||||
}
|
||||
|
||||
this.config.set_controls_mode(this.previous_controls_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message to the terminal.
|
||||
*
|
||||
* @param info The message to print.
|
||||
*/
|
||||
public void log(String info)
|
||||
{
|
||||
this.logger.info("[LambdaControls] " + info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the LambdaControls instance.
|
||||
*
|
||||
* @return The LambdaControls instance.
|
||||
*/
|
||||
public static LambdaControls get()
|
||||
{
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static int draw_button(int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient client)
|
||||
{
|
||||
return draw_button(x, y, button.get_button(), client);
|
||||
}
|
||||
|
||||
public static int draw_button(int x, int y, int button, @NotNull MinecraftClient client)
|
||||
{
|
||||
if (button == -1)
|
||||
return 0;
|
||||
|
||||
int controller_type = get().config.get_controller_type().get_id();
|
||||
boolean axis = false;
|
||||
int button_offset = button * 15;
|
||||
switch (button) {
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
|
||||
button_offset = 7 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
|
||||
button_offset = 8 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_BACK:
|
||||
button_offset = 4 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_START:
|
||||
button_offset = 6 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_GUIDE:
|
||||
button_offset = 5 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
|
||||
button_offset = 15 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
|
||||
button_offset = 16 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 100:
|
||||
button_offset = 0;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 100:
|
||||
button_offset = 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 100:
|
||||
button_offset = 2 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 100:
|
||||
button_offset = 3 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 200:
|
||||
button_offset = 4 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 200:
|
||||
button_offset = 5 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 200:
|
||||
button_offset = 6 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 200:
|
||||
button_offset = 7 * 18;
|
||||
axis = true;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 100:
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 200:
|
||||
button_offset = 9 * 15;
|
||||
break;
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 100:
|
||||
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 200:
|
||||
button_offset = 10 * 15;
|
||||
break;
|
||||
}
|
||||
|
||||
client.getTextureManager().bindTexture(axis ? LambdaControls.CONTROLLER_AXIS : LambdaControls.CONTROLLER_BUTTONS);
|
||||
GlStateManager.disableDepthTest();
|
||||
|
||||
GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
DrawableHelper.blit(x, y, (float) button_offset, (float) (controller_type * (axis ? 18 : 15)), axis ? 18 : 15, axis ? 18 : 15, 256, 256);
|
||||
GlStateManager.enableDepthTest();
|
||||
|
||||
return axis ? 18 : 15;
|
||||
}
|
||||
|
||||
public static int draw_button_tip(int x, int y, @NotNull ButtonBinding button, boolean display, @NotNull MinecraftClient client)
|
||||
{
|
||||
return draw_button_tip(x, y, button.get_button(), button.get_translation_key(), display, client);
|
||||
}
|
||||
|
||||
public static int draw_button_tip(int x, int y, int button, @NotNull String action, boolean display, @NotNull MinecraftClient client)
|
||||
{
|
||||
String translated_action = I18n.translate(action);
|
||||
|
||||
if (display) {
|
||||
int button_width = draw_button(x, y, button, client);
|
||||
|
||||
int text_y = (15 - client.textRenderer.fontHeight) / 2;
|
||||
client.textRenderer.drawWithShadow(translated_action, (float) (x + button_width + 5), (float) (y + text_y), 14737632);
|
||||
}
|
||||
|
||||
return display ? get_button_tip_width(translated_action, client.textRenderer) : -10;
|
||||
}
|
||||
|
||||
private static int get_button_tip_width(@NotNull String action, @NotNull TextRenderer text_renderer)
|
||||
{
|
||||
return 15 + 5 + text_renderer.getStringWidth(action);
|
||||
}
|
||||
}
|
||||
@@ -1,399 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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;
|
||||
|
||||
import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import net.minecraft.client.options.KeyBinding;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents LambdaControls configuration.
|
||||
*/
|
||||
public class LambdaControlsConfig
|
||||
{
|
||||
private final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/config.toml").build();
|
||||
private final Map<String, KeyBinding> keybinding_mappings = new HashMap<>();
|
||||
private final LambdaControls mod;
|
||||
private ControlsMode controls_mode;
|
||||
private ControllerType controller_type;
|
||||
// HUD settings.
|
||||
private boolean hud_enable;
|
||||
private HudSide hud_side;
|
||||
// Controller settings
|
||||
private double dead_zone;
|
||||
private double rotation_speed;
|
||||
private double mouse_speed;
|
||||
|
||||
public LambdaControlsConfig(@NotNull LambdaControls mod)
|
||||
{
|
||||
this.mod = mod;
|
||||
}
|
||||
|
||||
public void load()
|
||||
{
|
||||
this.keybinding_mappings.clear();
|
||||
this.config.load();
|
||||
this.mod.log("Configuration loaded.");
|
||||
this.controls_mode = ControlsMode.by_id(this.config.getOrElse("controls", "default")).orElse(ControlsMode.DEFAULT);
|
||||
// HUD settings.
|
||||
this.hud_enable = this.config.getOrElse("hud.enable", true);
|
||||
this.hud_side = HudSide.by_id(this.config.getOrElse("hud.side", "left")).orElse(HudSide.LEFT);
|
||||
// Controller settings.
|
||||
this.controller_type = ControllerType.by_id(this.config.getOrElse("controller.type", "default")).orElse(ControllerType.DEFAULT);
|
||||
this.dead_zone = this.config.getOrElse("controller.dead_zone", 0.25);
|
||||
this.rotation_speed = this.config.getOrElse("controller.rotation_speed", 40.0);
|
||||
this.mouse_speed = this.config.getOrElse("controller.mouse_speed", 25.0);
|
||||
// Controller controls.
|
||||
ButtonBinding.load_from_config(this);
|
||||
}
|
||||
|
||||
public void save()
|
||||
{
|
||||
this.config.set("controller.dead_zone", this.dead_zone);
|
||||
this.config.set("controller.rotation_speed", this.rotation_speed);
|
||||
this.config.set("controller.mouse_speed", this.mouse_speed);
|
||||
this.config.save();
|
||||
this.mod.log("Configuration saved.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controls mode from the configuration.
|
||||
*
|
||||
* @return The controls mode.
|
||||
*/
|
||||
public @NotNull ControlsMode get_controls_mode()
|
||||
{
|
||||
return this.controls_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controls mode in the configuration.
|
||||
*
|
||||
* @param controls_mode The controls mode.
|
||||
*/
|
||||
public void set_controls_mode(@NotNull ControlsMode controls_mode)
|
||||
{
|
||||
this.controls_mode = controls_mode;
|
||||
this.config.set("controls", controls_mode.get_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the auto switch mode is enabled or not.
|
||||
*
|
||||
* @return True if the auto switch mode is enabled, else false.
|
||||
*/
|
||||
public boolean has_auto_switch_mode()
|
||||
{
|
||||
return this.config.getOrElse("auto_switch_mode", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the auto switch mode is enabled or not.
|
||||
*
|
||||
* @param auto_switch_mode True if the auto switch mode is enabled, else false.
|
||||
*/
|
||||
public void set_auto_switch_mode(boolean auto_switch_mode)
|
||||
{
|
||||
this.config.set("auto_switch_mode", auto_switch_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the HUD is enabled.
|
||||
*
|
||||
* @return True if the HUD is enabled, else false.
|
||||
*/
|
||||
public boolean is_hud_enabled()
|
||||
{
|
||||
return this.hud_enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the HUD is enabled.
|
||||
*
|
||||
* @param enable True if the HUD is enabled, else false.
|
||||
*/
|
||||
public void set_hud_enabled(boolean enable)
|
||||
{
|
||||
this.hud_enable = enable;
|
||||
this.config.set("hud.enable", this.hud_enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the HUD side from the configuration.
|
||||
*
|
||||
* @return The HUD side.
|
||||
*/
|
||||
public @NotNull HudSide get_hud_side()
|
||||
{
|
||||
return this.hud_side;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HUD side in the configuration.
|
||||
*
|
||||
* @param hud_side The HUD side.
|
||||
*/
|
||||
public void set_hud_side(@NotNull HudSide hud_side)
|
||||
{
|
||||
this.hud_side = hud_side;
|
||||
this.config.set("hud.side", hud_side.get_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the used controller.
|
||||
*
|
||||
* @return The used controller.
|
||||
*/
|
||||
public @NotNull Controller get_controller()
|
||||
{
|
||||
Object raw = this.config.getRaw("controller.id");
|
||||
if (raw instanceof Number) {
|
||||
return Controller.by_id((Integer) raw);
|
||||
} else if (raw instanceof String) {
|
||||
return Controller.by_guid((String) raw).orElse(Controller.by_id(GLFW.GLFW_JOYSTICK_1));
|
||||
}
|
||||
return Controller.by_id(GLFW.GLFW_JOYSTICK_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the used controller.
|
||||
*
|
||||
* @param controller The used controller.
|
||||
*/
|
||||
public void set_controller(@NotNull Controller controller)
|
||||
{
|
||||
this.config.set("controller.id", controller.get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's type.
|
||||
*
|
||||
* @return The controller's type.
|
||||
*/
|
||||
public @NotNull ControllerType get_controller_type()
|
||||
{
|
||||
return this.controller_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller's type.
|
||||
*
|
||||
* @param controller_type The controller's type.
|
||||
*/
|
||||
public void set_controller_type(@NotNull ControllerType controller_type)
|
||||
{
|
||||
this.controller_type = controller_type;
|
||||
this.config.set("controller.type", controller_type.get_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's dead zone from the configuration.
|
||||
*
|
||||
* @return The controller's dead zone value.
|
||||
*/
|
||||
public double get_dead_zone()
|
||||
{
|
||||
return this.dead_zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller's dead zone in the configuration.
|
||||
*
|
||||
* @param dead_zone The new controller's dead zone value.
|
||||
*/
|
||||
public void set_dead_zone(double dead_zone)
|
||||
{
|
||||
this.dead_zone = dead_zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's rotation speed.
|
||||
*
|
||||
* @return The rotation speed.
|
||||
*/
|
||||
public double get_rotation_speed()
|
||||
{
|
||||
return this.rotation_speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller's rotation speed.
|
||||
*
|
||||
* @param rotation_speed The rotation speed.
|
||||
*/
|
||||
public void set_rotation_speed(double rotation_speed)
|
||||
{
|
||||
this.rotation_speed = rotation_speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's mouse speed.
|
||||
*
|
||||
* @return The mouse speed.
|
||||
*/
|
||||
public double get_mouse_speed()
|
||||
{
|
||||
return this.mouse_speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller's mouse speed.
|
||||
*
|
||||
* @param mouse_speed The mouse speed.
|
||||
*/
|
||||
public void set_mouse_speed(double mouse_speed)
|
||||
{
|
||||
this.mouse_speed = mouse_speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the right X axis is inverted or not.
|
||||
*
|
||||
* @return True if the right X axis is inverted, else false.
|
||||
*/
|
||||
public boolean does_invert_right_x_axis()
|
||||
{
|
||||
return this.config.getOrElse("controller.invert_right_x_axis", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the right X axis is inverted or not.
|
||||
*
|
||||
* @param invert True if the right X axis is inverted, else false.
|
||||
*/
|
||||
public void set_invert_right_x_axis(boolean invert)
|
||||
{
|
||||
this.config.set("controller.invert_right_x_axis", invert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the right Y axis is inverted or not.
|
||||
*
|
||||
* @return True if the right Y axis is inverted, else false.
|
||||
*/
|
||||
public boolean does_invert_right_y_axis()
|
||||
{
|
||||
return this.config.getOrElse("controller.invert_right_y_axis", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the right Y axis is inverted or not.
|
||||
*
|
||||
* @param invert True if the right Y axis is inverted, else false.
|
||||
*/
|
||||
public void set_invert_right_y_axis(boolean invert)
|
||||
{
|
||||
this.config.set("controller.invert_right_y_axis", invert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the right X axis sign.
|
||||
*
|
||||
* @return The right X axis sign.
|
||||
*/
|
||||
public double get_right_x_axis_sign()
|
||||
{
|
||||
return this.does_invert_right_x_axis() ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the right Y axis sign.
|
||||
*
|
||||
* @return The right Y axis sign.
|
||||
*/
|
||||
public double get_right_y_axis_sign()
|
||||
{
|
||||
return this.does_invert_right_y_axis() ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keybindings.
|
||||
*
|
||||
* @return The keybindings.
|
||||
*/
|
||||
public @NotNull Map<String, KeyBinding> get_keybindings()
|
||||
{
|
||||
return this.keybinding_mappings;
|
||||
}
|
||||
|
||||
public Optional<KeyBinding> get_keybind(@NotNull String id)
|
||||
{
|
||||
return Optional.ofNullable(this.keybinding_mappings.get(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the button binding from configuration.
|
||||
*
|
||||
* @param button The button binding.
|
||||
*/
|
||||
public void load_button_binding(@NotNull ButtonBinding button)
|
||||
{
|
||||
button.set_button(this.config.getOrElse("controller.controls." + button.get_name(), button.get_button()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the button binding in configuration.
|
||||
*
|
||||
* @param binding The button binding.
|
||||
* @param button The button.
|
||||
*/
|
||||
public void set_button_binding(@NotNull ButtonBinding binding, int button)
|
||||
{
|
||||
binding.set_button(button);
|
||||
this.config.set("controller.controls." + binding.get_name(), button);
|
||||
}
|
||||
|
||||
public boolean is_back_button(int btn, boolean is_btn, int state)
|
||||
{
|
||||
if (!is_btn && state == 0)
|
||||
return false;
|
||||
return ButtonBinding.BACK.is_button(ButtonBinding.axis_as_button(btn, state == 1));
|
||||
}
|
||||
|
||||
public boolean is_forward_button(int btn, boolean is_btn, int state)
|
||||
{
|
||||
if (!is_btn && state == 0)
|
||||
return false;
|
||||
return ButtonBinding.FORWARD.is_button(ButtonBinding.axis_as_button(btn, state == 1));
|
||||
}
|
||||
|
||||
public boolean is_left_button(int btn, boolean is_btn, int state)
|
||||
{
|
||||
if (!is_btn && state == 0)
|
||||
return false;
|
||||
return ButtonBinding.LEFT.is_button(ButtonBinding.axis_as_button(btn, state == 1));
|
||||
}
|
||||
|
||||
public boolean is_right_button(int btn, boolean is_btn, int state)
|
||||
{
|
||||
if (!is_btn && state == 0)
|
||||
return false;
|
||||
return ButtonBinding.RIGHT.is_button(ButtonBinding.axis_as_button(btn, state == 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified axis is an axis used for movements.
|
||||
*
|
||||
* @param i The axis index.
|
||||
* @return True if the axis is used for movements, else false.
|
||||
*/
|
||||
public boolean is_movement_axis(int i)
|
||||
{
|
||||
return ButtonBinding.FORWARD.is_button(ButtonBinding.axis_as_button(i, true)) || ButtonBinding.FORWARD.is_button(ButtonBinding.axis_as_button(i, false))
|
||||
|| ButtonBinding.BACK.is_button(ButtonBinding.axis_as_button(i, true)) || ButtonBinding.BACK.is_button(ButtonBinding.axis_as_button(i, false))
|
||||
|| ButtonBinding.LEFT.is_button(ButtonBinding.axis_as_button(i, true)) || ButtonBinding.LEFT.is_button(ButtonBinding.axis_as_button(i, false))
|
||||
|| ButtonBinding.RIGHT.is_button(ButtonBinding.axis_as_button(i, true)) || ButtonBinding.RIGHT.is_button(ButtonBinding.axis_as_button(i, false));
|
||||
}
|
||||
}
|
||||
@@ -1,671 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.gui.LabelWidget;
|
||||
import me.lambdaurora.lambdacontrols.gui.LambdaControlsControlsScreen;
|
||||
import me.lambdaurora.lambdacontrols.gui.TouchscreenOverlay;
|
||||
import me.lambdaurora.lambdacontrols.mixin.EntryListWidgetAccessor;
|
||||
import me.lambdaurora.lambdacontrols.util.AbstractContainerScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.util.CreativeInventoryScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor;
|
||||
import me.lambdaurora.lambdacontrols.util.MouseAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.gui.ParentElement;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
|
||||
import net.minecraft.client.gui.screen.world.WorldListWidget;
|
||||
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
|
||||
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
|
||||
import net.minecraft.client.gui.widget.SliderWidget;
|
||||
import net.minecraft.container.Slot;
|
||||
import net.minecraft.container.SlotActionType;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.aperlambda.lambdacommon.utils.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWGamepadState;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static me.lambdaurora.lambdacontrols.ButtonBinding.*;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls' input handler.
|
||||
*/
|
||||
public class LambdaInput
|
||||
{
|
||||
private static final Map<Integer, Boolean> BUTTON_STATES = new HashMap<>();
|
||||
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
|
||||
private static final Map<Integer, Boolean> AXIS_STATES = new HashMap<>();
|
||||
private static final Map<Integer, Integer> AXIS_COOLDOWNS = new HashMap<>();
|
||||
private final LambdaControlsConfig config;
|
||||
private int action_gui_cooldown = 0;
|
||||
private int ignore_next_a = 0;
|
||||
private int last_sneak = 0;
|
||||
private double prev_target_yaw = 0.0;
|
||||
private double prev_target_pitch = 0.0;
|
||||
private double target_yaw = 0.0;
|
||||
private double target_pitch = 0.0;
|
||||
private float prev_x_axis = 0.F;
|
||||
private float prev_y_axis = 0.F;
|
||||
private int prev_target_mouse_x = 0;
|
||||
private int prev_target_mouse_y = 0;
|
||||
private int target_mouse_x = 0;
|
||||
private int target_mouse_y = 0;
|
||||
private float mouse_speed_x = 0.F;
|
||||
private float mouse_speed_y = 0.F;
|
||||
|
||||
public LambdaInput(@NotNull LambdaControls mod)
|
||||
{
|
||||
this.config = mod.config;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called every Minecraft tick.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void on_tick(@NotNull MinecraftClient client)
|
||||
{
|
||||
this.prev_target_yaw = this.target_yaw;
|
||||
this.prev_target_pitch = this.target_pitch;
|
||||
|
||||
// Handles the key bindings.
|
||||
if (LambdaControls.BINDING_LOOK_UP.isPressed()) {
|
||||
this.handle_look(client, GLFW_GAMEPAD_AXIS_RIGHT_Y, 0.8F, 2);
|
||||
} else if (LambdaControls.BINDING_LOOK_DOWN.isPressed()) {
|
||||
this.handle_look(client, GLFW_GAMEPAD_AXIS_RIGHT_Y, 0.8F, 1);
|
||||
}
|
||||
if (LambdaControls.BINDING_LOOK_LEFT.isPressed()) {
|
||||
this.handle_look(client, GLFW_GAMEPAD_AXIS_RIGHT_X, 0.8F, 2);
|
||||
} else if (LambdaControls.BINDING_LOOK_RIGHT.isPressed()) {
|
||||
this.handle_look(client, GLFW_GAMEPAD_AXIS_RIGHT_X, 0.8F, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called every Minecraft tick for controller input update.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void on_controller_tick(@NotNull MinecraftClient client)
|
||||
{
|
||||
BUTTON_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0).forEach(entry -> BUTTON_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
|
||||
AXIS_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0).forEach(entry -> AXIS_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
|
||||
// Decreases the last_sneak counter which allows to double press to sneak continuously.
|
||||
if (this.last_sneak > 0)
|
||||
--this.last_sneak;
|
||||
// Decreases the cooldown for GUI actions.
|
||||
if (this.action_gui_cooldown > 0)
|
||||
--this.action_gui_cooldown;
|
||||
this.prev_target_mouse_x = this.target_mouse_x;
|
||||
this.prev_target_mouse_y = this.target_mouse_y;
|
||||
|
||||
Controller controller = this.config.get_controller();
|
||||
if (controller.is_connected()) {
|
||||
GLFWGamepadState state = controller.get_state();
|
||||
this.fetch_button_input(client, state);
|
||||
this.fetch_axe_input(client, state);
|
||||
}
|
||||
|
||||
if (this.ignore_next_a > 0)
|
||||
this.ignore_next_a--;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before the screen is rendered.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param screen The screen to render.
|
||||
*/
|
||||
public void on_pre_render_screen(@NotNull MinecraftClient client, @NotNull Screen screen)
|
||||
{
|
||||
if (!is_screen_interactive(screen)) {
|
||||
if (this.prev_target_mouse_x != this.target_mouse_x || this.prev_target_mouse_y != this.target_mouse_y) {
|
||||
double mouse_x = this.prev_target_mouse_x + (this.target_mouse_x - this.prev_target_mouse_x) * client.getTickDelta() + 0.5;
|
||||
double mouse_y = this.prev_target_mouse_y + (this.target_mouse_y - this.prev_target_mouse_y) * client.getTickDelta() + 0.5;
|
||||
GLFW.glfwSetCursorPos(client.getWindow().getHandle(), mouse_x, mouse_y);
|
||||
((MouseAccessor) client.mouse).on_cursor_pos(client.getWindow().getHandle(), mouse_x, mouse_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when Minecraft renders.
|
||||
*
|
||||
* @param client The client instance.
|
||||
*/
|
||||
public void on_render(@NotNull MinecraftClient client)
|
||||
{
|
||||
if ((client.currentScreen == null || client.currentScreen instanceof TouchscreenOverlay) &&
|
||||
(this.prev_target_yaw != this.target_yaw || this.prev_target_pitch != this.target_pitch)) {
|
||||
float delta_yaw = (float) ((this.target_yaw - client.player.prevYaw) * client.getTickDelta());
|
||||
float delta_pitch = (float) ((this.target_pitch - client.player.prevPitch) * client.getTickDelta());
|
||||
float rotation_yaw = client.player.prevYaw + delta_yaw;
|
||||
float rotation_pitch = client.player.prevPitch + delta_pitch;
|
||||
client.player.yaw = rotation_yaw;
|
||||
client.player.pitch = MathHelper.clamp(rotation_pitch, -90.F, 90.F);
|
||||
if (client.player.isRiding()) {
|
||||
client.player.getVehicle().copyPositionAndRotation(client.player);
|
||||
}
|
||||
client.getTutorialManager().onUpdateMouse(delta_pitch, delta_yaw);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when a Screen is opened.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param window_width The window width.
|
||||
* @param window_height The window height.
|
||||
*/
|
||||
public void on_screen_open(@NotNull MinecraftClient client, int window_width, int window_height)
|
||||
{
|
||||
if (client.currentScreen == null) {
|
||||
this.mouse_speed_x = this.mouse_speed_y = 0.0F;
|
||||
this.target_mouse_x = this.prev_target_mouse_x = (int) (window_width / 2.F);
|
||||
this.target_mouse_y = this.prev_target_mouse_y = (int) (window_height / 2.F);
|
||||
}
|
||||
}
|
||||
|
||||
private void fetch_button_input(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepad_state)
|
||||
{
|
||||
ByteBuffer buffer = gamepad_state.buttons();
|
||||
for (int btn = 0; btn < buffer.limit(); btn++) {
|
||||
boolean btn_state = buffer.get() == (byte) 1;
|
||||
boolean previous_state = BUTTON_STATES.getOrDefault(btn, false);
|
||||
|
||||
ButtonBinding.set_button_state(btn, btn_state);
|
||||
|
||||
if (btn_state != previous_state) {
|
||||
this.handle_button(client, btn, btn_state ? 0 : 1, btn_state);
|
||||
if (btn_state)
|
||||
BUTTON_COOLDOWNS.put(btn, 5);
|
||||
} else if (btn_state) {
|
||||
if (BUTTON_COOLDOWNS.getOrDefault(btn, 0) == 0) {
|
||||
BUTTON_COOLDOWNS.put(btn, 5);
|
||||
this.handle_button(client, btn, 2, true);
|
||||
}
|
||||
}
|
||||
|
||||
BUTTON_STATES.put(btn, btn_state);
|
||||
}
|
||||
}
|
||||
|
||||
private void fetch_axe_input(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepad_state)
|
||||
{
|
||||
FloatBuffer buffer = gamepad_state.axes();
|
||||
for (int i = 0; i < buffer.limit(); i++) {
|
||||
float value = buffer.get();
|
||||
float abs_value = Math.abs(value);
|
||||
|
||||
if (i == GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y)
|
||||
value *= -1.0F;
|
||||
|
||||
ButtonBinding.set_button_state(axis_as_button(i, true), value > 0.5F);
|
||||
ButtonBinding.set_button_state(axis_as_button(i, false), value < -0.5F);
|
||||
|
||||
int state = value > this.config.get_dead_zone() ? 1 : (value < -this.config.get_dead_zone() ? 2 : 0);
|
||||
this.handle_axe(client, i, value, abs_value, state);
|
||||
}
|
||||
}
|
||||
|
||||
private void handle_button(@NotNull MinecraftClient client, int button, int action, boolean state)
|
||||
{
|
||||
if (client.currentScreen instanceof LambdaControlsControlsScreen && action == 0) {
|
||||
LambdaControlsControlsScreen controls_screen = (LambdaControlsControlsScreen) client.currentScreen;
|
||||
if (controls_screen.focused_binding != null) {
|
||||
this.config.set_button_binding(controls_screen.focused_binding, button);
|
||||
controls_screen.focused_binding = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (action == 0 || action == 2) {
|
||||
// Handles RB and LB buttons.
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER || button == GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER) {
|
||||
this.handle_rb_lb(client, button == GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER);
|
||||
return;
|
||||
}
|
||||
|
||||
if (client.currentScreen != null && is_screen_interactive(client.currentScreen)
|
||||
&& (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN
|
||||
|| button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)) {
|
||||
if (this.action_gui_cooldown == 0) {
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP) {
|
||||
this.change_focus(client.currentScreen, false);
|
||||
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN) {
|
||||
this.change_focus(client.currentScreen, true);
|
||||
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT) {
|
||||
this.handle_left_right(client.currentScreen, false);
|
||||
} else {
|
||||
this.handle_left_right(client.currentScreen, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (action == 0) {
|
||||
// Handles when the player presses the Start button.
|
||||
if (PAUSE_GAME.is_button(button)) {
|
||||
// If in game, then pause the game.
|
||||
if (client.currentScreen == null)
|
||||
client.openPauseMenu(false);
|
||||
else if (client.currentScreen instanceof AbstractContainerScreen) // If the current screen is a container then close it.
|
||||
client.player.closeContainer();
|
||||
else// Else just close the current screen.
|
||||
client.currentScreen.onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null) {
|
||||
if (this.action_gui_cooldown == 0) {
|
||||
Element focused = client.currentScreen.getFocused();
|
||||
if (focused != null && is_screen_interactive(client.currentScreen)) {
|
||||
if (this.handle_a_button(client.currentScreen, focused)) {
|
||||
this.action_gui_cooldown = 5; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (client.currentScreen instanceof AbstractContainerScreen && client.interactionManager != null && client.player != null) {
|
||||
double pos_x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
|
||||
double pos_y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
|
||||
Slot slot = ((AbstractContainerScreenAccessor) client.currentScreen).get_slot_at(pos_x, pos_y);
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && slot != null) {
|
||||
client.interactionManager.clickSlot(((AbstractContainerScreen) client.currentScreen).getContainer().syncId, slot.id, GLFW.GLFW_MOUSE_BUTTON_1, SlotActionType.PICKUP, client.player);
|
||||
this.action_gui_cooldown = 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(((AbstractContainerScreen) 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(((AbstractContainerScreen) 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) {
|
||||
client.currentScreen.onClose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handles sneak button.
|
||||
if (SNEAK.is_button(button) && client.player != null) {
|
||||
this.toggle_sneaking(client);
|
||||
}
|
||||
}
|
||||
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !is_screen_interactive(client.currentScreen) && this.action_gui_cooldown == 0 && this.ignore_next_a == 0) {
|
||||
double mouse_x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
|
||||
double mouse_y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
|
||||
if (action == 0) {
|
||||
client.currentScreen.mouseClicked(mouse_x, mouse_y, GLFW.GLFW_MOUSE_BUTTON_1);
|
||||
} else if (action == 1) {
|
||||
client.currentScreen.mouseReleased(mouse_x, mouse_y, GLFW.GLFW_MOUSE_BUTTON_1);
|
||||
}
|
||||
this.action_gui_cooldown = 5;
|
||||
return;
|
||||
}
|
||||
|
||||
if (client.currentScreen == null && action != 2) {
|
||||
ButtonBinding.handle_button(client, button, action);
|
||||
}
|
||||
}
|
||||
|
||||
private void handle_axe(@NotNull MinecraftClient client, int axis, float value, float abs_value, int state)
|
||||
{
|
||||
int as_button_state = value > 0.5F ? 1 : (value < -0.5F ? 2 : 0);
|
||||
|
||||
if (client.currentScreen instanceof LambdaControlsControlsScreen && as_button_state != 0
|
||||
&& !(as_button_state == 2 && (axis == GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axis == GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER))) {
|
||||
LambdaControlsControlsScreen controls_screen = (LambdaControlsControlsScreen) client.currentScreen;
|
||||
if (controls_screen.focused_binding != null) {
|
||||
this.config.set_button_binding(controls_screen.focused_binding, axis_as_button(axis, as_button_state == 1));
|
||||
controls_screen.focused_binding = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
double dead_zone = this.config.get_dead_zone();
|
||||
if (client.currentScreen == null) {
|
||||
{
|
||||
int axis_minus = axis + 100;
|
||||
boolean current_plus_state = as_button_state == 1;
|
||||
boolean current_minus_state = as_button_state == 2;
|
||||
boolean previous_plus_state = AXIS_STATES.getOrDefault(axis, false);
|
||||
boolean previous_minus_state = AXIS_STATES.getOrDefault(axis_minus, false);
|
||||
|
||||
if (current_plus_state != previous_plus_state) {
|
||||
ButtonBinding.handle_button(client, ButtonBinding.axis_as_button(axis, true), 0);
|
||||
if (current_plus_state)
|
||||
AXIS_COOLDOWNS.put(axis, 5);
|
||||
} else if (current_plus_state) {
|
||||
if (AXIS_COOLDOWNS.getOrDefault(axis, 0) == 0) {
|
||||
AXIS_COOLDOWNS.put(axis, 5);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_minus_state != previous_minus_state) {
|
||||
ButtonBinding.handle_button(client, ButtonBinding.axis_as_button(axis, false), 0);
|
||||
if (current_minus_state)
|
||||
AXIS_COOLDOWNS.put(axis_minus, 5);
|
||||
} else if (current_minus_state) {
|
||||
if (AXIS_COOLDOWNS.getOrDefault(axis_minus, 0) == 0) {
|
||||
AXIS_COOLDOWNS.put(axis_minus, 5);
|
||||
}
|
||||
}
|
||||
|
||||
AXIS_STATES.put(axis, current_plus_state);
|
||||
AXIS_STATES.put(axis_minus, current_minus_state);
|
||||
}
|
||||
|
||||
// Handles the look direction.
|
||||
this.handle_look(client, axis, abs_value, state);
|
||||
} else {
|
||||
boolean allow_mouse_control = true;
|
||||
|
||||
if (this.action_gui_cooldown == 0 && this.config.is_movement_axis(axis) && is_screen_interactive(client.currentScreen)) {
|
||||
if (this.config.is_forward_button(axis, false, as_button_state)) {
|
||||
allow_mouse_control = this.change_focus(client.currentScreen, false);
|
||||
} else if (this.config.is_back_button(axis, false, as_button_state)) {
|
||||
allow_mouse_control = this.change_focus(client.currentScreen, true);
|
||||
} else if (this.config.is_left_button(axis, false, as_button_state)) {
|
||||
allow_mouse_control = this.handle_left_right(client.currentScreen, false);
|
||||
} else if (this.config.is_right_button(axis, false, as_button_state)) {
|
||||
allow_mouse_control = this.handle_left_right(client.currentScreen, true);
|
||||
}
|
||||
}
|
||||
|
||||
float movement_x = 0.0F;
|
||||
float movement_y = 0.0F;
|
||||
|
||||
if (this.config.is_back_button(axis, false, (value > 0 ? 1 : 2))) {
|
||||
movement_y = abs_value;
|
||||
} else if (this.config.is_forward_button(axis, false, (value > 0 ? 1 : 2))) {
|
||||
movement_y = -abs_value;
|
||||
} else if (this.config.is_left_button(axis, false, (value > 0 ? 1 : 2))) {
|
||||
movement_x = -abs_value;
|
||||
} else if (this.config.is_right_button(axis, false, (value > 0 ? 1 : 2))) {
|
||||
movement_x = abs_value;
|
||||
}
|
||||
|
||||
if (client.currentScreen != null && allow_mouse_control) {
|
||||
boolean moving = Math.abs(movement_y) >= dead_zone || Math.abs(movement_x) >= dead_zone;
|
||||
if (moving) {
|
||||
/*
|
||||
Updates the target mouse position when the initial movement stick movement is detected.
|
||||
It prevents the cursor to jump to the old target mouse position if the user moves the cursor with the mouse.
|
||||
*/
|
||||
if (Math.abs(prev_x_axis) < dead_zone && Math.abs(prev_y_axis) < dead_zone) {
|
||||
double mouse_x = client.mouse.getX();
|
||||
double mouse_y = client.mouse.getY();
|
||||
prev_target_mouse_x = target_mouse_x = (int) mouse_x;
|
||||
prev_target_mouse_y = target_mouse_y = (int) mouse_y;
|
||||
}
|
||||
|
||||
if (Math.abs(movement_x) >= dead_zone)
|
||||
this.mouse_speed_x = movement_x;
|
||||
else
|
||||
this.mouse_speed_x = 0.F;
|
||||
|
||||
if (Math.abs(movement_y) >= dead_zone)
|
||||
this.mouse_speed_y = movement_y;
|
||||
else
|
||||
this.mouse_speed_y = 0.F;
|
||||
} else {
|
||||
this.mouse_speed_x = 0.F;
|
||||
this.mouse_speed_y = 0.F;
|
||||
}
|
||||
|
||||
if (Math.abs(this.mouse_speed_x) > .05F || Math.abs(this.mouse_speed_y) > .05F) {
|
||||
this.target_mouse_x += this.mouse_speed_x * this.config.get_mouse_speed();
|
||||
this.target_mouse_x = MathHelper.clamp(this.target_mouse_x, 0, client.getWindow().getWidth());
|
||||
this.target_mouse_y += this.mouse_speed_y * this.config.get_mouse_speed();
|
||||
this.target_mouse_y = MathHelper.clamp(this.target_mouse_y, 0, client.getWindow().getHeight());
|
||||
}
|
||||
|
||||
this.move_mouse_to_closest_slot(client, client.currentScreen);
|
||||
}
|
||||
|
||||
this.prev_x_axis = movement_x;
|
||||
this.prev_y_axis = movement_y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the press on RB on LB.
|
||||
*
|
||||
* @param client The client's instance.
|
||||
* @param right True if RB is pressed, else false.
|
||||
*/
|
||||
private void handle_rb_lb(@NotNull MinecraftClient client, boolean right)
|
||||
{
|
||||
// When ingame
|
||||
if (client.currentScreen == null && client.player != null) {
|
||||
if (right)
|
||||
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 8 ? 0 : client.player.inventory.selectedSlot + 1;
|
||||
else
|
||||
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 0 ? 8 : client.player.inventory.selectedSlot - 1;
|
||||
} else if (client.currentScreen instanceof CreativeInventoryScreen) {
|
||||
CreativeInventoryScreenAccessor creative_inventory = (CreativeInventoryScreenAccessor) client.currentScreen;
|
||||
int current_selected_tab = creative_inventory.get_selected_tab();
|
||||
int next_tab = current_selected_tab + (right ? 1 : -1);
|
||||
if (next_tab < 0)
|
||||
next_tab = ItemGroup.GROUPS.length - 1;
|
||||
else if (next_tab >= ItemGroup.GROUPS.length)
|
||||
next_tab = 0;
|
||||
creative_inventory.set_selected_tab(ItemGroup.GROUPS[next_tab]);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handle_a_button(@NotNull Screen screen, @NotNull Element focused)
|
||||
{
|
||||
if (focused instanceof AbstractPressableButtonWidget) {
|
||||
AbstractPressableButtonWidget button_widget = (AbstractPressableButtonWidget) focused;
|
||||
button_widget.playDownSound(MinecraftClient.getInstance().getSoundManager());
|
||||
button_widget.onPress();
|
||||
return true;
|
||||
} else if (focused instanceof LabelWidget) {
|
||||
((LabelWidget) focused).on_press();
|
||||
return true;
|
||||
} else if (focused instanceof WorldListWidget) {
|
||||
WorldListWidget list = (WorldListWidget) focused;
|
||||
list.method_20159().ifPresent(WorldListWidget.Entry::play);
|
||||
return true;
|
||||
} else if (focused instanceof MultiplayerServerListWidget) {
|
||||
MultiplayerServerListWidget list = (MultiplayerServerListWidget) focused;
|
||||
MultiplayerServerListWidget.Entry entry = list.getSelected();
|
||||
if (entry instanceof MultiplayerServerListWidget.LanServerEntry || entry instanceof MultiplayerServerListWidget.ServerEntry) {
|
||||
((MultiplayerScreen) screen).select(entry);
|
||||
((MultiplayerScreen) screen).connect();
|
||||
}
|
||||
} else if (focused instanceof ParentElement) {
|
||||
Element child_focused = ((ParentElement) focused).getFocused();
|
||||
if (child_focused != null)
|
||||
return this.handle_a_button(screen, child_focused);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the left and right buttons.
|
||||
*
|
||||
* @param screen The current screen.
|
||||
* @param right True if the right button is pressed, else false.
|
||||
*/
|
||||
private boolean handle_left_right(@NotNull Screen screen, boolean right)
|
||||
{
|
||||
Element focused = screen.getFocused();
|
||||
if (focused != null)
|
||||
if (this.handle_right_left_element(focused, right))
|
||||
return this.change_focus(screen, right);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handle_right_left_element(@NotNull Element element, boolean right)
|
||||
{
|
||||
if (element instanceof SliderWidget) {
|
||||
SliderWidget slider = (SliderWidget) element;
|
||||
slider.keyPressed(right ? 262 : 263, 0, 0);
|
||||
this.action_gui_cooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
|
||||
return false;
|
||||
} else if (element instanceof AlwaysSelectedEntryListWidget) {
|
||||
((EntryListWidgetAccessor) element).move_selection(right ? 1 : -1);
|
||||
return false;
|
||||
} else if (element instanceof ParentElement) {
|
||||
ParentElement entry_list = (ParentElement) element;
|
||||
Element focused = entry_list.getFocused();
|
||||
if (focused == null)
|
||||
return true;
|
||||
return this.handle_right_left_element(focused, right);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles whether the player is sneaking.
|
||||
*
|
||||
* @param client The client's instance.
|
||||
*/
|
||||
private void toggle_sneaking(@NotNull MinecraftClient client)
|
||||
{
|
||||
((KeyBindingAccessor) client.options.keySneak).handle_press_state(!client.options.keySneak.isPressed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the look direction input.
|
||||
*
|
||||
* @param client The client isntance.
|
||||
* @param axis The axis to change.
|
||||
* @param value The value of the look.
|
||||
* @param state The state.
|
||||
*/
|
||||
public void handle_look(@NotNull MinecraftClient client, int axis, float value, int state)
|
||||
{
|
||||
// Handles the look direction.
|
||||
if (client.player != null) {
|
||||
double pow_value = Math.pow(value, 2.0);
|
||||
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
|
||||
if (state == 2) {
|
||||
this.target_pitch = client.player.pitch - this.config.get_right_y_axis_sign() * (this.config.get_rotation_speed() * pow_value) * 0.33D;
|
||||
this.target_pitch = MathHelper.clamp(this.target_pitch, -90.0D, 90.0D);
|
||||
} else if (state == 1) {
|
||||
this.target_pitch = client.player.pitch + this.config.get_right_y_axis_sign() * (this.config.get_rotation_speed() * pow_value) * 0.33D;
|
||||
this.target_pitch = MathHelper.clamp(this.target_pitch, -90.0D, 90.0D);
|
||||
}
|
||||
}
|
||||
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) {
|
||||
if (state == 2) {
|
||||
this.target_yaw = client.player.yaw - this.config.get_right_x_axis_sign() * (this.config.get_rotation_speed() * pow_value) * 0.33D;
|
||||
} else if (state == 1) {
|
||||
this.target_yaw = client.player.yaw + this.config.get_right_x_axis_sign() * (this.config.get_rotation_speed() * pow_value) * 0.33D;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean change_focus(@NotNull Screen screen, boolean down)
|
||||
{
|
||||
if (!screen.changeFocus(down)) {
|
||||
if (screen.changeFocus(down)) {
|
||||
this.action_gui_cooldown = 5;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
this.action_gui_cooldown = 5;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean is_screen_interactive(@NotNull Screen screen)
|
||||
{
|
||||
return !(screen instanceof AdvancementsScreen || screen instanceof AbstractContainerScreen);
|
||||
}
|
||||
|
||||
// Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686.
|
||||
private void move_mouse_to_closest_slot(@NotNull MinecraftClient client, @Nullable Screen screen)
|
||||
{
|
||||
// Makes the mouse attracted to slots. This helps with selecting items when using a controller.
|
||||
if (screen instanceof AbstractContainerScreen) {
|
||||
AbstractContainerScreen inventory_screen = (AbstractContainerScreen) screen;
|
||||
AbstractContainerScreenAccessor accessor = (AbstractContainerScreenAccessor) inventory_screen;
|
||||
int gui_left = accessor.get_x();
|
||||
int gui_top = accessor.get_y();
|
||||
int mouse_x = (int) (target_mouse_x * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
|
||||
int mouse_y = (int) (target_mouse_y * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight());
|
||||
|
||||
// Finds the closest slot in the GUI within 14 pixels.
|
||||
Optional<Pair<Slot, Double>> closest_slot = inventory_screen.getContainer().slotList.parallelStream()
|
||||
.map(slot -> {
|
||||
int pos_x = gui_left + slot.xPosition + 8;
|
||||
int pos_y = gui_top + slot.yPosition + 8;
|
||||
|
||||
// Distance between the slot and the cursor.
|
||||
double distance = Math.sqrt(Math.pow(pos_x - mouse_x, 2) + Math.pow(pos_y - mouse_y, 2));
|
||||
return Pair.of(slot, distance);
|
||||
}).filter(entry -> entry.get_value() <= 14.0)
|
||||
.min(Comparator.comparingDouble(Pair::get_value));
|
||||
|
||||
if (closest_slot.isPresent()) {
|
||||
Slot slot = closest_slot.get().get_key();
|
||||
if (slot.hasStack() || !client.player.inventory.getMainHandStack().isEmpty()) {
|
||||
int slot_center_x_scaled = gui_left + slot.xPosition + 8;
|
||||
int slot_center_y_scaled = gui_top + slot.yPosition + 8;
|
||||
int slot_center_x = (int) (slot_center_x_scaled / ((double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()));
|
||||
int slot_center_y = (int) (slot_center_y_scaled / ((double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()));
|
||||
double delta_x = slot_center_x - target_mouse_x;
|
||||
double delta_y = slot_center_y - target_mouse_y;
|
||||
|
||||
if (mouse_x != slot_center_x_scaled || mouse_y != slot_center_y_scaled) {
|
||||
this.target_mouse_x += delta_x * 0.75;
|
||||
this.target_mouse_y += delta_y * 0.75;
|
||||
} else {
|
||||
this.mouse_speed_x *= 0.3F;
|
||||
this.mouse_speed_y *= 0.3F;
|
||||
}
|
||||
this.mouse_speed_x *= .75F;
|
||||
this.mouse_speed_y *= .75F;
|
||||
} else {
|
||||
this.mouse_speed_x *= .1F;
|
||||
this.mouse_speed_y *= .1F;
|
||||
}
|
||||
} else {
|
||||
this.mouse_speed_x *= .3F;
|
||||
this.mouse_speed_y *= .3F;
|
||||
}
|
||||
} else {
|
||||
this.mouse_speed_x = 0.F;
|
||||
this.mouse_speed_y = 0.F;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a button with an icon instead of text.
|
||||
*/
|
||||
public abstract class AbstractIconButtonWidget extends ButtonWidget
|
||||
{
|
||||
private int icon_size = 0;
|
||||
|
||||
public AbstractIconButtonWidget(int x, int y, int width, int height, @NotNull String message, @NotNull PressAction on_press)
|
||||
{
|
||||
super(x, y, width, height, message, on_press);
|
||||
}
|
||||
|
||||
protected abstract int render_icon(int mouse_x, int mouse_y, float delta, int x, int y);
|
||||
|
||||
@Override
|
||||
public void renderButton(int mouse_x, int mouse_y, float delta)
|
||||
{
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
client.getTextureManager().bindTexture(WIDGETS_LOCATION);
|
||||
RenderSystem.color4f(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
int i = this.getYImage(this.isHovered());
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
|
||||
this.blit(this.x, this.y, 0, 46 + i * 20, this.width / 2, this.height);
|
||||
this.blit(this.x + this.width / 2, this.y, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
|
||||
this.renderBg(client, mouse_x, mouse_y);
|
||||
|
||||
this.icon_size = this.render_icon(mouse_x, mouse_y, delta, this.x + 4, this.y + (this.height / 2 - this.icon_size / 2));
|
||||
|
||||
if (!this.getMessage().isEmpty()) {
|
||||
int j = this.active ? 16777215 : 10526880;
|
||||
this.drawCenteredString(client.textRenderer, this.getMessage(), this.x + 8 + this.icon_size + (this.width - 8 - this.icon_size - 6) / 2,
|
||||
this.y + (this.height - 8) / 2, j | MathHelper.ceil(this.alpha * 255.0F) << 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a controller button widget.
|
||||
*/
|
||||
public class ControllerButtonWidget extends AbstractIconButtonWidget
|
||||
{
|
||||
private ButtonBinding binding;
|
||||
|
||||
public ControllerButtonWidget(int x, int y, int width, @NotNull ButtonBinding button_binding, @NotNull PressAction on_press)
|
||||
{
|
||||
super(x, y, width, 20, ButtonBinding.get_localized_button_name(button_binding.get_button()), on_press);
|
||||
this.binding = button_binding;
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
this.setMessage(ButtonBinding.get_localized_button_name(binding.get_button()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int render_icon(int mouse_x, int mouse_y, float delta, int x, int y)
|
||||
{
|
||||
return LambdaControls.draw_button(x, y, this.binding, MinecraftClient.getInstance());
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ButtonBinding;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.gui.widget.ElementListWidget;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.util.Formatting;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a control list widget.
|
||||
*/
|
||||
public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Entry>
|
||||
{
|
||||
private final LambdaControlsControlsScreen gui;
|
||||
private int field_2733;
|
||||
|
||||
public ControlsListWidget(@NotNull LambdaControlsControlsScreen gui, @NotNull MinecraftClient client)
|
||||
{
|
||||
super(client, gui.width + 45, gui.height, 43, gui.height - 32, 24);
|
||||
this.gui = gui;
|
||||
|
||||
ButtonBinding.stream_categories()
|
||||
.sorted(Comparator.comparingInt(ButtonBinding.Category::get_priority))
|
||||
.forEach(category -> {
|
||||
this.addEntry(new CategoryEntry(category));
|
||||
|
||||
category.get_bindings().forEach(binding -> {
|
||||
int i = client.textRenderer.getStringWidth(I18n.translate(binding.get_translation_key()));
|
||||
if (i > this.field_2733) {
|
||||
this.field_2733 = i;
|
||||
}
|
||||
|
||||
this.addEntry(new ControlsListWidget.ButtonBindingEntry(binding));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getScrollbarPosition()
|
||||
{
|
||||
return super.getScrollbarPosition() + 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowWidth()
|
||||
{
|
||||
return super.getRowWidth() + 32;
|
||||
}
|
||||
|
||||
public class ButtonBindingEntry extends Entry
|
||||
{
|
||||
private final ButtonBinding binding;
|
||||
private final String binding_name;
|
||||
private final ControllerButtonWidget edit_button;
|
||||
private final ButtonWidget reset_button;
|
||||
|
||||
ButtonBindingEntry(@NotNull ButtonBinding binding)
|
||||
{
|
||||
this.binding = binding;
|
||||
this.binding_name = I18n.translate(this.binding.get_translation_key());
|
||||
this.edit_button = new ControllerButtonWidget(0, 0, 90, this.binding, btn -> gui.focused_binding = binding)
|
||||
{
|
||||
protected String getNarrationMessage()
|
||||
{
|
||||
return binding.is_not_bound() ? I18n.translate("narrator.controls.unbound", binding_name) : I18n.translate("narrator.controls.bound", binding_name, super.getNarrationMessage());
|
||||
}
|
||||
};
|
||||
this.reset_button = new ButtonWidget(0, 0, 50, 20, I18n.translate("controls.reset"),
|
||||
btn -> gui.mod.config.set_button_binding(binding, binding.get_default_button()))
|
||||
{
|
||||
protected String getNarrationMessage()
|
||||
{
|
||||
return I18n.translate("narrator.controls.reset", binding_name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Element> children()
|
||||
{
|
||||
return Collections.unmodifiableList(Arrays.asList(this.edit_button, this.reset_button));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int index, int y, int x, int width, int height, int mouse_x, int mouse_y, boolean hovering, float delta)
|
||||
{
|
||||
boolean focused = gui.focused_binding == this.binding;
|
||||
TextRenderer text_renderer = ControlsListWidget.this.minecraft.textRenderer;
|
||||
String binding_name = this.binding_name;
|
||||
float var10002 = (float) (x + 70 - ControlsListWidget.this.field_2733);
|
||||
int var10003 = y + height / 2;
|
||||
text_renderer.draw(binding_name, var10002, (float) (var10003 - 9 / 2), 16777215);
|
||||
this.reset_button.x = x + 190;
|
||||
this.reset_button.y = y;
|
||||
this.reset_button.active = !this.binding.is_default();
|
||||
this.reset_button.render(mouse_x, mouse_y, delta);
|
||||
this.edit_button.x = x + 85;
|
||||
this.edit_button.y = y;
|
||||
this.edit_button.update();
|
||||
|
||||
if (focused) {
|
||||
this.edit_button.setMessage(Formatting.WHITE + "> " + Formatting.YELLOW + this.edit_button.getMessage() + Formatting.WHITE + " <");
|
||||
} else if (!this.binding.is_not_bound() && ButtonBinding.has_duplicates(this.binding.get_button())) {
|
||||
this.edit_button.setMessage(Formatting.RED + this.edit_button.getMessage());
|
||||
} else if (this.binding.is_not_bound()) {
|
||||
this.edit_button.setMessage(Formatting.GOLD + edit_button.getMessage());
|
||||
}
|
||||
|
||||
this.edit_button.render(mouse_x, mouse_y, delta);
|
||||
}
|
||||
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button)
|
||||
{
|
||||
if (this.edit_button.mouseClicked(mouseX, mouseY, button))
|
||||
return true;
|
||||
else
|
||||
return this.reset_button.mouseClicked(mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
public boolean mouseReleased(double mouseX, double mouseY, int button)
|
||||
{
|
||||
return this.edit_button.mouseReleased(mouseX, mouseY, button) || this.reset_button.mouseReleased(mouseX, mouseY, button);
|
||||
}
|
||||
}
|
||||
|
||||
public class CategoryEntry extends Entry
|
||||
{
|
||||
private final String name;
|
||||
private final int name_width;
|
||||
|
||||
public CategoryEntry(@NotNull ButtonBinding.Category category)
|
||||
{
|
||||
this.name = category.get_translated_name();
|
||||
this.name_width = ControlsListWidget.this.minecraft.textRenderer.getStringWidth(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int index, int y, int x, int width, int height, int mouse_x, int mouse_y, boolean hovering, float delta)
|
||||
{
|
||||
ControlsListWidget.this.minecraft.textRenderer.draw(this.name, (float) (ControlsListWidget.this.minecraft.currentScreen.width / 2 - this.name_width / 2),
|
||||
(float) ((y + height) - 9 - 1), 16777215);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changeFocus(boolean bl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Element> children()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public abstract static class Entry extends ElementListWidget.Entry<Entry>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.Drawable;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.render.Tessellator;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.util.math.Matrix4f;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Represents a label widget.
|
||||
*/
|
||||
// @TODO move this to a GUI library.
|
||||
public class LabelWidget extends DrawableHelper implements Element, Drawable
|
||||
{
|
||||
public static final Consumer<LabelWidget> DEFAULT_ACTION = label -> {
|
||||
};
|
||||
|
||||
private final MinecraftClient client = MinecraftClient.getInstance();
|
||||
private final Consumer<LabelWidget> press_action;
|
||||
private final int x;
|
||||
private final int y;
|
||||
private final int max_width;
|
||||
//private final int max_height;
|
||||
private String text;
|
||||
private String tooltip_text;
|
||||
public boolean visible;
|
||||
private int width;
|
||||
private int height;
|
||||
private boolean centered;
|
||||
protected boolean hovered;
|
||||
protected boolean focused;
|
||||
|
||||
public LabelWidget(int x, int y, @NotNull String text, int max_width, @NotNull Consumer<LabelWidget> press_action, boolean centered)
|
||||
{
|
||||
this.visible = true;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.max_width = max_width;
|
||||
this.press_action = press_action;
|
||||
this.centered = centered;
|
||||
this.set_text(text);
|
||||
}
|
||||
|
||||
public LabelWidget(int x, int y, @NotNull String text, int max_width, @NotNull Consumer<LabelWidget> press_action)
|
||||
{
|
||||
this(x, y, text, max_width, press_action, false);
|
||||
}
|
||||
|
||||
public LabelWidget(int x, int y, @NotNull String text, int max_width, boolean centered)
|
||||
{
|
||||
this(x, y, text, max_width, DEFAULT_ACTION, centered);
|
||||
}
|
||||
|
||||
public LabelWidget(int x, int y, @NotNull String text, int max_width)
|
||||
{
|
||||
this(x, y, text, max_width, DEFAULT_ACTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of this label.
|
||||
*
|
||||
* @param text The text to set.
|
||||
*/
|
||||
public void set_text(@NotNull String text)
|
||||
{
|
||||
int width = this.client.textRenderer.getStringWidth(text);
|
||||
while (width > this.max_width) {
|
||||
text = text.substring(0, text.length() - 1);
|
||||
width = this.client.textRenderer.getStringWidth(text);
|
||||
}
|
||||
|
||||
this.text = text;
|
||||
this.width = width;
|
||||
this.height = this.client.textRenderer.fontHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tooltip text of this label.
|
||||
*
|
||||
* @param text The tooltip text.
|
||||
*/
|
||||
public void set_tooltip_text(String text)
|
||||
{
|
||||
this.tooltip_text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width of this label widget.
|
||||
*
|
||||
* @return The width of this label widget.
|
||||
*/
|
||||
public int get_width()
|
||||
{
|
||||
return this.width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of this label widget.
|
||||
*
|
||||
* @return The height of this label widget.
|
||||
*/
|
||||
public int get_height()
|
||||
{
|
||||
return this.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the press event on this label widget.
|
||||
*/
|
||||
public void on_press()
|
||||
{
|
||||
this.press_action.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouse_x, int mouse_y, float delta)
|
||||
{
|
||||
if (this.visible) {
|
||||
int x = this.centered ? this.x - this.client.textRenderer.getStringWidth(this.text) / 2 : this.x;
|
||||
this.hovered = mouse_x >= x && mouse_y >= this.y && mouse_x < x + this.width && mouse_y < this.y + this.height;
|
||||
this.drawString(this.client.textRenderer, this.text, x, this.y, 10526880);
|
||||
|
||||
if (this.tooltip_text != null && !this.tooltip_text.isEmpty()) {
|
||||
List<String> wrapped_tooltip_text = this.client.textRenderer.wrapStringToWidthAsList(this.tooltip_text, Math.max(this.width / 2, 200));
|
||||
if (this.hovered)
|
||||
this.render_tooltip(wrapped_tooltip_text, mouse_x, mouse_y);
|
||||
else if (this.focused)
|
||||
this.render_tooltip(wrapped_tooltip_text, this.x - 12, this.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouse_x, double mouse_y, int button)
|
||||
{
|
||||
if (this.visible && button == GLFW.GLFW_MOUSE_BUTTON_1) {
|
||||
if (this.hovered) {
|
||||
this.on_press();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changeFocus(boolean down)
|
||||
{
|
||||
if (this.visible) {
|
||||
this.focused = !this.focused;
|
||||
return this.focused;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void render_tooltip(List<String> text, int x, int y)
|
||||
{
|
||||
if (!text.isEmpty()) {
|
||||
RenderSystem.disableRescaleNormal();
|
||||
RenderSystem.disableDepthTest();
|
||||
int i = 0;
|
||||
|
||||
for (String string : text) {
|
||||
int j = this.client.textRenderer.getStringWidth(string);
|
||||
if (j > i) {
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
int k = x + 12;
|
||||
int l = y - 12;
|
||||
int n = 8;
|
||||
if (text.size() > 1) {
|
||||
n += 2 + (text.size() - 1) * 10;
|
||||
}
|
||||
|
||||
if (k + i > this.client.getWindow().getScaledWidth()) {
|
||||
k -= 28 + i;
|
||||
}
|
||||
|
||||
if (l + n + 6 > this.client.getWindow().getScaledHeight()) {
|
||||
l = this.client.getWindow().getScaledHeight() - n - 6;
|
||||
}
|
||||
|
||||
this.setBlitOffset(300);
|
||||
this.client.getItemRenderer().zOffset = 300.0F;
|
||||
this.fillGradient(k - 3, l - 4, k + i + 3, l - 3, -267386864, -267386864);
|
||||
this.fillGradient(k - 3, l + n + 3, k + i + 3, l + n + 4, -267386864, -267386864);
|
||||
this.fillGradient(k - 3, l - 3, k + i + 3, l + n + 3, -267386864, -267386864);
|
||||
this.fillGradient(k - 4, l - 3, k - 3, l + n + 3, -267386864, -267386864);
|
||||
this.fillGradient(k + i + 3, l - 3, k + i + 4, l + n + 3, -267386864, -267386864);
|
||||
this.fillGradient(k - 3, l - 3 + 1, k - 3 + 1, l + n + 3 - 1, 1347420415, 1344798847);
|
||||
this.fillGradient(k + i + 2, l - 3 + 1, k + i + 3, l + n + 3 - 1, 1347420415, 1344798847);
|
||||
this.fillGradient(k - 3, l - 3, k + i + 3, l - 3 + 1, 1347420415, 1347420415);
|
||||
this.fillGradient(k - 3, l + n + 2, k + i + 3, l + n + 3, 1344798847, 1344798847);
|
||||
MatrixStack matrix_stack = new MatrixStack();
|
||||
VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer());
|
||||
matrix_stack.translate(0.0D, 0.0D, this.client.getItemRenderer().zOffset);
|
||||
Matrix4f matrix4f = matrix_stack.peek().getModel();
|
||||
|
||||
for (int r = 0; r < text.size(); ++r) {
|
||||
String string2 = text.get(r);
|
||||
if (string2 != null) {
|
||||
this.client.textRenderer.draw(string2, (float) k, (float) l, -1, true, matrix4f, immediate, false, 0, 15728880);
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
l += 2;
|
||||
}
|
||||
|
||||
l += 10;
|
||||
}
|
||||
|
||||
immediate.draw();
|
||||
this.setBlitOffset(0);
|
||||
this.client.getItemRenderer().zOffset = 0.0F;
|
||||
RenderSystem.enableDepthTest();
|
||||
RenderSystem.enableRescaleNormal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.options.BooleanOption;
|
||||
import net.minecraft.client.options.Option;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Represents the controls screen.
|
||||
*/
|
||||
public class LambdaControlsControlsScreen extends Screen
|
||||
{
|
||||
private final LambdaControlsSettingsScreen parent;
|
||||
final LambdaControls mod;
|
||||
private final Option inverts_right_x_axis;
|
||||
private final Option inverts_right_y_axis;
|
||||
private ControlsListWidget bindings_list_widget;
|
||||
private ButtonWidget reset_button;
|
||||
public ButtonBinding focused_binding;
|
||||
|
||||
protected LambdaControlsControlsScreen(@NotNull LambdaControlsSettingsScreen parent)
|
||||
{
|
||||
super(new TranslatableText("lambdacontrols.menu.title.controller_controls"));
|
||||
this.parent = parent;
|
||||
this.mod = parent.mod;
|
||||
this.inverts_right_x_axis = new BooleanOption("lambdacontrols.menu.invert_right_x_axis", game_options -> this.mod.config.does_invert_right_x_axis(),
|
||||
(game_options, new_value) -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.set_invert_right_x_axis(new_value);
|
||||
}
|
||||
});
|
||||
this.inverts_right_y_axis = new BooleanOption("lambdacontrols.menu.invert_right_y_axis", game_options -> this.mod.config.does_invert_right_y_axis(),
|
||||
(game_options, new_value) -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.set_invert_right_y_axis(new_value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed()
|
||||
{
|
||||
this.mod.config.save();
|
||||
super.removed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
this.addButton(this.inverts_right_x_axis.createButton(this.minecraft.options, this.width / 2 - 155, 18, 150));
|
||||
this.addButton(this.inverts_right_y_axis.createButton(this.minecraft.options, this.width / 2 - 155 + 160, 18, 150));
|
||||
this.bindings_list_widget = new ControlsListWidget(this, this.minecraft);
|
||||
this.children.add(this.bindings_list_widget);
|
||||
this.reset_button = this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 150, 20, I18n.translate("controls.resetAll"),
|
||||
btn -> ButtonBinding.stream().forEach(binding -> this.mod.config.set_button_binding(binding, binding.get_default_button()))));
|
||||
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20, I18n.translate("gui.done"),
|
||||
btn -> this.minecraft.openScreen(this.parent)));
|
||||
}
|
||||
|
||||
// Replacement for Predicate#not as it is Java 11.
|
||||
private <T> Predicate<T> not(Predicate<T> target)
|
||||
{
|
||||
Objects.requireNonNull(target);
|
||||
return target.negate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouse_x, int mouse_y, float delta)
|
||||
{
|
||||
this.renderBackground();
|
||||
this.bindings_list_widget.render(mouse_x, mouse_y, delta);
|
||||
this.drawCenteredString(this.font, this.title.asFormattedString(), this.width / 2, 8, 16777215);
|
||||
this.reset_button.active = ButtonBinding.stream().anyMatch(this.not(ButtonBinding::is_default));
|
||||
super.render(mouse_x, mouse_y, delta);
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ButtonBinding;
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls HUD.
|
||||
*/
|
||||
public class LambdaControlsHud extends DrawableHelper
|
||||
{
|
||||
private final MinecraftClient client;
|
||||
private final LambdaControls mod;
|
||||
|
||||
public LambdaControlsHud(@NotNull MinecraftClient client, @NotNull LambdaControls mod)
|
||||
{
|
||||
this.client = client;
|
||||
this.mod = mod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the LambdaControls' HUD.
|
||||
*/
|
||||
public void render()
|
||||
{
|
||||
if (this.mod.config.get_controls_mode() == ControlsMode.CONTROLLER && this.mod.config.is_hud_enabled() && this.client.currentScreen == null && !this.client.options.hudHidden) {
|
||||
int x = 10, y = bottom(10);
|
||||
x += this.draw_button_tip(x, y, ButtonBinding.INVENTORY, true) + 10;
|
||||
this.draw_button_tip(x, y, ButtonBinding.SWAP_HANDS, true);
|
||||
x = 10;
|
||||
x += this.draw_button_tip(x, (y -= 20), ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()) + 10;
|
||||
this.draw_button_tip(x, y, ButtonBinding.ATTACK.get_button(),
|
||||
this.client.crosshairTarget.getType() == HitResult.Type.BLOCK ? "lambdacontrols.action.hit" : ButtonBinding.ATTACK.get_translation_key(),
|
||||
this.client.crosshairTarget.getType() != HitResult.Type.MISS);
|
||||
}
|
||||
}
|
||||
|
||||
private int bottom(int y)
|
||||
{
|
||||
return this.client.getWindow().getScaledHeight() - y - 15;
|
||||
}
|
||||
|
||||
private int draw_button_tip(int x, int y, @NotNull ButtonBinding button, boolean display)
|
||||
{
|
||||
return LambdaControls.draw_button_tip(x, y, button, display, this.client);
|
||||
}
|
||||
|
||||
private int draw_button_tip(int x, int y, int button, @NotNull String action, boolean display)
|
||||
{
|
||||
return LambdaControls.draw_button_tip(x, y, button, action, display, this.client);
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.Controller;
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
|
||||
import net.minecraft.client.gui.widget.ButtonListWidget;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.options.*;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Util;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
/**
|
||||
* Represents the LambdaControls settings screen.
|
||||
*/
|
||||
public class LambdaControlsSettingsScreen extends Screen
|
||||
{
|
||||
public static final String GAMEPAD_TOOL_URL = "http://generalarcade.com/gamepadtool/";
|
||||
final LambdaControls mod;
|
||||
private final Screen parent;
|
||||
private final GameOptions options;
|
||||
private final Option auto_switch_mode_option;
|
||||
private final Option controller_option;
|
||||
private final Option controller_type_option;
|
||||
private final Option dead_zone_option;
|
||||
private final Option hud_enable_option;
|
||||
private final Option hud_side_option;
|
||||
private final Option mouse_speed_option;
|
||||
private final Option rotation_speed_option;
|
||||
private final String controller_mappings_url_text = I18n.translate("lambdacontrols.controller.mappings.2", Formatting.GOLD.toString(), GAMEPAD_TOOL_URL, Formatting.RESET.toString());
|
||||
private ButtonListWidget list;
|
||||
private LabelWidget gamepad_tool_url_label;
|
||||
|
||||
public LambdaControlsSettingsScreen(Screen parent, @NotNull GameOptions options)
|
||||
{
|
||||
super(new TranslatableText("lambdacontrols.title.settings"));
|
||||
this.mod = LambdaControls.get();
|
||||
this.parent = parent;
|
||||
this.options = options;
|
||||
this.auto_switch_mode_option = new BooleanOption("lambdacontrols.menu.auto_switch_mode", game_options -> this.mod.config.has_auto_switch_mode(),
|
||||
(game_options, new_value) -> this.mod.config.set_auto_switch_mode(new_value));
|
||||
this.controller_option = new CyclingOption("lambdacontrols.menu.controller", (game_options, amount) -> {
|
||||
int current_id = this.mod.config.get_controller().get_id();
|
||||
current_id += amount;
|
||||
if (current_id > GLFW.GLFW_JOYSTICK_LAST)
|
||||
current_id = GLFW.GLFW_JOYSTICK_1;
|
||||
this.mod.config.set_controller(Controller.by_id(current_id));
|
||||
}, (game_options, option) -> {
|
||||
String controller_name = this.mod.config.get_controller().get_name();
|
||||
if (!this.mod.config.get_controller().is_connected())
|
||||
return option.getDisplayPrefix() + Formatting.RED + controller_name;
|
||||
else if (!this.mod.config.get_controller().is_gamepad())
|
||||
return option.getDisplayPrefix() + Formatting.GOLD + controller_name;
|
||||
else
|
||||
return option.getDisplayPrefix() + controller_name;
|
||||
});
|
||||
this.controller_type_option = new CyclingOption("lambdacontrols.menu.controller_type",
|
||||
(game_options, amount) -> this.mod.config.set_controller_type(this.mod.config.get_controller_type().next()),
|
||||
(game_options, option) -> option.getDisplayPrefix() + this.mod.config.get_controller_type().get_translated_name());
|
||||
this.hud_enable_option = new BooleanOption("lambdacontrols.menu.hud_enable", (game_options) -> this.mod.config.is_hud_enabled(),
|
||||
(game_options, new_value) -> this.mod.config.set_hud_enabled(new_value));
|
||||
this.hud_side_option = new CyclingOption("lambdacontrols.menu.hud_side",
|
||||
(game_options, amount) -> this.mod.config.set_hud_side(this.mod.config.get_hud_side().next()),
|
||||
(game_options, option) -> option.getDisplayPrefix() + this.mod.config.get_hud_side().get_translated_name());
|
||||
this.dead_zone_option = new DoubleOption("lambdacontrols.menu.dead_zone", 0.05, 1.0, 0.05F, game_options -> this.mod.config.get_dead_zone(),
|
||||
(game_options, new_value) -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.set_dead_zone(new_value);
|
||||
}
|
||||
}, (game_options, option) -> {
|
||||
String value = String.valueOf(option.get(options));
|
||||
return option.getDisplayPrefix() + value.substring(0, Math.min(value.length(), 5));
|
||||
});
|
||||
this.rotation_speed_option = new DoubleOption("lambdacontrols.menu.rotation_speed", 0.0, 50.0, 0.5F, game_options -> this.mod.config.get_rotation_speed(),
|
||||
(game_options, new_value) -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.set_rotation_speed(new_value);
|
||||
}
|
||||
}, (game_options, option) -> option.getDisplayPrefix() + option.get(options));
|
||||
this.mouse_speed_option = new DoubleOption("lambdacontrols.menu.mouse_speed", 0.0, 50.0, 0.5F, game_options -> this.mod.config.get_mouse_speed(),
|
||||
(game_options, new_value) -> {
|
||||
synchronized (this.mod.config) {
|
||||
this.mod.config.set_mouse_speed(new_value);
|
||||
}
|
||||
}, (game_options, option) -> option.getDisplayPrefix() + option.get(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed()
|
||||
{
|
||||
this.mod.config.save();
|
||||
super.removed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
this.mod.config.save();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
private int get_text_height()
|
||||
{
|
||||
return (5 + this.font.fontHeight) * 3 + 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init();
|
||||
int button_height = 20;
|
||||
this.addButton(new ButtonWidget(this.width / 2 - 155, 18, 150, button_height, I18n.translate("lambdacontrols.menu.controls_mode") + ": " + this.mod.config.get_controls_mode().get_translated_name(),
|
||||
btn -> {
|
||||
ControlsMode next = this.mod.config.get_controls_mode().next();
|
||||
btn.setMessage(I18n.translate("lambdacontrols.menu.controls_mode") + ": " + next.get_translated_name());
|
||||
this.mod.config.set_controls_mode(next);
|
||||
this.mod.config.save();
|
||||
}));
|
||||
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, 18, 150, button_height, I18n.translate("options.controls"),
|
||||
btn -> {
|
||||
if (this.mod.config.get_controls_mode() == ControlsMode.CONTROLLER)
|
||||
this.minecraft.openScreen(new LambdaControlsControlsScreen(this));
|
||||
else
|
||||
this.minecraft.openScreen(new ControlsOptionsScreen(this, this.options));
|
||||
}));
|
||||
|
||||
this.list = new ButtonListWidget(this.minecraft, this.width, this.height, 43, this.height - 29 - this.get_text_height(), 25);
|
||||
this.list.addSingleOptionEntry(this.controller_option);
|
||||
this.list.addOptionEntry(this.controller_type_option, this.dead_zone_option);
|
||||
this.list.addOptionEntry(this.hud_enable_option, this.hud_side_option);
|
||||
this.list.addOptionEntry(this.rotation_speed_option, this.mouse_speed_option);
|
||||
this.list.addSingleOptionEntry(this.auto_switch_mode_option);
|
||||
this.list.addSingleOptionEntry(new ReloadControllerMappingsOption());
|
||||
this.children.add(this.list);
|
||||
|
||||
this.gamepad_tool_url_label = new LabelWidget(this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 2, this.controller_mappings_url_text, this.width,
|
||||
label -> Util.getOperatingSystem().open(GAMEPAD_TOOL_URL), true);
|
||||
this.gamepad_tool_url_label.set_tooltip_text(I18n.translate("chat.link.open"));
|
||||
this.children.add(this.gamepad_tool_url_label);
|
||||
|
||||
this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 300, button_height, I18n.translate("gui.done"),
|
||||
(buttonWidget) -> this.minecraft.openScreen(this.parent)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouse_x, int mouse_y, float delta)
|
||||
{
|
||||
this.renderBackground();
|
||||
this.list.render(mouse_x, mouse_y, delta);
|
||||
super.render(mouse_x, mouse_y, delta);
|
||||
this.drawCenteredString(this.font, 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);
|
||||
this.gamepad_tool_url_label.render(mouse_x, mouse_y, 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);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import net.minecraft.client.gui.widget.TexturedButtonWidget;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Represents a touchscreen button widget.
|
||||
*/
|
||||
public class TouchscreenButtonWidget extends TexturedButtonWidget
|
||||
{
|
||||
private final Consumer<Boolean> on_change_state;
|
||||
|
||||
public TouchscreenButtonWidget(int x, int y, int width, int height, int u, int v, int hovered_v_offset, Identifier texture, @NotNull Consumer<Boolean> on_changed_state)
|
||||
{
|
||||
super(x, y, width, height, u, v, hovered_v_offset, texture, 256, 256, btn -> on_changed_state.accept(true));
|
||||
this.on_change_state = on_changed_state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(double mouseX, double mouseY)
|
||||
{
|
||||
super.onRelease(mouseX, mouseY);
|
||||
this.on_change_state.accept(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button)
|
||||
{
|
||||
if (this.active && this.visible) {
|
||||
if (this.isValidClickButton(button)) {
|
||||
boolean clicked = this.clicked(mouseX, mouseY);
|
||||
if (clicked) {
|
||||
this.onClick(mouseX, mouseY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY)
|
||||
{
|
||||
super.onDrag(mouseX, mouseY, deltaX, deltaY);
|
||||
if (this.active && !this.isHovered)
|
||||
this.on_change_state.accept(false);
|
||||
}
|
||||
}
|
||||
@@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.gui;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.HudSide;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor;
|
||||
import net.minecraft.client.gui.screen.ChatScreen;
|
||||
import net.minecraft.client.gui.screen.GameMenuScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.gui.widget.TexturedButtonWidget;
|
||||
import net.minecraft.server.network.packet.PlayerActionC2SPacket;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Arm;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
|
||||
|
||||
/**
|
||||
* Represents the touchscreen overlay
|
||||
*/
|
||||
public class TouchscreenOverlay extends Screen
|
||||
{
|
||||
public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png");
|
||||
private LambdaControls mod;
|
||||
private TouchscreenButtonWidget jump_button;
|
||||
private TouchscreenButtonWidget fly_button;
|
||||
private TouchscreenButtonWidget fly_up_button;
|
||||
private TouchscreenButtonWidget fly_down_button;
|
||||
private int fly_button_enable_ticks = 0;
|
||||
private int forward_button_tick = 0;
|
||||
private TouchscreenButtonWidget forward_left_button;
|
||||
private TouchscreenButtonWidget forward_right_button;
|
||||
private TouchscreenButtonWidget start_sneak_button;
|
||||
private TouchscreenButtonWidget end_sneak_button;
|
||||
|
||||
public TouchscreenOverlay(@NotNull LambdaControls mod)
|
||||
{
|
||||
super(new LiteralText("Touchscreen overlay"));
|
||||
this.mod = mod;
|
||||
this.passEvents = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPauseScreen()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private void pause_game(boolean bl)
|
||||
{
|
||||
if (this.minecraft == null)
|
||||
return;
|
||||
boolean bl2 = this.minecraft.isIntegratedServerRunning() && !this.minecraft.getServer().isRemote();
|
||||
if (bl2) {
|
||||
this.minecraft.openScreen(new GameMenuScreen(!bl));
|
||||
this.minecraft.getSoundManager().pauseAll();
|
||||
} else {
|
||||
this.minecraft.openScreen(new GameMenuScreen(true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the forward button ticks cooldown.
|
||||
*
|
||||
* @param state The button state.
|
||||
*/
|
||||
private void update_forward_buttons_state(boolean state)
|
||||
{
|
||||
if (state)
|
||||
this.forward_button_tick = -1;
|
||||
else
|
||||
this.forward_button_tick = 20;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the jump buttons.
|
||||
*/
|
||||
private void update_jump_buttons()
|
||||
{
|
||||
if (this.minecraft == null)
|
||||
return;
|
||||
if (this.minecraft.player.abilities.allowFlying && this.minecraft.player.abilities.flying) {
|
||||
boolean old_state_fly = this.fly_button.visible;
|
||||
this.jump_button.visible = false;
|
||||
this.fly_button.visible = true;
|
||||
this.fly_up_button.visible = true;
|
||||
this.fly_down_button.visible = true;
|
||||
if (old_state_fly != this.fly_button.visible) {
|
||||
this.fly_button_enable_ticks = 5;
|
||||
this.handle_jump(false);
|
||||
} else if (this.fly_button_enable_ticks > 0)
|
||||
this.fly_button_enable_ticks--;
|
||||
} else {
|
||||
this.jump_button.visible = true;
|
||||
this.fly_button.visible = false;
|
||||
this.fly_up_button.visible = false;
|
||||
this.fly_down_button.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the jump button.
|
||||
*
|
||||
* @param state The state of the jump button.
|
||||
*/
|
||||
private void handle_jump(boolean state)
|
||||
{
|
||||
((KeyBindingAccessor) this.minecraft.options.keyJump).handle_press_state(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick()
|
||||
{
|
||||
if (this.forward_button_tick > 0) {
|
||||
this.forward_button_tick--;
|
||||
} else if (this.forward_button_tick == 0) {
|
||||
if (this.forward_left_button.visible)
|
||||
this.forward_left_button.visible = false;
|
||||
if (this.forward_right_button.visible)
|
||||
this.forward_right_button.visible = false;
|
||||
}
|
||||
this.update_jump_buttons();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init();
|
||||
int scaled_width = this.minecraft.getWindow().getScaledWidth();
|
||||
int scaled_height = this.minecraft.getWindow().getScaledHeight();
|
||||
this.addButton(new TexturedButtonWidget(scaled_width / 2 - 20, 0, 20, 20, 0, 106, 20, ButtonWidget.WIDGETS_LOCATION, 256, 256,
|
||||
btn -> this.minecraft.openScreen(new ChatScreen("")), ""));
|
||||
this.addButton(new TexturedButtonWidget(scaled_width / 2, 0, 20, 20, 0, 0, 20, WIDGETS_LOCATION, 256, 256,
|
||||
btn -> this.pause_game(false)));
|
||||
// Inventory buttons.
|
||||
int inventory_button_x = scaled_width / 2;
|
||||
int inventory_button_y = scaled_height - 16 - 5;
|
||||
if (this.minecraft.options.mainArm == Arm.LEFT) {
|
||||
inventory_button_x = inventory_button_x - 91 - 24;
|
||||
} else {
|
||||
inventory_button_x = inventory_button_x + 91 + 4;
|
||||
}
|
||||
this.addButton(new TexturedButtonWidget(inventory_button_x, inventory_button_y, 20, 20, 20, 0, 20, WIDGETS_LOCATION, 256, 256,
|
||||
btn -> {
|
||||
if (this.minecraft.interactionManager.hasRidingInventory()) {
|
||||
this.minecraft.player.openRidingInventory();
|
||||
} else {
|
||||
this.minecraft.getTutorialManager().onInventoryOpened();
|
||||
this.minecraft.openScreen(new InventoryScreen(this.minecraft.player));
|
||||
}
|
||||
}));
|
||||
int jump_button_x, swap_hands_x, sneak_button_x;
|
||||
int sneak_button_y = scaled_height - 10 - 40 - 5;
|
||||
if (this.mod.config.get_hud_side() == HudSide.LEFT) {
|
||||
jump_button_x = scaled_width - 20 - 20;
|
||||
swap_hands_x = jump_button_x - 5 - 40;
|
||||
sneak_button_x = 10 + 20 + 5;
|
||||
} else {
|
||||
jump_button_x = 20;
|
||||
swap_hands_x = jump_button_x + 5 + 40;
|
||||
sneak_button_x = scaled_width - 10 - 40 - 5;
|
||||
}
|
||||
// Swap items hand.
|
||||
this.addButton(new TouchscreenButtonWidget(swap_hands_x, sneak_button_y, 20, 20, 0, 160, 20, WIDGETS_LOCATION,
|
||||
state -> {
|
||||
if (state) {
|
||||
if (!this.minecraft.player.isSpectator()) {
|
||||
this.minecraft.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_HELD_ITEMS, BlockPos.ORIGIN, Direction.DOWN));
|
||||
}
|
||||
}
|
||||
}));
|
||||
// Drop
|
||||
this.addButton(new TouchscreenButtonWidget(swap_hands_x, sneak_button_y + 5 + 20, 20, 20, 20, 160, 20, WIDGETS_LOCATION,
|
||||
state -> ((KeyBindingAccessor) this.minecraft.options.keyDrop).handle_press_state(state)));
|
||||
// Jump keys
|
||||
this.addButton(this.jump_button = new TouchscreenButtonWidget(jump_button_x, sneak_button_y, 20, 20, 0, 40, 20, WIDGETS_LOCATION,
|
||||
this::handle_jump));
|
||||
this.addButton(this.fly_button = new TouchscreenButtonWidget(jump_button_x, sneak_button_y, 20, 20, 20, 40, 20, WIDGETS_LOCATION,
|
||||
state -> {
|
||||
if (this.fly_button_enable_ticks == 0) this.minecraft.player.abilities.flying = false;
|
||||
}));
|
||||
this.addButton(this.fly_up_button = new TouchscreenButtonWidget(jump_button_x, sneak_button_y - 5 - 20, 20, 20, 40, 40, 20, WIDGETS_LOCATION,
|
||||
this::handle_jump));
|
||||
this.addButton(this.fly_down_button = new TouchscreenButtonWidget(jump_button_x, sneak_button_y + 20 + 5, 20, 20, 60, 40, 20, WIDGETS_LOCATION,
|
||||
state -> ((KeyBindingAccessor) this.minecraft.options.keySneak).handle_press_state(state)));
|
||||
this.update_jump_buttons();
|
||||
// Movements keys
|
||||
this.addButton((this.start_sneak_button = new TouchscreenButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 0, 120, 20, WIDGETS_LOCATION,
|
||||
state -> {
|
||||
if (state) {
|
||||
((KeyBindingAccessor) this.minecraft.options.keySneak).handle_press_state(true);
|
||||
this.start_sneak_button.visible = false;
|
||||
this.end_sneak_button.visible = true;
|
||||
}
|
||||
})));
|
||||
this.addButton((this.end_sneak_button = new TouchscreenButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 20, 120, 20, WIDGETS_LOCATION,
|
||||
state -> {
|
||||
if (state) {
|
||||
((KeyBindingAccessor) this.minecraft.options.keySneak).handle_press_state(false);
|
||||
this.end_sneak_button.visible = false;
|
||||
this.start_sneak_button.visible = true;
|
||||
}
|
||||
})));
|
||||
this.end_sneak_button.visible = false;
|
||||
this.addButton(this.forward_left_button = new TouchscreenButtonWidget(sneak_button_x - 20 - 5, sneak_button_y - 5 - 20, 20, 20, 80, 80, 20, WIDGETS_LOCATION,
|
||||
state -> {
|
||||
((KeyBindingAccessor) this.minecraft.options.keyForward).handle_press_state(state);
|
||||
((KeyBindingAccessor) this.minecraft.options.keyLeft).handle_press_state(state);
|
||||
this.update_forward_buttons_state(state);
|
||||
}));
|
||||
this.forward_left_button.visible = false;
|
||||
this.addButton(new TouchscreenButtonWidget(sneak_button_x, sneak_button_y - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION,
|
||||
state -> {
|
||||
((KeyBindingAccessor) this.minecraft.options.keyForward).handle_press_state(state);
|
||||
this.update_forward_buttons_state(state);
|
||||
this.forward_left_button.visible = true;
|
||||
this.forward_right_button.visible = true;
|
||||
}));
|
||||
this.addButton(this.forward_right_button = new TouchscreenButtonWidget(sneak_button_x + 20 + 5, sneak_button_y - 5 - 20, 20, 20, 100, 80, 20, WIDGETS_LOCATION,
|
||||
state -> {
|
||||
((KeyBindingAccessor) this.minecraft.options.keyForward).handle_press_state(state);
|
||||
((KeyBindingAccessor) this.minecraft.options.keyRight).handle_press_state(state);
|
||||
this.update_forward_buttons_state(state);
|
||||
}));
|
||||
this.forward_right_button.visible = true;
|
||||
this.addButton(new TouchscreenButtonWidget(sneak_button_x + 20 + 5, sneak_button_y, 20, 20, 20, 80, 20, WIDGETS_LOCATION,
|
||||
state -> ((KeyBindingAccessor) this.minecraft.options.keyRight).handle_press_state(state)));
|
||||
this.addButton(new TouchscreenButtonWidget(sneak_button_x, sneak_button_y + 20 + 5, 20, 20, 40, 80, 20, WIDGETS_LOCATION,
|
||||
state -> ((KeyBindingAccessor) this.minecraft.options.keyBack).handle_press_state(state)));
|
||||
this.addButton(new TouchscreenButtonWidget(sneak_button_x - 20 - 5, sneak_button_y, 20, 20, 60, 80, 20, WIDGETS_LOCATION,
|
||||
state -> ((KeyBindingAccessor) this.minecraft.options.keyLeft).handle_press_state(state)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouseX, int mouseY, float delta)
|
||||
{
|
||||
super.render(mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouse_x, double mouse_y, int button)
|
||||
{
|
||||
if (mouse_y >= (double) (this.height - 22) && this.minecraft != null && this.minecraft.player != null) {
|
||||
int center_x = this.width / 2;
|
||||
if (mouse_x >= (double) (center_x - 90) && mouse_x <= (double) (center_x + 90)) {
|
||||
for (int slot = 0; slot < 9; ++slot) {
|
||||
int slot_x = center_x - 90 + slot * 20 + 2;
|
||||
if (mouse_x >= (double) slot_x && mouse_x <= (double) (slot_x + 20)) {
|
||||
this.minecraft.player.inventory.selectedSlot = slot;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.mouseClicked(mouse_x, mouse_y, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(double mouse_x, double mouse_y, int button, double delta_x, double delta_y)
|
||||
{
|
||||
if (button == GLFW.GLFW_MOUSE_BUTTON_1 && this.minecraft != null) {
|
||||
if (delta_y > 0.01)
|
||||
this.mod.input.handle_look(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(delta_y / 5.0), 2);
|
||||
else if (delta_y < 0.01)
|
||||
this.mod.input.handle_look(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(delta_y / 5.0), 1);
|
||||
|
||||
if (delta_x > 0.01)
|
||||
this.mod.input.handle_look(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(delta_x / 5.0), 2);
|
||||
else if (delta_x < 0.01)
|
||||
this.mod.input.handle_look(this.minecraft, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(delta_x / 5.0), 1);
|
||||
}
|
||||
return super.mouseDragged(mouse_x, mouse_y, button, delta_x, delta_y);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.util.AbstractContainerScreenAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen;
|
||||
import net.minecraft.container.Slot;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Represents the mixin for the class AbstractContainerScreen.
|
||||
*/
|
||||
@Mixin(AbstractContainerScreen.class)
|
||||
public abstract class AbstractContainerScreenMixin implements AbstractContainerScreenAccessor
|
||||
{
|
||||
protected int x;
|
||||
|
||||
protected int y;
|
||||
|
||||
@Shadow
|
||||
protected abstract Slot getSlotAt(double xPosition, double yPosition);
|
||||
|
||||
@Override
|
||||
public int get_x()
|
||||
{
|
||||
return this.x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_y()
|
||||
{
|
||||
return this.y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slot get_slot_at(double pos_x, double pos_y)
|
||||
{
|
||||
return this.getSlotAt(pos_x, pos_y);
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At("RETURN"))
|
||||
public void render(int mouseX, int mouseY, float delta, CallbackInfo ci)
|
||||
{
|
||||
if (LambdaControls.get().config.get_controls_mode() == ControlsMode.CONTROLLER) {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
int x = 10, y = client.getWindow().getScaledHeight() - 10 - 15;
|
||||
|
||||
x += LambdaControls.draw_button_tip(x, y, GLFW.GLFW_GAMEPAD_BUTTON_A, "lambdacontrols.action.pickup_all", true, client) + 10;
|
||||
x += LambdaControls.draw_button_tip(x, y, GLFW.GLFW_GAMEPAD_BUTTON_B, "lambdacontrols.action.exit", true, client) + 10;
|
||||
x += LambdaControls.draw_button_tip(x, y, GLFW.GLFW_GAMEPAD_BUTTON_X, "lambdacontrols.action.pickup", true, client) + 10;
|
||||
LambdaControls.draw_button_tip(x, y, GLFW.GLFW_GAMEPAD_BUTTON_Y, "lambdacontrols.action.quick_move", true, client);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.util.CreativeInventoryScreenAccessor;
|
||||
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(CreativeInventoryScreen.class)
|
||||
public abstract class CreativeInventoryScreenMixin implements CreativeInventoryScreenAccessor
|
||||
{
|
||||
@Shadow
|
||||
protected abstract void setSelectedTab(ItemGroup itemGroup);
|
||||
|
||||
@Accessor("selectedTab")
|
||||
public abstract int get_selected_tab();
|
||||
|
||||
@Override
|
||||
public void set_selected_tab(@NotNull ItemGroup group)
|
||||
{
|
||||
this.setSelectedTab(group);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.gui.LambdaControlsHud;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.hud.InGameHud;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(InGameHud.class)
|
||||
public class InGameHudMixin
|
||||
{
|
||||
private LambdaControlsHud lambdacontrols_hud;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
public void on_new(MinecraftClient client, CallbackInfo ci)
|
||||
{
|
||||
this.lambdacontrols_hud = new LambdaControlsHud(client, LambdaControls.get());
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;renderMountHealth()V"))
|
||||
public void on_render(CallbackInfo ci)
|
||||
{
|
||||
lambdacontrols_hud.render();
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.mixin;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.ControlsMode;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControls;
|
||||
import me.lambdaurora.lambdacontrols.gui.TouchscreenOverlay;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.util.Window;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public abstract class MinecraftClientMixin
|
||||
{
|
||||
@Final
|
||||
@Shadow
|
||||
private Window window;
|
||||
|
||||
@Shadow
|
||||
public boolean skipGameRender;
|
||||
|
||||
@Shadow
|
||||
public Screen currentScreen;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void on_init(CallbackInfo ci)
|
||||
{
|
||||
LambdaControls.get().on_mc_init((MinecraftClient) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At("HEAD"))
|
||||
private void on_render(boolean full_render, CallbackInfo ci)
|
||||
{
|
||||
LambdaControls.get().on_render((MinecraftClient) (Object) (this));
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void on_handle_input_events(CallbackInfo ci)
|
||||
{
|
||||
LambdaControls.get().on_tick((MinecraftClient) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(method = "openScreen", at = @At("RETURN"))
|
||||
private void on_open_screen(@Nullable Screen screen, CallbackInfo ci)
|
||||
{
|
||||
LambdaControls mod = LambdaControls.get();
|
||||
if (screen == null && mod.config.get_controls_mode() == ControlsMode.TOUCHSCREEN) {
|
||||
screen = new TouchscreenOverlay(mod);
|
||||
screen.init(((MinecraftClient) (Object) this), this.window.getScaledWidth(), this.window.getScaledHeight());
|
||||
this.skipGameRender = false;
|
||||
this.currentScreen = screen;
|
||||
} else if (screen != null) {
|
||||
mod.input.on_screen_open(((MinecraftClient) (Object) this), this.window.getWidth(), this.window.getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.mixin;
|
||||
|
||||
import net.minecraft.client.gui.ParentElement;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Screen.class)
|
||||
public abstract class ScreenMixin implements ParentElement
|
||||
{
|
||||
@Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true)
|
||||
private void on_key_pressed(int key_code, int scan_code, int modifiers, CallbackInfoReturnable<Boolean> ci)
|
||||
{
|
||||
if (key_code == GLFW.GLFW_KEY_UP || key_code == GLFW.GLFW_KEY_LEFT) {
|
||||
this.changeFocus(false);
|
||||
ci.setReturnValue(true);
|
||||
ci.cancel();
|
||||
} else if (key_code == GLFW.GLFW_KEY_DOWN || key_code == GLFW.GLFW_KEY_RIGHT) {
|
||||
this.changeFocus(true);
|
||||
ci.setReturnValue(true);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.util;
|
||||
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents an accessor to CreativeInventoryScreen.
|
||||
*/
|
||||
public interface CreativeInventoryScreenAccessor
|
||||
{
|
||||
/**
|
||||
* Gets the selected tab.
|
||||
*
|
||||
* @return The selected tab index.
|
||||
*/
|
||||
int get_selected_tab();
|
||||
|
||||
/**
|
||||
* Sets the selected tab.
|
||||
*
|
||||
* @param group The tab's item group.
|
||||
*/
|
||||
void set_selected_tab(@NotNull ItemGroup group);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 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.util;
|
||||
|
||||
/**
|
||||
* Represents mouse's extra access.
|
||||
*/
|
||||
public interface MouseAccessor
|
||||
{
|
||||
void on_mouse_button(long window, int button, int action, int mods);
|
||||
|
||||
void on_cursor_pos(long window, double x, double y);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
# LambdaControls configuration.
|
||||
|
||||
# The controls mode. Available modes: default, controller, touchscreen
|
||||
controls = "default"
|
||||
# Auto switch mode.
|
||||
auto_switch_mode = false
|
||||
|
||||
[hud]
|
||||
# Enables the HUD.
|
||||
enable = true
|
||||
# Dertermines where the movements buttons are.
|
||||
side = "left"
|
||||
|
||||
# Controller settings
|
||||
[controller]
|
||||
# Controller to use.
|
||||
id = 0
|
||||
# Controller's type.
|
||||
type = "default"
|
||||
# Controller's dead zone.
|
||||
dead_zone = 0.20
|
||||
# Rotation speed for look directions.
|
||||
rotation_speed = 40.0
|
||||
# Mouse speed in GUI.
|
||||
mouse_speed = 30.0
|
||||
# Inverts the right X axis.
|
||||
invert_right_x_axis = false
|
||||
# Inverts the right Y axis.
|
||||
invert_right_y_axis = false
|
||||
# Controller controls.
|
||||
[controller.controls]
|
||||
# Attack control.
|
||||
attack = 105
|
||||
# Back control.
|
||||
back = 201
|
||||
# Open chat control.
|
||||
chat = 12
|
||||
# Drop item control.
|
||||
drop_item = 1
|
||||
# Forward control.
|
||||
forward = 101
|
||||
# Inventory control.
|
||||
inventory = 3
|
||||
# Jump control.
|
||||
jump = 0
|
||||
# Pause game control.
|
||||
pause_game = 7
|
||||
# Pick block control.
|
||||
pick_block = 14
|
||||
# Show player list control.
|
||||
player_list = 6
|
||||
# Take screenshot control.
|
||||
screenshot = 13
|
||||
# Sneak control.
|
||||
sneak = 10
|
||||
# Sprint control.
|
||||
sprint = 9
|
||||
# Swap hands control.
|
||||
swap_hands = 2
|
||||
# Toggle perspective control.
|
||||
toggle_perspective = 11
|
||||
# Toggle smooth camera control.
|
||||
toggle_smooth_camera = -1
|
||||
# Use control.
|
||||
use = 104
|
||||