Merge pull request #259 from TeamMidnightDust/1.20.4

Backport changes from 1.9.0+
This commit is contained in:
Martin Prokoph
2024-02-03 13:16:41 +01:00
committed by GitHub
64 changed files with 1144 additions and 763 deletions

View File

@@ -62,6 +62,14 @@ Enter the folder created and run:
```
After this is done, everything should be built just fine!
## FAQ:
### The controller does not work, and it's name appears in orange, what can I do?
Orange controller names indicate a missing controller mapping.
Download [GamepadTool](https://generalarcade.com/gamepadtool/), create and copy a mapping, go to MidnightControls' Mappings File Editor and paste the string.
Alternatively, you can use [AntiMicroX](https://github.com/AntiMicroX/antimicroX) to create the mappings, in case the Gamepad Tool is not working for you.
If that works, you might as well consider submitting the mapping by opening a PR in this repo: https://github.com/gabomdq/SDL_GameControllerDB
That will make sure other people using the same controller as you don't have to use gamepad-tool anymore.
[Quilt]: https://quiltmc.org
[Mod loader: Quilt/Fabric]: https://img.shields.io/badge/modloader-Quilt%2FFabric-blueviolet?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAADGAAAAxgGwdJvFAAAFU0lEQVR4nO1bwW7bOBCdCHtP+wUNxIvhS7yA7kkPOjf9AKPam4/OF2zzB96bblXhH0jPPkS5G1jnIvgib/IFtX/ALoYZemmKtEWRRe3aDzAsURbJGQ6HM4/02Wq1gmNGcNTSnxQA8IdakDK4AOCfJpj3SpiI98r2rAMAbxrWNWFFOMeL1nCJdXQa1gPTbpCbnm34ABIeBThv2hgAfOyVcF+2ZwkAfHGo54kVIRe6NVxiny4d6vpn2g36ugfqFLhwFB6kkUoc67k0XLv0qYKj9wEnBXiqZwEAf/ZKOOuV8BkLWBFesyI8A4C/LOt6AoC39C7HtBvg9Vt65hUnC/BUDzrOf1MGq5S9WkDZnuVle7ZqsBKgw/tO73K0hku8/u64EmhxsoA96MMvxdEroBIKO+CWoshnqqJPYTAGRJ8sql3QO3Op7D19D3z7AV8KeAGArFf+32lWhDwnKNuzuaUCclaE93KBiOU9hMQV+FLAOxz9lPHRR0VkZXs2oBDUNon5ULZnKOgcYwl4FTwna/K+CtRRwIK+dTnCCwkP9I0fkXmh4FcN+6UKqqtHblvtb+18po4TvKaPilsS8qVuYx5havsbJXS1I0ZVAXP1B5jfyzm+hAnN+We1XPluioX03kJtY9oNtG1T+b1aburDxhRAQVMGHw3z9k65F41nktmjUnjjrAj7ZXv27ECIyEKgBd7saBuka7lsPu0GA1MjR0+KVpwgMTlrMkN4YoztlZ/2camTvD0QjcWZF6KxMgcLyKbdAN+HKOb1y6PYH49gEsUwUKw1G48gi2KQZcApkYxH1eldUQBxeKbkRfXEQjDZ21+h2bMiHJDwH2wk1rSX0XWueHZd2yCZ/oVSnilTaA3VAiqjRRahQ0JBjuov3ijfPqAua0kUg67tmyjWCmvsS504wGQRnywjPJ8wtY3xw3827fjMBXziUalL3DcNrIzYRwXcTbvBZ7lgPHoNxKKYky1/+2xsHxXQbw2X/EIoggQHyjC9Yh8VcC6NshDc66jLOHpC5KSAPejDL8U+KuArboTQZgjHeARn+MFnvhvbRyfYaQ2XfNkTVFgUr/mIxlvkJuyjAjCae6BrYQUPW37vhDpT4MnAsCyIgbHBnYbcADJt7/t+deBCiSWsCG8sOv5IgU2FnJh2g+RnBDl1oCpgogqEx1TEURUFokx+tpCYnEzzjg1kh+fq/Ix9OXpG6OjjgI1VIGWcOMhlXh4PPdAz1VTe90rIU8Z/L9JUnALXSK4SjSUzOY+Y1ekyOlzjaamTvf3X8cjunBH1v6OeVtsG1QI66qYEVkoVmyA/O5fYmIHjgSsrskUavAc6q1BLeXXiANMZu0HKwGav7opGv+LticZqHOToLBeZrJRxC97qjOsowCTgZYO9OlNa25haMwgvsFMJPp3gLW1ji8b6dO89fhfYIbzAl23T4adtjyNvD6/mbbs9Xgs1hRcwWoIvCxDb47nQNm5aRDHvoPGcblNYCi+gtQSfU+AdLYfioLXYtHA9eruBhsILVJRwUIGQo/ACG0o4GAV4El5grQSffMA3SqbEnBdb1zeunfYsvAB3jL4UwE92KauA2NnNbLerNKhEqJ6Q+FIAOjpcATAVzjFHoC3qC9OurCW0W9s+6vXpAy4p0hPkSUL3ziNHiY3tqfNdQN4jORgnSEGMLyU8Udbq1QIEdEyRF3hSwlp4vKkwQimrHDuxAR6S4tleFIPzERnhSFXQEtbkD1kbwiMOlhJroISK8IiDpcQsp4NWeMRBc4I1lWAUHnHwpOgOJWwVHvFbsMIGJewUHvFb7QuQYxR/ttgIzbUAgB9KOM3uc+PN7QAAAABJRU5ErkJggg==

View File

@@ -3,25 +3,14 @@ plugins {
id 'java-library'
id 'maven-publish'
id 'com.github.johnrengelman.shadow' version '7.0.0'
id 'com.modrinth.minotaur' version '1.2.+'
id 'com.modrinth.minotaur' version '2.+'
id 'net.darkhax.curseforgegradle' version '1.+'
}
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import com.modrinth.minotaur.TaskModrinthUpload
import com.modrinth.minotaur.request.VersionType
import com.modrinth.minotaur.responses.ResponseError
import org.apache.http.client.config.CookieSpecs
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.entity.EntityBuilder
import org.apache.http.client.methods.HttpPatch
import org.apache.http.entity.ContentType
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.util.EntityUtils
import net.darkhax.curseforgegradle.TaskPublishCurseForge
group = project.maven_group
version = "${project.mod_version}+${getMCVersionString()}"
archivesBaseName = project.archives_base_name
// This field defines the Java version your mod target.
def targetJavaVersion = 17
@@ -32,7 +21,7 @@ boolean isMCVersionNonRelease() {
}
String getMCVersionString() {
if (isMCVersionNonRelease() || project.minecraft_version == "1.19.4") {
if (isMCVersionNonRelease() || project.minecraft_version == "1.20.4") {
return project.minecraft_version
}
def version = project.minecraft_version.split('\\.')
@@ -159,115 +148,39 @@ processResources {
expand 'version': project.version
}
}
task publishModrinth(type: TaskModrinthUpload) {
dependsOn(build)
onlyIf {
System.getenv('MODRINTH_TOKEN')
}
token = System.getenv('MODRINTH_TOKEN')
projectId = project.modrinth_id
versionNumber = version
versionName = "midnightcontrols ${project.mod_version} (${getMCVersionString()})"
addGameVersion((String) project.minecraft_version)
addLoader('fabric')
versionType = isMCVersionNonRelease() ? VersionType.BETA : VersionType.RELEASE
// Changelog fetching
def changelogText = file('CHANGELOG.md').text
def regexVersion = ((String) project.mod_version).replaceAll('\\.', /\\./).replaceAll('\\+', '\\+')
def changelogRegex = ~"###? ${regexVersion}\\n\\n(( *- .+\\n)+)"
def matcher = changelogText =~ changelogRegex
if (matcher.find()) {
changelog = matcher.group(1)
def changelogLines = changelogText.split('\n')
def linkRefRegex = ~'^\\[([A-z0-9 _\\-/+.]+)]: '
for (int i = changelogLines.length - 1; i > 0; i--) {
def line = changelogLines[i]
if ((line =~ linkRefRegex).find())
changelog += '\n' + line
else break
}
}
// Readme
doFirst {
final def client = HttpClientBuilder.create().setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).build()).build()
final def patch = new HttpPatch((String) (apiURL + '/v1/mod/' + projectId))
patch.addHeader("Authorization", token)
var json = new JsonObject()
json.addProperty("body", parseReadme())
patch.setEntity(EntityBuilder.create()
.setText(json.toString())
.setContentType(ContentType.APPLICATION_JSON)
.build())
final def response = client.execute(patch)
final int status = response.getStatusLine().getStatusCode()
final def gson = new GsonBuilder().create()
if (status == 200) {
project.getLogger().lifecycle("Successfully updated readme to ${projectId}.")
} else {
errorInfo = gson.fromJson(EntityUtils.toString(response.getEntity()), ResponseError.class)
project.getLogger().error("Upload failed! Status: ${status} Error: ${errorInfo.getError()} Reason: ${errorInfo.getDescription()}")
throw new GradleException("Upload failed! Status: ${status} Reason: ${errorInfo.getDescription()}")
}
modrinth {
token = System.getenv("MODRINTH_TOKEN") // Remember to have the MODRINTH_TOKEN environment variable set or else this will fail - just make sure it stays private!
projectId = project.archives_base_name // This can be the project ID or the slug. Either will work!
versionNumber = project.version // You don't need to set this manually. Will fail if Modrinth has this version already
versionName = "MidnightControls " + project.mod_version + " - " + project.minecraft_version
versionType = isMCVersionNonRelease() ? "beta" : "release" // Can also be `beta` or `alpha`
uploadFile = remapJar // With Loom, this MUST be set to `remapJar` instead of `jar`!
gameVersions = [(String) project.minecraft_version] // Must be an array, even with only one version
loaders = ["fabric","quilt"] // Must also be an array - no need to specify this if you're using Loom or ForgeGradle
dependencies { // A special DSL for creating dependencies
// scope.type
// The scope can be `required`, `optional`, `incompatible`, or `embedded`
// The type can either be `project` or `version`
required.project "midnightlib" // Creates a new required dependency on MidnightLib
}
changelog = project.changelog
}
tasks.register('publishCurseForge', TaskPublishCurseForge) {
// configure the maven publication
publishing {
publications {
mavenJava(MavenPublication) {
artifact(sourcesJar) {
builtBy remapSourcesJar
}
// This token is used to authenticate with CurseForge. It should be handled
// with the same level of care and security as your actual password. You
// should never share your token with an untrusted source or publish it
// publicly to GitHub or embed it within a project. The best practice is to
// store this token in an environment variable or a build secret.
apiToken = System.getenv("CURSEFORGE_TOKEN")
pom {
name = 'midnightcontrols'
description = 'Adds better controls, and controller support.'
}
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.shadow.allDependencies.each {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
dependencyNode.appendNode('scope', 'compile')
}
}
}
}
repositories {
mavenLocal()
maven {
name 'GithubPackages'
url uri('https://maven.pkg.github.com/LambdAurora/midnightcontrols')
credentials {
username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") ?: System.getenv("TOKEN")
}
}
def midnightcontrolsMaven = System.getenv('midnightcontrols_MAVEN')
if (midnightcontrolsMaven) {
maven {
name 'midnightcontrolsMaven'
url uri(midnightcontrolsMaven)
credentials {
username = project.findProperty('gpr.user') ?: System.getenv('MAVEN_USERNAME')
password = project.findProperty('gpr.key') ?: System.getenv('MAVEN_PASSWORD')
}
}
}
}
// Tells CurseForgeGradle to publish the output of the jar task. This will
// return a UploadArtifact object that can be used to further configure the
// file.
def mainFile = upload(project.curseforge_id, remapJar)
mainFile.changelog = project.changelog
mainFile.displayName = "MidnightControls " + project.mod_version + " - " + project.minecraft_version
mainFile.addModLoader("Fabric", "Quilt")
mainFile.addRequirement("midnightlib")
mainFile.releaseType = "release"
}

View File

@@ -3,22 +3,24 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/use
minecraft_version=1.20
yarn_mappings=1.20+build.1
loader_version=0.14.21
minecraft_version=1.20.4
yarn_mappings=1.20.4+build.3
loader_version=0.15.3
# Mod Properties
mod_version = 1.8.2
mod_version = 1.9.3
maven_group = eu.midnightdust
archives_base_name = midnightcontrols
modrinth_id=bXX9h73M
modrinth_id = bXX9h73M
curseforge_id = 621768
changelog = See changes at: https://github.com/TeamMidnightDust/MidnightControls/commits/
# 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.83.0+1.20
fabric_version=0.91.3+1.20.4
sodium_version=mc1.19.2-0.4.4
spruceui_version=5.0.0+1.20
midnightlib_version=1.4.1-fabric
spruceui_version=5.0.3+1.20.4
midnightlib_version=1.5.3-fabric
modmenu_version=7.0.0
emotecraft_version=2.1.3-SNAPSHOT-build.29-MC1.19-fabric
bendylib_version=2.0.+

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

41
gradlew vendored
View File

@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,11 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,22 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
@@ -205,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.

15
gradlew.bat vendored
View File

@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@@ -10,12 +10,12 @@
package eu.midnightdust.midnightcontrols.client;
import dev.lambdaurora.spruceui.event.OpenScreenCallback;
import eu.midnightdust.lib.util.PlatformFunctions;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.MidnightControls;
import eu.midnightdust.midnightcontrols.MidnightControlsConstants;
import eu.midnightdust.midnightcontrols.MidnightControlsFeature;
import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat;
import eu.midnightdust.midnightcontrols.client.compat.VoxelMapCompat;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.ButtonCategory;
import eu.midnightdust.midnightcontrols.client.controller.Controller;
@@ -24,10 +24,11 @@ import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsHud;
import eu.midnightdust.midnightcontrols.client.gui.RingScreen;
import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay;
import eu.midnightdust.midnightcontrols.client.mixin.KeyBindingIDAccessor;
import eu.midnightdust.midnightcontrols.client.mixin.KeyBindingRegistryImplAccessor;
import eu.midnightdust.midnightcontrols.client.ring.ButtonBindingRingAction;
import eu.midnightdust.midnightcontrols.client.ring.MidnightRing;
import dev.lambdaurora.spruceui.hud.HudManager;
import eu.midnightdust.midnightcontrols.client.touch.TouchInput;
import eu.midnightdust.midnightcontrols.client.util.RainbowColor;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
@@ -47,6 +48,7 @@ import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import java.io.File;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
@@ -59,7 +61,6 @@ import java.util.TimerTask;
*/
public class MidnightControlsClient extends MidnightControls implements ClientModInitializer {
public static boolean lateInitDone = false;
public static boolean voxelmapInitDone = false;
private static MidnightControlsClient INSTANCE;
public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(new Identifier(MidnightControlsConstants.NAMESPACE, "look_up"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement");
@@ -122,20 +123,21 @@ public class MidnightControlsClient extends MidnightControls implements ClientMo
this.input.onScreenOpen(client, client.getWindow().getWidth(), client.getWindow().getHeight());
}
});
final MinecraftClient client = MinecraftClient.getInstance();
int delay = 0; // delay for 0 sec.
int period = 1; // repeat every 0.001 sec. (100 times a second)
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
input.updateCamera(client);
}
}, delay, period);
HudManager.register(this.hud = new MidnightControlsHud(this));
FabricLoader.getInstance().getModContainer("midnightcontrols").ifPresent(modContainer -> {
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier("midnightcontrols","bedrock"), modContainer, ResourcePackActivationType.NORMAL);
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier("midnightcontrols","legacy"), modContainer, ResourcePackActivationType.NORMAL);
});
int delay = 0; // delay for 0 sec.
int period = 1; // repeat every 0.001 sec. (100 times a second)
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
input.updateCamera(MinecraftClient.getInstance());
}
}, delay, period);
}
/**
@@ -154,18 +156,20 @@ public class MidnightControlsClient extends MidnightControls implements ClientMo
}
this.hud.setVisible(MidnightControlsConfig.hudEnable);
Controller.updateMappings();
GLFW.glfwSetJoystickCallback((jid, event) -> {
if (event == GLFW.GLFW_CONNECTED) {
var controller = Controller.byId(jid);
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, Text.translatable("midnightcontrols.controller.connected", jid),
Text.literal(controller.getName())));
} else if (event == GLFW.GLFW_DISCONNECTED) {
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, Text.translatable("midnightcontrols.controller.disconnected", jid),
null));
}
try {
GLFW.glfwSetJoystickCallback((jid, event) -> {
if (event == GLFW.GLFW_CONNECTED) {
var controller = Controller.byId(jid);
client.getToastManager().add(new SystemToast(SystemToast.Type.PERIODIC_NOTIFICATION, Text.translatable("midnightcontrols.controller.connected", jid),
Text.literal(controller.getName())));
} else if (event == GLFW.GLFW_DISCONNECTED) {
client.getToastManager().add(new SystemToast(SystemToast.Type.PERIODIC_NOTIFICATION, Text.translatable("midnightcontrols.controller.disconnected", jid),
null));
}
this.switchControlsMode();
});
this.switchControlsMode();
});
} catch (Exception e) {e.fillInStackTrace();}
MidnightControlsCompat.init(this);
}
@@ -174,30 +178,28 @@ public class MidnightControlsClient extends MidnightControls implements ClientMo
* This method is called to initialize keybindings
*/
public void initKeybindings() {
if (!voxelmapInitDone && FabricLoader.getInstance().isModLoaded("voxelmap") && KeyBindingIDAccessor.getKEYS_BY_ID().containsKey("key.minimap.toggleingamewaypoints")) {
this.log("Adding VoxelMap compatibility...");
new VoxelMapCompat().handle(this);
InputManager.loadButtonBindings();
voxelmapInitDone = true;
}
if (lateInitDone) return;
if (KeyBindingRegistryImplAccessor.getMODDED_KEY_BINDINGS() == null || KeyBindingRegistryImplAccessor.getMODDED_KEY_BINDINGS().isEmpty()) return;
for (int i = 0; i < KeyBindingRegistryImplAccessor.getMODDED_KEY_BINDINGS().size(); ++i) {
KeyBinding keyBinding = KeyBindingRegistryImplAccessor.getMODDED_KEY_BINDINGS().get(i);
if (!keyBinding.getTranslationKey().contains("midnightcontrols") && !keyBinding.getTranslationKey().contains("ok_zoomer") && !keyBinding.getTranslationKey().contains("okzoomer")) {
category = null;
InputManager.streamCategories().forEach(buttonCategory -> {
if (buttonCategory.getIdentifier().equals(new org.aperlambda.lambdacommon.Identifier("minecraft", keyBinding.getCategory())))
category = buttonCategory;
});
if (category == null) {
category = new ButtonCategory(new org.aperlambda.lambdacommon.Identifier("minecraft", keyBinding.getCategory()));
InputManager.registerCategory(category);
}
ButtonBinding buttonBinding = new ButtonBinding.Builder(keyBinding.getTranslationKey()).category(category).linkKeybind(keyBinding).register();
if (MidnightControlsConfig.debug) {
logger.info(keyBinding.getTranslationKey());
logger.info(buttonBinding);
if (KeyBindingIDAccessor.getKEYS_BY_ID() == null || KeyBindingIDAccessor.getKEYS_BY_ID().isEmpty()) return;
if (PlatformFunctions.isModLoaded("voxelmap") && !KeyBindingIDAccessor.getKEYS_BY_ID().containsKey("key.minimap.toggleingamewaypoints")) return;
if (PlatformFunctions.isModLoaded("wynntils") && KeyBindingIDAccessor.getKEYS_BY_ID().entrySet().stream().noneMatch(b -> Objects.equals(b.getValue().getCategory(), "Wynntils"))) return;
for (int i = 0; i < KeyBindingIDAccessor.getKEYS_BY_ID().size(); ++i) {
KeyBinding keyBinding = KeyBindingIDAccessor.getKEYS_BY_ID().entrySet().stream().toList().get(i).getValue();
if (MidnightControlsConfig.excludedKeybindings.stream().noneMatch(excluded -> keyBinding.getTranslationKey().startsWith(excluded))) {
if (!keyBinding.getTranslationKey().contains("midnightcontrols") && !keyBinding.getTranslationKey().contains("ok_zoomer") && !keyBinding.getTranslationKey().contains("okzoomer")) {
category = null;
InputManager.streamCategories().forEach(buttonCategory -> {
if (buttonCategory.getIdentifier().equals(new org.aperlambda.lambdacommon.Identifier("minecraft", keyBinding.getCategory())))
category = buttonCategory;
});
if (category == null) {
category = new ButtonCategory(new org.aperlambda.lambdacommon.Identifier("minecraft", keyBinding.getCategory()));
InputManager.registerCategory(category);
}
ButtonBinding buttonBinding = new ButtonBinding.Builder(keyBinding.getTranslationKey()).category(category).linkKeybind(keyBinding).register();
if (MidnightControlsConfig.debug) {
logger.info(keyBinding.getTranslationKey());
logger.info(buttonBinding);
}
}
}
}
@@ -227,9 +229,8 @@ public class MidnightControlsClient extends MidnightControls implements ClientMo
MidnightControlsConfig.enableHints = false;
MidnightControlsConfig.save();
}
}
public void onRender(MinecraftClient client) {
//this.input.onRender(client);
RainbowColor.tick();
TouchInput.tick();
}
/**

View File

@@ -18,8 +18,15 @@ import eu.midnightdust.midnightcontrols.MidnightControlsFeature;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.Controller;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.enums.CameraMode;
import eu.midnightdust.midnightcontrols.client.enums.ControllerType;
import eu.midnightdust.midnightcontrols.client.enums.HudSide;
import eu.midnightdust.midnightcontrols.client.enums.VirtualMouseSkin;
import eu.midnightdust.midnightcontrols.client.gui.RingScreen;
import eu.midnightdust.midnightcontrols.client.enums.TouchMode;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
@@ -33,65 +40,87 @@ import static org.lwjgl.glfw.GLFW.*;
* Represents MidnightControls configuration.
*/
public class MidnightControlsConfig extends MidnightConfig {
public static final String CONTROLLER = "controller";
public static final String TOUCH = "touch";
public static final String GAMEPLAY = "gameplay";
public static final String SCREENS = "screens";
public static final String VISUAL = "visual";
public static final String MISC = "misc";
public static boolean isEditing = false;
@Hidden @Entry public static int configVersion = 2;
// General
@Entry(category = "controller", name = "midnightcontrols.menu.controls_mode") public static ControlsMode controlsMode = ControlsMode.DEFAULT;
@Entry(category = "controller", name = "midnightcontrols.menu.auto_switch_mode") public static boolean autoSwitchMode = true;
@Entry(category = "misc", name = "Debug") public static boolean debug = false;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.controls_mode") public static ControlsMode controlsMode = ControlsMode.DEFAULT;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.auto_switch_mode") public static boolean autoSwitchMode = true;
@Entry(category = MISC, name = "Debug") public static boolean debug = false;
// HUD
@Entry(category = "visual", name = "midnightcontrols.menu.hud_enable") public static boolean hudEnable = true;
@Entry(category = "visual", name = "midnightcontrols.menu.hud_side") public static HudSide hudSide = HudSide.LEFT;
@Entry(category = "screens", name = "midnightcontrols.menu.move_chat") public static boolean moveChat = false;
@Entry(category = VISUAL, name = "midnightcontrols.menu.hud_enable") public static boolean hudEnable = true;
@Entry(category = VISUAL, name = "midnightcontrols.menu.hud_side") public static HudSide hudSide = HudSide.LEFT;
@Entry(category = SCREENS, name = "midnightcontrols.menu.move_chat") public static boolean moveChat = false;
// Gameplay
@Entry(category = "gameplay", name = "midnightcontrols.menu.analog_movement") public static boolean analogMovement = true;
@Entry(category = "gameplay", name = "midnightcontrols.menu.double_tap_to_sprint") public static boolean doubleTapToSprint = true;
@Entry(category = "gameplay", name = "midnightcontrols.menu.controller_toggle_sneak") public static boolean controllerToggleSneak = MinecraftClient.getInstance().options.getSneakToggled().getValue();
@Entry(category = "gameplay", name = "midnightcontrols.menu.controller_toggle_sprint") public static boolean controllerToggleSprint = MinecraftClient.getInstance().options.getSprintToggled().getValue();
@Entry(category = "gameplay", name = "midnightcontrols.menu.fast_block_placing") public static boolean fastBlockPlacing = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(category = "gameplay", name = "midnightcontrols.menu.fly_drifting") public static boolean flyDrifting = true; // Enabled by default as disabling this behaviour can be considered cheating on multiplayer servers. It can also conflict with some other mods.
@Entry(category = "gameplay", name = "midnightcontrols.menu.fly_drifting_vertical") public static boolean verticalFlyDrifting = true; // Enabled by default as disabling this behaviour can be considered cheating on multiplayer servers.
@Entry(category = "gameplay", name = "midnightcontrols.menu.reacharound.horizontal") public static boolean horizontalReacharound = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(category = "gameplay", name = "midnightcontrols.menu.reacharound.vertical") public static boolean verticalReacharound = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(category = "visual", name = "Reacharound Outline") public static boolean shouldRenderReacharoundOutline = true;
@Entry(category = "visual", name = "Reacharound Outline Color", isColor = true) public static String reacharoundOutlineColorHex = "#ffffff";
@Entry(category = "visual", name = "Reacharound Outline Alpha", isSlider = true, min = 0, max = 255) public static int reacharoundOutlineColorAlpha = 102;
@Entry(category = "controller", name = "midnightcontrols.menu.right_dead_zone", isSlider = true, min = 0.05, max = 1) public static double rightDeadZone = 0.25;
@Entry(category = "controller", name = "midnightcontrols.menu.left_dead_zone", isSlider = true, min = 0.05, max = 1) public static double leftDeadZone = 0.25;
@Entry(category = "controller", name = "midnightcontrols.menu.invert_right_y_axis") public static boolean invertRightYAxis = false;
@Entry(category = "controller", name = "midnightcontrols.menu.invert_right_x_axis") public static boolean invertRightXAxis = false;
@Entry(category = "controller", name = "midnightcontrols.menu.rotation_speed", isSlider = true, min = 0, max = 100, precision = 10) public static double rotationSpeed = 40.0; //used for x-axis, name kept for compatibility
@Entry(category = "controller", name = "midnightcontrols.menu.y_axis_rotation_speed", isSlider = true, min = 0, max = 100, precision = 10) public static double yAxisRotationSpeed = rotationSpeed;
@Entry(category = "screens", name = "midnightcontrols.menu.mouse_speed", isSlider = true, min = 0, max = 150, precision = 10) public static double mouseSpeed = 25.0;
@Entry(category = "screens", name = "midnightcontrols.menu.joystick_as_mouse") public static boolean joystickAsMouse = false;
@Entry(category = "screens", name = "midnightcontrols.menu.eye_tracker_as_mouse") public static boolean eyeTrackerAsMouse = false;
@Entry(category = "screens", name = "midnightcontrols.menu.eye_tracker_deadzone", isSlider = true, min = 0, max = 0.4) public static double eyeTrackerDeadzone = 0.05;
@Entry(category = "controller", name = "midnightcontrols.menu.unfocused_input") public static boolean unfocusedInput = false;
@Entry(category = "screens", name = "midnightcontrols.menu.virtual_mouse") public static boolean virtualMouse = false;
@Entry(category = "screens", name = "midnightcontrols.menu.virtual_mouse.skin") public static VirtualMouseSkin virtualMouseSkin = VirtualMouseSkin.DEFAULT_LIGHT;
@Entry(category = "screens", name = "midnightcontrols.menu.hide_cursor") public static boolean hideNormalMouse = false;
@Entry(category = "controller", name = "Controller ID") @Hidden public static Object controllerID = 0;
@Entry(category = "controller", name = "2nd Controller ID") @Hidden public static Object secondControllerID = -1;
@Entry(category = "visual", name = "midnightcontrols.menu.controller_type") public static ControllerType controllerType = ControllerType.DEFAULT;
@Entry(category = "screens", name = "Mouse screens") public static List<String> mouseScreens = Lists.newArrayList("net.minecraft.client.gui.screen.advancement",
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.analog_movement") public static boolean analogMovement = true;
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.double_tap_to_sprint") public static boolean doubleTapToSprint = true;
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.controller_toggle_sneak") public static boolean controllerToggleSneak = MinecraftClient.getInstance().options.getSneakToggled().getValue();
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.controller_toggle_sprint") public static boolean controllerToggleSprint = MinecraftClient.getInstance().options.getSprintToggled().getValue();
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.fast_block_placing") public static boolean fastBlockPlacing = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.fly_drifting") public static boolean flyDrifting = true; // Enabled by default as disabling this behaviour can be considered cheating on multiplayer servers. It can also conflict with some other mods.
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.fly_drifting_vertical") public static boolean verticalFlyDrifting = true; // Enabled by default as disabling this behaviour can be considered cheating on multiplayer servers.
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.reacharound.horizontal") public static boolean horizontalReacharound = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(category = GAMEPLAY, name = "midnightcontrols.menu.reacharound.vertical") public static boolean verticalReacharound = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(category = VISUAL, name = "Reacharound Outline") public static boolean shouldRenderReacharoundOutline = true;
@Entry(category = VISUAL, name = "Reacharound Outline Color", isColor = true) public static String reacharoundOutlineColorHex = "#ffffff";
@Entry(category = VISUAL, name = "Reacharound Outline Alpha", isSlider = true, min = 0, max = 255) public static int reacharoundOutlineColorAlpha = 102;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.right_dead_zone", isSlider = true, min = 0.05, max = 1) public static double rightDeadZone = 0.25;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.left_dead_zone", isSlider = true, min = 0.05, max = 1) public static double leftDeadZone = 0.25;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.invert_right_y_axis") public static boolean invertRightYAxis = false;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.invert_right_x_axis") public static boolean invertRightXAxis = false;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.rotation_speed", isSlider = true, min = 0, max = 100, precision = 10) public static double rotationSpeed = 35.0; //used for x-axis, name kept for compatibility
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.y_axis_rotation_speed", isSlider = true, min = 0, max = 100, precision = 10) public static double yAxisRotationSpeed = rotationSpeed;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.camera_mode") public static CameraMode cameraMode = CameraMode.FLAT;
@Entry(category = SCREENS, name = "midnightcontrols.menu.mouse_speed", isSlider = true, min = 0, max = 150, precision = 10) public static double mouseSpeed = 25.0;
@Entry(category = SCREENS, name = "midnightcontrols.menu.joystick_as_mouse") public static boolean joystickAsMouse = false;
@Entry(category = SCREENS, name = "midnightcontrols.menu.eye_tracker_as_mouse") public static boolean eyeTrackerAsMouse = false;
@Entry(category = SCREENS, name = "midnightcontrols.menu.eye_tracker_deadzone", isSlider = true, min = 0, max = 0.4) public static double eyeTrackerDeadzone = 0.05;
@Entry(category = CONTROLLER, name = "midnightcontrols.menu.unfocused_input") public static boolean unfocusedInput = false;
@Entry(category = SCREENS, name = "midnightcontrols.menu.virtual_mouse") public static boolean virtualMouse = false;
@Entry(category = SCREENS, name = "midnightcontrols.menu.virtual_mouse.skin") public static VirtualMouseSkin virtualMouseSkin = VirtualMouseSkin.DEFAULT_LIGHT;
@Entry(category = SCREENS, name = "midnightcontrols.menu.hide_cursor") public static boolean hideNormalMouse = false;
@Entry(category = CONTROLLER, name = "Controller ID") @Hidden public static Object controllerID = 0;
@Entry(category = CONTROLLER, name = "2nd Controller ID") @Hidden public static Object secondControllerID = -1;
@Entry(category = VISUAL, name = "midnightcontrols.menu.controller_type") public static ControllerType controllerType = ControllerType.DEFAULT;
@Entry(category = SCREENS, name = "Mouse screens") public static List<String> mouseScreens = Lists.newArrayList("net.minecraft.client.gui.screen.advancement",
"net.minecraft.class_457", "net.minecraft.class_408", "net.minecraft.class_3872", "me.flashyreese.mods.reeses_sodium_options.client.gui", "dev.emi.emi.screen",
"hardcorequesting.client.interfaces.GuiQuestBook", "hardcorequesting.client.interfaces.GuiReward", "hardcorequesting.client.interfaces.EditTrackerScreen",
"me.shedaniel.clothconfig2.gui.ClothConfigScreen", "com.mamiyaotaru.voxelmap.gui.GuiWaypoints", "com.mamiyaotaru.voxelmap.gui.GuiPersistentMap");
@Entry(category = "screens", name = "Arrow screens") public static List<String> arrowScreens = Lists.newArrayList(ChatScreen.class.getCanonicalName());
@Entry(category = "screens", name = "WASD screens") public static List<String> wasdScreens = Lists.newArrayList("com.ultreon.devices.core.Laptop");
@Entry(category = SCREENS, name = "Arrow screens") public static List<String> arrowScreens = Lists.newArrayList(ChatScreen.class.getCanonicalName());
@Entry(category = SCREENS, name = "WASD screens") public static List<String> wasdScreens = Lists.newArrayList("com.ultreon.devices.core.Laptop");
@Entry(category = TOUCH, name = "Screens with close button") public static List<String> closeButtonScreens = Lists.newArrayList(ChatScreen.class.getCanonicalName(), AdvancementsScreen.class.getCanonicalName(), RingScreen.class.getCanonicalName());
@Entry(category = TOUCH, name = "midnightcontrols.menu.touch_with_controller") public static boolean touchInControllerMode = false;
@Entry(category = TOUCH, name = "midnightcontrols.menu.touch_speed", isSlider = true, min = 0, max = 150, precision = 10) public static double touchSpeed = 50.0;
@Entry(category = TOUCH, name = "midnightcontrols.menu.invert_touch") public static boolean invertTouch = false;
@Entry(category = TOUCH, name = "midnightcontrols.menu.touch_mode") public static TouchMode touchMode = TouchMode.CROSSHAIR;
@Entry(category = TOUCH, name = "midnightcontrols.menu.touch_break_delay", isSlider = true, min = 50, max = 500) public static int touchBreakDelay = 120;
@Entry(category = TOUCH, name = "midnightcontrols.menu.touch_transparency", isSlider = true, min = 0, max = 100) public static int touchTransparency = 75;
@Entry(category = TOUCH, name = "Touch Outline Color", isColor = true) public static String touchOutlineColorHex = "#ffffff";
@Entry(category = TOUCH, name = "Touch Outline Alpha", isSlider = true, min = 0, max = 255) public static int touchOutlineColorAlpha = 150;
@Entry(category = TOUCH, name = "Left Touch button bindings") public static List<String> leftTouchBinds = Lists.newArrayList("debug_screen", "screenshot","toggle_perspective");
@Entry(category = TOUCH, name = "Right Touch button bindings") public static List<String> rightTouchBinds = Lists.newArrayList("screenshot","toggle_perspective", "use");
@Entry @Hidden public static Map<String, String> BINDING = new HashMap<>();
private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?");
@Deprecated @Hidden @Entry public static double[] maxAnalogValues = new double[]{1, 1, 1, 1};
@Entry(category = "controller", name = "Max analog value: Left X", isSlider = true, min = .25f, max = 1.f) public static double maxAnalogValueLeftX = maxAnalogValues[0];
@Entry(category = "controller", name = "Max analog value: Left Y", isSlider = true, min = .25f, max = 1.f) public static double maxAnalogValueLeftY = maxAnalogValues[1];
@Entry(category = "controller", name = "Max analog value: Right X", isSlider = true, min = .25f, max = 1.f) public static double maxAnalogValueRightX = maxAnalogValues[2];
@Entry(category = "controller", name = "Max analog value: Right Y", isSlider = true, min = .25f, max = 1.f) public static double maxAnalogValueRightY = maxAnalogValues[3];
@Entry(category = "controller", name = "Trigger button fix") public static boolean triggerFix = true;
@Entry(category = "gameplay", name = "Enable Hints") public static boolean enableHints = true;
@Entry(category = "screens", name = "Enable Shortcut in Controls Options") public static boolean shortcutInControls = true;
@Entry(category = "misc", name = "Ring Bindings (WIP)") public static List<String> ringBindings = new ArrayList<>();
@Entry(category = "misc", name = "Ignored Unbound Keys") public static List<String> ignoredUnboundKeys = Lists.newArrayList("inventorytabs.key.next_tab");
@Entry(category = CONTROLLER, name = "Max analog value: Left X", isSlider = true, min = .25f, max = 1.f) public static double maxAnalogValueLeftX = maxAnalogValues[0];
@Entry(category = CONTROLLER, name = "Max analog value: Left Y", isSlider = true, min = .25f, max = 1.f) public static double maxAnalogValueLeftY = maxAnalogValues[1];
@Entry(category = CONTROLLER, name = "Max analog value: Right X", isSlider = true, min = .25f, max = 1.f) public static double maxAnalogValueRightX = maxAnalogValues[2];
@Entry(category = CONTROLLER, name = "Max analog value: Right Y", isSlider = true, min = .25f, max = 1.f) public static double maxAnalogValueRightY = maxAnalogValues[3];
@Entry(category = CONTROLLER, name = "Trigger button fix") public static boolean triggerFix = true;
@Entry(category = MISC, name = "Excluded Keybindings") public static List<String> excludedKeybindings = Lists.newArrayList("key.forward", "key.left", "key.back", "key.right", "key.jump", "key.sneak", "key.sprint", "key.inventory",
"key.swapOffhand", "key.drop", "key.use", "key.attack", "key.chat", "key.playerlist", "key.screenshot", "key.togglePerspective", "key.smoothCamera", "key.fullscreen", "key.saveToolbarActivator", "key.loadToolbarActivator",
"key.pickItem", "key.hotbar.1", "key.hotbar.2", "key.hotbar.3", "key.hotbar.4", "key.hotbar.5", "key.hotbar.6", "key.hotbar.7", "key.hotbar.8", "key.hotbar.9");
@Entry(category = GAMEPLAY, name = "Enable Hints") public static boolean enableHints = true;
@Entry(category = SCREENS, name = "Enable Shortcut in Controls Options") public static boolean shortcutInControls = true;
@Entry(category = MISC, name = "Ring Bindings (WIP)") public static List<String> ringBindings = new ArrayList<>();
@Entry(category = MISC, name = "Ignored Unbound Keys") public static List<String> ignoredUnboundKeys = Lists.newArrayList("inventorytabs.key.next_tab");
@Entry @Hidden public static Map<String, Map<String, String>> controllerBindingProfiles = new HashMap<>();
private static Map<String, String> currentBindingProfile = new HashMap<>();
private static Controller prevController;
@@ -375,4 +404,7 @@ public class MidnightControlsConfig extends MidnightConfig {
else if (controller.contains("ouya")) return ControllerType.OUYA;
else return ControllerType.DEFAULT;
}
public static boolean doMixedInput() {
return touchInControllerMode && controlsMode == ControlsMode.CONTROLLER;
}
}

View File

@@ -17,12 +17,14 @@ import eu.midnightdust.midnightcontrols.client.compat.*;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.Controller;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.enums.CameraMode;
import eu.midnightdust.midnightcontrols.client.gui.RingScreen;
import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay;
import eu.midnightdust.midnightcontrols.client.gui.widget.ControllerControlsWidget;
import eu.midnightdust.midnightcontrols.client.mixin.*;
import eu.midnightdust.midnightcontrols.client.ring.RingPage;
import eu.midnightdust.midnightcontrols.client.util.HandledScreenAccessor;
import eu.midnightdust.midnightcontrols.client.util.MathUtil;
import eu.midnightdust.midnightcontrols.client.util.MouseAccessor;
import dev.lambdaurora.spruceui.navigation.NavigationDirection;
import dev.lambdaurora.spruceui.screen.SpruceScreen;
@@ -30,12 +32,12 @@ import dev.lambdaurora.spruceui.widget.AbstractSprucePressableButtonWidget;
import dev.lambdaurora.spruceui.widget.SpruceElement;
import dev.lambdaurora.spruceui.widget.SpruceLabelWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceParentWidget;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import net.fabricmc.loader.api.FabricLoader;
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.TitleScreen;
import net.minecraft.client.gui.screen.advancement.AdvancementTab;
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
@@ -46,8 +48,6 @@ 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.*;
import net.minecraft.client.input.Input;
import net.minecraft.client.util.InputUtil;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.math.MathHelper;
@@ -151,8 +151,13 @@ public class MidnightInput {
if (allowInput)
InputManager.updateBindings(client);
if (this.controlsInput != null
&& InputManager.STATES.int2ObjectEntrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) {
if (this.controlsInput != null) {
InputManager.STATES.forEach((num, button) -> {
if (button.isPressed()) System.out.println(num);
});
}
if (this.controlsInput != null && InputManager.STATES.int2ObjectEntrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) {
System.out.println("finished");
if (this.controlsInput.focusedBinding != null && !this.controlsInput.waiting) {
int[] buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
@@ -203,18 +208,8 @@ public class MidnightInput {
}
client.getTutorialManager().onUpdateMouse(this.targetPitch, this.targetYaw);
MidnightControlsCompat.HANDLERS.forEach(handler -> handler.handleCamera(client, targetYaw, targetPitch));
this.onRender(client);
}
}
/**
* This method is deprecated and will be removed in future versions
* It is just kept, because the current version of 'Do a Barrel Roll' mixins into this method
*
* @param client the client instance
*/
@Deprecated
public void onRender(@NotNull MinecraftClient client) {
}
/**
* This method is called when a Screen is opened.
@@ -266,12 +261,33 @@ public class MidnightInput {
InputManager.STATES.put(btn, state);
}
}
MathUtil.PolarUtil polarLeft = new MathUtil.PolarUtil();
MathUtil.PolarUtil polarRight = new MathUtil.PolarUtil();
private void fetchAxeInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon) {
var buffer = gamepadState.axes();
polarLeft.calculate(buffer.get(GLFW_GAMEPAD_AXIS_LEFT_X), buffer.get(GLFW_GAMEPAD_AXIS_LEFT_Y), 1, MidnightControlsConfig.leftDeadZone);
float leftX = polarLeft.polarX;
float leftY = polarLeft.polarY;
polarRight.calculate(buffer.get(GLFW_GAMEPAD_AXIS_RIGHT_X), buffer.get(GLFW_GAMEPAD_AXIS_RIGHT_Y), 1, MidnightControlsConfig.rightDeadZone);
float rightX = polarRight.polarX;
float rightY = polarRight.polarY;
for (int i = 0; i < buffer.limit(); i++) {
int axis = leftJoycon ? ButtonBinding.controller2Button(i) : i;
float value = buffer.get();
if (MidnightControlsConfig.analogMovement) {
switch (i) {
case GLFW_GAMEPAD_AXIS_LEFT_X -> value = leftX;
case GLFW_GAMEPAD_AXIS_LEFT_Y -> value = leftY;
}
}
switch (i) {
case GLFW_GAMEPAD_AXIS_RIGHT_X -> value = rightX;
case GLFW_GAMEPAD_AXIS_RIGHT_Y -> value = rightY;
}
float absValue = Math.abs(value);
if (i == GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y)
@@ -281,24 +297,26 @@ public class MidnightInput {
if (!(client.currentScreen instanceof RingScreen || (MidnightControlsCompat.isEmotecraftPresent() && EmotecraftCompat.isEmotecraftScreen(client.currentScreen)))) this.handleAxe(client, axis, value, absValue, state);
}
if (client.currentScreen instanceof RingScreen || (MidnightControlsCompat.isEmotecraftPresent() && EmotecraftCompat.isEmotecraftScreen(client.currentScreen))) {
float x = Math.abs(buffer.get(GLFW_GAMEPAD_AXIS_LEFT_X)) > MidnightControlsConfig.leftDeadZone ? buffer.get(GLFW_GAMEPAD_AXIS_LEFT_X) : 0;
float y = Math.abs(buffer.get(GLFW_GAMEPAD_AXIS_LEFT_Y)) > MidnightControlsConfig.leftDeadZone ? buffer.get(GLFW_GAMEPAD_AXIS_LEFT_Y) : 0;
float x = leftX;
float y = leftY;
if (x == 0 && y == 0) {
x = Math.abs(buffer.get(GLFW_GAMEPAD_AXIS_RIGHT_X)) > MidnightControlsConfig.rightDeadZone ? buffer.get(GLFW_GAMEPAD_AXIS_RIGHT_X) : 0;
y = Math.abs(buffer.get(GLFW_GAMEPAD_AXIS_RIGHT_Y)) > MidnightControlsConfig.rightDeadZone ? buffer.get(GLFW_GAMEPAD_AXIS_RIGHT_Y) : 0;
x = rightX;
y = rightY;
}
int index = -1;
if (x < 0) {
if (y < 0) index = 0;
if (y == 0) index = 3;
if (y > 0) index = 5;
} else if (x == 0) {
if (y < 0) index = 1;
if (y > 0) index = 6;
} else if (x > 0) {
if (y < 0) index = 2;
if (y == 0) index = 4;
if (y > 0) index = 7;
float border = 0.3f;
if (x < -border) {
index = 3;
if (y < -border) index = 0;
else if (y > border) index = 5;
} else if (x > border) {
index = 4;
if (y < -border) index = 2;
else if (y > border) index = 7;
} else {
if (y < -border) index = 1;
else if (y > border) index = 6;
}
if (client.currentScreen instanceof RingScreen && index > -1) RingPage.selected = index;
if (MidnightControlsCompat.isEmotecraftPresent() && EmotecraftCompat.isEmotecraftScreen(client.currentScreen)) EmotecraftCompat.handleEmoteSelector(index);
@@ -458,7 +476,6 @@ public class MidnightInput {
private void handleAxe(@NotNull MinecraftClient client, int axis, float value, float absValue, int state) {
int asButtonState = value > .5f ? 1 : (value < -.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)) {
@@ -478,8 +495,13 @@ public class MidnightInput {
}
{
boolean currentPlusState = asButtonState == 1;
boolean currentMinusState = asButtonState == 2;
boolean currentPlusState = value > getDeadZoneValue(axis);
boolean currentMinusState = value < -getDeadZoneValue(axis);
if (axis == GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axis == GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER) currentMinusState = false;
if (!MidnightControlsConfig.analogMovement && (axis == GLFW_GAMEPAD_AXIS_LEFT_X || axis == GLFW_GAMEPAD_AXIS_LEFT_Y)) {
currentPlusState = asButtonState == 1;
currentMinusState = asButtonState == 2;
}
var previousPlusState = InputManager.STATES.getOrDefault(ButtonBinding.axisAsButton(axis, true), ButtonState.NONE);
var previousMinusState = InputManager.STATES.getOrDefault(ButtonBinding.axisAsButton(axis, false), ButtonState.NONE);
@@ -505,9 +527,13 @@ public class MidnightInput {
}
}
double deadZone = this.getDeadZoneValue(axis);
float axisValue = absValue < deadZone ? 0.f : (float) (absValue - deadZone);
axisValue /= (1.0 - deadZone);
float axisValue = absValue;
if (!MidnightControlsConfig.analogMovement) {
double deadZone = this.getDeadZoneValue(axis);
axisValue = (float) (absValue - deadZone);
axisValue /= (1.0 - deadZone);
axisValue *= deadZone;
}
axisValue = (float) Math.min(axisValue / MidnightControlsConfig.getAxisMaxValue(axis), 1);
if (currentPlusState)
@@ -540,7 +566,7 @@ public class MidnightInput {
var accessor = (CreativeInventoryScreenAccessor) creativeInventoryScreen;
// @TODO allow rebinding to left stick
if (accessor.midnightcontrols$hasScrollbar() && absValue >= deadZone) {
creativeInventoryScreen.mouseScrolled(0.0, 0.0, -value);
creativeInventoryScreen.mouseScrolled(0.0, 0.0, 0, -value);
}
return;
}
@@ -548,7 +574,7 @@ public class MidnightInput {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
// @TODO allow rebinding to left stick
if (absValue >= deadZone) {
merchantScreen.mouseScrolled(0.0, 0.0, -(value * 1.5f));
merchantScreen.mouseScrolled(0.0, 0.0, 0, -(value * 1.5f));
}
return;
}
@@ -556,7 +582,7 @@ public class MidnightInput {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
// @TODO allow rebinding to left stick
if (absValue >= deadZone) {
stonecutterScreen.mouseScrolled(0.0, 0.0, -(value * 1.5f));
stonecutterScreen.mouseScrolled(0.0, 0.0, 0, -(value * 1.5f));
}
return;
}
@@ -575,7 +601,7 @@ public class MidnightInput {
.map(element -> (SpruceEntryListWidget<?>) element)
.filter(AbstractSpruceWidget::isFocusedOrHovered)
.noneMatch(element -> {
element.mouseScrolled(0.0, 0.0, -finalValue);
element.mouseScrolled(0.0, 0.0, 0, -finalValue);
return true;
})
&&
@@ -583,11 +609,11 @@ public class MidnightInput {
.map(element -> (EntryListWidget<?>) element)
.filter(element -> element.getType().isFocused())
.noneMatch(element -> {
element.mouseScrolled(0.0, 0.0, -finalValue);
element.mouseScrolled(0.0, 0.0, 0, -finalValue);
return true;
}))
{
client.currentScreen.mouseScrolled(0.0, 0.0, -(value * 1.5f));
client.currentScreen.mouseScrolled(0.0, 0.0, 0, -(value * 1.5f));
}
else if (isScreenInteractive(client.currentScreen) && absValue >= deadZone) {
if (value > 0 && joystickCooldown == 0) {
@@ -607,8 +633,6 @@ public class MidnightInput {
}
}
absValue -= deadZone;
absValue /= (1.0 - deadZone);
absValue = (float) MathHelper.clamp(absValue / MidnightControlsConfig.getAxisMaxValue(axis), 0.f, 1.f);
if (client.currentScreen == null) {
// Handles the look direction.
@@ -756,6 +780,10 @@ public class MidnightInput {
}
return true;
}
private double prevX = 0;
private double prevY = 0;
private double xValue;
private int xState;
/**
* Handles the look direction input.
@@ -766,8 +794,9 @@ public class MidnightInput {
* @param state the state
*/
public void handleLook(@NotNull MinecraftClient client, int axis, float value, int state) {
if (client.player == null) return;
// Handles the look direction.
if (client.player != null) {
if (MidnightControlsConfig.cameraMode == CameraMode.FLAT) {
double powValue = Math.pow(value, 2.0);
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
if (state == 2) {
@@ -783,6 +812,43 @@ public class MidnightInput {
this.targetYaw = MidnightControlsConfig.getRightXAxisSign() * (MidnightControlsConfig.rotationSpeed * powValue) * 0.11D;
}
}
return;
}
// Code below runs for adaptive camera mode
// Handles the look direction.
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) {
xValue = value;
xState = state;
return;
}
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y && client.player != null) {
double yStep = (MidnightControlsConfig.yAxisRotationSpeed / 100) * 0.6000000238418579 + 0.20000000298023224;
double xStep = (MidnightControlsConfig.rotationSpeed / 100) * 0.6000000238418579 + 0.20000000298023224;
double cursorDeltaX = 2 * xValue - this.prevX;
double cursorDeltaY = 2 * value - this.prevY;
boolean slowdown = client.options.getPerspective().isFirstPerson() && client.player.isUsingSpyglass();
double x = cursorDeltaX * xStep * (slowdown ? xStep : 1);
double y = cursorDeltaY * yStep * (slowdown ? yStep : 1);
double powXValue = Math.pow(x, 2.0);
double powYValue = Math.pow(y, 2.0);
if (state == 2) {
this.targetPitch = -MidnightControlsConfig.getRightYAxisSign() * (MidnightControlsConfig.yAxisRotationSpeed * powYValue) * 0.11D;
} else if (state == 1) {
this.targetPitch = MidnightControlsConfig.getRightYAxisSign() * (MidnightControlsConfig.yAxisRotationSpeed * powYValue) * 0.11D;
}
if (xState == 2) {
this.targetYaw = -MidnightControlsConfig.getRightXAxisSign() * (MidnightControlsConfig.rotationSpeed * powXValue) * 0.11D;
} else if (xState == 1) {
this.targetYaw = MidnightControlsConfig.getRightXAxisSign() * (MidnightControlsConfig.rotationSpeed * powXValue) * 0.11D;
}
this.prevY = value;
this.prevX = xValue;
}
}

View File

@@ -73,7 +73,7 @@ public class MidnightReacharound {
return MidnightControlsFeature.HORIZONTAL_REACHAROUND.isAvailable() || MidnightControlsFeature.VERTICAL_REACHAROUND.isAvailable();
}
private float getPlayerRange(@NotNull MinecraftClient client) {
public static float getPlayerRange(@NotNull MinecraftClient client) {
return client.interactionManager != null ? client.interactionManager.getReachDistance() : 0.f;
}

View File

@@ -1,16 +1,21 @@
package eu.midnightdust.midnightcontrols.client.compat;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import io.github.kosmx.emotes.arch.gui.EmoteMenuImpl;
import io.github.kosmx.emotes.arch.gui.screen.ingame.FastChosseScreen;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
public class EmotecraftCompat {
private static final MinecraftClient client = MinecraftClient.getInstance();
public static void openEmotecraftScreen(Screen parent) {
client.setScreen(new EmoteMenuImpl(parent));
}
public static boolean isEmotecraftScreen(Screen screen) {
return screen instanceof FastChosseScreen;
}
public static void handleEmoteSelector(int index) {
MinecraftClient client = MinecraftClient.getInstance();
if (client.currentScreen instanceof FastChosseScreen) {
int x = client.getWindow().getWidth() / 2;
int y = client.getWindow().getHeight() / 2;

View File

@@ -1,35 +1,12 @@
package eu.midnightdust.midnightcontrols.client.compat;
import eu.midnightdust.midnightcontrols.MidnightControls;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.compat.mixin.SodiumOptionsGUIAccessor;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI;
import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
public class SodiumCompat {
private static final MinecraftClient client = MinecraftClient.getInstance();
public static void handleInput(Screen screen, boolean direction) {
if (screen instanceof SodiumOptionsGUI optionsGUI) {
SodiumOptionsGUIAccessor accessor = (SodiumOptionsGUIAccessor) optionsGUI;
final int max = accessor.getControls().size()-1;
var option = accessor.getControls().stream().filter(ControlElement::isHovered).findFirst().orElse(accessor.getControls().get(0));
int i = accessor.getControls().indexOf(option);
i = (direction ? ((max > i) ? ++i : 0) : (i > 0 ? --i : max));
var dimensions = accessor.getControls().get(i).getDimensions();
int x = (int) (client.getWindow().getScaleFactor() * dimensions.getCenterX());
int y = (int) (client.getWindow().getScaleFactor() * dimensions.getCenterY());
InputManager.queueMousePosition(x,y);
InputManager.INPUT_MANAGER.updateMousePosition(client);
MidnightControlsClient.get().input.actionGuiCooldown = 5;
if (MidnightControlsConfig.debug) MidnightControls.get().log(i+" "+accessor.getControls().size()+" | " + dimensions.getCenterX() + " " + dimensions.getCenterY());
}
}
public static void handleTabs(Screen screen, boolean direction) {
if (screen instanceof SodiumOptionsGUI optionsGUI) {
SodiumOptionsGUIAccessor accessor = (SodiumOptionsGUIAccessor) optionsGUI;

View File

@@ -1,95 +0,0 @@
/*
* Copyright © 2022 Motschen <motschen@midnightdust.eu>
*
* This file is part of MidnightControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client.compat;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.ButtonCategory;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.mixin.KeyBindingIDAccessor;
import net.minecraft.client.option.KeyBinding;
import org.aperlambda.lambdacommon.Identifier;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
/**
* Represents a compatibility handler for VoxelMap.
*
* @author Motschen
* @version 1.8.0
* @since 1.8.0
*/
public class VoxelMapCompat implements CompatHandler {
private final KeyBinding voxelMapZoomKey = KeyBindingIDAccessor.getKEYS_BY_ID().getOrDefault("key.minimap.zoom", null);
private final KeyBinding voxelmapFullscreenKey = KeyBindingIDAccessor.getKEYS_BY_ID().getOrDefault("key.minimap.togglefullscreen", null);
private final KeyBinding voxelmapMenuKey = KeyBindingIDAccessor.getKEYS_BY_ID().getOrDefault("key.minimap.voxelmapmenu", null);;
private final KeyBinding voxelmapWaypointMenuKey = KeyBindingIDAccessor.getKEYS_BY_ID().getOrDefault("key.minimap.waypointmenu", null);;
private final KeyBinding voxelmapWaypointKey = KeyBindingIDAccessor.getKEYS_BY_ID().getOrDefault("key.minimap.waypointhotkey", null);
private final KeyBinding voxelmapMobToggleKey = KeyBindingIDAccessor.getKEYS_BY_ID().getOrDefault("key.minimap.togglemobs", null);
private final KeyBinding voxelmapWaypointToggleKey = KeyBindingIDAccessor.getKEYS_BY_ID().getOrDefault("key.minimap.toggleingamewaypoints", null);
private static final ButtonCategory VOXELMAP_CATEGORY = InputManager.registerCategory(new Identifier("minecraft","controls.minimap.title"));
@Override
public void handle(@NotNull MidnightControlsClient mod) {
if (MidnightControlsConfig.debug && KeyBindingIDAccessor.getKEYS_BY_ID() != null) KeyBindingIDAccessor.getKEYS_BY_ID().forEach((a, b) -> System.out.println(a + " - " + b));
new ButtonBinding.Builder("key.minimap.zoom")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW.GLFW_GAMEPAD_BUTTON_X)
.onlyInGame()
.cooldown(true)
.category(VOXELMAP_CATEGORY)
.linkKeybind(voxelMapZoomKey)
.register();
new ButtonBinding.Builder("key.minimap.togglefullscreen")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW.GLFW_GAMEPAD_BUTTON_Y)
.onlyInGame()
.cooldown(true)
.category(VOXELMAP_CATEGORY)
.linkKeybind(voxelmapFullscreenKey)
.register();
new ButtonBinding.Builder("key.minimap.voxelmapmenu")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW.GLFW_GAMEPAD_BUTTON_START)
.onlyInGame()
.cooldown(true)
.category(VOXELMAP_CATEGORY)
.linkKeybind(voxelmapMenuKey)
.register();
new ButtonBinding.Builder("key.minimap.waypointmenu")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW.GLFW_GAMEPAD_BUTTON_GUIDE)
.onlyInGame()
.cooldown(true)
.category(VOXELMAP_CATEGORY)
.linkKeybind(voxelmapWaypointMenuKey)
.register();
new ButtonBinding.Builder("key.minimap.waypointhotkey")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW.GLFW_GAMEPAD_BUTTON_BACK)
.onlyInGame()
.cooldown(true)
.category(VOXELMAP_CATEGORY)
.linkKeybind(voxelmapWaypointKey)
.register();
new ButtonBinding.Builder("key.minimap.togglemobs")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW.GLFW_GAMEPAD_BUTTON_A)
.onlyInGame()
.cooldown(true)
.category(VOXELMAP_CATEGORY)
.linkKeybind(voxelmapMobToggleKey)
.register();
new ButtonBinding.Builder("key.minimap.toggleingamewaypoints")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW.GLFW_GAMEPAD_BUTTON_B)
.onlyInGame()
.cooldown(true)
.category(VOXELMAP_CATEGORY)
.linkKeybind(voxelmapWaypointToggleKey)
.register();
}
}

View File

@@ -9,7 +9,7 @@
package eu.midnightdust.midnightcontrols.client.controller;
import eu.midnightdust.midnightcontrols.client.ButtonState;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.gui.RingScreen;
import net.minecraft.client.MinecraftClient;
@@ -75,9 +75,8 @@ public class ButtonBinding {
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding SCREENSHOT = new Builder("screenshot").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_A)
.action(InputHandlers::handleScreenshot).cooldown().register();
public static final ButtonBinding DEBUG_SCREEN = new Builder("debug_screen").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_B)
.action((client,binding,value,action) -> {if (action == ButtonState.PRESS) client.options.debugEnabled = !client.options.debugEnabled; return true;}).cooldown().register();
.action((client,binding,value,action) -> {if (action == ButtonState.PRESS) client.inGameHud.getDebugHud().toggleDebugHud(); return true;}).cooldown().register();
public static final ButtonBinding SLOT_DOWN = new Builder("slot_down").buttons(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)
.action(InputHandlers.handleInventorySlotPad(1)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_LEFT = new Builder("slot_left").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT)

View File

@@ -32,6 +32,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import static org.lwjgl.BufferUtils.createByteBuffer;
@@ -79,7 +80,7 @@ public record Controller(int id) implements Nameable {
* @return the controller's name
*/
@Override
public String getName() {
public @NotNull String getName() {
var name = this.isGamepad() ? GLFW.glfwGetGamepadName(this.id) : GLFW.glfwGetJoystickName(this.id);
return name == null ? String.valueOf(this.id()) : name;
}
@@ -145,6 +146,9 @@ public record Controller(int id) implements Nameable {
* Updates the controller mappings.
*/
public static void updateMappings() {
CompletableFuture.supplyAsync(Controller::updateMappingsSync);
}
private static boolean updateMappingsSync() {
try {
MidnightControlsClient.get().log("Updating controller mappings...");
File databaseFile = new File("config/gamecontrollerdatabase.txt");
@@ -161,7 +165,7 @@ public record Controller(int id) implements Nameable {
var database = ioResourceToBuffer(databaseFile.getPath(), 1024);
if (database != null) GLFW.glfwUpdateGamepadMappings(database);
if (!MidnightControlsClient.MAPPINGS_FILE.exists())
return;
return false;
var buffer = ioResourceToBuffer(MidnightControlsClient.MAPPINGS_FILE.getPath(), 1024);
if (buffer != null) GLFW.glfwUpdateGamepadMappings(buffer);
} catch (IOException e) {
@@ -176,7 +180,7 @@ public record Controller(int id) implements Nameable {
var string = l == 0L ? "" : MemoryUtil.memUTF8(l);
var client = MinecraftClient.getInstance();
if (client != null) {
client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT,
client.getToastManager().add(SystemToast.create(client, SystemToast.Type.PERIODIC_NOTIFICATION,
Text.translatable("midnightcontrols.controller.mappings.error"), Text.literal(string)));
MidnightControls.get().log(I18n.translate("midnightcontrols.controller.mappings.error")+string);
}
@@ -199,5 +203,6 @@ public record Controller(int id) implements Nameable {
controller.isGamepad()));
}
}
return true;
}
}

View File

@@ -10,7 +10,8 @@
package eu.midnightdust.midnightcontrols.client.controller;
import com.google.common.collect.Lists;
import eu.midnightdust.midnightcontrols.client.ButtonState;
import eu.midnightdust.lib.util.PlatformFunctions;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.MidnightInput;
@@ -19,17 +20,16 @@ import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat;
import eu.midnightdust.midnightcontrols.client.compat.SodiumCompat;
import eu.midnightdust.midnightcontrols.client.compat.YACLCompat;
import eu.midnightdust.midnightcontrols.client.gui.RingScreen;
import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay;
import eu.midnightdust.midnightcontrols.client.mixin.AdvancementsScreenAccessor;
import eu.midnightdust.midnightcontrols.client.mixin.CreativeInventoryScreenAccessor;
import eu.midnightdust.midnightcontrols.client.mixin.RecipeBookWidgetAccessor;
import eu.midnightdust.midnightcontrols.client.mixin.TabNavigationWidgetAccessor;
import eu.midnightdust.midnightcontrols.client.util.HandledScreenAccessor;
import eu.midnightdust.midnightcontrols.client.util.MouseAccessor;
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
import net.fabricmc.fabric.impl.client.itemgroup.CreativeGuiExtensions;
import net.fabricmc.fabric.impl.client.itemgroup.FabricCreativeGuiComponents;
import net.fabricmc.fabric.impl.itemgroup.FabricItemGroup;
import net.fabricmc.fabric.impl.itemgroup.ItemGroupEventsImpl;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.TitleScreen;
@@ -100,6 +100,7 @@ public class InputHandlers {
} else if (client.currentScreen instanceof RingScreen) {
MidnightControlsClient.get().ring.cyclePage(next);
} else if (client.currentScreen instanceof CreativeInventoryScreenAccessor inventory) {
if (PlatformFunctions.isModLoaded("connectormod")) return true;
ItemGroup currentTab = CreativeInventoryScreenAccessor.getSelectedTab();
int currentColumn = currentTab.getColumn();
ItemGroup.Row currentRow = currentTab.getRow();
@@ -160,7 +161,7 @@ public class InputHandlers {
nextTab = tabs.size() - 1;
else if (nextTab >= tabs.size())
nextTab = 0;
screen.getAdvancementManager().selectTab(tabs.get(nextTab).getRoot(), true);
screen.getAdvancementManager().selectTab(tabs.get(nextTab).getRoot().getAdvancementEntry(), true);
break;
}
}
@@ -190,6 +191,8 @@ public class InputHandlers {
}
public static PressAction handlePage(boolean next) {
return (client, button, value, action) -> {
if (action == ButtonState.RELEASE)
return false;
if (client.currentScreen instanceof CreativeInventoryScreen) {
try {
return client.currentScreen.children().stream().filter(element -> element instanceof PressableWidget)
@@ -277,7 +280,7 @@ public class InputHandlers {
if (action == ButtonState.PRESS) {
// If in game, then pause the game.
if (client.currentScreen == null || client.currentScreen instanceof RingScreen)
client.openPauseMenu(false);
client.openGameMenu(false);
else if (client.currentScreen instanceof HandledScreen && client.player != null) // If the current screen is a container then close it.
client.player.closeHandledScreen();
else // Else just close the current screen.
@@ -418,7 +421,7 @@ public class InputHandlers {
* @return true if the client is in game, else false
*/
public static boolean inGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) {
return (client.currentScreen == null && MidnightControlsClient.get().input.screenCloseCooldown <= 0) || client.currentScreen instanceof RingScreen;
return (client.currentScreen == null && MidnightControlsClient.get().input.screenCloseCooldown <= 0) || client.currentScreen instanceof TouchscreenOverlay || client.currentScreen instanceof RingScreen;
}
/**

View File

@@ -10,7 +10,7 @@
package eu.midnightdust.midnightcontrols.client.controller;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.client.ButtonState;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.util.MouseAccessor;
import it.unimi.dsi.fastutil.ints.*;
@@ -27,7 +27,6 @@ import org.lwjgl.glfw.GLFW;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**

View File

@@ -9,20 +9,12 @@
package eu.midnightdust.midnightcontrols.client.controller;
import eu.midnightdust.midnightcontrols.client.ButtonState;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.util.MathUtil;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.input.Input;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.tutorial.MovementTutorialStepHandler;
import net.minecraft.client.util.InputUtil;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.enchantment.SoulSpeedEnchantment;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.scanner.SimpleNbtScanner;
import net.minecraft.util.math.MathHelper;
import org.jetbrains.annotations.NotNull;
@@ -43,6 +35,7 @@ public final class MovementHandler implements PressAction {
private float slowdownFactor = 1.f;
private float movementForward = 0.f;
private float movementSideways = 0.f;
private MathUtil.PolarUtil polarUtil = new MathUtil.PolarUtil();
private MovementHandler() {
}
@@ -53,8 +46,6 @@ public final class MovementHandler implements PressAction {
* @param player The client player.
*/
public void applyMovement(@NotNull ClientPlayerEntity player) {
double movementR, movementTheta;
if (!this.shouldOverrideMovement)
return;
player.input.pressingForward = this.pressingForward;
@@ -62,12 +53,9 @@ public final class MovementHandler implements PressAction {
player.input.pressingLeft = this.pressingLeft;
player.input.pressingRight = this.pressingRight;
// Do an implicit square here
movementR = this.slowdownFactor * (Math.pow(this.movementSideways, 2) + Math.pow(this.movementForward, 2));
movementR = MathHelper.clamp(movementR, 0.f, 1.f);
movementTheta = Math.atan2(this.movementForward, this.movementSideways);
player.input.movementForward = (float) (movementR * Math.sin(movementTheta));
player.input.movementSideways = (float) (movementR * Math.cos(movementTheta));
polarUtil.calculate(this.movementSideways, this.movementForward, this.slowdownFactor);
player.input.movementForward = polarUtil.polarY;
player.input.movementSideways = polarUtil.polarX;
this.shouldOverrideMovement = false;
}

View File

@@ -9,7 +9,7 @@
package eu.midnightdust.midnightcontrols.client.controller;
import eu.midnightdust.midnightcontrols.client.ButtonState;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import eu.midnightdust.midnightcontrols.client.util.KeyBindingAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.StickyKeyBinding;

View File

@@ -7,7 +7,7 @@
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client;
package eu.midnightdust.midnightcontrols.client.enums;
/**
* Represents a button state.

View File

@@ -0,0 +1,17 @@
package eu.midnightdust.midnightcontrols.client.enums;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
public enum CameraMode {
FLAT, ADAPTIVE;
public Text getTranslatedText() {
return Text.translatable("midnightcontrols.midnightconfig.enum."+this.getClass().getSimpleName()+"."+this.name());
}
public @NotNull CameraMode next() {
var v = values();
if (v.length == this.ordinal() + 1)
return v[0];
return v[this.ordinal() + 1];
}
}

View File

@@ -7,7 +7,7 @@
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client;
package eu.midnightdust.midnightcontrols.client.enums;
import net.minecraft.text.Text;
import org.aperlambda.lambdacommon.utils.Nameable;

View File

@@ -7,7 +7,7 @@
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client;
package eu.midnightdust.midnightcontrols.client.enums;
import net.minecraft.text.Text;
import org.aperlambda.lambdacommon.utils.Nameable;

View File

@@ -0,0 +1,17 @@
package eu.midnightdust.midnightcontrols.client.enums;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
public enum TouchMode {
CROSSHAIR, FINGER_POS;
public Text getTranslatedText() {
return Text.translatable("midnightcontrols.midnightconfig.enum."+this.getClass().getSimpleName()+"."+this.name());
}
public @NotNull TouchMode next() {
var v = values();
if (v.length == this.ordinal() + 1)
return v[0];
return v[this.ordinal() + 1];
}
}

View File

@@ -7,7 +7,7 @@
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client;
package eu.midnightdust.midnightcontrols.client.enums;
import net.minecraft.text.Text;
import org.aperlambda.lambdacommon.utils.Nameable;

View File

@@ -63,7 +63,7 @@ public class MappingsStringInputWidget extends SpruceContainerWidget {
fw.close();
} catch (IOException e) {
if (this.client != null)
this.client.getToastManager().add(SystemToast.create(this.client, SystemToast.Type.TUTORIAL_HINT,
this.client.getToastManager().add(SystemToast.create(this.client, SystemToast.Type.PERIODIC_NOTIFICATION,
Text.translatable("midnightcontrols.controller.mappings.error.write"), Text.empty()));
e.printStackTrace();
}

View File

@@ -11,7 +11,7 @@ package eu.midnightdust.midnightcontrols.client.gui;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.MidnightControlsConstants;
import eu.midnightdust.midnightcontrols.client.HudSide;
import eu.midnightdust.midnightcontrols.client.enums.HudSide;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat;
@@ -38,7 +38,7 @@ import org.jetbrains.annotations.Nullable;
*/
public class MidnightControlsHud extends Hud {
private final MidnightControlsClient mod;
private MinecraftClient client;
private final MinecraftClient client = MinecraftClient.getInstance();
private int attackWidth = 0;
private int attackButtonWidth = 0;
private int dropItemWidth = 0;
@@ -64,7 +64,6 @@ public class MidnightControlsHud extends Hud {
@Override
public void init(@NotNull MinecraftClient client, int screenWidth, int screenHeight) {
super.init(client, screenWidth, screenHeight);
this.client = client;
this.inventoryWidth = this.width(ButtonBinding.INVENTORY);
this.inventoryButtonWidth = MidnightControlsRenderer.getBindingIconWidth(ButtonBinding.INVENTORY);
this.swapHandsWidth = this.width(ButtonBinding.SWAP_HANDS);
@@ -198,6 +197,7 @@ public class MidnightControlsHud extends Hud {
@Override
public void tick() {
if (this.client == null) return;
super.tick();
if (MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER) {
if (this.client.crosshairTarget == null)

View File

@@ -10,7 +10,7 @@
package eu.midnightdust.midnightcontrols.client.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import eu.midnightdust.midnightcontrols.client.ControllerType;
import eu.midnightdust.midnightcontrols.client.enums.ControllerType;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.MidnightInput;
@@ -21,9 +21,7 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
@@ -234,6 +232,7 @@ public class MidnightControlsRenderer {
}
//context.getMatrices().push();
context.getMatrices().translate(0f, 0f, 999f);
drawCursor(context, mouseX, mouseY, hoverSlot, client);
//context.getMatrices().pop();
}

View File

@@ -125,6 +125,7 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
private final SpruceOption unfocusedInputOption;
private final SpruceOption invertsRightXAxis;
private final SpruceOption invertsRightYAxis;
private final SpruceOption cameraModeOption;
private final SpruceOption toggleControllerProfileOption;
private final SpruceOption rightDeadZoneOption;
private final SpruceOption leftDeadZoneOption;
@@ -143,6 +144,13 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
Text.translatable(key.concat(".tooltip"))
);
}
// Touch options
private final SpruceOption touchWithControllerOption;
private final SpruceOption touchSpeedOption;
private final SpruceOption touchBreakDelayOption;
private final SpruceOption invertTouchOption;
private final SpruceOption touchTransparencyOption;
private final SpruceOption touchModeOption;
private final MutableText controllerMappingsUrlText = Text.literal("(")
.append(Text.literal(GAMEPAD_TOOL_URL).formatted(Formatting.GOLD))
@@ -191,7 +199,7 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
this.mouseSpeedOption = new SpruceDoubleOption("midnightcontrols.menu.mouse_speed", 0.0, 150.0, .5f,
() -> MidnightControlsConfig.mouseSpeed,
value -> MidnightControlsConfig.mouseSpeed = value, option -> option.getDisplayText(Text.literal(String.valueOf(option.get()))),
Text.translatable("midnightcontrols.menu.joystick_as_mouse.tooltip"));
Text.translatable("midnightcontrols.menu.mouse_speed.tooltip"));
this.joystickAsMouseOption = new SpruceToggleBooleanOption("midnightcontrols.menu.joystick_as_mouse",
() -> MidnightControlsConfig.joystickAsMouse, value -> MidnightControlsConfig.joystickAsMouse = value,
Text.translatable("midnightcontrols.menu.joystick_as_mouse.tooltip"));
@@ -262,6 +270,10 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
}
}, Text.translatable(""));
this.cameraModeOption = new SpruceCyclingOption("midnightcontrols.menu.camera_mode",
amount -> MidnightControlsConfig.cameraMode = MidnightControlsConfig.cameraMode.next(),
option -> option.getDisplayText(MidnightControlsConfig.cameraMode.getTranslatedText()),
Text.translatable("midnightcontrols.menu.camera_mode.tooltip"));
this.rightDeadZoneOption = new SpruceDoubleOption("midnightcontrols.menu.right_dead_zone", 0.05, 1.0, .05f,
() -> MidnightControlsConfig.rightDeadZone,
value -> MidnightControlsConfig.rightDeadZone = value, option -> {
@@ -284,6 +296,27 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
value -> MidnightControlsConfig.virtualMouse = value, Text.translatable("midnightcontrols.menu.virtual_mouse.tooltip"));
this.hideCursorOption = new SpruceToggleBooleanOption("midnightcontrols.menu.hide_cursor", () -> MidnightControlsConfig.hideNormalMouse,
value -> MidnightControlsConfig.hideNormalMouse = value, Text.translatable("midnightcontrols.menu.hide_cursor.tooltip"));
// Touch options
this.touchModeOption = new SpruceCyclingOption("midnightcontrols.menu.touch_mode",
amount -> MidnightControlsConfig.touchMode = MidnightControlsConfig.touchMode.next(),
option -> option.getDisplayText(MidnightControlsConfig.touchMode.getTranslatedText()),
Text.translatable("midnightcontrols.menu.touch_mode.tooltip"));
this.touchWithControllerOption = new SpruceToggleBooleanOption("midnightcontrols.menu.touch_with_controller", () -> MidnightControlsConfig.touchInControllerMode,
value -> MidnightControlsConfig.touchInControllerMode = value, Text.translatable("midnightcontrols.menu.touch_with_controller.tooltip"));
this.touchSpeedOption = new SpruceDoubleOption("midnightcontrols.menu.touch_speed", 0.0, 150.0, .5f,
() -> MidnightControlsConfig.touchSpeed,
value -> MidnightControlsConfig.touchSpeed = value, option -> option.getDisplayText(Text.literal(String.valueOf(option.get()))),
Text.translatable("midnightcontrols.menu.touch_speed.tooltip"));
this.touchBreakDelayOption = new SpruceDoubleOption("midnightcontrols.menu.touch_break_delay", 50, 500, 1f,
() -> (double) MidnightControlsConfig.touchBreakDelay,
value -> MidnightControlsConfig.touchBreakDelay = value.intValue(), option -> option.getDisplayText(Text.literal(String.valueOf(option.get()))),
Text.translatable("midnightcontrols.menu.touch_break_delay.tooltip"));
this.touchTransparencyOption = new SpruceDoubleOption("midnightcontrols.menu.touch_transparency", 0, 100, 1f,
() -> (double) MidnightControlsConfig.touchTransparency,
value -> MidnightControlsConfig.touchTransparency = value.intValue(), option -> option.getDisplayText(Text.literal(String.valueOf(option.get()))),
Text.translatable("midnightcontrols.menu.touch_break_delay.tooltip"));
this.invertTouchOption = new SpruceToggleBooleanOption("midnightcontrols.menu.invert_touch", () -> MidnightControlsConfig.invertTouch,
value -> MidnightControlsConfig.invertTouch = value, Text.translatable("midnightcontrols.menu.invert_touch.tooltip"));
}
@Override
@@ -337,6 +370,8 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
tabs.addSeparatorEntry(Text.translatable("midnightcontrols.menu.separator.controller"));
tabs.addTabEntry(Text.translatable("midnightcontrols.menu.title.controller"), null,
this::buildControllerTab);
tabs.addTabEntry(Text.translatable("midnightcontrols.menu.title.touch"), null,
this::buildTouchTab);
tabs.addTabEntry(Text.translatable("midnightcontrols.menu.title.mappings.string"), null,
this::buildMappingsStringEditorTab);
}
@@ -420,6 +455,7 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
list.addSingleOptionEntry(this.secondControllerOption);
list.addSingleOptionEntry(this.toggleControllerProfileOption);
list.addSingleOptionEntry(this.unfocusedInputOption);
list.addSingleOptionEntry(this.cameraModeOption);
list.addOptionEntry(this.invertsRightXAxis, this.invertsRightYAxis);
list.addSingleOptionEntry(this.rightDeadZoneOption);
list.addSingleOptionEntry(this.leftDeadZoneOption);
@@ -431,6 +467,18 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
root.addChild(labels);
return root;
}
public SpruceOptionListWidget buildTouchTab(int width, int height) {
var list = new SpruceOptionListWidget(Position.origin(), width, height);
list.setBackground(new MidnightControlsBackground(130));
list.addSingleOptionEntry(this.touchSpeedOption);
list.addSingleOptionEntry(this.touchWithControllerOption);
list.addSingleOptionEntry(this.invertTouchOption);
list.addSingleOptionEntry(new SpruceSeparatorOption("midnightcontrols.menu.title.hud", true, null));
list.addSingleOptionEntry(this.touchModeOption);
list.addSingleOptionEntry(this.touchBreakDelayOption);
list.addSingleOptionEntry(this.touchTransparencyOption);
return list;
}
public SpruceContainerWidget buildMappingsStringEditorTab(int width, int height) {
return new MappingsStringInputWidget(Position.origin(), width, height);

View File

@@ -33,7 +33,7 @@ public class ReloadControllerMappingsOption {
Controller.updateMappings();
if (client.currentScreen instanceof MidnightControlsSettingsScreen)
client.currentScreen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT,
client.getToastManager().add(SystemToast.create(client, SystemToast.Type.PERIODIC_NOTIFICATION,
Text.translatable("midnightcontrols.controller.mappings.updated"), Text.empty()));
}, Text.translatable("midnightcontrols.tooltip.reload_controller_mappings"));
}

View File

@@ -15,7 +15,6 @@ import eu.midnightdust.midnightcontrols.client.ring.RingPage;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
/**

View File

@@ -11,25 +11,39 @@ package eu.midnightdust.midnightcontrols.client.gui;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.widget.SpruceButtonWidget;
import eu.midnightdust.midnightcontrols.client.HudSide;
import eu.midnightdust.lib.util.PlatformFunctions;
import eu.midnightdust.midnightcontrols.MidnightControlsConstants;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import eu.midnightdust.midnightcontrols.client.enums.HudSide;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.gui.widget.SilentTexturedButtonWidget;
import eu.midnightdust.midnightcontrols.client.compat.EmotecraftCompat;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.touch.gui.ItemUseButtonWidget;
import eu.midnightdust.midnightcontrols.client.touch.gui.SilentTexturedButtonWidget;
import eu.midnightdust.midnightcontrols.client.touch.TouchUtils;
import eu.midnightdust.midnightcontrols.client.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.DrawContext;
import net.minecraft.client.gui.screen.*;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.client.gui.widget.TextIconButtonWidget;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.texture.MissingSprite;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.InputUtil;
import net.minecraft.item.*;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.text.Text;
import net.minecraft.util.Arm;
import net.minecraft.util.Identifier;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import java.util.List;
import java.util.Objects;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
@@ -38,17 +52,26 @@ import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
*/
public class TouchscreenOverlay extends Screen {
public static final Identifier WIDGETS_LOCATION = new Identifier("midnightcontrols", "textures/gui/widgets.png");
private MidnightControlsClient mod;
private final MidnightControlsClient mod;
private SilentTexturedButtonWidget inventoryButton;
private SilentTexturedButtonWidget swapHandsButton;
private SilentTexturedButtonWidget dropButton;
private ItemUseButtonWidget useButton;
private SilentTexturedButtonWidget jumpButton;
private SilentTexturedButtonWidget flyButton;
private SilentTexturedButtonWidget flyUpButton;
private SilentTexturedButtonWidget flyDownButton;
private int flyButtonEnableTicks = 0;
private int forwardButtonTick = 0;
private SilentTexturedButtonWidget forwardButton;
private SilentTexturedButtonWidget forwardLeftButton;
private SilentTexturedButtonWidget forwardRightButton;
private SilentTexturedButtonWidget leftButton;
private SilentTexturedButtonWidget rightButton;
private SilentTexturedButtonWidget backButton;
private SilentTexturedButtonWidget startSneakButton;
private SilentTexturedButtonWidget endSneakButton;
private int flyButtonEnableTicks = 0;
private int forwardButtonTick = 0;
public static TouchscreenOverlay instance;
public TouchscreenOverlay(@NotNull MidnightControlsClient mod) {
super(Text.literal("Touchscreen overlay"));
@@ -56,27 +79,18 @@ public class TouchscreenOverlay extends Screen {
}
@Override
public boolean shouldPause()
{
public boolean shouldPause() {
return false;
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
super.keyPressed(keyCode,scanCode,modifiers);
//return false;
return true;
}
public void renderInGameBackground(DrawContext context) {}
private void pauseGame(boolean bl) {
if (this.client == null)
return;
boolean bl2 = this.client.isIntegratedServerRunning() && !this.client.getServer().isRemote();
if (bl2) {
this.client.setScreen(new GameMenuScreen(!bl));
private void pauseGame() {
assert this.client != null;
this.client.setScreen(new GameMenuScreen(true));
if (this.client.isIntegratedServerRunning() && !Objects.requireNonNull(this.client.getServer()).isRemote()) {
this.client.getSoundManager().pauseAll();
} else {
this.client.setScreen(new GameMenuScreen(true));
}
}
@@ -87,24 +101,26 @@ public class TouchscreenOverlay extends Screen {
*
*/
private void updateForwardButtonsState(boolean state) {
if (state)
this.forwardButtonTick = -1;
else
this.forwardButtonTick = 20;
this.forwardButtonTick = state ? -1 : 20;
}
/**
* Updates the jump buttons.
*/
private void updateJumpButtons() {
if (this.client == null)
return;
if (!this.client.interactionManager.isFlyingLocked()) {
assert this.client != null;
assert this.client.player != null;
float transparency = MidnightControlsConfig.touchTransparency / 100f;
if (this.client.player.getAbilities().flying) {
boolean oldStateFly = this.flyButton.isVisible();
this.jumpButton.setVisible(false);
this.flyButton.setVisible(true);
this.flyUpButton.setVisible(true);
this.flyDownButton.setVisible(true);
this.flyButton.setAlpha(transparency);
this.flyUpButton.setAlpha(transparency);
this.flyDownButton.setAlpha(transparency);
if (oldStateFly != this.flyButton.isVisible()) {
this.flyButtonEnableTicks = 5;
this.setJump(false);
@@ -115,6 +131,7 @@ public class TouchscreenOverlay extends Screen {
this.flyButton.setVisible(false);
this.flyUpButton.setVisible(false);
this.flyDownButton.setVisible(false);
this.jumpButton.setAlpha(transparency);
}
}
@@ -124,6 +141,7 @@ public class TouchscreenOverlay extends Screen {
* @param btn The pressed button.
*/
private void handleJump(SpruceButtonWidget btn) {
assert this.client != null;
((KeyBindingAccessor) this.client.options.jumpKey).midnightcontrols$handlePressState(btn.isActive());
}
/**
@@ -132,31 +150,32 @@ public class TouchscreenOverlay extends Screen {
* @param state The state.
*/
private void setJump(boolean state) {
assert this.client != null;
((KeyBindingAccessor) this.client.options.jumpKey).midnightcontrols$handlePressState(state);
}
@Override
public void tick() {
if (this.forwardButtonTick > 0) {
this.forwardButtonTick--;
} else if (this.forwardButtonTick == 0) {
if (this.forwardLeftButton.isVisible())
this.forwardLeftButton.setVisible(false);
if (this.forwardRightButton.isVisible())
this.forwardRightButton.setVisible(false);
}
this.updateJumpButtons();
}
@Override
protected void init() {
super.init();
assert this.client != null;
assert this.client.player != null;
assert this.client.interactionManager != null;
int scaledWidth = this.client.getWindow().getScaledWidth();
int scaledHeight = this.client.getWindow().getScaledHeight();
this.addDrawableChild(new TexturedButtonWidget(scaledWidth / 2 - 20, 0, 20, 20, 0, 106, 20, new Identifier("textures/gui/widgets.png"), 256, 256,
btn -> this.client.setScreen(new ChatScreen("")), Text.empty()));
this.addDrawableChild(new TexturedButtonWidget(scaledWidth / 2, 0, 20, 20, 0, 0, 20, WIDGETS_LOCATION, 256, 256,
btn -> this.pauseGame(false)));
int emoteOffset = 0;
if (PlatformFunctions.isModLoaded("emotecraft")) {
emoteOffset = 10;
TextIconButtonWidget emoteButton = TextIconButtonWidget.builder(Text.empty(), btn -> EmotecraftCompat.openEmotecraftScreen(this), true).width(20).texture(new Identifier(MidnightControlsConstants.NAMESPACE, "touch/emote"), 20, 20).build();
emoteButton.setPosition(scaledWidth / 2 - 30, 0);
this.addDrawableChild(emoteButton);
}
TextIconButtonWidget chatButton = TextIconButtonWidget.builder(Text.empty(), btn -> this.client.setScreen(new ChatScreen("")), true).width(20).texture(new Identifier(MidnightControlsConstants.NAMESPACE, "touch/chat"), 20, 20).build();
chatButton.setPosition(scaledWidth / 2 - 20 + emoteOffset, 0);
this.addDrawableChild(chatButton);
TextIconButtonWidget pauseButton = TextIconButtonWidget.builder(Text.empty(), btn -> this.pauseGame(), true).width(20).texture(new Identifier(MidnightControlsConstants.NAMESPACE, "touch/pause"), 20, 20).build();
pauseButton.setPosition(scaledWidth / 2 + emoteOffset, 0);
this.addDrawableChild(pauseButton);
// Inventory buttons.
int inventoryButtonX = scaledWidth / 2;
int inventoryButtonY = scaledHeight - 16 - 5;
@@ -165,15 +184,15 @@ public class TouchscreenOverlay extends Screen {
} else {
inventoryButtonX = inventoryButtonX + 91 + 4;
}
this.addDrawableChild(new TexturedButtonWidget(inventoryButtonX, inventoryButtonY, 20, 20, 20, 0, 20, WIDGETS_LOCATION, 256, 256,
btn -> {
if (this.client.interactionManager.hasRidingInventory()) {
this.client.player.openRidingInventory();
} else {
this.client.getTutorialManager().onInventoryOpened();
this.client.setScreen(new InventoryScreen(this.client.player));
}
}));
this.addDrawableChild(this.inventoryButton = new SilentTexturedButtonWidget(Position.of(inventoryButtonX, inventoryButtonY), 20, 20, Text.empty(), btn -> {
if (this.client.interactionManager.hasRidingInventory()) {
this.client.player.openRidingInventory();
} else {
this.client.getTutorialManager().onInventoryOpened();
this.client.setScreen(new InventoryScreen(this.client.player));
}
}, 20, 0, 20, WIDGETS_LOCATION, 256, 256));
;
int jumpButtonX, swapHandsX, sneakButtonX;
int sneakButtonY = scaledHeight - 10 - 40 - 5;
if (MidnightControlsConfig.hudSide == HudSide.LEFT) {
@@ -186,17 +205,23 @@ public class TouchscreenOverlay extends Screen {
sneakButtonX = scaledWidth - 10 - 40 - 5;
}
// Swap items hand.
this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY), 20, 20, Text.empty(),
this.addDrawableChild(this.swapHandsButton = new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY), 20, 20, Text.empty(),
button -> {
if (button.isActive()) {
if (!this.client.player.isSpectator()) {
this.client.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN));
Objects.requireNonNull(this.client.getNetworkHandler()).sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN));
}
}
},0, 160, 20, WIDGETS_LOCATION));
// Drop
this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY + 5 + 20), 20, 20, Text.empty(), btn ->
((KeyBindingAccessor) this.client.options.dropKey).midnightcontrols$handlePressState(btn.isActive()), 0, 160, 20, WIDGETS_LOCATION));
this.addDrawableChild(this.dropButton = new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY + 5 + 20), 20, 20, Text.empty(), btn -> {
if (btn.isActive() && !client.player.isSpectator() && client.player.dropSelectedItem(false)) {
client.player.swingHand(Hand.MAIN_HAND);
}
}, 20, 160, 20, WIDGETS_LOCATION));
// Use
this.addDrawableChild(this.useButton = new ItemUseButtonWidget(Position.of(width/2-25, height - 70), 50, 17, Text.translatable(MidnightControlsConstants.NAMESPACE+".action.eat"), btn ->
client.interactionManager.interactItem(client.player, client.player.getActiveHand())));
// Jump keys
this.addDrawableChild(this.jumpButton = new SilentTexturedButtonWidget(Position.of(jumpButtonX, sneakButtonY), 20, 20, Text.empty(), this::handleJump, 0, 40, 20, WIDGETS_LOCATION));
this.addDrawableChild(this.flyButton = new SilentTexturedButtonWidget(Position.of(jumpButtonX, sneakButtonY), 20, 20, Text.empty(),btn -> {
@@ -226,15 +251,13 @@ public class TouchscreenOverlay extends Screen {
this.startSneakButton.setVisible(true);
}
}, 20, 120, 20, WIDGETS_LOCATION)));
this.endSneakButton.setVisible(false);
this.addDrawableChild(this.forwardLeftButton = new SilentTexturedButtonWidget(Position.of(sneakButtonX - 20 - 5, sneakButtonY - 5 - 20), 20, 20, Text.empty(), btn -> {
((KeyBindingAccessor) this.client.options.forwardKey).midnightcontrols$handlePressState(btn.isActive());
((KeyBindingAccessor) this.client.options.leftKey).midnightcontrols$handlePressState(btn.isActive());
this.updateForwardButtonsState(btn.isActive());
}, 80, 80, 20, WIDGETS_LOCATION
));
this.forwardLeftButton.setVisible(false);
this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(sneakButtonX, sneakButtonY - 5 - 20), 20, 20, Text.empty(), btn -> {
this.addDrawableChild(this.forwardButton = new SilentTexturedButtonWidget(Position.of(sneakButtonX, sneakButtonY - 5 - 20), 20, 20, Text.empty(), btn -> {
((KeyBindingAccessor) this.client.options.forwardKey).midnightcontrols$handlePressState(btn.isActive());
this.updateForwardButtonsState(btn.isActive());
this.forwardLeftButton.setVisible(true);
@@ -247,48 +270,107 @@ public class TouchscreenOverlay extends Screen {
this.updateForwardButtonsState(btn.isActive());
}, 100, 80, 20, WIDGETS_LOCATION
));
this.forwardRightButton.setVisible(true);
this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(sneakButtonX + 20 + 5, sneakButtonY), 20, 20, Text.empty(),
this.addDrawableChild(this.rightButton =new SilentTexturedButtonWidget(Position.of(sneakButtonX + 20 + 5, sneakButtonY), 20, 20, Text.empty(),
btn -> ((KeyBindingAccessor) this.client.options.rightKey).midnightcontrols$handlePressState(btn.isActive()), 20, 80, 20, WIDGETS_LOCATION
));
this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(sneakButtonX, sneakButtonY + 20 + 5), 20, 20, Text.empty(),
this.addDrawableChild(this.backButton = new SilentTexturedButtonWidget(Position.of(sneakButtonX, sneakButtonY + 20 + 5), 20, 20, Text.empty(),
btn -> ((KeyBindingAccessor) this.client.options.backKey).midnightcontrols$handlePressState(btn.isActive()), 40, 80, 20, WIDGETS_LOCATION
));
this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(sneakButtonX - 20 - 5, sneakButtonY), 20, 20, Text.empty(),
this.addDrawableChild(this.leftButton = new SilentTexturedButtonWidget(Position.of(sneakButtonX - 20 - 5, sneakButtonY), 20, 20, Text.empty(),
btn -> ((KeyBindingAccessor) this.client.options.leftKey).midnightcontrols$handlePressState(btn.isActive()), 60, 80, 20, WIDGETS_LOCATION
));
initCustomButtons(true);
initCustomButtons(false);
this.setButtonProperties(MidnightControlsConfig.touchTransparency / 100f);
TouchscreenOverlay.instance = this;
}
private void initCustomButtons(boolean left) {
assert client != null;
Identifier emptySprite = new Identifier(MidnightControlsConstants.NAMESPACE, "touch/empty");
List<String> list = left ? MidnightControlsConfig.leftTouchBinds : MidnightControlsConfig.rightTouchBinds;
Sprite missingSprite = client.getGuiAtlasManager().getSprite(MissingSprite.getMissingSpriteId());
for (int i = 0; i < list.size(); i++) {
String bindName = list.get(i);
ButtonBinding binding = InputManager.getBinding(bindName);
if (binding == null) continue;
boolean hasTexture = client.getGuiAtlasManager().getSprite(new Identifier(MidnightControlsConstants.NAMESPACE, "binding/"+bindName)) != missingSprite;
if (MidnightControlsConfig.debug) System.out.println(left +" "+new Identifier(MidnightControlsConstants.NAMESPACE, "binding/"+bindName)+" "+ hasTexture);
var button = TextIconButtonWidget.builder(Text.translatable(binding.getTranslationKey()), b -> binding.handle(client, 1, ButtonState.PRESS), hasTexture)
.texture(hasTexture ? new Identifier(MidnightControlsConstants.NAMESPACE, "binding/"+bindName) : emptySprite, 20, 20).dimension(20, 20).build();
button.setPosition(left ? (3+(i*23)) : this.width-(23+(i*23)), 3);
button.setAlpha(MidnightControlsConfig.touchTransparency / 100f);
this.addDrawableChild(button);
}
}
private void setButtonProperties(float transparency) {
this.inventoryButton.setAlpha(transparency);
this.dropButton.setAlpha(transparency);
this.swapHandsButton.setAlpha(transparency);
this.jumpButton.setAlpha(transparency);
this.flyButton.setAlpha(transparency);
this.flyUpButton.setAlpha(transparency);
this.useButton.setAlpha(Math.min(transparency+0.1f, 1.0f));
this.flyDownButton.setAlpha(transparency);
this.startSneakButton.setAlpha(transparency);
this.endSneakButton.setAlpha(transparency);
this.forwardButton.setAlpha(transparency);
this.forwardLeftButton.setAlpha(Math.max(0.05f, transparency-0.1f));
this.forwardRightButton.setAlpha(Math.max(0.05f, transparency-0.1f));
this.leftButton.setAlpha(transparency);
this.rightButton.setAlpha(transparency);
this.backButton.setAlpha(transparency);
this.useButton.setAlpha(Math.min(transparency+0.1f, 1.0f));
this.endSneakButton.setVisible(false);
this.forwardLeftButton.setVisible(false);
this.forwardRightButton.setVisible(false);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (mouseY >= (double) (this.height - 22) && this.client != null && this.client.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.client.player.getInventory().selectedSlot = slot;
return true;
}
}
}
public void tick() {
assert this.client != null;
assert this.client.interactionManager != null;
assert this.client.player != null;
if (this.forwardButtonTick > 0) {
--this.forwardButtonTick;
} else {
this.forwardLeftButton.setVisible(false);
this.forwardRightButton.setVisible(false);
}
return super.mouseClicked(mouseX, mouseY, button);
this.useButton.setVisible(client.player.getMainHandStack() != null && (client.player.getMainHandStack().getUseAction() != UseAction.NONE || client.player.getMainHandStack().getItem() instanceof ArmorItem) && !TouchUtils.hasInWorldUseAction(client.player.getMainHandStack()));
this.updateJumpButtons();
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
if (button == GLFW.GLFW_MOUSE_BUTTON_1 && this.client != null) {
if (!MidnightControlsConfig.invertTouch) {
deltaX = -deltaX;
deltaY = -deltaY;
}
if (deltaY > 0.01)
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 2);
else if (deltaY < 0.01)
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 1);
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs((deltaY / 3.0)*MidnightControlsConfig.touchSpeed/100), 2);
else this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs((deltaY / 3.0)*MidnightControlsConfig.touchSpeed/100), 1);
if (deltaX > 0.01)
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 2);
else if (deltaX < 0.01)
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 1);
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs((deltaX / 3.0)*MidnightControlsConfig.touchSpeed/100), 2);
else this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs((deltaX / 3.0)*MidnightControlsConfig.touchSpeed/100), 1);
}
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
KeyBinding.onKeyPressed(InputUtil.fromKeyCode(keyCode, scanCode));
super.keyPressed(keyCode,scanCode,modifiers);
return true;
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
super.render(context, mouseX, mouseY, delta);
context.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
context.fill(mouseX-10, mouseY-10, mouseX+10, mouseY+10, 0xFFFFFF);
}
}

View File

@@ -9,11 +9,11 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import eu.midnightdust.lib.util.screen.TexturedOverlayButtonWidget;
import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsSettingsScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.option.ControlsOptionsScreen;
import net.minecraft.client.gui.screen.option.GameOptionsScreen;
import net.minecraft.client.gui.widget.TextIconButtonWidget;
import net.minecraft.client.option.GameOptions;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
@@ -32,8 +32,9 @@ public abstract class ControlsOptionsScreenMixin extends GameOptionsScreen {
}
@Inject(method = "init", at = @At(value = "INVOKE", ordinal = 1, shift = At.Shift.AFTER, target = "Lnet/minecraft/client/gui/screen/option/ControlsOptionsScreen;addDrawableChild(Lnet/minecraft/client/gui/Element;)Lnet/minecraft/client/gui/Element;"))
private void addControllerButton(CallbackInfo ci) {
this.addDrawableChild(new TexturedOverlayButtonWidget(this.width / 2 + 158, this.height / 6 - 12, 20, 20,0,0,20, new Identifier("midnightcontrols", "textures/gui/midnightcontrols_button.png"), 32, 64, (button) -> {
this.client.setScreen(new MidnightControlsSettingsScreen(this, false));
}, Text.translatable("midnightcontrols.menu.title.controller")));
TextIconButtonWidget iconWidget = TextIconButtonWidget.builder(Text.translatable("midnightcontrols.menu.title.controller"), (button -> this.client.setScreen(new MidnightControlsSettingsScreen(this, false))), true)
.dimension(20,20).texture(new Identifier("midnightcontrols", "icon/controller"), 20, 20).build();
iconWidget.setPosition(this.width / 2 + 158, this.height / 6 - 12);
this.addDrawableChild(iconWidget);
}
}

View File

@@ -1,21 +0,0 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client.mixin;
import net.minecraft.client.gui.navigation.NavigationDirection;
import net.minecraft.client.gui.widget.EntryListWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(EntryListWidget.class)
public interface EntryListWidgetAccessor {
//@Invoker("getNeighbouringEntry")
//void midnightcontrols$getNeighbouringEntry(NavigationDirection direction);
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client.mixin;
import net.minecraft.client.option.GameOptions;
import net.minecraft.client.option.SimpleOption;
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;
/**
* Represents a mixin to GameOptions.
* <p>
* Sets the default of the Auto-Jump option to false.
*/
@Mixin(GameOptions.class)
public abstract class GameOptionsMixin {
@Shadow public abstract SimpleOption<Boolean> getAutoJump();
@Inject(method = "load", at = @At("HEAD"))
public void onInit(CallbackInfo ci) {
// Set default value of the Auto-Jump option to false.
getAutoJump().setValue(false);
}
}

View File

@@ -9,10 +9,12 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import com.mojang.blaze3d.systems.RenderSystem;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsRenderer;
import eu.midnightdust.midnightcontrols.client.touch.TouchUtils;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.render.GameRenderer;
@@ -26,7 +28,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(GameRenderer.class)
public class GameRendererMixin {
public abstract class GameRendererMixin {
@Shadow
@Final
MinecraftClient client;
@@ -37,8 +39,14 @@ public class GameRendererMixin {
MidnightControlsClient.get().input.onPreRenderScreen(this.client, this.client.currentScreen);
}
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;draw()V", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILSOFT)
private void renderVirtualCursor(float tickDelta, long startTime, boolean tick, CallbackInfo ci, MatrixStack matrixStack, DrawContext drawContext) {
private void renderVirtualCursor(float tickDelta, long startTime, boolean tick, CallbackInfo ci, boolean bl, MatrixStack matrixStack, DrawContext drawContext) {
MidnightControlsRenderer.renderVirtualCursor(drawContext, client);
drawContext.draw();
}
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/GameRenderer;renderHand:Z", ordinal = 0), method = "renderWorld")
private void postWorldRender(float tickDelta, long limitTime, MatrixStack matrix, CallbackInfo ci) {
TouchUtils.lastProjMat.set(RenderSystem.getProjectionMatrix());
TouchUtils.lastModMat.set(RenderSystem.getModelViewMatrix());
TouchUtils.lastWorldSpaceMatrix.set(matrix.peek().getPositionMatrix());
}
}

View File

@@ -2,20 +2,14 @@ package eu.midnightdust.midnightcontrols.client.mixin;
import net.minecraft.client.util.InputUtil;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Final;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import java.lang.invoke.MethodHandle;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(InputUtil.class)
public abstract class InputUtilMixin {
@Final
@Shadow
private static MethodHandle GLFW_RAW_MOUSE_MOTION_SUPPORTED_HANDLE;
/**
* @author kabliz
* @reason This method is static, and there is a terrible UX issue if raw input is turned on at the same time as
@@ -23,17 +17,8 @@ public abstract class InputUtilMixin {
* unresponsive and the player not understanding why. This overwrite preserves the user's mouse preferences,
* while not interfering with eye tracking, and the two modes can be switched between during a play session.
*/
@Overwrite
public static boolean isRawMouseMotionSupported(){
if(MidnightControlsConfig.eyeTrackerAsMouse){
return false;
} else { //Paste original implementation from InputUtil below.
try {
return GLFW_RAW_MOUSE_MOTION_SUPPORTED_HANDLE != null &&
(boolean) GLFW_RAW_MOUSE_MOTION_SUPPORTED_HANDLE.invokeExact();
} catch (Throwable var1) {
throw new RuntimeException(var1);
}
}
@Inject(method = "isRawMouseMotionSupported", at = @At("HEAD"), cancellable = true)
private static void setRawMouseMotionSupported(CallbackInfoReturnable<Boolean> cir) {
if (MidnightControlsConfig.eyeTrackerAsMouse) cir.setReturnValue(false);
}
}

View File

@@ -15,7 +15,7 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(KeyBinding.class)
public class KeyBindingMixin implements KeyBindingAccessor {
public abstract class KeyBindingMixin implements KeyBindingAccessor {
@Shadow
private int timesPressed;

View File

@@ -1,19 +0,0 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl;
import net.minecraft.client.option.KeyBinding;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(value = KeyBindingRegistryImpl.class, remap = false)
public interface KeyBindingRegistryImplAccessor {
@Accessor @Final
static List<KeyBinding> getMODDED_KEY_BINDINGS() {
return null;
}
}

View File

@@ -0,0 +1,18 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay;
import net.minecraft.client.Keyboard;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Keyboard.class)
public class KeyboardMixin {
@Redirect(method = "onKey", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;"))
private Screen midnightcontrols$ignoreTouchOverlay(MinecraftClient instance) {
if (instance.currentScreen instanceof TouchscreenOverlay) return null;
return instance.currentScreen;
}
}

View File

@@ -9,21 +9,15 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import eu.midnightdust.midnightcontrols.MidnightControls;
import eu.midnightdust.midnightcontrols.MidnightControlsFeature;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.MidnightInput;
import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsRenderer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.client.render.BufferBuilderStorage;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
@@ -35,7 +29,6 @@ import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -46,24 +39,15 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(MinecraftClient.class)
public abstract class MinecraftClientMixin {
@Shadow
@Nullable
public HitResult crosshairTarget;
@Shadow @Nullable public HitResult crosshairTarget;
@Shadow
@Nullable
public ClientPlayerEntity player;
@Shadow @Nullable public ClientPlayerEntity player;
@Shadow
@Nullable
public ClientPlayerInteractionManager interactionManager;
@Shadow @Nullable public ClientPlayerInteractionManager interactionManager;
@Shadow
@Final
public GameRenderer gameRenderer;
@Shadow @Final public GameRenderer gameRenderer;
@Shadow
private int itemUseCooldown;
@Shadow private int itemUseCooldown;
@Shadow public abstract BufferBuilderStorage getBufferBuilders();
@@ -115,10 +99,6 @@ public abstract class MinecraftClientMixin {
// }
this.midnightcontrols$lastPos = this.player.getPos();
}
@Inject(method = "render", at = @At("HEAD"))
private void onRender(CallbackInfo ci) {
MidnightControlsClient.get().onRender((MinecraftClient) (Object) (this));
}
@Inject(at = @At("TAIL"), method = "setScreen")
private void setScreen(Screen screen, CallbackInfo info) {
@@ -161,4 +141,10 @@ public abstract class MinecraftClientMixin {
}
}
}
// This is always supposed to be located at before the line 'this.profiler.swap("Keybindings");'
// @Redirect(method = "tick", at = @At(value = "FIELD",target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", ordinal = 6))
// private Screen midnightcontrols$ignoreTouchOverlay(MinecraftClient instance) {
// if (instance.currentScreen instanceof TouchscreenOverlay) return null;
// return instance.currentScreen;
// }
}

View File

@@ -0,0 +1,15 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import net.minecraft.client.Mouse;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(Mouse.class)
public interface MouseAccessor {
@Accessor
void setLeftButtonClicked(boolean value);
@Invoker("onCursorPos")
void midnightcontrols$onCursorPos(long window, double x, double y);
}

View File

@@ -12,103 +12,104 @@ package eu.midnightdust.midnightcontrols.client.mixin;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay;
import eu.midnightdust.midnightcontrols.client.touch.TouchInput;
import eu.midnightdust.midnightcontrols.client.touch.TouchUtils;
import eu.midnightdust.midnightcontrols.client.util.MouseAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.GlfwUtil;
import net.minecraft.client.util.SmoothUtil;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
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.CallbackInfoReturnable;
import eu.midnightdust.midnightcontrols.client.mouse.EyeTrackerHandler;
import static org.lwjgl.glfw.GLFW.GLFW_CURSOR;
import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_HIDDEN;
import static eu.midnightdust.midnightcontrols.client.MidnightControlsConfig.doMixedInput;
import static org.lwjgl.glfw.GLFW.*;
/**
* Adds extra access to the mouse.
*/
@Mixin(Mouse.class)
public abstract class MouseMixin implements MouseAccessor {
@Shadow
@Final
private MinecraftClient client;
@Shadow @Final private MinecraftClient client;
@Shadow
private double y;
@Shadow private double y;
@Shadow
private double cursorDeltaX;
@Shadow private double cursorDeltaX;
@Shadow
private double cursorDeltaY;
@Shadow private double cursorDeltaY;
@Shadow
private double x;
@Shadow private double x;
@Shadow
private boolean cursorLocked;
@Shadow private boolean cursorLocked;
@Shadow
private boolean hasResolutionChanged;
@Shadow private boolean hasResolutionChanged;
@Shadow
private double lastMouseUpdateTime;
@Shadow private double lastMouseUpdateTime;
@Shadow
@Final
private SmoothUtil cursorXSmoother;
@Shadow @Final private SmoothUtil cursorXSmoother;
@Shadow
@Final
private SmoothUtil cursorYSmoother;
@Shadow @Final private SmoothUtil cursorYSmoother;
@Shadow private boolean leftButtonClicked;
@Accessor
public abstract void setLeftButtonClicked(boolean value);
@Invoker("onCursorPos")
public abstract void midnightcontrols$onCursorPos(long window, double x, double y);
@Inject(method = "onMouseButton", at = @At(value = "TAIL"))
private void onMouseBackButton(long window, int button, int action, int mods, CallbackInfo ci) {
if (action == 1 && button == GLFW.GLFW_MOUSE_BUTTON_4 && MinecraftClient.getInstance().currentScreen != null) {
if (MidnightControlsClient.get().input.tryGoBack(MinecraftClient.getInstance().currentScreen)) {
action = 0;
@Inject(method = "onMouseButton", at = @At(value = "HEAD"), cancellable = true)
private void midnightcontrols$onMouseButton(long window, int button, int action, int mods, CallbackInfo ci) {
if (window != this.client.getWindow().getHandle()) return;
if (action == 1 && button == GLFW.GLFW_MOUSE_BUTTON_4 && client.currentScreen != null) {
MidnightControlsClient.get().input.tryGoBack(client.currentScreen);
}
else if ((doMixedInput() || client.currentScreen instanceof TouchscreenOverlay) && client.player != null && button == GLFW_MOUSE_BUTTON_1) {
double mouseX = x / client.getWindow().getScaleFactor();
double mouseY = y / client.getWindow().getScaleFactor();
int centerX = client.getWindow().getScaledWidth() / 2;
if (action == 1 && mouseY >= (double) (client.getWindow().getScaledHeight() - 22) && 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)) {
client.player.getInventory().selectedSlot = slot;
ci.cancel();
return;
}
}
}
if (action == 1) {
TouchInput.clickStartTime = System.currentTimeMillis();
boolean bl = false;
if (client.currentScreen instanceof TouchscreenOverlay overlay) bl = overlay.mouseClicked(mouseX, mouseY, button);
if (!bl) TouchInput.firstHitResult = TouchUtils.getTargettedObject(mouseX, mouseY);
if (client.currentScreen == null) ci.cancel();
}
else if (TouchInput.mouseReleased(mouseX, mouseY, button)) ci.cancel();
}
}
@Inject(method = "isCursorLocked", at = @At("HEAD"), cancellable = true)
private void isCursorLocked(CallbackInfoReturnable<Boolean> ci) {
private void midnightcontrols$isCursorLocked(CallbackInfoReturnable<Boolean> ci) {
if (this.client.currentScreen == null) {
if (MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && MidnightControlsConfig.virtualMouse) {
ci.setReturnValue(true);
ci.cancel();
}
}
}
@Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true)
private void onCursorLocked(CallbackInfo ci) {
if (/*config.getControlsMode() == ControlsMode.TOUCHSCREEN
||*/ (MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && MidnightControlsConfig.virtualMouse))
private void midnightcontrols$onCursorLocked(CallbackInfo ci) {
if (MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN || doMixedInput())
ci.cancel();
}
@Inject(method = "updateMouse", at = @At("HEAD"), cancellable = true)
private void updateMouse(CallbackInfo ci) {
private void midnightcontrols$updateMouse(CallbackInfo ci) {
if (MidnightControlsConfig.eyeTrackerAsMouse && cursorLocked && client.isWindowFocused()) {
//Eye Tracking is only for the camera controlling cursor, we need the normal cursor everywhere else.
// Eye Tracking is only for the camera controlling cursor, we need the normal cursor everywhere else.
if (!client.options.smoothCameraEnabled) {
cursorXSmoother.clear();
cursorYSmoother.clear();
@@ -120,17 +121,16 @@ public abstract class MouseMixin implements MouseAccessor {
cursorDeltaY = 0.0;
ci.cancel();
}
if (doMixedInput() && client.isWindowFocused()) {
ci.cancel();
}
}
@Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true)
private void lockCursor(CallbackInfo ci) {
if (MidnightControlsConfig.eyeTrackerAsMouse && client.isWindowFocused() && !this.cursorLocked) {
if (!MinecraftClient.IS_SYSTEM_MAC) {
KeyBinding.updatePressedStates();
}
@Inject(method = "lockCursor", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/InputUtil;setCursorParameters(JIDD)V",shift = At.Shift.BEFORE), cancellable = true)
private void midnightcontrols$lockCursor(CallbackInfo ci) {
if ((doMixedInput() || MidnightControlsConfig.eyeTrackerAsMouse)) {
//In eye tracking mode, we cannot have the cursor locked to the center.
GLFW.glfwSetInputMode(client.getWindow().getHandle(), GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
cursorLocked = true; //The game uses this flag for other gameplay checks
client.setScreen(null);
hasResolutionChanged = true;
ci.cancel();

View File

@@ -1,17 +0,0 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.screen.Screen;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(Screen.class)
public interface ScreenAccessor {
@Accessor
List<Selectable> getSelectables();
@Accessor @Nullable
Selectable getSelected();
}

View File

@@ -0,0 +1,38 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import dev.lambdaurora.spruceui.Position;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.InputHandlers;
import eu.midnightdust.midnightcontrols.client.touch.gui.SilentTexturedButtonWidget;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Drawable;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.text.Text;
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 static eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay.WIDGETS_LOCATION;
@Mixin(Screen.class)
public abstract class ScreenMixin {
@Shadow protected abstract <T extends Element & Drawable & Selectable> T addDrawableChild(T drawableElement);
@Shadow public int width;
@Inject(method = "init(Lnet/minecraft/client/MinecraftClient;II)V", at = @At("TAIL"))
public void midnightcontrols$addCloseButton(MinecraftClient client, int width, int height, CallbackInfo ci) {
if (MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN && (MidnightControlsConfig.closeButtonScreens.stream().anyMatch(s -> this.getClass().getName().startsWith(s) || ((Object)this) instanceof HandledScreen<?>))) {
this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(this.width - 30, 10), 20, 20, Text.empty(), btn ->
InputHandlers.handleExit().press(client, ButtonBinding.BACK, 0f, ButtonState.PRESS), 20, 160, 20, WIDGETS_LOCATION));
}
}
}

View File

@@ -10,8 +10,12 @@
package eu.midnightdust.midnightcontrols.client.mixin;
import eu.midnightdust.lib.util.MidnightColorUtil;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.touch.TouchInput;
import eu.midnightdust.midnightcontrols.client.enums.TouchMode;
import eu.midnightdust.midnightcontrols.client.util.RainbowColor;
import net.minecraft.block.ShapeContext;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.*;
@@ -21,14 +25,17 @@ import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.shape.VoxelShape;
import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.awt.*;
@@ -54,6 +61,13 @@ public abstract class WorldRendererMixin {
@Shadow
private static void drawCuboidShapeOutline(MatrixStack matrices, VertexConsumer vertexConsumer, VoxelShape shape, double offsetX, double offsetY, double offsetZ, float red, float green, float blue, float alpha) {
}
@Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/hit/HitResult;getType()Lnet/minecraft/util/hit/HitResult$Type;"))
private HitResult.Type dontRenderOutline(HitResult instance) {
if (MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN && MidnightControlsConfig.touchMode == TouchMode.FINGER_POS) {
return HitResult.Type.MISS;
}
return instance.getType();
}
@Inject(
method = "render",
@@ -66,6 +80,32 @@ public abstract class WorldRendererMixin {
)
private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer,
LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
if (((MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && MidnightControlsConfig.touchInControllerMode) || MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN)
&& MidnightControlsConfig.touchMode == TouchMode.FINGER_POS) {
this.renderFingerOutline(matrices, camera);
}
this.renderReacharoundOutline(matrices, camera);
}
@Unique
private void renderFingerOutline(MatrixStack matrices, Camera camera) {
if (TouchInput.firstHitResult == null || TouchInput.firstHitResult.getType() != HitResult.Type.BLOCK)
return;
BlockHitResult result = (BlockHitResult) TouchInput.firstHitResult;
var blockPos = result.getBlockPos();
if (this.world.getWorldBorder().contains(blockPos) && this.client.player != null) {
var outlineShape = this.world.getBlockState(blockPos).getOutlineShape(this.client.world, blockPos, ShapeContext.of(camera.getFocusedEntity()));
Color rgb = MidnightColorUtil.hex2Rgb(MidnightControlsConfig.touchOutlineColorHex);
if (MidnightControlsConfig.touchOutlineColorHex.isEmpty()) rgb = RainbowColor.radialRainbow(1,1);
var pos = camera.getPos();
matrices.push();
var vertexConsumer = this.bufferBuilders.getEntityVertexConsumers().getBuffer(RenderLayer.getLines());
drawCuboidShapeOutline(matrices, vertexConsumer, outlineShape, blockPos.getX() - pos.getX(), blockPos.getY() - pos.getY(), blockPos.getZ() - pos.getZ(),
rgb.getRed() / 255.f, rgb.getGreen() / 255.f, rgb.getBlue() / 255.f, MidnightControlsConfig.touchOutlineColorAlpha / 255.f);
matrices.pop();
}
}
@Unique
private void renderReacharoundOutline(MatrixStack matrices, Camera camera) {
if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS || !MidnightControlsConfig.shouldRenderReacharoundOutline)
return;
var result = MidnightControlsClient.get().reacharound.getLastReacharoundResult();
@@ -90,7 +130,7 @@ public abstract class WorldRendererMixin {
var outlineShape = placementState.getOutlineShape(this.client.world, blockPos, ShapeContext.of(camera.getFocusedEntity()));
Color rgb = MidnightColorUtil.hex2Rgb(MidnightControlsConfig.reacharoundOutlineColorHex);
if (MidnightControlsConfig.reacharoundOutlineColorHex.isEmpty()) rgb = MidnightColorUtil.radialRainbow(1,1);
if (MidnightControlsConfig.reacharoundOutlineColorHex.isEmpty()) rgb = RainbowColor.radialRainbow(1,1);
matrices.push();
var vertexConsumer = this.bufferBuilders.getEntityVertexConsumers().getBuffer(RenderLayer.getLines());
drawCuboidShapeOutline(matrices, vertexConsumer, outlineShape,

View File

@@ -10,16 +10,13 @@
package eu.midnightdust.midnightcontrols.client.ring;
import com.electronwill.nightconfig.core.Config;
import eu.midnightdust.midnightcontrols.client.ButtonState;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.util.KeyBindingAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.option.StickyKeyBinding;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.OrderedText;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;

View File

@@ -0,0 +1,104 @@
package eu.midnightdust.midnightcontrols.client.touch;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
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.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import static eu.midnightdust.midnightcontrols.client.MidnightControlsConfig.doMixedInput;
public class TouchInput {
private static final MinecraftClient client = MinecraftClient.getInstance();
public static long clickStartTime;
public static HitResult firstHitResult = null;
public static void tick() {
if ((client.currentScreen == null && doMixedInput()) || client.currentScreen instanceof TouchscreenOverlay) {
double scaleFactor = client.getWindow().getScaleFactor();
if (clickStartTime > 0 && System.currentTimeMillis() - clickStartTime >= MidnightControlsConfig.touchBreakDelay) {
mouseHeldDown(client.mouse.getX() / scaleFactor, client.mouse.getY() / scaleFactor);
}
}
}
public static void mouseHeldDown(double mouseX, double mouseY) {
assert client != null;
assert client.player != null;
assert client.interactionManager != null;
if (client.player.getMainHandStack() != null && TouchUtils.hasInWorldUseAction(client.player.getMainHandStack())) {
client.interactionManager.interactItem(client.player, client.player.getActiveHand());
return;
}
HitResult result = TouchUtils.getTargettedObject(mouseX, mouseY);
if (result == null || firstHitResult == null) {
client.interactionManager.cancelBlockBreaking();
return;
}
if (result instanceof BlockHitResult blockHit && firstHitResult instanceof BlockHitResult firstBlock && blockHit.getBlockPos().equals(firstBlock.getBlockPos())) {
if (MidnightControlsConfig.debug) System.out.println(blockHit.getBlockPos().toString());
if (client.interactionManager.updateBlockBreakingProgress(blockHit.getBlockPos(), blockHit.getSide())) {
client.particleManager.addBlockBreakingParticles(blockHit.getBlockPos(), blockHit.getSide());
client.player.swingHand(Hand.MAIN_HAND);
} else client.interactionManager.cancelBlockBreaking();
firstHitResult = TouchUtils.getTargettedObject(mouseX, mouseY);
}
else if (result instanceof EntityHitResult entityHit && firstHitResult instanceof EntityHitResult firstEntity && entityHit.getEntity().getUuid().compareTo(firstEntity.getEntity().getUuid()) == 0) {
if (client.interactionManager.interactEntity(client.player, entityHit.getEntity(), client.player.getActiveHand()) == ActionResult.SUCCESS) {
client.player.swingHand(Hand.MAIN_HAND);
}
firstHitResult = TouchUtils.getTargettedObject(mouseX, mouseY);
}
}
public static boolean mouseReleased(double mouseX, double mouseY, int button) {
firstHitResult = null;
if (client.interactionManager != null) client.interactionManager.cancelBlockBreaking();
if ((client.currentScreen == null || !client.currentScreen.mouseReleased(mouseX, mouseY, button)) && System.currentTimeMillis() - clickStartTime < MidnightControlsConfig.touchBreakDelay) {
assert client.player != null;
assert client.world != null;
assert client.interactionManager != null;
clickStartTime = -1;
if (client.player.getMainHandStack() != null && TouchUtils.hasInWorldUseAction(client.player.getMainHandStack())) {
client.interactionManager.stopUsingItem(client.player);
return true;
}
HitResult result = TouchUtils.getTargettedObject(mouseX, mouseY);
if (result == null) return false;
if (result instanceof BlockHitResult blockHit) {
BlockPos blockPos = blockHit.getBlockPos().offset(blockHit.getSide());
BlockState state = client.world.getBlockState(blockPos);
if (client.world.isAir(blockPos) || state.isReplaceable()) {
ItemStack stackInHand = client.player.getMainHandStack();
int previousStackCount = stackInHand.getCount();
var interaction = client.interactionManager.interactBlock(client.player, client.player.getActiveHand(), blockHit);
if (interaction.isAccepted()) {
if (interaction.shouldSwingHand()) {
client.player.swingHand(client.player.preferredHand);
if (!stackInHand.isEmpty() && (stackInHand.getCount() != previousStackCount || client.interactionManager.hasCreativeInventory())) {
client.gameRenderer.firstPersonRenderer.resetEquipProgress(client.player.preferredHand);
}
}
return true;
}
}
}
if (result instanceof EntityHitResult entityHit) {
client.interactionManager.attackEntity(client.player, entityHit.getEntity());
client.player.swingHand(Hand.MAIN_HAND);
return true;
}
}
clickStartTime = -1;
return false;
}
}

View File

@@ -0,0 +1,68 @@
package eu.midnightdust.midnightcontrols.client.touch;
import eu.midnightdust.lib.util.PlatformFunctions;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.enums.TouchMode;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.entity.projectile.ProjectileUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.util.UseAction;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RaycastContext;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.opengl.GL11;
import static eu.midnightdust.midnightcontrols.client.MidnightReacharound.getPlayerRange;
public class TouchUtils {
private static final MinecraftClient client = MinecraftClient.getInstance();
public static final Matrix4f lastWorldSpaceMatrix = new Matrix4f();
public static final Matrix4f lastProjMat = new Matrix4f();
public static final Matrix4f lastModMat = new Matrix4f();
public static HitResult getTargettedObject(double mouseX, double mouseY) {
if (MidnightControlsConfig.touchMode == TouchMode.CROSSHAIR || PlatformFunctions.isModLoaded("vulkanmod")) {
return client.crosshairTarget;
}
Vec3d near = screenSpaceToWorldSpace(mouseX, mouseY, 0);
Vec3d far = screenSpaceToWorldSpace(mouseX, mouseY, 1);
EntityHitResult entityCast = ProjectileUtil.raycast(client.player, near, far, Box.from(client.player.getPos()).expand(getPlayerRange(client)), entity -> (!entity.isSpectator() && entity.isAttackable()), getPlayerRange(client) * getPlayerRange(client));
if (entityCast != null && entityCast.getType() == HitResult.Type.ENTITY) return entityCast;
BlockHitResult result = client.world.raycast(new RaycastContext(near, far, RaycastContext.ShapeType.OUTLINE, RaycastContext.FluidHandling.ANY, client.player));
if (client.player.getPos().distanceTo(result.getPos()) > getPlayerRange(client)) return null;
return result;
}
/* Taken from https://github.com/0x3C50/Renderer/blob/master/src/main/java/me/x150/renderer/util/RendererUtils.java#L270
* Credits to 0x3C50 */
public static Vec3d screenSpaceToWorldSpace(double x, double y, double d) {
Camera camera = client.getEntityRenderDispatcher().camera;
int displayHeight = client.getWindow().getScaledHeight();
int displayWidth = client.getWindow().getScaledWidth();
int[] viewport = new int[4];
GL11.glGetIntegerv(GL11.GL_VIEWPORT, viewport);
Vector3f target = new Vector3f();
Matrix4f matrixProj = new Matrix4f(lastProjMat);
Matrix4f matrixModel = new Matrix4f(lastModMat);
matrixProj.mul(matrixModel)
.mul(lastWorldSpaceMatrix)
.unproject((float) x / displayWidth * viewport[2],
(float) (displayHeight - y) / displayHeight * viewport[3], (float) d, viewport, target);
return new Vec3d(target.x, target.y, target.z).add(camera.getPos());
}
public static boolean hasInWorldUseAction(ItemStack stack) {
UseAction action = stack.getUseAction();
return action == UseAction.BOW || action == UseAction.BRUSH || action == UseAction.SPEAR;
}
}

View File

@@ -0,0 +1,43 @@
package eu.midnightdust.midnightcontrols.client.touch.gui;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.widget.SpruceButtonWidget;
import eu.midnightdust.midnightcontrols.MidnightControlsConstants;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.PotionItem;
import net.minecraft.text.Text;
import net.minecraft.util.UseAction;
public class ItemUseButtonWidget extends SpruceButtonWidget {
public ItemUseButtonWidget(Position position, int width, int height, Text message, PressAction action) {
super(position, width, height, message, action);
}
@Override
protected void onRelease(double mouseX, double mouseY) {
assert client.player != null;
assert client.interactionManager != null;
UseAction action = client.player.getMainHandStack().getUseAction();
if (action == UseAction.SPYGLASS || action == UseAction.TOOT_HORN) client.interactionManager.stopUsingItem(client.player);
super.onRelease(mouseX, mouseY);
}
@Override
public void setVisible(boolean visible) {
if (visible && client.player != null && client.player.getMainHandStack() != null) {
UseAction action = client.player.getMainHandStack().getUseAction();
if (action == UseAction.EAT) {
this.setMessage(Text.translatable(MidnightControlsConstants.NAMESPACE+".action.eat"));
} else if (action == UseAction.DRINK) {
this.setMessage(Text.translatable(MidnightControlsConstants.NAMESPACE+".action.drink"));
} else if (client.player.getMainHandStack().getItem() instanceof ArmorItem) {
this.setMessage(Text.translatable(MidnightControlsConstants.NAMESPACE+".action.equip"));
} else if (!action.equals(UseAction.NONE)) {
this.setMessage(Text.translatable(MidnightControlsConstants.NAMESPACE+".action.use"));
}
}
this.setAlpha(MidnightControlsConfig.touchTransparency / 100f);
super.setVisible(visible);
}
}

View File

@@ -1,4 +1,4 @@
package eu.midnightdust.midnightcontrols.client.gui.widget;
package eu.midnightdust.midnightcontrols.client.touch.gui;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.widget.SpruceTexturedButtonWidget;
@@ -23,4 +23,17 @@ public class SilentTexturedButtonWidget extends SpruceTexturedButtonWidget {
}
@Override
public void playDownSound() {}
@Override
protected void onRelease(double mouseX, double mouseY) {
this.setActive(false);
super.onClick(mouseX, mouseY);
super.onRelease(mouseX, mouseY);
this.setActive(true);
}
@Override
public void onClick(double mouseX, double mouseY) {
this.setActive(true);
super.onClick(mouseX, mouseY);
this.setActive(false);
}
}

View File

@@ -0,0 +1,23 @@
package eu.midnightdust.midnightcontrols.client.util;
import net.minecraft.util.math.MathHelper;
public class MathUtil {
public static class PolarUtil {
public float polarX;
public float polarY;
public PolarUtil() {}
public void calculate(float x, float y, float speedFactor) {
calculate(x, y, speedFactor, 0);
}
public void calculate(float x, float y, float speedFactor, double deadZone) {
double inputR = Math.pow(x, 2) + Math.pow(y, 2);
inputR = (Math.abs(speedFactor * MathHelper.clamp(inputR,0.f,1.f)));
inputR = inputR < deadZone ? 0f : (inputR-deadZone) / (1f-deadZone);
double inputTheta = Math.atan2(y, x);
polarX = (float) (inputR *Math.cos(inputTheta));
polarY = (float) (inputR *Math.sin(inputTheta));
}
}
}

View File

@@ -0,0 +1,15 @@
package eu.midnightdust.midnightcontrols.client.util;
import java.awt.*;
public class RainbowColor {
public static float hue;
public static void tick() {
if (hue > 1) hue = 0f;
hue = hue + 0.01f;
}
public static Color radialRainbow(float saturation, float brightness) {
return Color.getHSBColor(hue, saturation, brightness);
}
}

View File

@@ -16,9 +16,13 @@
"midnightcontrols.midnightconfig.enum.ControllerType.NUMBERED": "Numbered Controller",
"midnightcontrols.midnightconfig.enum.ControlsMode.DEFAULT": "Keyboard/Mouse",
"midnightcontrols.midnightconfig.enum.ControlsMode.CONTROLLER": "Controller",
"midnightcontrols.midnightconfig.enum.ControlsMode.TOUCHSCREEN": "Touchscreen (WIP)",
"midnightcontrols.midnightconfig.enum.ControlsMode.TOUCHSCREEN": "Touchscreen (Beta)",
"midnightcontrols.midnightconfig.enum.HudSide.LEFT": "Left",
"midnightcontrols.midnightconfig.enum.HudSide.RIGHT": "Right",
"midnightcontrols.midnightconfig.enum.TouchMode.CROSSHAIR": "At Crosshair",
"midnightcontrols.midnightconfig.enum.TouchMode.FINGER_POS": "Finger Position",
"midnightcontrols.midnightconfig.enum.CameraMode.FLAT": "Flat",
"midnightcontrols.midnightconfig.enum.CameraMode.ADAPTIVE": "Adaptive",
"key.midnightcontrols.look_down": "Look down",
"key.midnightcontrols.look_left": "Look left",
"key.midnightcontrols.look_right": "Look right",
@@ -30,6 +34,9 @@
"midnightcontrols.action.controls_ring": "Open Unbound Keybind Ring",
"midnightcontrols.action.debug_screen": "Open Debug HUD (F3)",
"midnightcontrols.action.drop_item": "Drop Item",
"midnightcontrols.action.drink": "Drink",
"midnightcontrols.action.eat": "Eat",
"midnightcontrols.action.equip": "Equip",
"midnightcontrols.action.exit": "Exit Screen",
"midnightcontrols.action.forward": "Forward",
"midnightcontrols.action.hit": "Hit",
@@ -121,13 +128,14 @@
"midnightcontrols.controller_type.numbered": "Numbered Controller",
"midnightcontrols.controls_mode.default": "Keyboard/Mouse",
"midnightcontrols.controls_mode.controller": "Controller",
"midnightcontrols.controls_mode.touchscreen": "Touchscreen (WIP)",
"midnightcontrols.controls_mode.touchscreen": "Touchscreen (Beta)",
"midnightcontrols.hud_side.left": "Left",
"midnightcontrols.hud_side.right": "Right",
"midnightcontrols.menu.analog_movement": "Analog Movement",
"midnightcontrols.menu.analog_movement.tooltip": "When possible, enables analog movement.",
"midnightcontrols.menu.auto_switch_mode": "Auto Switch Mode",
"midnightcontrols.menu.auto_switch_mode.tooltip": "Whether the controls mode should be switched to Controller automatically if one is connected.",
"midnightcontrols.menu.camera_mode": "Camera Mode",
"midnightcontrols.menu.controller": "Controller",
"midnightcontrols.menu.controller2": "Second Controller",
"midnightcontrols.menu.controller2.tooltip": "Second controller to use, which allows (for example) Joy-Cons support.",
@@ -195,7 +203,14 @@
"midnightcontrols.menu.title.general": "General Options",
"midnightcontrols.menu.title.hud": "HUD Options",
"midnightcontrols.menu.title.mappings.string": "Mappings File Editor",
"midnightcontrols.menu.title.touch": "Touch Options",
"midnightcontrols.menu.title.visual": "Appearance Options",
"midnightcontrols.menu.touch_break_delay": "Touch Break Delay",
"midnightcontrols.menu.touch_speed": "Touch Speed",
"midnightcontrols.menu.invert_touch": "Invert Touch Direction",
"midnightcontrols.menu.touch_mode": "Touch Interaction Mode",
"midnightcontrols.menu.touch_transparency": "Touch HUD Transparency",
"midnightcontrols.menu.touch_with_controller": "Touch in Controller mode",
"midnightcontrols.menu.unfocused_input": "Unfocused Input",
"midnightcontrols.menu.unfocused_input.tooltip": "Allows controller input when the window is not focused.",
"midnightcontrols.menu.virtual_mouse": "Virtual Mouse",
@@ -213,6 +228,7 @@
"midnightcontrols.midnightconfig.category.misc": "Miscellaneous",
"midnightcontrols.midnightconfig.category.screens": "Screens",
"midnightcontrols.midnightconfig.category.gameplay": "Gameplay",
"midnightcontrols.midnightconfig.category.touch": "Touch",
"midnightcontrols.midnightconfig.category.visual": "Visual",
"modmenu.descriptionTranslation.midnightcontrols": "Adds controller support and enhanced controls overall.\nForked from LambdaControls, which sadly got discontinued."
}

View File

@@ -1,5 +1,24 @@
{
"midnightcontrols.midnightconfig.title": "MidnightControls 고급 설정",
"midnightcontrols.midnightconfig.enum.VirtualMouseSkin.DEFAULT_LIGHT": "기본 밝게",
"midnightcontrols.midnightconfig.enum.VirtualMouseSkin.DEFAULT_DARK": "기본 어둡게",
"midnightcontrols.midnightconfig.enum.VirtualMouseSkin.SECOND_LIGHT": "두 번째 밝게",
"midnightcontrols.midnightconfig.enum.VirtualMouseSkin.SECOND_DARK": "두 번째 어둡게",
"midnightcontrols.midnightconfig.enum.ControllerType.DEFAULT": "기본값값",
"midnightcontrols.midnightconfig.enum.ControllerType.DUALSHOCK": "듀얼쇼크",
"midnightcontrols.midnightconfig.enum.ControllerType.DUALSENSE": "듀얼센스",
"midnightcontrols.midnightconfig.enum.ControllerType.SWITCH": "Switch/Wii 컨트롤러",
"midnightcontrols.midnightconfig.enum.ControllerType.XBOX": "엑스박스 원/시리즈 컨트롤러",
"midnightcontrols.midnightconfig.enum.ControllerType.XBOX_360": "엑스박스 360 컨트롤러",
"midnightcontrols.midnightconfig.enum.ControllerType.STEAM_CONTROLLER": "스팀 컨트롤러",
"midnightcontrols.midnightconfig.enum.ControllerType.STEAM_DECK": "스팀 덱",
"midnightcontrols.midnightconfig.enum.ControllerType.OUYA": "OUYA 컨트롤러",
"midnightcontrols.midnightconfig.enum.ControllerType.NUMBERED": "숫자 컨트롤러",
"midnightcontrols.midnightconfig.enum.ControlsMode.DEFAULT": "키보드/마우스",
"midnightcontrols.midnightconfig.enum.ControlsMode.CONTROLLER": "컨트롤러",
"midnightcontrols.midnightconfig.enum.ControlsMode.TOUCHSCREEN": "터치스크린 (미완성)",
"midnightcontrols.midnightconfig.enum.HudSide.LEFT": "왼쪽",
"midnightcontrols.midnightconfig.enum.HudSide.RIGHT": "오른쪽",
"key.midnightcontrols.look_down": "아래쪽 보기",
"key.midnightcontrols.look_left": "왼쪽 보기",
"key.midnightcontrols.look_right": "오른쪽 보기",
@@ -8,6 +27,7 @@
"midnightcontrols.action.attack": "공격",
"midnightcontrols.action.back": "뒤로",
"midnightcontrols.action.chat": "채팅 열기",
"midnightcontrols.action.debug_screen": "디버그 HUD 열기 (F3)",
"midnightcontrols.action.drop_item": "아이템 버리기",
"midnightcontrols.action.exit": "종료",
"midnightcontrols.action.forward": "앞으로",
@@ -150,9 +170,9 @@
"midnightcontrols.menu.rotation_speed.tooltip": "컨트롤러 모드에서 적용되는 카메라 회전 속도.",
"midnightcontrols.menu.unfocused_input.tooltip": "창이 활성화된 상태가 아니여도 컨트롤러 입력 허용.",
"midnightcontrols.menu.virtual_mouse.tooltip": "분할 화면에선 도움 되는 가상 마우스를 사용합니다.",
"midnightcontrols.virtual_mouse.skin.default_light": "기본 라이트",
"midnightcontrols.virtual_mouse.skin.default_dark": "기본 다크",
"midnightcontrols.virtual_mouse.skin.second_light": "두 번째 라이트",
"midnightcontrols.virtual_mouse.skin.second_dark": "두 번째 다크",
"midnightcontrols.virtual_mouse.skin.default_light": "기본 밝게",
"midnightcontrols.virtual_mouse.skin.default_dark": "기본 어둡게",
"midnightcontrols.virtual_mouse.skin.second_light": "두 번째 밝게",
"midnightcontrols.virtual_mouse.skin.second_dark": "두 번째 어둡게",
"modmenu.descriptionTranslation.midnightcontrols": "컨트롤러 제어 및 전반적인 향상된 제어 기능을 추가합니다.\n안타깝게도 업데이트가 끊긴 LambdaControls의 Fork 버전입니다."
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

View File

@@ -8,21 +8,20 @@
"ClientPlayerEntityMixin",
"ControlsOptionsScreenMixin",
"CreativeInventoryScreenAccessor",
"EntryListWidgetAccessor",
"GameOptionsMixin",
"GameRendererMixin",
"HandledScreenMixin",
"KeyBindingMixin",
"InputUtilMixin",
"MinecraftClientMixin",
"MouseMixin",
"MouseAccessor",
"ChatScreenMixin",
"RecipeBookWidgetAccessor",
"WorldRendererMixin",
"KeyBindingRegistryImplAccessor",
"KeyBindingIDAccessor",
"ScreenAccessor",
"TabNavigationWidgetAccessor"
"TabNavigationWidgetAccessor",
"ScreenMixin",
"KeyboardMixin"
],
"injectors": {
"defaultRequire": 1