Compare commits

..

62 Commits

Author SHA1 Message Date
Motschen
df7c7bbdad MidnightControls 1.3.0 - Fixes and Improvements
- Merge #48 (Split rotation speed in X and Y, thanks to @ronniedude)
- Merge #47 (Korean translations by @gyular)
- Fix #50 (Stack pick-up problems in survival mode)
- Add some compatibility measures for EMI (Will likely be improved further in the future)
- Remove all REI-related code (not working anyway, EMI is better)
- Possibly fix #41 (Random crashes when changing keybinds)
2022-06-30 21:29:59 +02:00
Martin Prokoph
3ddae57eab Merge pull request #47 from gyular/ko_kr
Added Korean Translation
2022-06-30 19:20:55 +00:00
Martin Prokoph
a0701f55f6 Merge pull request #48 from ronniedude/1.19
Split rotationspeed option to allow for separate horizontal and vertical speeds (controller)
2022-06-30 15:03:02 +00:00
ronniedude
b15766dfdb Split rotationspeed option to allow for separate horizontal and vertical speed configurations (controller) 2022-06-29 16:55:15 -04:00
gyular
19ed068da9 Added Korean Translation 2022-06-28 01:53:56 +09:00
Motschen
d2e21f8723 MidnightControls 1.2.2 - Important Bugfix
Fix #45
Fix #44
2022-06-27 14:10:03 +02:00
Motschen
b3f7350de9 MidnightControls 1.2.1 - Fix log spam 2022-06-25 22:21:51 +02:00
Motschen
34408d7a2a MidnightControls 1.2.0 - Touchscreen, Modded Keybinds, Bugfixes
- Added #40 (Modded keybind support)
- Added #20 (Touchscreen support)
- Improved #13 (Sodium screen controller support)
- Attempt to fix #31 & #38 (Jittery input on low FPS)
- Fixed #35 (Front placing being broken)
- Fixed #32 (Option to disable double tap to sprint)
- Fixed #27 (Auto-adapt controller icons)
- Fixed #19 (HUD-scaling on big scales)
- Fixed #36 (Crash on game load)
- Fixed reset option
- Fixed scrolling in trading screens
- Disable features that might be considered as cheats (install MidnightControlsExtra to enable)
2022-06-25 21:23:25 +02:00
Motschen
6e64c7c97d MidnightControls 1.1.0 - 1.19, Inventory Improvements
- Update to 1.19
- Make buttons for Item/Stack Grabbing and Quick Moving configurable
- Add Keybinds for moving between Fabric Creative Inventory Pages
2022-06-09 21:59:26 +02:00
Martin Prokoph
bca73c93cc Merge pull request #29 from akemin-dayo/1.18
OkZoomerCompat, MidnightControlsCompat: Added compatibility with Ok Zoomer 5.0.0-beta.7 (Quilt).
2022-06-09 14:30:39 +00:00
Karen/あけみ
913e79fe5b OkZoomerCompat, MidnightControlsCompat: Added some more comments in the code. 2022-06-08 20:45:50 -07:00
Karen/あけみ
b1334a0455 OkZoomerCompat, MidnightControlsCompat: Added compatibility with Ok Zoomer 5.0.0-beta.7 (Quilt). Tested with Minecraft 1.18.2, Ok Zoomer 5.0.0-beta.7, quilted-fabric-api/QSL 1.1.0-beta.17 (implementing Fabric API 0.55.1 and QFAPI 1.0.0-beta.19), and Quilt Loader 0.17.0-beta.2. And yes, MidnightControls works with Quilt. 2022-06-08 20:40:35 -07:00
Motschen
ce9495c79c Fix vanilla mouseScreens not working in production 2022-05-08 19:42:41 +02:00
Motschen
ff8270d18a MidnightControls 1.0.0 - Bedrock icon resourcepack
- Bring back Lambda-style XBox icons and add optional resourcepack for Bedrock-style icons (Closes #16)
- Make screens on which the controller behaves like a mouse configurable in the advanced config.
2022-05-08 18:46:46 +02:00
Martin Prokoph
3f33549760 Merge pull request #18 from akemin-dayo/1.18
MidnightControlsSettingsScreen: Fix midnightcontrols.tooltip.controls_mode localisation key, which somehow got clobbered in commit SHA1 0226bfc62f.
2022-05-03 20:59:43 +02:00
Karen/あけみ
d034607032 Merge branch '1.18' of https://github.com/TeamMidnightDust/MidnightControls into 1.18
* '1.18' of https://github.com/TeamMidnightDust/MidnightControls:
  Fix crash on resizing options screen
  MidnightControls 0.3.0 - Automatic mapping downloading
2022-05-03 11:54:22 -07:00
Karen/あけみ
e9a11c0ab9 MidnightControlsSettingsScreen: Fix midnightcontrols.tooltip.controls_mode localisation key, which somehow got clobbered in commit SHA1 0226bfc62f. 2022-05-03 11:50:00 -07:00
Motschen
e0d90fc56a Fix crash on resizing options screen 2022-05-03 20:41:24 +02:00
Motschen
cac23d12a1 MidnightControls 0.3.0 - Automatic mapping downloading
- Automatic downloading of mappings from https://github.com/gabomdq/SDL_GameControllerDB
- Change some default settings
- Fix OkZoomer compat by @akemin-dayo
- German translations (by myself)
- Add contributors to fabric.mod.json
- Fix some issues
2022-05-03 20:29:29 +02:00
Martin Prokoph
b982772d31 Merge pull request #17 from akemin-dayo/akemi-ok-zoomer-compat
OkZoomerCompat, MidnightControlsCompat: Major rewrite that now adds compatibility with both 5.0.0-beta Ok Zoomer API versions via Reflection.
2022-05-03 17:23:59 +02:00
Martin Prokoph
e4ca0db2a2 Merge pull request #15 from akemin-dayo/1.18
Added an option to always show the HUD while in Controller Mode, matching the legacy behaviour of LambdaControls. Also changed some default settings to be "safe" in the sense that the features that can be considered "cheating" in multiplayer servers are now disabled by default.
2022-05-03 17:23:45 +02:00
Karen/あけみ
f0cd2a51d1 build.gradle, gradle.properties: Temporarily comment out Ok Zoomer and LibZoomer dependencies, since we don't use them right now as OkZoomerCompat uses Reflection at runtime instead to deal with the current API incompatibility situation. 2022-05-03 07:50:08 -07:00
Karen/あけみ
9d37862144 OkZoomerCompat, MidnightControlsCompat: Major rewrite that now adds compatibility with both 5.0.0-beta Ok Zoomer API versions via Reflection. This fully fixes all current Ok Zoomer-related crashing issues, such as those encountered in #3. Tested with Minecraft 1.18.2 (5.0.0-beta.6) and Minecraft 1.18.1 (5.0.0-beta.3). 2022-05-03 07:43:06 -07:00
Karen/あけみ
c31fb76215 MidnightControlsConfig: Changed some default settings to be "safe" in the sense that the features that can be considered "cheating" in multiplayer servers are now disabled by default. 2022-05-03 05:02:23 -07:00
Karen/あけみ
b6563af2b1 hud_always_show: Add untranslated strings to es_mx, fr_ca, fr_ft, tr_tr, and zh_cn. 2022-05-03 04:54:07 -07:00
Karen/あけみ
1a0030a680 Added an option to always show the HUD while in Controller Mode, matching the legacy behaviour of LambdaControls. This option is enabled by default so that users migrating from LambdaControls will have a consistent experience. 2022-05-03 04:53:45 -07:00
Motschen
78c858b753 Refresh MidnightControlsFeature state on config change 2022-05-03 12:59:08 +02:00
Martin Prokoph
24288b3ebd Update README.md 2022-05-03 10:25:09 +00:00
Motschen
0226bfc62f MidnightControls 0.2.0 - Fixes, improvements, compat
- Fix #4
- Fix #3 (maybe?)
- No longer break OptiFabric
- Better XBox controller icons (#7) by @Ivanoks
- Start of reimplementing REI compat
- Hide HUD when controller is missing
2022-05-03 12:22:20 +02:00
Martin Prokoph
28d92a65d4 Merge pull request #8 from DioEgizio/patch-1
fix links in fmj
2022-04-29 18:28:19 +02:00
DioEgizio
132bdc0cc5 fix links in fmj
fix links in fabric.mod.json
2022-04-21 16:48:43 +02:00
Motschen
bdffef681f Update CHANGELOG.md 2022-03-16 16:40:57 +01:00
Motschen
a49a64ef44 Update README.md 2022-03-12 23:12:17 +01:00
Motschen
0e192b2af4 Merge branch '1.18' of https://github.com/Motschen/LambdaControls into 1.18 2022-03-12 23:10:33 +01:00
Motschen
6dd654f2f5 Update metafiles 2022-03-12 23:10:29 +01:00
Motschen
eb406a4681 Update README.md 2022-03-12 23:02:55 +01:00
Motschen
d386e3d9a2 Update README.md 2022-03-12 23:02:10 +01:00
Motschen
5fcf4c2b1b MidnightControls 0.1.0 (Beta)
Changes from LambdaControls:
- Support for Steam Deck and Dualsense
- Support for L4, L5, R4, R5 buttons
- Updated Libraries
- New Logo and Name
- Lots of Bugfixes
- MidnightConfig backend
2022-03-12 22:33:19 +01:00
Hambaka
bfaa4f5d9a Update Simplified Chinese translation (#74)
Add back the missing Simplified Chinese translation in 1.17 branch from 1.16 branch (don't know why the lang file in 1.17 branch only has 135 lines, it feels like Neubulae's previous pr is disappeared)
Also adjust some translations based on to Neubulae's version.
2021-08-24 17:27:21 +02:00
Ennui Langeweile
5d5d808403 Update and fix Ok Zoomer compatibility (#68) 2021-07-15 01:28:02 +02:00
LambdAurora
d08647b3fc Tweak buildscript. 2021-07-15 01:14:37 +02:00
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
168 changed files with 8347 additions and 9612 deletions

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

@@ -0,0 +1,23 @@
name: Gradle Build
on: [ push, pull_request ]
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 }}
midnightcontrols_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,22 @@
# Changelog # Changelog
## v1.0.0 # MidnightControls
## 0.1.0
First beta!
Changes from LambdaControls:
- Support for Steam Deck and Dualsense
- Support for L4, L5, R4, R5 buttons
- Updated Libraries
- New Logo and Name
- Lots of Bugfixes
- MidnightConfig backend
# LambdaControls
## 1.0.0
:tada: First release! :tada: :tada: First release! :tada:
@@ -12,11 +28,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 +40,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 +62,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 +76,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 +106,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 +120,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

@@ -1,8 +1,8 @@
# Contributing to LambdaControls # Contributing to midnightcontrols
:tada: First of all, thanks for taking time to contribute! :tada: :tada: First of all, thanks for taking time to contribute! :tada:
The following is a set of guidelines for contributing to LambdaControls. The following is a set of guidelines for contributing to MidnightControls.
Feel free to propose changes to this document in a pull request. Feel free to propose changes to this document in a pull request.
**Table of Contents** **Table of Contents**
@@ -17,8 +17,8 @@ Feel free to propose changes to this document in a pull request.
## Code of Conduct ## Code of Conduct
This project and everyone participating in it is governed by the [Code of Conduct](https://github.com/LambdAurora/LambdaControls/blob/master/CODE_OF_CONDUCT.md). This project and everyone participating in it is governed by the [Code of Conduct](https://github.com/LambdAurora/midnightcontrols/blob/master/CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable behavior at [aurora42lambda@gmail.com](mailto:aurora42lambda@gmail.com). By participating, you are expected to uphold this code. Please report unacceptable behavior at [motschen@midnightdust.eu](mailto:motschen@midnightdust.eu).
## What should I know before I get started? ## What should I know before I get started?
@@ -26,9 +26,9 @@ 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 17
Java is the main language used to make LambdaControls alive. Java is the main language used to make MidnightControls 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.
### Minecraft ### Minecraft
@@ -45,9 +45,9 @@ As it is a Minecraft mod you should know a bit how Minecraft works and how moddi
### Git ### Git
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 midnightcontrols, 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,21 +55,21 @@ 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/TeamMidnightDust/MidnightControls/blob/1.18/.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/TeamMidnightDust/MidnightControls/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/TeamMidnightDust/MidnightControls/blob/1.17/.github/ISSUE_TEMPLATE/feature_request.md) guide.
### Do pull requests ### Do pull requests
You can help LambdaControls by writing code and submit it with pull requests. You can help midnightcontrols by writing code and submit it with pull requests.
Pull requests will be accepted if they follow the [styleguide](#styleguides), if they are useful, etc... Pull requests will be accepted if they follow the [styleguide](#styleguides), if they are useful, etc...
We can refuse a pull request if the commits are not signed, so don't forget to [sign them](https://help.github.com/en/articles/signing-commits)! We can refuse a pull request if the commits are not signed, so don't forget to [sign them](https://help.github.com/en/articles/signing-commits)!
@@ -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

7
HEADER Normal file
View File

@@ -0,0 +1,7 @@
Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
Copyright © 2022 Motschen <motschen@midnightdust.eu>
This file is part of MidnightControls.
Licensed under the MIT license. For more information,
see the LICENSE file.

View File

@@ -1,6 +1,7 @@
MIT License MIT License
Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
Copyright © 2022 Motschen <motschen@midnightdust.eu>
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
@@ -18,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View File

@@ -1,13 +1,16 @@
# LambdaControls # MidnightControls
![Java 8](https://img.shields.io/badge/language-Java%208-9B599A.svg?style=flat-square) <!-- modrinth_exclude.start -->
[![GitHub license](https://img.shields.io/github/license/LambdAurora/LambdaControls?style=flat-square)](https://raw.githubusercontent.com/LambdAurora/LambdaControls/master/LICENSE) ![Java 16](https://img.shields.io/badge/language-Java%2017-9B599A.svg?style=flat-square) <!-- modrinth_exclude.end -->
[![GitHub license](https://img.shields.io/github/license/TeamMidnightDust/MidnightControls?style=flat-square)](https://raw.githubusercontent.com/TeamMidnightDust/MidnightControls/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: Quilt/Fabric]][quilt] <!-- 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/TeamMidnightDust/MidnightControls?label=version&style=flat-square)](https://github.com/TeamMidnightDust/MidnightControls/releases)
[![CurseForge](http://cf.way2muchnoise.eu/title/354231.svg)](https://www.curseforge.com/minecraft/mc-mods/lambdacontrols) [![CurseForge](http://cf.way2muchnoise.eu/title/621768.svg)](https://www.curseforge.com/minecraft/mc-mods/midnightcontrols)
<!-- 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.
Forked from [LambdaControls](https://github.com/LambdAurora/LambdaControls) by the amazing [LambdAurora](https://github.com/LambdAurora), which was sadly discontinued.
## What's this mod? ## What's this mod?
@@ -19,27 +22,39 @@ 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 simple 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 - DualSense controllers
- Switch Pro controllers - Xbox controllers
- Joycons - Switch Pro controllers
- And many more! - Joy-Cons
- Steam controller and Steam Deck (WIP)
- 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 -->
[quilt]: https://quiltmc.org
[Mod loader: Quilt/Fabric]: https://img.shields.io/badge/modloader-Quilt%2FFabric-blueviolet?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAADGAAAAxgGwdJvFAAAFU0lEQVR4nO1bwW7bOBCdCHtP+wUNxIvhS7yA7kkPOjf9AKPam4/OF2zzB96bblXhH0jPPkS5G1jnIvgib/IFtX/ALoYZemmKtEWRRe3aDzAsURbJGQ6HM4/02Wq1gmNGcNTSnxQA8IdakDK4AOCfJpj3SpiI98r2rAMAbxrWNWFFOMeL1nCJdXQa1gPTbpCbnm34ABIeBThv2hgAfOyVcF+2ZwkAfHGo54kVIRe6NVxiny4d6vpn2g36ugfqFLhwFB6kkUoc67k0XLv0qYKj9wEnBXiqZwEAf/ZKOOuV8BkLWBFesyI8A4C/LOt6AoC39C7HtBvg9Vt65hUnC/BUDzrOf1MGq5S9WkDZnuVle7ZqsBKgw/tO73K0hku8/u64EmhxsoA96MMvxdEroBIKO+CWoshnqqJPYTAGRJ8sql3QO3Op7D19D3z7AV8KeAGArFf+32lWhDwnKNuzuaUCclaE93KBiOU9hMQV+FLAOxz9lPHRR0VkZXs2oBDUNon5ULZnKOgcYwl4FTwna/K+CtRRwIK+dTnCCwkP9I0fkXmh4FcN+6UKqqtHblvtb+18po4TvKaPilsS8qVuYx5havsbJXS1I0ZVAXP1B5jfyzm+hAnN+We1XPluioX03kJtY9oNtG1T+b1aburDxhRAQVMGHw3z9k65F41nktmjUnjjrAj7ZXv27ECIyEKgBd7saBuka7lsPu0GA1MjR0+KVpwgMTlrMkN4YoztlZ/2camTvD0QjcWZF6KxMgcLyKbdAN+HKOb1y6PYH49gEsUwUKw1G48gi2KQZcApkYxH1eldUQBxeKbkRfXEQjDZ21+h2bMiHJDwH2wk1rSX0XWueHZd2yCZ/oVSnilTaA3VAiqjRRahQ0JBjuov3ijfPqAua0kUg67tmyjWCmvsS504wGQRnywjPJ8wtY3xw3827fjMBXziUalL3DcNrIzYRwXcTbvBZ7lgPHoNxKKYky1/+2xsHxXQbw2X/EIoggQHyjC9Yh8VcC6NshDc66jLOHpC5KSAPejDL8U+KuArboTQZgjHeARn+MFnvhvbRyfYaQ2XfNkTVFgUr/mIxlvkJuyjAjCae6BrYQUPW37vhDpT4MnAsCyIgbHBnYbcADJt7/t+deBCiSWsCG8sOv5IgU2FnJh2g+RnBDl1oCpgogqEx1TEURUFokx+tpCYnEzzjg1kh+fq/Ix9OXpG6OjjgI1VIGWcOMhlXh4PPdAz1VTe90rIU8Z/L9JUnALXSK4SjSUzOY+Y1ekyOlzjaamTvf3X8cjunBH1v6OeVtsG1QI66qYEVkoVmyA/O5fYmIHjgSsrskUavAc6q1BLeXXiANMZu0HKwGav7opGv+LticZqHOToLBeZrJRxC97qjOsowCTgZYO9OlNa25haMwgvsFMJPp3gLW1ji8b6dO89fhfYIbzAl23T4adtjyNvD6/mbbs9Xgs1hRcwWoIvCxDb47nQNm5aRDHvoPGcblNYCi+gtQSfU+AdLYfioLXYtHA9eruBhsILVJRwUIGQo/ACG0o4GAV4El5grQSffMA3SqbEnBdb1zeunfYsvAB3jL4UwE92KauA2NnNbLerNKhEqJ6Q+FIAOjpcATAVzjFHoC3qC9OurCW0W9s+6vXpAy4p0hPkSUL3ziNHiY3tqfNdQN4jORgnSEGMLyU8Udbq1QIEdEyRF3hSwlp4vKkwQimrHDuxAR6S4tleFIPzERnhSFXQEtbkD1kbwiMOlhJroISK8IiDpcQsp4NWeMRBc4I1lWAUHnHwpOgOJWwVHvFbsMIGJewUHvFb7QuQYxR/ttgIzbUAgB9KOM3uc+PN7QAAAABJRU5ErkJggg==

View File

@@ -1,57 +1,259 @@
plugins { plugins {
id 'java-library' id 'fabric-loom' version '0.11-SNAPSHOT'
id 'maven-publish' id 'java-library'
id 'maven-publish'
id 'com.github.johnrengelman.shadow' version '7.0.0'
id 'com.modrinth.minotaur' version '1.2.+'
} }
allprojects { import com.google.gson.GsonBuilder
group = project.maven_group import com.google.gson.JsonObject
version = project.mod_version 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 = 17
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")
} boolean pingUrl(String address) {
} try {
} def conn = (HttpURLConnection) new URL(address).openConnection()
} int responseCode = conn.getResponseCode()
return (200 <= responseCode && responseCode <= 399)
} catch (IOException ignored) {
return false
}
}
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, '')
return readme
}
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/artifactory/libs-snapshot'
}
maven { url "https://maven.terraformersmc.com/releases/" }
maven { url 'https://maven.kosmx.dev' }
maven { url 'https://maven.shedaniel.me/' }
maven { url 'https://jitpack.io' }
maven { url "https://api.modrinth.com/maven" }
maven { url 'https://maven.quiltmc.org/repository/release'}
}
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}"
api('org.aperlambda:lambdajcommon:1.8.1') {
exclude group: 'com.google.code.gson'
exclude group: 'com.google.guava'
}
include 'org.aperlambda:lambdajcommon:1.8.1'
modImplementation "com.terraformersmc:modmenu:${project.modmenu_version}"
// Compatibility mods
// Ok Zoomer and LibZoomer are temporarily disabled for the time being, as we are currently using Reflection at runtime instead in OkZoomerCompat due to there being two major, completely incompatible API versions.
// modImplementation("maven.modrinth:ok-zoomer:${project.ok_zoomer_version}")
// modImplementation "io.github.ennuil:LibZoomer:${project.libzoomer_version}"
modImplementation "org.quiltmc:quilt-json5:1.0.0"
modApi "maven.modrinth:sodium:${project.sodium_version}"
//modImplementation("maven.modrinth:emi:${project.emi_version}")
modImplementation "maven.modrinth:emotecraft:${project.emotecraft_version}"
modImplementation "io.github.kosmx:bendy-lib:${project.bendylib_version}"
modImplementation "maven.modrinth:midnightlib:${project.midnightlib_version}"
include "maven.modrinth:midnightlib:${project.midnightlib_version}"
shadow 'com.electronwill.night-config:core:3.6.3'
shadow 'com.electronwill.night-config:toml:3.6.3'
}
loom {
accessWidenerPath = file("src/main/resources/midnightcontrols.accesswidener")
}
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
}
}
task publishModrinth(type: TaskModrinthUpload) {
dependsOn(build)
onlyIf {
System.getenv('MODRINTH_TOKEN')
}
token = System.getenv('MODRINTH_TOKEN')
projectId = project.modrinth_id
versionNumber = version
versionName = "midnightcontrols ${project.mod_version} (${getMCVersionString()})"
addGameVersion((String) project.minecraft_version)
addLoader('fabric')
versionType = isMCVersionNonRelease() ? VersionType.BETA : VersionType.RELEASE
// Changelog fetching
def changelogText = file('CHANGELOG.md').text
def regexVersion = ((String) project.mod_version).replaceAll('\\.', /\\./).replaceAll('\\+', '\\+')
def changelogRegex = ~"###? ${regexVersion}\\n\\n(( *- .+\\n)+)"
def matcher = changelogText =~ changelogRegex
if (matcher.find()) {
changelog = matcher.group(1)
def changelogLines = changelogText.split('\n')
def linkRefRegex = ~'^\\[([A-z0-9 _\\-/+.]+)]: '
for (int i = changelogLines.length - 1; i > 0; i--) {
def line = changelogLines[i]
if ((line =~ linkRefRegex).find())
changelog += '\n' + line
else break
}
}
// Readme
doFirst {
final def client = HttpClientBuilder.create().setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).build()).build()
final def patch = new HttpPatch((String) (apiURL + '/v1/mod/' + projectId))
patch.addHeader("Authorization", token)
var json = new JsonObject()
json.addProperty("body", parseReadme())
patch.setEntity(EntityBuilder.create()
.setText(json.toString())
.setContentType(ContentType.APPLICATION_JSON)
.build())
final def response = client.execute(patch)
final int status = response.getStatusLine().getStatusCode()
final def gson = new GsonBuilder().create()
if (status == 200) {
project.getLogger().lifecycle("Successfully updated readme to ${projectId}.")
} else {
errorInfo = gson.fromJson(EntityUtils.toString(response.getEntity()), ResponseError.class)
project.getLogger().error("Upload failed! Status: ${status} Error: ${errorInfo.getError()} Reason: ${errorInfo.getDescription()}")
throw new GradleException("Upload failed! Status: ${status} Reason: ${errorInfo.getDescription()}")
}
}
} }
/*
// 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(sourcesJar) {
artifact(remapJar) { builtBy remapSourcesJar
builtBy remapJar }
}
artifact(sourcesJar) {
builtBy remapSourcesJar
}
}
}
// select the repositories you want to publish to pom {
repositories { name = 'midnightcontrols'
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/midnightcontrols')
credentials {
username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") ?: System.getenv("TOKEN")
}
}
def midnightcontrolsMaven = System.getenv('midnightcontrols_MAVEN')
if (midnightcontrolsMaven) {
maven {
name 'midnightcontrolsMaven'
url uri(midnightcontrolsMaven)
credentials {
username = project.findProperty('gpr.user') ?: System.getenv('MAVEN_USERNAME')
password = project.findProperty('gpr.key') ?: System.getenv('MAVEN_PASSWORD')
}
}
}
}
}

303
controller.svg Normal file
View File

@@ -0,0 +1,303 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="1024.0px"
height="1024.0px"
viewBox="0 0 1024.0 1024.0"
version="1.1"
id="SVGRoot"
sodipodi:docname="controller.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview893"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:document-units="px"
showgrid="true"
inkscape:zoom="0.42961102"
inkscape:cx="455.06282"
inkscape:cy="790.24975"
inkscape:window-width="1920"
inkscape:window-height="1050"
inkscape:window-x="1920"
inkscape:window-y="30"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid956" />
</sodipodi:namedview>
<defs
id="defs888">
<linearGradient
inkscape:collect="always"
id="linearGradient1152">
<stop
style="stop-color:#ed02a0;stop-opacity:1"
offset="0"
id="stop1148" />
<stop
style="stop-color:#8900cb;stop-opacity:1"
offset="1"
id="stop1150" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient1154"
x1="0"
y1="0"
x2="1020"
y2="1020"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient4289"
x1="0"
y1="0"
x2="1020"
y2="1020"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient4663"
x1="0"
y1="0"
x2="1020"
y2="1020"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient5165"
x1="0"
y1="0"
x2="1020"
y2="1020"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient5507"
gradientUnits="userSpaceOnUse"
x1="0"
y1="0"
x2="1020"
y2="1020" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient5817"
x1="0"
y1="0"
x2="1020"
y2="1020"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient6161"
x1="0"
y1="0"
x2="1020"
y2="1020"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient6535"
x1="0"
y1="0"
x2="1025"
y2="1025"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient7579"
x1="0"
y1="0"
x2="1025"
y2="1025"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient8115"
x1="0"
y1="0"
x2="1025"
y2="1025"
gradientUnits="userSpaceOnUse" />
</defs>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:url(#linearGradient1154);fill-opacity:1"
id="rect1033"
width="1025"
height="1025"
x="0"
y="0"
rx="0"
ry="0" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41813"
id="rect2078"
width="671.12531"
height="330.82504"
x="178.42294"
y="283.78436"
ry="110.27502" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41852"
id="rect2146"
width="199.30905"
height="504.61328"
x="518.59406"
y="450.07187"
ry="97.030388"
transform="matrix(0.97214881,-0.23436445,0.26615211,0.96393104,0,0)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41852"
id="rect2146-3"
width="200.94308"
height="502.92538"
x="271.98715"
y="209.38025"
ry="97.050156"
transform="matrix(0.97237519,0.23342343,-0.26569554,0.96405699,0,0)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41813"
id="rect2384"
width="87.538078"
height="55.137505"
x="251.37137"
y="270"
ry="27.568752" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41813"
id="rect2384-6"
width="87.538078"
height="55.137505"
x="691.97968"
y="270"
ry="27.568752" />
<path
style="fill:url(#linearGradient4663);fill-opacity:1"
id="path2566"
sodipodi:type="arc"
sodipodi:cx="302.43524"
sodipodi:cy="400.95157"
sodipodi:rx="51.063881"
sodipodi:ry="48.245316"
sodipodi:start="2.7492077"
sodipodi:end="2.731929"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 255.25223,419.40025 a 51.063881,48.245316 0 0 1 27.4529,-62.94723 51.063881,48.245316 0 0 1 66.74267,25.66543 51.063881,48.245316 0 0 1 -26.87629,63.16896 51.063881,48.245316 0 0 1 -66.97486,-25.11969" />
<path
style="fill:url(#linearGradient5817);fill-opacity:1"
id="path2566-7"
sodipodi:type="arc"
sodipodi:cx="663.29633"
sodipodi:cy="527.23883"
sodipodi:rx="51.063881"
sodipodi:ry="48.245316"
sodipodi:start="2.7492077"
sodipodi:end="2.731929"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 616.11332,545.68751 a 51.063881,48.245316 0 0 1 27.45289,-62.94723 51.063881,48.245316 0 0 1 66.74267,25.66543 51.063881,48.245316 0 0 1 -26.87628,63.16896 51.063881,48.245316 0 0 1 -66.97487,-25.11969" />
<path
style="fill:url(#linearGradient5165);fill-opacity:1"
id="path2710"
sodipodi:type="arc"
sodipodi:cx="740.12561"
sodipodi:cy="345.81409"
sodipodi:rx="21.88452"
sodipodi:ry="20.676565"
sodipodi:start="2.7492077"
sodipodi:end="2.731929"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 719.90432,353.72066 a 21.88452,20.676565 0 0 1 11.76553,-26.97738 21.88452,20.676565 0 0 1 28.604,10.99947 21.88452,20.676565 0 0 1 -11.51841,27.07241 21.88452,20.676565 0 0 1 -28.70351,-10.76558" />
<path
style="fill:url(#linearGradient5507);fill-opacity:1"
id="path2710-5"
sodipodi:type="arc"
sodipodi:cx="785.35364"
sodipodi:cy="385.78876"
sodipodi:rx="21.88452"
sodipodi:ry="20.676565"
sodipodi:start="2.7492077"
sodipodi:end="2.731929"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 765.13235,393.69534 a 21.88452,20.676565 0 0 1 11.76553,-26.97739 21.88452,20.676565 0 0 1 28.604,10.99947 21.88452,20.676565 0 0 1 -11.51841,27.07241 21.88452,20.676565 0 0 1 -28.70351,-10.76558" />
<path
style="fill:url(#linearGradient6535);fill-opacity:1"
id="path2710-3"
sodipodi:type="arc"
sodipodi:cx="697.81555"
sodipodi:cy="385.78876"
sodipodi:rx="21.88452"
sodipodi:ry="20.676565"
sodipodi:start="2.7492077"
sodipodi:end="2.731929"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 677.59426,393.69534 a 21.88452,20.676565 0 0 1 11.76553,-26.97739 21.88452,20.676565 0 0 1 28.604,10.99947 21.88452,20.676565 0 0 1 -11.51841,27.07241 21.88452,20.676565 0 0 1 -28.70351,-10.76558" />
<path
style="fill:url(#linearGradient6161);fill-opacity:1"
id="path2710-56"
sodipodi:type="arc"
sodipodi:cx="741.58459"
sodipodi:cy="427.14188"
sodipodi:rx="21.88452"
sodipodi:ry="20.676565"
sodipodi:start="2.7492077"
sodipodi:end="2.731929"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 721.36331,435.04845 a 21.88452,20.676565 0 0 1 11.76552,-26.97738 21.88452,20.676565 0 0 1 28.604,10.99947 21.88452,20.676565 0 0 1 -11.51841,27.07241 21.88452,20.676565 0 0 1 -28.70351,-10.76558" />
<rect
style="fill:url(#linearGradient8115);fill-opacity:1;stroke-width:1.41813"
id="rect2896"
width="36.474197"
height="110.27502"
x="369.54779"
y="476.76566"
ry="13.784376" />
<rect
style="fill:url(#linearGradient7579);fill-opacity:1;stroke-width:1.41813"
id="rect2898"
width="116.71745"
height="37.217815"
x="327.2377"
y="512.60504"
ry="13.383304" />
<rect
style="fill:url(#linearGradient4289);fill-opacity:1;stroke-width:1.41813"
id="rect3104"
width="233.43489"
height="110.27502"
x="400.1861"
y="338.92191"
ry="13.383307" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.3 KiB

269
controller_banner.svg Normal file
View File

@@ -0,0 +1,269 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="1920"
height="1080"
viewBox="0 0 1920 1080"
version="1.1"
id="SVGRoot"
sodipodi:docname="controller_banner.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
inkscape:export-filename="/home/martin/Bilder/Bilder/MidnightControlsBanner.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview893"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:document-units="px"
showgrid="true"
inkscape:zoom="0.40120419"
inkscape:cx="928.45492"
inkscape:cy="816.29258"
inkscape:window-width="1920"
inkscape:window-height="1050"
inkscape:window-x="1920"
inkscape:window-y="30"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid956" />
</sodipodi:namedview>
<defs
id="defs888">
<linearGradient
inkscape:collect="always"
id="linearGradient2059">
<stop
style="stop-color:#ed02a0;stop-opacity:0.72909278"
offset="0"
id="stop2055" />
<stop
style="stop-color:#8900cb;stop-opacity:0.73234183"
offset="1"
id="stop2057" />
</linearGradient>
<inkscape:path-effect
effect="powerclip"
id="path-effect904"
is_visible="true"
lpeversion="1"
inverse="true"
flatten="false"
hide_clip="false"
message="Füllregel Gerade-Ungerade im &lt;b&gt;Füllung und Kontur&lt;/b&gt;-Dialog verwenden, wenn das Anwenden des Ausschnitts mit nachfolgendem Umwandeln in Pfade kein Ergebnis bringt" />
<inkscape:path-effect
effect="powerclip"
id="path-effect900"
is_visible="true"
lpeversion="1"
inverse="true"
flatten="false"
hide_clip="false"
message="Füllregel Gerade-Ungerade im &lt;b&gt;Füllung und Kontur&lt;/b&gt;-Dialog verwenden, wenn das Anwenden des Ausschnitts mit nachfolgendem Umwandeln in Pfade kein Ergebnis bringt" />
<inkscape:path-effect
effect="powerclip"
id="path-effect896"
is_visible="true"
lpeversion="1"
inverse="true"
flatten="false"
hide_clip="false"
message="Füllregel Gerade-Ungerade im &lt;b&gt;Füllung und Kontur&lt;/b&gt;-Dialog verwenden, wenn das Anwenden des Ausschnitts mit nachfolgendem Umwandeln in Pfade kein Ergebnis bringt" />
<rect
x="500"
y="800"
width="840"
height="220"
id="rect7833" />
<linearGradient
inkscape:collect="always"
id="linearGradient1152">
<stop
style="stop-color:#ed02a0;stop-opacity:1"
offset="0"
id="stop1148" />
<stop
style="stop-color:#8900cb;stop-opacity:1"
offset="1"
id="stop1150" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2059"
id="linearGradient1154"
x1="0"
y1="0"
x2="1920"
y2="1080"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient4289"
x1="-398"
y1="56"
x2="1522"
y2="1136"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(398,-56)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient7579"
x1="-398"
y1="56"
x2="1522"
y2="1136"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(398,-56)" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath878">
<path
id="path880"
style="display:none;fill:url(#linearGradient882);stroke-width:1.00028"
d="m 1170.0221,-4.111892 a 21.817197,20.751893 3.393352 0 0 -8.3753,3.68511674 21.817197,20.751893 3.393352 0 0 -4.1775,28.99380526 l 0.2304,0.284584 a 21.817197,20.751893 3.393352 0 0 30.5488,3.770316 21.817197,20.751893 3.393352 0 0 3.9128,-29.0289691 21.817197,20.751893 3.393352 0 0 -22.1392,-7.7048529 z M 858.04762,85.714292 c -7.15183,1.731644 -11.32417,8.932859 -9.35312,16.146398 l 22.2005,81.24794 c 1.97106,7.21354 9.31675,11.62594 16.46858,9.8943 L 1086.714,144.73497 c 7.1518,-1.73163 11.3223,-8.9324 9.3512,-16.14595 l -22.2005,-81.247936 c -1.971,-7.213536 -9.3149,-11.626381 -16.4667,-9.894748 z M 756.02165,124.73884 a 50.906793,48.421082 3.3933293 0 0 -19.54511,8.59585 50.906793,48.421082 3.3933293 0 0 -9.74699,67.65414 l 0.53564,0.66651 a 50.906793,48.421082 3.3933293 0 0 71.28286,8.79621 50.906793,48.421082 3.3933293 0 0 9.13065,-67.73384 50.906793,48.421082 3.3933293 0 0 -51.65705,-17.97887 z M 1139.8366,44.661798 a 21.817197,20.751893 3.393352 0 0 -8.3752,3.685094 21.817197,20.751893 3.393352 0 0 -4.1775,28.993805 l 0.2304,0.284584 a 21.817197,20.751893 3.393352 0 0 30.5487,3.770339 21.817197,20.751893 3.393352 0 0 3.9147,-29.029436 21.817197,20.751893 3.393352 0 0 -22.1411,-7.704386 z m 84.4396,-20.445031 a 21.817197,20.751893 3.393352 0 0 -8.3754,3.685117 21.817197,20.751893 3.393352 0 0 -4.1774,28.993806 l 0.2285,0.285027 a 21.817197,20.751893 3.393352 0 0 30.5488,3.77034 21.817197,20.751893 3.393352 0 0 3.9147,-29.02946 21.817197,20.751893 3.393352 0 0 -22.1392,-7.70483 z M 1193.05,74.672751 a 21.817197,20.751893 3.393352 0 0 -8.3759,3.68321 21.817197,20.751893 3.393352 0 0 -4.1769,28.995709 l 0.2303,0.28458 a 21.817197,20.751893 3.393352 0 0 30.5488,3.77035 21.817197,20.751893 3.393352 0 0 3.9128,-29.029006 21.817197,20.751893 3.393352 0 0 -22.1391,-7.704843 z M 865.52481,226.88685 c -7.36616,1.78355 -11.66248,9.20165 -9.63236,16.63136 l 5.86309,21.45735 -27.90161,6.7557 c -7.15183,1.73165 -11.32229,8.9324 -9.35123,16.14595 l 2.77837,10.1681 c 1.97106,7.21354 9.31487,11.6264 16.46669,9.89476 l 27.90161,-6.75571 6.22966,22.7989 c 2.03012,7.42971 9.59558,11.97577 16.96174,10.19223 l 8.59091,-2.08008 c 7.36616,-1.78354 11.6606,-9.2012 9.63048,-16.63091 l -6.22966,-22.7989 23.68151,-5.73391 c 7.15183,-1.73165 11.32229,-8.93242 9.35123,-16.14595 l -2.77837,-10.16811 c -1.97106,-7.21354 -9.31486,-11.62639 -16.46669,-9.89474 l -23.68151,5.73391 -5.86309,-21.45735 c -2.03012,-7.42971 -9.5937,-11.97623 -16.95987,-10.19269 z m 272.15169,-63.56116 a 50.906793,48.421082 3.3933293 0 0 -19.5432,8.59539 50.906793,48.421082 3.3933293 0 0 -9.747,67.65414 l 0.5356,0.66651 a 50.906793,48.421082 3.3933293 0 0 71.2829,8.79621 50.906793,48.421082 3.3933293 0 0 9.1307,-67.73384 50.906793,48.421082 3.3933293 0 0 -51.659,-17.97841 z" />
<path
id="lpe_path-effect896"
style="fill:url(#linearGradient882);stroke-width:1.00028"
class="powerclip"
d="M 636.0108,56.943474 H 846.95389 V 569.86886 H 636.0108 Z m 534.0113,-61.055366 a 21.817197,20.751893 3.393352 0 0 -8.3753,3.68511674 21.817197,20.751893 3.393352 0 0 -4.1775,28.99380526 l 0.2304,0.284584 a 21.817197,20.751893 3.393352 0 0 30.5488,3.770316 21.817197,20.751893 3.393352 0 0 3.9128,-29.0289691 21.817197,20.751893 3.393352 0 0 -22.1392,-7.7048529 z M 858.04762,85.714292 c -7.15183,1.731644 -11.32417,8.932859 -9.35312,16.146398 l 22.2005,81.24794 c 1.97106,7.21354 9.31675,11.62594 16.46858,9.8943 L 1086.714,144.73497 c 7.1518,-1.73163 11.3223,-8.9324 9.3512,-16.14595 l -22.2005,-81.247936 c -1.971,-7.213536 -9.3149,-11.626381 -16.4667,-9.894748 z M 756.02165,124.73884 a 50.906793,48.421082 3.3933293 0 0 -19.54511,8.59585 50.906793,48.421082 3.3933293 0 0 -9.74699,67.65414 l 0.53564,0.66651 a 50.906793,48.421082 3.3933293 0 0 71.28286,8.79621 50.906793,48.421082 3.3933293 0 0 9.13065,-67.73384 50.906793,48.421082 3.3933293 0 0 -51.65705,-17.97887 z M 1139.8366,44.661798 a 21.817197,20.751893 3.393352 0 0 -8.3752,3.685094 21.817197,20.751893 3.393352 0 0 -4.1775,28.993805 l 0.2304,0.284584 a 21.817197,20.751893 3.393352 0 0 30.5487,3.770339 21.817197,20.751893 3.393352 0 0 3.9147,-29.029436 21.817197,20.751893 3.393352 0 0 -22.1411,-7.704386 z m 84.4396,-20.445031 a 21.817197,20.751893 3.393352 0 0 -8.3754,3.685117 21.817197,20.751893 3.393352 0 0 -4.1774,28.993806 l 0.2285,0.285027 a 21.817197,20.751893 3.393352 0 0 30.5488,3.77034 21.817197,20.751893 3.393352 0 0 3.9147,-29.02946 21.817197,20.751893 3.393352 0 0 -22.1392,-7.70483 z M 1193.05,74.672751 a 21.817197,20.751893 3.393352 0 0 -8.3759,3.68321 21.817197,20.751893 3.393352 0 0 -4.1769,28.995709 l 0.2303,0.28458 a 21.817197,20.751893 3.393352 0 0 30.5488,3.77035 21.817197,20.751893 3.393352 0 0 3.9128,-29.029006 21.817197,20.751893 3.393352 0 0 -22.1391,-7.704843 z M 865.52481,226.88685 c -7.36616,1.78355 -11.66248,9.20165 -9.63236,16.63136 l 5.86309,21.45735 -27.90161,6.7557 c -7.15183,1.73165 -11.32229,8.9324 -9.35123,16.14595 l 2.77837,10.1681 c 1.97106,7.21354 9.31487,11.6264 16.46669,9.89476 l 27.90161,-6.75571 6.22966,22.7989 c 2.03012,7.42971 9.59558,11.97577 16.96174,10.19223 l 8.59091,-2.08008 c 7.36616,-1.78354 11.6606,-9.2012 9.63048,-16.63091 l -6.22966,-22.7989 23.68151,-5.73391 c 7.15183,-1.73165 11.32229,-8.93242 9.35123,-16.14595 l -2.77837,-10.16811 c -1.97106,-7.21354 -9.31486,-11.62639 -16.46669,-9.89474 l -23.68151,5.73391 -5.86309,-21.45735 c -2.03012,-7.42971 -9.5937,-11.97623 -16.95987,-10.19269 z m 272.15169,-63.56116 a 50.906793,48.421082 3.3933293 0 0 -19.5432,8.59539 50.906793,48.421082 3.3933293 0 0 -9.747,67.65414 l 0.5356,0.66651 a 50.906793,48.421082 3.3933293 0 0 71.2829,8.79621 50.906793,48.421082 3.3933293 0 0 9.1307,-67.73384 50.906793,48.421082 3.3933293 0 0 -51.659,-17.97841 z" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient882"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.96459266,-0.23355313,0.26584317,0.97291549,369.02066,-147.43741)"
x1="-398"
y1="56"
x2="1522"
y2="1136" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath884">
<path
id="path886"
style="display:none;fill:url(#linearGradient888);stroke-width:1.00027"
d="m 1026.6374,528.82806 a 20.752793,21.815894 86.926601 0 0 -9.2243,-0.58528 20.752793,21.815894 86.926601 0 0 -18.53105,23.48045 l 0.0557,0.35396 a 20.752793,21.815894 86.926601 0 0 24.81605,17.20206 20.752793,21.815894 86.926601 0 0 18.3173,-23.63171 20.752793,21.815894 86.926601 0 0 -15.4337,-16.81948 z M 707.37883,465.4963 c -7.15078,-1.7386 -14.49832,2.66675 -16.47273,9.87849 l -22.23828,81.2277 c -1.97441,7.21175 2.19438,14.41711 9.34515,16.15571 l 199.32113,48.46175 c 7.15073,1.73859 14.49643,-2.66722 16.47084,-9.87896 l 22.23828,-81.2277 c 1.97441,-7.21174 -2.19254,-14.41666 -9.34327,-16.15524 z M 598.02135,453.23104 a 48.423182,50.903752 86.926623 0 0 -21.5241,-1.36927 48.423182,50.903752 86.926623 0 0 -43.23978,54.7896 l 0.12713,0.82721 a 48.423182,50.903752 86.926623 0 0 57.90649,40.13811 48.423182,50.903752 86.926623 0 0 42.74098,-55.13985 48.423182,50.903752 86.926623 0 0 -36.01072,-39.2458 z m 377.16446,104.5578 a 20.752793,21.815894 86.926601 0 0 -9.22414,-0.58526 20.752793,21.815894 86.926601 0 0 -18.53108,23.48045 l 0.0557,0.35396 a 20.752793,21.815894 86.926601 0 0 24.8159,17.20204 20.752793,21.815894 86.926601 0 0 18.31921,-23.63124 20.752793,21.815894 86.926601 0 0 -15.43563,-16.81995 z m 84.42719,20.52712 a 20.752793,21.815894 86.926601 0 0 -9.2243,-0.58529 20.752793,21.815894 86.926601 0 0 -18.531,23.48045 l 0.054,0.35352 a 20.752793,21.815894 86.926601 0 0 24.8159,17.20204 20.752793,21.815894 86.926601 0 0 18.3193,-23.63122 20.752793,21.815894 86.926601 0 0 -15.4338,-16.8195 z m -53.2258,29.9599 a 20.752793,21.815894 86.926601 0 0 -9.22373,-0.58718 20.752793,21.815894 86.926601 0 0 -18.53161,23.48235 l 0.0557,0.35395 a 20.752793,21.815894 86.926601 0 0 24.81584,17.20205 20.752793,21.815894 86.926601 0 0 18.3174,-23.63169 20.752793,21.815894 86.926601 0 0 -15.4337,-16.81948 z M 641.50831,592.48259 c -7.36508,-1.79069 -14.93245,2.74811 -16.96603,10.17597 l -5.87307,21.452 -27.8975,-6.78283 c -7.15078,-1.7386 -14.49644,2.6672 -16.47085,9.87895 l -2.7831,10.16557 c -1.97441,7.21174 2.1925,14.41666 9.34328,16.15525 l 27.8975,6.78284 -6.24026,22.79322 c -2.03358,7.42786 2.25909,14.85024 9.62417,16.64094 l 8.58964,2.08844 c 7.36508,1.7907 14.93057,-2.74856 16.96415,-10.17642 l 6.24026,-22.79322 23.67803,5.75693 c 7.15078,1.7386 14.49644,-2.66722 16.47085,-9.87896 l 2.7831,-10.16557 c 1.97441,-7.21175 -2.1925,-14.41665 -9.34328,-16.15525 l -23.67803,-5.75693 5.87307,-21.45201 c 2.03358,-7.42785 -2.25721,-14.84978 -9.62229,-16.64048 z m 270.91446,68.20272 a 48.423182,50.903752 86.926623 0 0 -21.52221,-1.3688 48.423182,50.903752 86.926623 0 0 -43.23975,54.78961 l 0.12708,0.8272 a 48.423182,50.903752 86.926623 0 0 57.90652,40.13811 48.423182,50.903752 86.926623 0 0 42.74097,-55.13984 48.423182,50.903752 86.926623 0 0 -36.01261,-39.24628 z" />
<path
id="lpe_path-effect900"
style="fill:url(#linearGradient888);stroke-width:1.00027"
class="powerclip"
d="M 912.35657,483.93158 H 1121.6656 V 998.54486 H 912.35657 Z m 114.28083,44.89648 a 20.752793,21.815894 86.926601 0 0 -9.2243,-0.58528 20.752793,21.815894 86.926601 0 0 -18.53105,23.48045 l 0.0557,0.35396 a 20.752793,21.815894 86.926601 0 0 24.81605,17.20206 20.752793,21.815894 86.926601 0 0 18.3173,-23.63171 20.752793,21.815894 86.926601 0 0 -15.4337,-16.81948 z M 707.37883,465.4963 c -7.15078,-1.7386 -14.49832,2.66675 -16.47273,9.87849 l -22.23828,81.2277 c -1.97441,7.21175 2.19438,14.41711 9.34515,16.15571 l 199.32113,48.46175 c 7.15073,1.73859 14.49643,-2.66722 16.47084,-9.87896 l 22.23828,-81.2277 c 1.97441,-7.21174 -2.19254,-14.41666 -9.34327,-16.15524 z M 598.02135,453.23104 a 48.423182,50.903752 86.926623 0 0 -21.5241,-1.36927 48.423182,50.903752 86.926623 0 0 -43.23978,54.7896 l 0.12713,0.82721 a 48.423182,50.903752 86.926623 0 0 57.90649,40.13811 48.423182,50.903752 86.926623 0 0 42.74098,-55.13985 48.423182,50.903752 86.926623 0 0 -36.01072,-39.2458 z m 377.16446,104.5578 a 20.752793,21.815894 86.926601 0 0 -9.22414,-0.58526 20.752793,21.815894 86.926601 0 0 -18.53108,23.48045 l 0.0557,0.35396 a 20.752793,21.815894 86.926601 0 0 24.8159,17.20204 20.752793,21.815894 86.926601 0 0 18.31921,-23.63124 20.752793,21.815894 86.926601 0 0 -15.43563,-16.81995 z m 84.42719,20.52712 a 20.752793,21.815894 86.926601 0 0 -9.2243,-0.58529 20.752793,21.815894 86.926601 0 0 -18.531,23.48045 l 0.054,0.35352 a 20.752793,21.815894 86.926601 0 0 24.8159,17.20204 20.752793,21.815894 86.926601 0 0 18.3193,-23.63122 20.752793,21.815894 86.926601 0 0 -15.4338,-16.8195 z m -53.2258,29.9599 a 20.752793,21.815894 86.926601 0 0 -9.22373,-0.58718 20.752793,21.815894 86.926601 0 0 -18.53161,23.48235 l 0.0557,0.35395 a 20.752793,21.815894 86.926601 0 0 24.81584,17.20205 20.752793,21.815894 86.926601 0 0 18.3174,-23.63169 20.752793,21.815894 86.926601 0 0 -15.4337,-16.81948 z M 641.50831,592.48259 c -7.36508,-1.79069 -14.93245,2.74811 -16.96603,10.17597 l -5.87307,21.452 -27.8975,-6.78283 c -7.15078,-1.7386 -14.49644,2.6672 -16.47085,9.87895 l -2.7831,10.16557 c -1.97441,7.21174 2.1925,14.41666 9.34328,16.15525 l 27.8975,6.78284 -6.24026,22.79322 c -2.03358,7.42786 2.25909,14.85024 9.62417,16.64094 l 8.58964,2.08844 c 7.36508,1.7907 14.93057,-2.74856 16.96415,-10.17642 l 6.24026,-22.79322 23.67803,5.75693 c 7.15078,1.7386 14.49644,-2.66722 16.47085,-9.87896 l 2.7831,-10.16557 c 1.97441,-7.21175 -2.1925,-14.41665 -9.34328,-16.15525 l -23.67803,-5.75693 5.87307,-21.45201 c 2.03358,-7.42785 -2.25721,-14.84978 -9.62229,-16.64048 z m 270.91446,68.20272 a 48.423182,50.903752 86.926623 0 0 -21.52221,-1.3688 48.423182,50.903752 86.926623 0 0 -43.23975,54.78961 l 0.12708,0.8272 a 48.423182,50.903752 86.926623 0 0 57.90652,40.13811 48.423182,50.903752 86.926623 0 0 42.74097,-55.13984 48.423182,50.903752 86.926623 0 0 -36.01261,-39.24628 z" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient888"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.96445087,0.23449084,-0.26629564,0.97267307,398.764,38.857662)"
x1="-398"
y1="56"
x2="1522"
y2="1136" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath890">
<path
id="path892"
style="display:none;fill:url(#linearGradient894)"
d="m 1138.793,269.14648 a 21.88452,20.676565 0 0 0 -9.1231,1.59766 21.88452,20.676565 0 0 0 -11.7656,26.97656 l 0.1484,0.32813 a 21.88452,20.676565 0 0 0 28.7032,10.76562 21.88452,20.676565 0 0 0 11.5175,-27.07226 21.88452,20.676565 0 0 0 -19.4804,-12.59571 z m -327.22269,13.7754 c -7.41435,0 -13.38476,5.96846 -13.38476,13.38281 v 83.50976 c 0,7.41436 5.97041,13.38282 13.38476,13.38282 h 206.66799 c 7.4143,0 13.3828,-5.96846 13.3828,-13.38282 v -83.50976 c 0,-7.41435 -5.9685,-13.38281 -13.3828,-13.38281 z m -109.57617,13.80664 a 51.063881,48.245316 0 0 0 -21.28906,3.7246 51.063881,48.245316 0 0 0 -27.45313,62.94727 l 0.34375,0.76758 a 51.063881,48.245316 0 0 0 66.97657,25.11914 51.063881,48.245316 0 0 0 26.875,-63.16797 51.063881,48.245316 0 0 0 -45.45313,-29.39062 z m 394.48826,12.39257 a 21.88452,20.676565 0 0 0 -9.123,1.59766 21.88452,20.676565 0 0 0 -11.7656,26.97656 l 0.1484,0.32813 a 21.88452,20.676565 0 0 0 28.7031,10.76562 21.88452,20.676565 0 0 0 11.5195,-27.07226 21.88452,20.676565 0 0 0 -19.4824,-12.59571 z m 87.5391,0 a 21.88452,20.676565 0 0 0 -9.1231,1.59766 21.88452,20.676565 0 0 0 -11.7656,26.97656 l 0.1465,0.32813 a 21.88452,20.676565 0 0 0 28.7031,10.76562 21.88452,20.676565 0 0 0 11.5196,-27.07226 21.88452,20.676565 0 0 0 -19.4805,-12.59571 z m -43.7695,41.35352 a 21.88452,20.676565 0 0 0 -9.1231,1.5957 21.88452,20.676565 0 0 0 -11.7656,26.97852 l 0.1484,0.32812 a 21.88452,20.676565 0 0 0 28.7031,10.76563 21.88452,20.676565 0 0 0 11.5176,-27.07227 21.88452,20.676565 0 0 0 -19.4804,-12.5957 z m -358.91997,70.29101 c -7.63655,10e-6 -13.78515,6.14862 -13.78515,13.78516 v 22.05469 h -28.92579 c -7.41435,0 -13.38281,5.96845 -13.38281,13.38281 v 10.45117 c 0,7.41435 5.96846,13.38282 13.38281,13.38282 h 28.92579 v 23.43359 c 0,7.63654 6.1486,13.78516 13.78515,13.78516 h 8.90625 c 7.63655,0 13.7832,-6.14862 13.7832,-13.78516 v -23.43359 h 24.55079 c 7.41435,0 13.38281,-5.96847 13.38281,-13.38282 v -10.45117 c 0,-7.41436 -5.96846,-13.38281 -13.38281,-13.38281 h -24.55079 v -22.05469 c 0,-7.63654 -6.14665,-13.78516 -13.7832,-13.78516 z m 281.52147,2.25 a 51.063881,48.245316 0 0 0 -21.2871,3.72461 51.063881,48.245316 0 0 0 -27.4531,62.94727 l 0.3437,0.76758 a 51.063881,48.245316 0 0 0 66.9766,25.11914 51.063881,48.245316 0 0 0 26.875,-63.16797 51.063881,48.245316 0 0 0 -45.4551,-29.39063 z" />
<path
id="lpe_path-effect904"
style="fill:url(#linearGradient894)"
class="powerclip"
d="M 571.42297,222.78436 H 1252.5483 V 563.60941 H 571.42297 Z m 567.37003,46.36212 a 21.88452,20.676565 0 0 0 -9.1231,1.59766 21.88452,20.676565 0 0 0 -11.7656,26.97656 l 0.1484,0.32813 a 21.88452,20.676565 0 0 0 28.7032,10.76562 21.88452,20.676565 0 0 0 11.5175,-27.07226 21.88452,20.676565 0 0 0 -19.4804,-12.59571 z m -327.22269,13.7754 c -7.41435,0 -13.38476,5.96846 -13.38476,13.38281 v 83.50976 c 0,7.41436 5.97041,13.38282 13.38476,13.38282 h 206.66799 c 7.4143,0 13.3828,-5.96846 13.3828,-13.38282 v -83.50976 c 0,-7.41435 -5.9685,-13.38281 -13.3828,-13.38281 z m -109.57617,13.80664 a 51.063881,48.245316 0 0 0 -21.28906,3.7246 51.063881,48.245316 0 0 0 -27.45313,62.94727 l 0.34375,0.76758 a 51.063881,48.245316 0 0 0 66.97657,25.11914 51.063881,48.245316 0 0 0 26.875,-63.16797 51.063881,48.245316 0 0 0 -45.45313,-29.39062 z m 394.48826,12.39257 a 21.88452,20.676565 0 0 0 -9.123,1.59766 21.88452,20.676565 0 0 0 -11.7656,26.97656 l 0.1484,0.32813 a 21.88452,20.676565 0 0 0 28.7031,10.76562 21.88452,20.676565 0 0 0 11.5195,-27.07226 21.88452,20.676565 0 0 0 -19.4824,-12.59571 z m 87.5391,0 a 21.88452,20.676565 0 0 0 -9.1231,1.59766 21.88452,20.676565 0 0 0 -11.7656,26.97656 l 0.1465,0.32813 a 21.88452,20.676565 0 0 0 28.7031,10.76562 21.88452,20.676565 0 0 0 11.5196,-27.07226 21.88452,20.676565 0 0 0 -19.4805,-12.59571 z m -43.7695,41.35352 a 21.88452,20.676565 0 0 0 -9.1231,1.5957 21.88452,20.676565 0 0 0 -11.7656,26.97852 l 0.1484,0.32812 a 21.88452,20.676565 0 0 0 28.7031,10.76563 21.88452,20.676565 0 0 0 11.5176,-27.07227 21.88452,20.676565 0 0 0 -19.4804,-12.5957 z m -358.91997,70.29101 c -7.63655,10e-6 -13.78515,6.14862 -13.78515,13.78516 v 22.05469 h -28.92579 c -7.41435,0 -13.38281,5.96845 -13.38281,13.38281 v 10.45117 c 0,7.41435 5.96846,13.38282 13.38281,13.38282 h 28.92579 v 23.43359 c 0,7.63654 6.1486,13.78516 13.78515,13.78516 h 8.90625 c 7.63655,0 13.7832,-6.14862 13.7832,-13.78516 v -23.43359 h 24.55079 c 7.41435,0 13.38281,-5.96847 13.38281,-13.38282 v -10.45117 c 0,-7.41436 -5.96846,-13.38281 -13.38281,-13.38281 h -24.55079 v -22.05469 c 0,-7.63654 -6.14665,-13.78516 -13.7832,-13.78516 z m 281.52147,2.25 a 51.063881,48.245316 0 0 0 -21.2871,3.72461 51.063881,48.245316 0 0 0 -27.4531,62.94727 l 0.3437,0.76758 a 51.063881,48.245316 0 0 0 66.9766,25.11914 51.063881,48.245316 0 0 0 26.875,-63.16797 51.063881,48.245316 0 0 0 -45.4551,-29.39063 z" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1152"
id="linearGradient894"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(398,-56)"
x1="-398"
y1="56"
x2="1522"
y2="1136" />
</defs>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:url(#linearGradient1154);fill-opacity:1"
id="rect1033"
width="1920"
height="1080"
x="0"
y="0"
rx="0"
ry="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41813"
id="rect2078"
width="671.12531"
height="330.82504"
x="576.42297"
y="227.78436"
ry="110.27502"
sodipodi:type="rect"
clip-path="url(#clipPath890)"
inkscape:path-effect="#path-effect904"
d="m 686.69799,227.78436 h 450.57531 c 61.0923,0 110.275,49.18266 110.275,110.27502 v 110.27501 c 0,61.09236 -49.1827,110.27502 -110.275,110.27502 H 686.69799 c -61.09236,0 -110.27502,-49.18266 -110.27502,-110.27502 V 338.05938 c 0,-61.09236 49.18266,-110.27502 110.27502,-110.27502 z" />
<path
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41852"
id="rect2146"
width="199.30905"
height="504.61328"
x="917.35657"
y="488.93158"
ry="97.030388"
transform="matrix(0.97214881,-0.23436445,0.26615211,0.96393104,0,0)"
sodipodi:type="rect"
clip-path="url(#clipPath884)"
inkscape:path-effect="#path-effect900"
d="m 1014.387,488.93158 h 5.2482 c 53.7549,0 97.0304,43.27555 97.0304,97.03039 v 310.5525 c 0,53.75484 -43.2755,97.03039 -97.0304,97.03039 h -5.2482 c -53.75488,0 -97.03043,-43.27555 -97.03043,-97.03039 v -310.5525 c 0,-53.75484 43.27555,-97.03039 97.03043,-97.03039 z" />
<path
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41852"
id="rect2146-3"
width="200.94308"
height="502.92538"
x="641.0108"
y="61.943474"
ry="97.050156"
transform="matrix(0.97237519,0.23342343,-0.26569554,0.96405699,0,0)"
sodipodi:type="rect"
clip-path="url(#clipPath878)"
inkscape:path-effect="#path-effect896"
d="m 738.06096,61.943474 h 6.84277 c 53.76579,0 97.05016,43.284366 97.05016,97.050156 V 467.8187 c 0,53.76579 -43.28437,97.05016 -97.05016,97.05016 h -6.84277 c -53.76579,0 -97.05016,-43.28437 -97.05016,-97.05016 V 158.99363 c 0,-53.76579 43.28437,-97.050156 97.05016,-97.050156 z" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41813"
id="rect2384"
width="87.538078"
height="55.137505"
x="649.37134"
y="214"
ry="27.568752" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke-width:1.41813"
id="rect2384-6"
width="87.538078"
height="55.137505"
x="1089.9797"
y="214"
ry="27.568752" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB

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,27 +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 org.aperlambda.lambdacommon.Identifier;
/**
* Represents the constants used by LambdaControls.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class LambdaControlsConstants
{
public static final String NAMESPACE = "lambdacontrols";
public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(NAMESPACE, "controls_mode");
public static final Identifier FEATURE_CHANNEL = new Identifier(NAMESPACE, "feature");
public static final Identifier HELLO_CHANNEL = new Identifier(NAMESPACE, "hello");
}

View File

@@ -1,163 +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 org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* Represents a feature.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.1.0
*/
public class LambdaControlsFeature implements Nameable
{
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 HORIZONTAL_REACHAROUND = new LambdaControlsFeature("horizontal_reacharound", true, false);
public static final LambdaControlsFeature VERTICAL_REACHAROUND = new LambdaControlsFeature("vertical_reacharound", true, false);
private final String key;
private final boolean defaultAllowed;
private boolean allowed;
private final boolean defaultEnabled;
private boolean enabled;
public LambdaControlsFeature(@NotNull String key, boolean allowed, boolean enabled)
{
Objects.requireNonNull(key, "Feature key cannot be null.");
this.key = key;
this.setAllowed(this.defaultAllowed = allowed);
this.setEnabled(this.defaultEnabled = enabled);
}
public LambdaControlsFeature(@NotNull String key)
{
this(key, false, false);
}
/**
* Allows the feature.
*/
public void allow()
{
this.setAllowed(true);
}
/**
* Returns whether this feature is allowed.
*
* @return True if this feature is allowed, else false.
*/
public boolean isAllowed()
{
return this.allowed;
}
/**
* Sets whether this feature is allowed.
*
* @param allowed True if this feature is allowed, else false.
*/
public void setAllowed(boolean allowed)
{
this.allowed = allowed;
}
/**
* Resets allowed state to default.
*/
public void resetAllowed()
{
this.setAllowed(this.defaultAllowed);
}
/**
* Returns whether this feature is enabled.
*
* @return True if this feature is enabled, else false.
*/
public boolean isEnabled()
{
return this.enabled;
}
/**
* Returns whether this feature is enabled.
*
* @param enabled True if this feature is enabled, else false.
*/
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
/**
* Returns whether this feature is available or not.
*
* @return True if this feature is available, else false.
* @see #isAllowed()
* @see #isEnabled()
*/
public boolean isAvailable()
{
return this.isAllowed() && this.isEnabled();
}
/**
* Resets the feature to its default values.
*/
public void reset()
{
this.resetAllowed();
this.setEnabled(this.defaultEnabled);
}
@Override
public @NotNull String getName()
{
return this.key;
}
public static @NotNull Optional<LambdaControlsFeature> fromName(@NotNull String key)
{
Objects.requireNonNull(key, "Cannot find features with a null name.");
return FEATURES.parallelStream().filter(feature -> feature.getName().equals(key)).findFirst();
}
/**
* Resets all features to their default values.
*/
public static void resetAll()
{
FEATURES.parallelStream().forEach(LambdaControlsFeature::reset);
}
/**
* Resets all features to allow state.
*/
public static void resetAllAllowed()
{
FEATURES.parallelStream().forEach(LambdaControlsFeature::resetAllowed);
}
static {
FEATURES.add(FAST_BLOCK_PLACING);
FEATURES.add(HORIZONTAL_REACHAROUND);
FEATURES.add(VERTICAL_REACHAROUND);
}
}

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,204 +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 me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsHud;
import me.lambdaurora.lambdacontrols.client.gui.RingScreen;
import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay;
import me.lambdaurora.lambdacontrols.client.ring.KeyBindingRingAction;
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.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.client.util.InputUtil;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import java.io.File;
/**
* Represents the LambdaControls client mod.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.1.0
*/
public class LambdaControlsClient extends LambdaControls implements ClientModInitializer
{
private static LambdaControlsClient INSTANCE;
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");
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");
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");
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");
/*public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "ring"),
InputUtil.Type.MOUSE, GLFW.GLFW_MOUSE_BUTTON_5, "key.categories.misc");*/
public static final Identifier CONTROLLER_BUTTONS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png");
public static final Identifier CONTROLLER_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 final static File MAPPINGS_FILE = new File("config/gamecontrollerdb.txt");
public final LambdaControlsConfig config = new LambdaControlsConfig(this);
public final LambdaInput input = new LambdaInput(this);
public final LambdaRing ring = new LambdaRing(this);
public final LambdaReacharound reacharound = new LambdaReacharound();
private LambdaControlsHud hud;
private ControlsMode previousControlsMode;
@Override
public void onInitializeClient()
{
INSTANCE = this;
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_UP);
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_RIGHT);
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_DOWN);
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_LEFT);
//KeyBindingHelper.registerKeyBinding(BINDING_RING);
this.ring.registerAction("keybinding", KeyBindingRingAction.FACTORY);
ClientSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL, (context, attachedData) -> context.getTaskQueue()
.execute(() -> ClientSidePacketRegistry.INSTANCE.sendToServer(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode()))));
ClientSidePacketRegistry.INSTANCE.register(FEATURE_CHANNEL, (context, attachedData) -> {
String name = attachedData.readString(64);
boolean allowed = attachedData.readBoolean();
LambdaControlsFeature.fromName(name).ifPresent(feature -> context.getTaskQueue().execute(() -> feature.setAllowed(allowed)));
});
ClientTickEvents.START_CLIENT_TICK.register(this.reacharound::tick);
ClientTickEvents.END_CLIENT_TICK.register(this::onTick);
OpenScreenCallback.EVENT.register((client, screen) -> {
if (screen == null && this.config.getControlsMode() == ControlsMode.TOUCHSCREEN) {
screen = new TouchscreenOverlay(this);
screen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
client.skipGameRender = false;
client.currentScreen = screen;
} else if (screen != null) {
this.input.onScreenOpen(client, client.getWindow().getWidth(), client.getWindow().getHeight());
}
});
HudManager.register(this.hud = new LambdaControlsHud(this));
}
/**
* This method is called when Minecraft is initializing.
*/
public void onMcInit(@NotNull MinecraftClient client)
{
ButtonBinding.init(client.options);
this.config.load();
this.hud.setVisible(this.config.isHudEnabled());
Controller.updateMappings();
GLFW.glfwSetJoystickCallback((jid, event) -> {
if (event == GLFW.GLFW_CONNECTED) {
Controller controller = Controller.byId(jid);
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.connected", jid),
new LiteralText(controller.getName())));
} else if (event == GLFW.GLFW_DISCONNECTED) {
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.disconnected", jid),
null));
}
this.switchControlsMode();
});
LambdaControlsCompat.init(this);
}
/**
* This method is called every Minecraft tick.
*
* @param client The client instance.
*/
public void onTick(@NotNull MinecraftClient client)
{
this.input.onTick(client);
if (this.config.getControlsMode() == ControlsMode.CONTROLLER && (client.isWindowFocused() || this.config.hasUnfocusedInput()))
this.input.onControllerTick(client);
/*if (BINDING_RING.wasPressed()) {
client.openScreen(new RingScreen());
}*/
}
public void onRender(MinecraftClient client)
{
this.input.onRender(client.getTickDelta(), client);
}
/**
* Called when leaving a server.
*/
public void onLeave()
{
LambdaControlsFeature.resetAllAllowed();
}
/**
* Switches the controls mode if the auto switch is enabled.
*/
public void switchControlsMode()
{
if (this.config.hasAutoSwitchMode()) {
if (this.config.getController().isGamepad()) {
this.previousControlsMode = this.config.getControlsMode();
this.config.setControlsMode(ControlsMode.CONTROLLER);
} else {
if (this.previousControlsMode == null) {
this.previousControlsMode = ControlsMode.DEFAULT;
}
this.config.setControlsMode(this.previousControlsMode);
}
}
}
/**
* Sets whether the HUD is enabled or not.
*
* @param enabled True if the HUD is enabled, else false.
*/
public void setHudEnabled(boolean enabled)
{
this.config.setHudEnabled(enabled);
this.hud.setVisible(enabled);
}
/**
* Gets the LambdaControls client instance.
*
* @return The LambdaControls client instance.
*/
public static LambdaControlsClient get()
{
return INSTANCE;
}
}

