Compare commits

...

21 Commits

Author SHA1 Message Date
LambdAurora
1039ea5344 Fix crash at startup. 2021-06-23 15:37:17 +02:00
LambdAurora
bb19ea4da5 Fix buildscript for Modrinth publishing. 2021-06-23 14:32:20 +02:00
LambdAurora
a1773cc0d9 Quick fix. 2021-06-23 14:24:49 +02:00
LambdAurora
e652390583 LambdaControls 1.7.0: update to 1.17. 2021-06-23 14:18:20 +02:00
LambdAurora
f62819d9a4 LambdaControls v1.6.0: Fix several bugs and upgrade settings screen. 2021-03-18 13:28:38 +01:00
Yao Chung Hu
978b94176c Update Mexican Spanish Translation (#49)
* Update Mexican Spanish Translation

* Remove old translation key, add missing translation key

I swear I'm not blind
2021-03-18 13:12:03 +01:00
LambdAurora
c8989cb9ee Add max values to axes, fixes #41. 2021-03-17 23:50:16 +01:00
LambdAurora
97521e832d Add stick-independent dead zones (#32) and update license headers. 2021-03-17 18:49:10 +01:00
LambdAurora
400b625716 Reformat code and update networking. 2021-03-17 00:51:34 +01:00
LambdAurora
f89eebf0e7 More WIP GUI rework! 2021-03-16 22:37:50 +01:00
LambdAurora
cc0a9aebe2 Fix #37, fix some movement bugs, more WIP GUI rework. 2021-03-16 14:51:50 +01:00
LambdAurora
b8ec934c10 Change package. 2021-03-16 00:40:56 +01:00
LambdAurora
ac8fab83a2 More GUI rework! Controller controls tab works now. 2021-03-16 00:31:24 +01:00
LambdAurora
1489b796a8 Fix gradle stupidity. 2021-03-15 21:24:16 +01:00
LambdAurora
ab8b78f75a Modules be gone! 2021-03-15 20:39:40 +01:00
LambdAurora
c7026ba1fd Old stuff be gone. 2021-03-15 17:21:43 +01:00
LambdAurora
0532913d69 WIP broken stuff. 2021-03-15 17:20:16 +01:00
LambdAurora
597700b2bc Merge pull request #34 from egeesin/1.16
Add Turkish localization
2020-11-07 20:08:38 +01:00
Ege
4edb0952d8 Add Turkish translation strings 2020-10-20 03:17:37 +03:00
LambdAurora
178f19dc2c Merge pull request #29 from Hambaka/1.16
Update Simplified Chinese localization.
2020-09-01 19:43:39 +02:00
Hambaka
129c3d0f3b Update Simplified Chinese localization.
Update zh_cn.json

Translate new 5 lines strings.
Adjust some translations. ( followed suggestions in a Chinese Minecraft community project's translation style guide, although most changes in this commit are "add space" )

Note: The translation of "Show controls ring" is not final, since ring menu feature is not completed, I am not sure its feature, so current translation is "Show extra keys (select) menu".
2020-09-02 00:00:27 +08:00
132 changed files with 4307 additions and 5927 deletions

26
.github/workflows/gradlebuild.yml vendored Executable file
View File

@@ -0,0 +1,26 @@
name: Gradle Build
on:
push:
branches:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 16
uses: actions/setup-java@v1
with:
java-version: 16
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Gradle
run: ./gradlew build
- uses: actions/upload-artifact@v2
with:
name: Artifacts
path: ./build/libs/

40
.github/workflows/gradlepublish.yml vendored Executable file
View File

@@ -0,0 +1,40 @@
name: Gradle Package
on:
push:
tags:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 16
uses: actions/setup-java@v1
with:
java-version: 16
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Gradle
run: ./gradlew build
- uses: actions/upload-artifact@v2
with:
name: Artifacts
path: ./build/libs/
# The USERNAME and PASSWORD need to correspond to the credentials environment variables used in
# the publishing section of your build.gradle
- name: Publish to GitHub Packages and other Mavens
run: ./gradlew publish
env:
BRANCH_NAME: ${{ github.ref }}
RUN_COUNT: ${{ github.run_number }}
REPO_NAME: ${{ github.repository }}
USERNAME: ${{ github.actor }}
TOKEN: ${{ secrets.GITHUB_TOKEN }}
LAMBDACONTROLS_MAVEN: ${{ secrets.MAVEN_URL }}
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}

23
.github/workflows/modrinth_update.yml vendored Executable file
View File

@@ -0,0 +1,23 @@
name: Gradle Build
on:
release:
types:
- published
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 16
uses: actions/setup-java@v1
with:
java-version: 16
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Gradle
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
run: ./gradlew publishModrinth

7
.gitignore vendored
View File

@@ -1,7 +1,7 @@
# #
# LambdAurora's ignore file # LambdAurora's ignore file
# #
# v0.13 # v0.15
# JetBrains # JetBrains
.idea/ .idea/
@@ -53,6 +53,8 @@ __pycache__/
# OS # OS
## Windows ## Windows
desktop.ini desktop.ini
# MacOS
.DS_Store
# File types # File types
*.dll *.dll
@@ -61,10 +63,13 @@ desktop.ini
*.lib *.lib
lib*.a lib*.a
*.png~ *.png~
*.tar.?z
# Common # Common
bin/ bin/
build/ build/
dist/ dist/
lib/
obj/
run/ run/
target/ target/

View File

@@ -1,6 +1,6 @@
# Changelog # Changelog
## v1.0.0 ## 1.0.0
:tada: First release! :tada: :tada: First release! :tada:
@@ -12,11 +12,11 @@
- Added key bindings for look around. - Added key bindings for look around.
- And more! - And more!
### v1.0.1 ### 1.0.1
- Fixed tutorial toast to look around not affected by camera movement done with a controller. ([#2](https://github.com/LambdAurora/LambdaControls/issues/2)) - Fixed tutorial toast to look around not affected by camera movement done with a controller. ([#2](https://github.com/LambdAurora/LambdaControls/issues/2))
### v1.0.2 (Unofficial) ### 1.0.2 (Unofficial)
This update was never pushed but was aiming to fix [#4](https://github.com/LambdAurora/LambdaControls/issues/4). This update was never pushed but was aiming to fix [#4](https://github.com/LambdAurora/LambdaControls/issues/4).
@@ -24,7 +24,7 @@ This update was never pushed but was aiming to fix [#4](https://github.com/Lambd
- Fixed broken chat arrow keys. - Fixed broken chat arrow keys.
- Optimized a little bit the button indicator. (need more work) - Optimized a little bit the button indicator. (need more work)
## v1.1.0 - Chording update ## 1.1.0 - Chording update
This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAurora/LambdaControls/issues/9)). This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAurora/LambdaControls/issues/9)).
@@ -46,9 +46,9 @@ This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAur
- HUD side affects button indicators now. - HUD side affects button indicators now.
- Added support for Advancements tabs. - Added support for Advancements tabs.
### v1.1.1 ### 1.1.1
## v1.2.0-1.3.0 ## 1.2.0-1.3.0
- Improved rotation algorithm ([#11](https://github.com/LambdAurora/LambdaControls/issues/11)). - Improved rotation algorithm ([#11](https://github.com/LambdAurora/LambdaControls/issues/11)).
- Added virtual mouse. - Added virtual mouse.
@@ -60,21 +60,21 @@ This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAur
- And more! - And more!
- v1.3.0 specific: Updated to Minecraft 1.16.1 - v1.3.0 specific: Updated to Minecraft 1.16.1
### v1.3.1 ### 1.3.1
- Fixed broken inventory interactions ([#13](https://github.com/LambdAurora/LambdaControls/issues/13)) - Fixed broken inventory interactions ([#13](https://github.com/LambdAurora/LambdaControls/issues/13))
- Fixed virtual mouse preventing continuous attack (thus making breaking blocks impossible). - Fixed virtual mouse preventing continuous attack (thus making breaking blocks impossible).
- Added support for [ModUpdater](https://gitea.thebrokenrail.com/TheBrokenRail/ModUpdater) hopefully. - Added support for [ModUpdater](https://gitea.thebrokenrail.com/TheBrokenRail/ModUpdater) hopefully.
- Updated [SpruceUI](https://github.com/LambdAurora/SpruceUI) to 1.5.2. - Updated [SpruceUI](https://github.com/LambdAurora/SpruceUI) to 1.5.2.
### v1.3.2 ### 1.3.2
- Added vertical reacharound. - Added vertical reacharound.
- Added more API for compatibility handlers. - Added more API for compatibility handlers.
- Improved reacharound API. - Improved reacharound API.
- Improved [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items) compatibility. - Improved [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items) compatibility.
## v1.4.0 ## 1.4.0
- Added analog movements ([#10](https://github.com/LambdAurora/LambdaControls/issues/10)). - Added analog movements ([#10](https://github.com/LambdAurora/LambdaControls/issues/10)).
- Improved Ok Zoomer compability. - Improved Ok Zoomer compability.
@@ -90,11 +90,11 @@ This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAur
- Will allow for better compability with other mods. - Will allow for better compability with other mods.
- Might be interesting for keyboard users too. - Might be interesting for keyboard users too.
### v1.4.1 ### 1.4.1
- Fixed crash with [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items). - Fixed crash with [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items).
## v1.5.0 ## 1.5.0
- Added mappings string editor screen. - Added mappings string editor screen.
- Added Simplified Chinese translations ([#18](https://github.com/LambdAurora/LambdaControls/pull/18)). - Added Simplified Chinese translations ([#18](https://github.com/LambdAurora/LambdaControls/pull/18)).
@@ -104,9 +104,32 @@ This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAur
- Respect toggle setting in Accessibility screen. - Respect toggle setting in Accessibility screen.
- Tweaked rotation speeds. - Tweaked rotation speeds.
- Updated to Minecraft 1.16.2. - Updated to Minecraft 1.16.2.
- Updated [SpruceUI](https://github.com/LambdAurora/SpruceUI) to 1.6.4. - Updated [SpruceUI] to 1.6.4.
- Overhauled REI compatibility. - Overhauled REI compatibility.
- Improved horizontal reach-around. - Improved horizontal reach-around.
- Fixed crashes with Ok Zoomer. - Fixed crashes with Ok Zoomer.
- Fixed crashes with key unbinding. - Fixed crashes with key unbinding.
- More WIP on keybind ring. - More WIP on keybind ring.
## 1.6.0
- Reworked entirely the settings screen.
- Added independent stick dead zones. ([#32](https://github.com/LambdAurora/LambdaControls/issues/32))
- Added max values range. ([#41](https://github.com/LambdAurora/LambdaControls/issues/41))
- Updated [SpruceUI] and fix related crashes due to incompatible versions ([#40](https://github.com/LambdAurora/LambdaControls/issues/40), [#48](https://github.com/LambdAurora/LambdaControls/issues/48)).
- Fix boat control issues ([#37](https://github.com/LambdAurora/LambdaControls/issues/37)).
- Fix incompatibilities with mods using night-config. Now shadowing properly night-config. ([#33](https://github.com/LambdAurora/LambdaControls/issues/33), [#39](https://github.com/LambdAurora/LambdaControls/issues/39))
## 1.7.0
- Updated to 1.17.
- Small improvements to the codebase thanks to Java 16.
- Fix controller bindings not being saved ([#31](https://github.com/LambdAurora/LambdaControls/issues/31), [#55](https://github.com/LambdAurora/LambdaControls/issues/55)).
- Dropped entirely Touchscreen Input Mode.
- Dropped Roughly Enough Items compatibility.
### 1.7.1
- Fix crash at startup.
[SpruceUI]: https://github.com/LambdAurora/SpruceUI

View File

@@ -26,7 +26,7 @@ By participating, you are expected to uphold this code. Please report unacceptab
[Fabric](https://fabricmc.net/) is the mod loader and the software which allows Gradle to setup the workspace. [Fabric](https://fabricmc.net/) is the mod loader and the software which allows Gradle to setup the workspace.
### Java 8 ### Java 16
Java is the main language used to make LambdaControls alive. Java is the main language used to make LambdaControls alive.
Knowing how to code in Java is necessary if you contribute to the code. Knowing how to code in Java is necessary if you contribute to the code.
@@ -47,7 +47,7 @@ As it is a Minecraft mod you should know a bit how Minecraft works and how moddi
Git is the control version software we use for LambdaControls, please know how to use it if you consider contributing to the code. Git is the control version software we use for LambdaControls, please know how to use it if you consider contributing to the code.
Git commits should be and must be signed. Git commits should be signed.
## How can I contribute? ## How can I contribute?
@@ -55,17 +55,17 @@ Git commits should be and must be signed.
#### Before submitting a bug report #### Before submitting a bug report
- Check if you can reproduce it on other platforms, on multiple web browsers. - Check if you can reproduce it on other platforms.
- Perform a search to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one. - Perform a search to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one.
#### How do I submit a bug report? #### How do I submit a bug report?
Go in the issues tab in GitHub and read the [bug report guide](https://github.com/LambdAurora/LambdaControls/blob/master/.github/ISSUE_TEMPLATE/bug_report.md) Go in the issues tab in GitHub and read the [bug report guide](https://github.com/LambdAurora/LambdaControls/blob/1.17/.github/ISSUE_TEMPLATE/bug_report.md)
### Suggesting enhancements ### Suggesting enhancements
Enhancement suggestions are tracked as [GitHub issues](https://github.com/LambdAurora/LambdaControls/issues). Enhancement suggestions are tracked as [GitHub issues](https://github.com/LambdAurora/LambdaControls/issues).
Check out the [feature request](https://github.com/LambdAurora/LambdaControls/blob/master/.github/ISSUE_TEMPLATE/feature_request.md) guide. Check out the [feature request](https://github.com/LambdAurora/LambdaControls/blob/1.17/.github/ISSUE_TEMPLATE/feature_request.md) guide.
### Do pull requests ### Do pull requests
@@ -81,21 +81,16 @@ Feel free to pull request!
### Git commit messages ### Git commit messages
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...") * Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Consider starting the commit message with an emote, emotes for your commit can be found at the [gitmoji guide](https://gitmoji.carloscuesta.me/).
* (Not for the message) Don't forget to sign the commit. * (Not for the message) Don't forget to sign the commit.
### Naming convention ### Naming convention
Names in the code should be explicit and always in `snake_case`, `camelCase` will not be allowed. Names in the code should be explicit and always in `camelCase`, `snake_case` will not be allowed.
`PascalCase` can be used for class name. `PascalCase` can be used for class name.
We chose `snake_case` because it is more accessible for everyone: for people who don't speak English as their native language it is more easy to see the words when they are separated,
it also allows the correct use of screen reader on the code with `snake_case` due to the absence of upper case characters.
### Brace placement ### Brace placement
Every braces should be at the end of the line of function declaration, etc... Every braces should be at the end of the line of function declaration, etc.
The only exception is class declarations: braces must be on the next line.
### Quick note for users of the Intellij IDEA IDE ### Quick note for users of the Intellij IDEA IDE

6
HEADER Normal file
View File

@@ -0,0 +1,6 @@
Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
This file is part of LambdaControls.
Licensed under the MIT license. For more information,
see the LICENSE file.

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,11 +1,13 @@
# LambdaControls # LambdaControls
![Java 8](https://img.shields.io/badge/language-Java%208-9B599A.svg?style=flat-square) <!-- modrinth_exclude.start -->
![Java 16](https://img.shields.io/badge/language-Java%2016-9B599A.svg?style=flat-square) <!-- modrinth_exclude.end -->
[![GitHub license](https://img.shields.io/github/license/LambdAurora/LambdaControls?style=flat-square)](https://raw.githubusercontent.com/LambdAurora/LambdaControls/master/LICENSE) [![GitHub license](https://img.shields.io/github/license/LambdAurora/LambdaControls?style=flat-square)](https://raw.githubusercontent.com/LambdAurora/LambdaControls/master/LICENSE)
![Environment: Client](https://img.shields.io/badge/environment-client-1976d2?style=flat-square) ![Environment: Client](https://img.shields.io/badge/environment-client-1976d2?style=flat-square)
![Mod loader: Fabric](https://img.shields.io/badge/modloader-Fabric-1976d2?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAFHGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE4LTEyLTE2VDE2OjU0OjE3LTA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0wNy0yOFQyMToxNzo0OC0wNzowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0wNy0yOFQyMToxNzo0OC0wNzowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowZWRiMWMyYy1mZjhjLWU0NDEtOTMxZi00OTVkNGYxNGM3NjAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MGVkYjFjMmMtZmY4Yy1lNDQxLTkzMWYtNDk1ZDRmMTRjNzYwIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MGVkYjFjMmMtZmY4Yy1lNDQxLTkzMWYtNDk1ZDRmMTRjNzYwIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDowZWRiMWMyYy1mZjhjLWU0NDEtOTMxZi00OTVkNGYxNGM3NjAiIHN0RXZ0OndoZW49IjIwMTgtMTItMTZUMTY6NTQ6MTctMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4/HiGMAAAAtUlEQVRYw+XXrQqAMBQF4D2P2eBL+QIG8RnEJFaNBjEum+0+zMQLtwwv+wV3ZzhhMDgfJ0wUSinxZUQWgKos1JP/AbD4OneIDyQPwCFniA+EJ4CaXm4TxAXCC0BNHgLhAdAnx9hC8PwGSRtAFVMQjF7cNTWED8B1cgwW20yfJgAvrssAsZ1cB3g/xckAxr6FmCDU5N6f488BrpCQ4rQBJkiMYh4ACmLzwOQF0CExinkCsvw7vgGikl+OotaKRwAAAABJRU5ErkJggg==) [![Mod loader: Fabric]][fabric] <!-- modrinth_exclude.start -->
![Version](https://img.shields.io/github/v/tag/LambdAurora/LambdaControls?label=version&style=flat-square) ![Version](https://img.shields.io/github/v/tag/LambdAurora/LambdaControls?label=version&style=flat-square)
[![CurseForge](http://cf.way2muchnoise.eu/title/354231.svg)](https://www.curseforge.com/minecraft/mc-mods/lambdacontrols) [![CurseForge](http://cf.way2muchnoise.eu/title/354231.svg)](https://www.curseforge.com/minecraft/mc-mods/lambdacontrols)
<!-- modrinth_exclude.end -->
A Fabric Minecraft mod which adds better controls, reach-around and controller support. A Fabric Minecraft mod which adds better controls, reach-around and controller support.
@@ -19,27 +21,37 @@ This mod also adds controller support.
## ✅ Features: ## ✅ Features:
- Controller support - Controller support
- Touchscreen support (very experimental and buggy). - Touchscreen support (very experimental and buggy).
- Keyboard controls to look around. - Keyboard controls to look around.
- Toggleable on screen button indicator (like in Bedrock Edition). - Toggleable on screen button indicator (like in Bedrock Edition).
- Vertical reach-around. - Vertical reach-around.
- Many Bedrock Edition features: - Many Bedrock Edition features:
- Toggleable fly drifting - Toggleable fly drifting
- Front block placing (be careful with this one) - Front block placing (be careful with this one)
- New controls settings! - New controls settings!
- Many options in config to change to your liking. - Many options in config to change to your liking.
- Many controllers supported and in a simply way your own controller mappings. - Many controllers supported and in a simply way your own controller mappings.
- An easy API for developers to add their own button bindings. - An easy API for developers to add their own button bindings.
## 🎮 Supported Controllers: ## 🎮 Supported Controllers:
- Dualshock controllers - Dualshock controllers
- Xbox controllers - Xbox controllers
- Switch Pro controllers - Switch Pro controllers
- Joycons - Joycons
- And many more! - And many more!
## Screenshots
![controller_controls](images/controller_controls.png)
![controller_options](images/controller_options.png)
<!-- modrinth_exclude.start -->
## Build ## Build
Just do `./gradlew :fabric:shadowRemapJar` and everything should build just fine! Just do `./gradlew build` and everything should build just fine!
<!-- modrinth_exclude.end -->
[fabric]: https://fabricmc.net
[Mod loader: Fabric]: https://img.shields.io/badge/modloader-Fabric-1976d2?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAFHGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE4LTEyLTE2VDE2OjU0OjE3LTA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0wNy0yOFQyMToxNzo0OC0wNzowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0wNy0yOFQyMToxNzo0OC0wNzowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowZWRiMWMyYy1mZjhjLWU0NDEtOTMxZi00OTVkNGYxNGM3NjAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MGVkYjFjMmMtZmY4Yy1lNDQxLTkzMWYtNDk1ZDRmMTRjNzYwIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MGVkYjFjMmMtZmY4Yy1lNDQxLTkzMWYtNDk1ZDRmMTRjNzYwIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDowZWRiMWMyYy1mZjhjLWU0NDEtOTMxZi00OTVkNGYxNGM3NjAiIHN0RXZ0OndoZW49IjIwMTgtMTItMTZUMTY6NTQ6MTctMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4/HiGMAAAAtUlEQVRYw+XXrQqAMBQF4D2P2eBL+QIG8RnEJFaNBjEum+0+zMQLtwwv+wV3ZzhhMDgfJ0wUSinxZUQWgKos1JP/AbD4OneIDyQPwCFniA+EJ4CaXm4TxAXCC0BNHgLhAdAnx9hC8PwGSRtAFVMQjF7cNTWED8B1cgwW20yfJgAvrssAsZ1cB3g/xckAxr6FmCDU5N6f488BrpCQ4rQBJkiMYh4ACmLzwOQF0CExinkCsvw7vgGikl+OotaKRwAAAABJRU5ErkJggg==

View File

@@ -1,57 +1,265 @@
plugins { plugins {
id 'java-library' id 'fabric-loom' version '0.9.+'
id 'maven-publish' id 'java-library'
id 'maven-publish'
id 'com.github.johnrengelman.shadow' version '7.0.0'
id 'org.cadixdev.licenser' version '0.6.1'
id 'com.modrinth.minotaur' version '1.2.+'
} }
allprojects { import net.fabricmc.loom.task.RemapJarTask
group = project.maven_group import com.google.gson.GsonBuilder
version = project.mod_version 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
repositories { group = project.maven_group
mavenLocal() version = "${project.mod_version}+${getMCVersionString()}"
mavenCentral() archivesBaseName = project.archives_base_name
maven { url = 'https://aperlambda.github.io/maven' }
}
dependencies { // This field defines the Java version your mod target.
} def targetJavaVersion = 16
tasks.withType(JavaCompile) { boolean isMCVersionNonRelease() {
options.encoding = "UTF-8" return project.minecraft_version.matches('^\\d\\dw\\d\\d[a-z]$')
} || project.minecraft_version.matches('\\d+\\.\\d+-(pre|rc)(\\d+)')
}
publishing {
repositories { String getMCVersionString() {
mavenLocal() if (isMCVersionNonRelease()) {
maven { return project.minecraft_version
name = "GithubPackages" }
url = uri("https://maven.pkg.github.com/LambdAurora/LambdaControls") def version = project.minecraft_version.split('\\.')
credentials { return version[0] + '.' + version[1]
username = project.findProperty("gpr.user") ?: System.getenv("USERNAME") }
password = project.findProperty("gpr.key") ?: System.getenv("TOKEN")
} String parseReadme() {
} def excludeRegex = /(?m)<!-- modrinth_exclude\.start -->(.|\n)*?<!-- modrinth_exclude\.end -->/
} def linkRegex = /!\[([A-z_ ]+)]\((images\/[A-z.\/_]+)\)/
}
def readme = (String) file('README.md').text
readme = readme.replaceAll(excludeRegex, '')
readme = readme.replaceAll(linkRegex, '![$1](https://raw.githubusercontent.com/LambdAurora/LambdaControls/1.17/$2)')
return readme
}
minecraft {
accessWidener file('src/main/resources/lambdacontrols.accesswidener')
}
repositories {
mavenLocal()
mavenCentral()
maven { url 'https://aperlambda.github.io/maven' }
maven {
name 'Gegy'
url 'https://maven.gegy.dev'
}
maven {
name 'CottonMC'
url 'https://server.bbkr.space:8081/artifactory/libs-snapshot'
}
maven {
name 'Terraformers'
url 'https://maven.terraformersmc.com/releases'
}
maven { url 'https://maven.shedaniel.me/' }
}
configurations {
shadow
api.extendsFrom shadow
}
dependencies {
//to change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation "dev.lambdaurora:spruceui:${project.spruceui_version}"
include "dev.lambdaurora:spruceui:${project.spruceui_version}"
modImplementation "com.terraformersmc:modmenu:${project.modmenu_version}"
// Compatibility mods
/*modImplementation("com.github.joaoh1:okzoomer:e13183c59b") {
exclude group: 'me.shedaniel.cloth'
exclude group: 'io.github.prospector'
}*/
shadow 'com.electronwill.night-config:core:3.6.3'
shadow 'com.electronwill.night-config:toml:3.6.3'
}
java {
sourceCompatibility = JavaVersion.toVersion(targetJavaVersion)
targetCompatibility = JavaVersion.toVersion(targetJavaVersion)
withSourcesJar()
}
tasks.withType(JavaCompile).configureEach {
it.options.encoding = 'UTF-8'
it.options.release.set(targetJavaVersion)
}
processResources {
inputs.property 'version', project.version
filesMatching('fabric.mod.json') {
expand 'version': project.version
}
}
jar {
from('LICENSE') {
rename { "${it}_${project.archivesBaseName}" }
}
}
license {
header file('HEADER')
include '**/*.java'
}
shadowJar {
dependsOn jar
configurations = [project.configurations.shadow]
archiveClassifier.set('dev')
exclude 'META-INF/maven/**'
exclude 'com/google/**'
exclude 'javax/**'
exclude 'org/**'
relocate 'com.electronwill.nightconfig', 'dev.lambdaurora.lambdacontrols.shadow.nightconfig'
}
remapJar.dependsOn(shadowJar)
task shadowRemapJar(type: RemapJarTask) {
dependsOn shadowJar
input.set(file("${project.buildDir}/libs/$archivesBaseName-$version-dev.jar"))
archiveFileName = "${archivesBaseName}-${version}.jar"
addNestedDependencies.set(true)
remapAccessWidener.set(true)
}
build.dependsOn(shadowRemapJar)
task publishModrinth(type: TaskModrinthUpload) {
dependsOn(build)
onlyIf {
System.getenv('MODRINTH_TOKEN')
}
token = System.getenv('MODRINTH_TOKEN')
projectId = project.modrinth_id
versionNumber = version
versionName = "LambdaControls ${project.mod_version} (${getMCVersionString()})"
uploadFile = shadowRemapJar
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
matcher.find()
changelog = matcher.group(1)
// 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()}")
}
}
} }
/*
// configure the maven publication // configure the maven publication
publishing { publishing {
publications { publications {
mavenJava(MavenPublication) { mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven artifact(shadowRemapJar) {
artifact(remapJar) { builtBy shadowRemapJar
builtBy remapJar }
} artifact(sourcesJar) {
artifact(sourcesJar) { builtBy remapSourcesJar
builtBy remapSourcesJar }
}
}
}
// select the repositories you want to publish to pom {
repositories { name = 'LambdaControls'
mavenLocal() 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/LambdaControls")
credentials {
username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") ?: System.getenv("TOKEN")
}
}
def lambdacontrolsMaven = System.getenv('LAMBDACONTROLS_MAVEN')
if (lambdacontrolsMaven) {
maven {
name 'LambdaControlsMaven'
url uri(lambdacontrolsMaven)
credentials {
username = project.findProperty('gpr.user') ?: System.getenv('MAVEN_USERNAME')
password = project.findProperty('gpr.key') ?: System.getenv('MAVEN_PASSWORD')
}
}
}
}
}

View File

@@ -1,32 +0,0 @@
plugins {
id 'java-library'
id 'maven-publish'
}
archivesBaseName = project.archives_base_name + "-core"
dependencies {
api "org.jetbrains:annotations:17.0.0"
api "org.aperlambda:lambdajcommon:1.8.1"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withSourcesJar()
}
publishing {
publications {
mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven
artifact(jar) {
builtBy jar
}
artifact(sourcesJar) {
builtBy sourcesJar
}
}
}
}

View File

@@ -1,21 +0,0 @@
plugins {
id 'java-library'
}
archivesBaseName = project.archives_base_name + "-elytra"
repositories {
maven { url = 'https://hub.spigotmc.org/nexus/content/groups/public/' }
maven { url = 'https://mcelytra.github.io/maven/' }
maven { url = 'https://libraries.minecraft.net/' }
}
dependencies {
api project(":core")
implementation "org.mcelytra:elytra-core:1.0.0-SNAPSHOT"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.event;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
import org.aperlambda.lambdacommon.Identifier;
import org.jetbrains.annotations.NotNull;
import org.mcelytra.core.entity.EntityPlayer;
import org.mcelytra.core.event.HandlerList;
import org.mcelytra.core.event.player.PlayerEvent;
/**
* Represents an event which is fired when a player change their controls mode.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class PlayerControlsModeEvent extends PlayerEvent
{
private static final HandlerList HANDLERS = new HandlerList();
private final ControlsMode controlsMode;
public PlayerControlsModeEvent(@NotNull EntityPlayer player, @NotNull ControlsMode controlsMode)
{
super(new Identifier(LambdaControlsConstants.NAMESPACE, "player_controls_mode"), player, true);
this.controlsMode = controlsMode;
}
/**
* Returns the controls mode of the player.
*
* @return The player's controls mode.
*/
public ControlsMode getControlsMode()
{
return this.controlsMode;
}
@Override
public @NotNull HandlerList getHandlers()
{
return HANDLERS;
}
}

View File

@@ -1,127 +0,0 @@
import net.fabricmc.loom.task.RemapJarTask
plugins {
id 'fabric-loom' version '0.4-SNAPSHOT'
id 'java-library'
id 'maven-publish'
}
version = "${project.mod_version}+${project.minecraft_version}"
archivesBaseName = project.archives_base_name + "-fabric"
minecraft {
}
repositories {
maven {
name = 'CottonMC'
url = 'http://server.bbkr.space:8081/artifactory/libs-snapshot'
}
repositories {
maven { url = "https://jitpack.io" }
}
}
configurations {
shadowInternal
shadow
api.extendsFrom shadow
}
dependencies {
//to change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation "io.github.prospector:modmenu:${project.modmenu_version}"
modImplementation "com.github.lambdaurora:spruceui:${project.spruceui_version}"
include "com.github.lambdaurora:spruceui:${project.spruceui_version}"
// Compatibility mods
modImplementation "com.github.joaoh1:okzoomer:e13183c59b"
modImplementation "me.shedaniel:RoughlyEnoughItems:5.2.3"
api project(":core")
shadowInternal project(":core")
shadow("org.aperlambda:lambdajcommon:1.8.1") {
// Minecraft already has all that google crap.
exclude group: 'com.google.code.gson'
exclude group: 'com.google.guava'
}
shadow "com.electronwill.night-config:core:3.5.3"
shadow "com.electronwill.night-config:toml:3.5.3"
}
processResources {
inputs.property "version", project.version
from(sourceSets.main.resources.srcDirs) {
include "fabric.mod.json"
expand "version": project.version
}
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withSourcesJar()
}
jar {
from "../LICENSE"
}
task shadowJar(type: Jar) {
archiveClassifier.set("dev")
from sourceSets.main.output
from {
configurations.shadowInternal.filter {
it.getName().contains("lambdacontrols")
}.collect {
it.isDirectory() ? it : zipTree(it)
}
}
from {
configurations.shadow.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
task shadowRemapJar(type: RemapJarTask) {
dependsOn shadowJar
input = file("${project.buildDir}/libs/$archivesBaseName-$version-dev.jar")
archiveName = "${archivesBaseName}-${version}.jar"
addNestedDependencies = true
}
// configure the maven publication
publishing {
publications {
mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven
artifact(remapJar) {
builtBy remapJar
}
artifact(sourcesJar) {
builtBy remapSourcesJar
}
}
}
}
shadowJar.dependsOn(":core:jar")
build.dependsOn(":core:build")
publish.dependsOn(":core:publish")

View File

@@ -1,132 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols;
import io.netty.buffer.Unpooled;
import me.lambdaurora.lambdacontrols.event.PlayerChangeControlsModeCallback;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.Optional;
/**
* Represents the LambdaControls mod.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.0.0
*/
public class LambdaControls implements ModInitializer
{
private static LambdaControls INSTANCE;
public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(LambdaControlsConstants.CONTROLS_MODE_CHANNEL.toString());
public static final Identifier FEATURE_CHANNEL = new Identifier(LambdaControlsConstants.FEATURE_CHANNEL.toString());
public static final Identifier HELLO_CHANNEL = new Identifier(LambdaControlsConstants.HELLO_CHANNEL.toString());
public static final TranslatableText NOT_BOUND_TEXT = new TranslatableText("lambdacontrols.not_bound");
public final Logger logger = LogManager.getLogger("LambdaControls");
@Override
public void onInitialize()
{
INSTANCE = this;
this.log("Initializing LambdaControls...");
ServerSidePacketRegistry.INSTANCE.register(HELLO_CHANNEL,
(context, attachedData) -> {
String version = attachedData.readString(16);
ControlsMode.byId(attachedData.readString(32))
.ifPresent(controlsMode -> context.getTaskQueue()
.execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(context.getPlayer(), controlsMode)));
context.getTaskQueue().execute(() ->
ServerSidePacketRegistry.INSTANCE.sendToPlayer(context.getPlayer(), FEATURE_CHANNEL, this.makeFeatureBuffer(LambdaControlsFeature.HORIZONTAL_REACHAROUND)));
});
ServerSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL,
(context, attachedData) -> ControlsMode.byId(attachedData.readString(32))
.ifPresent(controlsMode -> context.getTaskQueue()
.execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(context.getPlayer(), controlsMode))));
}
/**
* Prints a message to the terminal.
*
* @param info The message to print.
*/
public void log(String info)
{
this.logger.info("[LambdaControls] " + info);
}
/**
* Prints a warning to the terminal.
*
* @param warning The warning to print.
*/
public void warn(String warning)
{
this.logger.info("[LambdaControls] " + warning);
}
/**
* Returns a packet byte buffer made for the lambdacontrols:controls_mode plugin message.
*
* @param controlsMode The controls mode to send.
* @return The packet byte buffer.
*/
public PacketByteBuf makeControlsModeBuffer(@NotNull ControlsMode controlsMode)
{
Objects.requireNonNull(controlsMode, "Controls mode cannot be null.");
return new PacketByteBuf(Unpooled.buffer()).writeString(controlsMode.getName(), 32);
}
/**
* Returns a packet byte buffer made for the lambdacontrols:feature plugin message.
*
* @param feature The feature data to send.
* @return The packet byte buffer.
*/
public PacketByteBuf makeFeatureBuffer(@NotNull LambdaControlsFeature feature)
{
Objects.requireNonNull(feature, "Feature cannot be null.");
PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()).writeString(feature.getName(), 64);
buffer.writeBoolean(feature.isAllowed());
return buffer;
}
public PacketByteBuf makeHello(@NotNull ControlsMode controlsMode)
{
String version = "";
Optional<ModContainer> container;
if ((container = FabricLoader.getInstance().getModContainer(LambdaControlsConstants.NAMESPACE)).isPresent()) {
version = container.get().getMetadata().getVersion().getFriendlyString();
}
return new PacketByteBuf(Unpooled.buffer()).writeString(version, 16).writeString(controlsMode.getName(), 32);
}
/**
* Gets the LambdaControls instance.
*
* @return The LambdaControls instance.
*/
public static LambdaControls get()
{
return INSTANCE;
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client;
import io.github.prospector.modmenu.api.ConfigScreenFactory;
import io.github.prospector.modmenu.api.ModMenuApi;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen;
/**
* Represents the API implementation of ModMenu for LambdaControls.
*
* @author LambdAurora
* @version 1.3.0
* @since 1.1.0
*/
public class LambdaControlsModMenu implements ModMenuApi
{
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory()
{
return parent -> new LambdaControlsSettingsScreen(parent, false);
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.compat;
import io.github.joaoh1.okzoomer.client.keybinds.ZoomKeybinds;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
/**
* Represents a compatibility handler for OkZoomer.
*
* @author LambdAurora
* @version 1.4.3
* @since 1.1.0
*/
public class OkZoomerCompat implements CompatHandler
{
@Override
public void handle(@NotNull LambdaControlsClient mod)
{
new ButtonBinding.Builder("zoom")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW.GLFW_GAMEPAD_BUTTON_X)
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.zoomKey)
.register();
if (ZoomKeybinds.areExtraKeybindsEnabled()) {
new ButtonBinding.Builder("zoom_in")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true))
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.increaseZoomKey)
.register();
new ButtonBinding.Builder("zoom_out")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true))
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.decreaseZoomKey)
.register();
new ButtonBinding.Builder("zoom_reset")
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.resetZoomKey)
.register();
}
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.compat.mixin;
import me.shedaniel.rei.gui.widget.EntryListEntryWidget;
import me.shedaniel.rei.gui.widget.EntryListWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
/**
* Represents an accessor to REI's EntryListWidget.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.5.0
*/
@Mixin(value = EntryListWidget.class, remap = false)
public interface EntryListWidgetAccessor
{
@Accessor(value = "entries")
List<EntryListEntryWidget> getEntries();
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.compat.mixin;
import me.shedaniel.rei.api.EntryStack;
import me.shedaniel.rei.gui.widget.EntryWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
/**
* Represents an accessor to REI's EntryWidget.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.5.0
*/
@Mixin(value = EntryWidget.class, remap = false)
public interface EntryWidgetAccessor
{
@Invoker("getCurrentEntry")
EntryStack lambdacontrols_getCurrentEntry();
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.compat.mixin;
import me.shedaniel.rei.api.widgets.Button;
import me.shedaniel.rei.gui.RecipeViewingScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
/**
* Represents an accessor to REI's RecipeViewingScreen.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.2.0
*/
@Mixin(value = RecipeViewingScreen.class, remap = false)
public interface RecipeViewingScreenAccessor
{
@Accessor("categoryBack")
Button getCategoryBack();
@Accessor("categoryNext")
Button getCategoryNext();
@Accessor("recipeBack")
Button getRecipeBack();
@Accessor("recipeNext")
Button getRecipeNext();
}

View File

@@ -1,654 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.client.ButtonState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.Identifier;
import org.aperlambda.lambdacommon.utils.Nameable;
import org.aperlambda.lambdacommon.utils.function.PairPredicate;
import org.aperlambda.lambdacommon.utils.function.Predicates;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.stream.Collectors;
import static me.lambdaurora.lambdacontrols.client.controller.InputManager.registerDefaultCategory;
import static org.lwjgl.glfw.GLFW.*;
/**
* Represents a button binding.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.0.0
*/
public class ButtonBinding implements Nameable
{
public static final ButtonCategory MOVEMENT_CATEGORY;
public static final ButtonCategory GAMEPLAY_CATEGORY;
public static final ButtonCategory INVENTORY_CATEGORY;
public static final ButtonCategory MULTIPLAYER_CATEGORY;
public static final ButtonCategory MISC_CATEGORY;
public static final ButtonBinding ATTACK = new Builder("attack").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true)).onlyInGame().register();
public static final ButtonBinding BACK = new Builder("back").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding CHAT = new Builder("chat").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT).onlyInGame().cooldown().register();
public static final ButtonBinding DROP_ITEM = new Builder("drop_item").buttons(GLFW_GAMEPAD_BUTTON_B).onlyInGame().cooldown().register();
public static final ButtonBinding FORWARD = new Builder("forward").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding HOTBAR_LEFT = new Builder("hotbar_left").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.action(InputHandlers.handleHotbar(false)).onlyInGame().cooldown().register();
public static final ButtonBinding HOTBAR_RIGHT = new Builder("hotbar_right").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
.action(InputHandlers.handleHotbar(true)).onlyInGame().cooldown().register();
public static final ButtonBinding INVENTORY = new Builder("inventory").buttons(GLFW_GAMEPAD_BUTTON_Y).onlyInGame().cooldown().register();
public static final ButtonBinding JUMP = new Builder("jump").buttons(GLFW_GAMEPAD_BUTTON_A).onlyInGame().register();
public static final ButtonBinding LEFT = new Builder("left").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding PAUSE_GAME = new Builder("pause_game").buttons(GLFW_GAMEPAD_BUTTON_START).action(InputHandlers::handlePauseGame).cooldown().register();
public static final ButtonBinding PICK_BLOCK = new Builder("pick_block").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT).onlyInGame().cooldown().register();
public static final ButtonBinding PLAYER_LIST = new Builder("player_list").buttons(GLFW_GAMEPAD_BUTTON_BACK).onlyInGame().register();
public static final ButtonBinding RIGHT = new Builder("right").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding SCREENSHOT = new Builder("screenshot").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_A)
.action(InputHandlers::handleScreenshot).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)
.action(InputHandlers.handleInventorySlotPad(3)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_RIGHT = new Builder("slot_right").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)
.action(InputHandlers.handleInventorySlotPad(2)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_UP = new Builder("slot_up").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP)
.action(InputHandlers.handleInventorySlotPad(0)).onlyInInventory().cooldown().register();
public static final ButtonBinding SMOOTH_CAMERA = new Builder("toggle_smooth_camera").onlyInGame().cooldown().register();
public static final ButtonBinding SNEAK = new Builder("sneak").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)
.actions(InputHandlers::handleToggleSneak).onlyInGame().cooldown().register();
public static final ButtonBinding SPRINT = new Builder("sprint").buttons(GLFW_GAMEPAD_BUTTON_LEFT_THUMB).onlyInGame().register();
public static final ButtonBinding SWAP_HANDS = new Builder("swap_hands").buttons(GLFW_GAMEPAD_BUTTON_X).onlyInGame().cooldown().register();
public static final ButtonBinding TAB_LEFT = new Builder("tab_back").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.action(InputHandlers.handleHotbar(false)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown().register();
public static final ButtonBinding TAB_RIGHT = new Builder("tab_next").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
.action(InputHandlers.handleHotbar(true)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown().register();
public static final ButtonBinding TOGGLE_PERSPECTIVE = new Builder("toggle_perspective").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_Y).cooldown().register();
public static final ButtonBinding USE = new Builder("use").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true)).register();
private int[] button;
private int[] defaultButton;
private String key;
private KeyBinding mcKeyBinding = null;
protected PairPredicate<MinecraftClient, ButtonBinding> filter;
private List<PressAction> actions = new ArrayList<>(Collections.singletonList(PressAction.DEFAULT_ACTION));
private boolean hasCooldown;
private int cooldown = 0;
boolean pressed = false;
public ButtonBinding(@NotNull String key, int[] defaultButton, @NotNull List<PressAction> actions, PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown)
{
this.setButton(this.defaultButton = defaultButton);
this.key = key;
this.filter = filter;
this.actions.addAll(actions);
this.hasCooldown = hasCooldown;
}
public ButtonBinding(@NotNull String key, int[] defaultButton, boolean hasCooldown)
{
this(key, defaultButton, Collections.emptyList(), Predicates.pairAlwaysTrue(), hasCooldown);
}
/**
* Returns the button bound.
*
* @return The bound button.
*/
public int[] getButton()
{
return this.button;
}
/**
* Sets the bound button.
*
* @param button The bound button.
*/
public void setButton(int[] button)
{
this.button = button;
if (InputManager.hasBinding(this))
InputManager.sortBindings();
}
/**
* Returns whether the bound button is the specified button or not.
*
* @param button The button to check.
* @return True if the bound button is the specified button, else false.
*/
public boolean isButton(int[] button)
{
return InputManager.areButtonsEquivalent(button, this.button);
}
/**
* Returns whether this button is down or not.
*
* @return True if the button is down, else false.
*/
public boolean isButtonDown()
{
return this.pressed;
}
/**
* Returns whether this button binding is bound or not.
*
* @return True if this button binding is bound, else false.
*/
public boolean isNotBound()
{
return this.button.length == 0 || this.button[0] == -1;
}
/**
* Gets the default button assigned to this binding.
*
* @return The default button.
*/
public int[] getDefaultButton()
{
return this.defaultButton;
}
/**
* Returns whether the assigned button is the default button.
*
* @return True if the assigned button is the default button, else false.
*/
public boolean isDefault()
{
return this.button.length == this.defaultButton.length && InputManager.areButtonsEquivalent(this.button, this.defaultButton);
}
/**
* Returns the button code.
*
* @return The button code.
*/
public @NotNull
String getButtonCode()
{
return Arrays.stream(this.button)
.mapToObj(btn -> Integer.valueOf(btn).toString())
.collect(Collectors.joining("+"));
}
/**
* Sets the key binding to emulate with this button binding.
*
* @param keyBinding The optional key binding.
*/
public void setKeyBinding(@Nullable KeyBinding keyBinding)
{
this.mcKeyBinding = keyBinding;
}
/**
* Returns whether the button binding is available in the current context.
*
* @param client The client instance.
* @return True if the button binding is available, else false.
*/
public boolean isAvailable(@NotNull MinecraftClient client)
{
return this.filter.test(client, this);
}
/**
* Updates the button binding cooldown.
*/
public void update()
{
if (this.hasCooldown && this.cooldown > 0)
this.cooldown--;
}
/**
* Handles the button binding.
*
* @param client The client instance.
* @param state The state.
*/
public void handle(@NotNull MinecraftClient client, float value, @NotNull ButtonState state)
{
if (state == ButtonState.REPEAT && this.hasCooldown && this.cooldown != 0)
return;
if (this.hasCooldown && state.isPressed()) {
this.cooldown = 5;
}
for (int i = this.actions.size() - 1; i >= 0; i--) {
if (this.actions.get(i).press(client, this, value, state))
break;
}
}
@Override
public @NotNull String getName()
{
return this.key;
}
/**
* Returns the translation key of this button binding.
*
* @return The translation key.
*/
public @NotNull String getTranslationKey()
{
return "lambdacontrols.action." + this.getName();
}
/**
* Returns the key binding equivalent of this button binding.
*
* @return The key binding equivalent.
*/
public @NotNull Optional<KeyBinding> asKeyBinding()
{
return Optional.ofNullable(this.mcKeyBinding);
}
@Override
public String toString()
{
return "ButtonBinding{id=\"" + this.key + "\","
+ "hasCooldown=" + this.hasCooldown
+ "}";
}
/**
* Returns the specified axis as a button.
*
* @param axis The axis.
* @param positive True if the axis part is positive, else false.
* @return The axis as a button.
*/
public static int axisAsButton(int axis, boolean positive)
{
return positive ? 100 + axis : 200 + axis;
}
/**
* Returns whether the specified button is an axis or not.
*
* @param button The button.
* @return True if the button is an axis, else false.
*/
public static boolean isAxis(int button)
{
button %= 500;
return button >= 100;
}
/**
* Returns the second Joycon's specified button code.
*
* @param button The raw button code.
* @return The second Joycon's button code.
*/
public static int controller2Button(int button)
{
return 500 + button;
}
public static void init(@NotNull GameOptions options)
{
ATTACK.mcKeyBinding = options.keyAttack;
BACK.mcKeyBinding = options.keyBack;
CHAT.mcKeyBinding = options.keyChat;
DROP_ITEM.mcKeyBinding = options.keyDrop;
FORWARD.mcKeyBinding = options.keyForward;
INVENTORY.mcKeyBinding = options.keyInventory;
JUMP.mcKeyBinding = options.keyJump;
LEFT.mcKeyBinding = options.keyLeft;
PICK_BLOCK.mcKeyBinding = options.keyPickItem;
PLAYER_LIST.mcKeyBinding = options.keyPlayerList;
RIGHT.mcKeyBinding = options.keyRight;
SCREENSHOT.mcKeyBinding = options.keyScreenshot;
SMOOTH_CAMERA.mcKeyBinding = options.keySmoothCamera;
SNEAK.mcKeyBinding = options.keySneak;
SPRINT.mcKeyBinding = options.keySprint;
SWAP_HANDS.mcKeyBinding = options.keySwapHands;
TOGGLE_PERSPECTIVE.mcKeyBinding = options.keyTogglePerspective;
USE.mcKeyBinding = options.keyUse;
}
/**
* Returns the localized name of the specified button.
*
* @param button The button.
* @return The localized name of the button.
*/
public static @NotNull Text getLocalizedButtonName(int button)
{
switch (button % 500) {
case -1:
return new TranslatableText("key.keyboard.unknown");
case GLFW_GAMEPAD_BUTTON_A:
return new TranslatableText("lambdacontrols.button.a");
case GLFW_GAMEPAD_BUTTON_B:
return new TranslatableText("lambdacontrols.button.b");
case GLFW_GAMEPAD_BUTTON_X:
return new TranslatableText("lambdacontrols.button.x");
case GLFW_GAMEPAD_BUTTON_Y:
return new TranslatableText("lambdacontrols.button.y");
case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
return new TranslatableText("lambdacontrols.button.left_bumper");
case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
return new TranslatableText("lambdacontrols.button.right_bumper");
case GLFW_GAMEPAD_BUTTON_BACK:
return new TranslatableText("lambdacontrols.button.back");
case GLFW_GAMEPAD_BUTTON_START:
return new TranslatableText("lambdacontrols.button.start");
case GLFW_GAMEPAD_BUTTON_GUIDE:
return new TranslatableText("lambdacontrols.button.guide");
case GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
return new TranslatableText("lambdacontrols.button.left_thumb");
case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
return new TranslatableText("lambdacontrols.button.right_thumb");
case GLFW_GAMEPAD_BUTTON_DPAD_UP:
return new TranslatableText("lambdacontrols.button.dpad_up");
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT:
return new TranslatableText("lambdacontrols.button.dpad_right");
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN:
return new TranslatableText("lambdacontrols.button.dpad_down");
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT:
return new TranslatableText("lambdacontrols.button.dpad_left");
case 100:
return new TranslatableText("lambdacontrols.axis.left_x+");
case 101:
return new TranslatableText("lambdacontrols.axis.left_y+");
case 102:
return new TranslatableText("lambdacontrols.axis.right_x+");
case 103:
return new TranslatableText("lambdacontrols.axis.right_y+");
case 104:
return new TranslatableText("lambdacontrols.axis.left_trigger");
case 105:
return new TranslatableText("lambdacontrols.axis.right_trigger");
case 200:
return new TranslatableText("lambdacontrols.axis.left_x-");
case 201:
return new TranslatableText("lambdacontrols.axis.left_y-");
case 202:
return new TranslatableText("lambdacontrols.axis.right_x-");
case 203:
return new TranslatableText("lambdacontrols.axis.right_y-");
default:
return new TranslatableText("lambdacontrols.button.unknown", button);
}
}
static {
MOVEMENT_CATEGORY = registerDefaultCategory("key.categories.movement", category -> category.registerAllBindings(
ButtonBinding.FORWARD,
ButtonBinding.BACK,
ButtonBinding.LEFT,
ButtonBinding.RIGHT,
ButtonBinding.JUMP,
ButtonBinding.SNEAK,
ButtonBinding.SPRINT));
GAMEPLAY_CATEGORY = registerDefaultCategory("key.categories.gameplay", category -> category.registerAllBindings(
ButtonBinding.ATTACK,
ButtonBinding.PICK_BLOCK,
ButtonBinding.USE
));
INVENTORY_CATEGORY = registerDefaultCategory("key.categories.inventory", category -> category.registerAllBindings(
ButtonBinding.DROP_ITEM,
ButtonBinding.HOTBAR_LEFT,
ButtonBinding.HOTBAR_RIGHT,
ButtonBinding.INVENTORY,
ButtonBinding.SWAP_HANDS
));
MULTIPLAYER_CATEGORY = registerDefaultCategory("key.categories.multiplayer",
category -> category.registerAllBindings(ButtonBinding.CHAT, ButtonBinding.PLAYER_LIST));
MISC_CATEGORY = registerDefaultCategory("key.categories.misc", category -> category.registerAllBindings(
ButtonBinding.SCREENSHOT,
//SMOOTH_CAMERA,
ButtonBinding.TOGGLE_PERSPECTIVE
));
}
/**
* Returns a builder instance.
*
* @param identifier The identifier of the button binding.
* @return The builder instance
* @since 1.5.0
*/
public static Builder builder(@NotNull Identifier identifier)
{
return new Builder(identifier);
}
/**
* Returns a builder instance.
*
* @param identifier The identifier of the button binding.
* @return The builder instance.
* @since 1.5.0
*/
public static Builder builder(@NotNull net.minecraft.util.Identifier identifier)
{
return new Builder(identifier);
}
/**
* Represents a quick {@link ButtonBinding} builder.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.1.0
*/
public static class Builder
{
private final String key;
private int[] buttons = new int[0];
private List<PressAction> actions = new ArrayList<>();
private PairPredicate<MinecraftClient, ButtonBinding> filter = Predicates.pairAlwaysTrue();
private boolean cooldown = false;
private ButtonCategory category = null;
private KeyBinding mcBinding = null;
/**
* This constructor shouldn't be used for other mods.
*
* @param key The key with format {@code "<namespace>.<name>"}.
*/
public Builder(@NotNull String key)
{
this.key = key;
this.unbound();
}
public Builder(@NotNull Identifier identifier)
{
this(identifier.getNamespace() + "." + identifier.getName());
}
public Builder(@NotNull net.minecraft.util.Identifier identifier)
{
this(new Identifier(identifier.toString()));
}
/**
* Defines the default buttons of the {@link ButtonBinding}.
*
* @param buttons The default buttons.
* @return The builder instance.
*/
public Builder buttons(int... buttons)
{
this.buttons = buttons;
return this;
}
/**
* Sets the {@link ButtonBinding} to unbound.
*
* @return The builder instance.
*/
public Builder unbound()
{
return this.buttons(-1);
}
/**
* Adds the actions to the {@link ButtonBinding}.
*
* @param actions The actions to add.
* @return The builder instance.
*/
public Builder actions(@NotNull PressAction... actions)
{
this.actions.addAll(Arrays.asList(actions));
return this;
}
/**
* Adds an action to the {@link ButtonBinding}.
*
* @param action The action to add.
* @return The builder instance.
*/
public Builder action(@NotNull PressAction action)
{
this.actions.add(action);
return this;
}
/**
* Sets a filter for the {@link ButtonBinding}.
*
* @param filter The filter.
* @return The builder instance.
*/
public Builder filter(@NotNull PairPredicate<MinecraftClient, ButtonBinding> filter)
{
this.filter = filter;
return this;
}
/**
* Sets the filter of {@link ButtonBinding} to only in game.
*
* @return The builder instance.
* @see #filter(PairPredicate)
* @see InputHandlers#inGame(MinecraftClient, ButtonBinding)
*/
public Builder onlyInGame()
{
return this.filter(InputHandlers::inGame);
}
/**
* Sets the filter of {@link ButtonBinding} to only in inventory.
*
* @return The builder instance.
* @see #filter(PairPredicate)
* @see InputHandlers#inInventory(MinecraftClient, ButtonBinding)
*/
public Builder onlyInInventory()
{
return this.filter(InputHandlers::inInventory);
}
/**
* Sets whether the {@link ButtonBinding} has a cooldown or not.
*
* @param cooldown True if the {@link ButtonBinding} has a cooldown, else false.
* @return The builder instance.
*/
public Builder cooldown(boolean cooldown)
{
this.cooldown = cooldown;
return this;
}
/**
* Puts a cooldown on the {@link ButtonBinding}.
*
* @return The builder instance.
* @since 1.5.0
*/
public Builder cooldown()
{
return this.cooldown(true);
}
/**
* Sets the category of the {@link ButtonBinding}.
*
* @param category The category.
* @return The builder instance.
*/
public Builder category(@Nullable ButtonCategory category)
{
this.category = category;
return this;
}
/**
* Sets the keybinding linked to the {@link ButtonBinding}.
*
* @param binding The keybinding to link.
* @return The builder instance.
*/
public Builder linkKeybind(@Nullable KeyBinding binding)
{
this.mcBinding = binding;
return this;
}
/**
* Builds the {@link ButtonBinding}.
*
* @return The built {@link ButtonBinding}.
*/
public ButtonBinding build()
{
ButtonBinding binding = new ButtonBinding(this.key, this.buttons, this.actions, this.filter, this.cooldown);
if (this.category != null)
this.category.registerBinding(binding);
if (this.mcBinding != null)
binding.setKeyBinding(this.mcBinding);
return binding;
}
/**
* Builds and registers the {@link ButtonBinding}.
*
* @return The built {@link ButtonBinding}.
* @see #build()
*/
public ButtonBinding register()
{
return InputManager.registerBinding(this.build());
}
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.spruceui.AbstractIconButtonWidget;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull;
/**
* Represents a controller button widget.
*/
public class ControllerButtonWidget extends AbstractIconButtonWidget
{
private ButtonBinding binding;
private int iconWidth;
public ControllerButtonWidget(int x, int y, int width, @NotNull ButtonBinding binding, @NotNull PressAction action)
{
super(x, y, width, 20, ButtonBinding.getLocalizedButtonName(binding.getButton()[0]), action);
this.binding = binding;
}
public void update()
{
int length = binding.getButton().length;
this.setMessage(this.binding.isNotBound() ? LambdaControls.NOT_BOUND_TEXT :
(length > 0 ? ButtonBinding.getLocalizedButtonName(binding.getButton()[0]) : new LiteralText("<>")));
}
@Override
public Text getMessage()
{
if (this.binding.getButton().length > 1)
return LiteralText.EMPTY;
return super.getMessage();
}
@Override
protected int renderIcon(MatrixStack matrices, int mouseX, int mouseY, float delta, int x, int y)
{
if (this.binding.getButton().length > 1) {
x += (this.width / 2 - this.iconWidth / 2) - 4;
}
Pair<Integer, Integer> size = LambdaControlsRenderer.drawButton(matrices, x, y, this.binding, MinecraftClient.getInstance());
this.iconWidth = size.key;
return size.value;
}
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.spruceui.SpruceButtonWidget;
import me.lambdaurora.spruceui.SpruceTexts;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.function.Predicates;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Represents the controls screen.
*/
public class ControllerControlsScreen extends Screen
{
private final Screen parent;
final LambdaControlsClient mod;
private final boolean hideSettings;
private ControlsListWidget bindingsListWidget;
private ButtonWidget resetButton;
public ButtonBinding focusedBinding;
public boolean waiting = false;
public List<Integer> currentButtons = new ArrayList<>();
public ControllerControlsScreen(@NotNull Screen parent, boolean hideSettings)
{
super(new TranslatableText("lambdacontrols.menu.title.controller_controls"));
this.parent = parent;
this.mod = LambdaControlsClient.get();
this.hideSettings = hideSettings;
}
@Override
public void removed()
{
this.mod.config.save();
super.removed();
}
@Override
protected void init()
{
this.addButton(new SpruceButtonWidget(this.width / 2 - 155, 18, this.hideSettings ? 310 : 150, 20,
new TranslatableText("lambdacontrols.menu.keyboard_controls"),
btn -> this.client.openScreen(new ControlsOptionsScreen(this, this.client.options))));
if (!this.hideSettings)
this.addButton(new SpruceButtonWidget(this.width / 2 - 155 + 160, 18, 150, 20,
SpruceTexts.MENU_OPTIONS,
btn -> this.client.openScreen(new LambdaControlsSettingsScreen(this, true))));
this.bindingsListWidget = new ControlsListWidget(this, this.client);
this.children.add(this.bindingsListWidget);
this.resetButton = this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 150, 20,
SpruceTexts.CONTROLS_RESET_ALL,
btn -> InputManager.streamBindings().collect(Collectors.toSet()).forEach(binding -> this.mod.config.setButtonBinding(binding, binding.getDefaultButton()))));
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20,
SpruceTexts.GUI_DONE,
btn -> this.client.openScreen(this.parent)));
}
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta)
{
this.renderBackground(matrices);
this.bindingsListWidget.render(matrices, mouseX, mouseY, delta);
drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 8, 16777215);
this.resetButton.active = InputManager.streamBindings().anyMatch(Predicates.not(ButtonBinding::isDefault));
super.render(matrices, mouseX, mouseY, delta);
}
}

View File

@@ -1,214 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.ButtonCategory;
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.spruceui.SpruceTexts;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ElementListWidget;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.MutableText;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Represents a control list widget.
*/
public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Entry>
{
private static final int[] UNBOUND = new int[]{-1};
private final ControllerControlsScreen gui;
private int field_2733;
public ControlsListWidget(@NotNull ControllerControlsScreen gui, @NotNull MinecraftClient client)
{
super(client, gui.width + 45, gui.height, 43, gui.height - 32, 24);
this.gui = gui;
InputManager.streamCategories()
.sorted(Comparator.comparingInt(ButtonCategory::getPriority))
.forEach(category -> {
this.addEntry(new CategoryEntry(category));
category.getBindings().forEach(binding -> {
int i = client.textRenderer.getWidth(I18n.translate(binding.getTranslationKey()));
if (i > this.field_2733) {
this.field_2733 = i;
}
this.addEntry(new ControlsListWidget.ButtonBindingEntry(binding));
});
});
}
@Override
protected int getScrollbarPositionX()
{
return super.getScrollbarPositionX() + 15;
}
@Override
public int getRowWidth()
{
return super.getRowWidth() + 32;
}
public class ButtonBindingEntry extends Entry
{
private final ButtonBinding binding;
private final String bindingName;
private final ControllerButtonWidget editButton;
private final ButtonWidget resetButton;
private final ButtonWidget unboundButton;
ButtonBindingEntry(@NotNull ButtonBinding binding)
{
this.binding = binding;
this.bindingName = I18n.translate(this.binding.getTranslationKey());
this.editButton = new ControllerButtonWidget(0, 0, 110, this.binding, btn -> {
gui.focusedBinding = binding;
gui.currentButtons.clear();
gui.waiting = true;
})
{
protected MutableText getNarrationMessage()
{
return binding.isNotBound() ? new TranslatableText("narrator.controls.unbound", bindingName) : new TranslatableText("narrator.controls.bound", bindingName, super.getNarrationMessage());
}
};
this.resetButton = new ButtonWidget(0, 0, 50, 20, new TranslatableText("controls.reset"),
btn -> gui.mod.config.setButtonBinding(binding, binding.getDefaultButton()))
{
protected MutableText getNarrationMessage()
{
return new TranslatableText("narrator.controls.reset", bindingName);
}
};
this.unboundButton = new ButtonWidget(0, 0, 50, 20, SpruceTexts.OPTIONS_GENERIC_UNBOUND,
btn -> {
gui.mod.config.setButtonBinding(binding, UNBOUND);
gui.focusedBinding = null;
})
{
protected MutableText getNarrationMessage()
{
return new TranslatableText("lambdacontrols.narrator.unbound", bindingName);
}
};
}
@Override
public List<? extends Element> children()
{
return Collections.unmodifiableList(Arrays.asList(this.editButton, this.resetButton));
}
@Override
public void render(MatrixStack matrices, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovering, float delta)
{
boolean focused = gui.focusedBinding == this.binding;
TextRenderer textRenderer = ControlsListWidget.this.client.textRenderer;
String bindingName = this.bindingName;
float var10002 = (float) (x + 70 - ControlsListWidget.this.field_2733);
int var10003 = y + height / 2;
textRenderer.draw(matrices, bindingName, var10002, (float) (var10003 - 9 / 2), 16777215);
this.resetButton.x = this.unboundButton.x = x + 190;
this.resetButton.y = this.unboundButton.y = y;
this.resetButton.active = !this.binding.isDefault();
if (focused)
this.unboundButton.render(matrices, mouseX, mouseY, delta);
else
this.resetButton.render(matrices, mouseX, mouseY, delta);
this.editButton.x = x + 75;
this.editButton.y = y;
this.editButton.update();
if (focused) {
MutableText text = new LiteralText("> ").formatted(Formatting.WHITE);
text.append(this.editButton.getMessage().copy().formatted(Formatting.YELLOW));
this.editButton.setMessage(text.append(new LiteralText(" <").formatted(Formatting.WHITE)));
} else if (!this.binding.isNotBound() && InputManager.hasDuplicatedBindings(this.binding)) {
MutableText text = this.editButton.getMessage().copy();
this.editButton.setMessage(text.formatted(Formatting.RED));
} else if (this.binding.isNotBound()) {
MutableText text = this.editButton.getMessage().copy();
this.editButton.setMessage(text.formatted(Formatting.GOLD));
}
this.editButton.render(matrices, mouseX, mouseY, delta);
}
public boolean mouseClicked(double mouseX, double mouseY, int button)
{
boolean focused = gui.focusedBinding == this.binding;
if (this.editButton.mouseClicked(mouseX, mouseY, button))
return true;
else
return focused ? this.unboundButton.mouseClicked(mouseX, mouseY, button) : this.resetButton.mouseClicked(mouseX, mouseY, button);
}
public boolean mouseReleased(double mouseX, double mouseY, int button)
{
return this.editButton.mouseReleased(mouseX, mouseY, button) || this.resetButton.mouseReleased(mouseX, mouseY, button)
|| this.unboundButton.mouseReleased(mouseX, mouseY, button);
}
}
public class CategoryEntry extends Entry
{
private final String name;
private final int nameWidth;
public CategoryEntry(@NotNull ButtonCategory category)
{
this.name = category.getTranslatedName();
this.nameWidth = ControlsListWidget.this.client.textRenderer.getWidth(this.name);
}
@Override
public void render(MatrixStack matrices, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovering, float delta)
{
ControlsListWidget.this.client.textRenderer.draw(matrices, this.name, (float) (ControlsListWidget.this.client.currentScreen.width / 2 - this.nameWidth / 2),
(float) ((y + height) - 9 - 1), 16777215);
}
@Override
public boolean changeFocus(boolean bl)
{
return false;
}
@Override
public List<? extends Element> children()
{
return Collections.emptyList();
}
}
@Environment(EnvType.CLIENT)
public abstract static class Entry extends ElementListWidget.Entry<Entry>
{
}
}

View File

@@ -1,291 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.spruceui.SpruceButtonWidget;
import me.lambdaurora.spruceui.SpruceLabelWidget;
import me.lambdaurora.spruceui.SpruceTexts;
import me.lambdaurora.spruceui.Tooltip;
import me.lambdaurora.spruceui.option.*;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonListWidget;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.Option;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.MutableText;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import net.minecraft.util.Util;
import org.lwjgl.glfw.GLFW;
/**
* Represents the LambdaControls settings screen.
*/
public class LambdaControlsSettingsScreen extends Screen
{
public static final String GAMEPAD_TOOL_URL = "https://generalarcade.com/gamepadtool/";
final LambdaControlsClient mod;
private final Screen parent;
private final boolean hideControls;
// General options
private final Option autoSwitchModeOption;
private final Option rotationSpeedOption;
private final Option mouseSpeedOption;
private final Option resetOption;
// Gameplay options
private final Option autoJumpOption;
private final Option fastBlockPlacingOption;
private final Option frontBlockPlacingOption;
private final Option verticalReacharoundOption;
private final Option flyDriftingOption;
private final Option flyVerticalDriftingOption;
// Controller options
private final Option controllerOption;
private final Option secondControllerOption;
private final Option controllerTypeOption;
private final Option deadZoneOption;
private final Option invertsRightXAxis;
private final Option invertsRightYAxis;
private final Option unfocusedInputOption;
private final Option virtualMouseOption;
private final Option virtualMouseSkinOption;
// Hud options
private final Option hudEnableOption;
private final Option hudSideOption;
private final MutableText controllerMappingsUrlText = new LiteralText("(")
.append(new LiteralText(GAMEPAD_TOOL_URL).formatted(Formatting.GOLD))
.append("),");
private ButtonListWidget list;
private SpruceLabelWidget gamepadToolUrlLabel;
public LambdaControlsSettingsScreen(Screen parent, boolean hideControls)
{
super(new TranslatableText("lambdacontrols.title.settings"));
this.mod = LambdaControlsClient.get();
this.parent = parent;
this.hideControls = hideControls;
// General options
this.autoSwitchModeOption = new SpruceBooleanOption("lambdacontrols.menu.auto_switch_mode", this.mod.config::hasAutoSwitchMode,
this.mod.config::setAutoSwitchMode, new TranslatableText("lambdacontrols.tooltip.auto_switch_mode"), true);
this.rotationSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.rotation_speed", 0.0, 100.0, 0.5F, this.mod.config::getRotationSpeed,
newValue -> {
synchronized (this.mod.config) {
this.mod.config.setRotationSpeed(newValue);
}
}, option -> option.getDisplayText(new LiteralText(String.valueOf(option.get()))),
new TranslatableText("lambdacontrols.tooltip.rotation_speed"));
this.mouseSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.mouse_speed", 0.0, 150.0, 0.5F, this.mod.config::getMouseSpeed,
newValue -> {
synchronized (this.mod.config) {
this.mod.config.setMouseSpeed(newValue);
}
}, option -> option.getDisplayText(new LiteralText(String.valueOf(option.get()))),
new TranslatableText("lambdacontrols.tooltip.mouse_speed"));
this.resetOption = new SpruceResetOption(btn -> {
this.mod.config.reset();
MinecraftClient client = MinecraftClient.getInstance();
this.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
});
// Gameplay options
this.autoJumpOption = SpruceBooleanOption.fromVanilla("options.autoJump", Option.AUTO_JUMP, null, true);
this.fastBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.fast_block_placing", this.mod.config::hasFastBlockPlacing,
this.mod.config::setFastBlockPlacing, new TranslatableText("lambdacontrols.tooltip.fast_block_placing"), true);
this.frontBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.reacharound.horizontal", this.mod.config::hasFrontBlockPlacing,
this.mod.config::setFrontBlockPlacing, new TranslatableText("lambdacontrols.tooltip.reacharound.horizontal"), true);
this.verticalReacharoundOption = new SpruceBooleanOption("lambdacontrols.menu.reacharound.vertical", this.mod.config::hasVerticalReacharound,
this.mod.config::setVerticalReacharound, new TranslatableText("lambdacontrols.tooltip.reacharound.vertical"), true);
this.flyDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting", this.mod.config::hasFlyDrifting,
this.mod.config::setFlyDrifting, new TranslatableText("lambdacontrols.tooltip.fly_drifting"), true);
this.flyVerticalDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting_vertical", this.mod.config::hasFlyVerticalDrifting,
this.mod.config::setFlyVerticalDrifting, new TranslatableText("lambdacontrols.tooltip.fly_drifting_vertical"), true);
// Controller options
this.controllerOption = new SpruceCyclingOption("lambdacontrols.menu.controller", amount -> {
int id = this.mod.config.getController().getId();
id += amount;
if (id > GLFW.GLFW_JOYSTICK_LAST)
id = GLFW.GLFW_JOYSTICK_1;
this.mod.config.setController(Controller.byId(id));
}, option -> {
String controllerName = this.mod.config.getController().getName();
if (!this.mod.config.getController().isConnected())
return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.RED));
else if (!this.mod.config.getController().isGamepad())
return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.GOLD));
else
return option.getDisplayText(new LiteralText(controllerName));
}, null);
this.secondControllerOption = new SpruceCyclingOption("lambdacontrols.menu.controller2",
amount -> {
int id = this.mod.config.getSecondController().map(Controller::getId).orElse(-1);
id += amount;
if (id > GLFW.GLFW_JOYSTICK_LAST)
id = -1;
this.mod.config.setSecondController(id == -1 ? null : Controller.byId(id));
}, option -> this.mod.config.getSecondController().map(controller -> {
String controllerName = controller.getName();
if (!controller.isConnected())
return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.RED));
else if (!controller.isGamepad())
return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.GOLD));
else
return option.getDisplayText(new LiteralText(controllerName));
}).orElse(option.getDisplayText(SpruceTexts.OPTIONS_OFF.shallowCopy().formatted(Formatting.RED))),
new TranslatableText("lambdacontrols.tooltip.controller2"));
this.controllerTypeOption = new SpruceCyclingOption("lambdacontrols.menu.controller_type",
amount -> this.mod.config.setControllerType(this.mod.config.getControllerType().next()),
option -> option.getDisplayText(this.mod.config.getControllerType().getTranslatedText()),
new TranslatableText("lambdacontrols.tooltip.controller_type"));
this.deadZoneOption = new SpruceDoubleOption("lambdacontrols.menu.dead_zone", 0.05, 1.0, 0.05F, this.mod.config::getDeadZone,
newValue -> {
synchronized (this.mod.config) {
this.mod.config.setDeadZone(newValue);
}
}, option -> {
String value = String.valueOf(option.get());
return option.getDisplayText(new LiteralText(value.substring(0, Math.min(value.length(), 5))));
}, new TranslatableText("lambdacontrols.tooltip.dead_zone"));
this.invertsRightXAxis = new SpruceBooleanOption("lambdacontrols.menu.invert_right_x_axis", this.mod.config::doesInvertRightXAxis,
newValue -> {
synchronized (this.mod.config) {
this.mod.config.setInvertRightXAxis(newValue);
}
}, null, true);
this.invertsRightYAxis = new SpruceBooleanOption("lambdacontrols.menu.invert_right_y_axis", this.mod.config::doesInvertRightYAxis,
newValue -> {
synchronized (this.mod.config) {
this.mod.config.setInvertRightYAxis(newValue);
}
}, null, true);
this.unfocusedInputOption = new SpruceBooleanOption("lambdacontrols.menu.unfocused_input", this.mod.config::hasUnfocusedInput,
this.mod.config::setUnfocusedInput, new TranslatableText("lambdacontrols.tooltip.unfocused_input"), true);
this.virtualMouseOption = new SpruceBooleanOption("lambdacontrols.menu.virtual_mouse", this.mod.config::hasVirtualMouse,
this.mod.config::setVirtualMouse, new TranslatableText("lambdacontrols.tooltip.virtual_mouse"), true);
this.virtualMouseSkinOption = new SpruceCyclingOption("lambdacontrols.menu.virtual_mouse.skin",
amount -> this.mod.config.setVirtualMouseSkin(this.mod.config.getVirtualMouseSkin().next()),
option -> option.getDisplayText(this.mod.config.getVirtualMouseSkin().getTranslatedText()),
null);
// HUD options
this.hudEnableOption = new SpruceBooleanOption("lambdacontrols.menu.hud_enable", this.mod.config::isHudEnabled,
this.mod::setHudEnabled, new TranslatableText("lambdacontrols.tooltip.hud_enable"), true);
this.hudSideOption = new SpruceCyclingOption("lambdacontrols.menu.hud_side",
amount -> this.mod.config.setHudSide(this.mod.config.getHudSide().next()),
option -> option.getDisplayText(this.mod.config.getHudSide().getTranslatedText()),
new TranslatableText("lambdacontrols.tooltip.hud_side"));
}
@Override
public void removed()
{
this.mod.config.save();
super.removed();
}
@Override
public void onClose()
{
this.mod.config.save();
super.onClose();
}
private int getTextHeight()
{
return (5 + this.textRenderer.fontHeight) * 3 + 5;
}
@Override
protected void init()
{
super.init();
int buttonHeight = 20;
SpruceButtonWidget controlsModeBtn = new SpruceButtonWidget(this.width / 2 - 155, 18, this.hideControls ? 310 : 150, buttonHeight,
new TranslatableText("lambdacontrols.menu.controls_mode").append(": ").append(new TranslatableText(this.mod.config.getControlsMode().getTranslationKey())),
btn -> {
ControlsMode next = this.mod.config.getControlsMode().next();
btn.setMessage(new TranslatableText("lambdacontrols.menu.controls_mode").append(": ").append(new TranslatableText(next.getTranslationKey())));
this.mod.config.setControlsMode(next);
this.mod.config.save();
if (this.client.player != null) {
ClientSidePacketRegistry.INSTANCE.sendToServer(LambdaControls.CONTROLS_MODE_CHANNEL, this.mod.makeControlsModeBuffer(next));
}
});
controlsModeBtn.setTooltip(new TranslatableText("lambdacontrols.tooltip.controls_mode"));
this.addButton(controlsModeBtn);
if (!this.hideControls)
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, 18, 150, buttonHeight, new TranslatableText("options.controls"),
btn -> {
if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER)
this.client.openScreen(new ControllerControlsScreen(this, true));
else
this.client.openScreen(new ControlsOptionsScreen(this, this.client.options));
}));
this.list = new ButtonListWidget(this.client, this.width, this.height, 43, this.height - 29 - this.getTextHeight(), 25);
// General options
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.general", true, null));
this.list.addOptionEntry(this.rotationSpeedOption, this.mouseSpeedOption);
this.list.addSingleOptionEntry(this.autoSwitchModeOption);
// Gameplay options
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.gameplay", true, null));
this.list.addOptionEntry(this.autoJumpOption, this.fastBlockPlacingOption);
this.list.addOptionEntry(this.frontBlockPlacingOption, this.verticalReacharoundOption);
this.list.addSingleOptionEntry(this.flyDriftingOption);
this.list.addSingleOptionEntry(this.flyVerticalDriftingOption);
this.list.addOptionEntry(Option.SNEAK_TOGGLED, Option.SPRINT_TOGGLED);
// Controller options
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.controller", true, null));
this.list.addSingleOptionEntry(this.controllerOption);
this.list.addSingleOptionEntry(this.secondControllerOption);
this.list.addOptionEntry(this.controllerTypeOption, this.deadZoneOption);
this.list.addOptionEntry(this.invertsRightXAxis, this.invertsRightYAxis);
this.list.addOptionEntry(this.unfocusedInputOption, this.virtualMouseOption);
this.list.addSingleOptionEntry(this.virtualMouseSkinOption);
this.list.addSingleOptionEntry(new ReloadControllerMappingsOption());
this.list.addSingleOptionEntry(new SpruceSimpleActionOption("lambdacontrols.menu.mappings.open_input_str",
btn -> this.client.openScreen(new MappingsStringInputScreen(this))));
// HUD options
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.hud", true, null));
this.list.addOptionEntry(this.hudEnableOption, this.hudSideOption);
this.children.add(this.list);
this.gamepadToolUrlLabel = new SpruceLabelWidget(this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight) * 2, this.controllerMappingsUrlText, this.width,
label -> Util.getOperatingSystem().open(GAMEPAD_TOOL_URL), true);
this.gamepadToolUrlLabel.setTooltip(new TranslatableText("chat.link.open"));
this.children.add(this.gamepadToolUrlLabel);
this.addButton(this.resetOption.createButton(this.client.options, this.width / 2 - 155, this.height - 29, 150));
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, buttonHeight, SpruceTexts.GUI_DONE,
btn -> this.client.openScreen(this.parent)));
}
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta)
{
this.renderBackground(matrices);
this.list.render(matrices, mouseX, mouseY, delta);
super.render(matrices, mouseX, mouseY, delta);
drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.menu.title"), this.width / 2, 8, 16777215);
drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.controller.mappings.1", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight) * 3, 10526880);
this.gamepadToolUrlLabel.render(matrices, mouseX, mouseY, delta);
drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.controller.mappings.3", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight), 10526880);
Tooltip.renderAll(matrices);
}
}

View File

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

View File

@@ -1,32 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.mixin;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPlayNetworkHandler.class)
public class ClientPlayNetworkHandlerMixin
{
@Inject(method = "onGameJoin", at = @At(value = "TAIL"))
private void onGameJoin(GameJoinS2CPacket packet, CallbackInfo ci)
{
ClientSidePacketRegistry.INSTANCE.sendToServer(LambdaControls.HELLO_CHANNEL, LambdaControls.get().makeHello(LambdaControlsClient.get().config.getControlsMode()));
ClientSidePacketRegistry.INSTANCE.sendToServer(LambdaControls.CONTROLS_MODE_CHANNEL,
LambdaControls.get().makeControlsModeBuffer(LambdaControlsClient.get().config.getControlsMode()));
}
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.mixin;
import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.screen.options.GameOptionsScreen;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.GameOptions;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* Injects the new controls settings button.
*/
@Mixin(ControlsOptionsScreen.class)
public class ControlsOptionsScreenMixin extends GameOptionsScreen
{
public ControlsOptionsScreenMixin(Screen parent, GameOptions gameOptions, Text text)
{
super(parent, gameOptions, text);
}
@Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/options/ControlsOptionsScreen;addButton(Lnet/minecraft/client/gui/widget/AbstractButtonWidget;)Lnet/minecraft/client/gui/widget/AbstractButtonWidget;", ordinal = 1))
private AbstractButtonWidget onInit(ControlsOptionsScreen screen, AbstractButtonWidget btn)
{
if (this.parent instanceof ControllerControlsScreen)
return this.addButton(btn);
else
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).getHeight(), new TranslatableText("menu.options"),
b -> this.client.openScreen(new LambdaControlsSettingsScreen(this, true))));
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.mixin;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.OptionsScreen;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* Injects the new controls settings button.
*/
@Mixin(OptionsScreen.class)
public class OptionsScreenMixin extends Screen
{
protected OptionsScreenMixin(Text title)
{
super(title);
}
@Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/options/OptionsScreen;addButton(Lnet/minecraft/client/gui/widget/AbstractButtonWidget;)Lnet/minecraft/client/gui/widget/AbstractButtonWidget;", ordinal = 7))
private AbstractButtonWidget lambdacontrols_onInit(OptionsScreen screen, AbstractButtonWidget btn)
{
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).getHeight(), btn.getMessage(),
b -> this.client.openScreen(new ControllerControlsScreen(this, false))));
} else {
return this.addButton(btn);
}
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.ring;
import com.electronwill.nightconfig.core.Config;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.util.math.MatrixStack;
import org.jetbrains.annotations.NotNull;
public class DummyRingAction extends RingAction
{
public DummyRingAction(@NotNull Config config)
{
super(config);
}
@Override
public @NotNull String getName()
{
return "dummy";
}
@Override
public void onAction(@NotNull RingButtonMode mode)
{
}
@Override
public void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered)
{
drawCenteredString(matrices, textRenderer, this.getName(), x + 25, y + 25 - textRenderer.fontHeight / 2, 0xffffff);
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.util;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import org.jetbrains.annotations.Nullable;
/**
* Represents an accessor to AbstractContainerScreen.
*/
public interface HandledScreenAccessor
{
/**
* Gets the left coordinate of the GUI.
*
* @return The left coordinate of the GUI.
*/
int getX();
/**
* Gets the top coordinate of the GUI.
*
* @return The top coordinate of the GUI.
*/
int getY();
/**
* Gets the slot at position.
*
* @param pos_x The X position to check.
* @param pos_y The Y position to check.
* @return The slot at the specified position.
*/
Slot lambdacontrols_getSlotAt(double pos_x, double pos_y);
boolean lambdacontrols_isClickOutsideBounds(double mouseX, double mouseY, int x, int y, int button);
/**
* Handles a mouse click on the specified slot.
*
* @param slot The slot instance.
* @param slotId The slot id.
* @param clickData The click data.
* @param actionType The action type.
*/
void lambdacontrols_onMouseClick(@Nullable Slot slot, int slotId, int clickData, SlotActionType actionType);
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.util;
/**
* Represents a Minecraft keybinding with extra access.
*/
public interface KeyBindingAccessor
{
boolean lambdacontrols_press();
boolean lambdacontrols_unpress();
default boolean lambdacontrols_handlePressState(boolean pressed)
{
if (pressed)
return this.lambdacontrols_press();
else
return this.lambdacontrols_unpress();
}
}

View File

@@ -1,18 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.client.util;
/**
* Represents mouse's extra access.
*/
public interface MouseAccessor
{
void lambdacontrols_onCursorPos(long window, double x, double y);
}

View File

@@ -1,15 +0,0 @@
{
"required": true,
"package": "me.lambdaurora.lambdacontrols.client.compat.mixin",
"plugin": "me.lambdaurora.lambdacontrols.client.compat.LambdaControlsMixinPlugin",
"compatibilityLevel": "JAVA_8",
"client": [
"EntryListWidgetAccessor",
"EntryWidgetAccessor",
"RecipeViewingScreenAccessor",
"VillagerRecipeViewingScreenAccessor"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -3,17 +3,18 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/use # check these on https://fabricmc.net/use
minecraft_version=1.16.2 minecraft_version=1.17
yarn_mappings=1.16.2+build.25 yarn_mappings=1.17+build.13
loader_version=0.9.1+build.205 loader_version=0.11.6
# Mod Properties # Mod Properties
mod_version = 1.5.0 mod_version = 1.7.1
maven_group = me.lambdaurora.lambdacontrols maven_group = dev.lambdaurora
archives_base_name = lambdacontrols archives_base_name = lambdacontrols
modrinth_id=W1D3UXEc
# Dependencies # Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.17.2+build.396-1.16 fabric_version=0.36.0+1.17
spruceui_version=1.6.4 spruceui_version=3.2.0+1.17
modmenu_version=1.14.6+build.31 modmenu_version=2.0.2

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

2
gradlew vendored Normal file → Executable file
View File

@@ -130,7 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath

21
gradlew.bat vendored
View File

@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,21 +64,6 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
@@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@@ -1,13 +1,11 @@
pluginManagement { pluginManagement {
repositories { repositories {
jcenter()
maven { maven {
name = 'Fabric' name 'Fabric'
url = 'https://maven.fabricmc.net/' url 'https://maven.fabricmc.net/'
} }
gradlePluginPortal() gradlePluginPortal()
} }
} }
rootProject.name = 'lambdacontrols' rootProject.name = 'lambdacontrols'
include 'core', 'fabric', 'spigot'

View File

@@ -1,52 +0,0 @@
plugins {
id 'java-library'
}
archivesBaseName = project.archives_base_name + "-spigot"
repositories {
maven { url = 'https://hub.spigotmc.org/nexus/content/groups/public/' }
maven { url = 'https://libraries.minecraft.net/' }
}
configurations {
include
}
dependencies {
api project(":core")
include(project(":core")) {
exclude group: 'com.google.code.gson'
exclude group: 'com.google.guava'
}
api 'org.spigotmc:spigot-api:1.15.1-R0.1-SNAPSHOT'
api 'io.netty:netty-all:4.1.28.Final'
implementation "com.electronwill.night-config:core:3.5.3"
implementation "com.electronwill.night-config:toml:3.5.3"
}
processResources {
inputs.property "version", project.version
from(sourceSets.main.resources.srcDirs) {
include "plugin.yml"
expand 'version': project.version.toString().replace("#", "")
}
}
jar {
from '../LICENSE'
dependsOn configurations.include
from {
(configurations.include).collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols;
import com.electronwill.nightconfig.core.file.FileConfig;
import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
* Represents the LambdaControls Spigot configuration.
*/
public class LambdaControlsConfig
{
private static final boolean DEFAULT_FRONT_BLOCK_PLACING = true;
protected final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/server_config.toml").build();
private final LambdaControlsSpigot plugin;
public LambdaControlsConfig(@NotNull LambdaControlsSpigot plugin)
{
this.plugin = plugin;
}
public void load()
{
File configDir = new File("config/");
if (!configDir.exists())
configDir.mkdirs();
this.config.load();
this.plugin.log("Configuration loaded.");
LambdaControlsFeature.HORIZONTAL_REACHAROUND.setAllowed(this.config.getOrElse("gameplay.front_block_placing", DEFAULT_FRONT_BLOCK_PLACING));
}
}

View File

@@ -1,148 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols;
import io.netty.buffer.Unpooled;
import me.lambdaurora.lambdacontrols.event.PlayerChangeControlsModeEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static me.lambdaurora.lambdacontrols.LambdaControlsConstants.*;
/**
* Represents the LambdaControls spigot plugin which provides extra features for servers.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class LambdaControlsSpigot extends JavaPlugin implements PluginMessageListener, Listener
{
private static final Map<Player, ControlsMode> PLAYERS_CONTROLS_MODE = new HashMap<>();
public final LambdaControlsConfig config = new LambdaControlsConfig(this);
@Override
public void onEnable()
{
super.onEnable();
this.config.load();
// Note that Spigot has a bullshit channel size restriction as Minecraft SUPPORTS UP TO 32767 AS CHANNEL SIZE.
// Please stop using that bad server software, move over Sponge or idk other things. REALLY.
this.getServer().getMessenger().registerIncomingPluginChannel(this, CONTROLS_MODE_CHANNEL.toString(), this);
this.getServer().getMessenger().registerOutgoingPluginChannel(this, CONTROLS_MODE_CHANNEL.toString());
this.getServer().getMessenger().registerOutgoingPluginChannel(this, FEATURE_CHANNEL.toString());
this.getServer().getMessenger().registerIncomingPluginChannel(this, HELLO_CHANNEL.toString(), this);
this.getServer().getPluginManager().registerEvents(this, this);
this.getServer().getOnlinePlayers().forEach(player -> {
PLAYERS_CONTROLS_MODE.put(player, ControlsMode.DEFAULT);
this.requestPlayerControlsMode(player);
this.updatePlayerFeature(player, LambdaControlsFeature.HORIZONTAL_REACHAROUND);
});
}
@Override
public void onDisable()
{
super.onDisable();
this.getServer().getMessenger().unregisterIncomingPluginChannel(this, CONTROLS_MODE_CHANNEL.toString());
this.getServer().getMessenger().unregisterOutgoingPluginChannel(this, CONTROLS_MODE_CHANNEL.toString());
this.getServer().getMessenger().unregisterOutgoingPluginChannel(this, FEATURE_CHANNEL.toString());
this.getServer().getMessenger().unregisterIncomingPluginChannel(this, HELLO_CHANNEL.toString());
PLAYERS_CONTROLS_MODE.clear();
}
public void requestPlayerControlsMode(@NotNull Player player)
{
player.sendPluginMessage(this, CONTROLS_MODE_CHANNEL.toString(), new byte[0]);
}
public void updatePlayerFeature(@NotNull Player player, @NotNull LambdaControlsFeature feature)
{
Objects.requireNonNull(player);
Objects.requireNonNull(feature);
player.sendPluginMessage(this, FEATURE_CHANNEL.toString(), this.makeFeatureMessage(feature));
}
/**
* Prints a message to the terminal.
*
* @param info The message to print.
*/
public void log(String info)
{
this.getLogger().info(info);
}
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message)
{
if (channel.equals(HELLO_CHANNEL.toString())) {
NettyPacketBuffer buffer = new NettyPacketBuffer(Unpooled.copiedBuffer(message));
String version = buffer.readString(16);
ControlsMode.byId(buffer.readString(32)).ifPresent(controlsMode -> {
PLAYERS_CONTROLS_MODE.put(player, controlsMode);
PlayerChangeControlsModeEvent event = new PlayerChangeControlsModeEvent(player, controlsMode);
this.getServer().getPluginManager().callEvent(event);
});
this.updatePlayerFeature(player, LambdaControlsFeature.HORIZONTAL_REACHAROUND);
} else if (channel.equals(CONTROLS_MODE_CHANNEL.toString())) {
NettyPacketBuffer buffer = new NettyPacketBuffer(Unpooled.copiedBuffer(message));
ControlsMode.byId(buffer.readString(32)).ifPresent(controlsMode -> {
PLAYERS_CONTROLS_MODE.put(player, controlsMode);
PlayerChangeControlsModeEvent event = new PlayerChangeControlsModeEvent(player, controlsMode);
this.getServer().getPluginManager().callEvent(event);
});
}
}
/**
* Returns a packet byte buffer made for the lambdacontrols:feature plugin message.
*
* @param feature The feature data to send.
* @return The packet byte buffer.
*/
public byte[] makeFeatureMessage(@NotNull LambdaControlsFeature feature)
{
Objects.requireNonNull(feature, "Feature cannot be null.");
NettyPacketBuffer buffer = new NettyPacketBuffer(Unpooled.buffer());
buffer.writeString(feature.getName());
buffer.writeBoolean(feature.isAllowed());
return buffer.array();
}
@EventHandler
public void onPlayerJoin(@NotNull PlayerJoinEvent event)
{
PLAYERS_CONTROLS_MODE.put(event.getPlayer(), ControlsMode.DEFAULT);
}
@EventHandler
public void onPlayerLeave(@NotNull PlayerQuitEvent event)
{
PLAYERS_CONTROLS_MODE.remove(event.getPlayer());
}
}

View File

@@ -1,102 +0,0 @@
package me.lambdaurora.lambdacontrols;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.EncoderException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class NettyPacketBuffer extends PacketBuffer
{
public NettyPacketBuffer(ByteBuf byteBuf)
{
super(byteBuf);
}
@Override
public int readVarint()
{
int var1 = 0;
int var2 = 0;
byte var3;
do {
var3 = this.readByte();
var1 |= (var3 & 127) << var2++ * 7;
if (var2 > 5)
throw new RuntimeException("VarInt too big");
} while ((var3 & 128) == 128);
return var1;
}
@Override
public void writeVarint(int input)
{
while ((input & -128) != 0) {
this.writeByte(input & 127 | 128);
input >>>= 7;
}
this.writeByte(input);
}
@Override
public String readString(int maxLength)
{
int var2 = this.readVarint();
if (var2 > maxLength * 4)
throw new DecoderException("The received encoded string buffer length is longer than maximum allowed (" + var2 + " > " + maxLength * 4 + ")");
else if (var2 < 0)
throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!");
else {
String var3 = this.readCharSequence(var2, StandardCharsets.UTF_8).toString();
if (var3.length() > maxLength)
throw new DecoderException("The received string length is longer than maximum allowed (" + var2 + " > " + maxLength + ")");
else
return var3;
}
}
@Override
public void writeString(String string)
{
byte[] var2 = string.getBytes(Charset.forName("UTF-8"));
if (var2.length > 32767) {
throw new EncoderException("String too big (was " + string.length() + " data encoded, max " + 32767 + ")");
} else {
this.writeVarint(var2.length);
this.writeCharSequence(string, StandardCharsets.UTF_8);
}
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
NettyPacketBuffer buffer = (NettyPacketBuffer) o;
return byteBuf.equals(buffer.byteBuf);
}
@Override
public int compareTo(ByteBuf buffer)
{
return this.byteBuf.compareTo(buffer);
}
@Override
public String toString()
{
return this.byteBuf.toString();
}
}

View File

@@ -1,65 +0,0 @@
/*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.event;
import me.lambdaurora.lambdacontrols.ControlsMode;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Represents an event which is fired when a player change their controls mode.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class PlayerChangeControlsModeEvent extends PlayerEvent
{
private static final HandlerList HANDLERS = new HandlerList();
private final ControlsMode controlsMode;
public PlayerChangeControlsModeEvent(@NotNull Player who, @NotNull ControlsMode controlsMode)
{
super(who);
this.controlsMode = controlsMode;
}
/**
* Returns the controls mode of the player.
*
* @return The player's controls mode.
*/
public ControlsMode getControlsMode()
{
return this.controlsMode;
}
@Override
public String toString()
{
return "PlayerChangeControlsModeEvent{" +
"player=" + this.player +
", controls_mode=" + this.controlsMode +
'}';
}
@Override
public @NotNull HandlerList getHandlers()
{
return HANDLERS;
}
public static @NotNull HandlerList getHandlerList()
{
return HANDLERS;
}
}

View File

@@ -1,6 +0,0 @@
name: LambdaControls
version: ${version}
description: A quick Spigot plugin for LambdaControls which allow server admins to disable some features.
main: me.lambdaurora.lambdacontrols.LambdaControlsSpigot
api-version: 1.13

View File

@@ -1,6 +0,0 @@
# LambdaControls server configuration.
# Gameplay settings
[gameplay]
# Allows front block placing like in Bedrock Edition.
front_block_placing = true

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols; package dev.lambdaurora.lambdacontrols;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -19,23 +19,20 @@ import java.util.Optional;
* Represents the controls mode. * Represents the controls mode.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.1.0 * @version 1.7.0
* @since 1.0.0 * @since 1.0.0
*/ */
public enum ControlsMode implements Nameable public enum ControlsMode implements Nameable {
{
DEFAULT, DEFAULT,
CONTROLLER, CONTROLLER;
TOUCHSCREEN;
/** /**
* Returns the next controls mode available. * Returns the next controls mode available.
* *
* @return The next available controls mode. * @return the next available controls mode
*/ */
public ControlsMode next() public ControlsMode next() {
{ var v = values();
ControlsMode[] v = values();
if (v.length == this.ordinal() + 1) if (v.length == this.ordinal() + 1)
return v[0]; return v[0];
return v[this.ordinal() + 1]; return v[this.ordinal() + 1];
@@ -44,28 +41,25 @@ public enum ControlsMode implements Nameable
/** /**
* Gets the translation key of this controls mode. * Gets the translation key of this controls mode.
* *
* @return The translated key of this controls mode. * @return the translated key of this controls mode
* @since 1.1.0 * @since 1.1.0
*/ */
public String getTranslationKey() public String getTranslationKey() {
{
return "lambdacontrols.controls_mode." + this.getName(); return "lambdacontrols.controls_mode." + this.getName();
} }
@Override @Override
public @NotNull String getName() public @NotNull String getName() {
{
return this.name().toLowerCase(); return this.name().toLowerCase();
} }
/** /**
* Gets the controls mode from its identifier. * Gets the controls mode from its identifier.
* *
* @param id The identifier of the controls mode. * @param id the identifier of the controls mode
* @return The controls mode if found, else empty. * @return the controls mode if found, else empty
*/ */
public static Optional<ControlsMode> byId(@NotNull String id) public static Optional<ControlsMode> byId(@NotNull String id) {
{
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
} }
} }

View File

@@ -0,0 +1,129 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols;
import dev.lambdaurora.lambdacontrols.event.PlayerChangeControlsModeCallback;
import io.netty.buffer.Unpooled;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.Optional;
/**
* Represents the LambdaControls mod.
*
* @author LambdAurora
* @version 1.7.0
* @since 1.0.0
*/
public class LambdaControls implements ModInitializer {
private static LambdaControls INSTANCE;
public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(LambdaControlsConstants.CONTROLS_MODE_CHANNEL.toString());
public static final Identifier FEATURE_CHANNEL = new Identifier(LambdaControlsConstants.FEATURE_CHANNEL.toString());
public static final Identifier HELLO_CHANNEL = new Identifier(LambdaControlsConstants.HELLO_CHANNEL.toString());
public static final TranslatableText NOT_BOUND_TEXT = new TranslatableText("lambdacontrols.not_bound");
public final Logger logger = LogManager.getLogger("LambdaControls");
@Override
public void onInitialize() {
INSTANCE = this;
this.log("Initializing LambdaControls...");
ServerPlayNetworking.registerGlobalReceiver(HELLO_CHANNEL, (server, player, handler, buf, responseSender) -> {
String version = buf.readString(32);
ControlsMode.byId(buf.readString(32))
.ifPresent(controlsMode -> server
.execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(player, controlsMode)));
server.execute(() -> {
ServerPlayNetworking.send(player, FEATURE_CHANNEL, this.makeFeatureBuffer(LambdaControlsFeature.HORIZONTAL_REACHAROUND));
});
});
ServerPlayNetworking.registerGlobalReceiver(CONTROLS_MODE_CHANNEL,
(server, player, handler, buf, responseSender) -> ControlsMode.byId(buf.readString(32))
.ifPresent(controlsMode -> server
.execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(player, controlsMode))));
}
/**
* Prints a message to the terminal.
*
* @param info the message to print
*/
public void log(String info) {
this.logger.info("[LambdaControls] " + info);
}
/**
* Prints a warning to the terminal.
*
* @param warning the warning to print
*/
public void warn(String warning) {
this.logger.info("[LambdaControls] " + warning);
}
/**
* Returns a packet byte buffer made for the lambdacontrols:controls_mode plugin message.
*
* @param controlsMode the controls mode to send
* @return the packet byte buffer
*/
public PacketByteBuf makeControlsModeBuffer(@NotNull ControlsMode controlsMode) {
Objects.requireNonNull(controlsMode, "Controls mode cannot be null.");
return new PacketByteBuf(Unpooled.buffer()).writeString(controlsMode.getName(), 32);
}
/**
* Returns a packet byte buffer made for the lambdacontrols:feature plugin message.
*
* @param features the features data to send
* @return the packet byte buffer
*/
public PacketByteBuf makeFeatureBuffer(LambdaControlsFeature... features) {
if (features.length == 0)
throw new IllegalArgumentException("At least one feature must be provided.");
var buffer = new PacketByteBuf(Unpooled.buffer());
buffer.writeVarInt(features.length);
for (var feature : features) {
buffer.writeString(feature.getName(), 64);
buffer.writeBoolean(feature.isAllowed());
}
return buffer;
}
public PacketByteBuf makeHello(@NotNull ControlsMode controlsMode) {
var version = "";
Optional<ModContainer> container;
if ((container = FabricLoader.getInstance().getModContainer(LambdaControlsConstants.NAMESPACE)).isPresent()) {
version = container.get().getMetadata().getVersion().getFriendlyString();
}
return new PacketByteBuf(Unpooled.buffer()).writeString(version, 32).writeString(controlsMode.getName(), 32);
}
/**
* Gets the LambdaControls instance.
*
* @return the LambdaControls instance
*/
public static LambdaControls get() {
return INSTANCE;
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols; package dev.lambdaurora.lambdacontrols;
import org.aperlambda.lambdacommon.Identifier; import org.aperlambda.lambdacommon.Identifier;
@@ -18,10 +18,9 @@ import org.aperlambda.lambdacommon.Identifier;
* @version 1.1.0 * @version 1.1.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsConstants public class LambdaControlsConstants {
{ public static final String NAMESPACE = "lambdacontrols";
public static final String NAMESPACE = "lambdacontrols";
public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(NAMESPACE, "controls_mode"); public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(NAMESPACE, "controls_mode");
public static final Identifier FEATURE_CHANNEL = new Identifier(NAMESPACE, "feature"); public static final Identifier FEATURE_CHANNEL = new Identifier(NAMESPACE, "feature");
public static final Identifier HELLO_CHANNEL = new Identifier(NAMESPACE, "hello"); public static final Identifier HELLO_CHANNEL = new Identifier(NAMESPACE, "hello");
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols; package dev.lambdaurora.lambdacontrols;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -24,117 +24,104 @@ import java.util.Optional;
* @version 1.5.0 * @version 1.5.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsFeature implements Nameable public class LambdaControlsFeature implements Nameable {
{ private static final List<LambdaControlsFeature> FEATURES = new ArrayList<>();
private static final List<LambdaControlsFeature> FEATURES = new ArrayList<>(); public static final LambdaControlsFeature FAST_BLOCK_PLACING = new LambdaControlsFeature("fast_block_placing", true, true);
public static final LambdaControlsFeature FAST_BLOCK_PLACING = new LambdaControlsFeature("fast_block_placing", true, true); public static final LambdaControlsFeature HORIZONTAL_REACHAROUND = new LambdaControlsFeature("horizontal_reacharound", true, false);
public static final LambdaControlsFeature HORIZONTAL_REACHAROUND = new LambdaControlsFeature("horizontal_reacharound", true, false); public static final LambdaControlsFeature VERTICAL_REACHAROUND = new LambdaControlsFeature("vertical_reacharound", true, false);
public static final LambdaControlsFeature VERTICAL_REACHAROUND = new LambdaControlsFeature("vertical_reacharound", true, false);
private final String key; private final String key;
private final boolean defaultAllowed; private final boolean defaultAllowed;
private boolean allowed; private boolean allowed;
private final boolean defaultEnabled; private final boolean defaultEnabled;
private boolean enabled; private boolean enabled;
public LambdaControlsFeature(@NotNull String key, boolean allowed, boolean enabled) public LambdaControlsFeature(@NotNull String key, boolean allowed, boolean enabled) {
{
Objects.requireNonNull(key, "Feature key cannot be null."); Objects.requireNonNull(key, "Feature key cannot be null.");
this.key = key; this.key = key;
this.setAllowed(this.defaultAllowed = allowed); this.setAllowed(this.defaultAllowed = allowed);
this.setEnabled(this.defaultEnabled = enabled); this.setEnabled(this.defaultEnabled = enabled);
} }
public LambdaControlsFeature(@NotNull String key) public LambdaControlsFeature(@NotNull String key) {
{
this(key, false, false); this(key, false, false);
} }
/** /**
* Allows the feature. * Allows the feature.
*/ */
public void allow() public void allow() {
{
this.setAllowed(true); this.setAllowed(true);
} }
/** /**
* Returns whether this feature is allowed. * Returns whether this feature is allowed.
* *
* @return True if this feature is allowed, else false. * @return {@code true} if this feature is allowed, else {@code false}
*/ */
public boolean isAllowed() public boolean isAllowed() {
{
return this.allowed; return this.allowed;
} }
/** /**
* Sets whether this feature is allowed. * Sets whether this feature is allowed.
* *
* @param allowed True if this feature is allowed, else false. * @param allowed {@code true} if this feature is allowed, else {@code false}
*/ */
public void setAllowed(boolean allowed) public void setAllowed(boolean allowed) {
{
this.allowed = allowed; this.allowed = allowed;
} }
/** /**
* Resets allowed state to default. * Resets allowed state to default.
*/ */
public void resetAllowed() public void resetAllowed() {
{
this.setAllowed(this.defaultAllowed); this.setAllowed(this.defaultAllowed);
} }
/** /**
* Returns whether this feature is enabled. * Returns whether this feature is enabled.
* *
* @return True if this feature is enabled, else false. * @return {@code true} if this feature is enabled, else {@code false}
*/ */
public boolean isEnabled() public boolean isEnabled() {
{
return this.enabled; return this.enabled;
} }
/** /**
* Returns whether this feature is enabled. * Returns whether this feature is enabled.
* *
* @param enabled True if this feature is enabled, else false. * @param enabled {@code true} if this feature is enabled, else {@code false}
*/ */
public void setEnabled(boolean enabled) public void setEnabled(boolean enabled) {
{
this.enabled = enabled; this.enabled = enabled;
} }
/** /**
* Returns whether this feature is available or not. * Returns whether this feature is available or not.
* *
* @return True if this feature is available, else false. * @return {@code true} if this feature is available, else {@code false}
* @see #isAllowed() * @see #isAllowed()
* @see #isEnabled() * @see #isEnabled()
*/ */
public boolean isAvailable() public boolean isAvailable() {
{
return this.isAllowed() && this.isEnabled(); return this.isAllowed() && this.isEnabled();
} }
/** /**
* Resets the feature to its default values. * Resets the feature to its default values.
*/ */
public void reset() public void reset() {
{
this.resetAllowed(); this.resetAllowed();
this.setEnabled(this.defaultEnabled); this.setEnabled(this.defaultEnabled);
} }
@Override @Override
public @NotNull String getName() public @NotNull String getName() {
{
return this.key; return this.key;
} }
public static @NotNull Optional<LambdaControlsFeature> fromName(@NotNull String key) public static @NotNull Optional<LambdaControlsFeature> fromName(@NotNull String key) {
{
Objects.requireNonNull(key, "Cannot find features with a null name."); Objects.requireNonNull(key, "Cannot find features with a null name.");
return FEATURES.parallelStream().filter(feature -> feature.getName().equals(key)).findFirst(); return FEATURES.parallelStream().filter(feature -> feature.getName().equals(key)).findFirst();
} }
@@ -142,16 +129,14 @@ public class LambdaControlsFeature implements Nameable
/** /**
* Resets all features to their default values. * Resets all features to their default values.
*/ */
public static void resetAll() public static void resetAll() {
{
FEATURES.parallelStream().forEach(LambdaControlsFeature::reset); FEATURES.parallelStream().forEach(LambdaControlsFeature::reset);
} }
/** /**
* Resets all features to allow state. * Resets all features to allow state.
*/ */
public static void resetAllAllowed() public static void resetAllAllowed() {
{
FEATURES.parallelStream().forEach(LambdaControlsFeature::resetAllowed); FEATURES.parallelStream().forEach(LambdaControlsFeature::resetAllowed);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package dev.lambdaurora.lambdacontrols.client;
/** /**
* Represents a button state. * Represents a button state.
@@ -16,8 +16,7 @@ package me.lambdaurora.lambdacontrols.client;
* @version 1.1.0 * @version 1.1.0
* @since 1.1.0 * @since 1.1.0
*/ */
public enum ButtonState public enum ButtonState {
{
NONE(0), NONE(0),
PRESS(1), PRESS(1),
RELEASE(2), RELEASE(2),
@@ -25,28 +24,25 @@ public enum ButtonState
public final int id; public final int id;
ButtonState(int id) ButtonState(int id) {
{
this.id = id; this.id = id;
} }
/** /**
* Returns whether this state is a pressed state. * Returns whether this state is a pressed state.
* *
* @return True if this state is a pressed state, else false. * @return true if this state is a pressed state, else false
*/ */
public boolean isPressed() public boolean isPressed() {
{
return this == PRESS || this == REPEAT; return this == PRESS || this == REPEAT;
} }
/** /**
* Returns whether this state is an unpressed state. * Returns whether this state is an unpressed state.
* *
* @return True if this state is an unpressed state, else false. * @return true if this state is an unpressed state, else false
*/ */
public boolean isUnpressed() public boolean isUnpressed() {
{
return this == RELEASE || this == NONE; return this == RELEASE || this == NONE;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package dev.lambdaurora.lambdacontrols.client;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -25,8 +25,7 @@ import java.util.Optional;
* @version 1.4.3 * @version 1.4.3
* @since 1.0.0 * @since 1.0.0
*/ */
public enum ControllerType implements Nameable public enum ControllerType implements Nameable {
{
DEFAULT(0), DEFAULT(0),
DUALSHOCK(1), DUALSHOCK(1),
SWITCH(2), SWITCH(2),
@@ -35,17 +34,15 @@ public enum ControllerType implements Nameable
STEAM(5), STEAM(5),
OUYA(6); OUYA(6);
private final int id; private final int id;
private final Text text; private final Text text;
ControllerType(int id) ControllerType(int id) {
{
this.id = id; this.id = id;
this.text = new TranslatableText("lambdacontrols.controller_type." + this.getName()); this.text = new TranslatableText("lambdacontrols.controller_type." + this.getName());
} }
ControllerType(int id, @NotNull Text text) ControllerType(int id, @NotNull Text text) {
{
this.id = id; this.id = id;
this.text = text; this.text = text;
} }
@@ -53,21 +50,19 @@ public enum ControllerType implements Nameable
/** /**
* Returns the controller type's identifier. * Returns the controller type's identifier.
* *
* @return The controller type's identifier. * @return the controller type's identifier
*/ */
public int getId() public int getId() {
{
return this.id; return this.id;
} }
/** /**
* Returns the next controller type available. * Returns the next controller type available.
* *
* @return The next available controller type. * @return the next available controller type
*/ */
public @NotNull ControllerType next() public @NotNull ControllerType next() {
{ var v = values();
ControllerType[] v = values();
if (v.length == this.ordinal() + 1) if (v.length == this.ordinal() + 1)
return v[0]; return v[0];
return v[this.ordinal() + 1]; return v[this.ordinal() + 1];
@@ -76,27 +71,24 @@ public enum ControllerType implements Nameable
/** /**
* Gets the translated text of this controller type. * Gets the translated text of this controller type.
* *
* @return The translated text of this controller type. * @return the translated text of this controller type
*/ */
public @NotNull Text getTranslatedText() public @NotNull Text getTranslatedText() {
{
return this.text; return this.text;
} }
@Override @Override
public @NotNull String getName() public @NotNull String getName() {
{
return this.name().toLowerCase(); return this.name().toLowerCase();
} }
/** /**
* Gets the controller type from its identifier. * Gets the controller type from its identifier.
* *
* @param id The identifier of the controller type. * @param id the identifier of the controller type
* @return The controller type if found, else empty. * @return the controller type if found, else empty
*/ */
public static @NotNull Optional<ControllerType> byId(@NotNull String id) public static @NotNull Optional<ControllerType> byId(@NotNull String id) {
{
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,9 +7,8 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package dev.lambdaurora.lambdacontrols.client;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
@@ -25,26 +24,23 @@ import java.util.Optional;
* @version 1.4.0 * @version 1.4.0
* @since 1.0.0 * @since 1.0.0
*/ */
public enum HudSide implements Nameable public enum HudSide implements Nameable {
{
LEFT, LEFT,
RIGHT; RIGHT;
private final Text text; private final Text text;
HudSide() HudSide() {
{
this.text = new TranslatableText(this.getTranslationKey()); this.text = new TranslatableText(this.getTranslationKey());
} }
/** /**
* Returns the next side available. * Returns the next side available.
* *
* @return The next available side. * @return the next available side
*/ */
public @NotNull HudSide next() public @NotNull HudSide next() {
{ var v = values();
HudSide[] v = values();
if (v.length == this.ordinal() + 1) if (v.length == this.ordinal() + 1)
return v[0]; return v[0];
return v[this.ordinal() + 1]; return v[this.ordinal() + 1];
@@ -53,37 +49,33 @@ public enum HudSide implements Nameable
/** /**
* Returns the translation key of this hud side. * Returns the translation key of this hud side.
* *
* @return The translation key of this hude side. * @return the translation key of this hude side
*/ */
public @NotNull String getTranslationKey() public @NotNull String getTranslationKey() {
{
return "lambdacontrols.hud_side." + this.getName(); return "lambdacontrols.hud_side." + this.getName();
} }
/** /**
* Gets the translated text of this hud side. * Gets the translated text of this hud side.
* *
* @return The translated text of this hud side. * @return the translated text of this hud side
*/ */
public @NotNull Text getTranslatedText() public @NotNull Text getTranslatedText() {
{
return this.text; return this.text;
} }
@Override @Override
public @NotNull String getName() public @NotNull String getName() {
{
return this.name().toLowerCase(); return this.name().toLowerCase();
} }
/** /**
* Gets the hud side from its identifier. * Gets the hud side from its identifier.
* *
* @param id The identifier of the hud side. * @param id the identifier of the hud side
* @return The hud side if found, else empty. * @return the hud side if found, else empty
*/ */
public static @NotNull Optional<HudSide> byId(@NotNull String id) public static @NotNull Optional<HudSide> byId(@NotNull String id) {
{
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,29 +7,28 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package dev.lambdaurora.lambdacontrols.client;
import me.lambdaurora.lambdacontrols.ControlsMode; import dev.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls; import dev.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.LambdaControlsConstants; import dev.lambdaurora.lambdacontrols.LambdaControlsConstants;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature; import dev.lambdaurora.lambdacontrols.LambdaControlsFeature;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import dev.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.Controller; import dev.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.lambdacontrols.client.controller.InputManager; import dev.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsHud; import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsHud;
import me.lambdaurora.lambdacontrols.client.gui.RingScreen; import dev.lambdaurora.lambdacontrols.client.ring.KeyBindingRingAction;
import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay; import dev.lambdaurora.lambdacontrols.client.ring.LambdaRing;
import me.lambdaurora.lambdacontrols.client.ring.KeyBindingRingAction; import dev.lambdaurora.spruceui.hud.HudManager;
import me.lambdaurora.lambdacontrols.client.ring.LambdaRing;
import me.lambdaurora.spruceui.event.OpenScreenCallback;
import me.lambdaurora.spruceui.hud.HudManager;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.toast.SystemToast; import net.minecraft.client.toast.SystemToast;
import net.minecraft.client.util.InputUtil; import net.minecraft.client.util.InputUtil;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
@@ -44,36 +43,34 @@ import java.io.File;
* Represents the LambdaControls client mod. * Represents the LambdaControls client mod.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.5.0 * @version 1.7.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsClient extends LambdaControls implements ClientModInitializer public class LambdaControlsClient extends LambdaControls implements ClientModInitializer {
{ private static LambdaControlsClient INSTANCE;
private static LambdaControlsClient INSTANCE; public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_up"),
public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_up"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement"); InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement");
public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_right"), public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_right"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement"); InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement");
public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_down"), public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_down"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement"); InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement");
public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_left"), public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_left"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement"); InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement");
/*public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "ring"), /*public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "ring"),
InputUtil.Type.MOUSE, GLFW.GLFW_MOUSE_BUTTON_5, "key.categories.misc");*/ InputUtil.Type.MOUSE, GLFW.GLFW_MOUSE_BUTTON_5, "key.categories.misc");*/
public static final Identifier CONTROLLER_BUTTONS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png"); public static final Identifier CONTROLLER_BUTTONS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png");
public static final Identifier CONTROLLER_AXIS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_axis.png"); public static final Identifier CONTROLLER_AXIS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_axis.png");
public static final Identifier CURSOR_TEXTURE = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/cursor.png"); public static final Identifier CURSOR_TEXTURE = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/cursor.png");
public final static File MAPPINGS_FILE = new File("config/gamecontrollerdb.txt"); public final static File MAPPINGS_FILE = new File("config/gamecontrollerdb.txt");
public final LambdaControlsConfig config = new LambdaControlsConfig(this); public final LambdaControlsConfig config = new LambdaControlsConfig(this);
public final LambdaInput input = new LambdaInput(this); public final LambdaInput input = new LambdaInput(this);
public final LambdaRing ring = new LambdaRing(this); public final LambdaRing ring = new LambdaRing(this);
public final LambdaReacharound reacharound = new LambdaReacharound(); public final LambdaReacharound reacharound = new LambdaReacharound();
private LambdaControlsHud hud; private LambdaControlsHud hud;
private ControlsMode previousControlsMode; private ControlsMode previousControlsMode;
@Override @Override
public void onInitializeClient() public void onInitializeClient() {
{
INSTANCE = this; INSTANCE = this;
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_UP); KeyBindingHelper.registerKeyBinding(BINDING_LOOK_UP);
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_RIGHT); KeyBindingHelper.registerKeyBinding(BINDING_LOOK_RIGHT);
@@ -83,18 +80,27 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
this.ring.registerAction("keybinding", KeyBindingRingAction.FACTORY); this.ring.registerAction("keybinding", KeyBindingRingAction.FACTORY);
ClientSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL, (context, attachedData) -> context.getTaskQueue() ClientPlayNetworking.registerGlobalReceiver(CONTROLS_MODE_CHANNEL, (client, handler, buf, responseSender) -> {
.execute(() -> ClientSidePacketRegistry.INSTANCE.sendToServer(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode())))); responseSender.sendPacket(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode()));
ClientSidePacketRegistry.INSTANCE.register(FEATURE_CHANNEL, (context, attachedData) -> {
String name = attachedData.readString(64);
boolean allowed = attachedData.readBoolean();
LambdaControlsFeature.fromName(name).ifPresent(feature -> context.getTaskQueue().execute(() -> feature.setAllowed(allowed)));
}); });
ClientPlayNetworking.registerGlobalReceiver(FEATURE_CHANNEL, (client, handler, buf, responseSender) -> {
int features = buf.readVarInt();
for (int i = 0; i < features; i++) {
var name = buf.readString(64);
boolean allowed = buf.readBoolean();
LambdaControlsFeature.fromName(name).ifPresent(feature -> client.execute(() -> feature.setAllowed(allowed)));
}
});
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
sender.sendPacket(HELLO_CHANNEL, this.makeHello(this.config.getControlsMode()));
sender.sendPacket(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode()));
});
ClientPlayConnectionEvents.DISCONNECT.register(this::onLeave);
ClientTickEvents.START_CLIENT_TICK.register(this.reacharound::tick); ClientTickEvents.START_CLIENT_TICK.register(this.reacharound::tick);
ClientTickEvents.END_CLIENT_TICK.register(this::onTick); ClientTickEvents.END_CLIENT_TICK.register(this::onTick);
OpenScreenCallback.EVENT.register((client, screen) -> { /*OpenScreenCallback.EVENT.register((client, screen) -> {
if (screen == null && this.config.getControlsMode() == ControlsMode.TOUCHSCREEN) { if (screen == null && this.config.getControlsMode() == ControlsMode.TOUCHSCREEN) {
screen = new TouchscreenOverlay(this); screen = new TouchscreenOverlay(this);
screen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); screen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
@@ -103,7 +109,7 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
} else if (screen != null) { } else if (screen != null) {
this.input.onScreenOpen(client, client.getWindow().getWidth(), client.getWindow().getHeight()); this.input.onScreenOpen(client, client.getWindow().getWidth(), client.getWindow().getHeight());
} }
}); });*/
HudManager.register(this.hud = new LambdaControlsHud(this)); HudManager.register(this.hud = new LambdaControlsHud(this));
} }
@@ -111,15 +117,14 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
/** /**
* This method is called when Minecraft is initializing. * This method is called when Minecraft is initializing.
*/ */
public void onMcInit(@NotNull MinecraftClient client) public void onMcInit(@NotNull MinecraftClient client) {
{
ButtonBinding.init(client.options); ButtonBinding.init(client.options);
this.config.load(); this.config.load();
this.hud.setVisible(this.config.isHudEnabled()); this.hud.setVisible(this.config.isHudEnabled());
Controller.updateMappings(); Controller.updateMappings();
GLFW.glfwSetJoystickCallback((jid, event) -> { GLFW.glfwSetJoystickCallback((jid, event) -> {
if (event == GLFW.GLFW_CONNECTED) { if (event == GLFW.GLFW_CONNECTED) {
Controller controller = Controller.byId(jid); var controller = Controller.byId(jid);
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.connected", jid), client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.connected", jid),
new LiteralText(controller.getName()))); new LiteralText(controller.getName())));
} else if (event == GLFW.GLFW_DISCONNECTED) { } else if (event == GLFW.GLFW_DISCONNECTED) {
@@ -136,37 +141,33 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
/** /**
* This method is called every Minecraft tick. * This method is called every Minecraft tick.
* *
* @param client The client instance. * @param client the client instance
*/ */
public void onTick(@NotNull MinecraftClient client) public void onTick(@NotNull MinecraftClient client) {
{ this.input.tick(client);
this.input.onTick(client);
if (this.config.getControlsMode() == ControlsMode.CONTROLLER && (client.isWindowFocused() || this.config.hasUnfocusedInput())) if (this.config.getControlsMode() == ControlsMode.CONTROLLER && (client.isWindowFocused() || this.config.hasUnfocusedInput()))
this.input.onControllerTick(client); this.input.tickController(client);
/*if (BINDING_RING.wasPressed()) { /*if (BINDING_RING.wasPressed()) {
client.openScreen(new RingScreen()); client.openScreen(new RingScreen());
}*/ }*/
} }
public void onRender(MinecraftClient client) public void onRender(MinecraftClient client) {
{
this.input.onRender(client.getTickDelta(), client); this.input.onRender(client.getTickDelta(), client);
} }
/** /**
* Called when leaving a server. * Called when leaving a server.
*/ */
public void onLeave() public void onLeave(ClientPlayNetworkHandler handler, MinecraftClient client) {
{
LambdaControlsFeature.resetAllAllowed(); LambdaControlsFeature.resetAllAllowed();
} }
/** /**
* Switches the controls mode if the auto switch is enabled. * Switches the controls mode if the auto switch is enabled.
*/ */
public void switchControlsMode() public void switchControlsMode() {
{
if (this.config.hasAutoSwitchMode()) { if (this.config.hasAutoSwitchMode()) {
if (this.config.getController().isGamepad()) { if (this.config.getController().isGamepad()) {
this.previousControlsMode = this.config.getControlsMode(); this.previousControlsMode = this.config.getControlsMode();
@@ -184,10 +185,9 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
/** /**
* Sets whether the HUD is enabled or not. * Sets whether the HUD is enabled or not.
* *
* @param enabled True if the HUD is enabled, else false. * @param enabled true if the HUD is enabled, else false
*/ */
public void setHudEnabled(boolean enabled) public void setHudEnabled(boolean enabled) {
{
this.config.setHudEnabled(enabled); this.config.setHudEnabled(enabled);
this.hud.setVisible(enabled); this.hud.setVisible(enabled);
} }
@@ -195,10 +195,9 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni
/** /**
* Gets the LambdaControls client instance. * Gets the LambdaControls client instance.
* *
* @return The LambdaControls client instance. * @return the LambdaControls client instance
*/ */
public static LambdaControlsClient get() public static LambdaControlsClient get() {
{
return INSTANCE; return INSTANCE;
} }
} }

View File

@@ -0,0 +1,28 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen;
/**
* Represents the API implementation of ModMenu for LambdaControls.
*
* @author LambdAurora
* @version 1.7.0
* @since 1.1.0
*/
public class LambdaControlsModMenu implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> new LambdaControlsSettingsScreen(parent, false);
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,21 +7,26 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package dev.lambdaurora.lambdacontrols.client;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import dev.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.Controller; import dev.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.lambdacontrols.client.controller.InputManager; import dev.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen; import dev.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay;
import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay; import dev.lambdaurora.lambdacontrols.client.gui.widget.ControllerControlsWidget;
import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor; import dev.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor; import dev.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor; import dev.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; import dev.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import me.lambdaurora.lambdacontrols.client.util.MouseAccessor; import dev.lambdaurora.lambdacontrols.client.util.MouseAccessor;
import me.lambdaurora.spruceui.SpruceLabelWidget; import dev.lambdaurora.spruceui.navigation.NavigationDirection;
import dev.lambdaurora.spruceui.screen.SpruceScreen;
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 net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.ParentElement; import net.minecraft.client.gui.ParentElement;
@@ -34,11 +39,10 @@ import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget; import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
import net.minecraft.client.gui.screen.pack.PackScreen; import net.minecraft.client.gui.screen.pack.PackScreen;
import net.minecraft.client.gui.screen.world.WorldListWidget; import net.minecraft.client.gui.screen.world.WorldListWidget;
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget; import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
import net.minecraft.client.gui.widget.EntryListWidget; import net.minecraft.client.gui.widget.EntryListWidget;
import net.minecraft.client.gui.widget.PressableWidget;
import net.minecraft.client.gui.widget.SliderWidget; import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType; import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
@@ -49,53 +53,50 @@ import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWGamepadState; import org.lwjgl.glfw.GLFWGamepadState;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import static me.lambdaurora.lambdacontrols.client.controller.ButtonBinding.axisAsButton; import static dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding.axisAsButton;
import static me.lambdaurora.lambdacontrols.client.controller.InputManager.INPUT_MANAGER; import static dev.lambdaurora.lambdacontrols.client.controller.InputManager.INPUT_MANAGER;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
/** /**
* Represents the LambdaControls' input handler. * Represents the LambdaControls' input handler.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.4.3 * @version 1.7.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class LambdaInput public class LambdaInput {
{ private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>(); private final LambdaControlsConfig config;
private final LambdaControlsConfig config;
// Cooldowns // Cooldowns
private int actionGuiCooldown = 0; private int actionGuiCooldown = 0;
private boolean ignoreNextARelease = false; private boolean ignoreNextARelease = false;
private double targetYaw = 0.0; private double targetYaw = 0.0;
private double targetPitch = 0.0; private double targetPitch = 0.0;
private float prevXAxis = 0.F; private float prevXAxis = 0.f;
private float prevYAxis = 0.F; private float prevYAxis = 0.f;
private int targetMouseX = 0; private int targetMouseX = 0;
private int targetMouseY = 0; private int targetMouseY = 0;
private float mouseSpeedX = 0.F; private float mouseSpeedX = 0.f;
private float mouseSpeedY = 0.F; private float mouseSpeedY = 0.f;
private int inventoryInteractionCooldown = 0; private int inventoryInteractionCooldown = 0;
public LambdaInput(@NotNull LambdaControlsClient mod) private ControllerControlsWidget controlsInput = null;
{
public LambdaInput(@NotNull LambdaControlsClient mod) {
this.config = mod.config; this.config = mod.config;
} }
/** /**
* This method is called every Minecraft tick. * This method is called every Minecraft tick.
* *
* @param client The client instance. * @param client the client instance
*/ */
public void onTick(@NotNull MinecraftClient client) public void tick(@NotNull MinecraftClient client) {
{
this.targetYaw = 0.F; this.targetYaw = 0.F;
this.targetPitch = 0.F; this.targetPitch = 0.F;
@@ -117,20 +118,20 @@ public class LambdaInput
/** /**
* This method is called every Minecraft tick for controller input update. * This method is called every Minecraft tick for controller input update.
* *
* @param client The client instance. * @param client the client instance
*/ */
public void onControllerTick(@NotNull MinecraftClient client) public void tickController(@NotNull MinecraftClient client) {
{ BUTTON_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0)
BUTTON_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0).forEach(entry -> BUTTON_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1)); .forEach(entry -> BUTTON_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
// Decreases the cooldown for GUI actions. // Decreases the cooldown for GUI actions.
if (this.actionGuiCooldown > 0) if (this.actionGuiCooldown > 0)
--this.actionGuiCooldown; --this.actionGuiCooldown;
InputManager.updateStates(); InputManager.updateStates();
Controller controller = this.config.getController(); var controller = this.config.getController();
if (controller.isConnected()) { if (controller.isConnected()) {
GLFWGamepadState state = controller.getState(); var state = controller.getState();
this.fetchButtonInput(client, state, false); this.fetchButtonInput(client, state, false);
this.fetchAxeInput(client, state, false); this.fetchAxeInput(client, state, false);
} }
@@ -143,20 +144,20 @@ public class LambdaInput
boolean allowInput = true; boolean allowInput = true;
if (client.currentScreen instanceof ControllerControlsScreen && ((ControllerControlsScreen) client.currentScreen).focusedBinding != null) if (this.controlsInput != null && this.controlsInput.focusedBinding != null)
allowInput = false; allowInput = false;
if (allowInput) if (allowInput)
InputManager.updateBindings(client); InputManager.updateBindings(client);
if (client.currentScreen instanceof ControllerControlsScreen && InputManager.STATES.entrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) { if (this.controlsInput != null
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen; && InputManager.STATES.int2ObjectEntrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) {
if (screen.focusedBinding != null && !screen.waiting) { if (this.controlsInput.focusedBinding != null && !this.controlsInput.waiting) {
int[] buttons = new int[screen.currentButtons.size()]; int[] buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < screen.currentButtons.size(); i++) for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = screen.currentButtons.get(i); buttons[i] = this.controlsInput.currentButtons.get(i);
screen.focusedBinding.setButton(buttons); this.controlsInput.finishBindingEdit(buttons);
screen.focusedBinding = null; this.controlsInput = null;
} }
} }
@@ -167,11 +168,10 @@ public class LambdaInput
/** /**
* This method is called before the screen is rendered. * This method is called before the screen is rendered.
* *
* @param client The client instance. * @param client the client instance
* @param screen The screen to render. * @param screen the screen to render
*/ */
public void onPreRenderScreen(@NotNull MinecraftClient client, @NotNull Screen screen) public void onPreRenderScreen(@NotNull MinecraftClient client, @NotNull Screen screen) {
{
if (!isScreenInteractive(screen)) { if (!isScreenInteractive(screen)) {
INPUT_MANAGER.updateMousePosition(client); INPUT_MANAGER.updateMousePosition(client);
} }
@@ -180,24 +180,23 @@ public class LambdaInput
/** /**
* This method is called when Minecraft renders. * This method is called when Minecraft renders.
* *
* @param client The client instance. * @param client the client instance
*/ */
public void onRender(float tickDelta, @NotNull MinecraftClient client) public void onRender(float tickDelta, @NotNull MinecraftClient client) {
{
if (!(client.currentScreen == null || client.currentScreen instanceof TouchscreenOverlay)) if (!(client.currentScreen == null || client.currentScreen instanceof TouchscreenOverlay))
return; return;
PlayerEntity player = client.player; var player = client.player;
if (player == null) if (player == null)
return; return;
if (this.targetYaw != 0F || this.targetPitch != 0F) { if (this.targetYaw != 0.f || this.targetPitch != 0.f) {
float rotationYaw = (float) (player.prevYaw + (this.targetYaw / 0.10) * tickDelta); float rotationYaw = (float) (player.prevYaw + (this.targetYaw / 0.10) * tickDelta);
float rotationPitch = (float) (player.prevPitch + (this.targetPitch / 0.10) * tickDelta); float rotationPitch = (float) (player.prevPitch + (this.targetPitch / 0.10) * tickDelta);
client.player.yaw = rotationYaw; client.player.setYaw(rotationYaw);
client.player.pitch = MathHelper.clamp(rotationPitch, -90.F, 90.F); client.player.setPitch(MathHelper.clamp(rotationPitch, -90.f, 90.f));
if (client.player.isRiding()) { if (client.player.isRiding()) {
client.player.getVehicle().copyPositionAndRotation(client.player); client.player.getVehicle().onPassengerLookAround(client.player);
} }
client.getTutorialManager().onUpdateMouse(this.targetPitch, this.targetYaw); client.getTutorialManager().onUpdateMouse(this.targetPitch, this.targetYaw);
} }
@@ -206,30 +205,36 @@ public class LambdaInput
/** /**
* This method is called when a Screen is opened. * This method is called when a Screen is opened.
* *
* @param client The client instance. * @param client the client instance
* @param windowWidth The window width. * @param windowWidth the window width
* @param windowHeight The window height. * @param windowHeight the window height
*/ */
public void onScreenOpen(@NotNull MinecraftClient client, int windowWidth, int windowHeight) public void onScreenOpen(@NotNull MinecraftClient client, int windowWidth, int windowHeight) {
{
if (client.currentScreen == null) { if (client.currentScreen == null) {
this.mouseSpeedX = this.mouseSpeedY = 0.0F; this.mouseSpeedX = this.mouseSpeedY = 0.0F;
INPUT_MANAGER.resetMousePosition(windowWidth, windowHeight); INPUT_MANAGER.resetMousePosition(windowWidth, windowHeight);
} else if (isScreenInteractive(client.currentScreen) && this.config.hasVirtualMouse()) { } else if (isScreenInteractive(client.currentScreen) && this.config.hasVirtualMouse()) {
((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), 0, 0); ((MouseAccessor) client.mouse).lambdacontrols$onCursorPos(client.getWindow().getHandle(), 0, 0);
INPUT_MANAGER.resetMouseTarget(client); INPUT_MANAGER.resetMouseTarget(client);
} }
this.inventoryInteractionCooldown = 5; this.inventoryInteractionCooldown = 5;
} }
private void fetchButtonInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon) public void beginControlsInput(ControllerControlsWidget widget) {
{ this.controlsInput = widget;
ByteBuffer buffer = gamepadState.buttons(); if (widget != null) {
this.controlsInput.currentButtons.clear();
this.controlsInput.waiting = true;
}
}
private void fetchButtonInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon) {
var buffer = gamepadState.buttons();
for (int i = 0; i < buffer.limit(); i++) { for (int i = 0; i < buffer.limit(); i++) {
int btn = leftJoycon ? ButtonBinding.controller2Button(i) : i; int btn = leftJoycon ? ButtonBinding.controller2Button(i) : i;
boolean btnState = buffer.get() == (byte) 1; boolean btnState = buffer.get() == (byte) 1;
ButtonState state = ButtonState.NONE; var state = ButtonState.NONE;
ButtonState previousState = InputManager.STATES.getOrDefault(btn, ButtonState.NONE); var previousState = InputManager.STATES.getOrDefault(btn, ButtonState.NONE);
if (btnState != previousState.isPressed()) { if (btnState != previousState.isPressed()) {
state = btnState ? ButtonState.PRESS : ButtonState.RELEASE; state = btnState ? ButtonState.PRESS : ButtonState.RELEASE;
@@ -248,9 +253,8 @@ public class LambdaInput
} }
} }
private void fetchAxeInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon) private void fetchAxeInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon) {
{ var buffer = gamepadState.axes();
FloatBuffer buffer = gamepadState.axes();
for (int i = 0; i < buffer.limit(); i++) { for (int i = 0; i < buffer.limit(); i++) {
int axis = leftJoycon ? ButtonBinding.controller2Button(i) : i; int axis = leftJoycon ? ButtonBinding.controller2Button(i) : i;
float value = buffer.get(); float value = buffer.get();
@@ -259,28 +263,24 @@ public class LambdaInput
if (i == GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y) if (i == GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y)
value *= -1.0F; value *= -1.0F;
int state = value > this.config.getDeadZone() ? 1 : (value < -this.config.getDeadZone() ? 2 : 0); int state = value > this.config.getRightDeadZone() ? 1 : (value < -this.config.getRightDeadZone() ? 2 : 0);
this.handleAxe(client, axis, value, absValue, state); this.handleAxe(client, axis, value, absValue, state);
} }
} }
private void handleButton(@NotNull MinecraftClient client, int button, int action, boolean state) private void handleButton(@NotNull MinecraftClient client, int button, int action, boolean state) {
{ if (this.controlsInput != null && this.controlsInput.focusedBinding != null) {
if (client.currentScreen instanceof ControllerControlsScreen) { if (action == 0 && !this.controlsInput.currentButtons.contains(button)) {
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen; this.controlsInput.currentButtons.add(button);
if (screen.focusedBinding != null) {
if (action == 0 && !screen.currentButtons.contains(button)) {
screen.currentButtons.add(button);
int[] buttons = new int[screen.currentButtons.size()]; var buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < screen.currentButtons.size(); i++) for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = screen.currentButtons.get(i); buttons[i] = this.controlsInput.currentButtons.get(i);
screen.focusedBinding.setButton(buttons); this.controlsInput.focusedBinding.setButton(buttons);
screen.waiting = false; this.controlsInput.waiting = false;
}
return;
} }
return;
} }
if (action == 0 || action == 2) { if (action == 0 || action == 2) {
@@ -289,14 +289,10 @@ public class LambdaInput
|| button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)) { || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)) {
if (this.actionGuiCooldown == 0) { if (this.actionGuiCooldown == 0) {
if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP) { if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP) {
this.changeFocus(client.currentScreen, false); this.changeFocus(client.currentScreen, NavigationDirection.UP);
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN) { } else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN) {
this.changeFocus(client.currentScreen, true); this.changeFocus(client.currentScreen, NavigationDirection.DOWN);
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT) { } else this.handleLeftRight(client.currentScreen, button != GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT);
this.handleLeftRight(client.currentScreen, false);
} else {
this.handleLeftRight(client.currentScreen, true);
}
} }
return; return;
} }
@@ -305,7 +301,7 @@ public class LambdaInput
if (action == 1) { if (action == 1) {
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null) { if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null) {
if (this.actionGuiCooldown == 0) { if (this.actionGuiCooldown == 0) {
Element focused = client.currentScreen.getFocused(); var focused = client.currentScreen.getFocused();
if (focused != null && isScreenInteractive(client.currentScreen)) { if (focused != null && isScreenInteractive(client.currentScreen)) {
if (this.handleAButton(client.currentScreen, focused)) { if (this.handleAButton(client.currentScreen, focused)) {
this.actionGuiCooldown = 5; // Prevent to press too quickly the focused element, so we have to skip 5 ticks. this.actionGuiCooldown = 5; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
@@ -330,7 +326,8 @@ public class LambdaInput
} }
} }
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !isScreenInteractive(client.currentScreen) && this.actionGuiCooldown == 0) { if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !isScreenInteractive(client.currentScreen)
&& this.actionGuiCooldown == 0) {
if (!this.ignoreNextARelease) { if (!this.ignoreNextARelease) {
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth(); double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight(); double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
@@ -351,12 +348,11 @@ public class LambdaInput
/** /**
* Handles inventory interaction. * Handles inventory interaction.
* *
* @param client The client instance. * @param client the client instance
* @param button The button pressed. * @param button the button pressed
* @return True if an inventory interaction was done. * @return {@code true} if an inventory interaction was done
*/ */
private boolean handleInventory(@NotNull MinecraftClient client, int button) private boolean handleInventory(@NotNull MinecraftClient client, int button) {
{
if (!(client.currentScreen instanceof HandledScreen)) if (!(client.currentScreen instanceof HandledScreen))
return false; return false;
@@ -374,25 +370,25 @@ public class LambdaInput
double x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth(); double x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight(); double y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
HandledScreen screen = (HandledScreen) client.currentScreen; var screen = (HandledScreen) client.currentScreen;
HandledScreenAccessor accessor = (HandledScreenAccessor) screen; var accessor = (HandledScreenAccessor) screen;
Slot slot = ((HandledScreenAccessor) client.currentScreen).lambdacontrols_getSlotAt(x, y); Slot slot = ((HandledScreenAccessor) client.currentScreen).lambdacontrols$getSlotAt(x, y);
int slotId; int slotId;
if (slot == null) { if (slot == null) {
if (client.player.inventory.getCursorStack().isEmpty()) if (client.player.currentScreenHandler.getCursorStack().isEmpty())
return false; return false;
slotId = accessor.lambdacontrols_isClickOutsideBounds(x, y, accessor.getX(), accessor.getY(), GLFW_MOUSE_BUTTON_1) ? -999 : -1; slotId = accessor.lambdacontrols$isClickOutsideBounds(x, y, accessor.getX(), accessor.getY(), GLFW_MOUSE_BUTTON_1) ? -999 : -1;
} else { } else {
slotId = slot.id; slotId = slot.id;
} }
SlotActionType actionType = SlotActionType.PICKUP; var actionType = SlotActionType.PICKUP;
int clickData = GLFW.GLFW_MOUSE_BUTTON_1; int clickData = GLFW.GLFW_MOUSE_BUTTON_1;
switch (button) { switch (button) {
case GLFW_GAMEPAD_BUTTON_A: case GLFW_GAMEPAD_BUTTON_A:
if (screen instanceof CreativeInventoryScreen) if (screen instanceof CreativeInventoryScreen)
if (((CreativeInventoryScreenAccessor) screen).lambdacontrols_isCreativeInventorySlot(slot)) if (((CreativeInventoryScreenAccessor) screen).lambdacontrols$isCreativeInventorySlot(slot))
actionType = SlotActionType.CLONE; actionType = SlotActionType.CLONE;
if (slot != null && LambdaControlsCompat.streamCompatHandlers().anyMatch(handler -> handler.isCreativeSlot(screen, slot))) if (slot != null && LambdaControlsCompat.streamCompatHandlers().anyMatch(handler -> handler.isCreativeSlot(screen, slot)))
actionType = SlotActionType.CLONE; actionType = SlotActionType.CLONE;
@@ -407,21 +403,20 @@ public class LambdaInput
return false; return false;
} }
accessor.lambdacontrols_onMouseClick(slot, slotId, clickData, actionType); accessor.lambdacontrols$onMouseClick(slot, slotId, clickData, actionType);
return true; return true;
} }
/** /**
* Tries to go back. * Tries to go back.
* *
* @param screen The current screen. * @param screen the current screen
* @return True if successful, else false. * @return true if successful, else false
*/ */
public boolean tryGoBack(@NotNull Screen screen) public boolean tryGoBack(@NotNull Screen screen) {
{ var set = ImmutableSet.of("gui.back", "gui.done", "gui.cancel", "gui.toTitle", "gui.toMenu");
ImmutableSet<String> set = ImmutableSet.of("gui.back", "gui.done", "gui.cancel", "gui.toTitle", "gui.toMenu"); return screen.children().stream().filter(element -> element instanceof PressableWidget)
return screen.children().stream().filter(element -> element instanceof AbstractPressableButtonWidget) .map(element -> (PressableWidget) element)
.map(element -> (AbstractPressableButtonWidget) element)
.filter(element -> element.getMessage() instanceof TranslatableText) .filter(element -> element.getMessage() instanceof TranslatableText)
.anyMatch(element -> { .anyMatch(element -> {
if (set.stream().anyMatch(key -> key.equals(((TranslatableText) element.getMessage()).getKey()))) { if (set.stream().anyMatch(key -> key.equals(((TranslatableText) element.getMessage()).getKey()))) {
@@ -432,20 +427,25 @@ public class LambdaInput
}); });
} }
private void handleAxe(@NotNull MinecraftClient client, int axis, float value, float absValue, int state) private double getDeadZoneValue(int axis) {
{ return (axis == GLFW_GAMEPAD_AXIS_LEFT_X || axis == GLFW_GAMEPAD_AXIS_LEFT_Y) ? this.config.getLeftDeadZone()
int asButtonState = value > 0.5F ? 1 : (value < -0.5F ? 2 : 0); : this.config.getRightDeadZone();
}
if (axis == GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axis == GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER || axis == ButtonBinding.controller2Button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER) || private void handleAxe(@NotNull MinecraftClient client, int axis, float value, float absValue, int state) {
axis == ButtonBinding.controller2Button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER)) 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))
if (asButtonState == 2) if (asButtonState == 2)
asButtonState = 0; asButtonState = 0;
{ {
boolean currentPlusState = asButtonState == 1; boolean currentPlusState = asButtonState == 1;
boolean currentMinusState = asButtonState == 2; boolean currentMinusState = asButtonState == 2;
ButtonState previousPlusState = InputManager.STATES.getOrDefault(axisAsButton(axis, true), ButtonState.NONE); var previousPlusState = InputManager.STATES.getOrDefault(axisAsButton(axis, true), ButtonState.NONE);
ButtonState previousMinusState = InputManager.STATES.getOrDefault(axisAsButton(axis, false), ButtonState.NONE); var previousMinusState = InputManager.STATES.getOrDefault(axisAsButton(axis, false), ButtonState.NONE);
if (currentPlusState != previousPlusState.isPressed()) { if (currentPlusState != previousPlusState.isPressed()) {
InputManager.STATES.put(axisAsButton(axis, true), currentPlusState ? ButtonState.PRESS : ButtonState.RELEASE); InputManager.STATES.put(axisAsButton(axis, true), currentPlusState ? ButtonState.PRESS : ButtonState.RELEASE);
@@ -469,8 +469,11 @@ public class LambdaInput
} }
} }
float axisValue = absValue < this.config.getDeadZone() ? 0.f : (float) (absValue - this.config.getDeadZone()); double deadZone = this.getDeadZoneValue(axis);
axisValue /= (1.0 - this.config.getDeadZone()); float axisValue = absValue < deadZone ? 0.f : (float) (absValue - deadZone);
axisValue /= (1.0 - deadZone);
axisValue = (float) Math.min(axisValue / this.config.getAxisMaxValue(axis), 1);
if (currentPlusState) if (currentPlusState)
InputManager.BUTTON_VALUES.put(axisAsButton(axis, true), axisValue); InputManager.BUTTON_VALUES.put(axisAsButton(axis, true), axisValue);
else else
@@ -481,38 +484,33 @@ public class LambdaInput
InputManager.BUTTON_VALUES.put(axisAsButton(axis, false), 0.f); InputManager.BUTTON_VALUES.put(axisAsButton(axis, false), 0.f);
} }
double deadZone = this.config.getDeadZone(); double deadZone = this.getDeadZoneValue(axis);
if (client.currentScreen instanceof ControllerControlsScreen) { if (this.controlsInput != null && this.controlsInput.focusedBinding != null) {
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen; if (asButtonState != 0 && !this.controlsInput.currentButtons.contains(axisAsButton(axis, asButtonState == 1))) {
if (screen.focusedBinding != null) {
if (asButtonState != 0 && !screen.currentButtons.contains(axisAsButton(axis, asButtonState == 1))) {
screen.currentButtons.add(axisAsButton(axis, asButtonState == 1)); this.controlsInput.currentButtons.add(axisAsButton(axis, asButtonState == 1));
int[] buttons = new int[screen.currentButtons.size()]; int[] buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < screen.currentButtons.size(); i++) for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = screen.currentButtons.get(i); buttons[i] = this.controlsInput.currentButtons.get(i);
screen.focusedBinding.setButton(buttons); this.controlsInput.focusedBinding.setButton(buttons);
screen.waiting = false; this.controlsInput.waiting = false;
}
return;
} }
} else if (client.currentScreen instanceof CreativeInventoryScreen) { return;
} else if (client.currentScreen instanceof CreativeInventoryScreen creativeInventoryScreen) {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) { if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
CreativeInventoryScreen screen = (CreativeInventoryScreen) client.currentScreen; var accessor = (CreativeInventoryScreenAccessor) creativeInventoryScreen;
CreativeInventoryScreenAccessor accessor = (CreativeInventoryScreenAccessor) screen;
// @TODO allow rebinding to left stick // @TODO allow rebinding to left stick
if (accessor.lambdacontrols_hasScrollbar() && absValue >= deadZone) { if (accessor.lambdacontrols$hasScrollbar() && absValue >= deadZone) {
screen.mouseScrolled(0.0, 0.0, -value); creativeInventoryScreen.mouseScrolled(0.0, 0.0, -value);
} }
return; return;
} }
} else if (client.currentScreen instanceof AdvancementsScreen) { } else if (client.currentScreen instanceof AdvancementsScreen advancementsScreen) {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X || axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) { if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X || axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
AdvancementsScreen screen = (AdvancementsScreen) client.currentScreen; var accessor = (AdvancementsScreenAccessor) advancementsScreen;
AdvancementsScreenAccessor accessor = (AdvancementsScreenAccessor) screen;
if (absValue >= deadZone) { if (absValue >= deadZone) {
AdvancementTab tab = accessor.getSelectedTab(); AdvancementTab tab = accessor.getSelectedTab();
tab.move(axis == GLFW_GAMEPAD_AXIS_RIGHT_X ? -value * 5.0 : 0.0, axis == GLFW_GAMEPAD_AXIS_RIGHT_Y ? -value * 5.0 : 0.0); tab.move(axis == GLFW_GAMEPAD_AXIS_RIGHT_X ? -value * 5.0 : 0.0, axis == GLFW_GAMEPAD_AXIS_RIGHT_Y ? -value * 5.0 : 0.0);
@@ -521,18 +519,20 @@ public class LambdaInput
} }
} }
absValue -= deadZone;
absValue /= (1.0 - deadZone);
absValue = (float) MathHelper.clamp(absValue / this.config.getAxisMaxValue(axis), 0.f, 1.f);
if (client.currentScreen == null) { if (client.currentScreen == null) {
// Handles the look direction. // Handles the look direction.
absValue -= this.config.getDeadZone(); this.handleLook(client, axis, absValue, state);
this.handleLook(client, axis, (float) (absValue / (1.0 - this.config.getDeadZone())), state);
} else { } else {
boolean allowMouseControl = true; boolean allowMouseControl = true;
if (this.actionGuiCooldown == 0 && this.config.isMovementAxis(axis) && isScreenInteractive(client.currentScreen)) { if (this.actionGuiCooldown == 0 && this.config.isMovementAxis(axis) && isScreenInteractive(client.currentScreen)) {
if (this.config.isForwardButton(axis, false, asButtonState)) { if (this.config.isForwardButton(axis, false, asButtonState)) {
allowMouseControl = this.changeFocus(client.currentScreen, false); allowMouseControl = this.changeFocus(client.currentScreen, NavigationDirection.UP);
} else if (this.config.isBackButton(axis, false, asButtonState)) { } else if (this.config.isBackButton(axis, false, asButtonState)) {
allowMouseControl = this.changeFocus(client.currentScreen, true); allowMouseControl = this.changeFocus(client.currentScreen, NavigationDirection.DOWN);
} else if (this.config.isLeftButton(axis, false, asButtonState)) { } else if (this.config.isLeftButton(axis, false, asButtonState)) {
allowMouseControl = this.handleLeftRight(client.currentScreen, false); allowMouseControl = this.handleLeftRight(client.currentScreen, false);
} else if (this.config.isRightButton(axis, false, asButtonState)) { } else if (this.config.isRightButton(axis, false, asButtonState)) {
@@ -540,8 +540,8 @@ public class LambdaInput
} }
} }
float movementX = 0.0F; float movementX = 0.f;
float movementY = 0.0F; float movementY = 0.f;
if (this.config.isBackButton(axis, false, (value > 0 ? 1 : 2))) { if (this.config.isBackButton(axis, false, (value > 0 ? 1 : 2))) {
movementY = absValue; movementY = absValue;
@@ -554,7 +554,7 @@ public class LambdaInput
} }
if (client.currentScreen != null && allowMouseControl) { if (client.currentScreen != null && allowMouseControl) {
boolean moving = Math.abs(movementY) >= deadZone || Math.abs(movementX) >= deadZone; boolean moving = movementY != 0 || movementX != 0;
if (moving) { if (moving) {
/* /*
Updates the target mouse position when the initial movement stick movement is detected. Updates the target mouse position when the initial movement stick movement is detected.
@@ -564,22 +564,18 @@ public class LambdaInput
INPUT_MANAGER.resetMouseTarget(client); INPUT_MANAGER.resetMouseTarget(client);
} }
if (Math.abs(movementX) >= deadZone) this.mouseSpeedX = movementX;
this.mouseSpeedX = movementX; this.mouseSpeedY = movementY;
else
this.mouseSpeedX = 0.F;
if (Math.abs(movementY) >= deadZone)
this.mouseSpeedY = movementY;
else
this.mouseSpeedY = 0.F;
} else { } else {
this.mouseSpeedX = 0.F; this.mouseSpeedX = 0.f;
this.mouseSpeedY = 0.F; this.mouseSpeedY = 0.f;
} }
if (Math.abs(this.mouseSpeedX) >= .05F || Math.abs(this.mouseSpeedY) >= .05F) { if (Math.abs(this.mouseSpeedX) >= .05f || Math.abs(this.mouseSpeedY) >= .05f) {
InputManager.queueMoveMousePosition(this.mouseSpeedX * this.config.getMouseSpeed(), this.mouseSpeedY * this.config.getMouseSpeed()); InputManager.queueMoveMousePosition(
this.mouseSpeedX * this.config.getMouseSpeed(),
this.mouseSpeedY * this.config.getMouseSpeed()
);
} }
this.moveMouseToClosestSlot(client, client.currentScreen); this.moveMouseToClosestSlot(client, client.currentScreen);
@@ -590,29 +586,33 @@ public class LambdaInput
} }
} }
private boolean handleAButton(@NotNull Screen screen, @NotNull Element focused) private boolean handleAButton(@NotNull Screen screen, @NotNull Element focused) {
{ if (focused instanceof PressableWidget widget) {
if (focused instanceof AbstractPressableButtonWidget) {
AbstractPressableButtonWidget widget = (AbstractPressableButtonWidget) focused;
widget.playDownSound(MinecraftClient.getInstance().getSoundManager()); widget.playDownSound(MinecraftClient.getInstance().getSoundManager());
widget.onPress(); widget.onPress();
return true; return true;
} else if (focused instanceof SpruceLabelWidget) { } else if (focused instanceof AbstractSprucePressableButtonWidget widget) {
((SpruceLabelWidget) focused).onPress(); widget.playDownSound();
widget.onPress();
return true; return true;
} else if (focused instanceof WorldListWidget) { } else if (focused instanceof SpruceLabelWidget labelWidget) {
WorldListWidget list = (WorldListWidget) focused; labelWidget.onPress();
list.method_20159().ifPresent(WorldListWidget.Entry::play);
return true; return true;
} else if (focused instanceof MultiplayerServerListWidget) { } else if (focused instanceof WorldListWidget list) {
MultiplayerServerListWidget list = (MultiplayerServerListWidget) focused; list.getSelectedAsOptional().ifPresent(WorldListWidget.Entry::play);
MultiplayerServerListWidget.Entry entry = list.getSelected(); return true;
} else if (focused instanceof MultiplayerServerListWidget list) {
var entry = list.getSelectedOrNull();
if (entry instanceof MultiplayerServerListWidget.LanServerEntry || entry instanceof MultiplayerServerListWidget.ServerEntry) { if (entry instanceof MultiplayerServerListWidget.LanServerEntry || entry instanceof MultiplayerServerListWidget.ServerEntry) {
((MultiplayerScreen) screen).select(entry); ((MultiplayerScreen) screen).select(entry);
((MultiplayerScreen) screen).connect(); ((MultiplayerScreen) screen).connect();
} }
} else if (focused instanceof ParentElement) { } else if (focused instanceof SpruceParentWidget) {
Element childFocused = ((ParentElement) focused).getFocused(); var childFocused = ((SpruceParentWidget<?>) focused).getFocused();
if (childFocused != null)
return this.handleAButton(screen, childFocused);
} else if (focused instanceof ParentElement widget) {
var childFocused = widget.getFocused();
if (childFocused != null) if (childFocused != null)
return this.handleAButton(screen, childFocused); return this.handleAButton(screen, childFocused);
} }
@@ -622,31 +622,37 @@ public class LambdaInput
/** /**
* Handles the left and right buttons. * Handles the left and right buttons.
* *
* @param screen The current screen. * @param screen the current screen
* @param right True if the right button is pressed, else false. * @param right true if the right button is pressed, else false
*/ */
private boolean handleLeftRight(@NotNull Screen screen, boolean right) private boolean handleLeftRight(@NotNull Screen screen, boolean right) {
{ if (screen instanceof SpruceScreen spruceScreen) {
Element focused = screen.getFocused(); spruceScreen.onNavigation(right ? NavigationDirection.RIGHT : NavigationDirection.LEFT, false);
this.actionGuiCooldown = 5;
return false;
}
var focused = screen.getFocused();
if (focused != null) if (focused != null)
if (this.handleRightLeftElement(focused, right)) if (this.handleRightLeftElement(focused, right))
return this.changeFocus(screen, right); return this.changeFocus(screen, right ? NavigationDirection.RIGHT : NavigationDirection.LEFT);
return true; return true;
} }
private boolean handleRightLeftElement(@NotNull Element element, boolean right) private boolean handleRightLeftElement(@NotNull Element element, boolean right) {
{ if (element instanceof SpruceElement spruceElement) {
if (element instanceof SliderWidget) { if (spruceElement.requiresCursor())
SliderWidget slider = (SliderWidget) element; return true;
return !spruceElement.onNavigation(right ? NavigationDirection.RIGHT : NavigationDirection.LEFT, false);
}
if (element instanceof SliderWidget slider) {
slider.keyPressed(right ? 262 : 263, 0, 0); slider.keyPressed(right ? 262 : 263, 0, 0);
this.actionGuiCooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks. this.actionGuiCooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
return false; return false;
} else if (element instanceof AlwaysSelectedEntryListWidget) { } else if (element instanceof AlwaysSelectedEntryListWidget) {
((EntryListWidgetAccessor) element).lambdacontrols_moveSelection(right ? EntryListWidget.MoveDirection.UP : EntryListWidget.MoveDirection.DOWN); ((EntryListWidgetAccessor) element).lambdacontrols$moveSelection(right ? EntryListWidget.MoveDirection.UP : EntryListWidget.MoveDirection.DOWN);
return false; return false;
} else if (element instanceof ParentElement) { } else if (element instanceof ParentElement entryList) {
ParentElement entryList = (ParentElement) element; var focused = entryList.getFocused();
Element focused = entryList.getFocused();
if (focused == null) if (focused == null)
return true; return true;
return this.handleRightLeftElement(focused, right); return this.handleRightLeftElement(focused, right);
@@ -657,13 +663,12 @@ public class LambdaInput
/** /**
* Handles the look direction input. * Handles the look direction input.
* *
* @param client The client instance. * @param client the client instance
* @param axis The axis to change. * @param axis the axis to change
* @param value The value of the look. * @param value the value of the look
* @param state The state. * @param state the state
*/ */
public void handleLook(@NotNull MinecraftClient client, int axis, float value, int state) public void handleLook(@NotNull MinecraftClient client, int axis, float value, int state) {
{
// Handles the look direction. // Handles the look direction.
if (client.player != null) { if (client.player != null) {
double powValue = Math.pow(value, 2.0); double powValue = Math.pow(value, 2.0);
@@ -684,10 +689,15 @@ public class LambdaInput
} }
} }
private boolean changeFocus(@NotNull Screen screen, boolean down) private boolean changeFocus(@NotNull Screen screen, NavigationDirection direction) {
{ if (screen instanceof SpruceScreen spruceScreen) {
if (!screen.changeFocus(down)) { if (spruceScreen.onNavigation(direction, false)) {
if (screen.changeFocus(down)) { this.actionGuiCooldown = 5;
}
return false;
}
if (!screen.changeFocus(direction.isLookingForward())) {
if (screen.changeFocus(direction.isLookingForward())) {
this.actionGuiCooldown = 5; this.actionGuiCooldown = 5;
return false; return false;
} }
@@ -698,18 +708,17 @@ public class LambdaInput
} }
} }
public static boolean isScreenInteractive(@NotNull Screen screen) public static boolean isScreenInteractive(@NotNull Screen screen) {
{ return !(screen instanceof AdvancementsScreen || screen instanceof HandledScreen || screen instanceof PackScreen
return !(screen instanceof AdvancementsScreen || screen instanceof HandledScreen || screen instanceof PackScreen || LambdaControlsCompat.requireMouseOnScreen(screen)); || (screen instanceof SpruceScreen && ((SpruceScreen) screen).requiresCursor())
|| LambdaControlsCompat.requireMouseOnScreen(screen));
} }
// Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686. // Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686.
private void moveMouseToClosestSlot(@NotNull MinecraftClient client, @Nullable Screen screen) private void moveMouseToClosestSlot(@NotNull MinecraftClient client, @Nullable Screen screen) {
{
// Makes the mouse attracted to slots. This helps with selecting items when using a controller. // Makes the mouse attracted to slots. This helps with selecting items when using a controller.
if (screen instanceof HandledScreen) { if (screen instanceof HandledScreen inventoryScreen) {
HandledScreen inventoryScreen = (HandledScreen) screen; var accessor = (HandledScreenAccessor) inventoryScreen;
HandledScreenAccessor accessor = (HandledScreenAccessor) inventoryScreen;
int guiLeft = accessor.getX(); int guiLeft = accessor.getX();
int guiTop = accessor.getY(); int guiTop = accessor.getY();
int mouseX = (int) (targetMouseX * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()); int mouseX = (int) (targetMouseX * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
@@ -728,8 +737,8 @@ public class LambdaInput
.min(Comparator.comparingDouble(p -> p.value)); .min(Comparator.comparingDouble(p -> p.value));
if (closestSlot.isPresent()) { if (closestSlot.isPresent()) {
Slot slot = closestSlot.get().key; var slot = closestSlot.get().key;
if (slot.hasStack() || !client.player.inventory.getMainHandStack().isEmpty()) { if (slot.hasStack() || !client.player.getInventory().getMainHandStack().isEmpty()) {
int slotCenterXScaled = guiLeft + slot.x + 8; int slotCenterXScaled = guiLeft + slot.x + 8;
int slotCenterYScaled = guiTop + slot.y + 8; int slotCenterYScaled = guiTop + slot.y + 8;
int slotCenterX = (int) (slotCenterXScaled / ((double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth())); int slotCenterX = (int) (slotCenterXScaled / ((double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()));

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,9 +7,9 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package dev.lambdaurora.lambdacontrols.client;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature; import dev.lambdaurora.lambdacontrols.LambdaControlsFeature;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.FluidBlock; import net.minecraft.block.FluidBlock;
@@ -30,17 +30,15 @@ import org.jetbrains.annotations.Nullable;
/** /**
* Represents the reach-around API of LambdaControls. * Represents the reach-around API of LambdaControls.
* *
* @version 1.5.0 * @version 1.7.0
* @since 1.3.2 * @since 1.3.2
*/ */
public class LambdaReacharound public class LambdaReacharound {
{ private BlockHitResult lastReacharoundResult = null;
private BlockHitResult lastReacharoundResult = null; private boolean lastReacharoundVertical = false;
private boolean lastReacharoundVertical = false; private boolean onSlab = false;
private boolean onSlab = false;
public void tick(@NotNull MinecraftClient client) public void tick(@NotNull MinecraftClient client) {
{
this.lastReacharoundResult = this.tryVerticalReachAround(client); this.lastReacharoundResult = this.tryVerticalReachAround(client);
if (this.lastReacharoundResult == null) { if (this.lastReacharoundResult == null) {
this.lastReacharoundResult = this.tryHorizontalReachAround(client); this.lastReacharoundResult = this.tryHorizontalReachAround(client);
@@ -51,58 +49,53 @@ public class LambdaReacharound
/** /**
* Returns the last reach around result. * Returns the last reach around result.
* *
* @return The last reach around result. * @return the last reach around result
*/ */
public @Nullable BlockHitResult getLastReacharoundResult() public @Nullable BlockHitResult getLastReacharoundResult() {
{
return this.lastReacharoundResult; return this.lastReacharoundResult;
} }
/** /**
* Returns whether the last reach around is vertical. * Returns whether the last reach around is vertical.
* *
* @return True if the reach around is vertical. * @return {@code true} if the reach around is vertical
*/ */
public boolean isLastReacharoundVertical() public boolean isLastReacharoundVertical() {
{
return this.lastReacharoundVertical; return this.lastReacharoundVertical;
} }
/** /**
* Returns whether reacharound is available or not. * Returns whether reacharound is available or not.
* *
* @return True if reacharound is available, else false. * @return {@code true} if reacharound is available, else {@code false}
*/ */
public boolean isReacharoundAvailable() public boolean isReacharoundAvailable() {
{
return LambdaControlsFeature.HORIZONTAL_REACHAROUND.isAvailable() || LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable(); return LambdaControlsFeature.HORIZONTAL_REACHAROUND.isAvailable() || LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable();
} }
private float getPlayerRange(@NotNull MinecraftClient client) private float getPlayerRange(@NotNull MinecraftClient client) {
{
return client.interactionManager != null ? client.interactionManager.getReachDistance() : 0.f; return client.interactionManager != null ? client.interactionManager.getReachDistance() : 0.f;
} }
/** /**
* Returns a nullable block hit result if vertical reach-around is possible. * Returns a nullable block hit result if vertical reach-around is possible.
* *
* @param client The client instance. * @param client the client instance
* @return A block hit result if vertical reach-around is possible, else null. * @return a block hit result if vertical reach-around is possible, else {@code null}
*/ */
public @Nullable BlockHitResult tryVerticalReachAround(@NotNull MinecraftClient client) public @Nullable BlockHitResult tryVerticalReachAround(@NotNull MinecraftClient client) {
{
if (!LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable()) if (!LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable())
return null; return null;
if (client.player == null || client.world == null || client.crosshairTarget == null || client.crosshairTarget.getType() != HitResult.Type.MISS if (client.player == null || client.world == null || client.crosshairTarget == null || client.crosshairTarget.getType() != HitResult.Type.MISS
|| !client.player.isOnGround() || client.player.pitch < 80.0F || !client.player.isOnGround() || client.player.getPitch(0.f) < 80.0F
|| client.player.isRiding()) || client.player.isRiding())
return null; return null;
Vec3d pos = client.player.getCameraPosVec(1.0F); Vec3d pos = client.player.getCameraPosVec(1.0F);
Vec3d rotationVec = client.player.getRotationVec(1.0F); Vec3d rotationVec = client.player.getRotationVec(1.0F);
float range = getPlayerRange(client); float range = getPlayerRange(client);
Vec3d rayVec = pos.add(rotationVec.x * range, rotationVec.y * range, rotationVec.z * range).add(0, 0.75, 0); var rayVec = pos.add(rotationVec.x * range, rotationVec.y * range, rotationVec.z * range).add(0, 0.75, 0);
BlockHitResult result = client.world.raycast(new RaycastContext(pos, rayVec, RaycastContext.ShapeType.OUTLINE, RaycastContext.FluidHandling.NONE, client.player)); var result = client.world.raycast(new RaycastContext(pos, rayVec, RaycastContext.ShapeType.OUTLINE, RaycastContext.FluidHandling.NONE, client.player));
if (result.getType() == HitResult.Type.BLOCK) { if (result.getType() == HitResult.Type.BLOCK) {
BlockPos blockPos = result.getBlockPos().down(); BlockPos blockPos = result.getBlockPos().down();
@@ -119,34 +112,34 @@ public class LambdaReacharound
/** /**
* Returns a nullable block hit result if horizontal reach-around is possible. * Returns a nullable block hit result if horizontal reach-around is possible.
* *
* @param client The client instance. * @param client the client instance
* @return A block hit result if horizontal reach-around is possible. * @return a block hit result if horizontal reach-around is possible
*/ */
public @Nullable BlockHitResult tryHorizontalReachAround(@NotNull MinecraftClient client) public @Nullable BlockHitResult tryHorizontalReachAround(@NotNull MinecraftClient client) {
{
if (!LambdaControlsFeature.HORIZONTAL_REACHAROUND.isAvailable()) if (!LambdaControlsFeature.HORIZONTAL_REACHAROUND.isAvailable())
return null; return null;
if (client.player != null && client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.MISS && client.player.isOnGround() && client.player.pitch > 35.0F) { if (client.player != null && client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.MISS
&& client.player.isOnGround() && client.player.getPitch(0.f) > 35.f) {
if (client.player.isRiding()) if (client.player.isRiding())
return null; return null;
BlockPos playerPos = client.player.getBlockPos().down(); var playerPos = client.player.getBlockPos().down();
if (client.player.getY() - playerPos.getY() - 1.0 >= 0.25) { if (client.player.getY() - playerPos.getY() - 1.0 >= 0.25) {
playerPos = playerPos.up(); playerPos = playerPos.up();
this.onSlab = true; this.onSlab = true;
} else { } else {
this.onSlab = false; this.onSlab = false;
} }
BlockPos targetPos = new BlockPos(client.crosshairTarget.getPos()).subtract(playerPos); var targetPos = new BlockPos(client.crosshairTarget.getPos()).subtract(playerPos);
BlockPos vector = new BlockPos(MathHelper.clamp(targetPos.getX(), -1, 1), 0, MathHelper.clamp(targetPos.getZ(), -1, 1)); var vector = new BlockPos.Mutable(MathHelper.clamp(targetPos.getX(), -1, 1), 0, MathHelper.clamp(targetPos.getZ(), -1, 1));
BlockPos blockPos = playerPos.add(vector); var blockPos = playerPos.add(vector);
Direction direction = client.player.getHorizontalFacing(); var direction = client.player.getHorizontalFacing();
BlockState state = client.world.getBlockState(blockPos); var state = client.world.getBlockState(blockPos);
if (!state.isAir()) if (!state.isAir())
return null; return null;
BlockState adjacentBlockState = client.world.getBlockState(blockPos.offset(direction.getOpposite())); var adjacentBlockState = client.world.getBlockState(blockPos.offset(direction.getOpposite()));
if (adjacentBlockState.isAir() || adjacentBlockState.getBlock() instanceof FluidBlock || (vector.getX() == 0 && vector.getZ() == 0)) { if (adjacentBlockState.isAir() || adjacentBlockState.getBlock() instanceof FluidBlock || (vector.getX() == 0 && vector.getZ() == 0)) {
return null; return null;
} }
@@ -156,15 +149,13 @@ public class LambdaReacharound
return null; return null;
} }
public @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @Nullable ItemStack stack) public @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @Nullable ItemStack stack) {
{
if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem)) if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem))
return result; return result;
return withSideForReacharound(result, Block.getBlockFromItem(stack.getItem())); return withSideForReacharound(result, Block.getBlockFromItem(stack.getItem()));
} }
public @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @NotNull Block block) public @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @NotNull Block block) {
{
if (block instanceof SlabBlock) { if (block instanceof SlabBlock) {
if (this.onSlab) result = result.withSide(Direction.UP); if (this.onSlab) result = result.withSide(Direction.UP);
else result = result.withSide(Direction.DOWN); else result = result.withSide(Direction.DOWN);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package dev.lambdaurora.lambdacontrols.client;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
@@ -20,21 +20,19 @@ import java.util.Optional;
/** /**
* Represents the virtual mouse skins. * Represents the virtual mouse skins.
* *
* @version 1.4.0 * @version 1.7.0
* @since 1.2.0 * @since 1.2.0
*/ */
public enum VirtualMouseSkin implements Nameable public enum VirtualMouseSkin implements Nameable {
{
DEFAULT_LIGHT("default_light"), DEFAULT_LIGHT("default_light"),
DEFAULT_DARK("default_dark"), DEFAULT_DARK("default_dark"),
SECOND_LIGHT("second_light"), SECOND_LIGHT("second_light"),
SECOND_DARK("second_dark"); SECOND_DARK("second_dark");
private final String name; private final String name;
private final Text text; private final Text text;
VirtualMouseSkin(String name) VirtualMouseSkin(String name) {
{
this.name = name; this.name = name;
this.text = new TranslatableText(this.getTranslationKey()); this.text = new TranslatableText(this.getTranslationKey());
} }
@@ -42,11 +40,10 @@ public enum VirtualMouseSkin implements Nameable
/** /**
* Returns the next virtual mouse skin available. * Returns the next virtual mouse skin available.
* *
* @return The next available virtual mouse skin. * @return the next available virtual mouse skin
*/ */
public @NotNull VirtualMouseSkin next() public @NotNull VirtualMouseSkin next() {
{ var v = values();
VirtualMouseSkin[] v = values();
if (v.length == this.ordinal() + 1) if (v.length == this.ordinal() + 1)
return v[0]; return v[0];
return v[this.ordinal() + 1]; return v[this.ordinal() + 1];
@@ -55,37 +52,33 @@ public enum VirtualMouseSkin implements Nameable
/** /**
* Returns the translation key of this virtual mouse skin. * Returns the translation key of this virtual mouse skin.
* *
* @return The virtual mouse skin's translation key. * @return the virtual mouse skin's translation key
*/ */
public @NotNull String getTranslationKey() public @NotNull String getTranslationKey() {
{
return "lambdacontrols.virtual_mouse.skin." + this.getName(); return "lambdacontrols.virtual_mouse.skin." + this.getName();
} }
/** /**
* Gets the translated text of this virtual mouse skin. * Gets the translated text of this virtual mouse skin.
* *
* @return The translated text of this virtual mouse skin. * @return the translated text of this virtual mouse skin
*/ */
public @NotNull Text getTranslatedText() public @NotNull Text getTranslatedText() {
{
return this.text; return this.text;
} }
@Override @Override
public @NotNull String getName() public @NotNull String getName() {
{
return this.name; return this.name;
} }
/** /**
* Gets the virtual mouse skin from its identifier. * Gets the virtual mouse skin from its identifier.
* *
* @param id The identifier of the virtual mouse skin. * @param id the identifier of the virtual mouse skin
* @return The virtual mouse skin if found, else empty. * @return the virtual mouse skin if found, else empty
*/ */
public static @NotNull Optional<VirtualMouseSkin> byId(@NotNull String id) public static @NotNull Optional<VirtualMouseSkin> byId(@NotNull String id) {
{
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,15 +7,14 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat; package dev.lambdaurora.lambdacontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -23,88 +22,85 @@ import org.jetbrains.annotations.Nullable;
* Represents a compatibility handler for a mod. * Represents a compatibility handler for a mod.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.5.0 * @version 1.7.0
* @since 1.1.0 * @since 1.1.0
*/ */
public interface CompatHandler public interface CompatHandler {
{
/** /**
* Handles compatibility of a mod. * Handles compatibility of a mod.
* *
* @param mod This mod instance. * @param mod this mod instance
*/ */
void handle(@NotNull LambdaControlsClient mod); void handle(@NotNull LambdaControlsClient mod);
/** /**
* Returns whether the mouse is required on the specified screen. * Returns whether the mouse is required on the specified screen.
* *
* @param screen The screen. * @param screen the screen
* @return True if the mouse is required on the specified screen, else false. * @return true if the mouse is required on the specified screen, else false
*/ */
default boolean requireMouseOnScreen(Screen screen) default boolean requireMouseOnScreen(Screen screen) {
{
return false; return false;
} }
/** /**
* Returns a slot at the specified location if possible. * Returns a slot at the specified location if possible.
* *
* @param screen The screen. * @param screen the screen
* @param mouseX The mouse X-coordinate. * @param mouseX the mouse X-coordinate
* @param mouseY The mouse Y-coordinate. * @param mouseY the mouse Y-coordinate
* @return A slot if present, else null. * @return a slot if present, else null
* @since 1.5.0 * @since 1.5.0
*/ */
default @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) default @Nullable CompatHandler.SlotPos getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) {
{
return null; return null;
} }
/** /**
* Returns whether the current slot is a creative slot or not. * Returns whether the current slot is a creative slot or not.
* *
* @param screen The screen. * @param screen the screen
* @param slot The slot to check. * @param slot the slot to check
* @return True if the slot is a creative slot, else false. * @return true if the slot is a creative slot, else false
*/ */
default boolean isCreativeSlot(@NotNull HandledScreen screen, @NotNull Slot slot) default boolean isCreativeSlot(@NotNull HandledScreen screen, @NotNull Slot slot) {
{
return false; return false;
} }
/** /**
* Returns a custom translation key to make custom attack action strings on the HUD. * Returns a custom translation key to make custom attack action strings on the HUD.
* *
* @param client The client instance. * @param client the client instance
* @param placeResult The last place block result. * @param placeResult the last place block result
* @return Null if untouched, else a translation key. * @return null if untouched, else a translation key
*/ */
default String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) default String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) {
{
return null; return null;
} }
/** /**
* Returns a custom translation key to make custom use action strings on the HUD. * Returns a custom translation key to make custom use action strings on the HUD.
* *
* @param client The client instance. * @param client the client instance
* @param placeResult The last place block result. * @param placeResult the last place block result
* @return Null if untouched, else a translation key. * @return null if untouched, else a translation key
*/ */
default String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) default String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) {
{
return null; return null;
} }
/** /**
* Handles the menu back button. * Handles the menu back button.
* *
* @param client The client instance. * @param client the client instance
* @param screen The screen. * @param screen the screen
* @return True if the handle was fired and succeed, else false. * @return true if the handle was fired and succeed, else false
*/ */
default boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) default boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) {
{
return false; return false;
} }
record SlotPos(int x, int y) {
public static final SlotPos INVALID_SLOT = new SlotPos(-1, -1);
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,9 +7,9 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat; package dev.lambdaurora.lambdacontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import org.aperlambda.lambdacommon.utils.LambdaReflection; import org.aperlambda.lambdacommon.utils.LambdaReflection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -25,20 +25,17 @@ import java.util.Optional;
* @version 1.3.2 * @version 1.3.2
* @since 1.3.2 * @since 1.3.2
*/ */
public class HQMCompat implements CompatHandler public class HQMCompat implements CompatHandler {
{ public static final String GUI_BASE_CLASS_PATH = "hardcorequesting.client.interfaces.GuiBase";
public static final String GUI_BASE_CLASS_PATH = "hardcorequesting.client.interfaces.GuiBase"; private Optional<Class<?>> guiBaseClass;
private Optional<Class<?>> guiBaseClass;
@Override @Override
public void handle(@NotNull LambdaControlsClient mod) public void handle(@NotNull LambdaControlsClient mod) {
{
this.guiBaseClass = LambdaReflection.getClass(GUI_BASE_CLASS_PATH); this.guiBaseClass = LambdaReflection.getClass(GUI_BASE_CLASS_PATH);
} }
@Override @Override
public boolean requireMouseOnScreen(Screen screen) public boolean requireMouseOnScreen(Screen screen) {
{
return this.guiBaseClass.map(clazz -> clazz.isInstance(screen)).orElse(false); return this.guiBaseClass.map(clazz -> clazz.isInstance(screen)).orElse(false);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,17 +7,15 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat; package dev.lambdaurora.lambdacontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.InputManager; import dev.lambdaurora.lambdacontrols.client.controller.InputManager;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.screen.slot.Slot;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import org.aperlambda.lambdacommon.utils.LambdaReflection; import org.aperlambda.lambdacommon.utils.LambdaReflection;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -32,25 +30,23 @@ import java.util.stream.Stream;
* @version 1.5.0 * @version 1.5.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class LambdaControlsCompat public class LambdaControlsCompat {
{
private static final List<CompatHandler> HANDLERS = new ArrayList<>(); private static final List<CompatHandler> HANDLERS = new ArrayList<>();
/** /**
* Initializes compatibility with other mods if needed. * Initializes compatibility with other mods if needed.
* *
* @param mod The mod instance. * @param mod the mod instance
*/ */
public static void init(@NotNull LambdaControlsClient mod) public static void init(@NotNull LambdaControlsClient mod) {
{ /*if (FabricLoader.getInstance().isModLoaded("okzoomer")) {
if (FabricLoader.getInstance().isModLoaded("okzoomer")) {
mod.log("Adding okzoomer compatibility..."); mod.log("Adding okzoomer compatibility...");
HANDLERS.add(new OkZoomerCompat()); HANDLERS.add(new OkZoomerCompat());
} }
if (isReiPresent()) { if (isReiPresent()) {
mod.log("Adding REI compatiblity..."); mod.log("Adding REI compatiblity...");
HANDLERS.add(new ReiCompat()); HANDLERS.add(new ReiCompat());
} }*/
if (FabricLoader.getInstance().isModLoaded("hardcorequesting") && LambdaReflection.doesClassExist(HQMCompat.GUI_BASE_CLASS_PATH)) { if (FabricLoader.getInstance().isModLoaded("hardcorequesting") && LambdaReflection.doesClassExist(HQMCompat.GUI_BASE_CLASS_PATH)) {
mod.log("Adding HQM compatibility..."); mod.log("Adding HQM compatibility...");
HANDLERS.add(new HQMCompat()); HANDLERS.add(new HQMCompat());
@@ -62,46 +58,42 @@ public class LambdaControlsCompat
/** /**
* Registers a new compatibility handler. * Registers a new compatibility handler.
* *
* @param handler The compatibility handler to register. * @param handler the compatibility handler to register
*/ */
public static void registerCompatHandler(@NotNull CompatHandler handler) public static void registerCompatHandler(@NotNull CompatHandler handler) {
{
HANDLERS.add(handler); HANDLERS.add(handler);
} }
/** /**
* Streams through compatibility handlers. * Streams through compatibility handlers.
* *
* @return A stream of compatibility handlers. * @return a stream of compatibility handlers
*/ */
public static Stream<CompatHandler> streamCompatHandlers() public static Stream<CompatHandler> streamCompatHandlers() {
{
return HANDLERS.stream(); return HANDLERS.stream();
} }
/** /**
* Returns whether the mouse is required on the specified screen. * Returns whether the mouse is required on the specified screen.
* *
* @param screen The screen. * @param screen the screen
* @return True if the mouse is requried on the specified screen, else false. * @return true if the mouse is requried on the specified screen, else false
*/ */
public static boolean requireMouseOnScreen(Screen screen) public static boolean requireMouseOnScreen(Screen screen) {
{
return HANDLERS.stream().anyMatch(handler -> handler.requireMouseOnScreen(screen)); return HANDLERS.stream().anyMatch(handler -> handler.requireMouseOnScreen(screen));
} }
/** /**
* Returns a slot at the specified location if possible. * Returns a slot at the specified location if possible.
* *
* @param screen The screen. * @param screen the screen
* @param mouseX The mouse X-coordinate. * @param mouseX the mouse X-coordinate
* @param mouseY The mouse Y-coordinate. * @param mouseY the mouse Y-coordinate
* @return A slot if present, else null. * @return a slot if present, else null
*/ */
public static @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) public static @Nullable CompatHandler.SlotPos getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) {
{ for (var handler : HANDLERS) {
for (CompatHandler handler : HANDLERS) { var slot = handler.getSlotAt(screen, mouseX, mouseY);
Pair<Integer, Integer> slot = handler.getSlotAt(screen, mouseX, mouseY);
if (slot != null) if (slot != null)
return slot; return slot;
} }
@@ -111,12 +103,11 @@ public class LambdaControlsCompat
/** /**
* Returns a custom translation key to make custom attack action strings on the HUD. * Returns a custom translation key to make custom attack action strings on the HUD.
* *
* @param client The client instance. * @param client the client instance
* @param placeResult The last place block result. * @param placeResult the last place block result
* @return Null if untouched, else a translation key. * @return null if untouched, else a translation key
*/ */
public static String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) public static String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) {
{
for (CompatHandler handler : HANDLERS) { for (CompatHandler handler : HANDLERS) {
String action = handler.getAttackActionAt(client, placeResult); String action = handler.getAttackActionAt(client, placeResult);
if (action != null) { if (action != null) {
@@ -129,12 +120,11 @@ public class LambdaControlsCompat
/** /**
* Returns a custom translation key to make custom use action strings on the HUD. * Returns a custom translation key to make custom use action strings on the HUD.
* *
* @param client The client instance. * @param client the client instance
* @param placeResult The last place block result. * @param placeResult the last place block result
* @return Null if untouched, else a translation key. * @return null if untouched, else a translation key
*/ */
public static String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) public static String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) {
{
for (CompatHandler handler : HANDLERS) { for (CompatHandler handler : HANDLERS) {
String action = handler.getUseActionAt(client, placeResult); String action = handler.getUseActionAt(client, placeResult);
if (action != null) { if (action != null) {
@@ -147,12 +137,11 @@ public class LambdaControlsCompat
/** /**
* Handles the menu back button. * Handles the menu back button.
* *
* @param client The client instance. * @param client the client instance
* @param screen The screen. * @param screen the screen
* @return True if the handle was fired and succeed, else false. * @return true if the handle was fired and succeed, else false
*/ */
public static boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) public static boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) {
{
for (CompatHandler handler : HANDLERS) { for (CompatHandler handler : HANDLERS) {
if (handler.handleMenuBack(client, screen)) if (handler.handleMenuBack(client, screen))
return true; return true;
@@ -163,10 +152,9 @@ public class LambdaControlsCompat
/** /**
* Returns whether Roughly Enough Items is present. * Returns whether Roughly Enough Items is present.
* *
* @return True if Roughly Enough Items is present, else false. * @return true if Roughly Enough Items is present, else false
*/ */
public static boolean isReiPresent() public static boolean isReiPresent() {
{
return FabricLoader.getInstance().isModLoaded("roughlyenoughitems"); return FabricLoader.getInstance().isModLoaded("roughlyenoughitems");
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat; package dev.lambdaurora.lambdacontrols.client.compat;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
@@ -25,58 +25,48 @@ import java.util.Set;
* @version 1.5.0 * @version 1.5.0
* @since 1.2.0 * @since 1.2.0
*/ */
public class LambdaControlsMixinPlugin implements IMixinConfigPlugin public class LambdaControlsMixinPlugin implements IMixinConfigPlugin {
{
private final HashMap<String, Boolean> conditionalMixins = new HashMap<>(); private final HashMap<String, Boolean> conditionalMixins = new HashMap<>();
public LambdaControlsMixinPlugin() public LambdaControlsMixinPlugin() {
{
this.putConditionalMixin("EntryListWidgetAccessor", LambdaControlsCompat.isReiPresent()); this.putConditionalMixin("EntryListWidgetAccessor", LambdaControlsCompat.isReiPresent());
this.putConditionalMixin("EntryWidgetAccessor", LambdaControlsCompat.isReiPresent()); this.putConditionalMixin("EntryWidgetAccessor", LambdaControlsCompat.isReiPresent());
this.putConditionalMixin("RecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent()); this.putConditionalMixin("RecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent());
this.putConditionalMixin("VillagerRecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent()); this.putConditionalMixin("VillagerRecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent());
} }
private void putConditionalMixin(@NotNull String path, boolean condition) private void putConditionalMixin(@NotNull String path, boolean condition) {
{
this.conditionalMixins.put("me.lambdaurora.lambdacontrols.client.compat.mixin." + path, condition); this.conditionalMixins.put("me.lambdaurora.lambdacontrols.client.compat.mixin." + path, condition);
} }
@Override @Override
public void onLoad(String mixinPackage) public void onLoad(String mixinPackage) {
{
} }
@Override @Override
public String getRefMapperConfig() public String getRefMapperConfig() {
{
return null; return null;
} }
@Override @Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
{
return this.conditionalMixins.getOrDefault(mixinClassName, Boolean.TRUE); return this.conditionalMixins.getOrDefault(mixinClassName, Boolean.TRUE);
} }
@Override @Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
{
} }
@Override @Override
public List<String> getMixins() public List<String> getMixins() {
{
return null; return null;
} }
@Override @Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
{
} }
@Override @Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
{
} }
} }

View File

@@ -0,0 +1,56 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.compat;
import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import org.jetbrains.annotations.NotNull;
/**
* Represents a compatibility handler for OkZoomer.
*
* @author LambdAurora
* @version 1.4.3
* @since 1.1.0
*/
public class OkZoomerCompat implements CompatHandler {
@Override
public void handle(@NotNull LambdaControlsClient mod) {
/*new ButtonBinding.Builder("zoom")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW.GLFW_GAMEPAD_BUTTON_X)
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.zoomKey)
.register();
if (ZoomKeybinds.areExtraKeybindsEnabled()) {
new ButtonBinding.Builder("zoom_in")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true))
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.increaseZoomKey)
.register();
new ButtonBinding.Builder("zoom_out")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true))
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.decreaseZoomKey)
.register();
new ButtonBinding.Builder("zoom_reset")
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(ZoomKeybinds.resetZoomKey)
.register();
}*/
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,57 +7,33 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat; package dev.lambdaurora.lambdacontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.ButtonState; import dev.lambdaurora.lambdacontrols.client.ButtonState;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.compat.mixin.EntryListWidgetAccessor; import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.compat.mixin.EntryWidgetAccessor; import dev.lambdaurora.lambdacontrols.client.controller.InputHandlers;
import me.lambdaurora.lambdacontrols.client.compat.mixin.RecipeViewingScreenAccessor; import dev.lambdaurora.lambdacontrols.client.controller.PressAction;
import me.lambdaurora.lambdacontrols.client.compat.mixin.VillagerRecipeViewingScreenAccessor;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.InputHandlers;
import me.lambdaurora.lambdacontrols.client.controller.PressAction;
import me.shedaniel.rei.api.*;
import me.shedaniel.rei.gui.ContainerScreenOverlay;
import me.shedaniel.rei.gui.PreRecipeViewingScreen;
import me.shedaniel.rei.gui.RecipeViewingScreen;
import me.shedaniel.rei.gui.VillagerRecipeViewingScreen;
import me.shedaniel.rei.gui.widget.EntryListEntryWidget;
import me.shedaniel.rei.gui.widget.EntryListWidget;
import me.shedaniel.rei.gui.widget.EntryWidget;
import me.shedaniel.rei.gui.widget.WidgetWithBounds;
import me.shedaniel.rei.impl.ScreenHelper;
import me.shedaniel.rei.impl.widgets.ButtonWidget;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.aperlambda.lambdacommon.utils.LambdaReflection;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Optional;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
/** /**
* Represents a compatibility handler for REI. * Represents a compatibility handler for REI.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.5.0 * @version 1.7.0
* @since 1.2.0 * @since 1.2.0
*/ */
public class ReiCompat implements CompatHandler public class ReiCompat implements CompatHandler {
{ //private static EntryListWidget ENTRY_LIST_WIDGET;
private static final Pair<Integer, Integer> INVALID_SLOT = new Pair<>(-1, -1);
private static EntryListWidget ENTRY_LIST_WIDGET;
@Override @Override
public void handle(@NotNull LambdaControlsClient mod) public void handle(@NotNull LambdaControlsClient mod) {
{
ButtonBinding.builder(new Identifier("rei", "category_back")) ButtonBinding.builder(new Identifier("rei", "category_back"))
.buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER) .buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.filter((client, binding) -> isViewingScreen(client.currentScreen)) .filter((client, binding) -> isViewingScreen(client.currentScreen))
@@ -114,77 +90,71 @@ public class ReiCompat implements CompatHandler
} }
@Override @Override
public boolean requireMouseOnScreen(Screen screen) public boolean requireMouseOnScreen(Screen screen) {
{ return isViewingScreen(screen) /*|| screen instanceof PreRecipeViewingScreen*/;
return isViewingScreen(screen) || screen instanceof PreRecipeViewingScreen;
} }
@Override @Override
public @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) public @Nullable SlotPos getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) {
{ /*var overlay = ScreenHelper.getOptionalOverlay();
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
if (overlay.isPresent() && overlay.get().isInside(mouseX, mouseY)) { if (overlay.isPresent() && overlay.get().isInside(mouseX, mouseY)) {
EntryListWidget widget = getEntryListWidget(); var widget = getEntryListWidget();
if (widget == null) if (widget == null)
return null; return null;
Pair<Integer, Integer> slot = this.getSlotAt(widget, mouseX, mouseY, false); var slot = this.getSlotAt(widget, mouseX, mouseY, false);
if (slot != null && slot != INVALID_SLOT) if (slot != null && slot != INVALID_SLOT)
return slot; return slot;
} else if (isViewingScreen(screen)) { } else if (isViewingScreen(screen)) {
for (Element element : screen.children()) { for (var element : screen.children()) {
Pair<Integer, Integer> slot = this.getSlotAt(element, mouseX, mouseY, true); var slot = this.getSlotAt(element, mouseX, mouseY, true);
if (slot != null && slot != INVALID_SLOT) if (slot != null && slot != INVALID_SLOT)
return slot; return slot;
} }
} }*/
return null; return null;
} }
private @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Element element, int mouseX, int mouseY, boolean allowEmpty) /*private @Nullable SlotPos getSlotAt(@NotNull Element element, int mouseX, int mouseY, boolean allowEmpty) {
{ if (element instanceof EntryWidget entry) {
if (element instanceof EntryWidget) {
EntryWidget entry = (EntryWidget) element;
if (entry.containsMouse(mouseX, mouseY)) { if (entry.containsMouse(mouseX, mouseY)) {
if (!allowEmpty && entry.entries().isEmpty()) if (!allowEmpty && entry.entries().isEmpty())
return INVALID_SLOT; return INVALID_SLOT;
return Pair.of(entry.getBounds().getX() + 1, entry.getBounds().getY() + 1); return new SlotPos(entry.getBounds().getX() + 1, entry.getBounds().getY() + 1);
} }
} else if (element instanceof EntryListWidget) { } else if (element instanceof EntryListWidget) {
List<EntryListEntryWidget> entries = ((EntryListWidgetAccessor) element).getEntries(); List<EntryListEntryWidget> entries = ((EntryListWidgetAccessor) element).getEntries();
for (EntryListEntryWidget entry : entries) { for (EntryListEntryWidget entry : entries) {
Pair<Integer, Integer> slot = this.getSlotAt(entry, mouseX, mouseY, allowEmpty); var slot = this.getSlotAt(entry, mouseX, mouseY, allowEmpty);
if (slot != null && slot != INVALID_SLOT) if (slot != null && slot != INVALID_SLOT)
return slot; return slot;
} }
} else if (!(element instanceof ButtonWidget) && element instanceof WidgetWithBounds) { } else if (!(element instanceof ButtonWidget) && element instanceof WidgetWithBounds widgetWithBounds) {
for (Element child : ((WidgetWithBounds) element).children()) { for (var child : widgetWithBounds.children()) {
Pair<Integer, Integer> slot = this.getSlotAt(child, mouseX, mouseY, allowEmpty); var slot = this.getSlotAt(child, mouseX, mouseY, allowEmpty);
if (slot != null && slot != INVALID_SLOT) if (slot != null && slot != INVALID_SLOT)
return slot; return slot;
} }
} }
return null; return null;
} }*/
private static boolean isViewingScreen(Screen screen) private static boolean isViewingScreen(Screen screen) {
{ return true;
return screen instanceof RecipeViewingScreen || screen instanceof VillagerRecipeViewingScreen; //return screen instanceof DefaultDisplayViewingScreen || screen instanceof CompositeDisplayViewingScreen;
} }
@Override @Override
public boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) public boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) {
{
if (!isViewingScreen(screen)) if (!isViewingScreen(screen))
return false; return false;
MinecraftClient.getInstance().openScreen(REIHelper.getInstance().getPreviousContainerScreen()); /*MinecraftClient.getInstance().openScreen(REIRuntimeImpl.getInstance().getPreviousContainerScreen());
ScreenHelper.getLastOverlay().init(); ScreenHelper.getLastOverlay().init();*/
return true; return true;
} }
private static EntryListWidget getEntryListWidget() /*private static EntryListWidget getEntryListWidget() {
{
if (ENTRY_LIST_WIDGET == null) { if (ENTRY_LIST_WIDGET == null) {
ENTRY_LIST_WIDGET = LambdaReflection.getFirstFieldOfType(ContainerScreenOverlay.class, EntryListWidget.class) ENTRY_LIST_WIDGET = LambdaReflection.getFirstFieldOfType(ContainerScreenOverlay.class, EntryListWidget.class)
.map(field -> (EntryListWidget) LambdaReflection.getFieldValue(null, field)) .map(field -> (EntryListWidget) LambdaReflection.getFieldValue(null, field))
@@ -193,59 +163,55 @@ public class ReiCompat implements CompatHandler
return ENTRY_LIST_WIDGET; return ENTRY_LIST_WIDGET;
} }
private static @Nullable EntryStack getCurrentStack(@NotNull MinecraftClient client) private static @Nullable EntryStack getCurrentStack(@NotNull MinecraftClient client) {
{
double x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth(); double x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight(); double y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
if (isViewingScreen(client.currentScreen)) { if (isViewingScreen(client.currentScreen)) {
for (Element element : client.currentScreen.children()) { for (var element : client.currentScreen.children()) {
EntryStack stack = getCurrentStack(element, x, y); var stack = getCurrentStack(element, x, y);
if (stack != null) if (stack != null)
return stack; return stack;
} }
} }
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay(); var overlay = ScreenHelper.getOptionalOverlay();
if (!overlay.isPresent()) if (!overlay.isPresent())
return RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen); return RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
EntryListWidget widget = getEntryListWidget(); var widget = getEntryListWidget();
if (widget == null) if (widget == null)
return RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen); return RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
return getCurrentStack(widget, x, y); return getCurrentStack(widget, x, y);
} }
private static @Nullable EntryStack getCurrentStack(@NotNull Element element, double mouseX, double mouseY) private static @Nullable EntryStack getCurrentStack(@NotNull Element element, double mouseX, double mouseY) {
{ if (element instanceof EntryWidget entry) {
if (element instanceof EntryWidget) {
EntryWidget entry = (EntryWidget) element;
if (entry.containsMouse(mouseX, mouseY)) if (entry.containsMouse(mouseX, mouseY))
return ((EntryWidgetAccessor) entry).lambdacontrols_getCurrentEntry(); return ((EntryWidgetAccessor) entry).lambdacontrols_getCurrentEntry();
} else if (element instanceof EntryListWidget) { } else if (element instanceof EntryListWidget) {
List<EntryListEntryWidget> entries = ((EntryListWidgetAccessor) element).getEntries(); var entries = ((EntryListWidgetAccessor) element).getEntries();
for (EntryListEntryWidget entry : entries) { for (EntryListEntryWidget entry : entries) {
if (entry.containsMouse(mouseX, mouseY)) { if (entry.containsMouse(mouseX, mouseY)) {
return ((EntryWidgetAccessor) entry).lambdacontrols_getCurrentEntry(); return ((EntryWidgetAccessor) entry).lambdacontrols_getCurrentEntry();
} }
} }
} else if (!(element instanceof ButtonWidget) && element instanceof WidgetWithBounds) { } else if (!(element instanceof ButtonWidget) && element instanceof WidgetWithBounds widgetWithBounds) {
for (Element child : ((WidgetWithBounds) element).children()) { for (var child : widgetWithBounds.children()) {
EntryStack stack = getCurrentStack(child, mouseX, mouseY); var stack = getCurrentStack(child, mouseX, mouseY);
if (stack != null) if (stack != null)
return stack; return stack;
} }
} }
return null; return null;
} }*/
private static PressAction handleShowRecipeUsage(boolean usage) private static PressAction handleShowRecipeUsage(boolean usage) {
{
return (client, button, value, action) -> { return (client, button, value, action) -> {
if (action.isUnpressed()) if (action.isUnpressed())
return false; return false;
EntryStack stack = RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen); /*EntryStack stack = RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
if (stack == null) { if (stack == null) {
stack = getCurrentStack(client); stack = getCurrentStack(client);
} }
@@ -257,23 +223,22 @@ public class ReiCompat implements CompatHandler
} else { } else {
return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addRecipesFor(stack).setOutputNotice(stack).fillPreferredOpenedCategory()); return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addRecipesFor(stack).setOutputNotice(stack).fillPreferredOpenedCategory());
} }
} }*/
return false; return false;
}; };
} }
private static PressAction handlePage(boolean next) private static PressAction handlePage(boolean next) {
{
return (client, button, value, action) -> { return (client, button, value, action) -> {
if (action == ButtonState.RELEASE) if (action == ButtonState.RELEASE)
return false; return false;
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay(); /*Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
if (!overlay.isPresent()) if (!overlay.isPresent())
return false; return false;
EntryListWidget widget = getEntryListWidget(); var widget = getEntryListWidget();
if (widget == null) if (widget == null)
return false; return false;
@@ -281,7 +246,7 @@ public class ReiCompat implements CompatHandler
widget.nextPage(); widget.nextPage();
else else
widget.previousPage(); widget.previousPage();
widget.updateEntriesPosition(); widget.updateEntriesPosition();*/
return true; return true;
}; };
@@ -293,20 +258,19 @@ public class ReiCompat implements CompatHandler
* @param next True if the action is to switch to the next tab. * @param next True if the action is to switch to the next tab.
* @return The handler. * @return The handler.
*/ */
private static PressAction handleTab(boolean next) private static PressAction handleTab(boolean next) {
{
return (client, button, value, action) -> { return (client, button, value, action) -> {
if (action != ButtonState.RELEASE) if (action != ButtonState.RELEASE)
return false; return false;
if (client.currentScreen instanceof RecipeViewingScreen) { /*if (client.currentScreen instanceof DefaultDisplayViewingScreen) {
RecipeViewingScreenAccessor screen = (RecipeViewingScreenAccessor) client.currentScreen; RecipeViewingScreenAccessor screen = (RecipeViewingScreenAccessor) client.currentScreen;
if (next) if (next)
screen.getCategoryNext().onClick(); screen.getCategoryNext().onClick();
else else
screen.getCategoryBack().onClick(); screen.getCategoryBack().onClick();
return true; return true;
} else if (client.currentScreen instanceof VillagerRecipeViewingScreen) { } else if (client.currentScreen instanceof CompositeDisplayViewingScreen) {
VillagerRecipeViewingScreenAccessor screen = (VillagerRecipeViewingScreenAccessor) client.currentScreen; VillagerRecipeViewingScreenAccessor screen = (VillagerRecipeViewingScreenAccessor) client.currentScreen;
List<RecipeCategory<?>> categories = screen.getCategories(); List<RecipeCategory<?>> categories = screen.getCategories();
int currentTab = screen.getSelectedCategoryIndex(); int currentTab = screen.getSelectedCategoryIndex();
@@ -314,26 +278,23 @@ public class ReiCompat implements CompatHandler
screen.setSelectedRecipeIndex(0); screen.setSelectedRecipeIndex(0);
screen.lambdacontrols_init(); screen.lambdacontrols_init();
return true; return true;
} }*/
return false; return false;
}; };
} }
private static PressAction handleRecipe(boolean next) private static PressAction handleRecipe(boolean next) {
{
return (client, button, value, action) -> { return (client, button, value, action) -> {
if (action.isUnpressed()) if (action.isUnpressed())
return false; return false;
if (client.currentScreen instanceof RecipeViewingScreen) { /*if (client.currentScreen instanceof RecipeViewingScreenAccessor screen) {
RecipeViewingScreenAccessor screen = (RecipeViewingScreenAccessor) client.currentScreen;
if (next) if (next)
screen.getRecipeNext().onClick(); screen.getRecipeNext().onClick();
else else
screen.getRecipeBack().onClick(); screen.getRecipeBack().onClick();
return true; return true;
} else if (client.currentScreen instanceof VillagerRecipeViewingScreen) { } else if (client.currentScreen instanceof VillagerRecipeViewingScreenAccessor screen) {
VillagerRecipeViewingScreenAccessor screen = (VillagerRecipeViewingScreenAccessor) client.currentScreen;
List<RecipeCategory<?>> categories = screen.getCategories(); List<RecipeCategory<?>> categories = screen.getCategories();
int currentTab = screen.getSelectedCategoryIndex(); int currentTab = screen.getSelectedCategoryIndex();
List<RecipeDisplay> recipes = screen.getCategoryMap().get(categories.get(currentTab)); List<RecipeDisplay> recipes = screen.getCategoryMap().get(categories.get(currentTab));
@@ -357,14 +318,13 @@ public class ReiCompat implements CompatHandler
screen.lambdacontrols_init(); screen.lambdacontrols_init();
return true; return true;
} }*/
return false; return false;
}; };
} }
private static int getNextIndex(int currentIndex, int size, boolean next) private static int getNextIndex(int currentIndex, int size, boolean next) {
{
int nextIndex = currentIndex + (next ? 1 : -1); int nextIndex = currentIndex + (next ? 1 : -1);
if (nextIndex < 0) if (nextIndex < 0)
nextIndex = size - 1; nextIndex = size - 1;

View File

@@ -0,0 +1,23 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.compat.mixin;
/**
* Represents an accessor to REI's EntryListWidget.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.5.0
*/
//@Mixin(value = EntryListWidget.class, remap = false)
public interface EntryListWidgetAccessor {
/*@Accessor(value = "entries")
List<EntryListEntryWidget> getEntries();*/
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.compat.mixin;
/**
* Represents an accessor to REI's EntryWidget.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.5.0
*/
//@Mixin(value = EntryWidget.class, remap = false)
public interface EntryWidgetAccessor {
/*@Invoker("getCurrentEntry")
EntryStack lambdacontrols_getCurrentEntry();*/
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.compat.mixin;
/**
* Represents an accessor to REI's RecipeViewingScreen.
*
* @author LambdAurora
* @version 1.7.0
* @since 1.2.0
*/
//@Mixin(value = DefaultDisplayViewingScreen.class, remap = false)
public interface RecipeViewingScreenAccessor {
/*@Accessor("categoryBack")
Button getCategoryBack();
@Accessor("categoryNext")
Button getCategoryNext();
@Accessor("recipeBack")
Button getRecipeBack();
@Accessor("recipeNext")
Button getRecipeNext();*/
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,34 +7,22 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat.mixin; package dev.lambdaurora.lambdacontrols.client.compat.mixin;
import me.shedaniel.clothconfig2.api.ScrollingContainer;
import me.shedaniel.rei.api.RecipeCategory;
import me.shedaniel.rei.api.RecipeDisplay;
import me.shedaniel.rei.gui.VillagerRecipeViewingScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
import java.util.List;
import java.util.Map;
/** /**
* Represents an accessor to REI's VillagerRecipeViewingScreen. * Represents an accessor to REI's VillagerRecipeViewingScreen.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.5.0 * @version 1.7.0
* @since 1.2.0 * @since 1.2.0
*/ */
@Mixin(VillagerRecipeViewingScreen.class) //@Mixin(CompositeDisplayViewingScreen.class)
public interface VillagerRecipeViewingScreenAccessor public interface VillagerRecipeViewingScreenAccessor {
{ /*@Accessor(value = "categoryMap", remap = false)
@Accessor(value = "categoryMap", remap = false) Map<DisplayCategory<?>, List<Display>> getCategoryMap();
Map<RecipeCategory<?>, List<RecipeDisplay>> getCategoryMap();
@Accessor(value = "categories", remap = false) @Accessor(value = "categories", remap = false)
List<RecipeCategory<?>> getCategories(); List<DisplayCategory<?>> getCategories();
@Accessor(value = "selectedCategoryIndex", remap = false) @Accessor(value = "selectedCategoryIndex", remap = false)
int getSelectedCategoryIndex(); int getSelectedCategoryIndex();
@@ -52,5 +40,5 @@ public interface VillagerRecipeViewingScreenAccessor
ScrollingContainer getScrolling(); ScrollingContainer getScrolling();
@Invoker("init") @Invoker("init")
void lambdacontrols_init(); void lambdacontrols_init();*/
} }

View File

@@ -0,0 +1,587 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.controller;
import dev.lambdaurora.lambdacontrols.client.ButtonState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.GameOptions;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.Identifier;
import org.aperlambda.lambdacommon.utils.Nameable;
import org.aperlambda.lambdacommon.utils.function.PairPredicate;
import org.aperlambda.lambdacommon.utils.function.Predicates;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.stream.Collectors;
import static org.lwjgl.glfw.GLFW.*;
/**
* Represents a button binding.
*
* @author LambdAurora
* @version 1.7.0
* @since 1.0.0
*/
public class ButtonBinding implements Nameable {
public static final ButtonCategory MOVEMENT_CATEGORY;
public static final ButtonCategory GAMEPLAY_CATEGORY;
public static final ButtonCategory INVENTORY_CATEGORY;
public static final ButtonCategory MULTIPLAYER_CATEGORY;
public static final ButtonCategory MISC_CATEGORY;
public static final ButtonBinding ATTACK = new Builder("attack").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true)).onlyInGame().register();
public static final ButtonBinding BACK = new Builder("back").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding CHAT = new Builder("chat").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT).onlyInGame().cooldown().register();
public static final ButtonBinding DROP_ITEM = new Builder("drop_item").buttons(GLFW_GAMEPAD_BUTTON_B).onlyInGame().cooldown().register();
public static final ButtonBinding FORWARD = new Builder("forward").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding HOTBAR_LEFT = new Builder("hotbar_left").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.action(InputHandlers.handleHotbar(false)).onlyInGame().cooldown().register();
public static final ButtonBinding HOTBAR_RIGHT = new Builder("hotbar_right").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
.action(InputHandlers.handleHotbar(true)).onlyInGame().cooldown().register();
public static final ButtonBinding INVENTORY = new Builder("inventory").buttons(GLFW_GAMEPAD_BUTTON_Y).onlyInGame().cooldown().register();
public static final ButtonBinding JUMP = new Builder("jump").buttons(GLFW_GAMEPAD_BUTTON_A).onlyInGame().register();
public static final ButtonBinding LEFT = new Builder("left").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding PAUSE_GAME = new Builder("pause_game").buttons(GLFW_GAMEPAD_BUTTON_START).action(InputHandlers::handlePauseGame).cooldown().register();
public static final ButtonBinding PICK_BLOCK = new Builder("pick_block").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT).onlyInGame().cooldown().register();
public static final ButtonBinding PLAYER_LIST = new Builder("player_list").buttons(GLFW_GAMEPAD_BUTTON_BACK).onlyInGame().register();
public static final ButtonBinding RIGHT = new Builder("right").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true))
.action(MovementHandler.HANDLER).onlyInGame().register();
public static final ButtonBinding SCREENSHOT = new Builder("screenshot").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_A)
.action(InputHandlers::handleScreenshot).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)
.action(InputHandlers.handleInventorySlotPad(3)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_RIGHT = new Builder("slot_right").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)
.action(InputHandlers.handleInventorySlotPad(2)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_UP = new Builder("slot_up").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP)
.action(InputHandlers.handleInventorySlotPad(0)).onlyInInventory().cooldown().register();
public static final ButtonBinding SMOOTH_CAMERA = new Builder("toggle_smooth_camera").onlyInGame().cooldown().register();
public static final ButtonBinding SNEAK = new Builder("sneak").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)
.actions(InputHandlers::handleToggleSneak).onlyInGame().cooldown().register();
public static final ButtonBinding SPRINT = new Builder("sprint").buttons(GLFW_GAMEPAD_BUTTON_LEFT_THUMB).onlyInGame().register();
public static final ButtonBinding SWAP_HANDS = new Builder("swap_hands").buttons(GLFW_GAMEPAD_BUTTON_X).onlyInGame().cooldown().register();
public static final ButtonBinding TAB_LEFT = new Builder("tab_back").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.action(InputHandlers.handleHotbar(false)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown().register();
public static final ButtonBinding TAB_RIGHT = new Builder("tab_next").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
.action(InputHandlers.handleHotbar(true)).filter(Predicates.or(InputHandlers::inInventory, InputHandlers::inAdvancements)).cooldown().register();
public static final ButtonBinding TOGGLE_PERSPECTIVE = new Builder("toggle_perspective").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_Y).cooldown().register();
public static final ButtonBinding USE = new Builder("use").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true)).register();
private int[] button;
private final int[] defaultButton;
private final String key;
private final Text text;
private KeyBinding mcKeyBinding = null;
protected PairPredicate<MinecraftClient, ButtonBinding> filter;
private final List<PressAction> actions = new ArrayList<>(Collections.singletonList(PressAction.DEFAULT_ACTION));
private boolean hasCooldown;
private int cooldown = 0;
boolean pressed = false;
public ButtonBinding(String key, int[] defaultButton, List<PressAction> actions, PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown) {
this.setButton(this.defaultButton = defaultButton);
this.key = key;
this.text = new TranslatableText(this.key);
this.filter = filter;
this.actions.addAll(actions);
this.hasCooldown = hasCooldown;
}
public ButtonBinding(String key, int[] defaultButton, boolean hasCooldown) {
this(key, defaultButton, Collections.emptyList(), Predicates.pairAlwaysTrue(), hasCooldown);
}
/**
* Returns the button bound.
*
* @return the bound button
*/
public int[] getButton() {
return this.button;
}
/**
* Sets the bound button.
*
* @param button the bound button
*/
public void setButton(int[] button) {
this.button = button;
if (InputManager.hasBinding(this))
InputManager.sortBindings();
}
/**
* Returns whether the bound button is the specified button or not.
*
* @param button the button to check
* @return true if the bound button is the specified button, else false
*/
public boolean isButton(int[] button) {
return InputManager.areButtonsEquivalent(button, this.button);
}
/**
* Returns whether this button is down or not.
*
* @return true if the button is down, else false
*/
public boolean isButtonDown() {
return this.pressed;
}
/**
* Returns whether this button binding is bound or not.
*
* @return true if this button binding is bound, else false
*/
public boolean isNotBound() {
return this.button.length == 0 || this.button[0] == -1;
}
/**
* Gets the default button assigned to this binding.
*
* @return the default button
*/
public int[] getDefaultButton() {
return this.defaultButton;
}
/**
* Returns whether the assigned button is the default button.
*
* @return true if the assigned button is the default button, else false
*/
public boolean isDefault() {
return this.button.length == this.defaultButton.length && InputManager.areButtonsEquivalent(this.button, this.defaultButton);
}
/**
* Returns the button code.
*
* @return the button code
*/
public String getButtonCode() {
return Arrays.stream(this.button)
.mapToObj(btn -> Integer.valueOf(btn).toString())
.collect(Collectors.joining("+"));
}
/**
* Sets the key binding to emulate with this button binding.
*
* @param keyBinding the optional key binding
*/
public void setKeyBinding(@Nullable KeyBinding keyBinding) {
this.mcKeyBinding = keyBinding;
}
/**
* Returns whether the button binding is available in the current context.
*
* @param client the client instance
* @return true if the button binding is available, else false
*/
public boolean isAvailable(@NotNull MinecraftClient client) {
return this.filter.test(client, this);
}
/**
* Updates the button binding cooldown.
*/
public void update() {
if (this.hasCooldown && this.cooldown > 0)
this.cooldown--;
}
/**
* Handles the button binding.
*
* @param client the client instance
* @param state the state
*/
public void handle(@NotNull MinecraftClient client, float value, @NotNull ButtonState state) {
if (state == ButtonState.REPEAT && this.hasCooldown && this.cooldown != 0)
return;
if (this.hasCooldown && state.isPressed()) {
this.cooldown = 5;
}
for (int i = this.actions.size() - 1; i >= 0; i--) {
if (this.actions.get(i).press(client, this, value, state))
break;
}
}
@Override
public @NotNull String getName() {
return this.key;
}
/**
* Returns the translation key of this button binding.
*
* @return the translation key
*/
public @NotNull String getTranslationKey() {
return "lambdacontrols.action." + this.getName();
}
public @NotNull Text getText() {
return this.text;
}
/**
* Returns the key binding equivalent of this button binding.
*
* @return the key binding equivalent
*/
public @NotNull Optional<KeyBinding> asKeyBinding() {
return Optional.ofNullable(this.mcKeyBinding);
}
@Override
public String toString() {
return "ButtonBinding{id=\"" + this.key + "\","
+ "hasCooldown=" + this.hasCooldown
+ "}";
}
/**
* Returns the specified axis as a button.
*
* @param axis the axis
* @param positive true if the axis part is positive, else false
* @return the axis as a button
*/
public static int axisAsButton(int axis, boolean positive) {
return positive ? 100 + axis : 200 + axis;
}
/**
* Returns whether the specified button is an axis or not.
*
* @param button the button
* @return true if the button is an axis, else false
*/
public static boolean isAxis(int button) {
button %= 500;
return button >= 100;
}
/**
* Returns the second Joycon's specified button code.
*
* @param button the raw button code
* @return the second Joycon's button code
*/
public static int controller2Button(int button) {
return 500 + button;
}
public static void init(@NotNull GameOptions options) {
ATTACK.mcKeyBinding = options.keyAttack;
BACK.mcKeyBinding = options.keyBack;
CHAT.mcKeyBinding = options.keyChat;
DROP_ITEM.mcKeyBinding = options.keyDrop;
FORWARD.mcKeyBinding = options.keyForward;
INVENTORY.mcKeyBinding = options.keyInventory;
JUMP.mcKeyBinding = options.keyJump;
LEFT.mcKeyBinding = options.keyLeft;
PICK_BLOCK.mcKeyBinding = options.keyPickItem;
PLAYER_LIST.mcKeyBinding = options.keyPlayerList;
RIGHT.mcKeyBinding = options.keyRight;
SCREENSHOT.mcKeyBinding = options.keyScreenshot;
SMOOTH_CAMERA.mcKeyBinding = options.keySmoothCamera;
SNEAK.mcKeyBinding = options.keySneak;
SPRINT.mcKeyBinding = options.keySprint;
SWAP_HANDS.mcKeyBinding = options.keySwapHands;
TOGGLE_PERSPECTIVE.mcKeyBinding = options.keyTogglePerspective;
USE.mcKeyBinding = options.keyUse;
}
/**
* Returns the localized name of the specified button.
*
* @param button the button
* @return the localized name of the button
*/
public static @NotNull Text getLocalizedButtonName(int button) {
return switch (button % 500) {
case -1 -> new TranslatableText("key.keyboard.unknown");
case GLFW_GAMEPAD_BUTTON_A -> new TranslatableText("lambdacontrols.button.a");
case GLFW_GAMEPAD_BUTTON_B -> new TranslatableText("lambdacontrols.button.b");
case GLFW_GAMEPAD_BUTTON_X -> new TranslatableText("lambdacontrols.button.x");
case GLFW_GAMEPAD_BUTTON_Y -> new TranslatableText("lambdacontrols.button.y");
case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER -> new TranslatableText("lambdacontrols.button.left_bumper");
case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER -> new TranslatableText("lambdacontrols.button.right_bumper");
case GLFW_GAMEPAD_BUTTON_BACK -> new TranslatableText("lambdacontrols.button.back");
case GLFW_GAMEPAD_BUTTON_START -> new TranslatableText("lambdacontrols.button.start");
case GLFW_GAMEPAD_BUTTON_GUIDE -> new TranslatableText("lambdacontrols.button.guide");
case GLFW_GAMEPAD_BUTTON_LEFT_THUMB -> new TranslatableText("lambdacontrols.button.left_thumb");
case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB -> new TranslatableText("lambdacontrols.button.right_thumb");
case GLFW_GAMEPAD_BUTTON_DPAD_UP -> new TranslatableText("lambdacontrols.button.dpad_up");
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT -> new TranslatableText("lambdacontrols.button.dpad_right");
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN -> new TranslatableText("lambdacontrols.button.dpad_down");
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT -> new TranslatableText("lambdacontrols.button.dpad_left");
case 100 -> new TranslatableText("lambdacontrols.axis.left_x+");
case 101 -> new TranslatableText("lambdacontrols.axis.left_y+");
case 102 -> new TranslatableText("lambdacontrols.axis.right_x+");
case 103 -> new TranslatableText("lambdacontrols.axis.right_y+");
case 104 -> new TranslatableText("lambdacontrols.axis.left_trigger");
case 105 -> new TranslatableText("lambdacontrols.axis.right_trigger");
case 200 -> new TranslatableText("lambdacontrols.axis.left_x-");
case 201 -> new TranslatableText("lambdacontrols.axis.left_y-");
case 202 -> new TranslatableText("lambdacontrols.axis.right_x-");
case 203 -> new TranslatableText("lambdacontrols.axis.right_y-");
default -> new TranslatableText("lambdacontrols.button.unknown", button);
};
}
static {
MOVEMENT_CATEGORY = InputManager.registerDefaultCategory("key.categories.movement", category -> category.registerAllBindings(
ButtonBinding.FORWARD,
ButtonBinding.BACK,
ButtonBinding.LEFT,
ButtonBinding.RIGHT,
ButtonBinding.JUMP,
ButtonBinding.SNEAK,
ButtonBinding.SPRINT));
GAMEPLAY_CATEGORY = InputManager.registerDefaultCategory("key.categories.gameplay", category -> category.registerAllBindings(
ButtonBinding.ATTACK,
ButtonBinding.PICK_BLOCK,
ButtonBinding.USE
));
INVENTORY_CATEGORY = InputManager.registerDefaultCategory("key.categories.inventory", category -> category.registerAllBindings(
ButtonBinding.DROP_ITEM,
ButtonBinding.HOTBAR_LEFT,
ButtonBinding.HOTBAR_RIGHT,
ButtonBinding.INVENTORY,
ButtonBinding.SWAP_HANDS
));
MULTIPLAYER_CATEGORY = InputManager.registerDefaultCategory("key.categories.multiplayer",
category -> category.registerAllBindings(ButtonBinding.CHAT, ButtonBinding.PLAYER_LIST));
MISC_CATEGORY = InputManager.registerDefaultCategory("key.categories.misc", category -> category.registerAllBindings(
ButtonBinding.SCREENSHOT,
//SMOOTH_CAMERA,
ButtonBinding.TOGGLE_PERSPECTIVE
));
}
/**
* Returns a builder instance.
*
* @param identifier the identifier of the button binding
* @return the builder instanc
* @since 1.5.0
*/
public static Builder builder(@NotNull Identifier identifier) {
return new Builder(identifier);
}
/**
* Returns a builder instance.
*
* @param identifier the identifier of the button binding
* @return the builder instance
* @since 1.5.0
*/
public static Builder builder(@NotNull net.minecraft.util.Identifier identifier) {
return new Builder(identifier);
}
/**
* Represents a quick {@link ButtonBinding} builder.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.1.0
*/
public static class Builder {
private final String key;
private int[] buttons = new int[0];
private final List<PressAction> actions = new ArrayList<>();
private PairPredicate<MinecraftClient, ButtonBinding> filter = Predicates.pairAlwaysTrue();
private boolean cooldown = false;
private ButtonCategory category = null;
private KeyBinding mcBinding = null;
/**
* This constructor shouldn't be used for other mods.
*
* @param key the key with format {@code "<namespace>.<name>"}
*/
public Builder(@NotNull String key) {
this.key = key;
this.unbound();
}
public Builder(@NotNull Identifier identifier) {
this(identifier.getNamespace() + "." + identifier.getName());
}
public Builder(@NotNull net.minecraft.util.Identifier identifier) {
this(new Identifier(identifier.toString()));
}
/**
* Defines the default buttons of the {@link ButtonBinding}.
*
* @param buttons the default buttons
* @return the builder instance
*/
public Builder buttons(int... buttons) {
this.buttons = buttons;
return this;
}
/**
* Sets the {@link ButtonBinding} to unbound.
*
* @return the builder instance
*/
public Builder unbound() {
return this.buttons(-1);
}
/**
* Adds the actions to the {@link ButtonBinding}.
*
* @param actions the actions to add
* @return the builder instance
*/
public Builder actions(@NotNull PressAction... actions) {
this.actions.addAll(Arrays.asList(actions));
return this;
}
/**
* Adds an action to the {@link ButtonBinding}.
*
* @param action the action to add
* @return the builder instance
*/
public Builder action(@NotNull PressAction action) {
this.actions.add(action);
return this;
}
/**
* Sets a filter for the {@link ButtonBinding}.
*
* @param filter the filter
* @return the builder instance
*/
public Builder filter(@NotNull PairPredicate<MinecraftClient, ButtonBinding> filter) {
this.filter = filter;
return this;
}
/**
* Sets the filter of {@link ButtonBinding} to only in game.
*
* @return the builder instance
* @see #filter(PairPredicate)
* @see InputHandlers#inGame(MinecraftClient, ButtonBinding)
*/
public Builder onlyInGame() {
return this.filter(InputHandlers::inGame);
}
/**
* Sets the filter of {@link ButtonBinding} to only in inventory.
*
* @return the builder instance
* @see #filter(PairPredicate)
* @see InputHandlers#inInventory(MinecraftClient, ButtonBinding)
*/
public Builder onlyInInventory() {
return this.filter(InputHandlers::inInventory);
}
/**
* Sets whether the {@link ButtonBinding} has a cooldown or not.
*
* @param cooldown true if the {@link ButtonBinding} has a cooldown, else false
* @return the builder instance
*/
public Builder cooldown(boolean cooldown) {
this.cooldown = cooldown;
return this;
}
/**
* Puts a cooldown on the {@link ButtonBinding}.
*
* @return the builder instance
* @since 1.5.0
*/
public Builder cooldown() {
return this.cooldown(true);
}
/**
* Sets the category of the {@link ButtonBinding}.
*
* @param category the category
* @return the builder instance
*/
public Builder category(@Nullable ButtonCategory category) {
this.category = category;
return this;
}
/**
* Sets the keybinding linked to the {@link ButtonBinding}.
*
* @param binding the keybinding to link
* @return the builder instance
*/
public Builder linkKeybind(@Nullable KeyBinding binding) {
this.mcBinding = binding;
return this;
}
/**
* Builds the {@link ButtonBinding}.
*
* @return the built {@link ButtonBinding}
*/
public ButtonBinding build() {
var binding = new ButtonBinding(this.key, this.buttons, this.actions, this.filter, this.cooldown);
if (this.category != null)
this.category.registerBinding(binding);
if (this.mcBinding != null)
binding.setKeyBinding(this.mcBinding);
return binding;
}
/**
* Builds and registers the {@link ButtonBinding}.
*
* @return the built {@link ButtonBinding}
* @see #build()
*/
public ButtonBinding register() {
return InputManager.registerBinding(this.build());
}
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.controller; package dev.lambdaurora.lambdacontrols.client.controller;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import org.aperlambda.lambdacommon.Identifier; import org.aperlambda.lambdacommon.Identifier;
@@ -26,47 +26,40 @@ import java.util.List;
* @version 1.1.0 * @version 1.1.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class ButtonCategory implements Identifiable public class ButtonCategory implements Identifiable {
{
private final List<ButtonBinding> bindings = new ArrayList<>(); private final List<ButtonBinding> bindings = new ArrayList<>();
private final Identifier id; private final Identifier id;
private int priority; private final int priority;
public ButtonCategory(@NotNull Identifier id, int priority) public ButtonCategory(@NotNull Identifier id, int priority) {
{
this.id = id; this.id = id;
this.priority = priority; this.priority = priority;
} }
public ButtonCategory(@NotNull Identifier id) public ButtonCategory(@NotNull Identifier id) {
{
this(id, 100); this(id, 100);
} }
public void registerBinding(@NotNull ButtonBinding binding) public void registerBinding(@NotNull ButtonBinding binding) {
{
if (this.bindings.contains(binding)) if (this.bindings.contains(binding))
throw new IllegalStateException("Cannot register twice a button binding in the same category."); throw new IllegalStateException("Cannot register twice a button binding in the same category.");
this.bindings.add(binding); this.bindings.add(binding);
} }
public void registerAllBindings(@NotNull ButtonBinding... bindings) public void registerAllBindings(@NotNull ButtonBinding... bindings) {
{
this.registerAllBindings(Arrays.asList(bindings)); this.registerAllBindings(Arrays.asList(bindings));
} }
public void registerAllBindings(@NotNull List<ButtonBinding> bindings) public void registerAllBindings(@NotNull List<ButtonBinding> bindings) {
{
bindings.forEach(this::registerBinding); bindings.forEach(this::registerBinding);
} }
/** /**
* Gets the bindings assigned to this category. * Gets the bindings assigned to this category.
* *
* @return The bindings assigned to this category. * @return the bindings assigned to this category
*/ */
public @NotNull List<ButtonBinding> getBindings() public @NotNull List<ButtonBinding> getBindings() {
{
return Collections.unmodifiableList(this.bindings); return Collections.unmodifiableList(this.bindings);
} }
@@ -75,10 +68,9 @@ public class ButtonCategory implements Identifiable
* <p> * <p>
* The translation key should be `modid.identifier_name`. * The translation key should be `modid.identifier_name`.
* *
* @return The translated name. * @return the translated name
*/ */
public @NotNull String getTranslatedName() public @NotNull String getTranslatedName() {
{
if (this.id.getNamespace().equals("minecraft")) if (this.id.getNamespace().equals("minecraft"))
return I18n.translate(this.id.getName()); return I18n.translate(this.id.getName());
else else
@@ -89,16 +81,14 @@ public class ButtonCategory implements Identifiable
* Gets the priority display of this category. * Gets the priority display of this category.
* It will defines in which order the categories will display on the controls screen. * It will defines in which order the categories will display on the controls screen.
* *
* @return The priority of this category. * @return the priority of this category
*/ */
public int getPriority() public int getPriority() {
{
return this.priority; return this.priority;
} }
@Override @Override
public @NotNull Identifier getIdentifier() public @NotNull Identifier getIdentifier() {
{
return this.id; return this.id;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,28 +7,24 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.controller; package dev.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.LambdaControls; import dev.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.toast.SystemToast; import net.minecraft.client.toast.SystemToast;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWGamepadState; import org.lwjgl.glfw.GLFWGamepadState;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import java.io.IOException; import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
@@ -41,36 +37,18 @@ import static org.lwjgl.BufferUtils.createByteBuffer;
* Represents a controller. * Represents a controller.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.4.3 * @version 1.7.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class Controller implements Nameable public record Controller(int id) implements Nameable {
{
private static final Map<Integer, Controller> CONTROLLERS = new HashMap<>(); private static final Map<Integer, Controller> CONTROLLERS = new HashMap<>();
private final int id;
public Controller(int id)
{
this.id = id;
}
/**
* Gets the identifier of this controller.
*
* @return The identifier of this controller.
*/
public int getId()
{
return this.id;
}
/** /**
* Gets the controller's globally unique identifier. * Gets the controller's globally unique identifier.
* *
* @return The controller's GUID. * @return the controller's GUID
*/ */
public String getGuid() public String getGuid() {
{
String guid = GLFW.glfwGetJoystickGUID(this.id); String guid = GLFW.glfwGetJoystickGUID(this.id);
return guid == null ? "" : guid; return guid == null ? "" : guid;
} }
@@ -78,50 +56,45 @@ public class Controller implements Nameable
/** /**
* Returns whether this controller is connected or not. * Returns whether this controller is connected or not.
* *
* @return True if this controller is connected, else false. * @return true if this controller is connected, else false
*/ */
public boolean isConnected() public boolean isConnected() {
{
return GLFW.glfwJoystickPresent(this.id); return GLFW.glfwJoystickPresent(this.id);
} }
/** /**
* Returns whether this controller is a gamepad or not. * Returns whether this controller is a gamepad or not.
* *
* @return True if this controller is a gamepad, else false. * @return true if this controller is a gamepad, else false
*/ */
public boolean isGamepad() public boolean isGamepad() {
{
return this.isConnected() && GLFW.glfwJoystickIsGamepad(this.id); return this.isConnected() && GLFW.glfwJoystickIsGamepad(this.id);
} }
/** /**
* Gets the name of the controller. * Gets the name of the controller.
* *
* @return The controller's name. * @return the controller's name
*/ */
@Override @Override
public @NotNull String getName() public String getName() {
{ var name = this.isGamepad() ? GLFW.glfwGetGamepadName(this.id) : GLFW.glfwGetJoystickName(this.id);
String name = this.isGamepad() ? GLFW.glfwGetGamepadName(this.id) : GLFW.glfwGetJoystickName(this.id); return name == null ? String.valueOf(this.id()) : name;
return name == null ? String.valueOf(this.getId()) : name;
} }
/** /**
* Gets the state of the controller. * Gets the state of the controller.
* *
* @return The state of the controller input. * @return the state of the controller input
*/ */
public GLFWGamepadState getState() public GLFWGamepadState getState() {
{ var state = GLFWGamepadState.create();
GLFWGamepadState state = GLFWGamepadState.create();
if (this.isGamepad()) if (this.isGamepad())
GLFW.glfwGetGamepadState(this.id, state); GLFW.glfwGetGamepadState(this.id, state);
return state; return state;
} }
public static @NotNull Controller byId(int id) public static Controller byId(int id) {
{
if (id > GLFW.GLFW_JOYSTICK_LAST) { if (id > GLFW.GLFW_JOYSTICK_LAST) {
LambdaControlsClient.get().log("Controller '" + id + "' doesn't exist."); LambdaControlsClient.get().log("Controller '" + id + "' doesn't exist.");
id = GLFW.GLFW_JOYSTICK_LAST; id = GLFW.GLFW_JOYSTICK_LAST;
@@ -136,61 +109,57 @@ public class Controller implements Nameable
} }
} }
public static @NotNull Optional<Controller> byGuid(@NotNull String guid) public static Optional<Controller> byGuid(@NotNull String guid) {
{
return CONTROLLERS.values().stream().filter(Controller::isConnected) return CONTROLLERS.values().stream().filter(Controller::isConnected)
.filter(controller -> controller.getGuid().equals(guid)) .filter(controller -> controller.getGuid().equals(guid))
.max(Comparator.comparingInt(Controller::getId)); .max(Comparator.comparingInt(Controller::id));
} }
/** /**
* Reads the specified resource and returns the raw data as a ByteBuffer. * Reads the specified resource and returns the raw data as a ByteBuffer.
* *
* @param resource The resource to read. * @param resource the resource to read
* @param bufferSize The initial buffer size. * @param bufferSize the initial buffer size
* @return The resource data. * @return the resource data
* @throws IOException If an IO error occurs. * @throws IOException If an IO error occurs.
*/ */
private static ByteBuffer ioResourceToBuffer(String resource, int bufferSize) throws IOException private static ByteBuffer ioResourceToBuffer(String resource, int bufferSize) throws IOException {
{
ByteBuffer buffer = null; ByteBuffer buffer = null;
Path path = Paths.get(resource); var path = Paths.get(resource);
if (Files.isReadable(path)) { if (Files.isReadable(path)) {
try (SeekableByteChannel fc = Files.newByteChannel(path)) { try (var fc = Files.newByteChannel(path)) {
buffer = createByteBuffer((int) fc.size() + 2); buffer = createByteBuffer((int) fc.size() + 2);
while (fc.read(buffer) != -1) ; while (fc.read(buffer) != -1) ;
buffer.put((byte) 0); buffer.put((byte) 0);
} }
} }
((Buffer) buffer).flip(); // Force Java 8 >.< buffer.flip(); // Force Java 8 >.<
return buffer; return buffer;
} }
/** /**
* Updates the controller mappings. * Updates the controller mappings.
*/ */
public static void updateMappings() public static void updateMappings() {
{
try { try {
if (!LambdaControlsClient.MAPPINGS_FILE.exists()) if (!LambdaControlsClient.MAPPINGS_FILE.exists())
return; return;
LambdaControlsClient.get().log("Updating controller mappings..."); LambdaControlsClient.get().log("Updating controller mappings...");
ByteBuffer buffer = ioResourceToBuffer(LambdaControlsClient.MAPPINGS_FILE.getPath(), 1024); var buffer = ioResourceToBuffer(LambdaControlsClient.MAPPINGS_FILE.getPath(), 1024);
GLFW.glfwUpdateGamepadMappings(buffer); GLFW.glfwUpdateGamepadMappings(buffer);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
MemoryStack memoryStack = MemoryStack.stackPush(); try (var memoryStack = MemoryStack.stackPush()) {
try { var pointerBuffer = memoryStack.mallocPointer(1);
PointerBuffer pointerBuffer = memoryStack.mallocPointer(1);
int i = GLFW.glfwGetError(pointerBuffer); int i = GLFW.glfwGetError(pointerBuffer);
if (i != 0) { if (i != 0) {
long l = pointerBuffer.get(); long l = pointerBuffer.get();
String string = l == 0L ? "" : MemoryUtil.memUTF8(l); var string = l == 0L ? "" : MemoryUtil.memUTF8(l);
MinecraftClient client = MinecraftClient.getInstance(); var client = MinecraftClient.getInstance();
if (client != null) { if (client != null) {
client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT, client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT,
new TranslatableText("lambdacontrols.controller.mappings.error"), new LiteralText(string))); new TranslatableText("lambdacontrols.controller.mappings.error"), new LiteralText(string)));
@@ -198,13 +167,11 @@ public class Controller implements Nameable
} }
} catch (Throwable e) { } catch (Throwable e) {
/* Ignored :concern: */ /* Ignored :concern: */
} finally {
memoryStack.close();
} }
if (LambdaControlsClient.get().config.hasDebug()) { if (LambdaControlsClient.get().config.hasDebug()) {
for (int i = GLFW.GLFW_JOYSTICK_1; i <= GLFW.GLFW_JOYSTICK_16; i++) { for (int i = GLFW.GLFW_JOYSTICK_1; i <= GLFW.GLFW_JOYSTICK_16; i++) {
Controller controller = byId(i); var controller = byId(i);
if (!controller.isConnected()) if (!controller.isConnected())
continue; continue;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,31 +7,25 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.controller; package dev.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.client.ButtonState; import dev.lambdaurora.lambdacontrols.client.ButtonState;
import me.lambdaurora.lambdacontrols.client.LambdaInput; import dev.lambdaurora.lambdacontrols.client.LambdaInput;
import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor; import dev.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor; import dev.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.RecipeBookWidgetAccessor; import dev.lambdaurora.lambdacontrols.client.mixin.RecipeBookWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; import dev.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.advancement.AdvancementTab;
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen; import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen; import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.client.gui.screen.recipebook.RecipeGroupButtonWidget; import net.minecraft.client.util.ScreenshotRecorder;
import net.minecraft.client.options.Option;
import net.minecraft.client.util.ScreenshotUtils;
import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemGroup;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import org.aperlambda.lambdacommon.utils.Pair; import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Comparator; import java.util.Comparator;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -40,17 +34,14 @@ import java.util.stream.Collectors;
* Represents some input handlers. * Represents some input handlers.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.4.3 * @version 1.7.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class InputHandlers public class InputHandlers {
{ private InputHandlers() {
private InputHandlers()
{
} }
public static PressAction handleHotbar(boolean next) public static PressAction handleHotbar(boolean next) {
{
return (client, button, value, action) -> { return (client, button, value, action) -> {
if (action == ButtonState.RELEASE) if (action == ButtonState.RELEASE)
return false; return false;
@@ -58,24 +49,23 @@ public class InputHandlers
// When ingame // When ingame
if (client.currentScreen == null && client.player != null) { if (client.currentScreen == null && client.player != null) {
if (next) if (next)
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 8 ? 0 : client.player.inventory.selectedSlot + 1; client.player.getInventory().selectedSlot = client.player.getInventory().selectedSlot == 8 ? 0 : client.player.getInventory().selectedSlot + 1;
else else
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 0 ? 8 : client.player.inventory.selectedSlot - 1; client.player.getInventory().selectedSlot = client.player.getInventory().selectedSlot == 0 ? 8 : client.player.getInventory().selectedSlot - 1;
return true; return true;
} else if (client.currentScreen instanceof CreativeInventoryScreen) { } else if (client.currentScreen instanceof CreativeInventoryScreenAccessor inventory) {
CreativeInventoryScreenAccessor inventory = (CreativeInventoryScreenAccessor) client.currentScreen;
int currentTab = inventory.getSelectedTab(); int currentTab = inventory.getSelectedTab();
int nextTab = currentTab + (next ? 1 : -1); int nextTab = currentTab + (next ? 1 : -1);
if (nextTab < 0) if (nextTab < 0)
nextTab = ItemGroup.GROUPS.length - 1; nextTab = ItemGroup.GROUPS.length - 1;
else if (nextTab >= ItemGroup.GROUPS.length) else if (nextTab >= ItemGroup.GROUPS.length)
nextTab = 0; nextTab = 0;
inventory.lambdacontrols_setSelectedTab(ItemGroup.GROUPS[nextTab]); inventory.lambdacontrols$setSelectedTab(ItemGroup.GROUPS[nextTab]);
return true; return true;
} else if (client.currentScreen instanceof InventoryScreen) { } else if (client.currentScreen instanceof InventoryScreen inventoryScreen) {
RecipeBookWidgetAccessor recipeBook = (RecipeBookWidgetAccessor) ((InventoryScreen) client.currentScreen).getRecipeBookWidget(); var recipeBook = (RecipeBookWidgetAccessor) inventoryScreen.getRecipeBookWidget();
List<RecipeGroupButtonWidget> tabs = recipeBook.getTabButtons(); var tabs = recipeBook.getTabButtons();
RecipeGroupButtonWidget currentTab = recipeBook.getCurrentTab(); var currentTab = recipeBook.getCurrentTab();
if (currentTab == null) if (currentTab == null)
return false; return false;
int nextTab = tabs.indexOf(currentTab) + (next ? 1 : -1); int nextTab = tabs.indexOf(currentTab) + (next ? 1 : -1);
@@ -86,12 +76,11 @@ public class InputHandlers
currentTab.setToggled(false); currentTab.setToggled(false);
recipeBook.setCurrentTab(currentTab = tabs.get(nextTab)); recipeBook.setCurrentTab(currentTab = tabs.get(nextTab));
currentTab.setToggled(true); currentTab.setToggled(true);
recipeBook.lambdacontrols_refreshResults(true); recipeBook.lambdacontrols$refreshResults(true);
return true; return true;
} else if (client.currentScreen instanceof AdvancementsScreen) { } else if (client.currentScreen instanceof AdvancementsScreenAccessor screen) {
AdvancementsScreenAccessor screen = (AdvancementsScreenAccessor) client.currentScreen; var tabs = screen.getTabs().values().stream().distinct().collect(Collectors.toList());
List<AdvancementTab> tabs = screen.getTabs().values().stream().distinct().collect(Collectors.toList()); var tab = screen.getSelectedTab();
AdvancementTab tab = screen.getSelectedTab();
if (tab == null) if (tab == null)
return false; return false;
for (int i = 0; i < tabs.size(); i++) { for (int i = 0; i < tabs.size(); i++) {
@@ -111,8 +100,7 @@ public class InputHandlers
}; };
} }
public static boolean handlePauseGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, float value, @NotNull ButtonState action) public static boolean handlePauseGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, float value, @NotNull ButtonState action) {
{
if (action == ButtonState.PRESS) { if (action == ButtonState.PRESS) {
// If in game, then pause the game. // If in game, then pause the game.
if (client.currentScreen == null) if (client.currentScreen == null)
@@ -128,47 +116,43 @@ public class InputHandlers
/** /**
* Handles the screenshot action. * Handles the screenshot action.
* *
* @param client The client instance. * @param client the client instance
* @param binding The binding which fired the action. * @param binding the binding which fired the action
* @param action The action done on the binding. * @param action the action done on the binding
* @return True if handled, else false. * @return true if handled, else false
*/ */
public static boolean handleScreenshot(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, float value, @NotNull ButtonState action) public static boolean handleScreenshot(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, float value, @NotNull ButtonState action) {
{
if (action == ButtonState.RELEASE) if (action == ButtonState.RELEASE)
ScreenshotUtils.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(), ScreenshotRecorder.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(),
text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text))); text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text)));
return true; return true;
} }
public static boolean handleToggleSneak(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action) public static boolean handleToggleSneak(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action) {
{
button.asKeyBinding().ifPresent(binding -> { button.asKeyBinding().ifPresent(binding -> {
boolean sneakToggled = client.options.sneakToggled; boolean sneakToggled = client.options.sneakToggled;
if (client.player.abilities.flying && sneakToggled) if (client.player.getAbilities().flying && sneakToggled)
client.options.sneakToggled = false; client.options.sneakToggled = false;
binding.setPressed(button.pressed); binding.setPressed(button.pressed);
if (client.player.abilities.flying && sneakToggled) if (client.player.getAbilities().flying && sneakToggled)
client.options.sneakToggled = true; client.options.sneakToggled = true;
}); });
return true; return true;
} }
public static PressAction handleInventorySlotPad(int direction) public static PressAction handleInventorySlotPad(int direction) {
{
return (client, binding, value, action) -> { return (client, binding, value, action) -> {
if (!(client.currentScreen instanceof HandledScreen && action != ButtonState.RELEASE)) if (!(client.currentScreen instanceof HandledScreen inventory && action != ButtonState.RELEASE))
return false; return false;
HandledScreen inventory = (HandledScreen) client.currentScreen; var accessor = (HandledScreenAccessor) inventory;
HandledScreenAccessor accessor = (HandledScreenAccessor) inventory;
int guiLeft = accessor.getX(); int guiLeft = accessor.getX();
int guiTop = accessor.getY(); int guiTop = accessor.getY();
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth(); double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight(); double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
// Finds the hovered slot. // Finds the hovered slot.
Slot mouseSlot = accessor.lambdacontrols_getSlotAt(mouseX, mouseY); var mouseSlot = accessor.lambdacontrols$getSlotAt(mouseX, mouseY);
// Finds the closest slot in the GUI within 14 pixels. // Finds the closest slot in the GUI within 14 pixels.
Optional<Slot> closestSlot = inventory.getScreenHandler().slots.parallelStream() Optional<Slot> closestSlot = inventory.getScreenHandler().slots.parallelStream()
@@ -188,7 +172,7 @@ public class InputHandlers
double distance = Math.sqrt(Math.pow(posX - otherPosX, 2) + Math.pow(posY - otherPosY, 2)); double distance = Math.sqrt(Math.pow(posX - otherPosX, 2) + Math.pow(posY - otherPosY, 2));
return Pair.of(slot, distance); return Pair.of(slot, distance);
}).filter(entry -> { }).filter(entry -> {
Slot slot = entry.key; var slot = entry.key;
int posX = guiLeft + slot.x + 8; int posX = guiLeft + slot.x + 8;
int posY = guiTop + slot.y + 8; int posY = guiTop + slot.y + 8;
int otherPosX = (int) mouseX; int otherPosX = (int) mouseX;
@@ -212,7 +196,7 @@ public class InputHandlers
.map(p -> p.key); .map(p -> p.key);
if (closestSlot.isPresent()) { if (closestSlot.isPresent()) {
Slot slot = closestSlot.get(); var slot = closestSlot.get();
int x = guiLeft + slot.x + 8; int x = guiLeft + slot.x + 8;
int y = guiTop + slot.y + 8; int y = guiTop + slot.y + 8;
InputManager.queueMousePosition(x * (double) client.getWindow().getWidth() / (double) client.getWindow().getScaledWidth(), InputManager.queueMousePosition(x * (double) client.getWindow().getWidth() / (double) client.getWindow().getScaledWidth(),
@@ -226,36 +210,33 @@ public class InputHandlers
/** /**
* Returns always true to the filter. * Returns always true to the filter.
* *
* @param client The client instance. * @param client the client instance
* @param binding The affected binding. * @param binding the affected binding
* @return True. * @return true
*/ */
public static boolean always(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) public static boolean always(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) {
{
return true; return true;
} }
/** /**
* Returns whether the client is in game or not. * Returns whether the client is in game or not.
* *
* @param client The client instance. * @param client the client instance
* @param binding The affected binding. * @param binding the affected binding
* @return True if the client is in game, else false. * @return true if the client is in game, else false
*/ */
public static boolean inGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) public static boolean inGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) {
{
return client.currentScreen == null; return client.currentScreen == null;
} }
/** /**
* Returns whether the client is in a non-interactive screen (which means require mouse input) or not. * Returns whether the client is in a non-interactive screen (which means require mouse input) or not.
* *
* @param client The client instance. * @param client the client instance
* @param binding The affected binding. * @param binding the affected binding
* @return True if the client is in a non-interactive screen, else false. * @return true if the client is in a non-interactive screen, else false
*/ */
public static boolean inNonInteractiveScreens(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) public static boolean inNonInteractiveScreens(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) {
{
if (client.currentScreen == null) if (client.currentScreen == null)
return false; return false;
return !LambdaInput.isScreenInteractive(client.currentScreen); return !LambdaInput.isScreenInteractive(client.currentScreen);
@@ -264,24 +245,22 @@ public class InputHandlers
/** /**
* Returns whether the client is in an inventory or not. * Returns whether the client is in an inventory or not.
* *
* @param client The client instance. * @param client the client instance
* @param binding The affected binding. * @param binding the affected binding
* @return True if the client is in an inventory, else false. * @return true if the client is in an inventory, else false
*/ */
public static boolean inInventory(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) public static boolean inInventory(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) {
{
return client.currentScreen instanceof HandledScreen; return client.currentScreen instanceof HandledScreen;
} }
/** /**
* Returns whether the client is in the advancements screen or not. * Returns whether the client is in the advancements screen or not.
* *
* @param client The client instance. * @param client the client instance
* @param binding The affected binding. * @param binding the affected binding
* @return True if the client is in the advancements screen, else false. * @return true if the client is in the advancements screen, else false
*/ */
public static boolean inAdvancements(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) public static boolean inAdvancements(@NotNull MinecraftClient client, @NotNull ButtonBinding binding) {
{
return client.currentScreen instanceof AdvancementsScreen; return client.currentScreen instanceof AdvancementsScreen;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,19 +7,20 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.controller; package dev.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.ControlsMode; import dev.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.client.ButtonState; import dev.lambdaurora.lambdacontrols.client.ButtonState;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaControlsConfig; import dev.lambdaurora.lambdacontrols.client.LambdaControlsConfig;
import me.lambdaurora.lambdacontrols.client.util.MouseAccessor; import dev.lambdaurora.lambdacontrols.client.util.MouseAccessor;
import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil; import net.minecraft.client.util.InputUtil;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import org.aperlambda.lambdacommon.Identifier; import org.aperlambda.lambdacommon.Identifier;
import org.aperlambda.lambdacommon.utils.Pair;
import org.aperlambda.lambdacommon.utils.function.PairPredicate; import org.aperlambda.lambdacommon.utils.function.PairPredicate;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -33,34 +34,30 @@ import java.util.stream.Stream;
* Represents an input manager for controllers. * Represents an input manager for controllers.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.4.0 * @version 1.7.0
* @since 1.1.0 * @since 1.1.0
*/ */
public class InputManager public class InputManager {
{ public static final InputManager INPUT_MANAGER = new InputManager();
public static final InputManager INPUT_MANAGER = new InputManager(); private static final List<ButtonBinding> BINDINGS = new ArrayList<>();
private static final List<ButtonBinding> BINDINGS = new ArrayList<>(); private static final List<ButtonCategory> CATEGORIES = new ArrayList<>();
private static final List<ButtonCategory> CATEGORIES = new ArrayList<>(); public static final Int2ObjectMap<ButtonState> STATES = new Int2ObjectOpenHashMap<>();
public static final Map<Integer, ButtonState> STATES = new HashMap<>(); public static final Int2FloatMap BUTTON_VALUES = new Int2FloatOpenHashMap();
public static final Map<Integer, Float> BUTTON_VALUES = new HashMap<>(); private int prevTargetMouseX = 0;
private int prevTargetMouseX = 0; private int prevTargetMouseY = 0;
private int prevTargetMouseY = 0; private int targetMouseX = 0;
private int targetMouseX = 0; private int targetMouseY = 0;
private int targetMouseY = 0;
protected InputManager() protected InputManager() {
{
} }
public void tick(@NotNull MinecraftClient client) public void tick(@NotNull MinecraftClient client) {
{
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) { if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
this.controllerTick(client); this.controllerTick(client);
} }
} }
public void controllerTick(@NotNull MinecraftClient client) public void controllerTick(@NotNull MinecraftClient client) {
{
this.prevTargetMouseX = this.targetMouseX; this.prevTargetMouseX = this.targetMouseX;
this.prevTargetMouseY = this.targetMouseY; this.prevTargetMouseY = this.targetMouseY;
} }
@@ -68,34 +65,31 @@ public class InputManager
/** /**
* Updates the mouse position. Should only be called on pre render of a screen. * Updates the mouse position. Should only be called on pre render of a screen.
* *
* @param client The client instance. * @param client the client instance
*/ */
public void updateMousePosition(@NotNull MinecraftClient client) public void updateMousePosition(@NotNull MinecraftClient client) {
{
Objects.requireNonNull(client, "Client instance cannot be null."); Objects.requireNonNull(client, "Client instance cannot be null.");
if (this.prevTargetMouseX != this.targetMouseX || this.prevTargetMouseY != this.targetMouseY) { if (this.prevTargetMouseX != this.targetMouseX || this.prevTargetMouseY != this.targetMouseY) {
double mouseX = this.prevTargetMouseX + (this.targetMouseX - this.prevTargetMouseX) * client.getTickDelta() + 0.5; double mouseX = this.prevTargetMouseX + (this.targetMouseX - this.prevTargetMouseX) * client.getTickDelta() + 0.5;
double mouseY = this.prevTargetMouseY + (this.targetMouseY - this.prevTargetMouseY) * client.getTickDelta() + 0.5; double mouseY = this.prevTargetMouseY + (this.targetMouseY - this.prevTargetMouseY) * client.getTickDelta() + 0.5;
if (!LambdaControlsClient.get().config.hasVirtualMouse()) if (!LambdaControlsClient.get().config.hasVirtualMouse())
GLFW.glfwSetCursorPos(client.getWindow().getHandle(), mouseX, mouseY); GLFW.glfwSetCursorPos(client.getWindow().getHandle(), mouseX, mouseY);
((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), mouseX, mouseY); ((MouseAccessor) client.mouse).lambdacontrols$onCursorPos(client.getWindow().getHandle(), mouseX, mouseY);
} }
} }
/** /**
* Resets the mouse position. * Resets the mouse position.
* *
* @param windowWidth The window width. * @param windowWidth the window width
* @param windowHeight The window height. * @param windowHeight the window height
*/ */
public void resetMousePosition(int windowWidth, int windowHeight) public void resetMousePosition(int windowWidth, int windowHeight) {
{
this.targetMouseX = this.prevTargetMouseX = (int) (windowWidth / 2.F); this.targetMouseX = this.prevTargetMouseX = (int) (windowWidth / 2.F);
this.targetMouseY = this.prevTargetMouseY = (int) (windowHeight / 2.F); this.targetMouseY = this.prevTargetMouseY = (int) (windowHeight / 2.F);
} }
public void resetMouseTarget(@NotNull MinecraftClient client) public void resetMouseTarget(@NotNull MinecraftClient client) {
{
double mouseX = client.mouse.getX(); double mouseX = client.mouse.getX();
double mouseY = client.mouse.getY(); double mouseY = client.mouse.getY();
this.prevTargetMouseX = this.targetMouseX = (int) mouseX; this.prevTargetMouseX = this.targetMouseX = (int) mouseX;
@@ -105,77 +99,69 @@ public class InputManager
/** /**
* Returns whether the specified binding is registered or not. * Returns whether the specified binding is registered or not.
* *
* @param binding The binding to check. * @param binding the binding to check
* @return True if the binding is registered, else false. * @return true if the binding is registered, else false
*/ */
public static boolean hasBinding(@NotNull ButtonBinding binding) public static boolean hasBinding(@NotNull ButtonBinding binding) {
{
return BINDINGS.contains(binding); return BINDINGS.contains(binding);
} }
/** /**
* Returns whether the specified binding is registered or not. * Returns whether the specified binding is registered or not.
* *
* @param name The name of the binding to check. * @param name the name of the binding to check
* @return True if the binding is registered, else false. * @return true if the binding is registered, else false
*/ */
public static boolean hasBinding(@NotNull String name) public static boolean hasBinding(@NotNull String name) {
{
return BINDINGS.parallelStream().map(ButtonBinding::getName).anyMatch(binding -> binding.equalsIgnoreCase(name)); return BINDINGS.parallelStream().map(ButtonBinding::getName).anyMatch(binding -> binding.equalsIgnoreCase(name));
} }
/** /**
* Returns whether the specified binding is registered or not. * Returns whether the specified binding is registered or not.
* *
* @param identifier The identifier of the binding to check. * @param identifier the identifier of the binding to check
* @return True if the binding is registered, else false. * @return true if the binding is registered, else false
*/ */
public static boolean hasBinding(@NotNull Identifier identifier) public static boolean hasBinding(@NotNull Identifier identifier) {
{
return hasBinding(identifier.getNamespace() + "." + identifier.getName()); return hasBinding(identifier.getNamespace() + "." + identifier.getName());
} }
/** /**
* Registers a button binding. * Registers a button binding.
* *
* @param binding The binding to register. * @param binding the binding to register
* @return The registered binding. * @return the registered binding
*/ */
public static @NotNull ButtonBinding registerBinding(@NotNull ButtonBinding binding) public static @NotNull ButtonBinding registerBinding(@NotNull ButtonBinding binding) {
{
if (hasBinding(binding)) if (hasBinding(binding))
throw new IllegalStateException("Cannot register twice a button binding in the registry."); throw new IllegalStateException("Cannot register twice a button binding in the registry.");
BINDINGS.add(binding); BINDINGS.add(binding);
return binding; return binding;
} }
public static @NotNull ButtonBinding registerBinding(@NotNull Identifier id, int[] defaultButton, @NotNull List<PressAction> actions, @NotNull PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown) public static @NotNull ButtonBinding registerBinding(@NotNull Identifier id, int[] defaultButton, @NotNull List<PressAction> actions, @NotNull PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown) {
{
return registerBinding(new ButtonBinding(id.getNamespace() + "." + id.getName(), defaultButton, actions, filter, hasCooldown)); return registerBinding(new ButtonBinding(id.getNamespace() + "." + id.getName(), defaultButton, actions, filter, hasCooldown));
} }
public static @NotNull ButtonBinding registerBinding(@NotNull Identifier id, int[] defaultButton, boolean hasCooldown) public static @NotNull ButtonBinding registerBinding(@NotNull Identifier id, int[] defaultButton, boolean hasCooldown) {
{
return registerBinding(id, defaultButton, Collections.emptyList(), InputHandlers::always, hasCooldown); return registerBinding(id, defaultButton, Collections.emptyList(), InputHandlers::always, hasCooldown);
} }
public static @NotNull ButtonBinding registerBinding(@NotNull net.minecraft.util.Identifier id, int[] defaultButton, @NotNull List<PressAction> actions, @NotNull PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown) public static @NotNull ButtonBinding registerBinding(@NotNull net.minecraft.util.Identifier id, int[] defaultButton, @NotNull List<PressAction> actions, @NotNull PairPredicate<MinecraftClient, ButtonBinding> filter, boolean hasCooldown) {
{
return registerBinding(new Identifier(id.getNamespace(), id.getPath()), defaultButton, actions, filter, hasCooldown); return registerBinding(new Identifier(id.getNamespace(), id.getPath()), defaultButton, actions, filter, hasCooldown);
} }
public static @NotNull ButtonBinding registerBinding(@NotNull net.minecraft.util.Identifier id, int[] defaultButton, boolean hasCooldown) public static @NotNull ButtonBinding registerBinding(@NotNull net.minecraft.util.Identifier id, int[] defaultButton, boolean hasCooldown) {
{
return registerBinding(id, defaultButton, Collections.emptyList(), InputHandlers::always, hasCooldown); return registerBinding(id, defaultButton, Collections.emptyList(), InputHandlers::always, hasCooldown);
} }
/** /**
* Sorts bindings to get bindings with the higher button counts first. * Sorts bindings to get bindings with the higher button counts first.
*/ */
public static void sortBindings() public static void sortBindings() {
{
synchronized (BINDINGS) { synchronized (BINDINGS) {
List<ButtonBinding> sorted = BINDINGS.stream().sorted(Collections.reverseOrder(Comparator.comparingInt(binding -> binding.getButton().length))) var sorted = BINDINGS.stream()
.sorted(Collections.reverseOrder(Comparator.comparingInt(binding -> binding.getButton().length)))
.collect(Collectors.toList()); .collect(Collectors.toList());
BINDINGS.clear(); BINDINGS.clear();
BINDINGS.addAll(sorted); BINDINGS.addAll(sorted);
@@ -185,28 +171,24 @@ public class InputManager
/** /**
* Registers a category of button bindings. * Registers a category of button bindings.
* *
* @param category The category to register. * @param category the category to register
* @return The registered category. * @return the registered category
*/ */
public static ButtonCategory registerCategory(@NotNull ButtonCategory category) public static ButtonCategory registerCategory(@NotNull ButtonCategory category) {
{
CATEGORIES.add(category); CATEGORIES.add(category);
return category; return category;
} }
public static ButtonCategory registerCategory(@NotNull Identifier identifier, int priority) public static ButtonCategory registerCategory(@NotNull Identifier identifier, int priority) {
{
return registerCategory(new ButtonCategory(identifier, priority)); return registerCategory(new ButtonCategory(identifier, priority));
} }
public static ButtonCategory registerCategory(@NotNull Identifier identifier) public static ButtonCategory registerCategory(@NotNull Identifier identifier) {
{
return registerCategory(new ButtonCategory(identifier)); return registerCategory(new ButtonCategory(identifier));
} }
protected static ButtonCategory registerDefaultCategory(@NotNull String key, @NotNull Consumer<ButtonCategory> keyAdder) protected static ButtonCategory registerDefaultCategory(@NotNull String key, @NotNull Consumer<ButtonCategory> keyAdder) {
{ var category = registerCategory(new Identifier("minecraft", key), CATEGORIES.size());
ButtonCategory category = registerCategory(new Identifier("minecraft", key), CATEGORIES.size());
keyAdder.accept(category); keyAdder.accept(category);
return category; return category;
} }
@@ -214,25 +196,23 @@ public class InputManager
/** /**
* Loads the button bindings from configuration. * Loads the button bindings from configuration.
* *
* @param config The configuration instance. * @param config the configuration instance
*/ */
public static void loadButtonBindings(@NotNull LambdaControlsConfig config) public static void loadButtonBindings(@NotNull LambdaControlsConfig config) {
{ var queue = new ArrayList<>(BINDINGS);
List<ButtonBinding> queue = new ArrayList<>(BINDINGS);
queue.forEach(config::loadButtonBinding); queue.forEach(config::loadButtonBinding);
} }
/** /**
* Returns the binding state. * Returns the binding state.
* *
* @param binding The binding. * @param binding the binding
* @return The current state of the binding. * @return the current state of the binding
*/ */
public static @NotNull ButtonState getBindingState(@NotNull ButtonBinding binding) public static @NotNull ButtonState getBindingState(@NotNull ButtonBinding binding) {
{ var state = ButtonState.REPEAT;
ButtonState state = ButtonState.REPEAT;
for (int btn : binding.getButton()) { for (int btn : binding.getButton()) {
ButtonState btnState = InputManager.STATES.getOrDefault(btn, ButtonState.NONE); var btnState = InputManager.STATES.getOrDefault(btn, ButtonState.NONE);
if (btnState == ButtonState.PRESS) if (btnState == ButtonState.PRESS)
state = ButtonState.PRESS; state = ButtonState.PRESS;
else if (btnState == ButtonState.RELEASE) { else if (btnState == ButtonState.RELEASE) {
@@ -246,8 +226,7 @@ public class InputManager
return state; return state;
} }
public static float getBindingValue(@NotNull ButtonBinding binding, @NotNull ButtonState state) public static float getBindingValue(@NotNull ButtonBinding binding, @NotNull ButtonState state) {
{
if (state.isUnpressed()) if (state.isUnpressed())
return 0.f; return 0.f;
@@ -266,34 +245,31 @@ public class InputManager
/** /**
* Returns whether the button has duplicated bindings. * Returns whether the button has duplicated bindings.
* *
* @param button The button to check. * @param button the button to check
* @return True if the button has duplicated bindings, else false. * @return true if the button has duplicated bindings, else false
*/ */
public static boolean hasDuplicatedBindings(int[] button) public static boolean hasDuplicatedBindings(int[] button) {
{
return BINDINGS.parallelStream().filter(binding -> areButtonsEquivalent(binding.getButton(), button)).count() > 1; return BINDINGS.parallelStream().filter(binding -> areButtonsEquivalent(binding.getButton(), button)).count() > 1;
} }
/** /**
* Returns whether the button has duplicated bindings. * Returns whether the button has duplicated bindings.
* *
* @param binding The binding to check. * @param binding the binding to check
* @return True if the button has duplicated bindings, else false. * @return true if the button has duplicated bindings, else false
*/ */
public static boolean hasDuplicatedBindings(ButtonBinding binding) public static boolean hasDuplicatedBindings(ButtonBinding binding) {
{
return BINDINGS.parallelStream().filter(other -> areButtonsEquivalent(other.getButton(), binding.getButton()) && other.filter.equals(binding.filter)).count() > 1; return BINDINGS.parallelStream().filter(other -> areButtonsEquivalent(other.getButton(), binding.getButton()) && other.filter.equals(binding.filter)).count() > 1;
} }
/** /**
* Returns whether the specified buttons are equivalent or not. * Returns whether the specified buttons are equivalent or not.
* *
* @param buttons1 First set of buttons. * @param buttons1 first set of buttons
* @param buttons2 Second set of buttons. * @param buttons2 second set of buttons
* @return True if the two sets of buttons are equivalent, else false. * @return true if the two sets of buttons are equivalent, else false
*/ */
public static boolean areButtonsEquivalent(int[] buttons1, int[] buttons2) public static boolean areButtonsEquivalent(int[] buttons1, int[] buttons2) {
{
if (buttons1.length != buttons2.length) if (buttons1.length != buttons2.length)
return false; return false;
int count = 0; int count = 0;
@@ -311,34 +287,33 @@ public class InputManager
/** /**
* Returns whether the button set contains the specified button or not. * Returns whether the button set contains the specified button or not.
* *
* @param buttons The button set. * @param buttons the button set
* @param button The button to check. * @param button the button to check
* @return True if the button set contains the specified button, else false. * @return true if the button set contains the specified button, else false
*/ */
public static boolean containsButton(int[] buttons, int button) public static boolean containsButton(int[] buttons, int button) {
{
return Arrays.stream(buttons).anyMatch(btn -> btn == button); return Arrays.stream(buttons).anyMatch(btn -> btn == button);
} }
/** /**
* Updates the button states. * Updates the button states.
*/ */
public static void updateStates() public static void updateStates() {
{ for (var entry : STATES.int2ObjectEntrySet()) {
STATES.forEach((btn, state) -> { if (entry.getValue() == ButtonState.PRESS)
if (state == ButtonState.PRESS) STATES.put(entry.getIntKey(), ButtonState.REPEAT);
STATES.put(btn, ButtonState.REPEAT); else if (entry.getValue() == ButtonState.RELEASE)
else if (state == ButtonState.RELEASE) STATES.put(entry.getIntKey(), ButtonState.NONE);
STATES.put(btn, ButtonState.NONE); }
});
} }
public static void updateBindings(@NotNull MinecraftClient client) public static void updateBindings(@NotNull MinecraftClient client) {
{ var skipButtons = new IntArrayList();
List<Integer> skipButtons = new ArrayList<>(); record ButtonStateValue(ButtonState state, float value) {
Map<ButtonBinding, Pair<ButtonState, Float>> states = new HashMap<>(); }
for (ButtonBinding binding : BINDINGS) { var states = new Object2ObjectOpenHashMap<ButtonBinding, ButtonStateValue>();
ButtonState state = binding.isAvailable(client) ? getBindingState(binding) : ButtonState.NONE; for (var binding : BINDINGS) {
var state = binding.isAvailable(client) ? getBindingState(binding) : ButtonState.NONE;
if (skipButtons.stream().anyMatch(btn -> containsButton(binding.getButton(), btn))) { if (skipButtons.stream().anyMatch(btn -> containsButton(binding.getButton(), btn))) {
if (binding.pressed) if (binding.pressed)
state = ButtonState.RELEASE; state = ButtonState.RELEASE;
@@ -357,64 +332,58 @@ public class InputManager
float value = getBindingValue(binding, state); float value = getBindingValue(binding, state);
states.put(binding, Pair.of(state, value)); states.put(binding, new ButtonStateValue(state, value));
} }
states.forEach((binding, state) -> { states.forEach((binding, state) -> {
if (state.key != ButtonState.NONE) { if (state.state() != ButtonState.NONE) {
binding.handle(client, state.value, state.key); binding.handle(client, state.value(), state.state());
} }
}); });
} }
public static void queueMousePosition(double x, double y) public static void queueMousePosition(double x, double y) {
{
INPUT_MANAGER.targetMouseX = (int) MathHelper.clamp(x, 0, MinecraftClient.getInstance().getWindow().getWidth()); INPUT_MANAGER.targetMouseX = (int) MathHelper.clamp(x, 0, MinecraftClient.getInstance().getWindow().getWidth());
INPUT_MANAGER.targetMouseY = (int) MathHelper.clamp(y, 0, MinecraftClient.getInstance().getWindow().getHeight()); INPUT_MANAGER.targetMouseY = (int) MathHelper.clamp(y, 0, MinecraftClient.getInstance().getWindow().getHeight());
} }
public static void queueMoveMousePosition(double x, double y) public static void queueMoveMousePosition(double x, double y) {
{
queueMousePosition(INPUT_MANAGER.targetMouseX + x, INPUT_MANAGER.targetMouseY + y); queueMousePosition(INPUT_MANAGER.targetMouseX + x, INPUT_MANAGER.targetMouseY + y);
} }
public static @NotNull Stream<ButtonBinding> streamBindings() public static @NotNull Stream<ButtonBinding> streamBindings() {
{
return BINDINGS.stream(); return BINDINGS.stream();
} }
public static @NotNull Stream<ButtonCategory> streamCategories() public static @NotNull Stream<ButtonCategory> streamCategories() {
{
return CATEGORIES.stream(); return CATEGORIES.stream();
} }
/** /**
* Returns a new key binding instance. * Returns a new key binding instance.
* *
* @param id The identifier of the key binding. * @param id the identifier of the key binding
* @param type The type. * @param type the type
* @param code The code. * @param code the code
* @param category The category of the key binding. * @param category the category of the key binding
* @return The key binding. * @return the key binding
* @see #makeKeyBinding(Identifier, InputUtil.Type, int, String) * @see #makeKeyBinding(Identifier, InputUtil.Type, int, String)
*/ */
public static @NotNull KeyBinding makeKeyBinding(@NotNull net.minecraft.util.Identifier id, InputUtil.Type type, int code, @NotNull String category) public static @NotNull KeyBinding makeKeyBinding(@NotNull net.minecraft.util.Identifier id, InputUtil.Type type, int code, @NotNull String category) {
{
return makeKeyBinding(new Identifier(id.getNamespace(), id.getPath()), type, code, category); return makeKeyBinding(new Identifier(id.getNamespace(), id.getPath()), type, code, category);
} }
/** /**
* Returns a new key binding instance. * Returns a new key binding instance.
* *
* @param id The identifier of the key binding. * @param id the identifier of the key binding
* @param type The type. * @param type the type
* @param code The code. * @param code the code
* @param category The category of the key binding. * @param category the category of the key binding
* @return The key binding. * @return the key binding
* @see #makeKeyBinding(net.minecraft.util.Identifier, InputUtil.Type, int, String) * @see #makeKeyBinding(net.minecraft.util.Identifier, InputUtil.Type, int, String)
*/ */
public static @NotNull KeyBinding makeKeyBinding(@NotNull Identifier id, InputUtil.Type type, int code, @NotNull String category) public static @NotNull KeyBinding makeKeyBinding(@NotNull Identifier id, InputUtil.Type type, int code, @NotNull String category) {
{
return new KeyBinding(String.format("key.%s.%s", id.getNamespace(), id.getName()), type, code, category); return new KeyBinding(String.format("key.%s.%s", id.getNamespace(), id.getName()), type, code, category);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,9 +7,10 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.controller; package dev.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.client.ButtonState; import dev.lambdaurora.lambdacontrols.client.ButtonState;
import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerEntity;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -18,22 +19,20 @@ import org.jetbrains.annotations.NotNull;
* Represents the movement handler. * Represents the movement handler.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.4.0 * @version 1.6.0
* @since 1.4.0 * @since 1.4.0
*/ */
public final class MovementHandler implements PressAction public final class MovementHandler implements PressAction {
{ public static final MovementHandler HANDLER = new MovementHandler();
public static final MovementHandler HANDLER = new MovementHandler(); private boolean shouldOverrideMovement = false;
private boolean shouldOverrideMovement = false; private boolean pressingForward = false;
private boolean pressingForward = false; private boolean pressingBack = false;
private boolean pressingBack = false; private boolean pressingLeft = false;
private boolean pressingLeft = false; private boolean pressingRight = false;
private boolean pressingRight = false; private float movementForward = 0.f;
private float movementForward = 0.f; private float movementSideways = 0.f;
private float movementSideways = 0.f;
private MovementHandler() private MovementHandler() {
{
} }
/** /**
@@ -41,8 +40,7 @@ public final class MovementHandler implements PressAction
* *
* @param player The client player. * @param player The client player.
*/ */
public void applyMovement(@NotNull ClientPlayerEntity player) public void applyMovement(@NotNull ClientPlayerEntity player) {
{
if (!this.shouldOverrideMovement) if (!this.shouldOverrideMovement)
return; return;
player.input.pressingForward = this.pressingForward; player.input.pressingForward = this.pressingForward;
@@ -55,8 +53,7 @@ public final class MovementHandler implements PressAction
} }
@Override @Override
public boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action) public boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action) {
{
if (client.currentScreen != null || client.player == null) if (client.currentScreen != null || client.player == null)
return this.shouldOverrideMovement = false; return this.shouldOverrideMovement = false;
@@ -66,12 +63,14 @@ public final class MovementHandler implements PressAction
else if (button == ButtonBinding.BACK || button == ButtonBinding.RIGHT) else if (button == ButtonBinding.BACK || button == ButtonBinding.RIGHT)
direction = -1; direction = -1;
if (direction == 0) if (action.isUnpressed())
return false; direction = 0;
this.shouldOverrideMovement = true; this.shouldOverrideMovement = direction != 0;
value = (float) Math.pow(value, 2); if (LambdaControlsClient.get().config.hasAnalogMovement()) {
value = (float) Math.pow(value, 2);
} else value = 1.f;
if (button == ButtonBinding.FORWARD || button == ButtonBinding.BACK) { if (button == ButtonBinding.FORWARD || button == ButtonBinding.BACK) {
// Handle forward movement. // Handle forward movement.
@@ -93,6 +92,6 @@ public final class MovementHandler implements PressAction
this.movementSideways *= 0.3D; this.movementSideways *= 0.3D;
} }
return true; return this.shouldOverrideMovement;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,24 +7,23 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.controller; package dev.lambdaurora.lambdacontrols.client.controller;
import me.lambdaurora.lambdacontrols.client.ButtonState; import dev.lambdaurora.lambdacontrols.client.ButtonState;
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; import dev.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.StickyKeyBinding; import net.minecraft.client.option.StickyKeyBinding;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Represents a press action callback. * Represents a press action callback.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.4.3 * @version 1.7.0
* @since 1.0.0 * @since 1.0.0
*/ */
@FunctionalInterface @FunctionalInterface
public interface PressAction public interface PressAction {
{
PressAction DEFAULT_ACTION = (client, button, value, action) -> { PressAction DEFAULT_ACTION = (client, button, value, action) -> {
if (action == ButtonState.REPEAT || client.currentScreen != null) if (action == ButtonState.REPEAT || client.currentScreen != null)
return false; return false;
@@ -32,7 +31,7 @@ public interface PressAction
if (binding instanceof StickyKeyBinding) if (binding instanceof StickyKeyBinding)
binding.setPressed(button.pressed); binding.setPressed(button.pressed);
else else
((KeyBindingAccessor) binding).lambdacontrols_handlePressState(button.isButtonDown()); ((KeyBindingAccessor) binding).lambdacontrols$handlePressState(button.isButtonDown());
}); });
return true; return true;
}; };
@@ -40,8 +39,8 @@ public interface PressAction
/** /**
* Handles when there is a press action. * Handles when there is a press action.
* *
* @param client The client instance. * @param client the client instance
* @param action The action done. * @param action the action done
*/ */
boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action); boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,18 +7,17 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.gui; package dev.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.ControlsMode; import dev.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControlsConstants; import dev.lambdaurora.lambdacontrols.LambdaControlsConstants;
import me.lambdaurora.lambdacontrols.client.HudSide; import dev.lambdaurora.lambdacontrols.client.HudSide;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import dev.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.spruceui.hud.Hud; import dev.lambdaurora.spruceui.hud.Hud;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.Window;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -32,37 +31,34 @@ import org.jetbrains.annotations.Nullable;
* Represents the LambdaControls HUD. * Represents the LambdaControls HUD.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.3.2 * @version 1.7.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class LambdaControlsHud extends Hud public class LambdaControlsHud extends Hud {
{
private final LambdaControlsClient mod; private final LambdaControlsClient mod;
private MinecraftClient client; private MinecraftClient client;
private int attackWidth = 0; private int attackWidth = 0;
private int attackButtonWidth = 0; private int attackButtonWidth = 0;
private int dropItemWidth = 0; private int dropItemWidth = 0;
private int dropItemButtonWidth = 0; private int dropItemButtonWidth = 0;
private int inventoryWidth = 0; private int inventoryWidth = 0;
private int inventoryButtonWidth = 0; private int inventoryButtonWidth = 0;
private int swapHandsWidth = 0; private int swapHandsWidth = 0;
private int swapHandsButtonWidth = 0; private int swapHandsButtonWidth = 0;
private int useWidth = 0; private int useWidth = 0;
private int useButtonWidth = 0; private int useButtonWidth = 0;
private BlockHitResult placeHitResult; private BlockHitResult placeHitResult;
private String attackAction = ""; private String attackAction = "";
private String placeAction = ""; private String placeAction = "";
private int ticksDisplayedCrosshair = 0; private int ticksDisplayedCrosshair = 0;
public LambdaControlsHud(@NotNull LambdaControlsClient mod) public LambdaControlsHud(@NotNull LambdaControlsClient mod) {
{
super(new Identifier(LambdaControlsConstants.NAMESPACE, "hud/button_indicator")); super(new Identifier(LambdaControlsConstants.NAMESPACE, "hud/button_indicator"));
this.mod = mod; this.mod = mod;
} }
@Override @Override
public void init(@NotNull MinecraftClient client, int screenWidth, int screenHeight) public void init(@NotNull MinecraftClient client, int screenWidth, int screenHeight) {
{
super.init(client, screenWidth, screenHeight); super.init(client, screenWidth, screenHeight);
this.client = client; this.client = client;
this.inventoryWidth = this.width(ButtonBinding.INVENTORY); this.inventoryWidth = this.width(ButtonBinding.INVENTORY);
@@ -79,8 +75,7 @@ public class LambdaControlsHud extends Hud
* Renders the LambdaControls' HUD. * Renders the LambdaControls' HUD.
*/ */
@Override @Override
public void render(MatrixStack matrices, float tickDelta) public void render(MatrixStack matrices, float tickDelta) {
{
if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER && this.client.currentScreen == null) { if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER && this.client.currentScreen == null) {
int y = bottom(2); int y = bottom(2);
this.renderFirstIcons(matrices, this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y); this.renderFirstIcons(matrices, this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y);
@@ -91,8 +86,8 @@ public class LambdaControlsHud extends Hud
if (this.mod.reacharound.isLastReacharoundVertical()) { if (this.mod.reacharound.isLastReacharoundVertical()) {
// Render crosshair indicator. // Render crosshair indicator.
Window window = this.client.getWindow(); var window = this.client.getWindow();
String text = "[ ]"; var text = "[ ]";
float scale = Math.min(5, this.ticksDisplayedCrosshair + tickDelta) / 5F; float scale = Math.min(5, this.ticksDisplayedCrosshair + tickDelta) / 5F;
scale *= scale; scale *= scale;
@@ -103,8 +98,7 @@ public class LambdaControlsHud extends Hud
} }
} }
public void renderFirstIcons(MatrixStack matrices, int x, int y) public void renderFirstIcons(MatrixStack matrices, int x, int y) {
{
int offset = 2 + this.inventoryWidth + this.inventoryButtonWidth + 4; int offset = 2 + this.inventoryWidth + this.inventoryButtonWidth + 4;
int currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x : x - this.inventoryButtonWidth; int currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x : x - this.inventoryButtonWidth;
this.drawButton(matrices, currentX, y, ButtonBinding.INVENTORY, true); this.drawButton(matrices, currentX, y, ButtonBinding.INVENTORY, true);
@@ -119,8 +113,7 @@ public class LambdaControlsHud extends Hud
this.drawButton(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()); this.drawButton(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty());
} }
public void renderSecondIcons(MatrixStack matrices, int x, int y) public void renderSecondIcons(MatrixStack matrices, int x, int y) {
{
int offset; int offset;
int currentX = x; int currentX = x;
if (!this.placeAction.isEmpty()) { if (!this.placeAction.isEmpty()) {
@@ -142,8 +135,7 @@ public class LambdaControlsHud extends Hud
this.drawButton(matrices, currentX, y, ButtonBinding.ATTACK, this.attackWidth != 0); this.drawButton(matrices, currentX, y, ButtonBinding.ATTACK, this.attackWidth != 0);
} }
public void renderFirstSection(MatrixStack matrices, int x, int y) public void renderFirstSection(MatrixStack matrices, int x, int y) {
{
int currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x + this.inventoryButtonWidth + 2 : x - this.inventoryButtonWidth - 2 - this.inventoryWidth; int currentX = this.mod.config.getHudSide() == HudSide.LEFT ? x + this.inventoryButtonWidth + 2 : x - this.inventoryButtonWidth - 2 - this.inventoryWidth;
this.drawTip(matrices, currentX, y, ButtonBinding.INVENTORY, true); this.drawTip(matrices, currentX, y, ButtonBinding.INVENTORY, true);
currentX += this.mod.config.getHudSide() == HudSide.LEFT ? this.inventoryWidth + 4 + this.swapHandsButtonWidth + 2 currentX += this.mod.config.getHudSide() == HudSide.LEFT ? this.inventoryWidth + 4 + this.swapHandsButtonWidth + 2
@@ -158,8 +150,7 @@ public class LambdaControlsHud extends Hud
this.drawTip(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()); this.drawTip(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty());
} }
public void renderSecondSection(MatrixStack matrices, int x, int y) public void renderSecondSection(MatrixStack matrices, int x, int y) {
{
int currentX = x; int currentX = x;
if (!this.placeAction.isEmpty()) { if (!this.placeAction.isEmpty()) {
@@ -181,8 +172,7 @@ public class LambdaControlsHud extends Hud
} }
@Override @Override
public void tick() public void tick() {
{
super.tick(); super.tick();
if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER) { if (this.mod.config.getControlsMode() == ControlsMode.CONTROLLER) {
if (this.client.crosshairTarget == null) if (this.client.crosshairTarget == null)
@@ -212,7 +202,7 @@ public class LambdaControlsHud extends Hud
this.ticksDisplayedCrosshair = 0; this.ticksDisplayedCrosshair = 0;
} }
String customAttackAction = LambdaControlsCompat.getAttackActionAt(this.client, this.placeHitResult); var customAttackAction = LambdaControlsCompat.getAttackActionAt(this.client, this.placeHitResult);
if (customAttackAction != null) { if (customAttackAction != null) {
this.attackAction = customAttackAction; this.attackAction = customAttackAction;
this.attackWidth = this.width(customAttackAction); this.attackWidth = this.width(customAttackAction);
@@ -234,7 +224,7 @@ public class LambdaControlsHud extends Hud
} }
} }
String customUseAction = LambdaControlsCompat.getUseActionAt(this.client, this.placeHitResult); var customUseAction = LambdaControlsCompat.getUseActionAt(this.client, this.placeHitResult);
if (customUseAction != null) if (customUseAction != null)
placeAction = customUseAction; placeAction = customUseAction;
@@ -249,44 +239,37 @@ public class LambdaControlsHud extends Hud
} }
@Override @Override
public boolean hasTicks() public boolean hasTicks() {
{
return true; return true;
} }
private int bottom(int y) private int bottom(int y) {
{
return this.client.getWindow().getScaledHeight() - y - LambdaControlsRenderer.ICON_SIZE; return this.client.getWindow().getScaledHeight() - y - LambdaControlsRenderer.ICON_SIZE;
} }
private int width(@NotNull ButtonBinding binding) private int width(@NotNull ButtonBinding binding) {
{
return this.width(binding.getTranslationKey()); return this.width(binding.getTranslationKey());
} }
private int width(@Nullable String text) private int width(@Nullable String text) {
{
if (text == null || text.isEmpty()) if (text == null || text.isEmpty())
return 0; return 0;
return this.client.textRenderer.getWidth(I18n.translate(text)); return this.client.textRenderer.getWidth(I18n.translate(text));
} }
private void drawButton(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display) private void drawButton(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display) {
{
if (display) if (display)
LambdaControlsRenderer.drawButton(matrices, x, y, button, this.client); LambdaControlsRenderer.drawButton(matrices, x, y, button, this.client);
} }
private void drawTip(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display) private void drawTip(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display) {
{
this.drawTip(matrices, x, y, button.getTranslationKey(), display); this.drawTip(matrices, x, y, button.getTranslationKey(), display);
} }
private void drawTip(MatrixStack matrices, int x, int y, @NotNull String action, boolean display) private void drawTip(MatrixStack matrices, int x, int y, @NotNull String action, boolean display) {
{
if (!display) if (!display)
return; return;
String translatedAction = I18n.translate(action); var translatedAction = I18n.translate(action);
int textY = (LambdaControlsRenderer.ICON_SIZE / 2 - this.client.textRenderer.fontHeight / 2) + 1; int textY = (LambdaControlsRenderer.ICON_SIZE / 2 - this.client.textRenderer.fontHeight / 2) + 1;
this.client.textRenderer.draw(matrices, translatedAction, (float) x, (float) (y + textY), 14737632); this.client.textRenderer.draw(matrices, translatedAction, (float) x, (float) (y + textY), 14737632);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,22 +7,20 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.gui; package dev.lambdaurora.lambdacontrols.client.gui;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaInput; import dev.lambdaurora.lambdacontrols.client.LambdaInput;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import dev.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; import dev.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -30,53 +28,42 @@ import org.lwjgl.glfw.GLFW;
* Represents the LambdaControls renderer. * Represents the LambdaControls renderer.
* *
* @author LambdAurora * @author LambdAurora
* @version 1.5.0 * @version 1.7.0
* @since 1.2.0 * @since 1.2.0
*/ */
public class LambdaControlsRenderer public class LambdaControlsRenderer {
{ public static final int ICON_SIZE = 20;
public static final int ICON_SIZE = 20;
private static final int BUTTON_SIZE = 15; private static final int BUTTON_SIZE = 15;
private static final int AXIS_SIZE = 18; private static final int AXIS_SIZE = 18;
public static int getButtonSize(int button) public static int getButtonSize(int button) {
{ return switch (button) {
switch (button) { case -1 -> 0;
case -1: case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 100, GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 200,
return 0; GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 100, GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 200,
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 100: GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 100, GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 200,
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 200: GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 100, GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 200 -> AXIS_SIZE;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 100: default -> BUTTON_SIZE;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 200: };
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 100:
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 200:
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 100:
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 200:
return AXIS_SIZE;
default:
return BUTTON_SIZE;
}
} }
/** /**
* Gets the binding icon width. * Gets the binding icon width.
* *
* @param binding The binding. * @param binding the binding
* @return The width. * @return the width
*/ */
public static int getBindingIconWidth(@NotNull ButtonBinding binding) public static int getBindingIconWidth(@NotNull ButtonBinding binding) {
{
return getBindingIconWidth(binding.getButton()); return getBindingIconWidth(binding.getButton());
} }
/** /**
* Gets the binding icon width. * Gets the binding icon width.
* *
* @param buttons The buttons. * @param buttons the buttons
* @return The width. * @return the width
*/ */
public static int getBindingIconWidth(int[] buttons) public static int getBindingIconWidth(int[] buttons) {
{
int width = 0; int width = 0;
for (int i = 0; i < buttons.length; i++) { for (int i = 0; i < buttons.length; i++) {
width += ICON_SIZE; width += ICON_SIZE;
@@ -87,13 +74,11 @@ public class LambdaControlsRenderer
return width; return width;
} }
public static Pair<Integer, Integer> drawButton(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient client) public static ButtonSize drawButton(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient client) {
{
return drawButton(matrices, x, y, button.getButton(), client); return drawButton(matrices, x, y, button.getButton(), client);
} }
public static Pair<Integer, Integer> drawButton(MatrixStack matrices, int x, int y, int[] buttons, @NotNull MinecraftClient client) public static ButtonSize drawButton(MatrixStack matrices, int x, int y, int[] buttons, @NotNull MinecraftClient client) {
{
int height = 0; int height = 0;
int length = 0; int length = 0;
int currentX = x; int currentX = x;
@@ -108,12 +93,11 @@ public class LambdaControlsRenderer
currentX = x + length; currentX = x + length;
} }
} }
return Pair.of(length, height); return new ButtonSize(length, height);
} }
@SuppressWarnings("deprecated") @SuppressWarnings("deprecated")
public static int drawButton(MatrixStack matrices, int x, int y, int button, @NotNull MinecraftClient client) public static int drawButton(MatrixStack matrices, int x, int y, int button, @NotNull MinecraftClient client) {
{
boolean second = false; boolean second = false;
if (button == -1) if (button == -1)
return 0; return 0;
@@ -126,75 +110,55 @@ public class LambdaControlsRenderer
boolean axis = false; boolean axis = false;
int buttonOffset = button * 15; int buttonOffset = button * 15;
switch (button) { switch (button) {
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER: case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER -> buttonOffset = 7 * 15;
buttonOffset = 7 * 15; case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER -> buttonOffset = 8 * 15;
break; case GLFW.GLFW_GAMEPAD_BUTTON_BACK -> buttonOffset = 4 * 15;
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER: case GLFW.GLFW_GAMEPAD_BUTTON_START -> buttonOffset = 6 * 15;
buttonOffset = 8 * 15; case GLFW.GLFW_GAMEPAD_BUTTON_GUIDE -> buttonOffset = 5 * 15;
break; case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB -> buttonOffset = 15 * 15;
case GLFW.GLFW_GAMEPAD_BUTTON_BACK: case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB -> buttonOffset = 16 * 15;
buttonOffset = 4 * 15; case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 100 -> {
break;
case GLFW.GLFW_GAMEPAD_BUTTON_START:
buttonOffset = 6 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_GUIDE:
buttonOffset = 5 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
buttonOffset = 15 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
buttonOffset = 16 * 15;
break;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 100:
buttonOffset = 0; buttonOffset = 0;
axis = true; axis = true;
break; }
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 100: case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 100 -> {
buttonOffset = 18; buttonOffset = 18;
axis = true; axis = true;
break; }
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 100: case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 100 -> {
buttonOffset = 2 * 18; buttonOffset = 2 * 18;
axis = true; axis = true;
break; }
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 100: case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 100 -> {
buttonOffset = 3 * 18; buttonOffset = 3 * 18;
axis = true; axis = true;
break; }
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 200: case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 200 -> {
buttonOffset = 4 * 18; buttonOffset = 4 * 18;
axis = true; axis = true;
break; }
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 200: case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 200 -> {
buttonOffset = 5 * 18; buttonOffset = 5 * 18;
axis = true; axis = true;
break; }
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 200: case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 200 -> {
buttonOffset = 6 * 18; buttonOffset = 6 * 18;
axis = true; axis = true;
break; }
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 200: case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 200 -> {
buttonOffset = 7 * 18; buttonOffset = 7 * 18;
axis = true; axis = true;
break; }
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 100: case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 100, GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 200 -> buttonOffset = 9 * 15;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 200: case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 100, GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 200 -> buttonOffset = 10 * 15;
buttonOffset = 9 * 15;
break;
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 100:
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 200:
buttonOffset = 10 * 15;
break;
} }
client.getTextureManager().bindTexture(axis ? LambdaControlsClient.CONTROLLER_AXIS : LambdaControlsClient.CONTROLLER_BUTTONS); RenderSystem.setShaderTexture(0, axis ? LambdaControlsClient.CONTROLLER_AXIS : LambdaControlsClient.CONTROLLER_BUTTONS);
RenderSystem.disableDepthTest(); RenderSystem.disableDepthTest();
int assetSize = axis ? AXIS_SIZE : BUTTON_SIZE; int assetSize = axis ? AXIS_SIZE : BUTTON_SIZE;
RenderSystem.color4f(1.0F, second ? 0.0F : 1.0F, 1.0F, 1.0F); RenderSystem.setShaderColor(1.f, second ? 0.f : 1.f, 1.f, 1.f);
DrawableHelper.drawTexture(matrices, x + (ICON_SIZE / 2 - assetSize / 2), y + (ICON_SIZE / 2 - assetSize / 2), DrawableHelper.drawTexture(matrices, x + (ICON_SIZE / 2 - assetSize / 2), y + (ICON_SIZE / 2 - assetSize / 2),
(float) buttonOffset, (float) (controllerType * (axis ? AXIS_SIZE : BUTTON_SIZE)), (float) buttonOffset, (float) (controllerType * (axis ? AXIS_SIZE : BUTTON_SIZE)),
assetSize, assetSize, assetSize, assetSize,
@@ -204,17 +168,15 @@ public class LambdaControlsRenderer
return ICON_SIZE; return ICON_SIZE;
} }
public static int drawButtonTip(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display, @NotNull MinecraftClient client) public static int drawButtonTip(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, boolean display, @NotNull MinecraftClient client) {
{
return drawButtonTip(matrices, x, y, button.getButton(), button.getTranslationKey(), display, client); return drawButtonTip(matrices, x, y, button.getButton(), button.getTranslationKey(), display, client);
} }
public static int drawButtonTip(MatrixStack matrices, int x, int y, int[] button, @NotNull String action, boolean display, @NotNull MinecraftClient client) public static int drawButtonTip(MatrixStack matrices, int x, int y, int[] button, @NotNull String action, boolean display, @NotNull MinecraftClient client) {
{
if (display) { if (display) {
int buttonWidth = drawButton(matrices, x, y, button, client).key; int buttonWidth = drawButton(matrices, x, y, button, client).length();
String translatedAction = I18n.translate(action); var translatedAction = I18n.translate(action);
int textY = (LambdaControlsRenderer.ICON_SIZE / 2 - client.textRenderer.fontHeight / 2) + 1; int textY = (LambdaControlsRenderer.ICON_SIZE / 2 - client.textRenderer.fontHeight / 2) + 1;
return client.textRenderer.drawWithShadow(matrices, translatedAction, (float) (x + buttonWidth + 2), (float) (y + textY), 14737632); return client.textRenderer.drawWithShadow(matrices, translatedAction, (float) (x + buttonWidth + 2), (float) (y + textY), 14737632);
@@ -223,14 +185,13 @@ public class LambdaControlsRenderer
return -10; return -10;
} }
private static int getButtonTipWidth(@NotNull String action, @NotNull TextRenderer textRenderer) private static int getButtonTipWidth(@NotNull String action, @NotNull TextRenderer textRenderer) {
{
return 15 + 5 + textRenderer.getWidth(action); return 15 + 5 + textRenderer.getWidth(action);
} }
public static void renderVirtualCursor(@NotNull MatrixStack matrices, @NotNull MinecraftClient client) public static void renderVirtualCursor(@NotNull MatrixStack matrices, @NotNull MinecraftClient client) {
{ if (!LambdaControlsClient.get().config.hasVirtualMouse() || (client.currentScreen == null
if (!LambdaControlsClient.get().config.hasVirtualMouse() || (client.currentScreen == null || LambdaInput.isScreenInteractive(client.currentScreen))) || LambdaInput.isScreenInteractive(client.currentScreen)))
return; return;
int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()); int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
@@ -238,12 +199,11 @@ public class LambdaControlsRenderer
boolean hoverSlot = false; boolean hoverSlot = false;
if (client.currentScreen instanceof HandledScreen) { if (client.currentScreen instanceof HandledScreenAccessor inventoryScreen) {
HandledScreenAccessor inventoryScreen = (HandledScreenAccessor) client.currentScreen;
int guiLeft = inventoryScreen.getX(); int guiLeft = inventoryScreen.getX();
int guiTop = inventoryScreen.getY(); int guiTop = inventoryScreen.getY();
Slot slot = inventoryScreen.lambdacontrols_getSlotAt(mouseX, mouseY); Slot slot = inventoryScreen.lambdacontrols$getSlotAt(mouseX, mouseY);
if (slot != null) { if (slot != null) {
mouseX = guiLeft + slot.x; mouseX = guiLeft + slot.x;
@@ -253,11 +213,11 @@ public class LambdaControlsRenderer
} }
if (!hoverSlot) { if (!hoverSlot) {
Pair<Integer, Integer> slot = LambdaControlsCompat.getSlotAt(client.currentScreen, mouseX, mouseY); var slot = LambdaControlsCompat.getSlotAt(client.currentScreen, mouseX, mouseY);
if (slot != null) { if (slot != null) {
mouseX = slot.getFirst(); mouseX = slot.x();
mouseY = slot.getSecond(); mouseY = slot.y();
hoverSlot = true; hoverSlot = true;
} }
} }
@@ -273,20 +233,23 @@ public class LambdaControlsRenderer
/** /**
* Draws the virtual cursor. * Draws the virtual cursor.
* *
* @param matrices The matrix stack. * @param matrices the matrix stack
* @param x X coordinate. * @param x x coordinate
* @param y Y coordinate. * @param y y coordinate
* @param hoverSlot True if hovering a slot, else false. * @param hoverSlot true if hovering a slot, else false
* @param client The client instance. * @param client the client instance
*/ */
public static void drawCursor(@NotNull MatrixStack matrices, int x, int y, boolean hoverSlot, @NotNull MinecraftClient client) public static void drawCursor(@NotNull MatrixStack matrices, int x, int y, boolean hoverSlot, @NotNull MinecraftClient client) {
{
client.getTextureManager().bindTexture(LambdaControlsClient.CURSOR_TEXTURE);
RenderSystem.disableDepthTest(); RenderSystem.disableDepthTest();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f);
DrawableHelper.drawTexture(matrices, x, y, hoverSlot ? 16.F : 0.F, LambdaControlsClient.get().config.getVirtualMouseSkin().ordinal() * 16.F, 16, 16, 32, 64); RenderSystem.setShaderTexture(0, LambdaControlsClient.CURSOR_TEXTURE);
DrawableHelper.drawTexture(matrices, x, y,
hoverSlot ? 16.f : 0.f, LambdaControlsClient.get().config.getVirtualMouseSkin().ordinal() * 16.f,
16, 16, 32, 64);
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
} }
public record ButtonSize(int length, int height) {
}
} }

View File

@@ -0,0 +1,395 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.gui;
import dev.lambdaurora.lambdacontrols.LambdaControls;
import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import dev.lambdaurora.lambdacontrols.client.LambdaControlsConfig;
import dev.lambdaurora.lambdacontrols.client.controller.Controller;
import dev.lambdaurora.lambdacontrols.client.gui.widget.ControllerControlsWidget;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.SpruceTexts;
import dev.lambdaurora.spruceui.option.*;
import dev.lambdaurora.spruceui.screen.SpruceScreen;
import dev.lambdaurora.spruceui.widget.AbstractSpruceWidget;
import dev.lambdaurora.spruceui.widget.SpruceLabelWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceContainerWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceOptionListWidget;
import dev.lambdaurora.spruceui.widget.container.tabbed.SpruceTabbedWidget;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import net.minecraft.util.Util;
import org.lwjgl.glfw.GLFW;
/**
* Represents the LambdaControls settings screen.
*/
public class LambdaControlsSettingsScreen extends SpruceScreen {
private static final Text SDL2_GAMEPAD_TOOL = new LiteralText("SDL2 Gamepad Tool").formatted(Formatting.GREEN);
public static final String GAMEPAD_TOOL_URL = "https://generalarcade.com/gamepadtool/";
final LambdaControlsClient mod = LambdaControlsClient.get();
private final LambdaControlsConfig config = this.mod.config;
private final Screen parent;
// General options
private final SpruceOption inputModeOption;
private final SpruceOption autoSwitchModeOption;
private final SpruceOption rotationSpeedOption;
private final SpruceOption mouseSpeedOption;
private final SpruceOption virtualMouseOption;
private final SpruceOption resetOption;
// Gameplay options
private final SpruceOption analogMovementOption;
private final SpruceOption autoJumpOption;
private final SpruceOption fastBlockPlacingOption;
private final SpruceOption frontBlockPlacingOption;
private final SpruceOption verticalReacharoundOption;
private final SpruceOption flyDriftingOption;
private final SpruceOption flyVerticalDriftingOption;
// Appearance options
private final SpruceOption controllerTypeOption;
private final SpruceOption virtualMouseSkinOption;
private final SpruceOption hudEnableOption;
private final SpruceOption hudSideOption;
// Controller options
private final SpruceOption controllerOption =
new SpruceCyclingOption("lambdacontrols.menu.controller",
amount -> {
int id = this.config.getController().id();
id += amount;
if (id > GLFW.GLFW_JOYSTICK_LAST)
id = GLFW.GLFW_JOYSTICK_1;
id = searchNextAvailableController(id, false);
this.config.setController(Controller.byId(id));
},
option -> {
var controller = this.config.getController();
var controllerName = controller.getName();
if (!controller.isConnected())
return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.RED));
else if (!controller.isGamepad())
return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.GOLD));
else
return option.getDisplayText(new LiteralText(controllerName));
}, null);
private final SpruceOption secondControllerOption = new SpruceCyclingOption("lambdacontrols.menu.controller2",
amount -> {
int id = this.config.getSecondController().map(Controller::id).orElse(-1);
id += amount;
if (id > GLFW.GLFW_JOYSTICK_LAST)
id = -1;
id = searchNextAvailableController(id, true);
this.config.setSecondController(id == -1 ? null : Controller.byId(id));
},
option -> this.config.getSecondController().map(controller -> {
var controllerName = controller.getName();
if (!controller.isConnected())
return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.RED));
else if (!controller.isGamepad())
return option.getDisplayText(new LiteralText(controllerName).formatted(Formatting.GOLD));
else
return option.getDisplayText(new LiteralText(controllerName));
}).orElse(option.getDisplayText(SpruceTexts.OPTIONS_OFF.shallowCopy().formatted(Formatting.RED))),
new TranslatableText("lambdacontrols.tooltip.controller2"));
private final SpruceOption unfocusedInputOption;
private final SpruceOption invertsRightXAxis;
private final SpruceOption invertsRightYAxis;
private final SpruceOption rightDeadZoneOption;
private final SpruceOption leftDeadZoneOption;
private final SpruceOption[] maxAnalogValueOptions = new SpruceOption[]{
maxAnalogValueOption(this.config, "lambdacontrols.menu.max_left_x_value", GLFW.GLFW_GAMEPAD_AXIS_LEFT_X),
maxAnalogValueOption(this.config, "lambdacontrols.menu.max_left_y_value", GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y),
maxAnalogValueOption(this.config, "lambdacontrols.menu.max_right_x_value", GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X),
maxAnalogValueOption(this.config, "lambdacontrols.menu.max_right_y_value", GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y)
};
private static SpruceOption maxAnalogValueOption(LambdaControlsConfig config, String key, int axis) {
return new SpruceDoubleOption(key, .25f, 1.f, 0.05f,
() -> config.getAxisMaxValue(axis),
newValue -> config.setAxisMaxValue(axis, newValue),
option -> option.getDisplayText(new LiteralText(String.format("%.2f", option.get()))),
new TranslatableText(key.replace("menu", "tooltip"))
);
}
private final MutableText controllerMappingsUrlText = new LiteralText("(")
.append(new LiteralText(GAMEPAD_TOOL_URL).formatted(Formatting.GOLD))
.append("),");
private static int searchNextAvailableController(int newId, boolean allowNone) {
if ((allowNone && newId == -1) || newId == 0) return newId;
boolean connected = Controller.byId(newId).isConnected();
if (!connected) {
newId++;
}
if (newId > GLFW.GLFW_JOYSTICK_LAST)
newId = allowNone ? -1 : GLFW.GLFW_JOYSTICK_1;
return connected ? newId : searchNextAvailableController(newId, allowNone);
}
public LambdaControlsSettingsScreen(Screen parent, boolean hideControls) {
super(new TranslatableText("lambdacontrols.title.settings"));
this.parent = parent;
// General options
this.inputModeOption = new SpruceCyclingOption("lambdacontrols.menu.controls_mode",
amount -> {
var next = this.config.getControlsMode().next();
this.config.setControlsMode(next);
this.config.save();
if (this.client.player != null) {
ClientPlayNetworking.getSender().sendPacket(LambdaControls.CONTROLS_MODE_CHANNEL, this.mod.makeControlsModeBuffer(next));
}
}, option -> option.getDisplayText(new TranslatableText(this.config.getControlsMode().getTranslationKey())),
new TranslatableText("lambdacontrols.tooltip.controls_mode"));
this.autoSwitchModeOption = new SpruceToggleBooleanOption("lambdacontrols.menu.auto_switch_mode", this.config::hasAutoSwitchMode,
this.config::setAutoSwitchMode, new TranslatableText("lambdacontrols.tooltip.auto_switch_mode"));
this.rotationSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.rotation_speed", 0.0, 100.0, .5f,
this.config::getRotationSpeed,
newValue -> {
synchronized (this.config) {
this.config.setRotationSpeed(newValue);
}
}, option -> option.getDisplayText(new LiteralText(String.valueOf(option.get()))),
new TranslatableText("lambdacontrols.tooltip.rotation_speed"));
this.mouseSpeedOption = new SpruceDoubleOption("lambdacontrols.menu.mouse_speed", 0.0, 150.0, .5f,
this.config::getMouseSpeed,
newValue -> {
synchronized (this.config) {
this.config.setMouseSpeed(newValue);
}
}, option -> option.getDisplayText(new LiteralText(String.valueOf(option.get()))),
new TranslatableText("lambdacontrols.tooltip.mouse_speed"));
this.resetOption = SpruceSimpleActionOption.reset(btn -> {
this.config.reset();
var client = MinecraftClient.getInstance();
this.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
});
// Gameplay options
this.analogMovementOption = new SpruceToggleBooleanOption("lambdacontrols.menu.analog_movement",
this.config::hasAnalogMovement, this.config::setAnalogMovement,
new TranslatableText("lambdacontrols.tooltip.analog_movement"));
this.autoJumpOption = new SpruceToggleBooleanOption("options.autoJump",
() -> this.client.options.autoJump,
newValue -> this.client.options.autoJump = newValue,
null);
this.fastBlockPlacingOption = new SpruceToggleBooleanOption("lambdacontrols.menu.fast_block_placing", this.config::hasFastBlockPlacing,
this.config::setFastBlockPlacing, new TranslatableText("lambdacontrols.tooltip.fast_block_placing"));
this.frontBlockPlacingOption = new SpruceToggleBooleanOption("lambdacontrols.menu.reacharound.horizontal", this.config::hasFrontBlockPlacing,
this.config::setFrontBlockPlacing, new TranslatableText("lambdacontrols.tooltip.reacharound.horizontal"));
this.verticalReacharoundOption = new SpruceToggleBooleanOption("lambdacontrols.menu.reacharound.vertical", this.config::hasVerticalReacharound,
this.config::setVerticalReacharound, new TranslatableText("lambdacontrols.tooltip.reacharound.vertical"));
this.flyDriftingOption = new SpruceToggleBooleanOption("lambdacontrols.menu.fly_drifting", this.config::hasFlyDrifting,
this.config::setFlyDrifting, new TranslatableText("lambdacontrols.tooltip.fly_drifting"));
this.flyVerticalDriftingOption = new SpruceToggleBooleanOption("lambdacontrols.menu.fly_drifting_vertical", this.config::hasFlyVerticalDrifting,
this.config::setFlyVerticalDrifting, new TranslatableText("lambdacontrols.tooltip.fly_drifting_vertical"));
// Appearance options
this.controllerTypeOption = new SpruceCyclingOption("lambdacontrols.menu.controller_type",
amount -> this.config.setControllerType(this.config.getControllerType().next()),
option -> option.getDisplayText(this.config.getControllerType().getTranslatedText()),
new TranslatableText("lambdacontrols.tooltip.controller_type"));
this.virtualMouseSkinOption = new SpruceCyclingOption("lambdacontrols.menu.virtual_mouse.skin",
amount -> this.config.setVirtualMouseSkin(this.config.getVirtualMouseSkin().next()),
option -> option.getDisplayText(this.config.getVirtualMouseSkin().getTranslatedText()),
null);
this.hudEnableOption = new SpruceToggleBooleanOption("lambdacontrols.menu.hud_enable", this.config::isHudEnabled,
this.mod::setHudEnabled, new TranslatableText("lambdacontrols.tooltip.hud_enable"));
this.hudSideOption = new SpruceCyclingOption("lambdacontrols.menu.hud_side",
amount -> this.config.setHudSide(this.config.getHudSide().next()),
option -> option.getDisplayText(this.config.getHudSide().getTranslatedText()),
new TranslatableText("lambdacontrols.tooltip.hud_side"));
// Controller options
this.rightDeadZoneOption = new SpruceDoubleOption("lambdacontrols.menu.right_dead_zone", 0.05, 1.0, .05f,
this.config::getRightDeadZone,
newValue -> {
synchronized (this.config) {
this.config.setRightDeadZone(newValue);
}
}, option -> {
var value = String.valueOf(option.get());
return option.getDisplayText(new LiteralText(value.substring(0, Math.min(value.length(), 5))));
}, new TranslatableText("lambdacontrols.tooltip.right_dead_zone"));
this.leftDeadZoneOption = new SpruceDoubleOption("lambdacontrols.menu.left_dead_zone", 0.05, 1.0, .05f,
this.config::getLeftDeadZone,
newValue -> {
synchronized (this.config) {
this.config.setLeftDeadZone(newValue);
}
}, option -> {
var value = String.valueOf(option.get());
return option.getDisplayText(new LiteralText(value.substring(0, Math.min(value.length(), 5))));
}, new TranslatableText("lambdacontrols.tooltip.left_dead_zone"));
this.invertsRightXAxis = new SpruceToggleBooleanOption("lambdacontrols.menu.invert_right_x_axis", this.config::doesInvertRightXAxis,
newValue -> {
synchronized (this.config) {
this.config.setInvertRightXAxis(newValue);
}
}, null);
this.invertsRightYAxis = new SpruceToggleBooleanOption("lambdacontrols.menu.invert_right_y_axis", this.config::doesInvertRightYAxis,
newValue -> {
synchronized (this.config) {
this.config.setInvertRightYAxis(newValue);
}
}, null);
this.unfocusedInputOption = new SpruceToggleBooleanOption("lambdacontrols.menu.unfocused_input", this.config::hasUnfocusedInput,
this.config::setUnfocusedInput, new TranslatableText("lambdacontrols.tooltip.unfocused_input"));
this.virtualMouseOption = new SpruceToggleBooleanOption("lambdacontrols.menu.virtual_mouse", this.config::hasVirtualMouse,
this.config::setVirtualMouse, new TranslatableText("lambdacontrols.tooltip.virtual_mouse"));
}
@Override
public void removed() {
this.config.save();
super.removed();
}
@Override
public void onClose() {
this.config.save();
super.onClose();
}
private int getTextHeight() {
return (5 + this.textRenderer.fontHeight) * 3 + 5;
}
@Override
protected void init() {
super.init();
this.buildTabs();
this.addDrawableChild(this.resetOption.createWidget(Position.of(this.width / 2 - 155, this.height - 29), 150));
this.addDrawableChild(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20, SpruceTexts.GUI_DONE,
btn -> this.client.openScreen(this.parent)));
}
public void buildTabs() {
var tabs = new SpruceTabbedWidget(Position.of(0, 24), this.width, this.height - 32 - 24,
null,
Math.max(116, this.width / 8), 0);
this.addDrawableChild(tabs);
tabs.addSeparatorEntry(new TranslatableText("lambdacontrols.menu.separator.general"));
tabs.addTabEntry(new TranslatableText("lambdacontrols.menu.title.general"), null,
this::buildGeneralTab);
tabs.addTabEntry(new TranslatableText("lambdacontrols.menu.title.gameplay"), null,
this::buildGameplayTab);
tabs.addTabEntry(new TranslatableText("lambdacontrols.menu.title.visual"), null,
this::buildVisualTab);
tabs.addSeparatorEntry(new TranslatableText("options.controls"));
tabs.addTabEntry(new TranslatableText("lambdacontrols.menu.title.controller_controls"), null,
this::buildControllerControlsTab);
tabs.addSeparatorEntry(new TranslatableText("lambdacontrols.menu.separator.controller"));
tabs.addTabEntry(new TranslatableText("lambdacontrols.menu.title.controller"), null,
this::buildControllerTab);
tabs.addTabEntry(new TranslatableText("lambdacontrols.menu.title.mappings.string"), null,
this::buildMappingsStringEditorTab);
}
public SpruceOptionListWidget buildGeneralTab(int width, int height) {
var list = new SpruceOptionListWidget(Position.origin(), width, height);
list.addSingleOptionEntry(this.inputModeOption);
list.addSingleOptionEntry(this.autoSwitchModeOption);
list.addSingleOptionEntry(this.rotationSpeedOption);
list.addSingleOptionEntry(this.mouseSpeedOption);
list.addSingleOptionEntry(this.virtualMouseOption);
return list;
}
public SpruceOptionListWidget buildGameplayTab(int width, int height) {
var list = new SpruceOptionListWidget(Position.origin(), width, height);
list.addSingleOptionEntry(this.analogMovementOption);
list.addSingleOptionEntry(this.fastBlockPlacingOption);
list.addSingleOptionEntry(this.frontBlockPlacingOption);
list.addSingleOptionEntry(this.verticalReacharoundOption);
list.addSingleOptionEntry(this.flyDriftingOption);
list.addSingleOptionEntry(this.flyVerticalDriftingOption);
list.addSingleOptionEntry(this.autoJumpOption);
return list;
}
public SpruceOptionListWidget buildVisualTab(int width, int height) {
var list = new SpruceOptionListWidget(Position.origin(), width, height);
list.addSingleOptionEntry(this.controllerTypeOption);
list.addSingleOptionEntry(this.virtualMouseSkinOption);
list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.hud", true, null));
list.addSingleOptionEntry(this.hudEnableOption);
list.addSingleOptionEntry(this.hudSideOption);
return list;
}
public ControllerControlsWidget buildControllerControlsTab(int width, int height) {
return new ControllerControlsWidget(Position.origin(), width, height);
}
public AbstractSpruceWidget buildControllerTab(int width, int height) {
var root = new SpruceContainerWidget(Position.origin(), width, height);
var aboutMappings1 = new SpruceLabelWidget(Position.of(0, 2),
new TranslatableText("lambdacontrols.controller.mappings.1", SDL2_GAMEPAD_TOOL),
width, true);
var gamepadToolUrlLabel = new SpruceLabelWidget(Position.of(0, aboutMappings1.getHeight() + 4),
this.controllerMappingsUrlText, width,
label -> Util.getOperatingSystem().open(GAMEPAD_TOOL_URL), true);
gamepadToolUrlLabel.setTooltip(new TranslatableText("chat.link.open"));
var aboutMappings3 = new SpruceLabelWidget(Position.of(0,
aboutMappings1.getHeight() + gamepadToolUrlLabel.getHeight() + 6),
new TranslatableText("lambdacontrols.controller.mappings.3", Formatting.GREEN.toString(), Formatting.RESET.toString()),
width, true);
int listHeight = height - 8 - aboutMappings1.getHeight() - aboutMappings3.getHeight() - gamepadToolUrlLabel.getHeight();
var labels = new SpruceContainerWidget(Position.of(0,
listHeight),
width, height - listHeight);
labels.addChild(aboutMappings1);
labels.addChild(gamepadToolUrlLabel);
labels.addChild(aboutMappings3);
var list = new SpruceOptionListWidget(Position.origin(), width, listHeight);
list.addSingleOptionEntry(this.controllerOption);
list.addSingleOptionEntry(this.secondControllerOption);
list.addSingleOptionEntry(this.unfocusedInputOption);
list.addOptionEntry(this.invertsRightXAxis, this.invertsRightYAxis);
list.addSingleOptionEntry(this.rightDeadZoneOption);
list.addSingleOptionEntry(this.leftDeadZoneOption);
for (var option : this.maxAnalogValueOptions) {
list.addSingleOptionEntry(option);
}
root.addChild(list);
root.addChild(labels);
return root;
}
public SpruceContainerWidget buildMappingsStringEditorTab(int width, int height) {
return new MappingsStringInputWidget(Position.origin(), width, height);
}
@Override
public void renderTitle(MatrixStack matrices, int mouseX, int mouseY, float delta) {
drawCenteredText(matrices, this.textRenderer, I18n.translate("lambdacontrols.menu.title"), this.width / 2, 8, 16777215);
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.gui;
import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import dev.lambdaurora.lambdacontrols.client.controller.Controller;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.option.SpruceOption;
import dev.lambdaurora.spruceui.widget.container.SpruceContainerWidget;
import dev.lambdaurora.spruceui.widget.text.SpruceTextAreaWidget;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
/**
* Represents the controller mappings file editor screen.
*
* @author LambdAurora
* @version 1.7.0
* @since 1.4.3
*/
public class MappingsStringInputWidget extends SpruceContainerWidget {
private final SpruceOption reloadMappingsOption;
private String mappings;
private SpruceTextAreaWidget textArea;
protected MappingsStringInputWidget(Position position, int width, int height) {
super(position, width, height);
//super(new TranslatableText("lambdacontrols.menu.title.mappings.string"));
this.reloadMappingsOption = ReloadControllerMappingsOption.newOption(btn -> {
this.writeMappings();
});
this.init();
}
public void removed() {
this.writeMappings();
Controller.updateMappings();
}
public void onClose() {
this.removed();
}
public void writeMappings() {
if (this.textArea != null) {
this.mappings = this.textArea.getText();
try {
var fw = new FileWriter(LambdaControlsClient.MAPPINGS_FILE, false);
fw.write(this.mappings);
fw.close();
} catch (IOException e) {
if (this.client != null)
this.client.getToastManager().add(SystemToast.create(this.client, SystemToast.Type.TUTORIAL_HINT,
new TranslatableText("lambdacontrols.controller.mappings.error.write"), LiteralText.EMPTY));
e.printStackTrace();
}
}
}
protected void init() {
if (this.textArea != null) {
this.mappings = this.textArea.getText();
}
var mappings = "";
if (this.mappings != null)
mappings = this.mappings;
else if (LambdaControlsClient.MAPPINGS_FILE.exists()) {
try {
mappings = String.join("\n", Files.readAllLines(LambdaControlsClient.MAPPINGS_FILE.toPath()));
this.mappings = mappings;
} catch (IOException e) {
/* Ignored */
}
}
int textFieldWidth = (int) (this.width * (5.0 / 6.0));
this.textArea = new SpruceTextAreaWidget(Position.of(this, this.width / 2 - textFieldWidth / 2, 0), textFieldWidth, this.height - 50, new LiteralText(mappings));
this.textArea.setText(mappings);
// Display as many lines as possible
this.textArea.setDisplayedLines(this.textArea.getInnerHeight() / this.client.textRenderer.fontHeight);
this.addChild(this.textArea);
this.addChild(this.reloadMappingsOption.createWidget(Position.of(this.width / 2 - 155, this.height - 29), 310));
}
/*public void renderTitle(MatrixStack matrices, int mouseX, int mouseY, float delta) {
drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 8, 16777215);
}*/
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,12 +7,12 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.gui; package dev.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.client.controller.Controller; import dev.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.spruceui.option.SpruceSimpleActionOption; import dev.lambdaurora.spruceui.option.SpruceSimpleActionOption;
import dev.lambdaurora.spruceui.widget.SpruceButtonWidget;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.toast.SystemToast; import net.minecraft.client.toast.SystemToast;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
@@ -23,19 +23,12 @@ import java.util.function.Consumer;
/** /**
* Represents the option to reload the controller mappings. * Represents the option to reload the controller mappings.
*/ */
public class ReloadControllerMappingsOption extends SpruceSimpleActionOption public class ReloadControllerMappingsOption {
{
private static final String KEY = "lambdacontrols.menu.reload_controller_mappings"; private static final String KEY = "lambdacontrols.menu.reload_controller_mappings";
public ReloadControllerMappingsOption() public static SpruceSimpleActionOption newOption(@Nullable Consumer<SpruceButtonWidget> before) {
{ return SpruceSimpleActionOption.of(KEY, btn -> {
this(null); var client = MinecraftClient.getInstance();
}
public ReloadControllerMappingsOption(@Nullable Consumer<AbstractButtonWidget> before)
{
super(KEY, btn -> {
MinecraftClient client = MinecraftClient.getInstance();
if (before != null) if (before != null)
before.accept(btn); before.accept(btn);
Controller.updateMappings(); Controller.updateMappings();

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,10 +7,10 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.gui; package dev.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.ring.RingPage; import dev.lambdaurora.lambdacontrols.client.ring.RingPage;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
@@ -22,25 +22,21 @@ import net.minecraft.text.TranslatableText;
* @version 1.4.3 * @version 1.4.3
* @since 1.4.3 * @since 1.4.3
*/ */
public class RingScreen extends Screen public class RingScreen extends Screen {
{
protected final LambdaControlsClient mod; protected final LambdaControlsClient mod;
public RingScreen() public RingScreen() {
{
super(new TranslatableText("lambdacontrols.menu.title.ring")); super(new TranslatableText("lambdacontrols.menu.title.ring"));
this.mod = LambdaControlsClient.get(); this.mod = LambdaControlsClient.get();
} }
@Override @Override
public boolean isPauseScreen() public boolean isPauseScreen() {
{
return false; return false;
} }
@Override @Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
{
super.render(matrices, mouseX, mouseY, delta); super.render(matrices, mouseX, mouseY, delta);
RingPage page = this.mod.ring.getCurrentPage(); RingPage page = this.mod.ring.getCurrentPage();
@@ -49,8 +45,7 @@ public class RingScreen extends Screen
} }
@Override @Override
public boolean mouseReleased(double mouseX, double mouseY, int button) public boolean mouseReleased(double mouseX, double mouseY, int button) {
{
/*if (LambdaControlsClient.BINDING_RING.matchesMouse(button)) { /*if (LambdaControlsClient.BINDING_RING.matchesMouse(button)) {
this.onClose(); this.onClose();
return true; return true;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,36 +7,21 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.gui; package dev.lambdaurora.lambdacontrols.client.gui;
import me.lambdaurora.lambdacontrols.client.HudSide; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
import me.lambdaurora.spruceui.SpruceTexturedButtonWidget;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.GameMenuScreen;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.util.Arm;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
/** /**
* Represents the touchscreen overlay * Represents the touchscreen overlay
*/ */
public class TouchscreenOverlay extends Screen public class TouchscreenOverlay extends Screen {
{ public TouchscreenOverlay(@NotNull LambdaControlsClient mod) {
public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png"); super(new LiteralText("Touchscreen overlay"));
}
/*public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png");
private LambdaControlsClient mod; private LambdaControlsClient mod;
private SpruceTexturedButtonWidget jumpButton; private SpruceTexturedButtonWidget jumpButton;
private SpruceTexturedButtonWidget flyButton; private SpruceTexturedButtonWidget flyButton;
@@ -85,7 +70,7 @@ public class TouchscreenOverlay extends Screen
* Updates the forward button ticks cooldown. * Updates the forward button ticks cooldown.
* *
* @param state The button state. * @param state The button state.
*/ *
private void updateForwardButtonsState(boolean state) private void updateForwardButtonsState(boolean state)
{ {
if (state) if (state)
@@ -96,7 +81,7 @@ public class TouchscreenOverlay extends Screen
/** /**
* Updates the jump buttons. * Updates the jump buttons.
*/ *
private void updateJumpButtons() private void updateJumpButtons()
{ {
if (this.client == null) if (this.client == null)
@@ -125,7 +110,7 @@ public class TouchscreenOverlay extends Screen
* *
* @param btn The pressed button. * @param btn The pressed button.
* @param state The state of the jump button. * @param state The state of the jump button.
*/ *
private void handleJump(ButtonWidget btn, boolean state) private void handleJump(ButtonWidget btn, boolean state)
{ {
((KeyBindingAccessor) this.client.options.keyJump).lambdacontrols_handlePressState(state); ((KeyBindingAccessor) this.client.options.keyJump).lambdacontrols_handlePressState(state);
@@ -293,5 +278,5 @@ public class TouchscreenOverlay extends Screen
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 / 5.0), 1);
} }
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
} }*/
} }

View File

@@ -0,0 +1,58 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.gui.widget;
import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.SpruceTexts;
import dev.lambdaurora.spruceui.widget.AbstractSpruceIconButtonWidget;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
/**
* Represents a controller button widget.
*/
public class ControllerButtonWidget extends AbstractSpruceIconButtonWidget {
private ButtonBinding binding;
private int iconWidth;
public ControllerButtonWidget(Position position, int width, @NotNull ButtonBinding binding, @NotNull PressAction action) {
super(position, width, 20, ButtonBinding.getLocalizedButtonName(binding.getButton()[0]), action);
this.binding = binding;
}
public void update() {
int length = binding.getButton().length;
this.setMessage(this.binding.isNotBound() ? SpruceTexts.NOT_BOUND.copy() :
(length > 0 ? ButtonBinding.getLocalizedButtonName(binding.getButton()[0]) : new LiteralText("<>")));
}
@Override
public Text getMessage() {
if (this.binding.getButton().length > 1)
return LiteralText.EMPTY;
return super.getMessage();
}
@Override
protected int renderIcon(MatrixStack matrices, int mouseX, int mouseY, float delta) {
int x = this.getX();
if (this.binding.getButton().length > 1) {
x += (this.width / 2 - this.iconWidth / 2) - 4;
}
var size = LambdaControlsRenderer.drawButton(matrices, x, this.getY(), this.binding, MinecraftClient.getInstance());
this.iconWidth = size.length();
return size.height();
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.gui.widget;
import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import dev.lambdaurora.lambdacontrols.client.controller.InputManager;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.SpruceTexts;
import dev.lambdaurora.spruceui.widget.SpruceButtonWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceContainerWidget;
import net.minecraft.client.gui.screen.option.ControlsOptionsScreen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.function.Predicates;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Represents the controls screen.
*/
public class ControllerControlsWidget extends SpruceContainerWidget {
final LambdaControlsClient mod;
private ControlsListWidget bindingsListWidget;
private SpruceButtonWidget resetButton;
public ButtonBinding focusedBinding;
public boolean waiting = false;
public List<Integer> currentButtons = new ArrayList<>();
public ControllerControlsWidget(Position position, int width, int height) {
super(position, width, height);
this.mod = LambdaControlsClient.get();
this.init();
}
protected void init() {
this.addChild(new SpruceButtonWidget(Position.of(this, this.width / 2 - 155, 18), 310, 20,
new TranslatableText("lambdacontrols.menu.keyboard_controls"),
btn -> this.client.openScreen(new ControlsOptionsScreen(null, this.client.options))));
this.bindingsListWidget = new ControlsListWidget(Position.of(this, 0, 43), this.width, this.height - 43 - 35, this);
this.addChild(this.bindingsListWidget);
this.addChild(this.resetButton = new SpruceButtonWidget(Position.of(this, this.width / 2 - 155, this.height - 29), 150, 20,
SpruceTexts.CONTROLS_RESET_ALL,
btn -> InputManager.streamBindings().collect(Collectors.toSet()).forEach(binding -> this.mod.config.setButtonBinding(binding, binding.getDefaultButton()))));
}
@Override
public void renderWidget(MatrixStack matrices, int mouseX, int mouseY, float delta) {
drawCenteredText(matrices, this.client.textRenderer, new TranslatableText("lambdacontrols.menu.title.controller_controls"),
this.getX() + this.width / 2, this.getY() + 4, 16777215);
this.resetButton.setActive(InputManager.streamBindings().anyMatch(Predicates.not(ButtonBinding::isDefault)));
super.renderWidget(matrices, mouseX, mouseY, delta);
}
public void finishBindingEdit(int... buttons) {
if (this.focusedBinding == null) return;
this.mod.config.setButtonBinding(this.focusedBinding, buttons);
this.focusedBinding = null;
}
}

View File

@@ -0,0 +1,320 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.gui.widget;
import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import dev.lambdaurora.lambdacontrols.client.controller.ButtonCategory;
import dev.lambdaurora.lambdacontrols.client.controller.InputManager;
import dev.lambdaurora.spruceui.Position;
import dev.lambdaurora.spruceui.SpruceTexts;
import dev.lambdaurora.spruceui.navigation.NavigationDirection;
import dev.lambdaurora.spruceui.navigation.NavigationUtils;
import dev.lambdaurora.spruceui.widget.SpruceButtonWidget;
import dev.lambdaurora.spruceui.widget.SpruceSeparatorWidget;
import dev.lambdaurora.spruceui.widget.SpruceWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceEntryListWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceParentWidget;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* Represents a control list widget.
*/
public class ControlsListWidget extends SpruceEntryListWidget<ControlsListWidget.Entry> {
private static final int[] UNBOUND = new int[]{-1};
private final ControllerControlsWidget gui;
protected int lastIndex = 0;
private final int maxTextLength;
public ControlsListWidget(Position position, int width, int height, ControllerControlsWidget gui) {
super(position, width, height, 4, ControlsListWidget.Entry.class);
this.gui = gui;
this.maxTextLength = InputManager.streamBindings().mapToInt(binding -> this.client.textRenderer.getWidth(binding.getText())).max().orElse(0);
InputManager.streamCategories()
.sorted(Comparator.comparingInt(ButtonCategory::getPriority))
.forEach(category -> {
this.addEntry(new CategoryEntry(this, category));
category.getBindings().forEach(binding -> {
this.addEntry(new ControlsListWidget.ButtonBindingEntry(this, binding));
});
});
this.setAllowOutsideHorizontalNavigation(true);
}
private int getRowWidth() {
return this.getWidth() - 6 - this.getRowLeft() * 2;
}
public int getRowLeft() {
int baseWidth = 220 + 32;
return this.getWidth() / 2 - baseWidth / 2 + 72 - this.maxTextLength;
}
public class ButtonBindingEntry extends Entry implements SpruceParentWidget<SpruceWidget> {
private final List<SpruceWidget> children = new ArrayList<>();
private @Nullable SpruceWidget focused;
private final ButtonBinding binding;
private final String bindingName;
private final ControllerButtonWidget editButton;
private final SpruceButtonWidget resetButton;
private final SpruceButtonWidget unbindButton;
ButtonBindingEntry(@NotNull ControlsListWidget parent, @NotNull ButtonBinding binding) {
super(parent);
this.binding = binding;
this.bindingName = I18n.translate(this.binding.getTranslationKey());
this.editButton = new ControllerButtonWidget(Position.of(this, parent.getWidth() / 2 - 8, 0), 110, this.binding, btn -> {
gui.focusedBinding = binding;
LambdaControlsClient.get().input.beginControlsInput(gui);
}) {
protected Text getNarrationMessage() {
return binding.isNotBound() ? new TranslatableText("narrator.controls.unbound", bindingName)
: new TranslatableText("narrator.controls.bound", bindingName, super.getNarrationMessage());
}
};
this.children.add(editButton);
this.resetButton = new SpruceButtonWidget(Position.of(this,
this.editButton.getPosition().getRelativeX() + this.editButton.getWidth() + 2, 0),
44, 20, new TranslatableText("controls.reset"),
btn -> LambdaControlsClient.get().config.setButtonBinding(binding, binding.getDefaultButton())) {
protected Text getNarrationMessage() {
return new TranslatableText("narrator.controls.reset", bindingName);
}
};
this.children.add(this.resetButton);
this.unbindButton = new SpruceButtonWidget(Position.of(this,
this.editButton.getPosition().getRelativeX() + this.editButton.getWidth() + 2, 0),
this.resetButton.getWidth(), this.resetButton.getHeight(), SpruceTexts.GUI_UNBIND,
btn -> {
LambdaControlsClient.get().config.setButtonBinding(binding, UNBOUND);
gui.focusedBinding = null;
LambdaControlsClient.get().input.beginControlsInput(null);
}) {
protected Text getNarrationMessage() {
return new TranslatableText("lambdacontrols.narrator.unbound", bindingName);
}
};
this.children.add(this.unbindButton);
this.position.setRelativeX(4);
this.width -= 10;
}
@Override
public List<SpruceWidget> children() {
return this.children;
}
@Override
public @Nullable SpruceWidget getFocused() {
return this.focused;
}
@Override
public void setFocused(@Nullable SpruceWidget focused) {
if (this.focused == focused)
return;
if (this.focused != null)
this.focused.setFocused(false);
this.focused = focused;
}
@Override
public int getHeight() {
return this.children.stream().mapToInt(SpruceWidget::getHeight).reduce(Integer::max).orElse(0) + 4;
}
/* Input */
@Override
protected boolean onMouseClick(double mouseX, double mouseY, int button) {
var it = this.children().iterator();
SpruceWidget element;
do {
if (!it.hasNext()) {
return false;
}
element = it.next();
} while (!element.mouseClicked(mouseX, mouseY, button));
this.setFocused(element);
if (button == GLFW.GLFW_MOUSE_BUTTON_1)
this.dragging = true;
return true;
}
@Override
protected boolean onMouseRelease(double mouseX, double mouseY, int button) {
this.dragging = false;
return this.hoveredElement(mouseX, mouseY).filter(element -> element.mouseReleased(mouseX, mouseY, button)).isPresent();
}
@Override
protected boolean onMouseDrag(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
return this.getFocused() != null && this.dragging && button == GLFW.GLFW_MOUSE_BUTTON_1
&& this.getFocused().mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
@Override
protected boolean onKeyPress(int keyCode, int scanCode, int modifiers) {
return this.focused != null && this.focused.keyPressed(keyCode, scanCode, modifiers);
}
/* Navigation */
@Override
public void setFocused(boolean focused) {
super.setFocused(focused);
if (!focused) {
this.setFocused(null);
}
}
@Override
public boolean onNavigation(@NotNull NavigationDirection direction, boolean tab) {
if (this.requiresCursor()) return false;
if (!tab && direction.isVertical()) {
if (this.isFocused()) {
this.setFocused(null);
return false;
}
int lastIndex = this.parent.lastIndex;
if (lastIndex >= this.children.size())
lastIndex = this.children.size() - 1;
if (!this.children.get(lastIndex).onNavigation(direction, tab))
return false;
this.setFocused(this.children.get(lastIndex));
return true;
}
boolean result = NavigationUtils.tryNavigate(direction, tab, this.children, this.focused, this::setFocused, true);
if (result) {
this.setFocused(true);
if (direction.isHorizontal() && this.getFocused() != null) {
this.parent.lastIndex = this.children.indexOf(this.getFocused());
}
}
return result;
}
/* Rendering */
@Override
protected void renderWidget(MatrixStack matrices, int mouseX, int mouseY, float delta) {
boolean focused = gui.focusedBinding == this.binding;
var textRenderer = ControlsListWidget.this.client.textRenderer;
int height = this.getHeight();
//float textX = (float) (this.getX() + 70 - ControlsListWidget.this.maxTextLength);
int textY = this.getY() + height / 2;
textRenderer.draw(matrices, this.bindingName, this.getX(), (float) (textY - 9 / 2), 16777215);
this.resetButton.setVisible(!focused);
this.unbindButton.setVisible(focused);
this.resetButton.setActive(!this.binding.isDefault());
this.editButton.update();
if (focused) {
var text = new LiteralText("> ").formatted(Formatting.WHITE);
text.append(this.editButton.getMessage().copy().formatted(Formatting.YELLOW));
this.editButton.setMessage(text.append(new LiteralText(" <").formatted(Formatting.WHITE)));
} else if (!this.binding.isNotBound() && InputManager.hasDuplicatedBindings(this.binding)) {
var text = this.editButton.getMessage().copy();
this.editButton.setMessage(text.formatted(Formatting.RED));
} else if (this.binding.isNotBound()) {
var text = this.editButton.getMessage().copy();
this.editButton.setMessage(text.formatted(Formatting.GOLD));
}
this.children.forEach(widget -> widget.render(matrices, mouseX, mouseY, delta));
}
}
public static class CategoryEntry extends Entry {
private final SpruceSeparatorWidget separatorWidget;
protected CategoryEntry(ControlsListWidget parent, ButtonCategory category) {
super(parent);
this.separatorWidget = new SpruceSeparatorWidget(Position.of(this, 2, 0), this.getWidth() - 4,
new LiteralText(category.getTranslatedName())) {
@Override
public int getWidth() {
return CategoryEntry.this.getWidth() - 4;
}
};
}
public SpruceSeparatorWidget getSeparatorWidget() {
return this.separatorWidget;
}
@Override
public int getHeight() {
return this.separatorWidget.getHeight() + 4;
}
/* Navigation */
@Override
public boolean onNavigation(@NotNull NavigationDirection direction, boolean tab) {
return this.separatorWidget.onNavigation(direction, tab);
}
/* Rendering */
@Override
protected void renderWidget(MatrixStack matrices, int mouseX, int mouseY, float delta) {
this.separatorWidget.render(matrices, mouseX, mouseY, delta);
}
@Override
public String toString() {
return "SpruceTabbedWidget$SeparatorEntry{" +
"position=" + this.getPosition() +
", width=" + this.getWidth() +
", height=" + this.getHeight() +
'}';
}
}
@Environment(EnvType.CLIENT)
public abstract static class Entry extends SpruceEntryListWidget.Entry {
protected final ControlsListWidget parent;
protected Entry(ControlsListWidget parent) {
this.parent = parent;
}
@Override
public int getWidth() {
return this.parent.getInnerWidth();
}
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import net.minecraft.advancement.Advancement; import net.minecraft.advancement.Advancement;
import net.minecraft.client.gui.screen.advancement.AdvancementTab; import net.minecraft.client.gui.screen.advancement.AdvancementTab;
@@ -22,8 +22,7 @@ import java.util.Map;
* Represents an accessor of {@link AdvancementsScreen}. * Represents an accessor of {@link AdvancementsScreen}.
*/ */
@Mixin(AdvancementsScreen.class) @Mixin(AdvancementsScreen.class)
public interface AdvancementsScreenAccessor public interface AdvancementsScreenAccessor {
{
@Accessor("advancementHandler") @Accessor("advancementHandler")
ClientAdvancementManager getAdvancementManager(); ClientAdvancementManager getAdvancementManager();

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,15 +7,14 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.gui.widget.ClickableWidget;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(AbstractButtonWidget.class) @Mixin(ClickableWidget.class)
public interface AbstractButtonWidgetAccessor public interface ClickableWidgetAccessor {
{
@Accessor("height") @Accessor("height")
int getHeight(); int getHeight();
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,11 +7,11 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.MovementHandler; import dev.lambdaurora.lambdacontrols.client.controller.MovementHandler;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.input.Input; import net.minecraft.client.input.Input;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
@@ -30,9 +30,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* Injects the anti fly drifting feature. * Injects the anti fly drifting feature.
*/ */
@Mixin(ClientPlayerEntity.class) @Mixin(ClientPlayerEntity.class)
public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity {
{ private boolean lambdacontrols$driftingPrevented = false;
private boolean lambdacontrols_driftingPrevented = false;
@Shadow @Shadow
protected abstract boolean hasMovementInput(); protected abstract boolean hasMovementInput();
@@ -47,39 +46,35 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity
@Shadow @Shadow
protected abstract boolean isCamera(); protected abstract boolean isCamera();
public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) {
{
super(world, profile); super(world, profile);
} }
@Inject(method = "move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V")) @Inject(method = "move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V"))
public void onMove(MovementType type, Vec3d movement, CallbackInfo ci) public void onMove(MovementType type, Vec3d movement, CallbackInfo ci) {
{ var mod = LambdaControlsClient.get();
LambdaControlsClient mod = LambdaControlsClient.get();
if (type == MovementType.SELF) { if (type == MovementType.SELF) {
if (this.abilities.flying && (!mod.config.hasFlyDrifting() || !mod.config.hasFlyVerticalDrifting())) { if (this.getAbilities().flying && (!mod.config.hasFlyDrifting() || !mod.config.hasFlyVerticalDrifting())) {
if (!this.hasMovementInput()) { if (!this.hasMovementInput()) {
if (!this.lambdacontrols_driftingPrevented) { if (!this.lambdacontrols$driftingPrevented) {
if (!mod.config.hasFlyDrifting()) if (!mod.config.hasFlyDrifting())
this.setVelocity(this.getVelocity().multiply(0, 1.0, 0)); this.setVelocity(this.getVelocity().multiply(0, 1.0, 0));
} }
this.lambdacontrols_driftingPrevented = true; this.lambdacontrols$driftingPrevented = true;
} else } else
this.lambdacontrols_driftingPrevented = false; this.lambdacontrols$driftingPrevented = false;
} }
} }
} }
@Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick(Z)V", shift = At.Shift.AFTER)) @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick(Z)V", shift = At.Shift.AFTER))
public void onInputUpdate(CallbackInfo ci) public void onInputUpdate(CallbackInfo ci) {
{
MovementHandler.HANDLER.applyMovement((ClientPlayerEntity) (Object) this); MovementHandler.HANDLER.applyMovement((ClientPlayerEntity) (Object) this);
} }
@Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isCamera()Z")) @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isCamera()Z"))
public void onTickMovement(CallbackInfo ci) public void onTickMovement(CallbackInfo ci) {
{ if (this.getAbilities().flying && this.isCamera()) {
if (this.abilities.flying && this.isCamera()) {
if (LambdaControlsClient.get().config.hasFlyVerticalDrifting()) if (LambdaControlsClient.get().config.hasFlyVerticalDrifting())
return; return;
int moving = 0; int moving = 0;

View File

@@ -0,0 +1,58 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package dev.lambdaurora.lambdacontrols.client.mixin;
import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen;
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.option.ControlsOptionsScreen;
import net.minecraft.client.gui.screen.option.GameOptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.CyclingButtonWidget;
import net.minecraft.client.option.GameOptions;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* Injects the new controls settings button.
*/
@Mixin(ControlsOptionsScreen.class)
public class ControlsOptionsScreenMixin extends GameOptionsScreen {
public ControlsOptionsScreenMixin(Screen parent, GameOptions gameOptions, Text text) {
super(parent, gameOptions, text);
}
@SuppressWarnings("unchecked")
@Redirect(
method = "init",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/gui/screen/option/ControlsOptionsScreen;addDrawableChild(Lnet/minecraft/client/gui/Element;)Lnet/minecraft/client/gui/Element;",
ordinal = 1
)
)
private <T extends Element & Drawable & Selectable, R extends Element & Drawable & Selectable> R onInit(ControlsOptionsScreen screen, T element) {
/*if (this.parent instanceof ControllerControlsWidget)
return this.addButton(btn);
else*/
if (element instanceof CyclingButtonWidget btn) {
return (R) this.addDrawableChild(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((ClickableWidgetAccessor) btn).getHeight(),
new TranslatableText("menu.options"),
b -> this.client.openScreen(new LambdaControlsSettingsScreen(this, true))));
} else {
return (R) this.addDrawableChild(element);
}
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,7 +7,7 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemGroup;
@@ -22,12 +22,11 @@ import org.spongepowered.asm.mixin.gen.Invoker;
* Represents an accessor to CreativeInventoryScreen. * Represents an accessor to CreativeInventoryScreen.
*/ */
@Mixin(CreativeInventoryScreen.class) @Mixin(CreativeInventoryScreen.class)
public interface CreativeInventoryScreenAccessor public interface CreativeInventoryScreenAccessor {
{
/** /**
* Gets the selected tab. * Gets the selected tab.
* *
* @return The selected tab index. * @return the selected tab index
*/ */
@Accessor("selectedTab") @Accessor("selectedTab")
int getSelectedTab(); int getSelectedTab();
@@ -35,25 +34,25 @@ public interface CreativeInventoryScreenAccessor
/** /**
* Sets the selected tab. * Sets the selected tab.
* *
* @param group The tab's item group. * @param group the tab's item group
*/ */
@Invoker("setSelectedTab") @Invoker("setSelectedTab")
void lambdacontrols_setSelectedTab(@NotNull ItemGroup group); void lambdacontrols$setSelectedTab(@NotNull ItemGroup group);
/** /**
* Returns whether the slot belongs to the creative inventory or not. * Returns whether the slot belongs to the creative inventory or not.
* *
* @param slot The slot to check. * @param slot the slot to check
* @return True if the slot is from the creative inventory, else false. * @return true if the slot is from the creative inventory, else false
*/ */
@Invoker("isCreativeInventorySlot") @Invoker("isCreativeInventorySlot")
boolean lambdacontrols_isCreativeInventorySlot(@Nullable Slot slot); boolean lambdacontrols$isCreativeInventorySlot(@Nullable Slot slot);
/** /**
* Returns whether the current tab has a scrollbar or not. * Returns whether the current tab has a scrollbar or not.
* *
* @return True if the current tab has a scrollbar, else false. * @return true if the current tab has a scrollbar, else false
*/ */
@Invoker("hasScrollbar") @Invoker("hasScrollbar")
boolean lambdacontrols_hasScrollbar(); boolean lambdacontrols$hasScrollbar();
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,15 +7,14 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import net.minecraft.client.gui.widget.EntryListWidget; import net.minecraft.client.gui.widget.EntryListWidget;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker; import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(EntryListWidget.class) @Mixin(EntryListWidget.class)
public interface EntryListWidgetAccessor public interface EntryListWidgetAccessor {
{
@Invoker("moveSelection") @Invoker("moveSelection")
void lambdacontrols_moveSelection(EntryListWidget.MoveDirection direction); void lambdacontrols$moveSelection(EntryListWidget.MoveDirection direction);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,9 +7,9 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import net.minecraft.client.options.GameOptions; import net.minecraft.client.option.GameOptions;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -22,14 +22,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* Sets the default of the Auto-Jump option to false. * Sets the default of the Auto-Jump option to false.
*/ */
@Mixin(GameOptions.class) @Mixin(GameOptions.class)
public class GameOptionsMixin public class GameOptionsMixin {
{
@Shadow @Shadow
public boolean autoJump; public boolean autoJump;
@Inject(method = "load", at = @At("HEAD")) @Inject(method = "load", at = @At("HEAD"))
public void onInit(CallbackInfo ci) public void onInit(CallbackInfo ci) {
{
// Set default value of the Auto-Jump option to false. // Set default value of the Auto-Jump option to false.
this.autoJump = false; this.autoJump = false;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,10 +7,10 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import me.lambdaurora.lambdacontrols.ControlsMode; import dev.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.GameRenderer; import net.minecraft.client.render.GameRenderer;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@@ -21,15 +21,13 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class) @Mixin(GameRenderer.class)
public class GameRendererMixin public class GameRendererMixin {
{
@Shadow @Shadow
@Final @Final
private MinecraftClient client; private MinecraftClient client;
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Mouse;getX()D")) @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Mouse;getX()D"))
private void onRender(float tickDelta, long startTime, boolean fullRender, CallbackInfo ci) private void onRender(float tickDelta, long startTime, boolean fullRender, CallbackInfo ci) {
{
if (this.client.currentScreen != null && LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) if (this.client.currentScreen != null && LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER)
LambdaControlsClient.get().input.onPreRenderScreen(this.client, this.client.currentScreen); LambdaControlsClient.get().input.onPreRenderScreen(this.client, this.client.currentScreen);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,13 +7,13 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import me.lambdaurora.lambdacontrols.ControlsMode; import dev.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import dev.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer; import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; import dev.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
@@ -32,8 +32,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* Represents the mixin for the class ContainerScreen. * Represents the mixin for the class ContainerScreen.
*/ */
@Mixin(HandledScreen.class) @Mixin(HandledScreen.class)
public abstract class HandledScreenMixin implements HandledScreenAccessor public abstract class HandledScreenMixin implements HandledScreenAccessor {
{
@Accessor("x") @Accessor("x")
public abstract int getX(); public abstract int getX();
@@ -41,19 +40,18 @@ public abstract class HandledScreenMixin implements HandledScreenAccessor
public abstract int getY(); public abstract int getY();
@Invoker("getSlotAt") @Invoker("getSlotAt")
public abstract Slot lambdacontrols_getSlotAt(double posX, double posY); public abstract Slot lambdacontrols$getSlotAt(double posX, double posY);
@Invoker("isClickOutsideBounds") @Invoker("isClickOutsideBounds")
public abstract boolean lambdacontrols_isClickOutsideBounds(double mouseX, double mouseY, int x, int y, int button); public abstract boolean lambdacontrols$isClickOutsideBounds(double mouseX, double mouseY, int x, int y, int button);
@Invoker("onMouseClick") @Invoker("onMouseClick")
public abstract void lambdacontrols_onMouseClick(@Nullable Slot slot, int slotId, int clickData, SlotActionType actionType); public abstract void lambdacontrols$onMouseClick(@Nullable Slot slot, int slotId, int clickData, SlotActionType actionType);
@Inject(method = "render", at = @At("RETURN")) @Inject(method = "render", at = @At("RETURN"))
public void onRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) public void onRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) {
{
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) { if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
MinecraftClient client = MinecraftClient.getInstance(); var client = MinecraftClient.getInstance();
int x = 2, y = client.getWindow().getScaledHeight() - 2 - LambdaControlsRenderer.ICON_SIZE; int x = 2, y = client.getWindow().getScaledHeight() - 2 - LambdaControlsRenderer.ICON_SIZE;
x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, "lambdacontrols.action.pickup_all", true, client) + 2; x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, "lambdacontrols.action.pickup_all", true, client) + 2;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of LambdaControls.
* *
@@ -7,16 +7,15 @@
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.mixin; package dev.lambdaurora.lambdacontrols.client.mixin;
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; import dev.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.option.KeyBinding;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@Mixin(KeyBinding.class) @Mixin(KeyBinding.class)
public class KeyBindingMixin implements KeyBindingAccessor public class KeyBindingMixin implements KeyBindingAccessor {
{
@Shadow @Shadow
private int timesPressed; private int timesPressed;
@@ -24,8 +23,7 @@ public class KeyBindingMixin implements KeyBindingAccessor
private boolean pressed; private boolean pressed;
@Override @Override
public boolean lambdacontrols_press() public boolean lambdacontrols$press() {
{
boolean oldPressed = this.pressed; boolean oldPressed = this.pressed;
if (!this.pressed) if (!this.pressed)
this.pressed = true; this.pressed = true;
@@ -34,8 +32,7 @@ public class KeyBindingMixin implements KeyBindingAccessor
} }
@Override @Override
public boolean lambdacontrols_unpress() public boolean lambdacontrols$unpress() {
{
if (this.pressed) { if (this.pressed) {
this.pressed = false; this.pressed = false;
return true; return true;

Some files were not shown because too many files have changed in this diff Show More