View File

@@ -1,832 +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 com.electronwill.nightconfig.core.file.FileConfig;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.util.Arrays;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_X;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y;
/**
* Represents LambdaControls configuration.
*/
public class LambdaControlsConfig
{
// General
private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT;
private static final boolean DEFAULT_AUTO_SWITCH_MODE = false;
private static final boolean DEFAULT_DEBUG = false;
// HUD
private static final boolean DEFAULT_HUD_ENABLE = true;
private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT;
// Gameplay
private static final boolean DEFAULT_FAST_BLOCK_INTERACTION = true;
private static final boolean DEFAULT_FLY_DRIFTING = false;
private static final boolean DEFAULT_FLY_VERTICAL_DRIFTING = true;
private static final boolean DEFAULT_HORIZONTAL_REACHAROUND = false;
private static final boolean DEFAULT_VERTICAL_REACHAROUND = false;
private static final boolean DEFAULT_REACHAROUND_OUTLINE = true;
private static final int[] DEFAULT_REACHAROUND_OUTLINE_COLOR = new int[]{255, 255, 255, 102};
// Controller
private static final ControllerType DEFAULT_CONTROLLER_TYPE = ControllerType.DEFAULT;
private static final double DEFAULT_DEAD_ZONE = 0.25;
private static final double DEFAULT_ROTATION_SPEED = 40.0;
private static final double DEFAULT_MOUSE_SPEED = 25.0;
private static final boolean DEFAULT_UNFOCUSED_INPUT = false;
private static final boolean DEFAULT_VIRTUAL_MOUSE = false;
private static final VirtualMouseSkin DEFAULT_VIRTUAL_MOUSE_SKIN = VirtualMouseSkin.DEFAULT_LIGHT;
private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?");
protected final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/config.toml").build();
private final LambdaControlsClient mod;
private ControlsMode controlsMode;
private ControllerType controllerType;
// Gameplay.
private boolean shouldRenderReacharoundOutline;
private int[] reacharoundOutlineColor;
// Controller settings
private double deadZone;
private double rotationSpeed;
private double mouseSpeed;
private boolean unfocusedInput;
private boolean virtualMouse;
private VirtualMouseSkin virtualMouseSkin;
// HUD settings.
private boolean hudEnable;
private HudSide hudSide;
public LambdaControlsConfig(@NotNull LambdaControlsClient mod)
{
this.mod = mod;
}
/**
* Loads the configuration
*/
public void load()
{
this.config.load();
this.checkAndFix();
this.mod.log("Configuration loaded.");
this.controlsMode = ControlsMode.byId(this.config.getOrElse("controls", DEFAULT_CONTROLS_MODE.getName())).orElse(DEFAULT_CONTROLS_MODE);
// HUD settings.
this.hudEnable = this.config.getOrElse("hud.enable", DEFAULT_HUD_ENABLE);
this.hudSide = HudSide.byId(this.config.getOrElse("hud.side", DEFAULT_HUD_SIDE.getName())).orElse(DEFAULT_HUD_SIDE);
// Gameplay
LambdaControlsFeature.FAST_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.fast_block_placing", DEFAULT_FAST_BLOCK_INTERACTION));
LambdaControlsFeature.HORIZONTAL_REACHAROUND.setEnabled(this.config.getOrElse("gameplay.reacharound.horizontal", DEFAULT_HORIZONTAL_REACHAROUND));
LambdaControlsFeature.VERTICAL_REACHAROUND.setEnabled(this.config.getOrElse("gameplay.reacharound.vertical", DEFAULT_VERTICAL_REACHAROUND));
this.shouldRenderReacharoundOutline = this.config.getOrElse("gameplay.reacharound.outline", DEFAULT_REACHAROUND_OUTLINE);
this.reacharoundOutlineColor = this.config.getOptional("gameplay.reacharound.outline_color").map(hex -> parseColor((String) hex)).orElse(DEFAULT_REACHAROUND_OUTLINE_COLOR);
// Controller settings.
this.controllerType = ControllerType.byId(this.config.getOrElse("controller.type", DEFAULT_CONTROLLER_TYPE.getName())).orElse(DEFAULT_CONTROLLER_TYPE);
this.deadZone = this.config.getOrElse("controller.dead_zone", DEFAULT_DEAD_ZONE);
this.rotationSpeed = this.config.getOrElse("controller.rotation_speed", DEFAULT_ROTATION_SPEED);
this.mouseSpeed = this.config.getOrElse("controller.mouse_speed", DEFAULT_MOUSE_SPEED);
this.unfocusedInput = this.config.getOrElse("controller.unfocused_input", DEFAULT_UNFOCUSED_INPUT);
this.virtualMouse = this.config.getOrElse("controller.virtual_mouse", DEFAULT_VIRTUAL_MOUSE);
this.virtualMouseSkin = VirtualMouseSkin.byId(this.config.getOrElse("controller.virtual_mouse_skin", DEFAULT_VIRTUAL_MOUSE_SKIN.getName())).orElse(DEFAULT_VIRTUAL_MOUSE_SKIN);
// Controller controls.
InputManager.loadButtonBindings(this);
this.mod.ring.load(this.config);
}
/**
* Saves the configuration.
*/
public void save()
{
this.config.set("controller.dead_zone", this.deadZone);
this.config.set("controller.rotation_speed", this.rotationSpeed);
this.config.set("controller.mouse_speed", this.mouseSpeed);
this.config.set("controller.unfocused_input", this.unfocusedInput);
this.config.set("controller.virtual_mouse", this.virtualMouse);
this.config.save();
this.mod.log("Configuration saved.");
}
public void checkAndFix()
{
InputManager.streamBindings().forEach(binding -> {
String path = "controller.controls." + binding.getName();
Object raw = this.config.getRaw(path);
if (raw instanceof Number) {
this.mod.warn("Invalid data at \"" + path + "\", fixing...");
this.config.set(path, String.valueOf(raw));
}
});
if (this.config.contains("gameplay.front_block_placing.enabled")) {
this.setFrontBlockPlacing(this.config.getOrElse("gameplay.front_block_placing.enabled", DEFAULT_HORIZONTAL_REACHAROUND));
this.config.remove("gameplay.front_block_placing.enabled");
}
if (this.config.contains("gameplay.front_block_placing.outline")) {
this.setRenderReacharoundOutline(this.config.getOrElse("gameplay.front_block_placing.outline", DEFAULT_REACHAROUND_OUTLINE));
this.config.remove("gameplay.front_block_placing.outline");
}
if (this.config.contains("gameplay.front_block_placing.outline_color")) {
this.config.getOptional("gameplay.front_block_placing.outline_color").ifPresent(color -> this.config.set("gameplay.reacharound.outline_color", color));
this.config.remove("gameplay.front_block_placing.outline_color");
}
this.renamed("controller.controls.tab_left", "controller.controls.tab_back");
this.renamed("controller.controls.tab_right", "controller.controls.tab_next");
}
private void renamed(String oldPath, String newPath)
{
if (!this.config.contains(oldPath))
return;
Object raw = this.config.getRaw(oldPath);
this.config.remove(oldPath);
this.config.set(newPath, raw);
}
/**
* Resets the configuration to default values.
*/
public void reset()
{
// General
this.setControlsMode(DEFAULT_CONTROLS_MODE);
this.setAutoSwitchMode(DEFAULT_AUTO_SWITCH_MODE);
this.setDebug(DEFAULT_DEBUG);
// Gameplay
this.setFastBlockPlacing(DEFAULT_FAST_BLOCK_INTERACTION);
this.setFlyDrifting(DEFAULT_FLY_DRIFTING);
this.setFlyVerticalDrifting(DEFAULT_FLY_VERTICAL_DRIFTING);
this.setFrontBlockPlacing(DEFAULT_HORIZONTAL_REACHAROUND);
this.setVerticalReacharound(DEFAULT_VERTICAL_REACHAROUND);
this.setRenderReacharoundOutline(DEFAULT_REACHAROUND_OUTLINE);
// Controller
this.setControllerType(DEFAULT_CONTROLLER_TYPE);
this.setDeadZone(DEFAULT_DEAD_ZONE);
this.setRotationSpeed(DEFAULT_ROTATION_SPEED);
this.setMouseSpeed(DEFAULT_MOUSE_SPEED);
this.setUnfocusedInput(DEFAULT_UNFOCUSED_INPUT);
this.setVirtualMouse(DEFAULT_VIRTUAL_MOUSE);
this.setVirtualMouseSkin(DEFAULT_VIRTUAL_MOUSE_SKIN);
// HUD
this.setHudEnabled(DEFAULT_HUD_ENABLE);
this.setHudSide(DEFAULT_HUD_SIDE);
// Collect prevents concurrent modification.
InputManager.streamBindings().collect(Collectors.toList()).forEach(binding -> this.setButtonBinding(binding, binding.getDefaultButton()));
}
/**
* Gets the controls mode from the configuration.
*
* @return The controls mode.
*/
public @NotNull ControlsMode getControlsMode()
{
return this.controlsMode;
}
/**
* Sets the controls mode in the configuration.
*
* @param controlsMode The controls mode.
*/
public void setControlsMode(@NotNull ControlsMode controlsMode)
{
this.controlsMode = controlsMode;
this.config.set("controls", controlsMode.getName());
}
/**
* Returns whether the auto switch mode is enabled or not.
*
* @return True if the auto switch mode is enabled, else false.
*/
public boolean hasAutoSwitchMode()
{
return this.config.getOrElse("auto_switch_mode", DEFAULT_AUTO_SWITCH_MODE);
}
/**
* Sets whether the auto switch mode is enabled or not.
*
* @param autoSwitchMode True if the auto switch mode is enabled, else false.
*/
public void setAutoSwitchMode(boolean autoSwitchMode)
{
this.config.set("auto_switch_mode", autoSwitchMode);
}
/**
* Returns whether the mod has debug enabled or not.
*
* @return True if debug is enabled, else false.
*/
public boolean hasDebug()
{
return this.config.getOrElse("debug", DEFAULT_DEBUG);
}
/**
* Sets whether the mod has debug enabled or not.
*
* @param debug True if debug is enabled, else false.
*/
protected void setDebug(boolean debug)
{
this.config.set("debug", debug);
}
/*
HUD settings
*/
/**
* Returns whether the HUD is enabled.
*
* @return True if the HUD is enabled, else false.
*/
public boolean isHudEnabled()
{
return this.hudEnable;
}
/**
* Sets whether the HUD is enabled.
*
* @param enable True if the HUD is enabled, else false.
*/
public void setHudEnabled(boolean enable)
{
this.hudEnable = enable;
this.config.set("hud.enable", this.hudEnable);
}
/**
* Gets the HUD side from the configuration.
*
* @return The HUD side.
*/
public @NotNull HudSide getHudSide()
{
return this.hudSide;
}
/**
* Sets the HUD side in the configuration.
*
* @param hudSide The HUD side.
*/
public void setHudSide(@NotNull HudSide hudSide)
{
this.hudSide = hudSide;
this.config.set("hud.side", hudSide.getName());
}
/*
Gameplay settings
*/
/**
* Gets whether fast block placing is enabled or not.
*
* @return True if fast block placing is enabled, else false.
*/
public boolean hasFastBlockPlacing()
{
return LambdaControlsFeature.FAST_BLOCK_PLACING.isEnabled();
}
/**
* Sets whether fast block placing is enabled or not.
*
* @param enable True if fast block placing is enabled, else false.
*/
public void setFastBlockPlacing(boolean enable)
{
LambdaControlsFeature.FAST_BLOCK_PLACING.setEnabled(enable);
this.config.set("gameplay.fast_block_placing", enable);
}
/**
* Returns whether fly drifting is enabled or not.
*
* @return True if fly drifting is enabled, else false.
*/
public boolean hasFlyDrifting()
{
return this.config.getOrElse("gameplay.fly.drifting", DEFAULT_FLY_DRIFTING);
}
/**
* Sets whether fly drifting is enabled or not.
*
* @param flyDrifting True if fly drifting is enabled, else false.
*/
public void setFlyDrifting(boolean flyDrifting)
{
this.config.set("gameplay.fly.drifting", flyDrifting);
}
/**
* Returns whether vertical fly drifting is enabled or not.
*
* @return True if vertical fly drifting is enabled, else false.
*/
public boolean hasFlyVerticalDrifting()
{
return this.config.getOrElse("gameplay.fly.vertical_drifting", DEFAULT_FLY_VERTICAL_DRIFTING);
}
/**
* Sets whether vertical fly drifting is enabled or not.
*
* @param flyDrifting True if vertical fly drifting is enabled, else false.
*/
public void setFlyVerticalDrifting(boolean flyDrifting)
{
this.config.set("gameplay.fly.vertical_drifting", flyDrifting);
}
/**
* Returns whether front block placing is enabled or not.
*
* @return True if front block placing is enabled, else false.
*/
public boolean hasFrontBlockPlacing()
{
return LambdaControlsFeature.HORIZONTAL_REACHAROUND.isEnabled();
}
/**
* Sets whether front block placing is enabled or not.
*
* @param enable True if front block placing is enabled, else false.
*/
public void setFrontBlockPlacing(boolean enable)
{
LambdaControlsFeature.HORIZONTAL_REACHAROUND.setEnabled(enable);
this.config.set("gameplay.reacharound.horizontal", enable);
}
/**
* Returns whether vertical reacharound is enabled or not.
*
* @return True if vertical reacharound is enabled, else false.
*/
public boolean hasVerticalReacharound()
{
return LambdaControlsFeature.VERTICAL_REACHAROUND.isEnabled();
}
/**
* Sets whether vertical reacharound is enabled or not.
*
* @param enable True if vertical reacharound is enabled, else false.
*/
public void setVerticalReacharound(boolean enable)
{
LambdaControlsFeature.VERTICAL_REACHAROUND.setEnabled(enable);
this.config.set("gameplay.reacharound.vertical", enable);
}
/**
* Returns whether front block placing outline is enabled or not.
*
* @return True if front block placing outline is enabled, else false.
*/
public boolean shouldRenderReacharoundOutline()
{
return this.shouldRenderReacharoundOutline;
}
/**
* Sets whether front block placing outline is enabled or not.
*
* @param render True if front block placing outline is enabled, else false.
*/
public void setRenderReacharoundOutline(boolean render)
{
this.config.set("gameplay.reacharound.outline", this.shouldRenderReacharoundOutline = render);
}
/**
* Returns the front block placing outline color as an integer array.
* <p>
* The integer array has 4 elements: red, green, blue and alpha.
*
* @return The color as a RGBA integer array.
*/
public int[] getReacharoundOutlineColor()
{
return this.reacharoundOutlineColor;
}
/*
Controller settings
*/
/**
* Gets the used controller.
*
* @return The used controller.
*/
public @NotNull Controller getController()
{
Object raw = this.config.getRaw("controller.id");
if (raw instanceof Number) {
return Controller.byId((Integer) raw);
} else if (raw instanceof String) {
return Controller.byGuid((String) raw).orElse(Controller.byId(GLFW.GLFW_JOYSTICK_1));
}
return Controller.byId(GLFW.GLFW_JOYSTICK_1);
}
/**
* Sets the used controller.
*
* @param controller The used controller.
*/
public void setController(@NotNull Controller controller)
{
this.config.set("controller.id", controller.getId());
}
/**
* Gets the second controller (for Joy-Con supports).
*
* @return The second controller.
*/
public @NotNull Optional<Controller> getSecondController()
{
Object raw = this.config.getRaw("controller.id2");
if (raw instanceof Number) {
if ((int) raw == -1)
return Optional.empty();
return Optional.of(Controller.byId((Integer) raw));
} else if (raw instanceof String) {
return Optional.of(Controller.byGuid((String) raw).orElse(Controller.byId(GLFW.GLFW_JOYSTICK_1)));
}
return Optional.empty();
}
/**
* Sets the second controller.
*
* @param controller The second controller.
*/
public void setSecondController(@Nullable Controller controller)
{
this.config.set("controller.id2", controller == null ? -1 : controller.getId());
}
/**
* Gets the controller's type.
*
* @return The controller's type.
*/
public @NotNull ControllerType getControllerType()
{
return this.controllerType;
}
/**
* Sets the controller's type.
*
* @param controllerType The controller's type.
*/
public void setControllerType(@NotNull ControllerType controllerType)
{
this.controllerType = controllerType;
this.config.set("controller.type", controllerType.getName());
}
/**
* Gets the controller's dead zone from the configuration.
*
* @return The controller's dead zone value.
*/
public double getDeadZone()
{
return this.deadZone;
}
/**
* Sets the controller's dead zone in the configuration.
*
* @param deadZone The new controller's dead zone value.
*/
public void setDeadZone(double deadZone)
{
this.deadZone = deadZone;
}
/**
* Gets the controller's rotation speed.
*
* @return The rotation speed.
*/
public double getRotationSpeed()
{
return this.rotationSpeed;
}
/**
* Sets the controller's rotation speed.
*
* @param rotationSpeed The rotation speed.
*/
public void setRotationSpeed(double rotationSpeed)
{
this.rotationSpeed = rotationSpeed;
}
/**
* Gets the controller's mouse speed.
*
* @return The mouse speed.
*/
public double getMouseSpeed()
{
return this.mouseSpeed;
}
/**
* Sets the controller's mouse speed.
*
* @param mouseSpeed The mouse speed.
*/
public void setMouseSpeed(double mouseSpeed)
{
this.mouseSpeed = mouseSpeed;
}
/**
* Returns whether the right X axis is inverted or not.
*
* @return True if the right X axis is inverted, else false.
*/
public boolean doesInvertRightXAxis()
{
return this.config.getOrElse("controller.invert_right_x_axis", false);
}
/**
* Sets whether the right X axis is inverted or not.
*
* @param invert True if the right X axis is inverted, else false.
*/
public void setInvertRightXAxis(boolean invert)
{
this.config.set("controller.invert_right_x_axis", invert);
}
/**
* Returns whether the right Y axis is inverted or not.
*
* @return True if the right Y axis is inverted, else false.
*/
public boolean doesInvertRightYAxis()
{
return this.config.getOrElse("controller.invert_right_y_axis", false);
}
/**
* Sets whether the right Y axis is inverted or not.
*
* @param invert True if the right Y axis is inverted, else false.
*/
public void setInvertRightYAxis(boolean invert)
{
this.config.set("controller.invert_right_y_axis", invert);
}
/**
* Returns whether unfocused controller input is allowed or not.
*
* @return True if unfocused controller input is allowed, else false.
*/
public boolean hasUnfocusedInput()
{
return this.unfocusedInput;
}
/**
* Sets whether unfocused controller input is allowed or not.
*
* @param unfocusedInput True if unfocused controller input is allowed, else false.
*/
public void setUnfocusedInput(boolean unfocusedInput)
{
this.unfocusedInput = unfocusedInput;
}
/**
* Returns whether the mouse is virtual or not.
*
* @return True if the mouse is virtual, else false.
*/
public boolean hasVirtualMouse()
{
return this.virtualMouse;
}
/**
* Sets whether the mouse is virtual or not.
*
* @param virtualMouse True if the mouse is virtual, else false.
*/
public void setVirtualMouse(boolean virtualMouse)
{
this.virtualMouse = virtualMouse;
}
/**
* Gets the virtual mouse skin.
*
* @return The virtual mouse skin.
*/
public VirtualMouseSkin getVirtualMouseSkin()
{
return this.virtualMouseSkin;
}
/**
* Sets the virtual mouse skin.
*
* @param skin The virtual mouse skin.
*/
public void setVirtualMouseSkin(VirtualMouseSkin skin)
{
this.virtualMouseSkin = skin;
this.config.set("controller.virtual_mouse_skin", skin.getName());
}
/**
* Gets the right X axis sign.
*
* @return The right X axis sign.
*/
public double getRightXAxisSign()
{
return this.doesInvertRightXAxis() ? -1.0 : 1.0;
}
/**
* Gets the right Y axis sign.
*
* @return The right Y axis sign.
*/
public double getRightYAxisSign()
{
return this.doesInvertRightYAxis() ? -1.0 : 1.0;
}
/**
* Loads the button binding from configuration.
*
* @param button The button binding.
*/
public void loadButtonBinding(@NotNull ButtonBinding button)
{
button.setButton(button.getDefaultButton());
String code = this.config.getOrElse("controller.controls." + button.getName(), button.getButtonCode());
Matcher matcher = BUTTON_BINDING_PATTERN.matcher(code);
try {
int[] buttons = new int[1];
int count = 0;
while (matcher.find()) {
count++;
if (count > buttons.length)
buttons = Arrays.copyOf(buttons, count);
String current;
if (!this.checkValidity(button, code, current = matcher.group(1)))
return;
buttons[count - 1] = Integer.parseInt(current);
}
if (count == 0) {
this.mod.warn("Malformed config value \"" + code + "\" for binding \"" + button.getName() + "\".");
this.setButtonBinding(button, new int[]{-1});
}
button.setButton(buttons);
} catch (Exception e) {
this.mod.warn("Malformed config value \"" + code + "\" for binding \"" + button.getName() + "\".");
this.config.set("controller.controls." + button.getName(), button.getButtonCode());
}
}
private boolean checkValidity(@NotNull ButtonBinding binding, @NotNull String input, String group)
{
if (group == null) {
this.mod.warn("Malformed config value \"" + input + "\" for binding \"" + binding.getName() + "\".");
this.config.set("controller.controls." + binding.getName(), binding.getButtonCode());
return false;
}
return true;
}
/**
* Sets the button binding in configuration.
*
* @param binding The button binding.
* @param button The button.
*/
public void setButtonBinding(@NotNull ButtonBinding binding, int[] button)
{
binding.setButton(button);
this.config.set("controller.controls." + binding.getName(), binding.getButtonCode());
}
public boolean isBackButton(int btn, boolean isBtn, int state)
{
if (!isBtn && state == 0)
return false;
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false) == ButtonBinding.axisAsButton(btn, state == 1);
}
public boolean isForwardButton(int btn, boolean isBtn, int state)
{
if (!isBtn && state == 0)
return false;
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true) == ButtonBinding.axisAsButton(btn, state == 1);
}
public boolean isLeftButton(int btn, boolean isBtn, int state)
{
if (!isBtn && state == 0)
return false;
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false) == ButtonBinding.axisAsButton(btn, state == 1);
}
public boolean isRightButton(int btn, boolean isBtn, int state)
{
if (!isBtn && state == 0)
return false;
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true) == ButtonBinding.axisAsButton(btn, state == 1);
}
/**
* Returns whether the specified axis is an axis used for movements.
*
* @param axis The axis index.
* @return True if the axis is used for movements, else false.
*/
public boolean isMovementAxis(int axis)
{
return axis == GLFW_GAMEPAD_AXIS_LEFT_Y || axis == GLFW_GAMEPAD_AXIS_LEFT_X;
}
/**
* Parses a color from a hexadecimal color string.
*
* @param hex The hexadecimal color.
* @return The color instance, null if invalid.
*/
private static int[] parseColor(String hex)
{
hex = hex.replace("#", "");
switch (hex.length()) {
case 6:
return new int[]{
Integer.valueOf(hex.substring(0, 2), 16),
Integer.valueOf(hex.substring(2, 4), 16),
Integer.valueOf(hex.substring(4, 6), 16),
255
};
case 8:
return new int[]{
Integer.valueOf(hex.substring(0, 2), 16),
Integer.valueOf(hex.substring(2, 4), 16),
Integer.valueOf(hex.substring(4, 6), 16),
Integer.valueOf(hex.substring(6, 8), 16)
};
}
return null;
}
}

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,762 +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 com.google.common.collect.ImmutableSet;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.controller.Controller;
import me.lambdaurora.lambdacontrols.client.controller.InputManager;
import me.lambdaurora.lambdacontrols.client.gui.ControllerControlsScreen;
import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay;
import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
import me.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import me.lambdaurora.lambdacontrols.client.util.MouseAccessor;
import me.lambdaurora.spruceui.SpruceLabelWidget;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.ParentElement;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.advancement.AdvancementTab;
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.multiplayer.MultiplayerScreen;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
import net.minecraft.client.gui.screen.pack.PackScreen;
import net.minecraft.client.gui.screen.world.WorldListWidget;
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
import net.minecraft.client.gui.widget.EntryListWidget;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.MathHelper;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWGamepadState;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static me.lambdaurora.lambdacontrols.client.controller.ButtonBinding.axisAsButton;
import static me.lambdaurora.lambdacontrols.client.controller.InputManager.INPUT_MANAGER;
import static org.lwjgl.glfw.GLFW.*;
/**
* Represents the LambdaControls' input handler.
*
* @author LambdAurora
* @version 1.4.3
* @since 1.0.0
*/
public class LambdaInput
{
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
private final LambdaControlsConfig config;
// Cooldowns
private int actionGuiCooldown = 0;
private boolean ignoreNextARelease = false;
private double targetYaw = 0.0;
private double targetPitch = 0.0;
private float prevXAxis = 0.F;
private float prevYAxis = 0.F;
private int targetMouseX = 0;
private int targetMouseY = 0;
private float mouseSpeedX = 0.F;
private float mouseSpeedY = 0.F;
private int inventoryInteractionCooldown = 0;
public LambdaInput(@NotNull LambdaControlsClient mod)
{
this.config = mod.config;
}
/**
* This method is called every Minecraft tick.
*
* @param client The client instance.
*/
public void onTick(@NotNull MinecraftClient client)
{
this.targetYaw = 0.F;
this.targetPitch = 0.F;
// Handles the key bindings.
if (LambdaControlsClient.BINDING_LOOK_UP.isPressed()) {
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_Y, 0.8F, 2);
} else if (LambdaControlsClient.BINDING_LOOK_DOWN.isPressed()) {
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_Y, 0.8F, 1);
}
if (LambdaControlsClient.BINDING_LOOK_LEFT.isPressed()) {
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_X, 0.8F, 2);
} else if (LambdaControlsClient.BINDING_LOOK_RIGHT.isPressed()) {
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_X, 0.8F, 1);
}
INPUT_MANAGER.tick(client);
}
/**
* This method is called every Minecraft tick for controller input update.
*
* @param client The client instance.
*/
public void onControllerTick(@NotNull MinecraftClient client)
{
BUTTON_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0).forEach(entry -> BUTTON_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
// Decreases the cooldown for GUI actions.
if (this.actionGuiCooldown > 0)
--this.actionGuiCooldown;
InputManager.updateStates();
Controller controller = this.config.getController();
if (controller.isConnected()) {
GLFWGamepadState state = controller.getState();
this.fetchButtonInput(client, state, false);
this.fetchAxeInput(client, state, false);
}
this.config.getSecondController().filter(Controller::isConnected)
.ifPresent(joycon -> {
GLFWGamepadState state = joycon.getState();
this.fetchButtonInput(client, state, true);
this.fetchAxeInput(client, state, true);
});
boolean allowInput = true;
if (client.currentScreen instanceof ControllerControlsScreen && ((ControllerControlsScreen) client.currentScreen).focusedBinding != null)
allowInput = false;
if (allowInput)
InputManager.updateBindings(client);
if (client.currentScreen instanceof ControllerControlsScreen && InputManager.STATES.entrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) {
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen;
if (screen.focusedBinding != null && !screen.waiting) {
int[] buttons = new int[screen.currentButtons.size()];
for (int i = 0; i < screen.currentButtons.size(); i++)
buttons[i] = screen.currentButtons.get(i);
screen.focusedBinding.setButton(buttons);
screen.focusedBinding = null;
}
}
if (this.inventoryInteractionCooldown > 0)
this.inventoryInteractionCooldown--;
}
/**
* This method is called before the screen is rendered.
*
* @param client The client instance.
* @param screen The screen to render.
*/
public void onPreRenderScreen(@NotNull MinecraftClient client, @NotNull Screen screen)
{
if (!isScreenInteractive(screen)) {
INPUT_MANAGER.updateMousePosition(client);
}
}
/**
* This method is called when Minecraft renders.
*
* @param client The client instance.
*/
public void onRender(float tickDelta, @NotNull MinecraftClient client)
{
if (!(client.currentScreen == null || client.currentScreen instanceof TouchscreenOverlay))
return;
PlayerEntity player = client.player;
if (player == null)
return;
if (this.targetYaw != 0F || this.targetPitch != 0F) {
float rotationYaw = (float) (player.prevYaw + (this.targetYaw / 0.10) * tickDelta);
float rotationPitch = (float) (player.prevPitch + (this.targetPitch / 0.10) * tickDelta);
client.player.yaw = rotationYaw;
client.player.pitch = MathHelper.clamp(rotationPitch, -90.F, 90.F);
if (client.player.isRiding()) {
client.player.getVehicle().copyPositionAndRotation(client.player);
}
client.getTutorialManager().onUpdateMouse(this.targetPitch, this.targetYaw);
}
}
/**
* This method is called when a Screen is opened.
*
* @param client The client instance.
* @param windowWidth The window width.
* @param windowHeight The window height.
*/
public void onScreenOpen(@NotNull MinecraftClient client, int windowWidth, int windowHeight)
{
if (client.currentScreen == null) {
this.mouseSpeedX = this.mouseSpeedY = 0.0F;
INPUT_MANAGER.resetMousePosition(windowWidth, windowHeight);
} else if (isScreenInteractive(client.currentScreen) && this.config.hasVirtualMouse()) {
((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), 0, 0);
INPUT_MANAGER.resetMouseTarget(client);
}
this.inventoryInteractionCooldown = 5;
}
private void fetchButtonInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon)
{
ByteBuffer buffer = gamepadState.buttons();
for (int i = 0; i < buffer.limit(); i++) {
int btn = leftJoycon ? ButtonBinding.controller2Button(i) : i;
boolean btnState = buffer.get() == (byte) 1;
ButtonState state = ButtonState.NONE;
ButtonState previousState = InputManager.STATES.getOrDefault(btn, ButtonState.NONE);
if (btnState != previousState.isPressed()) {
state = btnState ? ButtonState.PRESS : ButtonState.RELEASE;
this.handleButton(client, btn, btnState ? 0 : 1, btnState);
if (btnState)
BUTTON_COOLDOWNS.put(btn, 5);
} else if (btnState) {
state = ButtonState.REPEAT;
if (BUTTON_COOLDOWNS.getOrDefault(btn, 0) == 0) {
BUTTON_COOLDOWNS.put(btn, 5);
this.handleButton(client, btn, 2, true);
}
}
InputManager.STATES.put(btn, state);
}
}
private void fetchAxeInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon)
{
FloatBuffer buffer = gamepadState.axes();
for (int i = 0; i < buffer.limit(); i++) {
int axis = leftJoycon ? ButtonBinding.controller2Button(i) : i;
float value = buffer.get();
float absValue = Math.abs(value);
if (i == GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y)
value *= -1.0F;
int state = value > this.config.getDeadZone() ? 1 : (value < -this.config.getDeadZone() ? 2 : 0);
this.handleAxe(client, axis, value, absValue, state);
}
}
private void handleButton(@NotNull MinecraftClient client, int button, int action, boolean state)
{
if (client.currentScreen instanceof ControllerControlsScreen) {
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen;
if (screen.focusedBinding != null) {
if (action == 0 && !screen.currentButtons.contains(button)) {
screen.currentButtons.add(button);
int[] buttons = new int[screen.currentButtons.size()];
for (int i = 0; i < screen.currentButtons.size(); i++)
buttons[i] = screen.currentButtons.get(i);
screen.focusedBinding.setButton(buttons);
screen.waiting = false;
}
return;
}
}
if (action == 0 || action == 2) {
if (client.currentScreen != null && isScreenInteractive(client.currentScreen)
&& (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN
|| button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)) {
if (this.actionGuiCooldown == 0) {
if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP) {
this.changeFocus(client.currentScreen, false);
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN) {
this.changeFocus(client.currentScreen, true);
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT) {
this.handleLeftRight(client.currentScreen, false);
} else {
this.handleLeftRight(client.currentScreen, true);
}
}
return;
}
}
if (action == 1) {
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null) {
if (this.actionGuiCooldown == 0) {
Element focused = client.currentScreen.getFocused();
if (focused != null && isScreenInteractive(client.currentScreen)) {
if (this.handleAButton(client.currentScreen, focused)) {
this.actionGuiCooldown = 5; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
return;
}
}
}
}
if (this.handleInventory(client, button)) {
this.ignoreNextARelease = true;
return;
}
if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
if (client.currentScreen != null) {
if (!LambdaControlsCompat.handleMenuBack(client, client.currentScreen))
if (!this.tryGoBack(client.currentScreen))
client.currentScreen.onClose();
return;
}
}
}
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !isScreenInteractive(client.currentScreen) && this.actionGuiCooldown == 0) {
if (!this.ignoreNextARelease) {
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
if (action == 0) {
Screen.wrapScreenError(() -> client.currentScreen.mouseClicked(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1),
"mouseClicked event handler", client.currentScreen.getClass().getCanonicalName());
} else if (action == 1) {
Screen.wrapScreenError(() -> client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1),
"mouseReleased event handler", client.currentScreen.getClass().getCanonicalName());
}
this.actionGuiCooldown = 5;
} else {
this.ignoreNextARelease = false;
}
}
}
/**
* Handles inventory interaction.
*
* @param client The client instance.
* @param button The button pressed.
* @return True if an inventory interaction was done.
*/
private boolean handleInventory(@NotNull MinecraftClient client, int button)
{
if (!(client.currentScreen instanceof HandledScreen))
return false;
if (client.interactionManager == null || client.player == null)
return false;
if (this.inventoryInteractionCooldown > 0)
return true;
if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
client.player.closeHandledScreen();
return true;
}
double x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
HandledScreen screen = (HandledScreen) client.currentScreen;
HandledScreenAccessor accessor = (HandledScreenAccessor) screen;
Slot slot = ((HandledScreenAccessor) client.currentScreen).lambdacontrols_getSlotAt(x, y);
int slotId;
if (slot == null) {
if (client.player.inventory.getCursorStack().isEmpty())
return false;
slotId = accessor.lambdacontrols_isClickOutsideBounds(x, y, accessor.getX(), accessor.getY(), GLFW_MOUSE_BUTTON_1) ? -999 : -1;
} else {
slotId = slot.id;
}
SlotActionType actionType = SlotActionType.PICKUP;
int clickData = GLFW.GLFW_MOUSE_BUTTON_1;
switch (button) {
case GLFW_GAMEPAD_BUTTON_A:
if (screen instanceof CreativeInventoryScreen)
if (((CreativeInventoryScreenAccessor) screen).lambdacontrols_isCreativeInventorySlot(slot))
actionType = SlotActionType.CLONE;
if (slot != null && LambdaControlsCompat.streamCompatHandlers().anyMatch(handler -> handler.isCreativeSlot(screen, slot)))
actionType = SlotActionType.CLONE;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_X:
clickData = GLFW_MOUSE_BUTTON_2;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_Y:
actionType = SlotActionType.QUICK_MOVE;
break;
default:
return false;
}
accessor.lambdacontrols_onMouseClick(slot, slotId, clickData, actionType);
return true;
}
/**
* Tries to go back.
*
* @param screen The current screen.
* @return True if successful, else false.
*/
public boolean tryGoBack(@NotNull Screen screen)
{
ImmutableSet<String> set = ImmutableSet.of("gui.back", "gui.done", "gui.cancel", "gui.toTitle", "gui.toMenu");
return screen.children().stream().filter(element -> element instanceof AbstractPressableButtonWidget)
.map(element -> (AbstractPressableButtonWidget) element)
.filter(element -> element.getMessage() instanceof TranslatableText)
.anyMatch(element -> {
if (set.stream().anyMatch(key -> key.equals(((TranslatableText) element.getMessage()).getKey()))) {
element.onPress();
return true;
}
return false;
});
}
private void handleAxe(@NotNull MinecraftClient client, int axis, float value, float absValue, int state)
{
int asButtonState = value > 0.5F ? 1 : (value < -0.5F ? 2 : 0);
if (axis == GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axis == GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER || axis == ButtonBinding.controller2Button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER) ||
axis == ButtonBinding.controller2Button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER))
if (asButtonState == 2)
asButtonState = 0;
{
boolean currentPlusState = asButtonState == 1;
boolean currentMinusState = asButtonState == 2;
ButtonState previousPlusState = InputManager.STATES.getOrDefault(axisAsButton(axis, true), ButtonState.NONE);
ButtonState previousMinusState = InputManager.STATES.getOrDefault(axisAsButton(axis, false), ButtonState.NONE);
if (currentPlusState != previousPlusState.isPressed()) {
InputManager.STATES.put(axisAsButton(axis, true), currentPlusState ? ButtonState.PRESS : ButtonState.RELEASE);
if (currentPlusState)
BUTTON_COOLDOWNS.put(axisAsButton(axis, true), 5);
} else if (currentPlusState) {
InputManager.STATES.put(axisAsButton(axis, true), ButtonState.REPEAT);
if (BUTTON_COOLDOWNS.getOrDefault(axisAsButton(axis, true), 0) == 0) {
BUTTON_COOLDOWNS.put(axisAsButton(axis, true), 5);
}
}
if (currentMinusState != previousMinusState.isPressed()) {
InputManager.STATES.put(axisAsButton(axis, false), currentMinusState ? ButtonState.PRESS : ButtonState.RELEASE);
if (currentMinusState)
BUTTON_COOLDOWNS.put(axisAsButton(axis, false), 5);
} else if (currentMinusState) {
InputManager.STATES.put(axisAsButton(axis, false), ButtonState.REPEAT);
if (BUTTON_COOLDOWNS.getOrDefault(axisAsButton(axis, false), 0) == 0) {
BUTTON_COOLDOWNS.put(axisAsButton(axis, false), 5);
}
}
float axisValue = absValue < this.config.getDeadZone() ? 0.f : (float) (absValue - this.config.getDeadZone());
axisValue /= (1.0 - this.config.getDeadZone());
if (currentPlusState)
InputManager.BUTTON_VALUES.put(axisAsButton(axis, true), axisValue);
else
InputManager.BUTTON_VALUES.put(axisAsButton(axis, true), 0.f);
if (currentMinusState)
InputManager.BUTTON_VALUES.put(axisAsButton(axis, false), axisValue);
else
InputManager.BUTTON_VALUES.put(axisAsButton(axis, false), 0.f);
}
double deadZone = this.config.getDeadZone();
if (client.currentScreen instanceof ControllerControlsScreen) {
ControllerControlsScreen screen = (ControllerControlsScreen) client.currentScreen;
if (screen.focusedBinding != null) {
if (asButtonState != 0 && !screen.currentButtons.contains(axisAsButton(axis, asButtonState == 1))) {
screen.currentButtons.add(axisAsButton(axis, asButtonState == 1));
int[] buttons = new int[screen.currentButtons.size()];
for (int i = 0; i < screen.currentButtons.size(); i++)
buttons[i] = screen.currentButtons.get(i);
screen.focusedBinding.setButton(buttons);
screen.waiting = false;
}
return;
}
} else if (client.currentScreen instanceof CreativeInventoryScreen) {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
CreativeInventoryScreen screen = (CreativeInventoryScreen) client.currentScreen;
CreativeInventoryScreenAccessor accessor = (CreativeInventoryScreenAccessor) screen;
// @TODO allow rebinding to left stick
if (accessor.lambdacontrols_hasScrollbar() && absValue >= deadZone) {
screen.mouseScrolled(0.0, 0.0, -value);
}
return;
}
} else if (client.currentScreen instanceof AdvancementsScreen) {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X || axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
AdvancementsScreen screen = (AdvancementsScreen) client.currentScreen;
AdvancementsScreenAccessor accessor = (AdvancementsScreenAccessor) screen;
if (absValue >= deadZone) {
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);
}
return;
}
}
if (client.currentScreen == null) {
// Handles the look direction.
absValue -= this.config.getDeadZone();
this.handleLook(client, axis, (float) (absValue / (1.0 - this.config.getDeadZone())), state);
} else {
boolean allowMouseControl = true;
if (this.actionGuiCooldown == 0 && this.config.isMovementAxis(axis) && isScreenInteractive(client.currentScreen)) {
if (this.config.isForwardButton(axis, false, asButtonState)) {
allowMouseControl = this.changeFocus(client.currentScreen, false);
} else if (this.config.isBackButton(axis, false, asButtonState)) {
allowMouseControl = this.changeFocus(client.currentScreen, true);
} else if (this.config.isLeftButton(axis, false, asButtonState)) {
allowMouseControl = this.handleLeftRight(client.currentScreen, false);
} else if (this.config.isRightButton(axis, false, asButtonState)) {
allowMouseControl = this.handleLeftRight(client.currentScreen, true);
}
}
float movementX = 0.0F;
float movementY = 0.0F;
if (this.config.isBackButton(axis, false, (value > 0 ? 1 : 2))) {
movementY = absValue;
} else if (this.config.isForwardButton(axis, false, (value > 0 ? 1 : 2))) {
movementY = -absValue;
} else if (this.config.isLeftButton(axis, false, (value > 0 ? 1 : 2))) {
movementX = -absValue;
} else if (this.config.isRightButton(axis, false, (value > 0 ? 1 : 2))) {
movementX = absValue;
}
if (client.currentScreen != null && allowMouseControl) {
boolean moving = Math.abs(movementY) >= deadZone || Math.abs(movementX) >= deadZone;
if (moving) {
/*
Updates the target mouse position when the initial movement stick movement is detected.
It prevents the cursor to jump to the old target mouse position if the user moves the cursor with the mouse.
*/
if (Math.abs(prevXAxis) < deadZone && Math.abs(prevYAxis) < deadZone) {
INPUT_MANAGER.resetMouseTarget(client);
}
if (Math.abs(movementX) >= deadZone)
this.mouseSpeedX = movementX;
else
this.mouseSpeedX = 0.F;
if (Math.abs(movementY) >= deadZone)
this.mouseSpeedY = movementY;
else
this.mouseSpeedY = 0.F;
} else {
this.mouseSpeedX = 0.F;
this.mouseSpeedY = 0.F;
}
if (Math.abs(this.mouseSpeedX) >= .05F || Math.abs(this.mouseSpeedY) >= .05F) {
InputManager.queueMoveMousePosition(this.mouseSpeedX * this.config.getMouseSpeed(), this.mouseSpeedY * this.config.getMouseSpeed());
}
this.moveMouseToClosestSlot(client, client.currentScreen);
}
this.prevXAxis = movementX;
this.prevYAxis = movementY;
}
}
private boolean handleAButton(@NotNull Screen screen, @NotNull Element focused)
{
if (focused instanceof AbstractPressableButtonWidget) {
AbstractPressableButtonWidget widget = (AbstractPressableButtonWidget) focused;
widget.playDownSound(MinecraftClient.getInstance().getSoundManager());
widget.onPress();
return true;
} else if (focused instanceof SpruceLabelWidget) {
((SpruceLabelWidget) focused).onPress();
return true;
} else if (focused instanceof WorldListWidget) {
WorldListWidget list = (WorldListWidget) focused;
list.method_20159().ifPresent(WorldListWidget.Entry::play);
return true;
} else if (focused instanceof MultiplayerServerListWidget) {
MultiplayerServerListWidget list = (MultiplayerServerListWidget) focused;
MultiplayerServerListWidget.Entry entry = list.getSelected();
if (entry instanceof MultiplayerServerListWidget.LanServerEntry || entry instanceof MultiplayerServerListWidget.ServerEntry) {
((MultiplayerScreen) screen).select(entry);
((MultiplayerScreen) screen).connect();
}
} else if (focused instanceof ParentElement) {
Element childFocused = ((ParentElement) focused).getFocused();
if (childFocused != null)
return this.handleAButton(screen, childFocused);
}
return false;
}
/**
* Handles the left and right buttons.
*
* @param screen The current screen.
* @param right True if the right button is pressed, else false.
*/
private boolean handleLeftRight(@NotNull Screen screen, boolean right)
{
Element focused = screen.getFocused();
if (focused != null)
if (this.handleRightLeftElement(focused, right))
return this.changeFocus(screen, right);
return true;
}
private boolean handleRightLeftElement(@NotNull Element element, boolean right)
{
if (element instanceof SliderWidget) {
SliderWidget slider = (SliderWidget) element;
slider.keyPressed(right ? 262 : 263, 0, 0);
this.actionGuiCooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
return false;
} else if (element instanceof AlwaysSelectedEntryListWidget) {
((EntryListWidgetAccessor) element).lambdacontrols_moveSelection(right ? EntryListWidget.MoveDirection.UP : EntryListWidget.MoveDirection.DOWN);
return false;
} else if (element instanceof ParentElement) {
ParentElement entryList = (ParentElement) element;
Element focused = entryList.getFocused();
if (focused == null)
return true;
return this.handleRightLeftElement(focused, right);
}
return true;
}
/**
* Handles the look direction input.
*
* @param client The client instance.
* @param axis The axis to change.
* @param value The value of the look.
* @param state The state.
*/
public void handleLook(@NotNull MinecraftClient client, int axis, float value, int state)
{
// Handles the look direction.
if (client.player != null) {
double powValue = Math.pow(value, 2.0);
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
if (state == 2) {
this.targetPitch = -this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D;
} else if (state == 1) {
this.targetPitch = this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D;
}
}
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) {
if (state == 2) {
this.targetYaw = -this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D;
} else if (state == 1) {
this.targetYaw = this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D;
}
}
}
}
private boolean changeFocus(@NotNull Screen screen, boolean down)
{
if (!screen.changeFocus(down)) {
if (screen.changeFocus(down)) {
this.actionGuiCooldown = 5;
return false;
}
return true;
} else {
this.actionGuiCooldown = 5;
return false;
}
}
public static boolean isScreenInteractive(@NotNull Screen screen)
{
return !(screen instanceof AdvancementsScreen || screen instanceof HandledScreen || screen instanceof PackScreen || LambdaControlsCompat.requireMouseOnScreen(screen));
}
// Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686.
private void moveMouseToClosestSlot(@NotNull MinecraftClient client, @Nullable Screen screen)
{
// Makes the mouse attracted to slots. This helps with selecting items when using a controller.
if (screen instanceof HandledScreen) {
HandledScreen inventoryScreen = (HandledScreen) screen;
HandledScreenAccessor accessor = (HandledScreenAccessor) inventoryScreen;
int guiLeft = accessor.getX();
int guiTop = accessor.getY();
int mouseX = (int) (targetMouseX * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
int mouseY = (int) (targetMouseY * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight());
// Finds the closest slot in the GUI within 14 pixels.
Optional<Pair<Slot, Double>> closestSlot = inventoryScreen.getScreenHandler().slots.parallelStream()
.map(slot -> {
int x = guiLeft + slot.x + 8;
int y = guiTop + slot.y + 8;
// Distance between the slot and the cursor.
double distance = Math.sqrt(Math.pow(x - mouseX, 2) + Math.pow(y - mouseY, 2));
return Pair.of(slot, distance);
}).filter(entry -> entry.value <= 14.0)
.min(Comparator.comparingDouble(p -> p.value));
if (closestSlot.isPresent()) {
Slot slot = closestSlot.get().key;
if (slot.hasStack() || !client.player.inventory.getMainHandStack().isEmpty()) {
int slotCenterXScaled = guiLeft + slot.x + 8;
int slotCenterYScaled = guiTop + slot.y + 8;
int slotCenterX = (int) (slotCenterXScaled / ((double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()));
int slotCenterY = (int) (slotCenterYScaled / ((double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()));
double deltaX = slotCenterX - targetMouseX;
double deltaY = slotCenterY - targetMouseY;
if (mouseX != slotCenterXScaled || mouseY != slotCenterYScaled) {
this.targetMouseX += deltaX * 0.75;
this.targetMouseY += deltaY * 0.75;
} else {
this.mouseSpeedX *= 0.3F;
this.mouseSpeedY *= 0.3F;
}
this.mouseSpeedX *= .75F;
this.mouseSpeedY *= .75F;
} else {
this.mouseSpeedX *= .1F;
this.mouseSpeedY *= .1F;
}
} else {
this.mouseSpeedX *= .3F;
this.mouseSpeedY *= .3F;
}
} else {
this.mouseSpeedX = 0.F;
this.mouseSpeedY = 0.F;
}
}
}

View File

@@ -1,110 +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 me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.screen.slot.Slot;
import net.minecraft.util.hit.BlockHitResult;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a compatibility handler for a mod.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.1.0
*/
public interface CompatHandler
{
/**
* Handles compatibility of a mod.
*
* @param mod This mod instance.
*/
void handle(@NotNull LambdaControlsClient mod);
/**
* Returns whether the mouse is required on the specified screen.
*
* @param screen The screen.
* @return True if the mouse is required on the specified screen, else false.
*/
default boolean requireMouseOnScreen(Screen screen)
{
return false;
}
/**
* Returns a slot at the specified location if possible.
*
* @param screen The screen.
* @param mouseX The mouse X-coordinate.
* @param mouseY The mouse Y-coordinate.
* @return A slot if present, else null.
* @since 1.5.0
*/
default @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Screen screen, int mouseX, int mouseY)
{
return null;
}
/**
* Returns whether the current slot is a creative slot or not.
*
* @param screen The screen.
* @param slot The slot to check.
* @return True if the slot is a creative slot, else false.
*/
default boolean isCreativeSlot(@NotNull HandledScreen screen, @NotNull Slot slot)
{
return false;
}
/**
* Returns a custom translation key to make custom attack action strings on the HUD.
*
* @param client The client instance.
* @param placeResult The last place block result.
* @return Null if untouched, else a translation key.
*/
default String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult)
{
return null;
}
/**
* Returns a custom translation key to make custom use action strings on the HUD.
*
* @param client The client instance.
* @param placeResult The last place block result.
* @return Null if untouched, else a translation key.
*/
default String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult)
{
return null;
}
/**
* Handles the menu back button.
*
* @param client The client instance.
* @param screen The screen.
* @return True if the handle was fired and succeed, else false.
*/
default boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen)
{
return false;
}
}

View File

@@ -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,375 +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 me.lambdaurora.lambdacontrols.client.ButtonState;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.compat.mixin.EntryListWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.compat.mixin.EntryWidgetAccessor;
import me.lambdaurora.lambdacontrols.client.compat.mixin.RecipeViewingScreenAccessor;
import me.lambdaurora.lambdacontrols.client.compat.mixin.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.gui.Element;
import net.minecraft.client.gui.screen.Screen;
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.Nullable;
import java.util.List;
import java.util.Optional;
import static org.lwjgl.glfw.GLFW.*;
/**
* Represents a compatibility handler for REI.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.2.0
*/
public class ReiCompat implements CompatHandler
{
private static final Pair<Integer, Integer> INVALID_SLOT = new Pair<>(-1, -1);
private static EntryListWidget ENTRY_LIST_WIDGET;
@Override
public void handle(@NotNull LambdaControlsClient mod)
{
ButtonBinding.builder(new Identifier("rei", "category_back"))
.buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
.filter((client, binding) -> isViewingScreen(client.currentScreen))
.action(handleTab(false))
.cooldown(true)
.register();
ButtonBinding.builder(new Identifier("rei", "category_next"))
.buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
.filter((client, binding) -> isViewingScreen(client.currentScreen))
.action(handleTab(true))
.cooldown(true)
.register();
ButtonBinding.builder(new Identifier("rei", "page_back"))
.buttons(ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_X, false))
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
.action(handlePage(false))
.cooldown(true)
.register();
ButtonBinding.builder(new Identifier("rei", "page_next"))
.buttons(ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_X, true))
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
.action(handlePage(true))
.cooldown(true)
.register();
ButtonBinding.builder(new Identifier("rei", "recipe_back"))
.buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP)
.filter((client, binding) -> isViewingScreen(client.currentScreen))
.action(handleRecipe(false))
.cooldown(true)
.register();
ButtonBinding.builder(new Identifier("rei", "recipe_next"))
.buttons(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)
.filter((client, binding) -> isViewingScreen(client.currentScreen))
.action(handleRecipe(true))
.cooldown(true)
.register();
// For some reasons this is broken.
ButtonBinding.builder(new Identifier("rei", "show_usage"))
.buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
.action(handleShowRecipeUsage(true))
.cooldown(true)
.register();
ButtonBinding.builder(new Identifier("rei", "show_recipe"))
.buttons(GLFW_GAMEPAD_BUTTON_LEFT_THUMB)
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
.action(handleShowRecipeUsage(false))
.cooldown(true)
.register();
}
@Override
public boolean requireMouseOnScreen(Screen screen)
{
return isViewingScreen(screen) || screen instanceof PreRecipeViewingScreen;
}
@Override
public @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Screen screen, int mouseX, int mouseY)
{
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
if (overlay.isPresent() && overlay.get().isInside(mouseX, mouseY)) {
EntryListWidget widget = getEntryListWidget();
if (widget == null)
return null;
Pair<Integer, Integer> slot = this.getSlotAt(widget, mouseX, mouseY, false);
if (slot != null && slot != INVALID_SLOT)
return slot;
} else if (isViewingScreen(screen)) {
for (Element element : screen.children()) {
Pair<Integer, Integer> slot = this.getSlotAt(element, mouseX, mouseY, true);
if (slot != null && slot != INVALID_SLOT)
return slot;
}
}
return null;
}
private @Nullable Pair<Integer, Integer> getSlotAt(@NotNull Element element, int mouseX, int mouseY, boolean allowEmpty)
{
if (element instanceof EntryWidget) {
EntryWidget entry = (EntryWidget) element;
if (entry.containsMouse(mouseX, mouseY)) {
if (!allowEmpty && entry.entries().isEmpty())
return INVALID_SLOT;
return Pair.of(entry.getBounds().getX() + 1, entry.getBounds().getY() + 1);
}
} else if (element instanceof EntryListWidget) {
List<EntryListEntryWidget> entries = ((EntryListWidgetAccessor) element).getEntries();
for (EntryListEntryWidget entry : entries) {
Pair<Integer, Integer> slot = this.getSlotAt(entry, mouseX, mouseY, allowEmpty);
if (slot != null && slot != INVALID_SLOT)
return slot;
}
} else if (!(element instanceof ButtonWidget) && element instanceof WidgetWithBounds) {
for (Element child : ((WidgetWithBounds) element).children()) {
Pair<Integer, Integer> slot = this.getSlotAt(child, mouseX, mouseY, allowEmpty);
if (slot != null && slot != INVALID_SLOT)
return slot;
}
}
return null;
}
private static boolean isViewingScreen(Screen screen)
{
return screen instanceof RecipeViewingScreen || screen instanceof VillagerRecipeViewingScreen;
}
@Override
public boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen)
{
if (!isViewingScreen(screen))
return false;
MinecraftClient.getInstance().openScreen(REIHelper.getInstance().getPreviousContainerScreen());
ScreenHelper.getLastOverlay().init();
return true;
}
private static EntryListWidget getEntryListWidget()
{
if (ENTRY_LIST_WIDGET == null) {
ENTRY_LIST_WIDGET = LambdaReflection.getFirstFieldOfType(ContainerScreenOverlay.class, EntryListWidget.class)
.map(field -> (EntryListWidget) LambdaReflection.getFieldValue(null, field))
.orElse(null);
}
return ENTRY_LIST_WIDGET;
}
private static @Nullable EntryStack getCurrentStack(@NotNull MinecraftClient client)
{
double x = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double y = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
if (isViewingScreen(client.currentScreen)) {
for (Element element : client.currentScreen.children()) {
EntryStack stack = getCurrentStack(element, x, y);
if (stack != null)
return stack;
}
}
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
if (!overlay.isPresent())
return RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
EntryListWidget widget = getEntryListWidget();
if (widget == null)
return RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
return getCurrentStack(widget, x, y);
}
private static @Nullable EntryStack getCurrentStack(@NotNull Element element, double mouseX, double mouseY)
{
if (element instanceof EntryWidget) {
EntryWidget entry = (EntryWidget) element;
if (entry.containsMouse(mouseX, mouseY))
return ((EntryWidgetAccessor) entry).lambdacontrols_getCurrentEntry();
} else if (element instanceof EntryListWidget) {
List<EntryListEntryWidget> entries = ((EntryListWidgetAccessor) element).getEntries();
for (EntryListEntryWidget entry : entries) {
if (entry.containsMouse(mouseX, mouseY)) {
return ((EntryWidgetAccessor) entry).lambdacontrols_getCurrentEntry();
}
}
} else if (!(element instanceof ButtonWidget) && element instanceof WidgetWithBounds) {
for (Element child : ((WidgetWithBounds) element).children()) {
EntryStack stack = getCurrentStack(child, mouseX, mouseY);
if (stack != null)
return stack;
}
}
return null;
}
private static PressAction handleShowRecipeUsage(boolean usage)
{
return (client, button, value, action) -> {
if (action.isUnpressed())
return false;
EntryStack stack = RecipeHelper.getInstance().getScreenFocusedStack(client.currentScreen);
if (stack == null) {
stack = getCurrentStack(client);
}
if (stack != null && !stack.isEmpty()) {
stack = stack.copy();
if (usage) {
return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addUsagesFor(stack).setInputNotice(stack).fillPreferredOpenedCategory());
} else {
return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addRecipesFor(stack).setOutputNotice(stack).fillPreferredOpenedCategory());
}
}
return false;
};
}
private static PressAction handlePage(boolean next)
{
return (client, button, value, action) -> {
if (action == ButtonState.RELEASE)
return false;
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
if (!overlay.isPresent())
return false;
EntryListWidget widget = getEntryListWidget();
if (widget == null)
return false;
if (next)
widget.nextPage();
else
widget.previousPage();
widget.updateEntriesPosition();
return true;
};
}
/**
* Returns the handler for category tabs buttons.
*
* @param next True if the action is to switch to the next tab.
* @return The handler.
*/
private static PressAction handleTab(boolean next)
{
return (client, button, value, action) -> {
if (action != ButtonState.RELEASE)
return false;
if (client.currentScreen instanceof RecipeViewingScreen) {
RecipeViewingScreenAccessor screen = (RecipeViewingScreenAccessor) client.currentScreen;
if (next)
screen.getCategoryNext().onClick();
else
screen.getCategoryBack().onClick();
return true;
} else if (client.currentScreen instanceof VillagerRecipeViewingScreen) {
VillagerRecipeViewingScreenAccessor screen = (VillagerRecipeViewingScreenAccessor) client.currentScreen;
List<RecipeCategory<?>> categories = screen.getCategories();
int currentTab = screen.getSelectedCategoryIndex();
screen.setSelectedCategoryIndex(getNextIndex(currentTab, categories.size(), next));
screen.setSelectedRecipeIndex(0);
screen.lambdacontrols_init();
return true;
}
return false;
};
}
private static PressAction handleRecipe(boolean next)
{
return (client, button, value, action) -> {
if (action.isUnpressed())
return false;
if (client.currentScreen instanceof RecipeViewingScreen) {
RecipeViewingScreenAccessor screen = (RecipeViewingScreenAccessor) client.currentScreen;
if (next)
screen.getRecipeNext().onClick();
else
screen.getRecipeBack().onClick();
return true;
} else if (client.currentScreen instanceof VillagerRecipeViewingScreen) {
VillagerRecipeViewingScreenAccessor screen = (VillagerRecipeViewingScreenAccessor) client.currentScreen;
List<RecipeCategory<?>> categories = screen.getCategories();
int currentTab = screen.getSelectedCategoryIndex();
List<RecipeDisplay> recipes = screen.getCategoryMap().get(categories.get(currentTab));
if (recipes.size() == 0)
return true;
int currentRecipe = screen.getSelectedRecipeIndex();
int nextRecipe = getNextIndex(currentRecipe, recipes.size(), next);
if (nextRecipe == 0) {
screen.getScrolling().scrollTo(0.0, true);
} else if (nextRecipe == recipes.size() - 1) {
screen.getScrolling().scrollTo(screen.getScrolling().getMaxScroll(), true);
} else {
double scrollAmount = screen.getScrolling().getMaxScroll() / (float) recipes.size();
screen.getScrolling().offset(next ? scrollAmount : -scrollAmount, true);
}
screen.setSelectedRecipeIndex(nextRecipe);
screen.lambdacontrols_init();
return true;
}
return false;
};
}
private static int getNextIndex(int currentIndex, int size, boolean next)
{
int nextIndex = currentIndex + (next ? 1 : -1);
if (nextIndex < 0)
nextIndex = size - 1;
else if (nextIndex >= size)
nextIndex = 0;
return nextIndex;
}
}

View File

@@ -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,56 +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.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.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.2.0
*/
@Mixin(VillagerRecipeViewingScreen.class)
public interface VillagerRecipeViewingScreenAccessor
{
@Accessor(value = "categoryMap", remap = false)
Map<RecipeCategory<?>, List<RecipeDisplay>> getCategoryMap();
@Accessor(value = "categories", remap = false)
List<RecipeCategory<?>> getCategories();
@Accessor(value = "selectedCategoryIndex", remap = false)
int getSelectedCategoryIndex();
@Accessor(value = "selectedCategoryIndex", remap = false)
void setSelectedCategoryIndex(int selectedCategoryIndex);
@Accessor(value = "selectedRecipeIndex", remap = false)
int getSelectedRecipeIndex();
@Accessor(value = "selectedRecipeIndex", remap = false)
void setSelectedRecipeIndex(int selectedRecipeIndex);
@Accessor(value = "scrolling", remap = false)
ScrollingContainer getScrolling();
@Invoker("init")
void lambdacontrols_init();
}

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

View File

@@ -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,292 +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 com.mojang.blaze3d.systems.RenderSystem;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.LambdaInput;
import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
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.util.math.MatrixStack;
import net.minecraft.screen.slot.Slot;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
/**
* Represents the LambdaControls renderer.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.2.0
*/
public class LambdaControlsRenderer
{
public static final int ICON_SIZE = 20;
private static final int BUTTON_SIZE = 15;
private static final int AXIS_SIZE = 18;
public static int getButtonSize(int button)
{
switch (button) {
case -1:
return 0;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 100:
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 200:
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 100:
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.
*
* @param binding The binding.
* @return The width.
*/
public static int getBindingIconWidth(@NotNull ButtonBinding binding)
{
return getBindingIconWidth(binding.getButton());
}
/**
* Gets the binding icon width.
*
* @param buttons The buttons.
* @return The width.
*/
public static int getBindingIconWidth(int[] buttons)
{
int width = 0;
for (int i = 0; i < buttons.length; i++) {
width += ICON_SIZE;
if (i + 1 < buttons.length) {
width += 2;
}
}
return width;
}
public static Pair<Integer, Integer> drawButton(MatrixStack matrices, int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient 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)
{
int height = 0;
int length = 0;
int currentX = x;
for (int i = 0; i < buttons.length; i++) {
int btn = buttons[i];
int size = drawButton(matrices, currentX, y, btn, client);
if (size > height)
height = size;
length += size;
if (i + 1 < buttons.length) {
length += 2;
currentX = x + length;
}
}
return Pair.of(length, height);
}
@SuppressWarnings("deprecated")
public static int drawButton(MatrixStack matrices, int x, int y, int button, @NotNull MinecraftClient client)
{
boolean second = false;
if (button == -1)
return 0;
else if (button >= 500) {
button -= 1000;
second = true;
}
int controllerType = LambdaControlsClient.get().config.getControllerType().getId();
boolean axis = false;
int buttonOffset = button * 15;
switch (button) {
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
buttonOffset = 7 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
buttonOffset = 8 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_BACK:
buttonOffset = 4 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_START:
buttonOffset = 6 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_GUIDE:
buttonOffset = 5 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
buttonOffset = 15 * 15;
break;
case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
buttonOffset = 16 * 15;
break;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 100:
buttonOffset = 0;
axis = true;
break;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 100:
buttonOffset = 18;
axis = true;
break;
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 100:
buttonOffset = 2 * 18;
axis = true;
break;
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 100:
buttonOffset = 3 * 18;
axis = true;
break;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_X + 200:
buttonOffset = 4 * 18;
axis = true;
break;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y + 200:
buttonOffset = 5 * 18;
axis = true;
break;
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X + 200:
buttonOffset = 6 * 18;
axis = true;
break;
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y + 200:
buttonOffset = 7 * 18;
axis = true;
break;
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 100:
case GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + 200:
buttonOffset = 9 * 15;
break;
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 100:
case GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + 200:
buttonOffset = 10 * 15;
break;
}
client.getTextureManager().bindTexture(axis ? LambdaControlsClient.CONTROLLER_AXIS : LambdaControlsClient.CONTROLLER_BUTTONS);
RenderSystem.disableDepthTest();
int assetSize = axis ? AXIS_SIZE : BUTTON_SIZE;
RenderSystem.color4f(1.0F, second ? 0.0F : 1.0F, 1.0F, 1.0F);
DrawableHelper.drawTexture(matrices, x + (ICON_SIZE / 2 - assetSize / 2), y + (ICON_SIZE / 2 - assetSize / 2),
(float) buttonOffset, (float) (controllerType * (axis ? AXIS_SIZE : BUTTON_SIZE)),
assetSize, assetSize,
256, 256);
RenderSystem.enableDepthTest();
return ICON_SIZE;
}
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);
}
public static int drawButtonTip(MatrixStack matrices, int x, int y, int[] button, @NotNull String action, boolean display, @NotNull MinecraftClient client)
{
if (display) {
int buttonWidth = drawButton(matrices, x, y, button, client).key;
String translatedAction = I18n.translate(action);
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 -10;
}
private static int getButtonTipWidth(@NotNull String action, @NotNull TextRenderer textRenderer)
{
return 15 + 5 + textRenderer.getWidth(action);
}
public static void renderVirtualCursor(@NotNull MatrixStack matrices, @NotNull MinecraftClient client)
{
if (!LambdaControlsClient.get().config.hasVirtualMouse() || (client.currentScreen == null || LambdaInput.isScreenInteractive(client.currentScreen)))
return;
int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
int mouseY = (int) (client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight());
boolean hoverSlot = false;
if (client.currentScreen instanceof HandledScreen) {
HandledScreenAccessor inventoryScreen = (HandledScreenAccessor) client.currentScreen;
int guiLeft = inventoryScreen.getX();
int guiTop = inventoryScreen.getY();
Slot slot = inventoryScreen.lambdacontrols_getSlotAt(mouseX, mouseY);
if (slot != null) {
mouseX = guiLeft + slot.x;
mouseY = guiTop + slot.y;
hoverSlot = true;
}
}
if (!hoverSlot) {
Pair<Integer, Integer> slot = LambdaControlsCompat.getSlotAt(client.currentScreen, mouseX, mouseY);
if (slot != null) {
mouseX = slot.getFirst();
mouseY = slot.getSecond();
hoverSlot = true;
}
}
if (!hoverSlot) {
mouseX -= 8;
mouseY -= 8;
}
drawCursor(matrices, mouseX, mouseY, hoverSlot, client);
}
/**
* Draws the virtual cursor.
*
* @param matrices The matrix stack.
* @param x X coordinate.
* @param y Y coordinate.
* @param hoverSlot True if hovering a slot, else false.
* @param client The client instance.
*/
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.color4f(1.0F, 1.0F, 1.0F, 1.0F);
DrawableHelper.drawTexture(matrices, x, y, hoverSlot ? 16.F : 0.F, LambdaControlsClient.get().config.getVirtualMouseSkin().ordinal() * 16.F, 16, 16, 32, 64);
RenderSystem.enableDepthTest();
}
}

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,48 +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.Controller;
import me.lambdaurora.spruceui.option.SpruceSimpleActionOption;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
/**
* Represents the option to reload the controller mappings.
*/
public class ReloadControllerMappingsOption extends SpruceSimpleActionOption
{
private static final String KEY = "lambdacontrols.menu.reload_controller_mappings";
public ReloadControllerMappingsOption()
{
this(null);
}
public ReloadControllerMappingsOption(@Nullable Consumer<AbstractButtonWidget> before)
{
super(KEY, btn -> {
MinecraftClient client = MinecraftClient.getInstance();
if (before != null)
before.accept(btn);
Controller.updateMappings();
if (client.currentScreen instanceof LambdaControlsSettingsScreen)
client.currentScreen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT,
new TranslatableText("lambdacontrols.controller.mappings.updated"), LiteralText.EMPTY));
}, new TranslatableText("lambdacontrols.tooltip.reload_controller_mappings"));
}
}

View File

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

View File

@@ -1,297 +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.HudSide;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
import me.lambdaurora.spruceui.SpruceTexturedButtonWidget;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.GameMenuScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.text.LiteralText;
import net.minecraft.util.Arm;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
/**
* Represents the touchscreen overlay
*/
public class TouchscreenOverlay extends Screen
{
public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png");
private LambdaControlsClient mod;
private SpruceTexturedButtonWidget jumpButton;
private SpruceTexturedButtonWidget flyButton;
private SpruceTexturedButtonWidget flyUpButton;
private SpruceTexturedButtonWidget flyDownButton;
private int flyButtonEnableTicks = 0;
private int forwardButtonTick = 0;
private SpruceTexturedButtonWidget forwardLeftButton;
private SpruceTexturedButtonWidget forwardRightButton;
private SpruceTexturedButtonWidget startSneakButton;
private SpruceTexturedButtonWidget endSneakButton;
public TouchscreenOverlay(@NotNull LambdaControlsClient mod)
{
super(new LiteralText("Touchscreen overlay"));
this.mod = mod;
this.passEvents = true;
}
@Override
public boolean isPauseScreen()
{
return false;
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers)
{
return false;
}
private void pauseGame(boolean bl)
{
if (this.client == null)
return;
boolean bl2 = this.client.isIntegratedServerRunning() && !this.client.getServer().isRemote();
if (bl2) {
this.client.openScreen(new GameMenuScreen(!bl));
this.client.getSoundManager().pauseAll();
} else {
this.client.openScreen(new GameMenuScreen(true));
}
}
/**
* Updates the forward button ticks cooldown.
*
* @param state The button state.
*/
private void updateForwardButtonsState(boolean state)
{
if (state)
this.forwardButtonTick = -1;
else
this.forwardButtonTick = 20;
}
/**
* Updates the jump buttons.
*/
private void updateJumpButtons()
{
if (this.client == null)
return;
if (this.client.player.abilities.allowFlying && this.client.player.abilities.flying) {
boolean oldStateFly = this.flyButton.visible;
this.jumpButton.visible = false;
this.flyButton.visible = true;
this.flyUpButton.visible = true;
this.flyDownButton.visible = true;
if (oldStateFly != this.flyButton.visible) {
this.flyButtonEnableTicks = 5;
this.handleJump(null, false);
} else if (this.flyButtonEnableTicks > 0)
this.flyButtonEnableTicks--;
} else {
this.jumpButton.visible = true;
this.flyButton.visible = false;
this.flyUpButton.visible = false;
this.flyDownButton.visible = false;
}
}
/**
* Handles the jump button.
*
* @param btn The pressed button.
* @param state The state of the jump button.
*/
private void handleJump(ButtonWidget btn, boolean state)
{
((KeyBindingAccessor) this.client.options.keyJump).lambdacontrols_handlePressState(state);
}
@Override
public void tick()
{
if (this.forwardButtonTick > 0) {
this.forwardButtonTick--;
} else if (this.forwardButtonTick == 0) {
if (this.forwardLeftButton.visible)
this.forwardLeftButton.visible = false;
if (this.forwardRightButton.visible)
this.forwardRightButton.visible = false;
}
this.updateJumpButtons();
}
@Override
protected void init()
{
super.init();
int scaledWidth = this.client.getWindow().getScaledWidth();
int scaledHeight = this.client.getWindow().getScaledHeight();
this.addButton(new TexturedButtonWidget(scaledWidth / 2 - 20, 0, 20, 20, 0, 106, 20, ButtonWidget.WIDGETS_LOCATION, 256, 256,
btn -> this.client.openScreen(new ChatScreen("")), LiteralText.EMPTY));
this.addButton(new TexturedButtonWidget(scaledWidth / 2, 0, 20, 20, 0, 0, 20, WIDGETS_LOCATION, 256, 256,
btn -> this.pauseGame(false)));
// Inventory buttons.
int inventoryButtonX = scaledWidth / 2;
int inventoryButtonY = scaledHeight - 16 - 5;
if (this.client.options.mainArm == Arm.LEFT) {
inventoryButtonX = inventoryButtonX - 91 - 24;
} else {
inventoryButtonX = inventoryButtonX + 91 + 4;
}
this.addButton(new TexturedButtonWidget(inventoryButtonX, inventoryButtonY, 20, 20, 20, 0, 20, WIDGETS_LOCATION, 256, 256,
btn -> {
if (this.client.interactionManager.hasRidingInventory()) {
this.client.player.openRidingInventory();
} else {
this.client.getTutorialManager().onInventoryOpened();
this.client.openScreen(new InventoryScreen(this.client.player));
}
}));
int jumpButtonX, swapHandsX, sneakButtonX;
int sneakButtonY = scaledHeight - 10 - 40 - 5;
if (this.mod.config.getHudSide() == HudSide.LEFT) {
jumpButtonX = scaledWidth - 20 - 20;
swapHandsX = jumpButtonX - 5 - 40;
sneakButtonX = 10 + 20 + 5;
} else {
jumpButtonX = 20;
swapHandsX = jumpButtonX + 5 + 40;
sneakButtonX = scaledWidth - 10 - 40 - 5;
}
// Swap items hand.
this.addButton(new SpruceTexturedButtonWidget(swapHandsX, sneakButtonY, 20, 20, 0, 160, 20, WIDGETS_LOCATION,
(btn, state) -> {
if (state) {
if (!this.client.player.isSpectator()) {
this.client.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN));
}
}
}));
// Drop
this.addButton(new SpruceTexturedButtonWidget(swapHandsX, sneakButtonY + 5 + 20, 20, 20, 20, 160, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.client.options.keyDrop).lambdacontrols_handlePressState(state)));
// Jump keys
this.addButton(this.jumpButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY, 20, 20, 0, 40, 20, WIDGETS_LOCATION,
this::handleJump));
this.addButton(this.flyButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY, 20, 20, 20, 40, 20, WIDGETS_LOCATION,
(btn, state) -> {
if (this.flyButtonEnableTicks == 0) this.client.player.abilities.flying = false;
}));
this.addButton(this.flyUpButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY - 5 - 20, 20, 20, 40, 40, 20, WIDGETS_LOCATION,
this::handleJump));
this.addButton(this.flyDownButton = new SpruceTexturedButtonWidget(jumpButtonX, sneakButtonY + 20 + 5, 20, 20, 60, 40, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.client.options.keySneak).lambdacontrols_handlePressState(state)));
this.updateJumpButtons();
// Movements keys
this.addButton((this.startSneakButton = new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY, 20, 20, 0, 120, 20, WIDGETS_LOCATION,
(btn, state) -> {
if (state) {
((KeyBindingAccessor) this.client.options.keySneak).lambdacontrols_handlePressState(true);
this.startSneakButton.visible = false;
this.endSneakButton.visible = true;
}
})));
this.addButton((this.endSneakButton = new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY, 20, 20, 20, 120, 20, WIDGETS_LOCATION,
(btn, state) -> {
if (state) {
((KeyBindingAccessor) this.client.options.keySneak).lambdacontrols_handlePressState(false);
this.endSneakButton.visible = false;
this.startSneakButton.visible = true;
}
})));
this.endSneakButton.visible = false;
this.addButton(this.forwardLeftButton = new SpruceTexturedButtonWidget(sneakButtonX - 20 - 5, sneakButtonY - 5 - 20, 20, 20, 80, 80, 20, WIDGETS_LOCATION,
(btn, state) -> {
((KeyBindingAccessor) this.client.options.keyForward).lambdacontrols_handlePressState(state);
((KeyBindingAccessor) this.client.options.keyLeft).lambdacontrols_handlePressState(state);
this.updateForwardButtonsState(state);
}));
this.forwardLeftButton.visible = false;
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION,
(btn, state) -> {
((KeyBindingAccessor) this.client.options.keyForward).lambdacontrols_handlePressState(state);
this.updateForwardButtonsState(state);
this.forwardLeftButton.visible = true;
this.forwardRightButton.visible = true;
}));
this.addButton(this.forwardRightButton = new SpruceTexturedButtonWidget(sneakButtonX + 20 + 5, sneakButtonY - 5 - 20, 20, 20, 100, 80, 20, WIDGETS_LOCATION,
(btn, state) -> {
((KeyBindingAccessor) this.client.options.keyForward).lambdacontrols_handlePressState(state);
((KeyBindingAccessor) this.client.options.keyRight).lambdacontrols_handlePressState(state);
this.updateForwardButtonsState(state);
}));
this.forwardRightButton.visible = true;
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX + 20 + 5, sneakButtonY, 20, 20, 20, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.client.options.keyRight).lambdacontrols_handlePressState(state)));
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX, sneakButtonY + 20 + 5, 20, 20, 40, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.client.options.keyBack).lambdacontrols_handlePressState(state)));
this.addButton(new SpruceTexturedButtonWidget(sneakButtonX - 20 - 5, sneakButtonY, 20, 20, 60, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.client.options.keyLeft).lambdacontrols_handlePressState(state)));
this.buttons.forEach(button -> {
if (button instanceof SpruceTexturedButtonWidget) {
((SpruceTexturedButtonWidget) button).setSilent(true);
}
});
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button)
{
if (mouseY >= (double) (this.height - 22) && this.client != null && this.client.player != null) {
int centerX = this.width / 2;
if (mouseX >= (double) (centerX - 90) && mouseX <= (double) (centerX + 90)) {
for (int slot = 0; slot < 9; ++slot) {
int slotX = centerX - 90 + slot * 20 + 2;
if (mouseX >= (double) slotX && mouseX <= (double) (slotX + 20)) {
this.client.player.inventory.selectedSlot = slot;
return true;
}
}
}
}
return super.mouseClicked(mouseX, mouseY, button);
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY)
{
if (button == GLFW.GLFW_MOUSE_BUTTON_1 && this.client != null) {
if (deltaY > 0.01)
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 2);
else if (deltaY < 0.01)
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs(deltaY / 5.0), 1);
if (deltaX > 0.01)
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 2);
else if (deltaX < 0.01)
this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs(deltaX / 5.0), 1);
}
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
}

View File

@@ -1,21 +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 net.minecraft.client.gui.widget.AbstractButtonWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(AbstractButtonWidget.class)
public interface AbstractButtonWidgetAccessor
{
@Accessor("height")
int getHeight();
}

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,69 +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.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer;
import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* Represents the mixin for the class ContainerScreen.
*/
@Mixin(HandledScreen.class)
public abstract class HandledScreenMixin implements HandledScreenAccessor
{
@Accessor("x")
public abstract int getX();
@Accessor("y")
public abstract int getY();
@Invoker("getSlotAt")
public abstract Slot lambdacontrols_getSlotAt(double posX, double posY);
@Invoker("isClickOutsideBounds")
public abstract boolean lambdacontrols_isClickOutsideBounds(double mouseX, double mouseY, int x, int y, int button);
@Invoker("onMouseClick")
public abstract void lambdacontrols_onMouseClick(@Nullable Slot slot, int slotId, int clickData, SlotActionType actionType);
@Inject(method = "render", at = @At("RETURN"))
public void onRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci)
{
if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) {
MinecraftClient client = MinecraftClient.getInstance();
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_B}, "lambdacontrols.action.exit", true, client) + 2;
if (LambdaControlsCompat.isReiPresent()) {
x = 2;
y -= 24;
}
x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_X}, "lambdacontrols.action.pickup", true, client) + 2;
LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_Y}, "lambdacontrols.action.quick_move", true, client);
}
}
}

View File

@@ -1,71 +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.LambdaControlsConfig;
import me.lambdaurora.lambdacontrols.client.util.MouseAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Invoker;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/**
* Adds extra access to the mouse.
*/
@Mixin(Mouse.class)
public abstract class MouseMixin implements MouseAccessor
{
@Shadow
@Final
private MinecraftClient client;
@Invoker("onCursorPos")
public abstract void lambdacontrols_onCursorPos(long window, double x, double y);
@Inject(method = "method_1605", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/client/gui/screen/Screen;mouseReleased(DDI)Z"))
private void onMouseBackButton(boolean[] result, double mouseX, double mouseY, int button, CallbackInfo ci)
{
if (!result[0] && button == GLFW.GLFW_MOUSE_BUTTON_4 && this.client.currentScreen != null) {
if (LambdaControlsClient.get().input.tryGoBack(this.client.currentScreen)) {
result[0] = true;
}
}
}
@Inject(method = "isCursorLocked", at = @At("HEAD"), cancellable = true)
private void isCursorLocked(CallbackInfoReturnable<Boolean> ci)
{
if (this.client.currentScreen == null) {
LambdaControlsConfig config = LambdaControlsClient.get().config;
if (config.getControlsMode() == ControlsMode.CONTROLLER && config.hasVirtualMouse()) {
ci.setReturnValue(true);
ci.cancel();
}
}
}
@Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true)
private void onCursorLocked(CallbackInfo ci)
{
LambdaControlsConfig config = LambdaControlsClient.get().config;
if (config.getControlsMode() == ControlsMode.TOUCHSCREEN
|| (config.getControlsMode() == ControlsMode.CONTROLLER && config.hasVirtualMouse()))
ci.cancel();
}
}

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

View File

@@ -1,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);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -1,135 +0,0 @@
{
"key.lambdacontrols.look_down": "Look down",
"key.lambdacontrols.look_left": "Look left",
"key.lambdacontrols.look_right": "Look right",
"key.lambdacontrols.look_up": "Look up",
"key.lambdacontrols.ring": "Show controls ring",
"lambdacontrols.action.attack": "Attack",
"lambdacontrols.action.back": "Back",
"lambdacontrols.action.chat": "Open Chat",
"lambdacontrols.action.drop_item": "Drop Item",
"lambdacontrols.action.exit": "Exit",
"lambdacontrols.action.forward": "Forward",
"lambdacontrols.action.hit": "Hit",
"lambdacontrols.action.hotbar_left": "Hotbar left",
"lambdacontrols.action.hotbar_right": "Hotbar right",
"lambdacontrols.action.inventory": "Inventory",
"lambdacontrols.action.jump": "Jump",
"lambdacontrols.action.left": "Left",
"lambdacontrols.action.pause_game": "Pause Game",
"lambdacontrols.action.pick_block": "Pick Block",
"lambdacontrols.action.pickup": "Pickup",
"lambdacontrols.action.pickup_all": "Pickup all",
"lambdacontrols.action.place": "Place",
"lambdacontrols.action.player_list": "Player List",
"lambdacontrols.action.quick_move": "Quick move",
"lambdacontrols.action.right": "Right",
"lambdacontrols.action.screenshot": "Take Screenshot",
"lambdacontrols.action.sneak": "Sneak",
"lambdacontrols.action.sprint": "Sprint",
"lambdacontrols.action.swap_hands": "Swap Hands",
"lambdacontrols.action.toggle_perspective": "Toggle Perspective",
"lambdacontrols.action.toggle_smooth_camera": "Toggle Cinematic Camera",
"lambdacontrols.action.use": "Use",
"lambdacontrols.action.zoom": "Zoom",
"lambdacontrols.action.zoom.in": "Increase Zoom",
"lambdacontrols.action.zoom.out": "Decrease Zoom",
"lambdacontrols.action.zoom.reset": "Reset Zoom",
"lambdacontrols.button.a": "A",
"lambdacontrols.button.b": "B",
"lambdacontrols.button.x": "X",
"lambdacontrols.button.y": "Y",
"lambdacontrols.button.left_bumper": "Left bumper",
"lambdacontrols.button.right_bumper": "Right bumper",
"lambdacontrols.button.back": "Back",
"lambdacontrols.button.start": "Start",
"lambdacontrols.button.guide": "Guide",
"lambdacontrols.button.left_thumb": "Left thumb",
"lambdacontrols.button.right_thumb": "Right thumb",
"lambdacontrols.button.dpad_up": "DPAD up",
"lambdacontrols.button.dpad_right": "DPAD right",
"lambdacontrols.button.dpad_down": "DPAD down",
"lambdacontrols.button.dpad_left": "DPAD left",
"lambdacontrols.axis.left_x+": "Left X+",
"lambdacontrols.axis.left_y+": "Left Y+",
"lambdacontrols.axis.right_x+": "Right X+",
"lambdacontrols.axis.right_y+": "Right Y+",
"lambdacontrols.axis.left_trigger": "Left trigger",
"lambdacontrols.axis.right_trigger": "Right trigger",
"lambdacontrols.axis.left_x-": "Left X-",
"lambdacontrols.axis.left_y-": "Left Y-",
"lambdacontrols.axis.right_x-": "Right X-",
"lambdacontrols.axis.right_y-": "Right Y-",
"lambdacontrols.button.unknown": "Unknown (%d)",
"lambdacontrols.controller.connected": "Controller %d connected.",
"lambdacontrols.controller.disconnected": "Controller %d disconnected.",
"lambdacontrols.controller.mappings.1": "To configure the controller mappings, please use %sSDL2 Gamepad Tool%s",
"lambdacontrols.controller.mappings.3": "and put the mapping in `%s.minecraft/config/gamecontrollerdb.txt%s`.",
"lambdacontrols.controller.mappings.error": "Error while loading mappings.",
"lambdacontrols.controller.mappings.error.write": "Error while writing mappings to file.",
"lambdacontrols.controller.mappings.updated": "Updated mappings!",
"lambdacontrols.controller_type.default": "default",
"lambdacontrols.controller_type.dualshock": "DualShock",
"lambdacontrols.controller_type.switch": "Switch",
"lambdacontrols.controller_type.xbox": "Xbox",
"lambdacontrols.controller_type.steam": "Steam",
"lambdacontrols.controller_type.ouya": "OUYA",
"lambdacontrols.controls_mode.default": "Keyboard/Mouse",
"lambdacontrols.controls_mode.controller": "Controller",
"lambdacontrols.controls_mode.touchscreen": "Touchscreen",
"lambdacontrols.hud_side.left": "left",
"lambdacontrols.hud_side.right": "right",
"lambdacontrols.menu.auto_switch_mode": "Auto Switch Mode",
"lambdacontrols.menu.controller": "Controller",
"lambdacontrols.menu.controller2": "Second Controller",
"lambdacontrols.menu.controller_type": "Controller Type",
"lambdacontrols.menu.controls_mode": "Mode",
"lambdacontrols.menu.dead_zone": "Dead Zone",
"lambdacontrols.menu.fast_block_placing": "Fast Block Placing",
"lambdacontrols.menu.fly_drifting": "Fly Drifting",
"lambdacontrols.menu.fly_drifting_vertical": "Vertical Fly Drifting",
"lambdacontrols.menu.hud_enable": "Enable HUD",
"lambdacontrols.menu.hud_side": "HUD Side",
"lambdacontrols.menu.invert_right_x_axis": "Invert Right X",
"lambdacontrols.menu.invert_right_y_axis": "Invert Right Y",
"lambdacontrols.menu.keyboard_controls": "Keyboard Controls...",
"lambdacontrols.menu.mappings.open_input_str": "Open Mappings File Editor",
"lambdacontrols.menu.mouse_speed": "Mouse Speed",
"lambdacontrols.menu.reacharound.horizontal": "Front Block Placing",
"lambdacontrols.menu.reacharound.vertical": "Vertical Reacharound",
"lambdacontrols.menu.reload_controller_mappings": "Reload Controller Mappings",
"lambdacontrols.menu.rotation_speed": "Rotation Speed",
"lambdacontrols.menu.title": "LambdaControls - Settings",
"lambdacontrols.menu.title.controller": "Controller Options",
"lambdacontrols.menu.title.controller_controls": "Controller Controls",
"lambdacontrols.menu.title.gameplay": "Gameplay Options",
"lambdacontrols.menu.title.general": "General Options",
"lambdacontrols.menu.title.hud": "HUD Options",
"lambdacontrols.menu.title.mappings.string": "Mappings File Editor",
"lambdacontrols.menu.unfocused_input": "Unfocused Input",
"lambdacontrols.menu.virtual_mouse": "Virtual Mouse",
"lambdacontrols.menu.virtual_mouse.skin": "Virtual Mouse Skin",
"lambdacontrols.narrator.unbound": "Unbound %s",
"lambdacontrols.not_bound": "Not bound",
"lambdacontrols.tooltip.auto_switch_mode": "If the controls mode should be switched to Controller automatically if one is connected.",
"lambdacontrols.tooltip.controller2": "Second controller to use, which allows Joy-Cons support for example.",
"lambdacontrols.tooltip.controller_type": "The controller type to display the correct buttons.",
"lambdacontrols.tooltip.controls_mode": "The controls mode.",
"lambdacontrols.tooltip.dead_zone": "The dead zone for the controller's analogue sticks.",
"lambdacontrols.tooltip.fast_block_placing": "While flying in creative mode, enables fast block placing depending on your speed. §cOn some servers this might be considered as cheating.",
"lambdacontrols.tooltip.fly_drifting": "While flying, enables Vanilla drifting/inertia.",
"lambdacontrols.tooltip.fly_drifting_vertical": "While flying, enables Vanilla vertical drifting/intertia.",
"lambdacontrols.tooltip.hud_enable": "Toggles the on-screen controller button indicator.",
"lambdacontrols.tooltip.hud_side": "The position of the HUD.",
"lambdacontrols.tooltip.mouse_speed": "The controller's emulated mouse speed.",
"lambdacontrols.tooltip.reacharound.horizontal": "Enables front block placing, §cmight be considered cheating on some servers§r.",
"lambdacontrols.tooltip.reacharound.vertical": "Enables vertical reacharound, §cmight be considered cheating on some servers§r.",
"lambdacontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file.",
"lambdacontrols.tooltip.rotation_speed": "The camera rotation speed in controller mode.",
"lambdacontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused.",
"lambdacontrols.tooltip.virtual_mouse": "Enable the virtual mouse which is handful in the case of a splitscreen.",
"lambdacontrols.virtual_mouse.skin.default_light": "Default Light",
"lambdacontrols.virtual_mouse.skin.default_dark": "Default Dark",
"lambdacontrols.virtual_mouse.skin.second_light": "Second Light",
"lambdacontrols.virtual_mouse.skin.second_dark": "Second Dark"
}

View File

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

View File

@@ -1,135 +0,0 @@
{
"key.lambdacontrols.look_down": "Regarder en bas",
"key.lambdacontrols.look_left": "Regarder à gauche",
"key.lambdacontrols.look_right": "Regarder à droite",
"key.lambdacontrols.look_up": "Regarder en haut",
"key.lambdacontrols.ring": "Affiche l'anneau de contrôle",
"lambdacontrols.action.attack": "Attaquer",
"lambdacontrols.action.back": "Reculer",
"lambdacontrols.action.chat": "Ouvrir le tchat",
"lambdacontrols.action.drop_item": "Jeter l'objet",
"lambdacontrols.action.exit": "Sortir",
"lambdacontrols.action.forward": "Avancer",
"lambdacontrols.action.hit": "Taper",
"lambdacontrols.action.hotbar_left": "Case à gauche de la barre d'action",
"lambdacontrols.action.hotbar_right": "Case à droite de la barre d'action",
"lambdacontrols.action.inventory": "Inventaire",
"lambdacontrols.action.jump": "Sauter",
"lambdacontrols.action.left": "Aller à gauche",
"lambdacontrols.action.pause_game": "Mettre en pause le jeu",
"lambdacontrols.action.pick_block": "Choisir le bloc",
"lambdacontrols.action.pickup": "Prendre",
"lambdacontrols.action.pickup_all": "Prendre tout",
"lambdacontrols.action.place": "Placer",
"lambdacontrols.action.player_list": "Afficher la liste des joueurs",
"lambdacontrols.action.quick_move": "Mouvement rapide",
"lambdacontrols.action.right": "Aller à droite",
"lambdacontrols.action.screenshot": "Prendre une capture d'écran",
"lambdacontrols.action.sneak": "S'accroupir",
"lambdacontrols.action.sprint": "Courir",
"lambdacontrols.action.swap_hands": "Échanger de mains",
"lambdacontrols.action.toggle_perspective": "Changer de point de vue",
"lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique",
"lambdacontrols.action.use": "Utiliser",
"lambdacontrols.action.zoom": "Zoom",
"lambdacontrols.action.zoom.in": "Augmenter le zoom",
"lambdacontrols.action.zoom.out": "Diminuer le zoom",
"lambdacontrols.action.zoom.reset": "Remettre le zoom à zéro",
"lambdacontrols.button.a": "A",
"lambdacontrols.button.b": "B",
"lambdacontrols.button.x": "X",
"lambdacontrols.button.y": "Y",
"lambdacontrols.button.left_bumper": "Gâchette gauche",
"lambdacontrols.button.right_bumper": "Gâchette droite",
"lambdacontrols.button.back": "Retour",
"lambdacontrols.button.start": "Touche Menu",
"lambdacontrols.button.guide": "Guide",
"lambdacontrols.button.left_thumb": "Stick gauche",
"lambdacontrols.button.right_thumb": "Stick droit",
"lambdacontrols.button.dpad_up": "D-Pad haut",
"lambdacontrols.button.dpad_right": "D-Pad droit",
"lambdacontrols.button.dpad_down": "D-Pad bas",
"lambdacontrols.button.dpad_left": "D-Pad gauche",
"lambdacontrols.axis.left_x+": "X+ Gauche",
"lambdacontrols.axis.left_y+": "Y+ Gauche",
"lambdacontrols.axis.right_x+": "X+ Droit",
"lambdacontrols.axis.right_y+": "Y+ Droit",
"lambdacontrols.axis.left_trigger": "Gâchette gauche",
"lambdacontrols.axis.right_trigger": "Gâchette droite",
"lambdacontrols.axis.left_x-": "X- Gauche",
"lambdacontrols.axis.left_y-": "Y- Gauche",
"lambdacontrols.axis.right_x-": "X- Droit",
"lambdacontrols.axis.right_y-": "Y- Droit",
"lambdacontrols.button.unknown": "Inconnu (%d)",
"lambdacontrols.controller.connected": "Manette %d connecté.",
"lambdacontrols.controller.disconnected": "Manette %d déconnecté.",
"lambdacontrols.controller.mappings.1": "Pour configurer les correspondances de la manette, veuillez utiliser %sSDL2 Gamepad Tool%s",
"lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.",
"lambdacontrols.controller.mappings.error": "Une erreur est apparue pendant le chargement des manettes.",
"lambdacontrols.controller.mappings.error.write": "Une erreur est apparue pendant l'écriture des manettes au fichier.",
"lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!",
"lambdacontrols.controller_type.default": "default",
"lambdacontrols.controller_type.dualshock": "DualShock",
"lambdacontrols.controller_type.switch": "Switch",
"lambdacontrols.controller_type.xbox": "Xbox",
"lambdacontrols.controller_type.steam": "Steam",
"lambdacontrols.controller_type.ouya": "OUYA",
"lambdacontrols.controls_mode.default": "Clavier/Souris",
"lambdacontrols.controls_mode.controller": "Manette",
"lambdacontrols.controls_mode.touchscreen": "Tactile",
"lambdacontrols.hud_side.left": "gauche",
"lambdacontrols.hud_side.right": "droit",
"lambdacontrols.menu.auto_switch_mode": "Changement auto de mode",
"lambdacontrols.menu.controller": "Manette",
"lambdacontrols.menu.controller2": "Deuxième manette",
"lambdacontrols.menu.controller_type": "Type de manette",
"lambdacontrols.menu.controls_mode": "Mode",
"lambdacontrols.menu.dead_zone": "Zone morte",
"lambdacontrols.menu.fast_block_placing": "Placement rapide de blocs",
"lambdacontrols.menu.fly_drifting": "Inertie de vol",
"lambdacontrols.menu.fly_drifting_vertical": "Inertie verticale de vol",
"lambdacontrols.menu.hud_enable": "Activer le HUD",
"lambdacontrols.menu.hud_side": "Côté du HUD",
"lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)",
"lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)",
"lambdacontrols.menu.keyboard_controls": "Contrôles clavier...",
"lambdacontrols.menu.mappings.open_input_str": "Ouvrir l'éditeur de fichier des manettes",
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
"lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc",
"lambdacontrols.menu.reacharound.vertical": "Placement vertical",
"lambdacontrols.menu.reload_controller_mappings": "Recharger les manettes",
"lambdacontrols.menu.rotation_speed": "Vitesse de rotation",
"lambdacontrols.menu.title": "LambdaControls - Paramètres",
"lambdacontrols.menu.title.controller": "Options de manettes",
"lambdacontrols.menu.title.controller_controls": "Contrôles de la manette",
"lambdacontrols.menu.title.gameplay": "Options de Gameplay",
"lambdacontrols.menu.title.general": "Options générales",
"lambdacontrols.menu.title.hud": "Options du HUD",
"lambdacontrols.menu.title.mappings.string": "Éditeur du fichier des manettes",
"lambdacontrols.menu.unfocused_input": "Entrée en fond",
"lambdacontrols.menu.virtual_mouse": "Souris virtuelle",
"lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle",
"lambdacontrols.narrator.unbound": "Délier %s",
"lambdacontrols.not_bound": "Non défini",
"lambdacontrols.tooltip.auto_switch_mode": "Détermine si le mode de contrôle doit automatiquement changer sur Manette si une manette est connectée et inversement.",
"lambdacontrols.tooltip.controller2": "Défini une deuxième manette, utile dans le cas d'utilisation de Joy-Cons.",
"lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.",
"lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.",
"lambdacontrols.tooltip.dead_zone": "Zone morte des axes de la manette.",
"lambdacontrols.tooltip.fast_block_placing": "Active le placement rapide de blocs en vol.",
"lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement Vanilla.",
"lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical Vanilla.",
"lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.",
"lambdacontrols.tooltip.hud_side": "Change la position du HUD.",
"lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.",
"lambdacontrols.tooltip.reacharound.horizontal": "Active le placement avant de blocs, §cpeut être considérer comme de la triche sur certains serveurs§r.",
"lambdacontrols.tooltip.reacharound.vertical": "Active le placement vertical de blocs, c'est-à-dire de blocs en dessous du bloc sur lequel vous êtes placé, §cpeut être considérer comme de la triche sur certains serveurs§r.",
"lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes.",
"lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.",
"lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.",
"lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.",
"lambdacontrols.virtual_mouse.skin.default_light": "défaut clair",
"lambdacontrols.virtual_mouse.skin.default_dark": "défaut foncé",
"lambdacontrols.virtual_mouse.skin.second_light": "second clair",
"lambdacontrols.virtual_mouse.skin.second_dark": "second foncé"
}

View File

@@ -1,135 +0,0 @@
{
"key.lambdacontrols.look_down": "Regarder en bas",
"key.lambdacontrols.look_left": "Regarder à gauche",
"key.lambdacontrols.look_right": "Regarder à droite",
"key.lambdacontrols.look_up": "Regarder en haut",
"key.lambdacontrols.ring": "Affiche l'anneau de contrôle",
"lambdacontrols.action.attack": "Attaquer",
"lambdacontrols.action.back": "Reculer",
"lambdacontrols.action.chat": "Ouvrir le tchat",
"lambdacontrols.action.drop_item": "Jeter l'objet",
"lambdacontrols.action.exit": "Sortir",
"lambdacontrols.action.forward": "Avancer",
"lambdacontrols.action.hit": "Taper",
"lambdacontrols.action.hotbar_left": "Case à gauche de la barre d'action",
"lambdacontrols.action.hotbar_right": "Case à droite de la barre d'action",
"lambdacontrols.action.inventory": "Inventaire",
"lambdacontrols.action.jump": "Sauter",
"lambdacontrols.action.left": "Aller à gauche",
"lambdacontrols.action.pause_game": "Mettre en pause le jeu",
"lambdacontrols.action.pick_block": "Choisir le bloc",
"lambdacontrols.action.pickup": "Prendre",
"lambdacontrols.action.pickup_all": "Prendre tout",
"lambdacontrols.action.place": "Placer",
"lambdacontrols.action.player_list": "Afficher la liste des joueurs",
"lambdacontrols.action.quick_move": "Mouvement rapide",
"lambdacontrols.action.right": "Aller à droite",
"lambdacontrols.action.screenshot": "Prendre une capture d'écran",
"lambdacontrols.action.sneak": "S'accroupir",
"lambdacontrols.action.sprint": "Courir",
"lambdacontrols.action.swap_hands": "Échanger de mains",
"lambdacontrols.action.toggle_perspective": "Changer de point de vue",
"lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique",
"lambdacontrols.action.use": "Utiliser",
"lambdacontrols.action.zoom": "Zoom",
"lambdacontrols.action.zoom.in": "Augmenter le zoom",
"lambdacontrols.action.zoom.out": "Diminuer le zoom",
"lambdacontrols.action.zoom.reset": "Remettre le zoom à zéro",
"lambdacontrols.button.a": "A",
"lambdacontrols.button.b": "B",
"lambdacontrols.button.x": "X",
"lambdacontrols.button.y": "Y",
"lambdacontrols.button.left_bumper": "Gâchette gauche",
"lambdacontrols.button.right_bumper": "Gâchette droite",
"lambdacontrols.button.back": "Retour",
"lambdacontrols.button.start": "Touche Menu",
"lambdacontrols.button.guide": "Guide",
"lambdacontrols.button.left_thumb": "Stick gauche",
"lambdacontrols.button.right_thumb": "Stick droit",
"lambdacontrols.button.dpad_up": "D-Pad haut",
"lambdacontrols.button.dpad_right": "D-Pad droit",
"lambdacontrols.button.dpad_down": "D-Pad bas",
"lambdacontrols.button.dpad_left": "D-Pad gauche",
"lambdacontrols.axis.left_x+": "X+ Gauche",
"lambdacontrols.axis.left_y+": "Y+ Gauche",
"lambdacontrols.axis.right_x+": "X+ Droit",
"lambdacontrols.axis.right_y+": "Y+ Droit",
"lambdacontrols.axis.left_trigger": "Gâchette gauche",
"lambdacontrols.axis.right_trigger": "Gâchette droite",
"lambdacontrols.axis.left_x-": "X- Gauche",
"lambdacontrols.axis.left_y-": "Y- Gauche",
"lambdacontrols.axis.right_x-": "X- Droit",
"lambdacontrols.axis.right_y-": "Y- Droit",
"lambdacontrols.button.unknown": "Inconnu (%d)",
"lambdacontrols.controller.connected": "Manette %d connecté.",
"lambdacontrols.controller.disconnected": "Manette %d déconnecté.",
"lambdacontrols.controller.mappings.1": "Pour configurer les correspondances de la manette, veuillez utiliser %sSDL2 Gamepad Tool%s",
"lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.",
"lambdacontrols.controller.mappings.error": "Une erreur est apparue pendant le chargement des manettes.",
"lambdacontrols.controller.mappings.error.write": "Une erreur est apparue pendant l'écriture des manettes au fichier.",
"lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!",
"lambdacontrols.controller_type.default": "default",
"lambdacontrols.controller_type.dualshock": "DualShock",
"lambdacontrols.controller_type.switch": "Switch",
"lambdacontrols.controller_type.xbox": "Xbox",
"lambdacontrols.controller_type.steam": "Steam",
"lambdacontrols.controller_type.ouya": "OUYA",
"lambdacontrols.controls_mode.default": "Clavier/Souris",
"lambdacontrols.controls_mode.controller": "Manette",
"lambdacontrols.controls_mode.touchscreen": "Tactile",
"lambdacontrols.hud_side.left": "gauche",
"lambdacontrols.hud_side.right": "droit",
"lambdacontrols.menu.auto_switch_mode": "Changement auto de mode",
"lambdacontrols.menu.controller": "Manette",
"lambdacontrols.menu.controller2": "Deuxième manette",
"lambdacontrols.menu.controller_type": "Type de manette",
"lambdacontrols.menu.controls_mode": "Mode",
"lambdacontrols.menu.dead_zone": "Zone morte",
"lambdacontrols.menu.fast_block_placing": "Placement rapide de blocs",
"lambdacontrols.menu.fly_drifting": "Inertie de vol",
"lambdacontrols.menu.fly_drifting_vertical": "Inertie verticale de vol",
"lambdacontrols.menu.hud_enable": "Activer le HUD",
"lambdacontrols.menu.hud_side": "Côté du HUD",
"lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)",
"lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)",
"lambdacontrols.menu.keyboard_controls": "Contrôles clavier...",
"lambdacontrols.menu.mappings.open_input_str": "Ouvrir l'éditeur de fichier des manettes",
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
"lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc",
"lambdacontrols.menu.reacharound.vertical": "Placement vertical",
"lambdacontrols.menu.reload_controller_mappings": "Recharger les manettes",
"lambdacontrols.menu.rotation_speed": "Vitesse de rotation",
"lambdacontrols.menu.title": "LambdaControls - Paramètres",
"lambdacontrols.menu.title.controller": "Options de manettes",
"lambdacontrols.menu.title.controller_controls": "Contrôles de la manette",
"lambdacontrols.menu.title.gameplay": "Options de Gameplay",
"lambdacontrols.menu.title.general": "Options générales",
"lambdacontrols.menu.title.hud": "Options du HUD",
"lambdacontrols.menu.title.mappings.string": "Éditeur du fichier des manettes",
"lambdacontrols.menu.unfocused_input": "Entrée en fond",
"lambdacontrols.menu.virtual_mouse": "Souris virtuelle",
"lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle",
"lambdacontrols.narrator.unbound": "Délier %s",
"lambdacontrols.not_bound": "Non défini",
"lambdacontrols.tooltip.auto_switch_mode": "Détermine si le mode de contrôle doit automatiquement changer sur Manette si une manette est connectée et inversement.",
"lambdacontrols.tooltip.controller2": "Défini une deuxième manette, utile dans le cas d'utilisation de Joy-Cons.",
"lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.",
"lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.",
"lambdacontrols.tooltip.dead_zone": "Zone morte des axes de la manette.",
"lambdacontrols.tooltip.fast_block_placing": "Active le placement rapide de blocs en vol.",
"lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement Vanilla.",
"lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical Vanilla.",
"lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.",
"lambdacontrols.tooltip.hud_side": "Change la position du HUD.",
"lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.",
"lambdacontrols.tooltip.reacharound.horizontal": "Active le placement avant de blocs, §cpeut être considérer comme de la triche sur certains serveurs§r.",
"lambdacontrols.tooltip.reacharound.vertical": "Active le placement vertical de blocs, c'est-à-dire de blocs en dessous du bloc sur lequel vous êtes placé, §cpeut être considérer comme de la triche sur certains serveurs§r.",
"lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes.",
"lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.",
"lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.",
"lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.",
"lambdacontrols.virtual_mouse.skin.default_light": "défaut clair",
"lambdacontrols.virtual_mouse.skin.default_dark": "défaut foncé",
"lambdacontrols.virtual_mouse.skin.second_light": "second clair",
"lambdacontrols.virtual_mouse.skin.second_dark": "second foncé"
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,117 +0,0 @@
# LambdaControls configuration.
# The controls mode. Available modes: default, controller, touchscreen
controls = "default"
# Auto switch mode.
auto_switch_mode = false
# Debug mode
debug = false
[hud]
# Enables the HUD.
enable = true
# Dertermines where the movements buttons are.
side = "left"
# Gameplay settings
[gameplay]
# Enables fast block placing like in Bedrock Edition.
fast_block_placing = true
# Fly behaviors
[gameplay.fly]
# Enables fly drifting.
drifting = false
# Enables vertical fly drifting.
vertical_drifting = true
[gameplay.reacharound]
# Enables front block placing like in Bedrock Edition.
horizontal = false
# Enables vertical reacharound.
vertical = false
# Enables front block placing outline.
outline = true
# The color in a hexadecimal format of the outline.
outline_color = "#ffffff66"
# Controller settings
[controller]
# Controller to use.
id = 0
# Second controller to use.
id2 = -1
# Controller's type.
type = "default"
# Controller's dead zone.
dead_zone = 0.20
# Rotation speed for look directions.
rotation_speed = 10.0
# Mouse speed in GUI.
mouse_speed = 30.0
# Inverts the right X axis.
invert_right_x_axis = false
# Inverts the right Y axis.
invert_right_y_axis = false
# Allow unfocused input.
unfocused_input = false
# Virtual mouse.
virtual_mouse = false
# Virtual mouse skin
virtual_mouse_skin = "default_light"
# Controller controls.
[controller.controls]
# Attack control.
attack = "105"
# Back control.
back = "201"
# Open chat control.
chat = "12"
# Drop item control.
drop_item = "1"
# Forward control.
forward = "101"
# Hot-bar left control.
hotbar_left = "4"
# Hot-bar right control.
hotbar_right = "5"
# Inventory control.
inventory = "3"
# Jump control.
jump = "0"
# Left movement control.
left = "200"
# Pause game control.
pause_game = "7"
# Pick block control.
pick_block = "14"
# Show player list control.
player_list = "6"
# Right movement control.
right = "100"
# Take screenshot control.
screenshot = "11+0"
# Down slot control.
slot_down = "13"
# Left slot control.
slot_left = "14"
# Right slot control.
slot_right = "12"
# Up slot control.
slot_up = "11"
# Sneak control.
sneak = "10"
# Sprint control.
sprint = "9"
# Swap hands control.
swap_hands = "2"
# Switch to back tab control.
tab_back = "4"
# Switch to next tab control.
tab_next = "5"
# Toggle perspective control.
toggle_perspective = "11+3"
# Toggle smooth camera control.
toggle_smooth_camera = "-1"
# Use control.
use = "104"
# Zoom control.
zoom = "11+2"

View File

@@ -1,57 +0,0 @@
{
"schemaVersion": 1,
"id": "lambdacontrols",
"name": "LambdaControls",
"version": "${version}",
"description": "Adds better controls: controller and touchscreen support.",
"authors": [
"LambdAurora"
],
"contact": {
"homepage": "https://www.curseforge.com/minecraft/mc-mods/lambdacontrols",
"sources": "https://github.com/LambdAurora/LambdaControls.git",
"issues": "https://github.com/LambdAurora/LambdaControls/issues"
},
"license": "MIT",
"icon": "assets/lambdacontrols/icon.png",
"environment": "client",
"entrypoints": {
"main": [
"me.lambdaurora.lambdacontrols.LambdaControls"
],
"client": [
"me.lambdaurora.lambdacontrols.client.LambdaControlsClient"
],
"modmenu": [
"me.lambdaurora.lambdacontrols.client.LambdaControlsModMenu"
]
},
"mixins": [
"lambdacontrols.mixins.json",
"lambdacontrols_compat.mixins.json"
],
"depends": {
"fabricloader": ">=0.9.0",
"fabric": ">=0.4.0",
"minecraft": ">=1.16.2",
"spruceui": ">=1.6.3"
},
"recommends": {
"modmenu": ">=1.12.2"
},
"suggests": {
"flamingo": "*",
"roughlyenoughitems": ">=4.5.5",
"okzoomer": ">=4.0.0"
},
"breaks": {
"modmenu": "<1.12.2",
"optifabric": "*"
},
"custom": {
"modupdater": {
"strategy": "curseforge",
"projectID": 354231
}
}
}

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,27 @@ 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.19
yarn_mappings=1.16.2+build.25 yarn_mappings=1.19+build.1
loader_version=0.9.1+build.205 loader_version=0.14.7
# Mod Properties # Mod Properties
mod_version = 1.5.0 mod_version = 1.3.0
maven_group = me.lambdaurora.lambdacontrols maven_group = eu.midnightdust
archives_base_name = lambdacontrols archives_base_name = midnightcontrols
modrinth_id=bXX9h73M
# 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.55.2+1.19
spruceui_version=1.6.4 sodium_version=mc1.19-0.4.2
modmenu_version=1.14.6+build.31 spruceui_version=4.0.0+1.19
midnightlib_version=0.5.2
modmenu_version=4.0.0
emotecraft_version=2.1.3-SNAPSHOT-build.29-MC1.19-fabric
bendylib_version=2.0.+
emi_version=0.1.1+1.18.2
# Ok Zoomer and LibZoomer are temporarily disabled for the time being, as we are currently using Reflection at runtime instead in OkZoomerCompat due to there being two major, completely incompatible API versions.
# ok_zoomer_version=5.0.0-beta.3+1.17.1
# libzoomer_version=0.3.0+1.17.1

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.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

269
gradlew vendored Normal file → Executable file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh #!/bin/sh
# #
# Copyright 2015 the original author or authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
# #
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

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

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 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 = 'midnightcontrols'
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,15 +1,15 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols; package eu.midnightdust.midnightcontrols;
import org.aperlambda.lambdacommon.utils.Nameable; import dev.lambdaurora.spruceui.util.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays; import java.util.Arrays;
@@ -19,11 +19,10 @@ 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; TOUCHSCREEN;
@@ -31,11 +30,10 @@ public enum ControlsMode implements Nameable
/** /**
* 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 +42,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 "midnightcontrols.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 midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols;
import eu.midnightdust.midnightcontrols.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.Text;
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 MidnightControls mod.
*
* @author LambdAurora & Motschen
* @version 1.8.0
* @since 1.0.0
*/
public class MidnightControls implements ModInitializer {
private static MidnightControls INSTANCE;
public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(MidnightControlsConstants.CONTROLS_MODE_CHANNEL.toString());
public static final Identifier FEATURE_CHANNEL = new Identifier(MidnightControlsConstants.FEATURE_CHANNEL.toString());
public static final Identifier HELLO_CHANNEL = new Identifier(MidnightControlsConstants.HELLO_CHANNEL.toString());
public static boolean isExtrasLoaded;
public final Logger logger = LogManager.getLogger("MidnightControls");
@Override
public void onInitialize() {
INSTANCE = this;
isExtrasLoaded = FabricLoader.getInstance().isModLoaded("midnightcontrols-extra");
this.log("Initializing MidnightControls...");
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(MidnightControlsFeature.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("[MidnightControls] " + info);
}
/**
* Prints a warning to the terminal.
*
* @param warning the warning to print
*/
public void warn(String warning) {
this.logger.info("[MidnightControls] " + warning);
}
/**
* Returns a packet byte buffer made for the midnightcontrols: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 midnightcontrols:feature plugin message.
*
* @param features the features data to send
* @return the packet byte buffer
*/
public PacketByteBuf makeFeatureBuffer(MidnightControlsFeature... 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(MidnightControlsConstants.NAMESPACE)).isPresent()) {
version = container.get().getMetadata().getVersion().getFriendlyString();
}
return new PacketByteBuf(Unpooled.buffer()).writeString(version, 32).writeString(controlsMode.getName(), 32);
}
/**
* Gets the MidnightControls instance.
*
* @return the MidnightControls instance
*/
public static MidnightControls get() {
return INSTANCE;
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols;
import net.minecraft.util.Identifier;
/**
* Represents the constants used by MidnightControls.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class MidnightControlsConstants {
public static final String NAMESPACE = "midnightcontrols";
public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(NAMESPACE, "controls_mode");
public static final Identifier FEATURE_CHANNEL = new Identifier(NAMESPACE, "feature");
public static final Identifier HELLO_CHANNEL = new Identifier("lambdacontrols", "hello");
}

View File

@@ -0,0 +1,158 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols;
import dev.lambdaurora.spruceui.util.Nameable;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* Represents a feature.
*
* @author LambdAurora
* @version 1.5.0
* @since 1.1.0
*/
public class MidnightControlsFeature implements Nameable {
private static final List<MidnightControlsFeature> FEATURES = new ArrayList<>();
public static final MidnightControlsFeature FAST_BLOCK_PLACING = new MidnightControlsFeature("fast_block_placing", true, MidnightControlsConfig.fastBlockPlacing);
public static final MidnightControlsFeature HORIZONTAL_REACHAROUND = new MidnightControlsFeature("horizontal_reacharound", true, MidnightControlsConfig.horizontalReacharound);
public static final MidnightControlsFeature VERTICAL_REACHAROUND = new MidnightControlsFeature("vertical_reacharound", true, MidnightControlsConfig.verticalReacharound);
private final String key;
private final boolean defaultAllowed;
private boolean allowed;
private final boolean defaultEnabled;
private boolean enabled;
public MidnightControlsFeature(@NotNull String key, boolean allowed, boolean enabled) {
Objects.requireNonNull(key, "Feature key cannot be null.");
this.key = key;
this.setAllowed(this.defaultAllowed = allowed);
this.setEnabled(this.defaultEnabled = enabled);
}
public MidnightControlsFeature(@NotNull String key) {
this(key, false, false);
}
/**
* Allows the feature.
*/
public void allow() {
this.setAllowed(true);
}
/**
* Returns whether this feature is allowed.
*
* @return {@code true} if this feature is allowed, else {@code false}
*/
public boolean isAllowed() {
return MidnightControls.isExtrasLoaded && this.allowed;
}
/**
* Sets whether this feature is allowed.
*
* @param allowed {@code true} if this feature is allowed, else {@code false}
*/
public void setAllowed(boolean allowed) {
this.allowed = allowed;
}
/**
* Resets allowed state to default.
*/
public void resetAllowed() {
this.setAllowed(this.defaultAllowed);
}
/**
* Returns whether this feature is enabled.
*
* @return {@code true} if this feature is enabled, else {@code false}
*/
public boolean isEnabled() {
return this.enabled;
}
/**
* Returns whether this feature is enabled.
*
* @param enabled {@code true} if this feature is enabled, else {@code false}
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* Refreshes the enabled values from the config.
*/
public static void refreshEnabled() {
MidnightControlsFeature.VERTICAL_REACHAROUND.setEnabled(MidnightControlsConfig.verticalReacharound);
MidnightControlsFeature.FAST_BLOCK_PLACING.setEnabled(MidnightControlsConfig.fastBlockPlacing);
MidnightControlsFeature.HORIZONTAL_REACHAROUND.setEnabled(MidnightControlsConfig.horizontalReacharound);
}
/**
* Returns whether this feature is available or not.
*
* @return {@code true} if this feature is available, else {@code false}
* @see #isAllowed()
* @see #isEnabled()
*/
public boolean isAvailable() {
return this.isAllowed() && this.isEnabled();
}
/**
* Resets the feature to its default values.
*/
public void reset() {
this.resetAllowed();
this.setEnabled(this.defaultEnabled);
}
@Override
public @NotNull String getName() {
return this.key;
}
public static @NotNull Optional<MidnightControlsFeature> fromName(@NotNull String key) {
Objects.requireNonNull(key, "Cannot find features with a null name.");
return FEATURES.parallelStream().filter(feature -> feature.getName().equals(key)).findFirst();
}
/**
* Resets all features to their default values.
*/
public static void resetAll() {
FEATURES.parallelStream().forEach(MidnightControlsFeature::reset);
}
/**
* Resets all features to allow state.
*/
public static void resetAllAllowed() {
FEATURES.parallelStream().forEach(MidnightControlsFeature::resetAllowed);
}
static {
FEATURES.add(FAST_BLOCK_PLACING);
FEATURES.add(HORIZONTAL_REACHAROUND);
FEATURES.add(VERTICAL_REACHAROUND);
}
}

View File

@@ -1,13 +1,13 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package eu.midnightdust.midnightcontrols.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,17 +1,15 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package eu.midnightdust.midnightcontrols.client;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -25,27 +23,26 @@ 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, Text.of("Default")),
DEFAULT(0), DUALSHOCK(1, Text.of("Dualshock")),
DUALSHOCK(1), DUALSENSE(2, Text.of("Dualsense")),
SWITCH(2), SWITCH(3, Text.of("Switch")),
XBOX_360(3, new LiteralText("Xbox 360")), XBOX_360(4, Text.of("Xbox 360")),
XBOX(4), XBOX(5, Text.of("Xbox")),
STEAM(5), STEAM_DECK(6, Text.of("Steam Deck")),
OUYA(6); STEAM_CONTROLLER(7, Text.of("Steam Controller")),
OUYA(8, Text.of("Ouya"));
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 = Text.translatable("midnightcontrols.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,17 +1,15 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package eu.midnightdust.midnightcontrols.client;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -25,26 +23,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 = Text.translatable(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 +48,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 "midnightcontrols.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

@@ -0,0 +1,242 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client;
import dev.lambdaurora.spruceui.event.OpenScreenCallback;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.MidnightControls;
import eu.midnightdust.midnightcontrols.MidnightControlsConstants;
import eu.midnightdust.midnightcontrols.MidnightControlsFeature;
import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.ButtonCategory;
import eu.midnightdust.midnightcontrols.client.controller.Controller;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsHud;
import eu.midnightdust.midnightcontrols.client.gui.RingScreen;
import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay;
import eu.midnightdust.midnightcontrols.client.mixin.KeyBindingRegistryImplAccessor;
import eu.midnightdust.midnightcontrols.client.ring.KeyBindingRingAction;
import eu.midnightdust.midnightcontrols.client.ring.MidnightRing;
import dev.lambdaurora.spruceui.hud.HudManager;
import net.fabricmc.api.ClientModInitializer;
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.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.ResourcePackActivationType;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.client.util.InputUtil;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import java.io.File;
/**
* Represents the midnightcontrols client mod.
*
* @author LambdAurora
* @version 1.7.0
* @since 1.1.0
*/
public class MidnightControlsClient extends MidnightControls implements ClientModInitializer {
public static boolean lateInitDone = false;
private static MidnightControlsClient INSTANCE;
public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(new Identifier(MidnightControlsConstants.NAMESPACE, "look_up"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement");
public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(new Identifier(MidnightControlsConstants.NAMESPACE, "look_right"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement");
public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(new Identifier(MidnightControlsConstants.NAMESPACE, "look_down"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement");
public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(new Identifier(MidnightControlsConstants.NAMESPACE, "look_left"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement");
public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(new Identifier(MidnightControlsConstants.NAMESPACE, "ring"),
InputUtil.Type.KEYSYM, InputUtil.UNKNOWN_KEY.getCode(), "key.categories.misc");
public static final Identifier CONTROLLER_BUTTONS = new Identifier(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png");
public static final Identifier CONTROLLER_EXPANDED = new Identifier(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_expanded.png");
public static final Identifier CONTROLLER_AXIS = new Identifier(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_axis.png");
public static final Identifier CURSOR_TEXTURE = new Identifier(MidnightControlsConstants.NAMESPACE, "textures/gui/cursor.png");
public final static File MAPPINGS_FILE = new File("config/gamecontrollercustommappings.txt");
public final MidnightInput input = new MidnightInput();
public final MidnightRing ring = new MidnightRing(this);
public final MidnightReacharound reacharound = new MidnightReacharound();
private MidnightControlsHud hud;
private ControlsMode previousControlsMode;
@Override
public void onInitializeClient() {
INSTANCE = this;
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_UP);
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_RIGHT);
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_DOWN);
KeyBindingHelper.registerKeyBinding(BINDING_LOOK_LEFT);
//KeyBindingHelper.registerKeyBinding(BINDING_RING);
this.ring.registerAction("keybinding", KeyBindingRingAction.FACTORY);
this.ring.load();
ClientPlayNetworking.registerGlobalReceiver(CONTROLS_MODE_CHANNEL, (client, handler, buf, responseSender) ->
responseSender.sendPacket(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(MidnightControlsConfig.controlsMode)));
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();
MidnightControlsFeature.fromName(name).ifPresent(feature -> client.execute(() -> feature.setAllowed(allowed)));
}
});
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
sender.sendPacket(HELLO_CHANNEL, this.makeHello(MidnightControlsConfig.controlsMode));
sender.sendPacket(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(MidnightControlsConfig.controlsMode));
});
ClientPlayConnectionEvents.DISCONNECT.register(this::onLeave);
ClientTickEvents.START_CLIENT_TICK.register(this.reacharound::tick);
ClientTickEvents.START_CLIENT_TICK.register(this::onTick);
OpenScreenCallback.EVENT.register((client, screen) -> {
if (screen == null && MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN) {
screen = new TouchscreenOverlay(this);
screen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
client.skipGameRender = false;
client.currentScreen = screen;
} else if (screen != null) {
this.input.onScreenOpen(client, client.getWindow().getWidth(), client.getWindow().getHeight());
}
});
HudManager.register(this.hud = new MidnightControlsHud(this));
FabricLoader.getInstance().getModContainer("midnightcontrols").ifPresent(modContainer ->
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier("midnightcontrols","bedrock"), modContainer, ResourcePackActivationType.NORMAL));
}
/**
* This method is called when Minecraft is initializing.
*/
public void onMcInit(@NotNull MinecraftClient client) {
ButtonBinding.init(client.options);
MidnightControlsConfig.load();
this.hud.setVisible(MidnightControlsConfig.hudEnable);
Controller.updateMappings();
GLFW.glfwSetJoystickCallback((jid, event) -> {
if (event == GLFW.GLFW_CONNECTED) {
var controller = Controller.byId(jid);
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, Text.translatable("midnightcontrols.controller.connected", jid),
Text.literal(controller.getName())));
} else if (event == GLFW.GLFW_DISCONNECTED) {
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, Text.translatable("midnightcontrols.controller.disconnected", jid),
null));
}
this.switchControlsMode();
});
MidnightControlsCompat.init(this);
}
ButtonCategory category;
/**
* This method is called to initialize keybindings
*/
public void initKeybindings() {
if (lateInitDone) return;
if (KeyBindingRegistryImplAccessor.getModdedKeyBindings() == null || KeyBindingRegistryImplAccessor.getModdedKeyBindings().isEmpty()) return;
for (int i = 0; i < KeyBindingRegistryImplAccessor.getModdedKeyBindings().size(); ++i) {
KeyBinding keyBinding = KeyBindingRegistryImplAccessor.getModdedKeyBindings().get(i);
if (!keyBinding.getTranslationKey().contains("midnightcontrols") && !keyBinding.getTranslationKey().contains("ok_zoomer") && !keyBinding.getTranslationKey().contains("okzoomer")) {
category = null;
InputManager.streamCategories().forEach(buttonCategory -> {
if (buttonCategory.getIdentifier().equals(new org.aperlambda.lambdacommon.Identifier("minecraft", keyBinding.getCategory())))
category = buttonCategory;
});
if (category == null) {
category = new ButtonCategory(new org.aperlambda.lambdacommon.Identifier("minecraft", keyBinding.getCategory()));
InputManager.registerCategory(category);
}
ButtonBinding buttonBinding = new ButtonBinding.Builder(keyBinding.getTranslationKey()).category(category).linkKeybind(keyBinding).register();
if (MidnightControlsConfig.debug) {
logger.info(keyBinding.getTranslationKey());
logger.info(buttonBinding);
}
}
}
InputManager.loadButtonBindings();
lateInitDone = true;
}
/**
* This method is called every Minecraft tick.
*
* @param client the client instance
*/
public void onTick(@NotNull MinecraftClient client) {
this.initKeybindings();
this.input.tick(client);
if (MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && (client.isWindowFocused() || MidnightControlsConfig.unfocusedInput))
this.input.tickController(client);
// if (BINDING_RING.wasPressed()) {
// client.setScreen(new RingScreen());
// }
}
public void onRender(MinecraftClient client) {
this.input.onRender(client.getTickDelta(), client);
}
/**
* Called when leaving a server.
*/
public void onLeave(ClientPlayNetworkHandler handler, MinecraftClient client) {
MidnightControlsFeature.resetAllAllowed();
}
/**
* Switches the controls mode if the auto switch is enabled.
*/
public void switchControlsMode() {
if (MidnightControlsConfig.autoSwitchMode) {
if (MidnightControlsConfig.getController().isGamepad()) {
this.previousControlsMode = MidnightControlsConfig.controlsMode;
MidnightControlsConfig.controlsMode = ControlsMode.CONTROLLER;
} else {
if (this.previousControlsMode == null) {
this.previousControlsMode = ControlsMode.DEFAULT;
}
MidnightControlsConfig.controlsMode = this.previousControlsMode;
}
}
}
/**
* Sets whether the HUD is enabled or not.
*
* @param enabled true if the HUD is enabled, else false
*/
public void setHudEnabled(boolean enabled) {
MidnightControlsConfig.hudEnable = enabled;
this.hud.setVisible(enabled);
}
/**
* Gets the midnightcontrols client instance.
*
* @return the midnightcontrols client instance
*/
public static MidnightControlsClient get() {
return INSTANCE;
}
}

View File

@@ -0,0 +1,306 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client;
import com.google.common.collect.Lists;
import eu.midnightdust.lib.config.MidnightConfig;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.MidnightControlsFeature;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.Controller;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.util.*;
import java.util.regex.Pattern;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_X;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y;
/**
* Represents MidnightControls configuration.
*/
public class MidnightControlsConfig extends MidnightConfig {
// General
@Entry(name = "midnightcontrols.menu.controls_mode") public static ControlsMode controlsMode = ControlsMode.DEFAULT;
@Entry(name = "midnightcontrols.menu.auto_switch_mode") public static boolean autoSwitchMode = true;
@Entry(name = "Debug") public static boolean debug = false;
// HUD
@Entry(name = "midnightcontrols.menu.hud_enable") public static boolean hudEnable = true;
@Entry(name = "midnightcontrols.menu.hud_side") public static HudSide hudSide = HudSide.LEFT;
// Gameplay
@Entry(name = "midnightcontrols.menu.analog_movement") public static boolean analogMovement = true;
@Entry(name = "midnightcontrols.menu.double_tap_to_sprint") public static boolean doubleTapToSprint = true;
@Entry(name = "midnightcontrols.menu.fast_block_placing") public static boolean fastBlockPlacing = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(name = "midnightcontrols.menu.fly_drifting") public static boolean flyDrifting = true; // Enabled by default as disabling this behaviour can be considered cheating on multiplayer servers. It can also conflict with some other mods.
@Entry(name = "midnightcontrols.menu.fly_drifting_vertical") public static boolean verticalFlyDrifting = true; // Enabled by default as disabling this behaviour can be considered cheating on multiplayer servers.
@Entry(name = "midnightcontrols.menu.reacharound.horizontal") public static boolean horizontalReacharound = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(name = "midnightcontrols.menu.reacharound.vertical") public static boolean verticalReacharound = false; // Disabled by default as this behaviour can be considered cheating on multiplayer servers.
@Entry(name = "Reacharound Outline") public static boolean shouldRenderReacharoundOutline = true;
@Entry(name = "Reacharound Outline Color") public static int[] reacharoundOutlineColor = new int[]{255, 255, 255, 102};
@Entry(name = "midnightcontrols.menu.right_dead_zone") public static double rightDeadZone = 0.25;
@Entry(name = "midnightcontrols.menu.left_dead_zone") public static double leftDeadZone = 0.25;
@Entry(name = "midnightcontrols.menu.invert_right_y_axis") public static boolean invertRightYAxis = false;
@Entry(name = "midnightcontrols.menu.invert_right_x_axis") public static boolean invertRightXAxis = false;
@Entry(name = "midnightcontrols.menu.rotation_speed") public static double rotationSpeed = 40.0; //used for x axis, name kept for compatability
@Entry(name = "midnightcontrols.menu.y_axis_rotation_speed") public static double yAxisRotationSpeed = rotationSpeed;
@Entry(name = "midnightcontrols.menu.mouse_speed") public static double mouseSpeed = 25.0;
@Entry(name = "midnightcontrols.menu.unfocused_input") public static boolean unfocusedInput = false;
@Entry(name = "midnightcontrols.menu.virtual_mouse") public static boolean virtualMouse = false;
@Entry(name = "midnightcontrols.menu.virtual_mouse.skin") public static VirtualMouseSkin virtualMouseSkin = VirtualMouseSkin.DEFAULT_LIGHT;
@Entry(name = "Controller ID") public static Object controllerID = 0;
@Entry(name = "2nd Controller ID") public static Object secondControllerID = -1;
@Entry(name = "midnightcontrols.menu.controller_type") public static ControllerType controllerType = ControllerType.DEFAULT;
@Entry(name = "Mouse screens") public static List<String> mouseScreens = Lists.newArrayList("me.jellysquid.mods.sodium.client.gui", "net.coderbot.iris.gui", "net.minecraft.client.gui.screen.advancement", "net.minecraft.client.gui.screen.pack.PackScreen", "net.minecraft.class_5375", "net.minecraft.class_457", "net.minecraft.class_408", "me.flashyreese.mods.reeses_sodium_options.client.gui", "dev.emi.emi.screen");
@Entry(name = "Keybindings") public static Map<String, String> BINDINGS = new HashMap<>();
private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?");
@Entry(name = "Max analog values") public static double[] maxAnalogValues = new double[]{1, 1, 1, 1};
/**
* Loads the configuration
*/
public static void load() {
MidnightControlsConfig.init("midnightcontrols", MidnightControlsConfig.class);
MidnightControlsClient.get().log("Configuration loaded.");
// Controller controls.
InputManager.loadButtonBindings();
//this.mod.ring.load(this.config);
}
/**
* Saves the configuration.
*/
public static void save() {
MidnightControlsConfig.write("midnightcontrols");
MidnightControlsClient.get().log("Configuration saved.");
MidnightControlsFeature.refreshEnabled();
}
/**
* Gets the used controller.
*
* @return the controller
*/
public static Controller getController() {
var raw = MidnightControlsConfig.controllerID;
if (raw instanceof Number) {
return Controller.byId(((Number) raw).intValue());
} else if (raw instanceof String) {
return Controller.byGuid((String) raw).orElse(Controller.byId(GLFW.GLFW_JOYSTICK_1));
}
return Controller.byId(GLFW.GLFW_JOYSTICK_1);
}
/**
* Sets the used controller.
*
* @param controller the controller
*/
public static void setController(Controller controller) {
MidnightControlsConfig.controllerID = controller.id();
MidnightControlsConfig.write("midnightcontrols");
}
/**
* Gets the second controller (for Joy-Con supports).
*
* @return the second controller
*/
public static Optional<Controller> getSecondController() {
var raw = MidnightControlsConfig.secondControllerID;
if (raw instanceof Number) {
if (((Number) raw).intValue() == -1)
return Optional.empty();
return Optional.of(Controller.byId(((Number) raw).intValue()));
} else if (raw instanceof String) {
return Optional.of(Controller.byGuid((String) raw).orElse(Controller.byId(GLFW.GLFW_JOYSTICK_1)));
}
return Optional.empty();
}
/**
* Sets the second controller.
*
* @param controller the second controller
*/
public static void setSecondController(@Nullable Controller controller) {
MidnightControlsConfig.secondControllerID = controller == null ? -1 : controller.id();
}
/**
* Gets the right X axis sign.
*
* @return the right X axis sign
*/
public static double getRightXAxisSign() {
return MidnightControlsConfig.invertRightXAxis ? -1.0 : 1.0;
}
/**
* Gets the right Y axis sign.
*
* @return the right Y axis sign
*/
public static double getRightYAxisSign() {
return MidnightControlsConfig.invertRightYAxis ? -1.0 : 1.0;
}
public static double getAxisMaxValue(int axis) {
if (axis >= MidnightControlsConfig.maxAnalogValues.length)
return 1;
return MidnightControlsConfig.maxAnalogValues[axis];
}
public static void setAxisMaxValue(int axis, double value) {
if (axis < MidnightControlsConfig.maxAnalogValues.length)
MidnightControlsConfig.maxAnalogValues[axis] = value;
}
/**
* Loads the button binding from configuration.
*
* @param button the button binding
*/
public static void loadButtonBinding(@NotNull ButtonBinding button) {
button.setButton(button.getDefaultButton());
var code = MidnightControlsConfig.BINDINGS.getOrDefault("controller.controls." + button.getName(), button.getButtonCode());
var matcher = BUTTON_BINDING_PATTERN.matcher(code);
try {
var buttons = new int[1];
int count = 0;
while (matcher.find()) {
count++;
if (count > buttons.length)
buttons = Arrays.copyOf(buttons, count);
String current;
if (!MidnightControlsConfig.checkValidity(button, code, current = matcher.group(1)))
return;
buttons[count - 1] = Integer.parseInt(current);
}
if (count == 0) {
MidnightControlsClient.get().warn("Malformed config value \"" + code + "\" for binding \"" + button.getName() + "\".");
MidnightControlsConfig.setButtonBinding(button, new int[]{-1});
}
button.setButton(buttons);
} catch (Exception e) {
MidnightControlsClient.get().warn("Malformed config value \"" + code + "\" for binding \"" + button.getName() + "\".");
MidnightControlsConfig.BINDINGS.put("controller.controls." + button.getName(), button.getButtonCode());
}
}
private static boolean checkValidity(@NotNull ButtonBinding binding, @NotNull String input, String group) {
if (group == null) {
MidnightControlsClient.get().warn("Malformed config value \"" + input + "\" for binding \"" + binding.getName() + "\".");
MidnightControlsConfig.BINDINGS.put("controller.controls." + binding.getName(), binding.getButtonCode());
return false;
}
return true;
}
/**
* Sets the button binding in configuration.
*
* @param binding the button binding
* @param button the button
*/
public static void setButtonBinding(@NotNull ButtonBinding binding, int[] button) {
binding.setButton(button);
MidnightControlsConfig.BINDINGS.put("controller.controls." + binding.getName(), binding.getButtonCode());
}
public static boolean isBackButton(int btn, boolean isBtn, int state) {
if (!isBtn && state == 0)
return false;
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false) == ButtonBinding.axisAsButton(btn, state == 1);
}
public static boolean isForwardButton(int btn, boolean isBtn, int state) {
if (!isBtn && state == 0)
return false;
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true) == ButtonBinding.axisAsButton(btn, state == 1);
}
public static boolean isLeftButton(int btn, boolean isBtn, int state) {
if (!isBtn && state == 0)
return false;
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false) == ButtonBinding.axisAsButton(btn, state == 1);
}
public static boolean isRightButton(int btn, boolean isBtn, int state) {
if (!isBtn && state == 0)
return false;
return ButtonBinding.axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true) == ButtonBinding.axisAsButton(btn, state == 1);
}
/**
* Returns whether the specified axis is an axis used for movements.
*
* @param axis the axis index
* @return true if the axis is used for movements, else false
*/
public static boolean isMovementAxis(int axis) {
return axis == GLFW_GAMEPAD_AXIS_LEFT_Y || axis == GLFW_GAMEPAD_AXIS_LEFT_X;
}
public static void reset() {
controlsMode = ControlsMode.DEFAULT;
autoSwitchMode = true;
debug = false;
hudEnable = true;
hudSide = HudSide.LEFT;
analogMovement = true;
doubleTapToSprint = true;
fastBlockPlacing = false;
flyDrifting = true;
verticalFlyDrifting = true;
horizontalReacharound = false;
verticalReacharound = false;
shouldRenderReacharoundOutline = true;
reacharoundOutlineColor = new int[]{255, 255, 255, 102};
rightDeadZone = 0.25;
leftDeadZone = 0.25;
invertRightYAxis = false;
invertRightXAxis = false;
rotationSpeed = 40.0;
yAxisRotationSpeed = rotationSpeed;
mouseSpeed = 25.0;
unfocusedInput = false;
virtualMouse = false;
virtualMouseSkin = VirtualMouseSkin.DEFAULT_LIGHT;
controllerID = 0;
secondControllerID = -1;
controllerType = ControllerType.DEFAULT;
mouseScreens = Lists.newArrayList("me.jellysquid.mods.sodium.client.gui", "net.coderbot.iris.gui", "net.minecraft.client.gui.screen.advancement", "net.minecraft.client.gui.screen.pack.PackScreen", "net.minecraft.class_5375", "net.minecraft.class_457", "net.minecraft.class_408", "me.flashyreese.mods.reeses_sodium_options.client.gui", "dev.emi.emi.screen");
BINDINGS = new HashMap<>();
maxAnalogValues = new double[]{1, 1, 1, 1};
}
/**
* Gets the controller type from the controller's identifier.
*
* @return the controller name matches a type, else empty
*/
public static @NotNull ControllerType matchControllerToType() {
String controller = getController().getName().toLowerCase();
if (controller.contains("xbox 360")) return ControllerType.XBOX_360;
else if (controller.contains("xbox") || controller.contains("afterglow")) return ControllerType.XBOX;
else if (controller.contains("steam deck")) return ControllerType.STEAM_DECK;
else if (controller.contains("steam")) return ControllerType.STEAM_CONTROLLER;
else if (controller.contains("dualsense")) return ControllerType.DUALSENSE;
else if (controller.contains("dualshock") || controller.contains("ps4")) return ControllerType.DUALSHOCK;
else if (controller.contains("switch") || controller.contains("joy-con")) return ControllerType.SWITCH;
else if (controller.contains("ouya")) return ControllerType.OUYA;
else return ControllerType.DEFAULT;
}
}

View File

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

View File

@@ -0,0 +1,735 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client;
import com.google.common.collect.ImmutableSet;
import dev.lambdaurora.spruceui.widget.container.SpruceEntryListWidget;
import dev.lambdaurora.spruceui.widget.container.SpruceOptionListWidget;
import eu.midnightdust.midnightcontrols.MidnightControls;
import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat;
import eu.midnightdust.midnightcontrols.client.compat.SodiumCompat;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.Controller;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay;
import eu.midnightdust.midnightcontrols.client.gui.widget.ControllerControlsWidget;
import eu.midnightdust.midnightcontrols.client.mixin.AdvancementsScreenAccessor;
import eu.midnightdust.midnightcontrols.client.mixin.CreativeInventoryScreenAccessor;
import eu.midnightdust.midnightcontrols.client.mixin.EntryListWidgetAccessor;
import eu.midnightdust.midnightcontrols.client.util.HandledScreenAccessor;
import eu.midnightdust.midnightcontrols.client.util.MouseAccessor;
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.fabricmc.fabric.impl.item.group.CreativeGuiExtensions;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.ParentElement;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.gui.screen.advancement.AdvancementTab;
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.ingame.MerchantScreen;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
import net.minecraft.client.gui.screen.world.WorldListWidget;
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
import net.minecraft.client.gui.widget.EntryListWidget;
import net.minecraft.client.gui.widget.PressableWidget;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWGamepadState;
import java.util.*;
import static org.lwjgl.glfw.GLFW.*;
/**
* Represents the midnightcontrols' input handler.
*
* @author LambdAurora
* @version 1.7.0
* @since 1.0.0
*/
public class MidnightInput {
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
// Cooldowns
public int actionGuiCooldown = 0;
public boolean ignoreNextARelease = false;
private double targetYaw = 0.0;
private double targetPitch = 0.0;
private float prevXAxis = 0.f;
private float prevYAxis = 0.f;
private int targetMouseX = 0;
private int targetMouseY = 0;
private float mouseSpeedX = 0.f;
private float mouseSpeedY = 0.f;
public int inventoryInteractionCooldown = 0;
private ControllerControlsWidget controlsInput = null;
public MidnightInput() {}
/**
* This method is called every Minecraft tick.
*
* @param client the client instance
*/
public void tick(@NotNull MinecraftClient client) {
this.targetYaw = 0.F;
this.targetPitch = 0.F;
// Handles the key bindings.
if (MidnightControlsClient.BINDING_LOOK_UP.isPressed()) {
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_Y, 0.8F, 2);
} else if (MidnightControlsClient.BINDING_LOOK_DOWN.isPressed()) {
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_Y, 0.8F, 1);
}
if (MidnightControlsClient.BINDING_LOOK_LEFT.isPressed()) {
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_X, 0.8F, 2);
} else if (MidnightControlsClient.BINDING_LOOK_RIGHT.isPressed()) {
this.handleLook(client, GLFW_GAMEPAD_AXIS_RIGHT_X, 0.8F, 1);
}
InputManager.INPUT_MANAGER.tick(client);
}
/**
* This method is called every Minecraft tick for controller input update.
*
* @param client the client instance
*/
public void tickController(@NotNull MinecraftClient client) {
BUTTON_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0)
.forEach(entry -> BUTTON_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
// Decreases the cooldown for GUI actions.
if (this.actionGuiCooldown > 0)
--this.actionGuiCooldown;
InputManager.updateStates();
var controller = MidnightControlsConfig.getController();
if (controller.isConnected()) {
var state = controller.getState();
this.fetchButtonInput(client, state, false);
this.fetchAxeInput(client, state, false);
}
MidnightControlsConfig.getSecondController().filter(Controller::isConnected)
.ifPresent(joycon -> {
GLFWGamepadState state = joycon.getState();
this.fetchButtonInput(client, state, true);
this.fetchAxeInput(client, state, true);
});
boolean allowInput = true;
if (this.controlsInput != null && this.controlsInput.focusedBinding != null)
allowInput = false;
if (allowInput)
InputManager.updateBindings(client);
if (this.controlsInput != null
&& InputManager.STATES.int2ObjectEntrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) {
if (this.controlsInput.focusedBinding != null && !this.controlsInput.waiting) {
int[] buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = this.controlsInput.currentButtons.get(i);
this.controlsInput.finishBindingEdit(buttons);
this.controlsInput = null;
}
}
if (this.inventoryInteractionCooldown > 0)
this.inventoryInteractionCooldown--;
}
/**
* This method is called before the screen is rendered.
*
* @param client the client instance
* @param screen the screen to render
*/
public void onPreRenderScreen(@NotNull MinecraftClient client, @NotNull Screen screen) {
if (!isScreenInteractive(screen)) {
InputManager.INPUT_MANAGER.updateMousePosition(client);
}
}
/**
* This method is called when Minecraft renders.
*
* @param client the client instance
*/
public void onRender(float tickDelta, @NotNull MinecraftClient client) {
if (!(client.currentScreen == null || client.currentScreen instanceof TouchscreenOverlay))
return;
var player = client.player;
if (player == null)
return;
if (this.targetYaw != 0.f || this.targetPitch != 0.f) {
float rotationYaw = (float) (player.prevYaw + (this.targetYaw / 0.10) * tickDelta);
float rotationPitch = (float) (player.prevPitch + (this.targetPitch / 0.10) * tickDelta);
client.player.setYaw(rotationYaw);
client.player.setPitch(MathHelper.clamp(rotationPitch, -90.f, 90.f));
if (client.player.isRiding()) {
client.player.getVehicle().onPassengerLookAround(client.player);
}
client.getTutorialManager().onUpdateMouse(this.targetPitch, this.targetYaw);
}
}
/**
* This method is called when a Screen is opened.
*
* @param client the client instance
* @param windowWidth the window width
* @param windowHeight the window height
*/
public void onScreenOpen(@NotNull MinecraftClient client, int windowWidth, int windowHeight) {
if (client.currentScreen == null) {
this.mouseSpeedX = this.mouseSpeedY = 0.0F;
InputManager.INPUT_MANAGER.resetMousePosition(windowWidth, windowHeight);
} else if (isScreenInteractive(client.currentScreen) && MidnightControlsConfig.virtualMouse) {
((MouseAccessor) client.mouse).midnightcontrols$onCursorPos(client.getWindow().getHandle(), 0, 0);
InputManager.INPUT_MANAGER.resetMouseTarget(client);
}
this.inventoryInteractionCooldown = 5;
}
public void beginControlsInput(ControllerControlsWidget widget) {
this.controlsInput = widget;
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++) {
int btn = leftJoycon ? ButtonBinding.controller2Button(i) : i;
boolean btnState = buffer.get() == (byte) 1;
var state = ButtonState.NONE;
var previousState = InputManager.STATES.getOrDefault(btn, ButtonState.NONE);
if (btnState != previousState.isPressed()) {
state = btnState ? ButtonState.PRESS : ButtonState.RELEASE;
this.handleButton(client, btn, btnState ? 0 : 1, btnState);
if (btnState)
BUTTON_COOLDOWNS.put(btn, 5);
} else if (btnState) {
state = ButtonState.REPEAT;
if (BUTTON_COOLDOWNS.getOrDefault(btn, 0) == 0) {
BUTTON_COOLDOWNS.put(btn, 5);
this.handleButton(client, btn, 2, true);
}
}
InputManager.STATES.put(btn, state);
}
}
private void fetchAxeInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon) {
var buffer = gamepadState.axes();
for (int i = 0; i < buffer.limit(); i++) {
int axis = leftJoycon ? ButtonBinding.controller2Button(i) : i;
float value = buffer.get();
float absValue = Math.abs(value);
if (i == GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y)
value *= -1.0F;
int state = value > MidnightControlsConfig.rightDeadZone ? 1 : (value < -MidnightControlsConfig.rightDeadZone ? 2 : 0);
this.handleAxe(client, axis, value, absValue, state);
}
}
public void handleButton(@NotNull MinecraftClient client, int button, int action, boolean state) {
if (this.controlsInput != null && this.controlsInput.focusedBinding != null) {
if (action == 0 && !this.controlsInput.currentButtons.contains(button)) {
this.controlsInput.currentButtons.add(button);
var buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = this.controlsInput.currentButtons.get(i);
this.controlsInput.focusedBinding.setButton(buttons);
this.controlsInput.waiting = false;
}
return;
}
if (action == 0 || action == 2) {
if (client.currentScreen != null
&& (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN
|| button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)) {
if (this.actionGuiCooldown == 0) {
if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP) {
this.changeFocus(client.currentScreen, NavigationDirection.UP);
} else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN) {
this.changeFocus(client.currentScreen, NavigationDirection.DOWN);
} else this.handleLeftRight(client.currentScreen, button != GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT);
}
return;
}
}
if (action == 1) {
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null) {
if (this.actionGuiCooldown == 0) {
var focused = client.currentScreen.getFocused();
if (focused != null && isScreenInteractive(client.currentScreen)) {
if (this.handleAButton(client.currentScreen, focused)) {
this.actionGuiCooldown = 5; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
return;
}
}
}
}
if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
if (client.currentScreen != null && client.currentScreen.getClass() != TitleScreen.class) {
if (!MidnightControlsCompat.handleMenuBack(client, client.currentScreen))
if (!this.tryGoBack(client.currentScreen))
client.currentScreen.close();
return;
}
}
}
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !isScreenInteractive(client.currentScreen)
&& this.actionGuiCooldown == 0) {
if (client.currentScreen instanceof CreativeInventoryScreen creativeScreen && ((HandledScreenAccessor) creativeScreen).midnightcontrols$getSlotAt(
client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth(),
client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()) != null) return;
if (!this.ignoreNextARelease) {
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
if (action == 0) {
Screen.wrapScreenError(() -> client.currentScreen.mouseClicked(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1),
"mouseClicked event handler", client.currentScreen.getClass().getCanonicalName());
} else if (action == 1) {
Screen.wrapScreenError(() -> client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1),
"mouseReleased event handler", client.currentScreen.getClass().getCanonicalName());
}
this.actionGuiCooldown = 5;
} else {
this.ignoreNextARelease = false;
}
}
}
/**
/**
* Tries to go back.
*
* @param screen the current screen
* @return true if successful, else false
*/
public boolean tryGoBack(@NotNull Screen screen) {
var set = ImmutableSet.of("gui.back", "gui.done", "gui.cancel", "gui.toTitle", "gui.toMenu");
return screen.children().stream().filter(element -> element instanceof PressableWidget)
.map(element -> (PressableWidget) element)
.filter(element -> element.getMessage() != null && element.getMessage().getContent() != null)
.anyMatch(element -> {
if (set.stream().anyMatch(key -> element.getMessage().getContent().toString().equals(key))) {
element.onPress();
return true;
}
return false;
});
}
private double getDeadZoneValue(int axis) {
return (axis == GLFW_GAMEPAD_AXIS_LEFT_X || axis == GLFW_GAMEPAD_AXIS_LEFT_Y) ? MidnightControlsConfig.leftDeadZone
: MidnightControlsConfig.rightDeadZone;
}
private void handleAxe(@NotNull MinecraftClient client, int axis, float value, float absValue, int state) {
int asButtonState = value > .5f ? 1 : (value < -.5f ? 2 : 0);
if (axis == GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axis == GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER
|| axis == ButtonBinding.controller2Button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER)
|| axis == ButtonBinding.controller2Button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER))
if (asButtonState == 2)
asButtonState = 0;
{
boolean currentPlusState = asButtonState == 1;
boolean currentMinusState = asButtonState == 2;
var previousPlusState = InputManager.STATES.getOrDefault(ButtonBinding.axisAsButton(axis, true), ButtonState.NONE);
var previousMinusState = InputManager.STATES.getOrDefault(ButtonBinding.axisAsButton(axis, false), ButtonState.NONE);
if (currentPlusState != previousPlusState.isPressed()) {
InputManager.STATES.put(ButtonBinding.axisAsButton(axis, true), currentPlusState ? ButtonState.PRESS : ButtonState.RELEASE);
if (currentPlusState)
BUTTON_COOLDOWNS.put(ButtonBinding.axisAsButton(axis, true), 5);
} else if (currentPlusState) {
InputManager.STATES.put(ButtonBinding.axisAsButton(axis, true), ButtonState.REPEAT);
if (BUTTON_COOLDOWNS.getOrDefault(ButtonBinding.axisAsButton(axis, true), 0) == 0) {
BUTTON_COOLDOWNS.put(ButtonBinding.axisAsButton(axis, true), 5);
}
}
if (currentMinusState != previousMinusState.isPressed()) {
InputManager.STATES.put(ButtonBinding.axisAsButton(axis, false), currentMinusState ? ButtonState.PRESS : ButtonState.RELEASE);
if (currentMinusState)
BUTTON_COOLDOWNS.put(ButtonBinding.axisAsButton(axis, false), 5);
} else if (currentMinusState) {
InputManager.STATES.put(ButtonBinding.axisAsButton(axis, false), ButtonState.REPEAT);
if (BUTTON_COOLDOWNS.getOrDefault(ButtonBinding.axisAsButton(axis, false), 0) == 0) {
BUTTON_COOLDOWNS.put(ButtonBinding.axisAsButton(axis, false), 5);
}
}
double deadZone = this.getDeadZoneValue(axis);
float axisValue = absValue < deadZone ? 0.f : (float) (absValue - deadZone);
axisValue /= (1.0 - deadZone);
axisValue = (float) Math.min(axisValue / MidnightControlsConfig.getAxisMaxValue(axis), 1);
if (currentPlusState)
InputManager.BUTTON_VALUES.put(ButtonBinding.axisAsButton(axis, true), axisValue);
else
InputManager.BUTTON_VALUES.put(ButtonBinding.axisAsButton(axis, true), 0.f);
if (currentMinusState)
InputManager.BUTTON_VALUES.put(ButtonBinding.axisAsButton(axis, false), axisValue);
else
InputManager.BUTTON_VALUES.put(ButtonBinding.axisAsButton(axis, false), 0.f);
}
double deadZone = this.getDeadZoneValue(axis);
if (this.controlsInput != null && this.controlsInput.focusedBinding != null) {
if (asButtonState != 0 && !this.controlsInput.currentButtons.contains(ButtonBinding.axisAsButton(axis, asButtonState == 1))) {
this.controlsInput.currentButtons.add(ButtonBinding.axisAsButton(axis, asButtonState == 1));
int[] buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = this.controlsInput.currentButtons.get(i);
this.controlsInput.focusedBinding.setButton(buttons);
this.controlsInput.waiting = false;
}
return;
} else if (client.currentScreen instanceof CreativeInventoryScreen creativeInventoryScreen) {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
var accessor = (CreativeInventoryScreenAccessor) creativeInventoryScreen;
// @TODO allow rebinding to left stick
if (accessor.midnightcontrols$hasScrollbar() && absValue >= deadZone) {
creativeInventoryScreen.mouseScrolled(0.0, 0.0, -value);
}
return;
}
} else if (client.currentScreen instanceof MerchantScreen merchantScreen) {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
// @TODO allow rebinding to left stick
if (absValue >= deadZone) {
merchantScreen.mouseScrolled(0.0, 0.0, -(value * 1.5f));
}
return;
}
} else if (client.currentScreen instanceof AdvancementsScreen advancementsScreen) {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X || axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
var accessor = (AdvancementsScreenAccessor) advancementsScreen;
if (absValue >= deadZone) {
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);
}
return;
}
} else if (client.currentScreen != null) {
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y && absValue >= deadZone) {
client.currentScreen.children().stream().filter(element -> element instanceof EntryListWidget)
.map(element -> (EntryListWidget<?>) element)
.filter(element -> element.getType().isFocused())
.anyMatch(element -> {
element.mouseScrolled(0.0, 0.0, -value);
return true;
});
client.currentScreen.children().stream().filter(element -> element instanceof SpruceEntryListWidget)
.map(element -> (SpruceEntryListWidget<?>) element)
.filter(element -> element.getType().isFocused())
.anyMatch(element -> {
MidnightControls.get().log(String.valueOf(value));
element.mouseScrolled(0.0, 0.0, -value);
return true;
});
return;
}
}
absValue -= deadZone;
absValue /= (1.0 - deadZone);
absValue = (float) MathHelper.clamp(absValue / MidnightControlsConfig.getAxisMaxValue(axis), 0.f, 1.f);
if (client.currentScreen == null) {
// Handles the look direction.
this.handleLook(client, axis, absValue, state);
} else {
boolean allowMouseControl = true;
if (this.actionGuiCooldown == 0 && MidnightControlsConfig.isMovementAxis(axis) && isScreenInteractive(client.currentScreen)) {
if (MidnightControlsConfig.isForwardButton(axis, false, asButtonState)) {
allowMouseControl = this.changeFocus(client.currentScreen, NavigationDirection.UP);
} else if (MidnightControlsConfig.isBackButton(axis, false, asButtonState)) {
allowMouseControl = this.changeFocus(client.currentScreen, NavigationDirection.DOWN);
} else if (MidnightControlsConfig.isLeftButton(axis, false, asButtonState)) {
allowMouseControl = this.handleLeftRight(client.currentScreen, false);
} else if (MidnightControlsConfig.isRightButton(axis, false, asButtonState)) {
allowMouseControl = this.handleLeftRight(client.currentScreen, true);
}
}
float movementX = 0.f;
float movementY = 0.f;
if (MidnightControlsConfig.isBackButton(axis, false, (value > 0 ? 1 : 2))) {
movementY = absValue;
} else if (MidnightControlsConfig.isForwardButton(axis, false, (value > 0 ? 1 : 2))) {
movementY = -absValue;
} else if (MidnightControlsConfig.isLeftButton(axis, false, (value > 0 ? 1 : 2))) {
movementX = -absValue;
} else if (MidnightControlsConfig.isRightButton(axis, false, (value > 0 ? 1 : 2))) {
movementX = absValue;
}
if (client.currentScreen != null && allowMouseControl) {
boolean moving = movementY != 0 || movementX != 0;
if (moving) {
/*
Updates the target mouse position when the initial movement stick movement is detected.
It prevents the cursor to jump to the old target mouse position if the user moves the cursor with the mouse.
*/
if (Math.abs(prevXAxis) < deadZone && Math.abs(prevYAxis) < deadZone) {
InputManager.INPUT_MANAGER.resetMouseTarget(client);
}
this.mouseSpeedX = movementX;
this.mouseSpeedY = movementY;
} else {
this.mouseSpeedX = 0.f;
this.mouseSpeedY = 0.f;
}
if (Math.abs(this.mouseSpeedX) >= .05f || Math.abs(this.mouseSpeedY) >= .05f) {
InputManager.queueMoveMousePosition(
this.mouseSpeedX * MidnightControlsConfig.mouseSpeed,
this.mouseSpeedY * MidnightControlsConfig.mouseSpeed
);
}
this.moveMouseToClosestSlot(client, client.currentScreen);
}
this.prevXAxis = movementX;
this.prevYAxis = movementY;
}
}
public boolean handleAButton(@NotNull Screen screen, @NotNull Element focused) {
if (focused instanceof PressableWidget widget) {
widget.playDownSound(MinecraftClient.getInstance().getSoundManager());
widget.onPress();
return true;
} else if (focused instanceof AbstractSprucePressableButtonWidget widget) {
widget.playDownSound();
widget.onPress();
return true;
} else if (focused instanceof SpruceLabelWidget labelWidget) {
labelWidget.onPress();
return true;
} else if (focused instanceof WorldListWidget list) {
list.getSelectedAsOptional().ifPresent(WorldListWidget.WorldEntry::play);
return true;
} else if (focused instanceof MultiplayerServerListWidget list) {
var entry = list.getSelectedOrNull();
if (entry instanceof MultiplayerServerListWidget.LanServerEntry || entry instanceof MultiplayerServerListWidget.ServerEntry) {
((MultiplayerScreen) screen).select(entry);
((MultiplayerScreen) screen).connect();
}
} else if (focused instanceof SpruceParentWidget) {
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)
return this.handleAButton(screen, childFocused);
}
return false;
}
/**
* Handles the left and right buttons.
*
* @param screen the current screen
* @param right true if the right button is pressed, else false
*/
private boolean handleLeftRight(@NotNull Screen screen, boolean right) {
if (screen instanceof SpruceScreen spruceScreen) {
spruceScreen.onNavigation(right ? NavigationDirection.RIGHT : NavigationDirection.LEFT, false);
this.actionGuiCooldown = 5;
return false;
}
var focused = screen.getFocused();
if (focused != null)
if (this.handleRightLeftElement(focused, right))
return this.changeFocus(screen, right ? NavigationDirection.RIGHT : NavigationDirection.LEFT);
return true;
}
private boolean handleRightLeftElement(@NotNull Element element, boolean right) {
if (element instanceof SpruceElement spruceElement) {
if (spruceElement.requiresCursor())
return true;
return !spruceElement.onNavigation(right ? NavigationDirection.RIGHT : NavigationDirection.LEFT, false);
}
if (element instanceof SliderWidget slider) {
slider.keyPressed(right ? 262 : 263, 0, 0);
this.actionGuiCooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
return false;
} else if (element instanceof AlwaysSelectedEntryListWidget) {
((EntryListWidgetAccessor) element).midnightcontrols$moveSelection(right ? EntryListWidget.MoveDirection.UP : EntryListWidget.MoveDirection.DOWN);
return false;
} else if (element instanceof ParentElement entryList) {
var focused = entryList.getFocused();
if (focused == null)
return true;
return this.handleRightLeftElement(focused, right);
}
return true;
}
/**
* Handles the look direction input.
*
* @param client the client instance
* @param axis the axis to change
* @param value the value of the look
* @param state the state
*/
public void handleLook(@NotNull MinecraftClient client, int axis, float value, int state) {
// Handles the look direction.
if (client.player != null) {
double powValue = Math.pow(value, 2.0);
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
if (state == 2) {
this.targetPitch = -MidnightControlsConfig.getRightYAxisSign() * (MidnightControlsConfig.yAxisRotationSpeed * powValue) * 0.11D;
} else if (state == 1) {
this.targetPitch = MidnightControlsConfig.getRightYAxisSign() * (MidnightControlsConfig.yAxisRotationSpeed * powValue) * 0.11D;
}
}
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) {
if (state == 2) {
this.targetYaw = -MidnightControlsConfig.getRightXAxisSign() * (MidnightControlsConfig.rotationSpeed * powValue) * 0.11D;
} else if (state == 1) {
this.targetYaw = MidnightControlsConfig.getRightXAxisSign() * (MidnightControlsConfig.rotationSpeed * powValue) * 0.11D;
}
}
}
}
private boolean changeFocus(@NotNull Screen screen, NavigationDirection direction) {
if (screen instanceof SpruceScreen spruceScreen) {
if (spruceScreen.onNavigation(direction, false)) {
this.actionGuiCooldown = 5;
}
return false;
}
if (FabricLoader.getInstance().isModLoaded("sodium")) SodiumCompat.handleInput(screen, direction.isLookingForward());
if (!screen.changeFocus(direction.isLookingForward())) {
if (screen.changeFocus(direction.isLookingForward())) {
this.actionGuiCooldown = 5;
return false;
}
return true;
} else {
this.actionGuiCooldown = 5;
return false;
}
}
public static boolean isScreenInteractive(@NotNull Screen screen) {
return !(screen instanceof HandledScreen || MidnightControlsConfig.mouseScreens.stream().anyMatch(a -> screen.getClass().toString().contains(a))
|| (screen instanceof SpruceScreen && ((SpruceScreen) screen).requiresCursor())
|| MidnightControlsCompat.requireMouseOnScreen(screen));
}
// Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686.
private void moveMouseToClosestSlot(@NotNull MinecraftClient client, @Nullable Screen screen) {
// Makes the mouse attracted to slots. This helps with selecting items when using a controller.
if (screen instanceof HandledScreen inventoryScreen) {
var accessor = (HandledScreenAccessor) inventoryScreen;
int guiLeft = accessor.getX();
int guiTop = accessor.getY();
int mouseX = (int) (targetMouseX * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
int mouseY = (int) (targetMouseY * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight());
// Finds the closest slot in the GUI within 14 pixels.
Optional<Pair<Slot, Double>> closestSlot = inventoryScreen.getScreenHandler().slots.parallelStream()
.map(slot -> {
int x = guiLeft + slot.x + 8;
int y = guiTop + slot.y + 8;
// Distance between the slot and the cursor.
double distance = Math.sqrt(Math.pow(x - mouseX, 2) + Math.pow(y - mouseY, 2));
return Pair.of(slot, distance);
}).filter(entry -> entry.value <= 14.0)
.min(Comparator.comparingDouble(p -> p.value));
if (closestSlot.isPresent()) {
var slot = closestSlot.get().key;
if (slot.hasStack() || !client.player.getInventory().getMainHandStack().isEmpty()) {
int slotCenterXScaled = guiLeft + slot.x + 8;
int slotCenterYScaled = guiTop + slot.y + 8;
int slotCenterX = (int) (slotCenterXScaled / ((double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()));
int slotCenterY = (int) (slotCenterYScaled / ((double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()));
double deltaX = slotCenterX - targetMouseX;
double deltaY = slotCenterY - targetMouseY;
if (mouseX != slotCenterXScaled || mouseY != slotCenterYScaled) {
this.targetMouseX += deltaX * 0.75;
this.targetMouseY += deltaY * 0.75;
} else {
this.mouseSpeedX *= 0.3F;
this.mouseSpeedY *= 0.3F;
}
this.mouseSpeedX *= .75F;
this.mouseSpeedY *= .75F;
} else {
this.mouseSpeedX *= .1F;
this.mouseSpeedY *= .1F;
}
} else {
this.mouseSpeedX *= .3F;
this.mouseSpeedY *= .3F;
}
} else {
this.mouseSpeedX = 0.F;
this.mouseSpeedY = 0.F;
}
}
}

View File

@@ -1,15 +1,15 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package eu.midnightdust.midnightcontrols.client;
import me.lambdaurora.lambdacontrols.LambdaControlsFeature; import eu.midnightdust.midnightcontrols.MidnightControlsFeature;
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;
@@ -28,19 +28,17 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
/** /**
* Represents the reach-around API of LambdaControls. * Represents the reach-around API of midnightcontrols.
* *
* @version 1.5.0 * @version 1.7.0
* @since 1.3.2 * @since 1.3.2
*/ */
public class LambdaReacharound public class MidnightReacharound {
{ 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 MidnightControlsFeature.HORIZONTAL_REACHAROUND.isAvailable() || MidnightControlsFeature.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 (!MidnightControlsFeature.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,52 +112,50 @@ 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 (!MidnightControlsFeature.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;
} }
return new BlockHitResult(client.crosshairTarget.getPos(), direction, blockPos, false); return new BlockHitResult(new Vec3d(blockPos.getX(),blockPos.getY(),blockPos.getZ()), direction, blockPos, false);
} }
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,16 +1,15 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client; package eu.midnightdust.midnightcontrols.client;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.aperlambda.lambdacommon.utils.Nameable; import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -20,33 +19,30 @@ 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 = Text.translatable(this.getTranslationKey());
} }
/** /**
* 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 +51,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 "midnightcontrols.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

@@ -0,0 +1,106 @@
/*
* Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of midnightcontrols.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client.compat;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.screen.slot.Slot;
import net.minecraft.util.hit.BlockHitResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a compatibility handler for a mod.
*
* @author LambdAurora
* @version 1.7.0
* @since 1.1.0
*/
public interface CompatHandler {
/**
* Handles compatibility of a mod.
*
* @param mod this mod instance
*/
void handle(@NotNull MidnightControlsClient mod);
/**
* Returns whether the mouse is required on the specified screen.
*
* @param screen the screen
* @return true if the mouse is required on the specified screen, else false
*/
default boolean requireMouseOnScreen(Screen screen) {
return false;
}
/**
* Returns a slot at the specified location if possible.
*
* @param screen the screen
* @param mouseX the mouse X-coordinate
* @param mouseY the mouse Y-coordinate
* @return a slot if present, else null
* @since 1.5.0
*/
default @Nullable CompatHandler.SlotPos getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) {
return null;
}
/**
* Returns whether the current slot is a creative slot or not.
*
* @param screen the screen
* @param slot the slot to check
* @return true if the slot is a creative slot, else false
*/
default boolean isCreativeSlot(@NotNull HandledScreen screen, @NotNull Slot slot) {
return false;
}
/**
* Returns a custom translation key to make custom attack action strings on the HUD.
*
* @param client the client instance
* @param placeResult the last place block result
* @return null if untouched, else a translation key
*/
default String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) {
return null;
}
/**
* Returns a custom translation key to make custom use action strings on the HUD.
*
* @param client the client instance
* @param placeResult the last place block result
* @return null if untouched, else a translation key
*/
default String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) {
return null;
}
/**
* Handles the menu back button.
*
* @param client the client instance
* @param screen the screen
* @return true if the handle was fired and succeed, else false
*/
default boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) {
return false;
}
record SlotPos(int x, int y) {
public static final SlotPos INVALID_SLOT = new SlotPos(-1, -1);
}
}

View File

@@ -1,15 +1,15 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat; package eu.midnightdust.midnightcontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
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 MidnightControlsClient 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,23 +1,21 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat; package eu.midnightdust.midnightcontrols.client.compat;
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import me.lambdaurora.lambdacontrols.client.controller.InputManager; import eu.midnightdust.midnightcontrols.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,76 +30,72 @@ 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 MidnightControlsCompat {
{ public 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 MidnightControlsClient mod) {
{ // "okzoomer" is the mod ID used by Fabric-compatible versions of Ok Zoomer. (5.0.0-beta.6 and below.)
if (FabricLoader.getInstance().isModLoaded("okzoomer")) { // "ok_zoomer" is the mod ID used by Quilt-exclusive versions of Ok Zoomer. (5.0.0-beta.7 and above.)
mod.log("Adding okzoomer compatibility..."); if (FabricLoader.getInstance().isModLoaded("okzoomer") || FabricLoader.getInstance().isModLoaded("ok_zoomer")) {
mod.log("Adding Ok Zoomer 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());
} }
HANDLERS.forEach(handler -> handler.handle(mod)); HANDLERS.forEach(handler -> handler.handle(mod));
InputManager.loadButtonBindings(mod.config); InputManager.loadButtonBindings();
} }
/** /**
* 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 +105,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 +122,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 +139,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 +154,17 @@ 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");
} }
/**
* Returns whether EMI is present.
*
* @return true if EMI is present, else false
*/
public static boolean isEMIPresent() {
return FabricLoader.getInstance().isModLoaded("emi");
}
} }

View File

@@ -1,14 +1,15 @@
/* /*
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com> * Copyright © 2021 LambdAurora <aurora42lambda@gmail.com>
* *
* This file is part of LambdaControls. * This file is part of midnightcontrols.
* *
* Licensed under the MIT license. For more information, * Licensed under the MIT license. For more information,
* see the LICENSE file. * see the LICENSE file.
*/ */
package me.lambdaurora.lambdacontrols.client.compat; package eu.midnightdust.midnightcontrols.client.compat;
import net.fabricmc.loader.api.FabricLoader;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
@@ -25,58 +26,45 @@ 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 MidnightControlsMixinPlugin implements IMixinConfigPlugin {
{
private final HashMap<String, Boolean> conditionalMixins = new HashMap<>(); private final HashMap<String, Boolean> conditionalMixins = new HashMap<>();
public LambdaControlsMixinPlugin() public MidnightControlsMixinPlugin() {
{ this.putConditionalMixin("SodiumOptionsGUIAccessor", FabricLoader.getInstance().isModLoaded("sodium"));
this.putConditionalMixin("EntryListWidgetAccessor", LambdaControlsCompat.isReiPresent());
this.putConditionalMixin("EntryWidgetAccessor", LambdaControlsCompat.isReiPresent());
this.putConditionalMixin("RecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent());
this.putConditionalMixin("VillagerRecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent());
} }
private void putConditionalMixin(@NotNull String path, boolean condition) private void putConditionalMixin(@NotNull String path, boolean condition) {
{ this.conditionalMixins.put("eu.midnightdust.midnightcontrols.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,195 @@
/*
* Copyright © 2021-2022 Karen/あけみ <karen@akemi.ai>, LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of MidnightControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package eu.midnightdust.midnightcontrols.client.compat;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import net.minecraft.client.option.KeyBinding;
import org.jetbrains.annotations.NotNull;
import org.aperlambda.lambdacommon.utils.LambdaReflection;
import org.lwjgl.glfw.GLFW;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Represents a compatibility handler for Ok Zoomer.
*
* @author Karen/あけみ, LambdAurora
* @version 1.4.3
* @since 1.1.0
*/
public class OkZoomerCompat implements CompatHandler {
private boolean didAllReflectionCallsSucceed = false;
private KeyBinding okZoomerZoomKey;
private KeyBinding okZoomerIncreaseZoomKey;
private KeyBinding okZoomerDecreaseZoomKey;
private KeyBinding okZoomerResetZoomKey;
private Method okZoomerAreExtraKeyBindsEnabledMethod;
public OkZoomerCompat() {
// These strings represent the names of the classes, fields, and methods we use from the Ok Zoomer API
String okZoomerZoomKeybindsClassString;
String okZoomerZoomKeyFieldString;
String okZoomerIncreaseZoomKeyFieldString;
String okZoomerDecreaseZoomKeyFieldString;
String okZoomerResetZoomKeyFieldString;
String okZoomerAreExtraKeyBindsEnabledMethodNameString;
// These variables represent the actual objects that we reflect to
Class<?> okZoomerZoomKeybindsClass;
Field okZoomerZoomKeyField;
Field okZoomerIncreaseZoomKeyField;
Field okZoomerDecreaseZoomKeyField;
Field okZoomerResetZoomKeyField;
// First, we need to determine which version of the Ok Zoomer API we're dealing with here.
if (LambdaReflection.doesClassExist("io.github.ennuil.okzoomer.keybinds.ZoomKeybinds")) {
// https://github.com/EnnuiL/OkZoomer/blob/5.0.0-beta.3+1.17.1/src/main/java/io/github/ennuil/okzoomer/keybinds/ZoomKeybinds.java
MidnightControlsClient.get().log("Ok Zoomer version 5.0.0-beta.3 or below detected!");
okZoomerZoomKeybindsClassString = "io.github.ennuil.okzoomer.keybinds.ZoomKeybinds";
okZoomerZoomKeyFieldString = "zoomKey";
okZoomerIncreaseZoomKeyFieldString = "increaseZoomKey";
okZoomerDecreaseZoomKeyFieldString = "decreaseZoomKey";
okZoomerResetZoomKeyFieldString = "resetZoomKey";
okZoomerAreExtraKeyBindsEnabledMethodNameString = "areExtraKeybindsEnabled";
} else if (LambdaReflection.doesClassExist("io.github.ennuil.okzoomer.key_binds.ZoomKeyBinds")) {
// https://github.com/EnnuiL/OkZoomer/blob/5.0.0-beta.6+1.18.2/src/main/java/io/github/ennuil/okzoomer/key_binds/ZoomKeyBinds.java
MidnightControlsClient.get().log("Ok Zoomer version 5.0.0-beta.6, 5.0.0-beta.5, or 5.0.0-beta.4 detected!");
okZoomerZoomKeybindsClassString = "io.github.ennuil.okzoomer.key_binds.ZoomKeyBinds";
okZoomerZoomKeyFieldString = "ZOOM_KEY";
okZoomerIncreaseZoomKeyFieldString = "INCREASE_ZOOM_KEY";
okZoomerDecreaseZoomKeyFieldString = "DECREASE_ZOOM_KEY";
okZoomerResetZoomKeyFieldString = "RESET_ZOOM_KEY";
okZoomerAreExtraKeyBindsEnabledMethodNameString = "areExtraKeyBindsEnabled";
} else if (LambdaReflection.doesClassExist("io.github.ennuil.ok_zoomer.key_binds.ZoomKeyBinds")) {
// https://github.com/EnnuiL/OkZoomer/blob/5.0.0-beta.7+1.18.2/src/main/java/io/github/ennuil/ok_zoomer/key_binds/ZoomKeyBinds.java
MidnightControlsClient.get().log("Ok Zoomer version 5.0.0-beta.7 (Quilt) or above detected!");
okZoomerZoomKeybindsClassString = "io.github.ennuil.ok_zoomer.key_binds.ZoomKeyBinds";
okZoomerZoomKeyFieldString = "ZOOM_KEY";
okZoomerIncreaseZoomKeyFieldString = "INCREASE_ZOOM_KEY";
okZoomerDecreaseZoomKeyFieldString = "DECREASE_ZOOM_KEY";
okZoomerResetZoomKeyFieldString = "RESET_ZOOM_KEY";
okZoomerAreExtraKeyBindsEnabledMethodNameString = "areExtraKeyBindsEnabled";
} else {
// If all of the above checks fail, then the version of the Ok Zoomer API that the user is trying to use is too new.
MidnightControlsClient.get().warn("The version of Ok Zoomer that you are currently using is too new, and is not yet supported by MidnightControls!");
return;
}
// Reflect to the ZoomKeyBinds (>= 5.0.0-beta.4) / ZoomKeybinds (<= 5.0.0-beta.3) class.
try {
okZoomerZoomKeybindsClass = Class.forName(okZoomerZoomKeybindsClassString);
} catch (ClassNotFoundException exception) {
// This theoretically should never happen.
MidnightControlsClient.get().warn("MidnightControls failed to reflect to the Ok Zoomer keybinds class!");
exception.printStackTrace();
return;
}
// Reflect to all of the keybind fields.
try {
okZoomerZoomKeyField = okZoomerZoomKeybindsClass.getField(okZoomerZoomKeyFieldString);
okZoomerIncreaseZoomKeyField = okZoomerZoomKeybindsClass.getField(okZoomerIncreaseZoomKeyFieldString);
okZoomerDecreaseZoomKeyField = okZoomerZoomKeybindsClass.getField(okZoomerDecreaseZoomKeyFieldString);
okZoomerResetZoomKeyField = okZoomerZoomKeybindsClass.getField(okZoomerResetZoomKeyFieldString);
} catch (NoSuchFieldException exception) {
MidnightControlsClient.get().warn("MidnightControls failed to reflect to the Ok Zoomer keybind fields!");
exception.printStackTrace();
return;
}
// Initialise KeyBinding objects
try {
okZoomerZoomKey = (KeyBinding) okZoomerZoomKeyField.get(null);
okZoomerIncreaseZoomKey = (KeyBinding) okZoomerIncreaseZoomKeyField.get(null);
okZoomerDecreaseZoomKey = (KeyBinding) okZoomerDecreaseZoomKeyField.get(null);
okZoomerResetZoomKey = (KeyBinding) okZoomerResetZoomKeyField.get(null);
} catch (IllegalAccessException exception) {
MidnightControlsClient.get().warn("MidnightControls failed to reflect to the Ok Zoomer keybind objects!");
exception.printStackTrace();
return;
}
// Reflect to the areExtraKeyBindsEnabled (>= 5.0.0-beta.4) / areExtraKeybindsEnabled (<= 5.0.0-beta.3) method.
// TODO: Consider replacing this entirely with getExtraKeyBind (>= 5.0.0-beta.4) / getExtraKeybind (<= 5.0.0-beta.3) in the future.
try {
okZoomerAreExtraKeyBindsEnabledMethod = okZoomerZoomKeybindsClass.getDeclaredMethod(okZoomerAreExtraKeyBindsEnabledMethodNameString);
} catch (NoSuchMethodException exception) {
MidnightControlsClient.get().warn("MidnightControls failed to reflect to an Ok Zoomer method (areExtraKeyBindsEnabled / areExtraKeybindsEnabled)!");
exception.printStackTrace();
return;
}
didAllReflectionCallsSucceed = true;
}
@Override
public void handle(@NotNull MidnightControlsClient mod) {
if (didAllReflectionCallsSucceed) {
new ButtonBinding.Builder("zoom")
.buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW.GLFW_GAMEPAD_BUTTON_X)
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(okZoomerZoomKey)
.register();
boolean okZoomerAreExtraKeyBindsEnabled = false;
try {
okZoomerAreExtraKeyBindsEnabled = (boolean) okZoomerAreExtraKeyBindsEnabledMethod.invoke(null);
} catch (IllegalAccessException exception) {
MidnightControlsClient.get().warn("MidnightControls encountered an IllegalAccessException while attempting to invoke a reflected Ok Zoomer method (areExtraKeyBindsEnabled / areExtraKeybindsEnabled)!");
exception.printStackTrace();
} catch (InvocationTargetException exception) {
MidnightControlsClient.get().warn("MidnightControls encountered an InvocationTargetException while attempting to invoke a reflected Ok Zoomer method (areExtraKeyBindsEnabled / areExtraKeybindsEnabled)!");
exception.printStackTrace();
}
if (okZoomerAreExtraKeyBindsEnabled) {
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(okZoomerIncreaseZoomKey)
.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(okZoomerDecreaseZoomKey)
.register();
new ButtonBinding.Builder("zoom_reset")
.onlyInGame()
.cooldown(true)
.category(ButtonBinding.MISC_CATEGORY)
.linkKeybind(okZoomerResetZoomKey)
.register();
}
}
}
}

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