├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── gradlebuild.yml │ ├── gradlepublish.yml │ └── modrinth_update.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── HEADER ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── icon.png ├── images ├── controller_controls.png └── controller_options.png ├── settings.gradle └── src └── main ├── java └── dev │ └── lambdaurora │ └── lambdacontrols │ ├── ControlsMode.java │ ├── LambdaControls.java │ ├── LambdaControlsConstants.java │ ├── LambdaControlsFeature.java │ ├── client │ ├── ButtonState.java │ ├── ControllerType.java │ ├── HudSide.java │ ├── LambdaControlsClient.java │ ├── LambdaControlsConfig.java │ ├── LambdaControlsModMenu.java │ ├── LambdaInput.java │ ├── LambdaReacharound.java │ ├── VirtualMouseSkin.java │ ├── compat │ │ ├── CompatHandler.java │ │ ├── HQMCompat.java │ │ ├── LambdaControlsCompat.java │ │ ├── LambdaControlsMixinPlugin.java │ │ ├── OkZoomerCompat.java │ │ ├── ReiCompat.java │ │ └── mixin │ │ │ ├── EntryListWidgetAccessor.java │ │ │ ├── EntryWidgetAccessor.java │ │ │ ├── RecipeViewingScreenAccessor.java │ │ │ └── VillagerRecipeViewingScreenAccessor.java │ ├── controller │ │ ├── ButtonBinding.java │ │ ├── ButtonCategory.java │ │ ├── Controller.java │ │ ├── InputHandlers.java │ │ ├── InputManager.java │ │ ├── MovementHandler.java │ │ └── PressAction.java │ ├── gui │ │ ├── LambdaControlsHud.java │ │ ├── LambdaControlsRenderer.java │ │ ├── LambdaControlsSettingsScreen.java │ │ ├── MappingsStringInputWidget.java │ │ ├── ReloadControllerMappingsOption.java │ │ ├── RingScreen.java │ │ ├── TouchscreenOverlay.java │ │ └── widget │ │ │ ├── ControllerButtonWidget.java │ │ │ ├── ControllerControlsWidget.java │ │ │ └── ControlsListWidget.java │ ├── mixin │ │ ├── AdvancementsScreenAccessor.java │ │ ├── ClickableWidgetAccessor.java │ │ ├── ClientPlayerEntityMixin.java │ │ ├── ControlsOptionsScreenMixin.java │ │ ├── CreativeInventoryScreenAccessor.java │ │ ├── EntryListWidgetAccessor.java │ │ ├── GameOptionsMixin.java │ │ ├── GameRendererMixin.java │ │ ├── HandledScreenMixin.java │ │ ├── KeyBindingMixin.java │ │ ├── MinecraftClientMixin.java │ │ ├── MouseMixin.java │ │ ├── OptionsScreenMixin.java │ │ ├── RecipeBookWidgetAccessor.java │ │ └── WorldRendererMixin.java │ ├── ring │ │ ├── DummyRingAction.java │ │ ├── KeyBindingRingAction.java │ │ ├── LambdaRing.java │ │ ├── RingAction.java │ │ ├── RingButtonMode.java │ │ └── RingPage.java │ └── util │ │ ├── HandledScreenAccessor.java │ │ ├── KeyBindingAccessor.java │ │ └── MouseAccessor.java │ └── event │ └── PlayerChangeControlsModeCallback.java └── resources ├── assets └── lambdacontrols │ ├── icon.png │ ├── icon_x400.png │ ├── lang │ ├── en_us.json │ ├── es_mx.json │ ├── fr_ca.json │ ├── fr_fr.json │ ├── tr_tr.json │ └── zh_cn.json │ └── textures │ └── gui │ ├── controller_axis.png │ ├── controller_buttons.png │ ├── cursor.png │ └── widgets.png ├── config.toml ├── fabric.mod.json ├── lambdacontrols.accesswidener ├── lambdacontrols.mixins.json └── lambdacontrols_compat.mixins.json /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. Linux] 28 | - Minecraft [e.g. 1.14.4] 29 | - Fabric [e.g. fabric 0.7.2+build.174] 30 | - Mods [e.g. aurora_keystrokes v1.0.0, modmenu v1.7.15] 31 | - Version [e.g. 1.0.0] 32 | - Branch [e.g. dev] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/gradlebuild.yml: -------------------------------------------------------------------------------- 1 | name: Gradle Build 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Set up JDK 16 11 | uses: actions/setup-java@v1 12 | with: 13 | java-version: 16 14 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml 15 | settings-path: ${{ github.workspace }} # location for the settings.xml file 16 | 17 | - name: Build with Gradle 18 | run: ./gradlew build 19 | 20 | - uses: actions/upload-artifact@v2 21 | with: 22 | name: Artifacts 23 | path: ./build/libs/ 24 | -------------------------------------------------------------------------------- /.github/workflows/gradlepublish.yml: -------------------------------------------------------------------------------- 1 | name: Gradle Package 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Set up JDK 16 14 | uses: actions/setup-java@v1 15 | with: 16 | java-version: 16 17 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml 18 | settings-path: ${{ github.workspace }} # location for the settings.xml file 19 | 20 | - name: Build with Gradle 21 | run: ./gradlew build 22 | 23 | - uses: actions/upload-artifact@v2 24 | with: 25 | name: Artifacts 26 | path: ./build/libs/ 27 | 28 | # The USERNAME and PASSWORD need to correspond to the credentials environment variables used in 29 | # the publishing section of your build.gradle 30 | - name: Publish to GitHub Packages and other Mavens 31 | run: ./gradlew publish 32 | env: 33 | BRANCH_NAME: ${{ github.ref }} 34 | RUN_COUNT: ${{ github.run_number }} 35 | REPO_NAME: ${{ github.repository }} 36 | USERNAME: ${{ github.actor }} 37 | TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | LAMBDACONTROLS_MAVEN: ${{ secrets.MAVEN_URL }} 39 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 40 | MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} 41 | -------------------------------------------------------------------------------- /.github/workflows/modrinth_update.yml: -------------------------------------------------------------------------------- 1 | name: Gradle Build 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Set up JDK 16 14 | uses: actions/setup-java@v1 15 | with: 16 | java-version: 16 17 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml 18 | settings-path: ${{ github.workspace }} # location for the settings.xml file 19 | 20 | - name: Build with Gradle 21 | env: 22 | MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} 23 | run: ./gradlew publishModrinth 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # LambdAurora's ignore file 3 | # 4 | # v0.15 5 | 6 | # JetBrains 7 | .idea/ 8 | *.iml 9 | *.ipr 10 | *.iws 11 | ## Intellij IDEA 12 | out/ 13 | ## CLion 14 | cmake-build-debug*/ 15 | cmake-build-release*/ 16 | ## Eclipse 17 | eclipse 18 | *.launch 19 | .settings 20 | .metadata 21 | .classpath 22 | .project 23 | ## Visual Studio 24 | .vs/ 25 | CMakeSettings.json 26 | 27 | # Build system 28 | ## Cargo 29 | Cargo.lock 30 | ## CMake 31 | CMakeCache.txt 32 | CMakeFiles/ 33 | ## Gradle 34 | .gradle/ 35 | ## Node.JS 36 | node_modules/ 37 | 38 | # Editors 39 | ## VSCode 40 | .vscode/ 41 | 42 | # Logging 43 | logs/ 44 | 45 | # Languages 46 | ## Java 47 | classes/ 48 | ## Python 49 | __pycache__/ 50 | ## Rust 51 | **/*.rs.bk 52 | 53 | # OS 54 | ## Windows 55 | desktop.ini 56 | # MacOS 57 | .DS_Store 58 | 59 | # File types 60 | *.dll 61 | *.so 62 | *.dylib 63 | *.lib 64 | lib*.a 65 | *.png~ 66 | *.tar.?z 67 | 68 | # Common 69 | bin/ 70 | build/ 71 | dist/ 72 | lib/ 73 | obj/ 74 | run/ 75 | target/ 76 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.0 4 | 5 | :tada: First release! :tada: 6 | 7 | - Added controller support. 8 | - Added new controls settings GUI. 9 | - Added experimental touchscreen support. 10 | - Added controller controls GUI. 11 | - Added a lot of options. 12 | - Added key bindings for look around. 13 | - And more! 14 | 15 | ### 1.0.1 16 | 17 | - Fixed tutorial toast to look around not affected by camera movement done with a controller. ([#2](https://github.com/LambdAurora/LambdaControls/issues/2)) 18 | 19 | ### 1.0.2 (Unofficial) 20 | 21 | This update was never pushed but was aiming to fix [#4](https://github.com/LambdAurora/LambdaControls/issues/4). 22 | 23 | - Fixed the toggle sneak button binding. 24 | - Fixed broken chat arrow keys. 25 | - Optimized a little bit the button indicator. (need more work) 26 | 27 | ## 1.1.0 - Chording update 28 | 29 | This update also has a backport 1.14.4 version ([#9](https://github.com/LambdAurora/LambdaControls/issues/9)). 30 | 31 | - Rewrote everything (almost). 32 | - Added [networking](https://github.com/LambdAurora/LambdaControls/wiki/LambdaControls-Networking) for some features. 33 | - Added second controller support (Joycons supported now hopefully). 34 | - Added chording. 35 | - Added better developer API 36 | - Added hover messages ([#5](https://github.com/LambdAurora/LambdaControls/issues/5)). 37 | - Added hotbar button bindings ([#7](https://github.com/LambdAurora/LambdaControls/issues/7)). 38 | - Added front block placing feature ([#8](https://github.com/LambdAurora/LambdaControls/issues/8)). 39 | - Added no creative fly drifting ([#8](https://github.com/LambdAurora/LambdaControls/issues/8)). 40 | - Added option to enable controller focus. 41 | - Added [OkZoomer](https://github.com/joaoh1/OkZoomer) compatibility. 42 | - Added D-pad movements in inventories. 43 | - Increased max speed ranges. 44 | - Added [SpruceUI](https://github.com/LambdAurora/SpruceUI) for cleaner custom UI widgets. 45 | - Added reset settings button. 46 | - HUD side affects button indicators now. 47 | - Added support for Advancements tabs. 48 | 49 | ### 1.1.1 50 | 51 | ## 1.2.0-1.3.0 52 | 53 | - Improved rotation algorithm ([#11](https://github.com/LambdAurora/LambdaControls/issues/11)). 54 | - Added virtual mouse. 55 | - Added outline on front block placing. 56 | - Added fast block placement ([#8](https://github.com/LambdAurora/LambdaControls/issues/8)). 57 | - Added [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items) compatibility. 58 | - Improved HUD. 59 | - Added recipe book control. 60 | - And more! 61 | - v1.3.0 specific: Updated to Minecraft 1.16.1 62 | 63 | ### 1.3.1 64 | 65 | - Fixed broken inventory interactions ([#13](https://github.com/LambdAurora/LambdaControls/issues/13)) 66 | - Fixed virtual mouse preventing continuous attack (thus making breaking blocks impossible). 67 | - Added support for [ModUpdater](https://gitea.thebrokenrail.com/TheBrokenRail/ModUpdater) hopefully. 68 | - Updated [SpruceUI](https://github.com/LambdAurora/SpruceUI) to 1.5.2. 69 | 70 | ### 1.3.2 71 | 72 | - Added vertical reacharound. 73 | - Added more API for compatibility handlers. 74 | - Improved reacharound API. 75 | - Improved [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items) compatibility. 76 | 77 | ## 1.4.0 78 | 79 | - Added analog movements ([#10](https://github.com/LambdAurora/LambdaControls/issues/10)). 80 | - Improved Ok Zoomer compability. 81 | - Updated [SpruceUI](https://github.com/LambdAurora/SpruceUI) to 1.5.8 to ensure 1.16.2 compability. 82 | - Internal changes: 83 | - Added analog input value to button bindings. 84 | - Replace lot of strings with Texts. 85 | - Improved block outline rendering injection. 86 | - Shadow library jars instead of Jar-in-Jar. 87 | - Fixed crash in inventory ([#16](https://github.com/LambdAurora/LambdaControls/issues/16)) 88 | - WIP: 89 | - Started to work on action ring. 90 | - Will allow for better compability with other mods. 91 | - Might be interesting for keyboard users too. 92 | 93 | ### 1.4.1 94 | 95 | - Fixed crash with [REI](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items). 96 | 97 | ## 1.5.0 98 | 99 | - Added mappings string editor screen. 100 | - Added Simplified Chinese translations ([#18](https://github.com/LambdAurora/LambdaControls/pull/18)). 101 | - Added Mexican Spanish translations ([#22](https://github.com/LambdAurora/LambdaControls/pull/22)). 102 | - Added Xbox 360 button skin and overhauled Xbox button skin. 103 | - Added debug option. 104 | - Respect toggle setting in Accessibility screen. 105 | - Tweaked rotation speeds. 106 | - Updated to Minecraft 1.16.2. 107 | - Updated [SpruceUI] to 1.6.4. 108 | - Overhauled REI compatibility. 109 | - Improved horizontal reach-around. 110 | - Fixed crashes with Ok Zoomer. 111 | - Fixed crashes with key unbinding. 112 | - More WIP on keybind ring. 113 | 114 | ## 1.6.0 115 | 116 | - Reworked entirely the settings screen. 117 | - Added independent stick dead zones. ([#32](https://github.com/LambdAurora/LambdaControls/issues/32)) 118 | - Added max values range. ([#41](https://github.com/LambdAurora/LambdaControls/issues/41)) 119 | - 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)). 120 | - Fix boat control issues ([#37](https://github.com/LambdAurora/LambdaControls/issues/37)). 121 | - 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)) 122 | 123 | ## 1.7.0 124 | 125 | - Updated to 1.17. 126 | - Small improvements to the codebase thanks to Java 16. 127 | - Fix controller bindings not being saved ([#31](https://github.com/LambdAurora/LambdaControls/issues/31), [#55](https://github.com/LambdAurora/LambdaControls/issues/55)). 128 | - Dropped entirely Touchscreen Input Mode. 129 | - Dropped Roughly Enough Items compatibility. 130 | 131 | ### 1.7.1 132 | 133 | - Fix crash at startup. 134 | 135 | [SpruceUI]: https://github.com/LambdAurora/SpruceUI -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at aurora42lambda@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to LambdaControls 2 | 3 | :tada: First of all, thanks for taking time to contribute! :tada: 4 | 5 | The following is a set of guidelines for contributing to LambdaControls. 6 | Feel free to propose changes to this document in a pull request. 7 | 8 | **Table of Contents** 9 | 10 | [Code of Conduct](#code-of-conduct) 11 | 12 | [What should I know before I get started?](#what-should-i-know-before-i-get-started) 13 | 14 | [How can I contribute?](#how-can-i-contribute) 15 | 16 | [Styleguides](#styleguides) 17 | 18 | ## Code of Conduct 19 | 20 | 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). 21 | By participating, you are expected to uphold this code. Please report unacceptable behavior at [aurora42lambda@gmail.com](mailto:aurora42lambda@gmail.com). 22 | 23 | ## What should I know before I get started? 24 | 25 | ### Fabric 26 | 27 | [Fabric](https://fabricmc.net/) is the mod loader and the software which allows Gradle to setup the workspace. 28 | 29 | ### Java 16 30 | 31 | Java is the main language used to make LambdaControls alive. 32 | Knowing how to code in Java is necessary if you contribute to the code. 33 | 34 | ### Minecraft 35 | 36 | As it is a Minecraft mod you should know a bit how Minecraft works and how modding works. 37 | 38 | ### Mixins 39 | 40 | [Mixins](https://github.com/SpongePowered/Mixin/wiki) are a main part in this mod, they allow the necessary modifications to the Minecraft Client. 41 | 42 | ### Gradle 43 | 44 | [Gradle](https://gradle.org/) is the build tool used for this project. 45 | 46 | ### Git 47 | 48 | Git is the control version software we use for LambdaControls, please know how to use it if you consider contributing to the code. 49 | 50 | Git commits should be signed. 51 | 52 | ## How can I contribute? 53 | 54 | ### Reporting Bugs 55 | 56 | #### Before submitting a bug report 57 | 58 | - Check if you can reproduce it on other platforms. 59 | - 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. 60 | 61 | #### How do I submit a bug report? 62 | 63 | Go in the issues tab in GitHub and read the [bug report guide](https://github.com/LambdAurora/LambdaControls/blob/1.17/.github/ISSUE_TEMPLATE/bug_report.md) 64 | 65 | ### Suggesting enhancements 66 | 67 | Enhancement suggestions are tracked as [GitHub issues](https://github.com/LambdAurora/LambdaControls/issues). 68 | Check out the [feature request](https://github.com/LambdAurora/LambdaControls/blob/1.17/.github/ISSUE_TEMPLATE/feature_request.md) guide. 69 | 70 | ### Do pull requests 71 | 72 | You can help LambdaControls by writing code and submit it with pull requests. 73 | 74 | Pull requests will be accepted if they follow the [styleguide](#styleguides), if they are useful, etc... 75 | 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)! 76 | 77 | Feel free to pull request! 78 | 79 | ## Styleguides 80 | 81 | ### Git commit messages 82 | 83 | * Use the imperative mood ("Move cursor to..." not "Moves cursor to...") 84 | * (Not for the message) Don't forget to sign the commit. 85 | 86 | ### Naming convention 87 | 88 | Names in the code should be explicit and always in `camelCase`, `snake_case` will not be allowed. 89 | `PascalCase` can be used for class name. 90 | 91 | ### Brace placement 92 | 93 | Every braces should be at the end of the line of function declaration, etc. 94 | 95 | ### Quick note for users of the Intellij IDEA IDE 96 | 97 | As a user of the Intellij IDEA IDE you have the format code shortcut which use a codestyle described by a file. 98 | You can import the codestyle file here: [LambdAurora's dotfiles](https://github.com/LambdAurora/dotfiles/blob/master/jetbrains/lambdacodestyle2.xml). 99 | -------------------------------------------------------------------------------- /HEADER: -------------------------------------------------------------------------------- 1 | Copyright © 2021 LambdAurora 2 | 3 | This file is part of LambdaControls. 4 | 5 | Licensed under the MIT license. For more information, 6 | see the LICENSE file. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2021 LambdAurora 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LambdaControls 2 | 3 | 4 | ![Java 16](https://img.shields.io/badge/language-Java%2016-9B599A.svg?style=flat-square) 5 | [![GitHub license](https://img.shields.io/github/license/LambdAurora/LambdaControls?style=flat-square)](https://raw.githubusercontent.com/LambdAurora/LambdaControls/master/LICENSE) 6 | ![Environment: Client](https://img.shields.io/badge/environment-client-1976d2?style=flat-square) 7 | [![Mod loader: Fabric]][fabric] 8 | ![Version](https://img.shields.io/github/v/tag/LambdAurora/LambdaControls?label=version&style=flat-square) 9 | [![CurseForge](http://cf.way2muchnoise.eu/title/354231.svg)](https://www.curseforge.com/minecraft/mc-mods/lambdacontrols) 10 | 11 | 12 | A Fabric Minecraft mod which adds better controls, reach-around and controller support. 13 | 14 | ## What's this mod? 15 | 16 | This mod adds better controls, reach-around features, etc. 17 | 18 | Haven't you dreamed to travel in your modded Minecraft world with your controller? Yes? Then this mod is made for you! 19 | 20 | This mod also adds controller support. 21 | 22 | ## ✅ Features: 23 | 24 | - Controller support 25 | - Touchscreen support (very experimental and buggy). 26 | - Keyboard controls to look around. 27 | - Toggleable on screen button indicator (like in Bedrock Edition). 28 | - Vertical reach-around. 29 | - Many Bedrock Edition features: 30 | - Toggleable fly drifting 31 | - Front block placing (be careful with this one) 32 | - New controls settings! 33 | - Many options in config to change to your liking. 34 | - Many controllers supported and in a simply way your own controller mappings. 35 | - An easy API for developers to add their own button bindings. 36 | 37 | ## 🎮 Supported Controllers: 38 | 39 | - Dualshock controllers 40 | - Xbox controllers 41 | - Switch Pro controllers 42 | - Joycons 43 | - And many more! 44 | 45 | ## Screenshots 46 | 47 | ![controller_controls](images/controller_controls.png) 48 | ![controller_options](images/controller_options.png) 49 | 50 | 51 | ## Build 52 | 53 | Just do `./gradlew build` and everything should build just fine! 54 | 55 | 56 | [fabric]: https://fabricmc.net 57 | [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== 58 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | # Fabric Properties 5 | # check these on https://fabricmc.net/use 6 | minecraft_version=1.17 7 | yarn_mappings=1.17+build.13 8 | loader_version=0.11.6 9 | 10 | # Mod Properties 11 | mod_version = 1.7.1 12 | maven_group = dev.lambdaurora 13 | archives_base_name = lambdacontrols 14 | modrinth_id=W1D3UXEc 15 | 16 | # Dependencies 17 | # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api 18 | fabric_version=0.36.0+1.17 19 | spruceui_version=3.2.0+1.17 20 | modmenu_version=2.0.2 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/icon.png -------------------------------------------------------------------------------- /images/controller_controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/images/controller_controls.png -------------------------------------------------------------------------------- /images/controller_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/images/controller_options.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name 'Fabric' 5 | url 'https://maven.fabricmc.net/' 6 | } 7 | gradlePluginPortal() 8 | } 9 | } 10 | 11 | rootProject.name = 'lambdacontrols' 12 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/ControlsMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols; 11 | 12 | import org.aperlambda.lambdacommon.utils.Nameable; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.Arrays; 16 | import java.util.Optional; 17 | 18 | /** 19 | * Represents the controls mode. 20 | * 21 | * @author LambdAurora 22 | * @version 1.7.0 23 | * @since 1.0.0 24 | */ 25 | public enum ControlsMode implements Nameable { 26 | DEFAULT, 27 | CONTROLLER; 28 | 29 | /** 30 | * Returns the next controls mode available. 31 | * 32 | * @return the next available controls mode 33 | */ 34 | public ControlsMode next() { 35 | var v = values(); 36 | if (v.length == this.ordinal() + 1) 37 | return v[0]; 38 | return v[this.ordinal() + 1]; 39 | } 40 | 41 | /** 42 | * Gets the translation key of this controls mode. 43 | * 44 | * @return the translated key of this controls mode 45 | * @since 1.1.0 46 | */ 47 | public String getTranslationKey() { 48 | return "lambdacontrols.controls_mode." + this.getName(); 49 | } 50 | 51 | @Override 52 | public @NotNull String getName() { 53 | return this.name().toLowerCase(); 54 | } 55 | 56 | /** 57 | * Gets the controls mode from its identifier. 58 | * 59 | * @param id the identifier of the controls mode 60 | * @return the controls mode if found, else empty 61 | */ 62 | public static Optional byId(@NotNull String id) { 63 | return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/LambdaControls.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols; 11 | 12 | import dev.lambdaurora.lambdacontrols.event.PlayerChangeControlsModeCallback; 13 | import io.netty.buffer.Unpooled; 14 | import net.fabricmc.api.ModInitializer; 15 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 16 | import net.fabricmc.loader.api.FabricLoader; 17 | import net.fabricmc.loader.api.ModContainer; 18 | import net.minecraft.network.PacketByteBuf; 19 | import net.minecraft.text.TranslatableText; 20 | import net.minecraft.util.Identifier; 21 | import org.apache.logging.log4j.LogManager; 22 | import org.apache.logging.log4j.Logger; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | import java.util.Objects; 26 | import java.util.Optional; 27 | 28 | /** 29 | * Represents the LambdaControls mod. 30 | * 31 | * @author LambdAurora 32 | * @version 1.7.0 33 | * @since 1.0.0 34 | */ 35 | public class LambdaControls implements ModInitializer { 36 | private static LambdaControls INSTANCE; 37 | public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(LambdaControlsConstants.CONTROLS_MODE_CHANNEL.toString()); 38 | public static final Identifier FEATURE_CHANNEL = new Identifier(LambdaControlsConstants.FEATURE_CHANNEL.toString()); 39 | public static final Identifier HELLO_CHANNEL = new Identifier(LambdaControlsConstants.HELLO_CHANNEL.toString()); 40 | 41 | public static final TranslatableText NOT_BOUND_TEXT = new TranslatableText("lambdacontrols.not_bound"); 42 | 43 | public final Logger logger = LogManager.getLogger("LambdaControls"); 44 | 45 | @Override 46 | public void onInitialize() { 47 | INSTANCE = this; 48 | this.log("Initializing LambdaControls..."); 49 | 50 | ServerPlayNetworking.registerGlobalReceiver(HELLO_CHANNEL, (server, player, handler, buf, responseSender) -> { 51 | String version = buf.readString(32); 52 | ControlsMode.byId(buf.readString(32)) 53 | .ifPresent(controlsMode -> server 54 | .execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(player, controlsMode))); 55 | server.execute(() -> { 56 | ServerPlayNetworking.send(player, FEATURE_CHANNEL, this.makeFeatureBuffer(LambdaControlsFeature.HORIZONTAL_REACHAROUND)); 57 | }); 58 | }); 59 | ServerPlayNetworking.registerGlobalReceiver(CONTROLS_MODE_CHANNEL, 60 | (server, player, handler, buf, responseSender) -> ControlsMode.byId(buf.readString(32)) 61 | .ifPresent(controlsMode -> server 62 | .execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(player, controlsMode)))); 63 | } 64 | 65 | /** 66 | * Prints a message to the terminal. 67 | * 68 | * @param info the message to print 69 | */ 70 | public void log(String info) { 71 | this.logger.info("[LambdaControls] " + info); 72 | } 73 | 74 | /** 75 | * Prints a warning to the terminal. 76 | * 77 | * @param warning the warning to print 78 | */ 79 | public void warn(String warning) { 80 | this.logger.info("[LambdaControls] " + warning); 81 | } 82 | 83 | /** 84 | * Returns a packet byte buffer made for the lambdacontrols:controls_mode plugin message. 85 | * 86 | * @param controlsMode the controls mode to send 87 | * @return the packet byte buffer 88 | */ 89 | public PacketByteBuf makeControlsModeBuffer(@NotNull ControlsMode controlsMode) { 90 | Objects.requireNonNull(controlsMode, "Controls mode cannot be null."); 91 | return new PacketByteBuf(Unpooled.buffer()).writeString(controlsMode.getName(), 32); 92 | } 93 | 94 | /** 95 | * Returns a packet byte buffer made for the lambdacontrols:feature plugin message. 96 | * 97 | * @param features the features data to send 98 | * @return the packet byte buffer 99 | */ 100 | public PacketByteBuf makeFeatureBuffer(LambdaControlsFeature... features) { 101 | if (features.length == 0) 102 | throw new IllegalArgumentException("At least one feature must be provided."); 103 | var buffer = new PacketByteBuf(Unpooled.buffer()); 104 | buffer.writeVarInt(features.length); 105 | for (var feature : features) { 106 | buffer.writeString(feature.getName(), 64); 107 | buffer.writeBoolean(feature.isAllowed()); 108 | } 109 | return buffer; 110 | } 111 | 112 | public PacketByteBuf makeHello(@NotNull ControlsMode controlsMode) { 113 | var version = ""; 114 | Optional container; 115 | if ((container = FabricLoader.getInstance().getModContainer(LambdaControlsConstants.NAMESPACE)).isPresent()) { 116 | version = container.get().getMetadata().getVersion().getFriendlyString(); 117 | } 118 | return new PacketByteBuf(Unpooled.buffer()).writeString(version, 32).writeString(controlsMode.getName(), 32); 119 | } 120 | 121 | /** 122 | * Gets the LambdaControls instance. 123 | * 124 | * @return the LambdaControls instance 125 | */ 126 | public static LambdaControls get() { 127 | return INSTANCE; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/LambdaControlsConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols; 11 | 12 | import org.aperlambda.lambdacommon.Identifier; 13 | 14 | /** 15 | * Represents the constants used by LambdaControls. 16 | * 17 | * @author LambdAurora 18 | * @version 1.1.0 19 | * @since 1.1.0 20 | */ 21 | public class LambdaControlsConstants { 22 | public static final String NAMESPACE = "lambdacontrols"; 23 | public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(NAMESPACE, "controls_mode"); 24 | public static final Identifier FEATURE_CHANNEL = new Identifier(NAMESPACE, "feature"); 25 | public static final Identifier HELLO_CHANNEL = new Identifier(NAMESPACE, "hello"); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/LambdaControlsFeature.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols; 11 | 12 | import org.aperlambda.lambdacommon.utils.Nameable; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Objects; 18 | import java.util.Optional; 19 | 20 | /** 21 | * Represents a feature. 22 | * 23 | * @author LambdAurora 24 | * @version 1.5.0 25 | * @since 1.1.0 26 | */ 27 | public class LambdaControlsFeature implements Nameable { 28 | private static final List FEATURES = new ArrayList<>(); 29 | public static final LambdaControlsFeature FAST_BLOCK_PLACING = new LambdaControlsFeature("fast_block_placing", true, true); 30 | public static final LambdaControlsFeature HORIZONTAL_REACHAROUND = new LambdaControlsFeature("horizontal_reacharound", true, false); 31 | public static final LambdaControlsFeature VERTICAL_REACHAROUND = new LambdaControlsFeature("vertical_reacharound", true, false); 32 | 33 | private final String key; 34 | private final boolean defaultAllowed; 35 | private boolean allowed; 36 | private final boolean defaultEnabled; 37 | private boolean enabled; 38 | 39 | public LambdaControlsFeature(@NotNull String key, boolean allowed, boolean enabled) { 40 | Objects.requireNonNull(key, "Feature key cannot be null."); 41 | this.key = key; 42 | this.setAllowed(this.defaultAllowed = allowed); 43 | this.setEnabled(this.defaultEnabled = enabled); 44 | } 45 | 46 | public LambdaControlsFeature(@NotNull String key) { 47 | this(key, false, false); 48 | } 49 | 50 | /** 51 | * Allows the feature. 52 | */ 53 | public void allow() { 54 | this.setAllowed(true); 55 | } 56 | 57 | /** 58 | * Returns whether this feature is allowed. 59 | * 60 | * @return {@code true} if this feature is allowed, else {@code false} 61 | */ 62 | public boolean isAllowed() { 63 | return this.allowed; 64 | } 65 | 66 | /** 67 | * Sets whether this feature is allowed. 68 | * 69 | * @param allowed {@code true} if this feature is allowed, else {@code false} 70 | */ 71 | public void setAllowed(boolean allowed) { 72 | this.allowed = allowed; 73 | } 74 | 75 | /** 76 | * Resets allowed state to default. 77 | */ 78 | public void resetAllowed() { 79 | this.setAllowed(this.defaultAllowed); 80 | } 81 | 82 | /** 83 | * Returns whether this feature is enabled. 84 | * 85 | * @return {@code true} if this feature is enabled, else {@code false} 86 | */ 87 | public boolean isEnabled() { 88 | return this.enabled; 89 | } 90 | 91 | /** 92 | * Returns whether this feature is enabled. 93 | * 94 | * @param enabled {@code true} if this feature is enabled, else {@code false} 95 | */ 96 | public void setEnabled(boolean enabled) { 97 | this.enabled = enabled; 98 | } 99 | 100 | /** 101 | * Returns whether this feature is available or not. 102 | * 103 | * @return {@code true} if this feature is available, else {@code false} 104 | * @see #isAllowed() 105 | * @see #isEnabled() 106 | */ 107 | public boolean isAvailable() { 108 | return this.isAllowed() && this.isEnabled(); 109 | } 110 | 111 | /** 112 | * Resets the feature to its default values. 113 | */ 114 | public void reset() { 115 | this.resetAllowed(); 116 | this.setEnabled(this.defaultEnabled); 117 | } 118 | 119 | @Override 120 | public @NotNull String getName() { 121 | return this.key; 122 | } 123 | 124 | public static @NotNull Optional fromName(@NotNull String key) { 125 | Objects.requireNonNull(key, "Cannot find features with a null name."); 126 | return FEATURES.parallelStream().filter(feature -> feature.getName().equals(key)).findFirst(); 127 | } 128 | 129 | /** 130 | * Resets all features to their default values. 131 | */ 132 | public static void resetAll() { 133 | FEATURES.parallelStream().forEach(LambdaControlsFeature::reset); 134 | } 135 | 136 | /** 137 | * Resets all features to allow state. 138 | */ 139 | public static void resetAllAllowed() { 140 | FEATURES.parallelStream().forEach(LambdaControlsFeature::resetAllowed); 141 | } 142 | 143 | static { 144 | FEATURES.add(FAST_BLOCK_PLACING); 145 | FEATURES.add(HORIZONTAL_REACHAROUND); 146 | FEATURES.add(VERTICAL_REACHAROUND); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/ButtonState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client; 11 | 12 | /** 13 | * Represents a button state. 14 | * 15 | * @author LambdAurora 16 | * @version 1.1.0 17 | * @since 1.1.0 18 | */ 19 | public enum ButtonState { 20 | NONE(0), 21 | PRESS(1), 22 | RELEASE(2), 23 | REPEAT(3); 24 | 25 | public final int id; 26 | 27 | ButtonState(int id) { 28 | this.id = id; 29 | } 30 | 31 | /** 32 | * Returns whether this state is a pressed state. 33 | * 34 | * @return true if this state is a pressed state, else false 35 | */ 36 | public boolean isPressed() { 37 | return this == PRESS || this == REPEAT; 38 | } 39 | 40 | /** 41 | * Returns whether this state is an unpressed state. 42 | * 43 | * @return true if this state is an unpressed state, else false 44 | */ 45 | public boolean isUnpressed() { 46 | return this == RELEASE || this == NONE; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/ControllerType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client; 11 | 12 | import net.minecraft.text.LiteralText; 13 | import net.minecraft.text.Text; 14 | import net.minecraft.text.TranslatableText; 15 | import org.aperlambda.lambdacommon.utils.Nameable; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | import java.util.Arrays; 19 | import java.util.Optional; 20 | 21 | /** 22 | * Represents a controller type. 23 | * 24 | * @author LambdAurora 25 | * @version 1.4.3 26 | * @since 1.0.0 27 | */ 28 | public enum ControllerType implements Nameable { 29 | DEFAULT(0), 30 | DUALSHOCK(1), 31 | SWITCH(2), 32 | XBOX_360(3, new LiteralText("Xbox 360")), 33 | XBOX(4), 34 | STEAM(5), 35 | OUYA(6); 36 | 37 | private final int id; 38 | private final Text text; 39 | 40 | ControllerType(int id) { 41 | this.id = id; 42 | this.text = new TranslatableText("lambdacontrols.controller_type." + this.getName()); 43 | } 44 | 45 | ControllerType(int id, @NotNull Text text) { 46 | this.id = id; 47 | this.text = text; 48 | } 49 | 50 | /** 51 | * Returns the controller type's identifier. 52 | * 53 | * @return the controller type's identifier 54 | */ 55 | public int getId() { 56 | return this.id; 57 | } 58 | 59 | /** 60 | * Returns the next controller type available. 61 | * 62 | * @return the next available controller type 63 | */ 64 | public @NotNull ControllerType next() { 65 | var v = values(); 66 | if (v.length == this.ordinal() + 1) 67 | return v[0]; 68 | return v[this.ordinal() + 1]; 69 | } 70 | 71 | /** 72 | * Gets the translated text of this controller type. 73 | * 74 | * @return the translated text of this controller type 75 | */ 76 | public @NotNull Text getTranslatedText() { 77 | return this.text; 78 | } 79 | 80 | @Override 81 | public @NotNull String getName() { 82 | return this.name().toLowerCase(); 83 | } 84 | 85 | /** 86 | * Gets the controller type from its identifier. 87 | * 88 | * @param id the identifier of the controller type 89 | * @return the controller type if found, else empty 90 | */ 91 | public static @NotNull Optional byId(@NotNull String id) { 92 | return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/HudSide.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client; 11 | 12 | import net.minecraft.text.Text; 13 | import net.minecraft.text.TranslatableText; 14 | import org.aperlambda.lambdacommon.utils.Nameable; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.Arrays; 18 | import java.util.Optional; 19 | 20 | /** 21 | * Represents the hud side which is the side where the movements buttons are. 22 | * 23 | * @author LambdAurora 24 | * @version 1.4.0 25 | * @since 1.0.0 26 | */ 27 | public enum HudSide implements Nameable { 28 | LEFT, 29 | RIGHT; 30 | 31 | private final Text text; 32 | 33 | HudSide() { 34 | this.text = new TranslatableText(this.getTranslationKey()); 35 | } 36 | 37 | /** 38 | * Returns the next side available. 39 | * 40 | * @return the next available side 41 | */ 42 | public @NotNull HudSide next() { 43 | var v = values(); 44 | if (v.length == this.ordinal() + 1) 45 | return v[0]; 46 | return v[this.ordinal() + 1]; 47 | } 48 | 49 | /** 50 | * Returns the translation key of this hud side. 51 | * 52 | * @return the translation key of this hude side 53 | */ 54 | public @NotNull String getTranslationKey() { 55 | return "lambdacontrols.hud_side." + this.getName(); 56 | } 57 | 58 | /** 59 | * Gets the translated text of this hud side. 60 | * 61 | * @return the translated text of this hud side 62 | */ 63 | public @NotNull Text getTranslatedText() { 64 | return this.text; 65 | } 66 | 67 | @Override 68 | public @NotNull String getName() { 69 | return this.name().toLowerCase(); 70 | } 71 | 72 | /** 73 | * Gets the hud side from its identifier. 74 | * 75 | * @param id the identifier of the hud side 76 | * @return the hud side if found, else empty 77 | */ 78 | public static @NotNull Optional byId(@NotNull String id) { 79 | return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/LambdaControlsClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client; 11 | 12 | import dev.lambdaurora.lambdacontrols.ControlsMode; 13 | import dev.lambdaurora.lambdacontrols.LambdaControls; 14 | import dev.lambdaurora.lambdacontrols.LambdaControlsConstants; 15 | import dev.lambdaurora.lambdacontrols.LambdaControlsFeature; 16 | import dev.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; 17 | import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding; 18 | import dev.lambdaurora.lambdacontrols.client.controller.Controller; 19 | import dev.lambdaurora.lambdacontrols.client.controller.InputManager; 20 | import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsHud; 21 | import dev.lambdaurora.lambdacontrols.client.ring.KeyBindingRingAction; 22 | import dev.lambdaurora.lambdacontrols.client.ring.LambdaRing; 23 | import dev.lambdaurora.spruceui.hud.HudManager; 24 | import net.fabricmc.api.ClientModInitializer; 25 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 26 | import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; 27 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; 28 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 29 | import net.minecraft.client.MinecraftClient; 30 | import net.minecraft.client.network.ClientPlayNetworkHandler; 31 | import net.minecraft.client.option.KeyBinding; 32 | import net.minecraft.client.toast.SystemToast; 33 | import net.minecraft.client.util.InputUtil; 34 | import net.minecraft.text.LiteralText; 35 | import net.minecraft.text.TranslatableText; 36 | import net.minecraft.util.Identifier; 37 | import org.jetbrains.annotations.NotNull; 38 | import org.lwjgl.glfw.GLFW; 39 | 40 | import java.io.File; 41 | 42 | /** 43 | * Represents the LambdaControls client mod. 44 | * 45 | * @author LambdAurora 46 | * @version 1.7.0 47 | * @since 1.1.0 48 | */ 49 | public class LambdaControlsClient extends LambdaControls implements ClientModInitializer { 50 | private static LambdaControlsClient INSTANCE; 51 | public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_up"), 52 | InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement"); 53 | public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_right"), 54 | InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement"); 55 | public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_down"), 56 | InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement"); 57 | public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_left"), 58 | InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement"); 59 | /*public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "ring"), 60 | InputUtil.Type.MOUSE, GLFW.GLFW_MOUSE_BUTTON_5, "key.categories.misc");*/ 61 | public static final Identifier CONTROLLER_BUTTONS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png"); 62 | public static final Identifier CONTROLLER_AXIS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_axis.png"); 63 | public static final Identifier CURSOR_TEXTURE = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/cursor.png"); 64 | public final static File MAPPINGS_FILE = new File("config/gamecontrollerdb.txt"); 65 | public final LambdaControlsConfig config = new LambdaControlsConfig(this); 66 | public final LambdaInput input = new LambdaInput(this); 67 | public final LambdaRing ring = new LambdaRing(this); 68 | public final LambdaReacharound reacharound = new LambdaReacharound(); 69 | private LambdaControlsHud hud; 70 | private ControlsMode previousControlsMode; 71 | 72 | @Override 73 | public void onInitializeClient() { 74 | INSTANCE = this; 75 | KeyBindingHelper.registerKeyBinding(BINDING_LOOK_UP); 76 | KeyBindingHelper.registerKeyBinding(BINDING_LOOK_RIGHT); 77 | KeyBindingHelper.registerKeyBinding(BINDING_LOOK_DOWN); 78 | KeyBindingHelper.registerKeyBinding(BINDING_LOOK_LEFT); 79 | //KeyBindingHelper.registerKeyBinding(BINDING_RING); 80 | 81 | this.ring.registerAction("keybinding", KeyBindingRingAction.FACTORY); 82 | 83 | ClientPlayNetworking.registerGlobalReceiver(CONTROLS_MODE_CHANNEL, (client, handler, buf, responseSender) -> { 84 | responseSender.sendPacket(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode())); 85 | }); 86 | ClientPlayNetworking.registerGlobalReceiver(FEATURE_CHANNEL, (client, handler, buf, responseSender) -> { 87 | int features = buf.readVarInt(); 88 | for (int i = 0; i < features; i++) { 89 | var name = buf.readString(64); 90 | boolean allowed = buf.readBoolean(); 91 | LambdaControlsFeature.fromName(name).ifPresent(feature -> client.execute(() -> feature.setAllowed(allowed))); 92 | } 93 | }); 94 | ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { 95 | sender.sendPacket(HELLO_CHANNEL, this.makeHello(this.config.getControlsMode())); 96 | sender.sendPacket(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode())); 97 | }); 98 | ClientPlayConnectionEvents.DISCONNECT.register(this::onLeave); 99 | 100 | ClientTickEvents.START_CLIENT_TICK.register(this.reacharound::tick); 101 | ClientTickEvents.END_CLIENT_TICK.register(this::onTick); 102 | 103 | /*OpenScreenCallback.EVENT.register((client, screen) -> { 104 | if (screen == null && this.config.getControlsMode() == ControlsMode.TOUCHSCREEN) { 105 | screen = new TouchscreenOverlay(this); 106 | screen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); 107 | client.skipGameRender = false; 108 | client.currentScreen = screen; 109 | } else if (screen != null) { 110 | this.input.onScreenOpen(client, client.getWindow().getWidth(), client.getWindow().getHeight()); 111 | } 112 | });*/ 113 | 114 | HudManager.register(this.hud = new LambdaControlsHud(this)); 115 | } 116 | 117 | /** 118 | * This method is called when Minecraft is initializing. 119 | */ 120 | public void onMcInit(@NotNull MinecraftClient client) { 121 | ButtonBinding.init(client.options); 122 | this.config.load(); 123 | this.hud.setVisible(this.config.isHudEnabled()); 124 | Controller.updateMappings(); 125 | GLFW.glfwSetJoystickCallback((jid, event) -> { 126 | if (event == GLFW.GLFW_CONNECTED) { 127 | var controller = Controller.byId(jid); 128 | client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.connected", jid), 129 | new LiteralText(controller.getName()))); 130 | } else if (event == GLFW.GLFW_DISCONNECTED) { 131 | client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.disconnected", jid), 132 | null)); 133 | } 134 | 135 | this.switchControlsMode(); 136 | }); 137 | 138 | LambdaControlsCompat.init(this); 139 | } 140 | 141 | /** 142 | * This method is called every Minecraft tick. 143 | * 144 | * @param client the client instance 145 | */ 146 | public void onTick(@NotNull MinecraftClient client) { 147 | this.input.tick(client); 148 | if (this.config.getControlsMode() == ControlsMode.CONTROLLER && (client.isWindowFocused() || this.config.hasUnfocusedInput())) 149 | this.input.tickController(client); 150 | 151 | /*if (BINDING_RING.wasPressed()) { 152 | client.openScreen(new RingScreen()); 153 | }*/ 154 | } 155 | 156 | public void onRender(MinecraftClient client) { 157 | this.input.onRender(client.getTickDelta(), client); 158 | } 159 | 160 | /** 161 | * Called when leaving a server. 162 | */ 163 | public void onLeave(ClientPlayNetworkHandler handler, MinecraftClient client) { 164 | LambdaControlsFeature.resetAllAllowed(); 165 | } 166 | 167 | /** 168 | * Switches the controls mode if the auto switch is enabled. 169 | */ 170 | public void switchControlsMode() { 171 | if (this.config.hasAutoSwitchMode()) { 172 | if (this.config.getController().isGamepad()) { 173 | this.previousControlsMode = this.config.getControlsMode(); 174 | this.config.setControlsMode(ControlsMode.CONTROLLER); 175 | } else { 176 | if (this.previousControlsMode == null) { 177 | this.previousControlsMode = ControlsMode.DEFAULT; 178 | } 179 | 180 | this.config.setControlsMode(this.previousControlsMode); 181 | } 182 | } 183 | } 184 | 185 | /** 186 | * Sets whether the HUD is enabled or not. 187 | * 188 | * @param enabled true if the HUD is enabled, else false 189 | */ 190 | public void setHudEnabled(boolean enabled) { 191 | this.config.setHudEnabled(enabled); 192 | this.hud.setVisible(enabled); 193 | } 194 | 195 | /** 196 | * Gets the LambdaControls client instance. 197 | * 198 | * @return the LambdaControls client instance 199 | */ 200 | public static LambdaControlsClient get() { 201 | return INSTANCE; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/LambdaControlsModMenu.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client; 11 | 12 | import com.terraformersmc.modmenu.api.ConfigScreenFactory; 13 | import com.terraformersmc.modmenu.api.ModMenuApi; 14 | import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen; 15 | 16 | /** 17 | * Represents the API implementation of ModMenu for LambdaControls. 18 | * 19 | * @author LambdAurora 20 | * @version 1.7.0 21 | * @since 1.1.0 22 | */ 23 | public class LambdaControlsModMenu implements ModMenuApi { 24 | @Override 25 | public ConfigScreenFactory getModConfigScreenFactory() { 26 | return parent -> new LambdaControlsSettingsScreen(parent, false); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/LambdaReacharound.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client; 11 | 12 | import dev.lambdaurora.lambdacontrols.LambdaControlsFeature; 13 | import net.minecraft.block.Block; 14 | import net.minecraft.block.BlockState; 15 | import net.minecraft.block.FluidBlock; 16 | import net.minecraft.block.SlabBlock; 17 | import net.minecraft.client.MinecraftClient; 18 | import net.minecraft.item.BlockItem; 19 | import net.minecraft.item.ItemStack; 20 | import net.minecraft.util.hit.BlockHitResult; 21 | import net.minecraft.util.hit.HitResult; 22 | import net.minecraft.util.math.BlockPos; 23 | import net.minecraft.util.math.Direction; 24 | import net.minecraft.util.math.MathHelper; 25 | import net.minecraft.util.math.Vec3d; 26 | import net.minecraft.world.RaycastContext; 27 | import org.jetbrains.annotations.NotNull; 28 | import org.jetbrains.annotations.Nullable; 29 | 30 | /** 31 | * Represents the reach-around API of LambdaControls. 32 | * 33 | * @version 1.7.0 34 | * @since 1.3.2 35 | */ 36 | public class LambdaReacharound { 37 | private BlockHitResult lastReacharoundResult = null; 38 | private boolean lastReacharoundVertical = false; 39 | private boolean onSlab = false; 40 | 41 | public void tick(@NotNull MinecraftClient client) { 42 | this.lastReacharoundResult = this.tryVerticalReachAround(client); 43 | if (this.lastReacharoundResult == null) { 44 | this.lastReacharoundResult = this.tryHorizontalReachAround(client); 45 | this.lastReacharoundVertical = false; 46 | } else this.lastReacharoundVertical = true; 47 | } 48 | 49 | /** 50 | * Returns the last reach around result. 51 | * 52 | * @return the last reach around result 53 | */ 54 | public @Nullable BlockHitResult getLastReacharoundResult() { 55 | return this.lastReacharoundResult; 56 | } 57 | 58 | /** 59 | * Returns whether the last reach around is vertical. 60 | * 61 | * @return {@code true} if the reach around is vertical 62 | */ 63 | public boolean isLastReacharoundVertical() { 64 | return this.lastReacharoundVertical; 65 | } 66 | 67 | /** 68 | * Returns whether reacharound is available or not. 69 | * 70 | * @return {@code true} if reacharound is available, else {@code false} 71 | */ 72 | public boolean isReacharoundAvailable() { 73 | return LambdaControlsFeature.HORIZONTAL_REACHAROUND.isAvailable() || LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable(); 74 | } 75 | 76 | private float getPlayerRange(@NotNull MinecraftClient client) { 77 | return client.interactionManager != null ? client.interactionManager.getReachDistance() : 0.f; 78 | } 79 | 80 | /** 81 | * Returns a nullable block hit result if vertical reach-around is possible. 82 | * 83 | * @param client the client instance 84 | * @return a block hit result if vertical reach-around is possible, else {@code null} 85 | */ 86 | public @Nullable BlockHitResult tryVerticalReachAround(@NotNull MinecraftClient client) { 87 | if (!LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable()) 88 | return null; 89 | if (client.player == null || client.world == null || client.crosshairTarget == null || client.crosshairTarget.getType() != HitResult.Type.MISS 90 | || !client.player.isOnGround() || client.player.getPitch(0.f) < 80.0F 91 | || client.player.isRiding()) 92 | return null; 93 | 94 | Vec3d pos = client.player.getCameraPosVec(1.0F); 95 | Vec3d rotationVec = client.player.getRotationVec(1.0F); 96 | float range = getPlayerRange(client); 97 | var rayVec = pos.add(rotationVec.x * range, rotationVec.y * range, rotationVec.z * range).add(0, 0.75, 0); 98 | var result = client.world.raycast(new RaycastContext(pos, rayVec, RaycastContext.ShapeType.OUTLINE, RaycastContext.FluidHandling.NONE, client.player)); 99 | 100 | if (result.getType() == HitResult.Type.BLOCK) { 101 | BlockPos blockPos = result.getBlockPos().down(); 102 | BlockState state = client.world.getBlockState(blockPos); 103 | 104 | if (client.player.getBlockPos().getY() - blockPos.getY() > 1 && (client.world.isAir(blockPos) || state.getMaterial().isReplaceable())) { 105 | return new BlockHitResult(result.getPos(), Direction.DOWN, blockPos, false); 106 | } 107 | } 108 | 109 | return null; 110 | } 111 | 112 | /** 113 | * Returns a nullable block hit result if horizontal reach-around is possible. 114 | * 115 | * @param client the client instance 116 | * @return a block hit result if horizontal reach-around is possible 117 | */ 118 | public @Nullable BlockHitResult tryHorizontalReachAround(@NotNull MinecraftClient client) { 119 | if (!LambdaControlsFeature.HORIZONTAL_REACHAROUND.isAvailable()) 120 | return null; 121 | 122 | if (client.player != null && client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.MISS 123 | && client.player.isOnGround() && client.player.getPitch(0.f) > 35.f) { 124 | if (client.player.isRiding()) 125 | return null; 126 | var playerPos = client.player.getBlockPos().down(); 127 | if (client.player.getY() - playerPos.getY() - 1.0 >= 0.25) { 128 | playerPos = playerPos.up(); 129 | this.onSlab = true; 130 | } else { 131 | this.onSlab = false; 132 | } 133 | var targetPos = new BlockPos(client.crosshairTarget.getPos()).subtract(playerPos); 134 | var vector = new BlockPos.Mutable(MathHelper.clamp(targetPos.getX(), -1, 1), 0, MathHelper.clamp(targetPos.getZ(), -1, 1)); 135 | var blockPos = playerPos.add(vector); 136 | 137 | var direction = client.player.getHorizontalFacing(); 138 | 139 | var state = client.world.getBlockState(blockPos); 140 | if (!state.isAir()) 141 | return null; 142 | var adjacentBlockState = client.world.getBlockState(blockPos.offset(direction.getOpposite())); 143 | if (adjacentBlockState.isAir() || adjacentBlockState.getBlock() instanceof FluidBlock || (vector.getX() == 0 && vector.getZ() == 0)) { 144 | return null; 145 | } 146 | 147 | return new BlockHitResult(client.crosshairTarget.getPos(), direction, blockPos, false); 148 | } 149 | return null; 150 | } 151 | 152 | public @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @Nullable ItemStack stack) { 153 | if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem)) 154 | return result; 155 | return withSideForReacharound(result, Block.getBlockFromItem(stack.getItem())); 156 | } 157 | 158 | public @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @NotNull Block block) { 159 | if (block instanceof SlabBlock) { 160 | if (this.onSlab) result = result.withSide(Direction.UP); 161 | else result = result.withSide(Direction.DOWN); 162 | } 163 | return result; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/VirtualMouseSkin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client; 11 | 12 | import net.minecraft.text.Text; 13 | import net.minecraft.text.TranslatableText; 14 | import org.aperlambda.lambdacommon.utils.Nameable; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.Arrays; 18 | import java.util.Optional; 19 | 20 | /** 21 | * Represents the virtual mouse skins. 22 | * 23 | * @version 1.7.0 24 | * @since 1.2.0 25 | */ 26 | public enum VirtualMouseSkin implements Nameable { 27 | DEFAULT_LIGHT("default_light"), 28 | DEFAULT_DARK("default_dark"), 29 | SECOND_LIGHT("second_light"), 30 | SECOND_DARK("second_dark"); 31 | 32 | private final String name; 33 | private final Text text; 34 | 35 | VirtualMouseSkin(String name) { 36 | this.name = name; 37 | this.text = new TranslatableText(this.getTranslationKey()); 38 | } 39 | 40 | /** 41 | * Returns the next virtual mouse skin available. 42 | * 43 | * @return the next available virtual mouse skin 44 | */ 45 | public @NotNull VirtualMouseSkin next() { 46 | var v = values(); 47 | if (v.length == this.ordinal() + 1) 48 | return v[0]; 49 | return v[this.ordinal() + 1]; 50 | } 51 | 52 | /** 53 | * Returns the translation key of this virtual mouse skin. 54 | * 55 | * @return the virtual mouse skin's translation key 56 | */ 57 | public @NotNull String getTranslationKey() { 58 | return "lambdacontrols.virtual_mouse.skin." + this.getName(); 59 | } 60 | 61 | /** 62 | * Gets the translated text of this virtual mouse skin. 63 | * 64 | * @return the translated text of this virtual mouse skin 65 | */ 66 | public @NotNull Text getTranslatedText() { 67 | return this.text; 68 | } 69 | 70 | @Override 71 | public @NotNull String getName() { 72 | return this.name; 73 | } 74 | 75 | /** 76 | * Gets the virtual mouse skin from its identifier. 77 | * 78 | * @param id the identifier of the virtual mouse skin 79 | * @return the virtual mouse skin if found, else empty 80 | */ 81 | public static @NotNull Optional byId(@NotNull String id) { 82 | return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/CompatHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 13 | import net.minecraft.client.MinecraftClient; 14 | import net.minecraft.client.gui.screen.Screen; 15 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 16 | import net.minecraft.screen.slot.Slot; 17 | import net.minecraft.util.hit.BlockHitResult; 18 | import org.jetbrains.annotations.NotNull; 19 | import org.jetbrains.annotations.Nullable; 20 | 21 | /** 22 | * Represents a compatibility handler for a mod. 23 | * 24 | * @author LambdAurora 25 | * @version 1.7.0 26 | * @since 1.1.0 27 | */ 28 | public interface CompatHandler { 29 | /** 30 | * Handles compatibility of a mod. 31 | * 32 | * @param mod this mod instance 33 | */ 34 | void handle(@NotNull LambdaControlsClient mod); 35 | 36 | /** 37 | * Returns whether the mouse is required on the specified screen. 38 | * 39 | * @param screen the screen 40 | * @return true if the mouse is required on the specified screen, else false 41 | */ 42 | default boolean requireMouseOnScreen(Screen screen) { 43 | return false; 44 | } 45 | 46 | /** 47 | * Returns a slot at the specified location if possible. 48 | * 49 | * @param screen the screen 50 | * @param mouseX the mouse X-coordinate 51 | * @param mouseY the mouse Y-coordinate 52 | * @return a slot if present, else null 53 | * @since 1.5.0 54 | */ 55 | default @Nullable CompatHandler.SlotPos getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) { 56 | return null; 57 | } 58 | 59 | /** 60 | * Returns whether the current slot is a creative slot or not. 61 | * 62 | * @param screen the screen 63 | * @param slot the slot to check 64 | * @return true if the slot is a creative slot, else false 65 | */ 66 | default boolean isCreativeSlot(@NotNull HandledScreen screen, @NotNull Slot slot) { 67 | return false; 68 | } 69 | 70 | /** 71 | * Returns a custom translation key to make custom attack action strings on the HUD. 72 | * 73 | * @param client the client instance 74 | * @param placeResult the last place block result 75 | * @return null if untouched, else a translation key 76 | */ 77 | default String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) { 78 | return null; 79 | } 80 | 81 | /** 82 | * Returns a custom translation key to make custom use action strings on the HUD. 83 | * 84 | * @param client the client instance 85 | * @param placeResult the last place block result 86 | * @return null if untouched, else a translation key 87 | */ 88 | default String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) { 89 | return null; 90 | } 91 | 92 | /** 93 | * Handles the menu back button. 94 | * 95 | * @param client the client instance 96 | * @param screen the screen 97 | * @return true if the handle was fired and succeed, else false 98 | */ 99 | default boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) { 100 | return false; 101 | } 102 | 103 | record SlotPos(int x, int y) { 104 | public static final SlotPos INVALID_SLOT = new SlotPos(-1, -1); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/HQMCompat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 13 | import net.minecraft.client.gui.screen.Screen; 14 | import org.aperlambda.lambdacommon.utils.LambdaReflection; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.Optional; 18 | 19 | /** 20 | * Represents HQM compatibility handler. 21 | *

22 | * This is bad. 23 | * 24 | * @author LambdAurora 25 | * @version 1.3.2 26 | * @since 1.3.2 27 | */ 28 | public class HQMCompat implements CompatHandler { 29 | public static final String GUI_BASE_CLASS_PATH = "hardcorequesting.client.interfaces.GuiBase"; 30 | private Optional> guiBaseClass; 31 | 32 | @Override 33 | public void handle(@NotNull LambdaControlsClient mod) { 34 | this.guiBaseClass = LambdaReflection.getClass(GUI_BASE_CLASS_PATH); 35 | } 36 | 37 | @Override 38 | public boolean requireMouseOnScreen(Screen screen) { 39 | return this.guiBaseClass.map(clazz -> clazz.isInstance(screen)).orElse(false); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/LambdaControlsCompat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 13 | import dev.lambdaurora.lambdacontrols.client.controller.InputManager; 14 | import net.fabricmc.loader.api.FabricLoader; 15 | import net.minecraft.client.MinecraftClient; 16 | import net.minecraft.client.gui.screen.Screen; 17 | import net.minecraft.util.hit.BlockHitResult; 18 | import org.aperlambda.lambdacommon.utils.LambdaReflection; 19 | import org.jetbrains.annotations.NotNull; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.stream.Stream; 25 | 26 | /** 27 | * Represents a compatibility handler. 28 | * 29 | * @author LambdAurora 30 | * @version 1.5.0 31 | * @since 1.1.0 32 | */ 33 | public class LambdaControlsCompat { 34 | private static final List HANDLERS = new ArrayList<>(); 35 | 36 | /** 37 | * Initializes compatibility with other mods if needed. 38 | * 39 | * @param mod the mod instance 40 | */ 41 | public static void init(@NotNull LambdaControlsClient mod) { 42 | if (FabricLoader.getInstance().isModLoaded("okzoomer")) { 43 | mod.log("Adding okzoomer compatibility..."); 44 | HANDLERS.add(new OkZoomerCompat()); 45 | } 46 | /*if (isReiPresent()) { 47 | mod.log("Adding REI compatiblity..."); 48 | HANDLERS.add(new ReiCompat()); 49 | }*/ 50 | if (FabricLoader.getInstance().isModLoaded("hardcorequesting") && LambdaReflection.doesClassExist(HQMCompat.GUI_BASE_CLASS_PATH)) { 51 | mod.log("Adding HQM compatibility..."); 52 | HANDLERS.add(new HQMCompat()); 53 | } 54 | HANDLERS.forEach(handler -> handler.handle(mod)); 55 | InputManager.loadButtonBindings(mod.config); 56 | } 57 | 58 | /** 59 | * Registers a new compatibility handler. 60 | * 61 | * @param handler the compatibility handler to register 62 | */ 63 | public static void registerCompatHandler(@NotNull CompatHandler handler) { 64 | HANDLERS.add(handler); 65 | } 66 | 67 | /** 68 | * Streams through compatibility handlers. 69 | * 70 | * @return a stream of compatibility handlers 71 | */ 72 | public static Stream streamCompatHandlers() { 73 | return HANDLERS.stream(); 74 | } 75 | 76 | /** 77 | * Returns whether the mouse is required on the specified screen. 78 | * 79 | * @param screen the screen 80 | * @return true if the mouse is requried on the specified screen, else false 81 | */ 82 | public static boolean requireMouseOnScreen(Screen screen) { 83 | return HANDLERS.stream().anyMatch(handler -> handler.requireMouseOnScreen(screen)); 84 | } 85 | 86 | /** 87 | * Returns a slot at the specified location if possible. 88 | * 89 | * @param screen the screen 90 | * @param mouseX the mouse X-coordinate 91 | * @param mouseY the mouse Y-coordinate 92 | * @return a slot if present, else null 93 | */ 94 | public static @Nullable CompatHandler.SlotPos getSlotAt(@NotNull Screen screen, int mouseX, int mouseY) { 95 | for (var handler : HANDLERS) { 96 | var slot = handler.getSlotAt(screen, mouseX, mouseY); 97 | if (slot != null) 98 | return slot; 99 | } 100 | return null; 101 | } 102 | 103 | /** 104 | * Returns a custom translation key to make custom attack action strings on the HUD. 105 | * 106 | * @param client the client instance 107 | * @param placeResult the last place block result 108 | * @return null if untouched, else a translation key 109 | */ 110 | public static String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) { 111 | for (CompatHandler handler : HANDLERS) { 112 | String action = handler.getAttackActionAt(client, placeResult); 113 | if (action != null) { 114 | return action; 115 | } 116 | } 117 | return null; 118 | } 119 | 120 | /** 121 | * Returns a custom translation key to make custom use action strings on the HUD. 122 | * 123 | * @param client the client instance 124 | * @param placeResult the last place block result 125 | * @return null if untouched, else a translation key 126 | */ 127 | public static String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) { 128 | for (CompatHandler handler : HANDLERS) { 129 | String action = handler.getUseActionAt(client, placeResult); 130 | if (action != null) { 131 | return action; 132 | } 133 | } 134 | return null; 135 | } 136 | 137 | /** 138 | * Handles the menu back button. 139 | * 140 | * @param client the client instance 141 | * @param screen the screen 142 | * @return true if the handle was fired and succeed, else false 143 | */ 144 | public static boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) { 145 | for (CompatHandler handler : HANDLERS) { 146 | if (handler.handleMenuBack(client, screen)) 147 | return true; 148 | } 149 | return false; 150 | } 151 | 152 | /** 153 | * Returns whether Roughly Enough Items is present. 154 | * 155 | * @return true if Roughly Enough Items is present, else false 156 | */ 157 | public static boolean isReiPresent() { 158 | return FabricLoader.getInstance().isModLoaded("roughlyenoughitems"); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/LambdaControlsMixinPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat; 11 | 12 | import org.jetbrains.annotations.NotNull; 13 | import org.objectweb.asm.tree.ClassNode; 14 | import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; 15 | import org.spongepowered.asm.mixin.extensibility.IMixinInfo; 16 | 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Set; 20 | 21 | /** 22 | * This plugin is only present for the conditional mixins. 23 | * 24 | * @author LambdAurora 25 | * @version 1.5.0 26 | * @since 1.2.0 27 | */ 28 | public class LambdaControlsMixinPlugin implements IMixinConfigPlugin { 29 | private final HashMap conditionalMixins = new HashMap<>(); 30 | 31 | public LambdaControlsMixinPlugin() { 32 | this.putConditionalMixin("EntryListWidgetAccessor", LambdaControlsCompat.isReiPresent()); 33 | this.putConditionalMixin("EntryWidgetAccessor", LambdaControlsCompat.isReiPresent()); 34 | this.putConditionalMixin("RecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent()); 35 | this.putConditionalMixin("VillagerRecipeViewingScreenAccessor", LambdaControlsCompat.isReiPresent()); 36 | } 37 | 38 | private void putConditionalMixin(@NotNull String path, boolean condition) { 39 | this.conditionalMixins.put("me.lambdaurora.lambdacontrols.client.compat.mixin." + path, condition); 40 | } 41 | 42 | @Override 43 | public void onLoad(String mixinPackage) { 44 | } 45 | 46 | @Override 47 | public String getRefMapperConfig() { 48 | return null; 49 | } 50 | 51 | @Override 52 | public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { 53 | return this.conditionalMixins.getOrDefault(mixinClassName, Boolean.TRUE); 54 | } 55 | 56 | @Override 57 | public void acceptTargets(Set myTargets, Set otherTargets) { 58 | } 59 | 60 | @Override 61 | public List getMixins() { 62 | return null; 63 | } 64 | 65 | @Override 66 | public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { 67 | } 68 | 69 | @Override 70 | public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/OkZoomerCompat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 13 | import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding; 14 | import io.github.ennuil.okzoomer.keybinds.ZoomKeybinds; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.lwjgl.glfw.GLFW; 17 | 18 | /** 19 | * Represents a compatibility handler for OkZoomer. 20 | * 21 | * @author LambdAurora 22 | * @version 1.4.3 23 | * @since 1.1.0 24 | */ 25 | public class OkZoomerCompat implements CompatHandler { 26 | @Override 27 | public void handle(@NotNull LambdaControlsClient mod) { 28 | new ButtonBinding.Builder("zoom") 29 | .buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW.GLFW_GAMEPAD_BUTTON_X) 30 | .onlyInGame() 31 | .cooldown(true) 32 | .category(ButtonBinding.MISC_CATEGORY) 33 | .linkKeybind(ZoomKeybinds.zoomKey) 34 | .register(); 35 | 36 | if (ZoomKeybinds.areExtraKeybindsEnabled()) { 37 | new ButtonBinding.Builder("zoom_in") 38 | .buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true)) 39 | .onlyInGame() 40 | .cooldown(true) 41 | .category(ButtonBinding.MISC_CATEGORY) 42 | .linkKeybind(ZoomKeybinds.increaseZoomKey) 43 | .register(); 44 | new ButtonBinding.Builder("zoom_out") 45 | .buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true)) 46 | .onlyInGame() 47 | .cooldown(true) 48 | .category(ButtonBinding.MISC_CATEGORY) 49 | .linkKeybind(ZoomKeybinds.decreaseZoomKey) 50 | .register(); 51 | new ButtonBinding.Builder("zoom_reset") 52 | .onlyInGame() 53 | .cooldown(true) 54 | .category(ButtonBinding.MISC_CATEGORY) 55 | .linkKeybind(ZoomKeybinds.resetZoomKey) 56 | .register(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/mixin/EntryListWidgetAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat.mixin; 11 | 12 | /** 13 | * Represents an accessor to REI's EntryListWidget. 14 | * 15 | * @author LambdAurora 16 | * @version 1.5.0 17 | * @since 1.5.0 18 | */ 19 | //@Mixin(value = EntryListWidget.class, remap = false) 20 | public interface EntryListWidgetAccessor { 21 | /*@Accessor(value = "entries") 22 | List getEntries();*/ 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/mixin/EntryWidgetAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat.mixin; 11 | 12 | /** 13 | * Represents an accessor to REI's EntryWidget. 14 | * 15 | * @author LambdAurora 16 | * @version 1.5.0 17 | * @since 1.5.0 18 | */ 19 | //@Mixin(value = EntryWidget.class, remap = false) 20 | public interface EntryWidgetAccessor { 21 | /*@Invoker("getCurrentEntry") 22 | EntryStack lambdacontrols_getCurrentEntry();*/ 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/mixin/RecipeViewingScreenAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat.mixin; 11 | 12 | /** 13 | * Represents an accessor to REI's RecipeViewingScreen. 14 | * 15 | * @author LambdAurora 16 | * @version 1.7.0 17 | * @since 1.2.0 18 | */ 19 | //@Mixin(value = DefaultDisplayViewingScreen.class, remap = false) 20 | public interface RecipeViewingScreenAccessor { 21 | /*@Accessor("categoryBack") 22 | Button getCategoryBack(); 23 | 24 | @Accessor("categoryNext") 25 | Button getCategoryNext(); 26 | 27 | @Accessor("recipeBack") 28 | Button getRecipeBack(); 29 | 30 | @Accessor("recipeNext") 31 | Button getRecipeNext();*/ 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/compat/mixin/VillagerRecipeViewingScreenAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.compat.mixin; 11 | 12 | /** 13 | * Represents an accessor to REI's VillagerRecipeViewingScreen. 14 | * 15 | * @author LambdAurora 16 | * @version 1.7.0 17 | * @since 1.2.0 18 | */ 19 | //@Mixin(CompositeDisplayViewingScreen.class) 20 | public interface VillagerRecipeViewingScreenAccessor { 21 | /*@Accessor(value = "categoryMap", remap = false) 22 | Map, List> getCategoryMap(); 23 | 24 | @Accessor(value = "categories", remap = false) 25 | List> getCategories(); 26 | 27 | @Accessor(value = "selectedCategoryIndex", remap = false) 28 | int getSelectedCategoryIndex(); 29 | 30 | @Accessor(value = "selectedCategoryIndex", remap = false) 31 | void setSelectedCategoryIndex(int selectedCategoryIndex); 32 | 33 | @Accessor(value = "selectedRecipeIndex", remap = false) 34 | int getSelectedRecipeIndex(); 35 | 36 | @Accessor(value = "selectedRecipeIndex", remap = false) 37 | void setSelectedRecipeIndex(int selectedRecipeIndex); 38 | 39 | @Accessor(value = "scrolling", remap = false) 40 | ScrollingContainer getScrolling(); 41 | 42 | @Invoker("init") 43 | void lambdacontrols_init();*/ 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/controller/ButtonCategory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.controller; 11 | 12 | import net.minecraft.client.resource.language.I18n; 13 | import org.aperlambda.lambdacommon.Identifier; 14 | import org.aperlambda.lambdacommon.utils.Identifiable; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import java.util.Collections; 20 | import java.util.List; 21 | 22 | /** 23 | * Represents a button binding category 24 | * 25 | * @author LambdAurora 26 | * @version 1.1.0 27 | * @since 1.1.0 28 | */ 29 | public class ButtonCategory implements Identifiable { 30 | private final List bindings = new ArrayList<>(); 31 | private final Identifier id; 32 | private final int priority; 33 | 34 | public ButtonCategory(@NotNull Identifier id, int priority) { 35 | this.id = id; 36 | this.priority = priority; 37 | } 38 | 39 | public ButtonCategory(@NotNull Identifier id) { 40 | this(id, 100); 41 | } 42 | 43 | public void registerBinding(@NotNull ButtonBinding binding) { 44 | if (this.bindings.contains(binding)) 45 | throw new IllegalStateException("Cannot register twice a button binding in the same category."); 46 | this.bindings.add(binding); 47 | } 48 | 49 | public void registerAllBindings(@NotNull ButtonBinding... bindings) { 50 | this.registerAllBindings(Arrays.asList(bindings)); 51 | } 52 | 53 | public void registerAllBindings(@NotNull List bindings) { 54 | bindings.forEach(this::registerBinding); 55 | } 56 | 57 | /** 58 | * Gets the bindings assigned to this category. 59 | * 60 | * @return the bindings assigned to this category 61 | */ 62 | public @NotNull List getBindings() { 63 | return Collections.unmodifiableList(this.bindings); 64 | } 65 | 66 | /** 67 | * Gets the translated name of this category. 68 | *

69 | * The translation key should be `modid.identifier_name`. 70 | * 71 | * @return the translated name 72 | */ 73 | public @NotNull String getTranslatedName() { 74 | if (this.id.getNamespace().equals("minecraft")) 75 | return I18n.translate(this.id.getName()); 76 | else 77 | return I18n.translate(this.id.getNamespace() + "." + this.id.getName()); 78 | } 79 | 80 | /** 81 | * Gets the priority display of this category. 82 | * It will defines in which order the categories will display on the controls screen. 83 | * 84 | * @return the priority of this category 85 | */ 86 | public int getPriority() { 87 | return this.priority; 88 | } 89 | 90 | @Override 91 | public @NotNull Identifier getIdentifier() { 92 | return this.id; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/controller/Controller.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.controller; 11 | 12 | import dev.lambdaurora.lambdacontrols.LambdaControls; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import net.minecraft.client.MinecraftClient; 15 | import net.minecraft.client.toast.SystemToast; 16 | import net.minecraft.text.LiteralText; 17 | import net.minecraft.text.TranslatableText; 18 | import org.aperlambda.lambdacommon.utils.Nameable; 19 | import org.jetbrains.annotations.NotNull; 20 | import org.lwjgl.glfw.GLFW; 21 | import org.lwjgl.glfw.GLFWGamepadState; 22 | import org.lwjgl.system.MemoryStack; 23 | import org.lwjgl.system.MemoryUtil; 24 | 25 | import java.io.IOException; 26 | import java.nio.ByteBuffer; 27 | import java.nio.file.Files; 28 | import java.nio.file.Paths; 29 | import java.util.Comparator; 30 | import java.util.HashMap; 31 | import java.util.Map; 32 | import java.util.Optional; 33 | 34 | import static org.lwjgl.BufferUtils.createByteBuffer; 35 | 36 | /** 37 | * Represents a controller. 38 | * 39 | * @author LambdAurora 40 | * @version 1.7.0 41 | * @since 1.0.0 42 | */ 43 | public record Controller(int id) implements Nameable { 44 | private static final Map CONTROLLERS = new HashMap<>(); 45 | 46 | /** 47 | * Gets the controller's globally unique identifier. 48 | * 49 | * @return the controller's GUID 50 | */ 51 | public String getGuid() { 52 | String guid = GLFW.glfwGetJoystickGUID(this.id); 53 | return guid == null ? "" : guid; 54 | } 55 | 56 | /** 57 | * Returns whether this controller is connected or not. 58 | * 59 | * @return true if this controller is connected, else false 60 | */ 61 | public boolean isConnected() { 62 | return GLFW.glfwJoystickPresent(this.id); 63 | } 64 | 65 | /** 66 | * Returns whether this controller is a gamepad or not. 67 | * 68 | * @return true if this controller is a gamepad, else false 69 | */ 70 | public boolean isGamepad() { 71 | return this.isConnected() && GLFW.glfwJoystickIsGamepad(this.id); 72 | } 73 | 74 | /** 75 | * Gets the name of the controller. 76 | * 77 | * @return the controller's name 78 | */ 79 | @Override 80 | public String getName() { 81 | var name = this.isGamepad() ? GLFW.glfwGetGamepadName(this.id) : GLFW.glfwGetJoystickName(this.id); 82 | return name == null ? String.valueOf(this.id()) : name; 83 | } 84 | 85 | /** 86 | * Gets the state of the controller. 87 | * 88 | * @return the state of the controller input 89 | */ 90 | public GLFWGamepadState getState() { 91 | var state = GLFWGamepadState.create(); 92 | if (this.isGamepad()) 93 | GLFW.glfwGetGamepadState(this.id, state); 94 | return state; 95 | } 96 | 97 | public static Controller byId(int id) { 98 | if (id > GLFW.GLFW_JOYSTICK_LAST) { 99 | LambdaControlsClient.get().log("Controller '" + id + "' doesn't exist."); 100 | id = GLFW.GLFW_JOYSTICK_LAST; 101 | } 102 | Controller controller; 103 | if (CONTROLLERS.containsKey(id)) 104 | return CONTROLLERS.get(id); 105 | else { 106 | controller = new Controller(id); 107 | CONTROLLERS.put(id, controller); 108 | return controller; 109 | } 110 | } 111 | 112 | public static Optional byGuid(@NotNull String guid) { 113 | return CONTROLLERS.values().stream().filter(Controller::isConnected) 114 | .filter(controller -> controller.getGuid().equals(guid)) 115 | .max(Comparator.comparingInt(Controller::id)); 116 | } 117 | 118 | /** 119 | * Reads the specified resource and returns the raw data as a ByteBuffer. 120 | * 121 | * @param resource the resource to read 122 | * @param bufferSize the initial buffer size 123 | * @return the resource data 124 | * @throws IOException If an IO error occurs. 125 | */ 126 | private static ByteBuffer ioResourceToBuffer(String resource, int bufferSize) throws IOException { 127 | ByteBuffer buffer = null; 128 | 129 | var path = Paths.get(resource); 130 | if (Files.isReadable(path)) { 131 | try (var fc = Files.newByteChannel(path)) { 132 | buffer = createByteBuffer((int) fc.size() + 2); 133 | while (fc.read(buffer) != -1) ; 134 | buffer.put((byte) 0); 135 | } 136 | } 137 | 138 | buffer.flip(); // Force Java 8 >.< 139 | return buffer; 140 | } 141 | 142 | /** 143 | * Updates the controller mappings. 144 | */ 145 | public static void updateMappings() { 146 | try { 147 | if (!LambdaControlsClient.MAPPINGS_FILE.exists()) 148 | return; 149 | LambdaControlsClient.get().log("Updating controller mappings..."); 150 | var buffer = ioResourceToBuffer(LambdaControlsClient.MAPPINGS_FILE.getPath(), 1024); 151 | GLFW.glfwUpdateGamepadMappings(buffer); 152 | } catch (IOException e) { 153 | e.printStackTrace(); 154 | } 155 | 156 | try (var memoryStack = MemoryStack.stackPush()) { 157 | var pointerBuffer = memoryStack.mallocPointer(1); 158 | int i = GLFW.glfwGetError(pointerBuffer); 159 | if (i != 0) { 160 | long l = pointerBuffer.get(); 161 | var string = l == 0L ? "" : MemoryUtil.memUTF8(l); 162 | var client = MinecraftClient.getInstance(); 163 | if (client != null) { 164 | client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT, 165 | new TranslatableText("lambdacontrols.controller.mappings.error"), new LiteralText(string))); 166 | } 167 | } 168 | } catch (Throwable e) { 169 | /* Ignored :concern: */ 170 | } 171 | 172 | if (LambdaControlsClient.get().config.hasDebug()) { 173 | for (int i = GLFW.GLFW_JOYSTICK_1; i <= GLFW.GLFW_JOYSTICK_16; i++) { 174 | var controller = byId(i); 175 | 176 | if (!controller.isConnected()) 177 | continue; 178 | 179 | LambdaControls.get().log(String.format("Controller #%d name: \"%s\"\n GUID: %s\n Gamepad: %s", 180 | controller.id, 181 | controller.getName(), 182 | controller.getGuid(), 183 | controller.isGamepad())); 184 | } 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/controller/MovementHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.controller; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.ButtonState; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import net.minecraft.client.MinecraftClient; 15 | import net.minecraft.client.network.ClientPlayerEntity; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | /** 19 | * Represents the movement handler. 20 | * 21 | * @author LambdAurora 22 | * @version 1.6.0 23 | * @since 1.4.0 24 | */ 25 | public final class MovementHandler implements PressAction { 26 | public static final MovementHandler HANDLER = new MovementHandler(); 27 | private boolean shouldOverrideMovement = false; 28 | private boolean pressingForward = false; 29 | private boolean pressingBack = false; 30 | private boolean pressingLeft = false; 31 | private boolean pressingRight = false; 32 | private float movementForward = 0.f; 33 | private float movementSideways = 0.f; 34 | 35 | private MovementHandler() { 36 | } 37 | 38 | /** 39 | * Applies movement input of this handler to the player's input. 40 | * 41 | * @param player The client player. 42 | */ 43 | public void applyMovement(@NotNull ClientPlayerEntity player) { 44 | if (!this.shouldOverrideMovement) 45 | return; 46 | player.input.pressingForward = this.pressingForward; 47 | player.input.pressingBack = this.pressingBack; 48 | player.input.pressingLeft = this.pressingLeft; 49 | player.input.pressingRight = this.pressingRight; 50 | player.input.movementForward = this.movementForward; 51 | player.input.movementSideways = this.movementSideways; 52 | this.shouldOverrideMovement = false; 53 | } 54 | 55 | @Override 56 | public boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action) { 57 | if (client.currentScreen != null || client.player == null) 58 | return this.shouldOverrideMovement = false; 59 | 60 | int direction = 0; 61 | if (button == ButtonBinding.FORWARD || button == ButtonBinding.LEFT) 62 | direction = 1; 63 | else if (button == ButtonBinding.BACK || button == ButtonBinding.RIGHT) 64 | direction = -1; 65 | 66 | if (action.isUnpressed()) 67 | direction = 0; 68 | 69 | this.shouldOverrideMovement = direction != 0; 70 | 71 | if (LambdaControlsClient.get().config.hasAnalogMovement()) { 72 | value = (float) Math.pow(value, 2); 73 | } else value = 1.f; 74 | 75 | if (button == ButtonBinding.FORWARD || button == ButtonBinding.BACK) { 76 | // Handle forward movement. 77 | this.pressingForward = direction > 0; 78 | this.pressingBack = direction < 0; 79 | this.movementForward = direction * value; 80 | 81 | // Slowing down if sneaking. 82 | if (client.player.input.sneaking) 83 | this.movementForward *= 0.3D; 84 | } else { 85 | // Handle sideways movement. 86 | this.pressingLeft = direction > 0; 87 | this.pressingRight = direction < 0; 88 | this.movementSideways = direction * value; 89 | 90 | // Slowing down if sneaking. 91 | if (client.player.input.sneaking) 92 | this.movementSideways *= 0.3D; 93 | } 94 | 95 | return this.shouldOverrideMovement; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/controller/PressAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.controller; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.ButtonState; 13 | import dev.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; 14 | import net.minecraft.client.MinecraftClient; 15 | import net.minecraft.client.option.StickyKeyBinding; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | /** 19 | * Represents a press action callback. 20 | * 21 | * @author LambdAurora 22 | * @version 1.7.0 23 | * @since 1.0.0 24 | */ 25 | @FunctionalInterface 26 | public interface PressAction { 27 | PressAction DEFAULT_ACTION = (client, button, value, action) -> { 28 | if (action == ButtonState.REPEAT || client.currentScreen != null) 29 | return false; 30 | button.asKeyBinding().ifPresent(binding -> { 31 | if (binding instanceof StickyKeyBinding) 32 | binding.setPressed(button.pressed); 33 | else 34 | ((KeyBindingAccessor) binding).lambdacontrols$handlePressState(button.isButtonDown()); 35 | }); 36 | return true; 37 | }; 38 | 39 | /** 40 | * Handles when there is a press action. 41 | * 42 | * @param client the client instance 43 | * @param action the action done 44 | */ 45 | boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action); 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/gui/MappingsStringInputWidget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.gui; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 13 | import dev.lambdaurora.lambdacontrols.client.controller.Controller; 14 | import dev.lambdaurora.spruceui.Position; 15 | import dev.lambdaurora.spruceui.option.SpruceOption; 16 | import dev.lambdaurora.spruceui.widget.container.SpruceContainerWidget; 17 | import dev.lambdaurora.spruceui.widget.text.SpruceTextAreaWidget; 18 | import net.minecraft.client.toast.SystemToast; 19 | import net.minecraft.text.LiteralText; 20 | import net.minecraft.text.TranslatableText; 21 | 22 | import java.io.FileWriter; 23 | import java.io.IOException; 24 | import java.nio.file.Files; 25 | 26 | /** 27 | * Represents the controller mappings file editor screen. 28 | * 29 | * @author LambdAurora 30 | * @version 1.7.0 31 | * @since 1.4.3 32 | */ 33 | public class MappingsStringInputWidget extends SpruceContainerWidget { 34 | private final SpruceOption reloadMappingsOption; 35 | private String mappings; 36 | private SpruceTextAreaWidget textArea; 37 | 38 | protected MappingsStringInputWidget(Position position, int width, int height) { 39 | super(position, width, height); 40 | //super(new TranslatableText("lambdacontrols.menu.title.mappings.string")); 41 | 42 | this.reloadMappingsOption = ReloadControllerMappingsOption.newOption(btn -> { 43 | this.writeMappings(); 44 | }); 45 | 46 | this.init(); 47 | } 48 | 49 | public void removed() { 50 | this.writeMappings(); 51 | Controller.updateMappings(); 52 | } 53 | 54 | public void onClose() { 55 | this.removed(); 56 | } 57 | 58 | public void writeMappings() { 59 | if (this.textArea != null) { 60 | this.mappings = this.textArea.getText(); 61 | try { 62 | var fw = new FileWriter(LambdaControlsClient.MAPPINGS_FILE, false); 63 | fw.write(this.mappings); 64 | fw.close(); 65 | } catch (IOException e) { 66 | if (this.client != null) 67 | this.client.getToastManager().add(SystemToast.create(this.client, SystemToast.Type.TUTORIAL_HINT, 68 | new TranslatableText("lambdacontrols.controller.mappings.error.write"), LiteralText.EMPTY)); 69 | e.printStackTrace(); 70 | } 71 | } 72 | } 73 | 74 | protected void init() { 75 | if (this.textArea != null) { 76 | this.mappings = this.textArea.getText(); 77 | } 78 | 79 | var mappings = ""; 80 | 81 | if (this.mappings != null) 82 | mappings = this.mappings; 83 | else if (LambdaControlsClient.MAPPINGS_FILE.exists()) { 84 | try { 85 | mappings = String.join("\n", Files.readAllLines(LambdaControlsClient.MAPPINGS_FILE.toPath())); 86 | this.mappings = mappings; 87 | } catch (IOException e) { 88 | /* Ignored */ 89 | } 90 | } 91 | 92 | int textFieldWidth = (int) (this.width * (5.0 / 6.0)); 93 | this.textArea = new SpruceTextAreaWidget(Position.of(this, this.width / 2 - textFieldWidth / 2, 0), textFieldWidth, this.height - 50, new LiteralText(mappings)); 94 | this.textArea.setText(mappings); 95 | // Display as many lines as possible 96 | this.textArea.setDisplayedLines(this.textArea.getInnerHeight() / this.client.textRenderer.fontHeight); 97 | this.addChild(this.textArea); 98 | 99 | this.addChild(this.reloadMappingsOption.createWidget(Position.of(this.width / 2 - 155, this.height - 29), 310)); 100 | } 101 | 102 | /*public void renderTitle(MatrixStack matrices, int mouseX, int mouseY, float delta) { 103 | drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 8, 16777215); 104 | }*/ 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/gui/ReloadControllerMappingsOption.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.gui; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.controller.Controller; 13 | import dev.lambdaurora.spruceui.option.SpruceSimpleActionOption; 14 | import dev.lambdaurora.spruceui.widget.SpruceButtonWidget; 15 | import net.minecraft.client.MinecraftClient; 16 | import net.minecraft.client.toast.SystemToast; 17 | import net.minecraft.text.LiteralText; 18 | import net.minecraft.text.TranslatableText; 19 | import org.jetbrains.annotations.Nullable; 20 | 21 | import java.util.function.Consumer; 22 | 23 | /** 24 | * Represents the option to reload the controller mappings. 25 | */ 26 | public class ReloadControllerMappingsOption { 27 | private static final String KEY = "lambdacontrols.menu.reload_controller_mappings"; 28 | 29 | public static SpruceSimpleActionOption newOption(@Nullable Consumer before) { 30 | return SpruceSimpleActionOption.of(KEY, btn -> { 31 | var client = MinecraftClient.getInstance(); 32 | if (before != null) 33 | before.accept(btn); 34 | Controller.updateMappings(); 35 | if (client.currentScreen instanceof LambdaControlsSettingsScreen) 36 | client.currentScreen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); 37 | client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT, 38 | new TranslatableText("lambdacontrols.controller.mappings.updated"), LiteralText.EMPTY)); 39 | }, new TranslatableText("lambdacontrols.tooltip.reload_controller_mappings")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/gui/RingScreen.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.gui; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 13 | import dev.lambdaurora.lambdacontrols.client.ring.RingPage; 14 | import net.minecraft.client.gui.screen.Screen; 15 | import net.minecraft.client.util.math.MatrixStack; 16 | import net.minecraft.text.TranslatableText; 17 | 18 | /** 19 | * Represents the controls ring screen. 20 | * 21 | * @author LambdAurora 22 | * @version 1.4.3 23 | * @since 1.4.3 24 | */ 25 | public class RingScreen extends Screen { 26 | protected final LambdaControlsClient mod; 27 | 28 | public RingScreen() { 29 | super(new TranslatableText("lambdacontrols.menu.title.ring")); 30 | this.mod = LambdaControlsClient.get(); 31 | } 32 | 33 | @Override 34 | public boolean isPauseScreen() { 35 | return false; 36 | } 37 | 38 | @Override 39 | public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { 40 | super.render(matrices, mouseX, mouseY, delta); 41 | 42 | RingPage page = this.mod.ring.getCurrentPage(); 43 | 44 | page.render(matrices, this.textRenderer, this.width, this.height, mouseX, mouseY, delta); 45 | } 46 | 47 | @Override 48 | public boolean mouseReleased(double mouseX, double mouseY, int button) { 49 | /*if (LambdaControlsClient.BINDING_RING.matchesMouse(button)) { 50 | this.onClose(); 51 | return true; 52 | }*/ 53 | return false; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/gui/widget/ControllerButtonWidget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.gui.widget; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding; 13 | import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer; 14 | import dev.lambdaurora.spruceui.Position; 15 | import dev.lambdaurora.spruceui.SpruceTexts; 16 | import dev.lambdaurora.spruceui.widget.AbstractSpruceIconButtonWidget; 17 | import net.minecraft.client.MinecraftClient; 18 | import net.minecraft.client.util.math.MatrixStack; 19 | import net.minecraft.text.LiteralText; 20 | import net.minecraft.text.Text; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | /** 24 | * Represents a controller button widget. 25 | */ 26 | public class ControllerButtonWidget extends AbstractSpruceIconButtonWidget { 27 | private ButtonBinding binding; 28 | private int iconWidth; 29 | 30 | public ControllerButtonWidget(Position position, int width, @NotNull ButtonBinding binding, @NotNull PressAction action) { 31 | super(position, width, 20, ButtonBinding.getLocalizedButtonName(binding.getButton()[0]), action); 32 | this.binding = binding; 33 | } 34 | 35 | public void update() { 36 | int length = binding.getButton().length; 37 | this.setMessage(this.binding.isNotBound() ? SpruceTexts.NOT_BOUND.copy() : 38 | (length > 0 ? ButtonBinding.getLocalizedButtonName(binding.getButton()[0]) : new LiteralText("<>"))); 39 | } 40 | 41 | @Override 42 | public Text getMessage() { 43 | if (this.binding.getButton().length > 1) 44 | return LiteralText.EMPTY; 45 | return super.getMessage(); 46 | } 47 | 48 | @Override 49 | protected int renderIcon(MatrixStack matrices, int mouseX, int mouseY, float delta) { 50 | int x = this.getX(); 51 | if (this.binding.getButton().length > 1) { 52 | x += (this.width / 2 - this.iconWidth / 2) - 4; 53 | } 54 | var size = LambdaControlsRenderer.drawButton(matrices, x, this.getY(), this.binding, MinecraftClient.getInstance()); 55 | this.iconWidth = size.length(); 56 | return size.height(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/gui/widget/ControllerControlsWidget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.gui.widget; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 13 | import dev.lambdaurora.lambdacontrols.client.controller.ButtonBinding; 14 | import dev.lambdaurora.lambdacontrols.client.controller.InputManager; 15 | import dev.lambdaurora.spruceui.Position; 16 | import dev.lambdaurora.spruceui.SpruceTexts; 17 | import dev.lambdaurora.spruceui.widget.SpruceButtonWidget; 18 | import dev.lambdaurora.spruceui.widget.container.SpruceContainerWidget; 19 | import net.minecraft.client.gui.screen.option.ControlsOptionsScreen; 20 | import net.minecraft.client.util.math.MatrixStack; 21 | import net.minecraft.text.TranslatableText; 22 | import org.aperlambda.lambdacommon.utils.function.Predicates; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.stream.Collectors; 27 | 28 | /** 29 | * Represents the controls screen. 30 | */ 31 | public class ControllerControlsWidget extends SpruceContainerWidget { 32 | final LambdaControlsClient mod; 33 | private ControlsListWidget bindingsListWidget; 34 | private SpruceButtonWidget resetButton; 35 | public ButtonBinding focusedBinding; 36 | public boolean waiting = false; 37 | public List currentButtons = new ArrayList<>(); 38 | 39 | public ControllerControlsWidget(Position position, int width, int height) { 40 | super(position, width, height); 41 | this.mod = LambdaControlsClient.get(); 42 | 43 | this.init(); 44 | } 45 | 46 | protected void init() { 47 | this.addChild(new SpruceButtonWidget(Position.of(this, this.width / 2 - 155, 18), 310, 20, 48 | new TranslatableText("lambdacontrols.menu.keyboard_controls"), 49 | btn -> this.client.openScreen(new ControlsOptionsScreen(null, this.client.options)))); 50 | this.bindingsListWidget = new ControlsListWidget(Position.of(this, 0, 43), this.width, this.height - 43 - 35, this); 51 | this.addChild(this.bindingsListWidget); 52 | this.addChild(this.resetButton = new SpruceButtonWidget(Position.of(this, this.width / 2 - 155, this.height - 29), 150, 20, 53 | SpruceTexts.CONTROLS_RESET_ALL, 54 | btn -> InputManager.streamBindings().collect(Collectors.toSet()).forEach(binding -> this.mod.config.setButtonBinding(binding, binding.getDefaultButton())))); 55 | } 56 | 57 | @Override 58 | public void renderWidget(MatrixStack matrices, int mouseX, int mouseY, float delta) { 59 | drawCenteredText(matrices, this.client.textRenderer, new TranslatableText("lambdacontrols.menu.title.controller_controls"), 60 | this.getX() + this.width / 2, this.getY() + 4, 16777215); 61 | this.resetButton.setActive(InputManager.streamBindings().anyMatch(Predicates.not(ButtonBinding::isDefault))); 62 | super.renderWidget(matrices, mouseX, mouseY, delta); 63 | } 64 | 65 | public void finishBindingEdit(int... buttons) { 66 | if (this.focusedBinding == null) return; 67 | this.mod.config.setButtonBinding(this.focusedBinding, buttons); 68 | this.focusedBinding = null; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/AdvancementsScreenAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import net.minecraft.advancement.Advancement; 13 | import net.minecraft.client.gui.screen.advancement.AdvancementTab; 14 | import net.minecraft.client.gui.screen.advancement.AdvancementsScreen; 15 | import net.minecraft.client.network.ClientAdvancementManager; 16 | import org.spongepowered.asm.mixin.Mixin; 17 | import org.spongepowered.asm.mixin.gen.Accessor; 18 | 19 | import java.util.Map; 20 | 21 | /** 22 | * Represents an accessor of {@link AdvancementsScreen}. 23 | */ 24 | @Mixin(AdvancementsScreen.class) 25 | public interface AdvancementsScreenAccessor { 26 | @Accessor("advancementHandler") 27 | ClientAdvancementManager getAdvancementManager(); 28 | 29 | @Accessor("tabs") 30 | Map getTabs(); 31 | 32 | @Accessor("selectedTab") 33 | AdvancementTab getSelectedTab(); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/ClickableWidgetAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import net.minecraft.client.gui.widget.ClickableWidget; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.gen.Accessor; 15 | 16 | @Mixin(ClickableWidget.class) 17 | public interface ClickableWidgetAccessor { 18 | @Accessor("height") 19 | int getHeight(); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/ClientPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import com.mojang.authlib.GameProfile; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import dev.lambdaurora.lambdacontrols.client.controller.MovementHandler; 15 | import net.minecraft.client.MinecraftClient; 16 | import net.minecraft.client.input.Input; 17 | import net.minecraft.client.network.AbstractClientPlayerEntity; 18 | import net.minecraft.client.network.ClientPlayerEntity; 19 | import net.minecraft.client.world.ClientWorld; 20 | import net.minecraft.entity.MovementType; 21 | import net.minecraft.util.math.Vec3d; 22 | import org.spongepowered.asm.mixin.Final; 23 | import org.spongepowered.asm.mixin.Mixin; 24 | import org.spongepowered.asm.mixin.Shadow; 25 | import org.spongepowered.asm.mixin.injection.At; 26 | import org.spongepowered.asm.mixin.injection.Inject; 27 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 28 | 29 | /** 30 | * Injects the anti fly drifting feature. 31 | */ 32 | @Mixin(ClientPlayerEntity.class) 33 | public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity { 34 | private boolean lambdacontrols$driftingPrevented = false; 35 | 36 | @Shadow 37 | protected abstract boolean hasMovementInput(); 38 | 39 | @Shadow 40 | @Final 41 | protected MinecraftClient client; 42 | 43 | @Shadow 44 | public Input input; 45 | 46 | @Shadow 47 | protected abstract boolean isCamera(); 48 | 49 | public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) { 50 | super(world, profile); 51 | } 52 | 53 | @Inject(method = "move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V")) 54 | public void onMove(MovementType type, Vec3d movement, CallbackInfo ci) { 55 | var mod = LambdaControlsClient.get(); 56 | if (type == MovementType.SELF) { 57 | if (this.getAbilities().flying && (!mod.config.hasFlyDrifting() || !mod.config.hasFlyVerticalDrifting())) { 58 | if (!this.hasMovementInput()) { 59 | if (!this.lambdacontrols$driftingPrevented) { 60 | if (!mod.config.hasFlyDrifting()) 61 | this.setVelocity(this.getVelocity().multiply(0, 1.0, 0)); 62 | } 63 | this.lambdacontrols$driftingPrevented = true; 64 | } else 65 | this.lambdacontrols$driftingPrevented = false; 66 | } 67 | } 68 | } 69 | 70 | @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick(Z)V", shift = At.Shift.AFTER)) 71 | public void onInputUpdate(CallbackInfo ci) { 72 | MovementHandler.HANDLER.applyMovement((ClientPlayerEntity) (Object) this); 73 | } 74 | 75 | @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isCamera()Z")) 76 | public void onTickMovement(CallbackInfo ci) { 77 | if (this.getAbilities().flying && this.isCamera()) { 78 | if (LambdaControlsClient.get().config.hasFlyVerticalDrifting()) 79 | return; 80 | int moving = 0; 81 | if (this.input.sneaking) { 82 | --moving; 83 | } 84 | 85 | if (this.input.jumping) { 86 | ++moving; 87 | } 88 | 89 | if (moving == 0) { 90 | this.setVelocity(this.getVelocity().multiply(1.0, 0.0, 1.0)); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/ControlsOptionsScreenMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen; 13 | import net.minecraft.client.gui.Drawable; 14 | import net.minecraft.client.gui.Element; 15 | import net.minecraft.client.gui.Selectable; 16 | import net.minecraft.client.gui.screen.Screen; 17 | import net.minecraft.client.gui.screen.option.ControlsOptionsScreen; 18 | import net.minecraft.client.gui.screen.option.GameOptionsScreen; 19 | import net.minecraft.client.gui.widget.ButtonWidget; 20 | import net.minecraft.client.gui.widget.CyclingButtonWidget; 21 | import net.minecraft.client.option.GameOptions; 22 | import net.minecraft.text.Text; 23 | import net.minecraft.text.TranslatableText; 24 | import org.spongepowered.asm.mixin.Mixin; 25 | import org.spongepowered.asm.mixin.injection.At; 26 | import org.spongepowered.asm.mixin.injection.Redirect; 27 | 28 | /** 29 | * Injects the new controls settings button. 30 | */ 31 | @Mixin(ControlsOptionsScreen.class) 32 | public class ControlsOptionsScreenMixin extends GameOptionsScreen { 33 | public ControlsOptionsScreenMixin(Screen parent, GameOptions gameOptions, Text text) { 34 | super(parent, gameOptions, text); 35 | } 36 | 37 | @SuppressWarnings("unchecked") 38 | @Redirect( 39 | method = "init", 40 | at = @At( 41 | value = "INVOKE", 42 | target = "Lnet/minecraft/client/gui/screen/option/ControlsOptionsScreen;addDrawableChild(Lnet/minecraft/client/gui/Element;)Lnet/minecraft/client/gui/Element;", 43 | ordinal = 1 44 | ) 45 | ) 46 | private R onInit(ControlsOptionsScreen screen, T element) { 47 | /*if (this.parent instanceof ControllerControlsWidget) 48 | return this.addButton(btn); 49 | else*/ 50 | if (element instanceof CyclingButtonWidget btn) { 51 | return (R) this.addDrawableChild(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((ClickableWidgetAccessor) btn).getHeight(), 52 | new TranslatableText("menu.options"), 53 | b -> this.client.openScreen(new LambdaControlsSettingsScreen(this, true)))); 54 | } else { 55 | return (R) this.addDrawableChild(element); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/CreativeInventoryScreenAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; 13 | import net.minecraft.item.ItemGroup; 14 | import net.minecraft.screen.slot.Slot; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.jetbrains.annotations.Nullable; 17 | import org.spongepowered.asm.mixin.Mixin; 18 | import org.spongepowered.asm.mixin.gen.Accessor; 19 | import org.spongepowered.asm.mixin.gen.Invoker; 20 | 21 | /** 22 | * Represents an accessor to CreativeInventoryScreen. 23 | */ 24 | @Mixin(CreativeInventoryScreen.class) 25 | public interface CreativeInventoryScreenAccessor { 26 | /** 27 | * Gets the selected tab. 28 | * 29 | * @return the selected tab index 30 | */ 31 | @Accessor("selectedTab") 32 | int getSelectedTab(); 33 | 34 | /** 35 | * Sets the selected tab. 36 | * 37 | * @param group the tab's item group 38 | */ 39 | @Invoker("setSelectedTab") 40 | void lambdacontrols$setSelectedTab(@NotNull ItemGroup group); 41 | 42 | /** 43 | * Returns whether the slot belongs to the creative inventory or not. 44 | * 45 | * @param slot the slot to check 46 | * @return true if the slot is from the creative inventory, else false 47 | */ 48 | @Invoker("isCreativeInventorySlot") 49 | boolean lambdacontrols$isCreativeInventorySlot(@Nullable Slot slot); 50 | 51 | /** 52 | * Returns whether the current tab has a scrollbar or not. 53 | * 54 | * @return true if the current tab has a scrollbar, else false 55 | */ 56 | @Invoker("hasScrollbar") 57 | boolean lambdacontrols$hasScrollbar(); 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/EntryListWidgetAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import net.minecraft.client.gui.widget.EntryListWidget; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.gen.Invoker; 15 | 16 | @Mixin(EntryListWidget.class) 17 | public interface EntryListWidgetAccessor { 18 | @Invoker("moveSelection") 19 | void lambdacontrols$moveSelection(EntryListWidget.MoveDirection direction); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/GameOptionsMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import net.minecraft.client.option.GameOptions; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | 19 | /** 20 | * Represents a mixin to GameOptions. 21 | *

22 | * Sets the default of the Auto-Jump option to false. 23 | */ 24 | @Mixin(GameOptions.class) 25 | public class GameOptionsMixin { 26 | @Shadow 27 | public boolean autoJump; 28 | 29 | @Inject(method = "load", at = @At("HEAD")) 30 | public void onInit(CallbackInfo ci) { 31 | // Set default value of the Auto-Jump option to false. 32 | this.autoJump = false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/GameRendererMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import dev.lambdaurora.lambdacontrols.ControlsMode; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import net.minecraft.client.MinecraftClient; 15 | import net.minecraft.client.render.GameRenderer; 16 | import org.spongepowered.asm.mixin.Final; 17 | import org.spongepowered.asm.mixin.Mixin; 18 | import org.spongepowered.asm.mixin.Shadow; 19 | import org.spongepowered.asm.mixin.injection.At; 20 | import org.spongepowered.asm.mixin.injection.Inject; 21 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 22 | 23 | @Mixin(GameRenderer.class) 24 | public class GameRendererMixin { 25 | @Shadow 26 | @Final 27 | private MinecraftClient client; 28 | 29 | @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Mouse;getX()D")) 30 | private void onRender(float tickDelta, long startTime, boolean fullRender, CallbackInfo ci) { 31 | if (this.client.currentScreen != null && LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) 32 | LambdaControlsClient.get().input.onPreRenderScreen(this.client, this.client.currentScreen); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/HandledScreenMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import dev.lambdaurora.lambdacontrols.ControlsMode; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import dev.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; 15 | import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer; 16 | import dev.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; 17 | import net.minecraft.client.MinecraftClient; 18 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 19 | import net.minecraft.client.util.math.MatrixStack; 20 | import net.minecraft.screen.slot.Slot; 21 | import net.minecraft.screen.slot.SlotActionType; 22 | import org.jetbrains.annotations.Nullable; 23 | import org.lwjgl.glfw.GLFW; 24 | import org.spongepowered.asm.mixin.Mixin; 25 | import org.spongepowered.asm.mixin.gen.Accessor; 26 | import org.spongepowered.asm.mixin.gen.Invoker; 27 | import org.spongepowered.asm.mixin.injection.At; 28 | import org.spongepowered.asm.mixin.injection.Inject; 29 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 30 | 31 | /** 32 | * Represents the mixin for the class ContainerScreen. 33 | */ 34 | @Mixin(HandledScreen.class) 35 | public abstract class HandledScreenMixin implements HandledScreenAccessor { 36 | @Accessor("x") 37 | public abstract int getX(); 38 | 39 | @Accessor("y") 40 | public abstract int getY(); 41 | 42 | @Invoker("getSlotAt") 43 | public abstract Slot lambdacontrols$getSlotAt(double posX, double posY); 44 | 45 | @Invoker("isClickOutsideBounds") 46 | public abstract boolean lambdacontrols$isClickOutsideBounds(double mouseX, double mouseY, int x, int y, int button); 47 | 48 | @Invoker("onMouseClick") 49 | public abstract void lambdacontrols$onMouseClick(@Nullable Slot slot, int slotId, int clickData, SlotActionType actionType); 50 | 51 | @Inject(method = "render", at = @At("RETURN")) 52 | public void onRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) { 53 | if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER) { 54 | var client = MinecraftClient.getInstance(); 55 | int x = 2, y = client.getWindow().getScaledHeight() - 2 - LambdaControlsRenderer.ICON_SIZE; 56 | 57 | x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, "lambdacontrols.action.pickup_all", true, client) + 2; 58 | x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_B}, "lambdacontrols.action.exit", true, client) + 2; 59 | if (LambdaControlsCompat.isReiPresent()) { 60 | x = 2; 61 | y -= 24; 62 | } 63 | x = LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_X}, "lambdacontrols.action.pickup", true, client) + 2; 64 | LambdaControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_Y}, "lambdacontrols.action.quick_move", true, client); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/KeyBindingMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; 13 | import net.minecraft.client.option.KeyBinding; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.Shadow; 16 | 17 | @Mixin(KeyBinding.class) 18 | public class KeyBindingMixin implements KeyBindingAccessor { 19 | @Shadow 20 | private int timesPressed; 21 | 22 | @Shadow 23 | private boolean pressed; 24 | 25 | @Override 26 | public boolean lambdacontrols$press() { 27 | boolean oldPressed = this.pressed; 28 | if (!this.pressed) 29 | this.pressed = true; 30 | ++this.timesPressed; 31 | return oldPressed != this.pressed; 32 | } 33 | 34 | @Override 35 | public boolean lambdacontrols$unpress() { 36 | if (this.pressed) { 37 | this.pressed = false; 38 | return true; 39 | } 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import dev.lambdaurora.lambdacontrols.LambdaControlsFeature; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer; 15 | import net.minecraft.client.MinecraftClient; 16 | import net.minecraft.client.network.ClientPlayerEntity; 17 | import net.minecraft.client.network.ClientPlayerInteractionManager; 18 | import net.minecraft.client.render.GameRenderer; 19 | import net.minecraft.client.util.math.MatrixStack; 20 | import net.minecraft.client.world.ClientWorld; 21 | import net.minecraft.item.BlockItem; 22 | import net.minecraft.item.ItemStack; 23 | import net.minecraft.util.ActionResult; 24 | import net.minecraft.util.Hand; 25 | import net.minecraft.util.hit.BlockHitResult; 26 | import net.minecraft.util.hit.HitResult; 27 | import net.minecraft.util.math.BlockPos; 28 | import net.minecraft.util.math.Direction; 29 | import net.minecraft.util.math.Vec3d; 30 | import org.jetbrains.annotations.Nullable; 31 | import org.spongepowered.asm.mixin.Final; 32 | import org.spongepowered.asm.mixin.Mixin; 33 | import org.spongepowered.asm.mixin.Shadow; 34 | import org.spongepowered.asm.mixin.injection.At; 35 | import org.spongepowered.asm.mixin.injection.Inject; 36 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 37 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 38 | 39 | @Mixin(MinecraftClient.class) 40 | public abstract class MinecraftClientMixin { 41 | @Shadow 42 | @Nullable 43 | public HitResult crosshairTarget; 44 | 45 | @Shadow 46 | @Nullable 47 | public ClientPlayerEntity player; 48 | 49 | @Shadow 50 | @Nullable 51 | public ClientPlayerInteractionManager interactionManager; 52 | 53 | @Shadow 54 | @Nullable 55 | public ClientWorld world; 56 | 57 | @Shadow 58 | @Final 59 | public GameRenderer gameRenderer; 60 | 61 | @Shadow 62 | private int itemUseCooldown; 63 | 64 | private BlockPos lambdacontrols$lastTargetPos; 65 | private Vec3d lambdacontrols$lastPos; 66 | private Direction lambdacontrols$lastTargetSide; 67 | 68 | @Inject(method = "", at = @At("RETURN")) 69 | private void onInit(CallbackInfo ci) { 70 | LambdaControlsClient.get().onMcInit((MinecraftClient) (Object) this); 71 | } 72 | 73 | @Inject(method = "tick", at = @At("HEAD")) 74 | private void onStartTick(CallbackInfo ci) { 75 | if (this.player == null) 76 | return; 77 | 78 | if (!LambdaControlsFeature.FAST_BLOCK_PLACING.isAvailable()) 79 | return; 80 | if (this.lambdacontrols$lastPos == null) 81 | this.lambdacontrols$lastPos = this.player.getPos(); 82 | 83 | int cooldown = this.itemUseCooldown; 84 | BlockHitResult hitResult; 85 | if (this.crosshairTarget != null && this.crosshairTarget.getType() == HitResult.Type.BLOCK && this.player.getAbilities().flying) { 86 | hitResult = (BlockHitResult) this.crosshairTarget; 87 | var targetPos = hitResult.getBlockPos(); 88 | var side = hitResult.getSide(); 89 | 90 | boolean sidewaysBlockPlacing = this.lambdacontrols$lastTargetPos == null || !targetPos.equals(this.lambdacontrols$lastTargetPos.offset(this.lambdacontrols$lastTargetSide)); 91 | boolean backwardsBlockPlacing = this.player.input.movementForward < 0.0f && (this.lambdacontrols$lastTargetPos == null || targetPos.equals(this.lambdacontrols$lastTargetPos.offset(this.lambdacontrols$lastTargetSide))); 92 | 93 | if (cooldown > 1 94 | && !targetPos.equals(this.lambdacontrols$lastTargetPos) 95 | && (sidewaysBlockPlacing || backwardsBlockPlacing)) { 96 | this.itemUseCooldown = 1; 97 | } 98 | 99 | this.lambdacontrols$lastTargetPos = targetPos.toImmutable(); 100 | this.lambdacontrols$lastTargetSide = side; 101 | } 102 | // Removed front placing sprinting as way too cheaty. 103 | /*else if (this.player.isSprinting()) { 104 | hitResult = LambdaControlsClient.get().reacharound.getLastReacharoundResult(); 105 | if (hitResult != null) { 106 | if (cooldown > 0) 107 | this.itemUseCooldown = 0; 108 | } 109 | }*/ 110 | this.lambdacontrols$lastPos = this.player.getPos(); 111 | } 112 | 113 | @Inject(method = "render", at = @At("HEAD")) 114 | private void onRender(boolean fullRender, CallbackInfo ci) { 115 | LambdaControlsClient.get().onRender((MinecraftClient) (Object) (this)); 116 | } 117 | 118 | @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V", shift = At.Shift.AFTER)) 119 | private void renderVirtualCursor(boolean fullRender, CallbackInfo ci) { 120 | LambdaControlsRenderer.renderVirtualCursor(new MatrixStack(), (MinecraftClient) (Object) this); 121 | } 122 | 123 | @Inject(method = "doItemUse()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/hit/HitResult;getType()Lnet/minecraft/util/hit/HitResult$Type;"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true) 124 | private void onItemUse(CallbackInfo ci, Hand[] hands, int handCount, int handIndex, Hand hand, ItemStack stackInHand) { 125 | var mod = LambdaControlsClient.get(); 126 | if (!stackInHand.isEmpty() && this.player.getPitch(0.f) > 35.0F && mod.reacharound.isReacharoundAvailable()) { 127 | if (this.crosshairTarget != null && this.crosshairTarget.getType() == HitResult.Type.MISS && this.player.isOnGround()) { 128 | if (!stackInHand.isEmpty() && stackInHand.getItem() instanceof BlockItem) { 129 | var hitResult = mod.reacharound.getLastReacharoundResult(); 130 | 131 | if (hitResult == null) 132 | return; 133 | 134 | hitResult = mod.reacharound.withSideForReacharound(hitResult, stackInHand); 135 | 136 | int previousStackCount = stackInHand.getCount(); 137 | var result = this.interactionManager.interactBlock(this.player, this.world, hand, hitResult); 138 | if (result.isAccepted()) { 139 | if (result.shouldSwingHand()) { 140 | this.player.swingHand(hand); 141 | if (!stackInHand.isEmpty() && (stackInHand.getCount() != previousStackCount || this.interactionManager.hasCreativeInventory())) { 142 | this.gameRenderer.firstPersonRenderer.resetEquipProgress(hand); 143 | } 144 | } 145 | 146 | ci.cancel(); 147 | } 148 | 149 | if (result == ActionResult.FAIL) { 150 | ci.cancel(); 151 | } 152 | } 153 | } 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/MouseMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import dev.lambdaurora.lambdacontrols.ControlsMode; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsConfig; 15 | import dev.lambdaurora.lambdacontrols.client.util.MouseAccessor; 16 | import net.minecraft.client.MinecraftClient; 17 | import net.minecraft.client.Mouse; 18 | import net.minecraft.client.gui.screen.Screen; 19 | import org.lwjgl.glfw.GLFW; 20 | import org.spongepowered.asm.mixin.Final; 21 | import org.spongepowered.asm.mixin.Mixin; 22 | import org.spongepowered.asm.mixin.Shadow; 23 | import org.spongepowered.asm.mixin.gen.Invoker; 24 | import org.spongepowered.asm.mixin.injection.At; 25 | import org.spongepowered.asm.mixin.injection.Inject; 26 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 27 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 28 | 29 | /** 30 | * Adds extra access to the mouse. 31 | */ 32 | @Mixin(Mouse.class) 33 | public abstract class MouseMixin implements MouseAccessor { 34 | @Shadow 35 | @Final 36 | private MinecraftClient client; 37 | 38 | @Invoker("onCursorPos") 39 | public abstract void lambdacontrols$onCursorPos(long window, double x, double y); 40 | 41 | @Inject(method = "method_1605", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/client/gui/screen/Screen;mouseReleased(DDI)Z")) 42 | private static void onMouseBackButton(boolean[] result, Screen screen, double mouseX, double mouseY, int button, CallbackInfo ci) { 43 | if (!result[0] && button == GLFW.GLFW_MOUSE_BUTTON_4 && screen != null) { 44 | if (LambdaControlsClient.get().input.tryGoBack(screen)) { 45 | result[0] = true; 46 | } 47 | } 48 | } 49 | 50 | @Inject(method = "isCursorLocked", at = @At("HEAD"), cancellable = true) 51 | private void isCursorLocked(CallbackInfoReturnable ci) { 52 | if (this.client.currentScreen == null) { 53 | var config = LambdaControlsClient.get().config; 54 | if (config.getControlsMode() == ControlsMode.CONTROLLER && config.hasVirtualMouse()) { 55 | ci.setReturnValue(true); 56 | ci.cancel(); 57 | } 58 | } 59 | } 60 | 61 | @Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true) 62 | private void onCursorLocked(CallbackInfo ci) { 63 | LambdaControlsConfig config = LambdaControlsClient.get().config; 64 | if (/*config.getControlsMode() == ControlsMode.TOUCHSCREEN 65 | ||*/ (config.getControlsMode() == ControlsMode.CONTROLLER && config.hasVirtualMouse())) 66 | ci.cancel(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/OptionsScreenMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import dev.lambdaurora.lambdacontrols.ControlsMode; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import dev.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen; 15 | import net.minecraft.client.gui.Drawable; 16 | import net.minecraft.client.gui.Element; 17 | import net.minecraft.client.gui.Selectable; 18 | import net.minecraft.client.gui.screen.Screen; 19 | import net.minecraft.client.gui.screen.option.OptionsScreen; 20 | import net.minecraft.client.gui.widget.ButtonWidget; 21 | import net.minecraft.text.Text; 22 | import org.spongepowered.asm.mixin.Mixin; 23 | import org.spongepowered.asm.mixin.injection.At; 24 | import org.spongepowered.asm.mixin.injection.Redirect; 25 | 26 | /** 27 | * Injects the new controls settings button. 28 | */ 29 | @Mixin(OptionsScreen.class) 30 | public class OptionsScreenMixin extends Screen { 31 | protected OptionsScreenMixin(Text title) { 32 | super(title); 33 | } 34 | 35 | @SuppressWarnings("unchecked") 36 | @Redirect( 37 | method = "init", 38 | at = @At( 39 | value = "INVOKE", 40 | target = "Lnet/minecraft/client/gui/screen/option/OptionsScreen;addDrawableChild(Lnet/minecraft/client/gui/Element;)Lnet/minecraft/client/gui/Element;", 41 | ordinal = 7 42 | ) 43 | ) 44 | private T lambdacontrols$onInit(OptionsScreen screen, T element) { 45 | if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.CONTROLLER && element instanceof ButtonWidget btn) { 46 | return (T) this.addDrawableChild(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((ClickableWidgetAccessor) btn).getHeight(), 47 | btn.getMessage(), 48 | b -> this.client.openScreen(new LambdaControlsSettingsScreen(this, false)))); 49 | } else { 50 | return this.addDrawableChild(element); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/RecipeBookWidgetAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget; 13 | import net.minecraft.client.gui.screen.recipebook.RecipeGroupButtonWidget; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.gen.Accessor; 16 | import org.spongepowered.asm.mixin.gen.Invoker; 17 | 18 | import java.util.List; 19 | 20 | @Mixin(RecipeBookWidget.class) 21 | public interface RecipeBookWidgetAccessor { 22 | @Accessor("tabButtons") 23 | List getTabButtons(); 24 | 25 | @Accessor("currentTab") 26 | RecipeGroupButtonWidget getCurrentTab(); 27 | 28 | @Accessor("currentTab") 29 | void setCurrentTab(RecipeGroupButtonWidget currentTab); 30 | 31 | @Invoker("refreshResults") 32 | void lambdacontrols$refreshResults(boolean resetCurrentPage); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/mixin/WorldRendererMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.mixin; 11 | 12 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 13 | import net.minecraft.block.ShapeContext; 14 | import net.minecraft.client.MinecraftClient; 15 | import net.minecraft.client.render.*; 16 | import net.minecraft.client.util.math.MatrixStack; 17 | import net.minecraft.client.world.ClientWorld; 18 | import net.minecraft.item.BlockItem; 19 | import net.minecraft.item.ItemPlacementContext; 20 | import net.minecraft.item.ItemUsageContext; 21 | import net.minecraft.util.Hand; 22 | import net.minecraft.util.hit.HitResult; 23 | import net.minecraft.util.math.Matrix4f; 24 | import net.minecraft.util.shape.VoxelShape; 25 | import org.spongepowered.asm.mixin.Final; 26 | import org.spongepowered.asm.mixin.Mixin; 27 | import org.spongepowered.asm.mixin.Shadow; 28 | import org.spongepowered.asm.mixin.injection.At; 29 | import org.spongepowered.asm.mixin.injection.Inject; 30 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 31 | 32 | /** 33 | * Represents a mixin to WorldRenderer. 34 | *

35 | * Handles the rendering of the block outline of the reach-around features. 36 | */ 37 | @Mixin(WorldRenderer.class) 38 | public abstract class WorldRendererMixin { 39 | @Shadow 40 | @Final 41 | private MinecraftClient client; 42 | 43 | @Shadow 44 | private ClientWorld world; 45 | 46 | @Shadow 47 | @Final 48 | private BufferBuilderStorage bufferBuilders; 49 | 50 | @Shadow 51 | private static void drawShapeOutline(MatrixStack matrixStack, VertexConsumer vertexConsumer, VoxelShape voxelShape, double d, double e, double f, float g, float h, float i, float j) { 52 | } 53 | 54 | @Inject( 55 | method = "render", 56 | at = @At( 57 | value = "FIELD", 58 | target = "Lnet/minecraft/client/MinecraftClient;crosshairTarget:Lnet/minecraft/util/hit/HitResult;", 59 | ordinal = 1, 60 | shift = At.Shift.AFTER 61 | ) 62 | ) 63 | private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, 64 | LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { 65 | if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS || !LambdaControlsClient.get().config.shouldRenderReacharoundOutline()) 66 | return; 67 | var result = LambdaControlsClient.get().reacharound.getLastReacharoundResult(); 68 | if (result == null) 69 | return; 70 | var blockPos = result.getBlockPos(); 71 | if (this.world.getWorldBorder().contains(blockPos)) { 72 | var stack = this.client.player.getStackInHand(Hand.MAIN_HAND); 73 | if (stack == null || !(stack.getItem() instanceof BlockItem)) 74 | return; 75 | 76 | var mod = LambdaControlsClient.get(); 77 | 78 | var block = ((BlockItem) stack.getItem()).getBlock(); 79 | result = mod.reacharound.withSideForReacharound(result, block); 80 | var context = new ItemPlacementContext(new ItemUsageContext(this.client.player, Hand.MAIN_HAND, result)); 81 | 82 | var placementState = block.getPlacementState(context); 83 | if (placementState == null) 84 | return; 85 | var pos = camera.getPos(); 86 | 87 | var outlineShape = placementState.getOutlineShape(this.client.world, blockPos, ShapeContext.of(camera.getFocusedEntity())); 88 | int[] color = mod.config.getReacharoundOutlineColor(); 89 | 90 | var vertexConsumer = this.bufferBuilders.getEntityVertexConsumers().getBuffer(RenderLayer.getLines()); 91 | drawShapeOutline(matrices, vertexConsumer, outlineShape, 92 | (double) blockPos.getX() - pos.getX(), (double) blockPos.getY() - pos.getY(), (double) blockPos.getZ() - pos.getZ(), 93 | color[0] / 255.f, color[1] / 255.f, color[2] / 255.f, color[3] / 255.f); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/ring/DummyRingAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.ring; 11 | 12 | import com.electronwill.nightconfig.core.Config; 13 | import net.minecraft.client.font.TextRenderer; 14 | import net.minecraft.client.util.math.MatrixStack; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | public class DummyRingAction extends RingAction { 18 | public DummyRingAction(@NotNull Config config) { 19 | super(config); 20 | } 21 | 22 | @Override 23 | public @NotNull String getName() { 24 | return "dummy"; 25 | } 26 | 27 | @Override 28 | public void onAction(@NotNull RingButtonMode mode) { 29 | 30 | } 31 | 32 | @Override 33 | public void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered) { 34 | drawCenteredText(matrices, textRenderer, this.getName(), x + 25, y + 25 - textRenderer.fontHeight / 2, 0xffffff); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/ring/KeyBindingRingAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.ring; 11 | 12 | import com.electronwill.nightconfig.core.Config; 13 | import dev.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; 14 | import net.minecraft.client.font.TextRenderer; 15 | import net.minecraft.client.gui.screen.Screen; 16 | import net.minecraft.client.option.KeyBinding; 17 | import net.minecraft.client.util.math.MatrixStack; 18 | import net.minecraft.text.TranslatableText; 19 | import org.jetbrains.annotations.NotNull; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | import java.util.function.Supplier; 23 | 24 | public class KeyBindingRingAction extends RingAction { 25 | public static final Factory FACTORY = new Factory(); 26 | public final KeyBinding binding; 27 | 28 | public KeyBindingRingAction(@NotNull Config config, @NotNull KeyBinding binding) { 29 | super(config); 30 | this.binding = binding; 31 | } 32 | 33 | @Override 34 | public @NotNull String getName() { 35 | return this.binding.getTranslationKey(); 36 | } 37 | 38 | @Override 39 | public void onAction(@NotNull RingButtonMode mode) { 40 | KeyBindingAccessor accessor = (KeyBindingAccessor) this.binding; 41 | switch (mode) { 42 | case PRESS, HOLD -> accessor.lambdacontrols$handlePressState(this.activated); 43 | case TOGGLE -> { 44 | accessor.lambdacontrols$handlePressState(!this.binding.isPressed()); 45 | this.activated = !this.binding.isPressed(); 46 | } 47 | } 48 | } 49 | 50 | @Override 51 | public void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered) { 52 | drawCenteredText(matrices, textRenderer, new TranslatableText(this.getName()), x + 25, y + 25 - textRenderer.fontHeight / 2, 0xffffff); 53 | } 54 | 55 | protected static class Factory implements RingAction.Factory { 56 | @Override 57 | public @NotNull Supplier newFromGui(@NotNull Screen screen) { 58 | return () -> null; 59 | } 60 | 61 | @Override 62 | public @Nullable RingAction parse(@NotNull Config config) { 63 | return null; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/ring/LambdaRing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.ring; 11 | 12 | import com.electronwill.nightconfig.core.Config; 13 | import dev.lambdaurora.lambdacontrols.client.LambdaControlsClient; 14 | import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.ArrayList; 18 | import java.util.Collections; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | /** 23 | * Represents a key binding ring. 24 | * 25 | * @author LambdAurora 26 | * @version 1.7.0 27 | * @since 1.4.0 28 | */ 29 | public final class LambdaRing { 30 | public static final int ELEMENT_SIZE = 50; 31 | 32 | private final Map actionFactories = new Object2ObjectOpenHashMap<>(); 33 | private final List pages = new ArrayList<>(Collections.singletonList(RingPage.DEFAULT)); 34 | private final LambdaControlsClient mod; 35 | private int currentPage = 0; 36 | 37 | public LambdaRing(@NotNull LambdaControlsClient mod) { 38 | this.mod = mod; 39 | } 40 | 41 | public void registerAction(@NotNull String name, @NotNull RingAction.Factory factory) { 42 | if (this.actionFactories.containsKey(name)) { 43 | this.mod.warn("Tried to register twice a ring action: \"" + name + "\"."); 44 | return; 45 | } 46 | this.actionFactories.put(name, factory); 47 | } 48 | 49 | /** 50 | * Loads the ring from configuration. 51 | * 52 | * @param config the configuration 53 | */ 54 | public void load(@NotNull Config config) { 55 | List configPages = config.get("ring.pages"); 56 | if (configPages != null) { 57 | this.pages.clear(); 58 | for (var configPage : configPages) { 59 | RingPage.parseRingPage(configPage).ifPresent(this.pages::add); 60 | } 61 | } 62 | if (this.pages.isEmpty()) { 63 | this.pages.add(RingPage.DEFAULT); 64 | } 65 | } 66 | 67 | public @NotNull RingPage getCurrentPage() { 68 | if (this.currentPage >= this.pages.size()) 69 | this.currentPage = this.pages.size() - 1; 70 | else if (this.currentPage < 0) 71 | this.currentPage = 0; 72 | return this.pages.get(this.currentPage); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/ring/RingAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.ring; 11 | 12 | import com.electronwill.nightconfig.core.Config; 13 | import net.minecraft.client.font.TextRenderer; 14 | import net.minecraft.client.gui.DrawableHelper; 15 | import net.minecraft.client.gui.screen.Screen; 16 | import net.minecraft.client.util.math.MatrixStack; 17 | import net.minecraft.text.Text; 18 | import net.minecraft.text.TranslatableText; 19 | import org.aperlambda.lambdacommon.utils.Nameable; 20 | import org.jetbrains.annotations.NotNull; 21 | import org.jetbrains.annotations.Nullable; 22 | 23 | import java.util.function.Supplier; 24 | 25 | /** 26 | * Represents a ring action. 27 | * 28 | * @author LambdAurora 29 | * @version 1.5.0 30 | * @since 1.4.0 31 | */ 32 | public abstract class RingAction extends DrawableHelper implements Nameable { 33 | protected Config config; 34 | protected boolean activated = false; 35 | 36 | public RingAction(@NotNull Config config) { 37 | this.config = config; 38 | } 39 | 40 | /** 41 | * Gets the text name of the ring action. 42 | * 43 | * @return the text name 44 | */ 45 | public Text getTextName() { 46 | return new TranslatableText(this.getName()); 47 | } 48 | 49 | /** 50 | * Returns whether the action is activated or not. 51 | * 52 | * @return true if the action is activated, else false 53 | */ 54 | public boolean isActivated() { 55 | return this.activated; 56 | } 57 | 58 | public void activate(@NotNull RingButtonMode mode) { 59 | this.activated = !this.activated; 60 | 61 | this.onAction(mode); 62 | } 63 | 64 | public abstract void onAction(@NotNull RingButtonMode mode); 65 | 66 | public void render(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered) { 67 | fill(matrices, x, y, x + LambdaRing.ELEMENT_SIZE, y + LambdaRing.ELEMENT_SIZE, hovered ? 0xbb777777 : 0xbb000000); 68 | drawIcon(matrices, textRenderer, x, y, hovered); 69 | } 70 | 71 | public abstract void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered); 72 | 73 | /** 74 | * Represents a factory for {@link RingAction}. 75 | * 76 | * @version 1.4.3 77 | * @since 1.4.3 78 | */ 79 | public interface Factory { 80 | @NotNull Supplier newFromGui(@NotNull Screen screen); 81 | 82 | @Nullable RingAction parse(@NotNull Config config); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/ring/RingButtonMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.ring; 11 | 12 | import net.minecraft.text.Text; 13 | import net.minecraft.text.TranslatableText; 14 | import org.aperlambda.lambdacommon.utils.Nameable; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | /** 18 | * Represents the mode of a ring button. 19 | * 20 | * @author LambdAurora 21 | * @version 1.4.0 22 | * @since 1.4.0 23 | */ 24 | public enum RingButtonMode implements Nameable { 25 | PRESS("press"), 26 | HOLD("hold"), 27 | TOGGLE("toggle"); 28 | 29 | private final String name; 30 | private final Text text; 31 | 32 | RingButtonMode(@NotNull String name) { 33 | this.name = name; 34 | this.text = new TranslatableText(this.getTranslationKey()); 35 | } 36 | 37 | /** 38 | * Returns the next ring button mode available. 39 | * 40 | * @return the next ring button mode 41 | */ 42 | public @NotNull RingButtonMode next() { 43 | var v = values(); 44 | if (v.length == this.ordinal() + 1) 45 | return v[0]; 46 | return v[this.ordinal() + 1]; 47 | } 48 | 49 | /** 50 | * Returns the translation key of this ring button mode. 51 | * 52 | * @return the translation key of this ring button mode 53 | */ 54 | public @NotNull String getTranslationKey() { 55 | return "lambdacontrols.ring.button_mode." + this.getName(); 56 | } 57 | 58 | /** 59 | * Gets the translated name of this ring button mode. 60 | * 61 | * @return the translated name of this ring button mode 62 | */ 63 | public @NotNull Text getTranslatedText() { 64 | return this.text; 65 | } 66 | 67 | @Override 68 | public @NotNull String getName() { 69 | return this.name; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/ring/RingPage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.ring; 11 | 12 | import com.electronwill.nightconfig.core.Config; 13 | import net.minecraft.client.font.TextRenderer; 14 | import net.minecraft.client.gui.DrawableHelper; 15 | import net.minecraft.client.util.math.MatrixStack; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | import java.util.List; 19 | import java.util.Optional; 20 | 21 | /** 22 | * Represents a ring page. 23 | * 24 | * @author LambdAurora 25 | * @version 1.5.0 26 | * @since 1.4.0 27 | */ 28 | public class RingPage extends DrawableHelper { 29 | public static final RingPage DEFAULT = new RingPage("Default"); 30 | 31 | public final String name; 32 | private RingAction[] actions = new RingAction[8]; 33 | 34 | public RingPage(@NotNull String name) { 35 | this.name = name; 36 | for (int i = 0; i < 8; i++) { 37 | this.actions[i] = null; 38 | } 39 | } 40 | 41 | /** 42 | * Renders the ring page. 43 | * 44 | * @param matrices the matrices 45 | * @param width the screen width 46 | * @param height the screen height 47 | * @param mouseX the mouse X-coordinate 48 | * @param mouseY the mouse Y-coordinate 49 | * @param tickDelta the tick delta 50 | */ 51 | public void render(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int width, int height, int mouseX, int mouseY, float tickDelta) { 52 | int centerX = width / 2; 53 | int centerY = height / 2; 54 | 55 | int offset = LambdaRing.ELEMENT_SIZE + (LambdaRing.ELEMENT_SIZE / 2) + 5; 56 | 57 | int y = centerY - offset; 58 | int x = centerX - offset; 59 | for (int i = 0; i < 3; i++) { 60 | var ringAction = this.actions[i]; 61 | if (ringAction != null) 62 | ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY)); 63 | x += 55; 64 | } 65 | y += 55; 66 | x = centerX - offset; 67 | for (int i = 3; i < 5; i++) { 68 | var ringAction = this.actions[i]; 69 | if (ringAction != null) 70 | ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY)); 71 | x += 55 * 2; 72 | } 73 | y += 55; 74 | x = centerX - offset; 75 | for (int i = 5; i < 8; i++) { 76 | var ringAction = this.actions[i]; 77 | if (ringAction != null) 78 | ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY)); 79 | x += 55; 80 | } 81 | } 82 | 83 | private static boolean isHovered(int x, int y, int mouseX, int mouseY) { 84 | return mouseX >= x && mouseY >= y && mouseX <= x + LambdaRing.ELEMENT_SIZE && mouseY <= y + LambdaRing.ELEMENT_SIZE; 85 | } 86 | 87 | /** 88 | * Tries to parse a ring page configuration. 89 | * 90 | * @param config the configuration 91 | * @return an optional ring page 92 | */ 93 | public static @NotNull Optional parseRingPage(@NotNull Config config) { 94 | String name = config.get("name"); 95 | if (name == null) 96 | return Optional.empty(); 97 | 98 | var page = new RingPage(name); 99 | 100 | List actionConfigs = config.get("actions"); 101 | 102 | 103 | return Optional.of(page); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/util/HandledScreenAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.util; 11 | 12 | import net.minecraft.screen.slot.Slot; 13 | import net.minecraft.screen.slot.SlotActionType; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | /** 17 | * Represents an accessor to AbstractContainerScreen. 18 | */ 19 | public interface HandledScreenAccessor { 20 | /** 21 | * Gets the left coordinate of the GUI. 22 | * 23 | * @return the left coordinate of the GUI 24 | */ 25 | int getX(); 26 | 27 | /** 28 | * Gets the top coordinate of the GUI. 29 | * 30 | * @return the top coordinate of the GUI 31 | */ 32 | int getY(); 33 | 34 | /** 35 | * Gets the slot at position. 36 | * 37 | * @param posX the X position to check 38 | * @param posY the Y position to check 39 | * @return the slot at the specified position 40 | */ 41 | Slot lambdacontrols$getSlotAt(double posX, double posY); 42 | 43 | boolean lambdacontrols$isClickOutsideBounds(double mouseX, double mouseY, int x, int y, int button); 44 | 45 | /** 46 | * Handles a mouse click on the specified slot. 47 | * 48 | * @param slot the slot instance 49 | * @param slotId the slot id 50 | * @param clickData the click data 51 | * @param actionType the action type 52 | */ 53 | void lambdacontrols$onMouseClick(@Nullable Slot slot, int slotId, int clickData, SlotActionType actionType); 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/util/KeyBindingAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.util; 11 | 12 | /** 13 | * Represents a Minecraft keybinding with extra access. 14 | */ 15 | public interface KeyBindingAccessor { 16 | boolean lambdacontrols$press(); 17 | 18 | boolean lambdacontrols$unpress(); 19 | 20 | default boolean lambdacontrols$handlePressState(boolean pressed) { 21 | if (pressed) 22 | return this.lambdacontrols$press(); 23 | else 24 | return this.lambdacontrols$unpress(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/client/util/MouseAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.client.util; 11 | 12 | /** 13 | * Represents mouse's extra access. 14 | */ 15 | public interface MouseAccessor { 16 | void lambdacontrols$onCursorPos(long window, double x, double y); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/dev/lambdaurora/lambdacontrols/event/PlayerChangeControlsModeCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 LambdAurora 3 | * 4 | * This file is part of LambdaControls. 5 | * 6 | * Licensed under the MIT license. For more information, 7 | * see the LICENSE file. 8 | */ 9 | 10 | package dev.lambdaurora.lambdacontrols.event; 11 | 12 | import dev.lambdaurora.lambdacontrols.ControlsMode; 13 | import net.fabricmc.fabric.api.event.Event; 14 | import net.fabricmc.fabric.api.event.EventFactory; 15 | import net.minecraft.entity.player.PlayerEntity; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | /** 19 | * Represents an event callback which is fired when a player changes the controls mode. 20 | * 21 | * @author LambdAurora 22 | * @version 1.1.0 23 | * @since 1.1.0 24 | */ 25 | @FunctionalInterface 26 | public interface PlayerChangeControlsModeCallback { 27 | Event EVENT = EventFactory.createArrayBacked(PlayerChangeControlsModeCallback.class, listeners -> (player, controlsMode) -> { 28 | for (PlayerChangeControlsModeCallback event : listeners) { 29 | event.apply(player, controlsMode); 30 | } 31 | }); 32 | 33 | void apply(@NotNull PlayerEntity player, @NotNull ControlsMode controlsMode); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/src/main/resources/assets/lambdacontrols/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/icon_x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/src/main/resources/assets/lambdacontrols/icon_x400.png -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "key.lambdacontrols.look_down": "Look down", 3 | "key.lambdacontrols.look_left": "Look left", 4 | "key.lambdacontrols.look_right": "Look right", 5 | "key.lambdacontrols.look_up": "Look up", 6 | "key.lambdacontrols.ring": "Show controls ring", 7 | "lambdacontrols.action.attack": "Attack", 8 | "lambdacontrols.action.back": "Back", 9 | "lambdacontrols.action.chat": "Open Chat", 10 | "lambdacontrols.action.drop_item": "Drop Item", 11 | "lambdacontrols.action.exit": "Exit", 12 | "lambdacontrols.action.forward": "Forward", 13 | "lambdacontrols.action.hit": "Hit", 14 | "lambdacontrols.action.hotbar_left": "Hotbar left", 15 | "lambdacontrols.action.hotbar_right": "Hotbar right", 16 | "lambdacontrols.action.inventory": "Inventory", 17 | "lambdacontrols.action.jump": "Jump", 18 | "lambdacontrols.action.left": "Left", 19 | "lambdacontrols.action.pause_game": "Pause Game", 20 | "lambdacontrols.action.pick_block": "Pick Block", 21 | "lambdacontrols.action.pickup": "Pickup", 22 | "lambdacontrols.action.pickup_all": "Pickup all", 23 | "lambdacontrols.action.place": "Place", 24 | "lambdacontrols.action.player_list": "Player List", 25 | "lambdacontrols.action.quick_move": "Quick move", 26 | "lambdacontrols.action.right": "Right", 27 | "lambdacontrols.action.screenshot": "Take Screenshot", 28 | "lambdacontrols.action.sneak": "Sneak", 29 | "lambdacontrols.action.sprint": "Sprint", 30 | "lambdacontrols.action.swap_hands": "Swap Hands", 31 | "lambdacontrols.action.toggle_perspective": "Toggle Perspective", 32 | "lambdacontrols.action.toggle_smooth_camera": "Toggle Cinematic Camera", 33 | "lambdacontrols.action.use": "Use", 34 | "lambdacontrols.action.zoom": "Zoom", 35 | "lambdacontrols.action.zoom_in": "Increase Zoom", 36 | "lambdacontrols.action.zoom_out": "Decrease Zoom", 37 | "lambdacontrols.action.zoom_reset": "Reset Zoom", 38 | "lambdacontrols.button.a": "A", 39 | "lambdacontrols.button.b": "B", 40 | "lambdacontrols.button.x": "X", 41 | "lambdacontrols.button.y": "Y", 42 | "lambdacontrols.button.left_bumper": "Left bumper", 43 | "lambdacontrols.button.right_bumper": "Right bumper", 44 | "lambdacontrols.button.back": "Back", 45 | "lambdacontrols.button.start": "Start", 46 | "lambdacontrols.button.guide": "Guide", 47 | "lambdacontrols.button.left_thumb": "Left thumb", 48 | "lambdacontrols.button.right_thumb": "Right thumb", 49 | "lambdacontrols.button.dpad_up": "DPAD up", 50 | "lambdacontrols.button.dpad_right": "DPAD right", 51 | "lambdacontrols.button.dpad_down": "DPAD down", 52 | "lambdacontrols.button.dpad_left": "DPAD left", 53 | "lambdacontrols.axis.left_x+": "Left X+", 54 | "lambdacontrols.axis.left_y+": "Left Y+", 55 | "lambdacontrols.axis.right_x+": "Right X+", 56 | "lambdacontrols.axis.right_y+": "Right Y+", 57 | "lambdacontrols.axis.left_trigger": "Left trigger", 58 | "lambdacontrols.axis.right_trigger": "Right trigger", 59 | "lambdacontrols.axis.left_x-": "Left X-", 60 | "lambdacontrols.axis.left_y-": "Left Y-", 61 | "lambdacontrols.axis.right_x-": "Right X-", 62 | "lambdacontrols.axis.right_y-": "Right Y-", 63 | "lambdacontrols.button.unknown": "Unknown (%d)", 64 | "lambdacontrols.controller.connected": "Controller %d connected.", 65 | "lambdacontrols.controller.disconnected": "Controller %d disconnected.", 66 | "lambdacontrols.controller.mappings.1": "To configure the controller mappings, please use %s", 67 | "lambdacontrols.controller.mappings.3": "and paste the mapping in the mappings file editor.", 68 | "lambdacontrols.controller.mappings.error": "Error while loading mappings.", 69 | "lambdacontrols.controller.mappings.error.write": "Error while writing mappings to file.", 70 | "lambdacontrols.controller.mappings.updated": "Updated mappings!", 71 | "lambdacontrols.controller_type.default": "default", 72 | "lambdacontrols.controller_type.dualshock": "DualShock", 73 | "lambdacontrols.controller_type.switch": "Switch", 74 | "lambdacontrols.controller_type.xbox": "Xbox", 75 | "lambdacontrols.controller_type.steam": "Steam", 76 | "lambdacontrols.controller_type.ouya": "OUYA", 77 | "lambdacontrols.controls_mode.default": "Keyboard/Mouse", 78 | "lambdacontrols.controls_mode.controller": "Controller", 79 | "lambdacontrols.controls_mode.touchscreen": "Touchscreen", 80 | "lambdacontrols.hud_side.left": "left", 81 | "lambdacontrols.hud_side.right": "right", 82 | "lambdacontrols.menu.analog_movement": "Analog Movement", 83 | "lambdacontrols.menu.auto_switch_mode": "Auto Switch Mode", 84 | "lambdacontrols.menu.controller": "Controller", 85 | "lambdacontrols.menu.controller2": "Second Controller", 86 | "lambdacontrols.menu.controller_type": "Controller Type", 87 | "lambdacontrols.menu.controls_mode": "Mode", 88 | "lambdacontrols.menu.fast_block_placing": "Fast Block Placing", 89 | "lambdacontrols.menu.fly_drifting": "Fly Drifting", 90 | "lambdacontrols.menu.fly_drifting_vertical": "Vertical Fly Drifting", 91 | "lambdacontrols.menu.hud_enable": "Enable HUD", 92 | "lambdacontrols.menu.hud_side": "HUD Side", 93 | "lambdacontrols.menu.invert_right_x_axis": "Invert Right X", 94 | "lambdacontrols.menu.invert_right_y_axis": "Invert Right Y", 95 | "lambdacontrols.menu.keyboard_controls": "Keyboard Controls...", 96 | "lambdacontrols.menu.left_dead_zone": "Left Dead Zone", 97 | "lambdacontrols.menu.mappings.open_input_str": "Open Mappings File Editor", 98 | "lambdacontrols.menu.max_left_x_value": "Left X Axis Max Value", 99 | "lambdacontrols.menu.max_left_y_value": "Left Y Axis Max Value", 100 | "lambdacontrols.menu.max_right_x_value": "Right X Axis Max Value", 101 | "lambdacontrols.menu.max_right_y_value": "Right Y Axis Max Value", 102 | "lambdacontrols.menu.mouse_speed": "Mouse Speed", 103 | "lambdacontrols.menu.reacharound.horizontal": "Front Block Placing", 104 | "lambdacontrols.menu.reacharound.vertical": "Vertical Reacharound", 105 | "lambdacontrols.menu.reload_controller_mappings": "Reload Controller Mappings", 106 | "lambdacontrols.menu.right_dead_zone": "Right Dead Zone", 107 | "lambdacontrols.menu.rotation_speed": "Rotation Speed", 108 | "lambdacontrols.menu.separator.controller": "Controller", 109 | "lambdacontrols.menu.separator.general": "General", 110 | "lambdacontrols.menu.title": "LambdaControls - Settings", 111 | "lambdacontrols.menu.title.controller": "Controller Options", 112 | "lambdacontrols.menu.title.controller_controls": "Controller Controls", 113 | "lambdacontrols.menu.title.gameplay": "Gameplay Options", 114 | "lambdacontrols.menu.title.general": "General Options", 115 | "lambdacontrols.menu.title.hud": "HUD Options", 116 | "lambdacontrols.menu.title.mappings.string": "Mappings File Editor", 117 | "lambdacontrols.menu.title.visual": "Appearance Options", 118 | "lambdacontrols.menu.unfocused_input": "Unfocused Input", 119 | "lambdacontrols.menu.virtual_mouse": "Virtual Mouse", 120 | "lambdacontrols.menu.virtual_mouse.skin": "Virtual Mouse Skin", 121 | "lambdacontrols.narrator.unbound": "Unbound %s", 122 | "lambdacontrols.not_bound": "Not bound", 123 | "lambdacontrols.tooltip.analog_movement": "Enables analog movement when possible.", 124 | "lambdacontrols.tooltip.auto_switch_mode": "If the controls mode should be switched to Controller automatically if one is connected.", 125 | "lambdacontrols.tooltip.controller2": "Second controller to use, which allows Joy-Cons support for example.", 126 | "lambdacontrols.tooltip.controller_type": "The controller type to display the correct buttons.", 127 | "lambdacontrols.tooltip.controls_mode": "The controls mode.", 128 | "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.", 129 | "lambdacontrols.tooltip.fly_drifting": "While flying, enables Vanilla drifting/inertia.", 130 | "lambdacontrols.tooltip.fly_drifting_vertical": "While flying, enables Vanilla vertical drifting/intertia.", 131 | "lambdacontrols.tooltip.hud_enable": "Toggles the on-screen controller button indicator.", 132 | "lambdacontrols.tooltip.hud_side": "The position of the HUD.", 133 | "lambdacontrols.tooltip.left_dead_zone": "The dead zone for the controller's left analogue stick.", 134 | "lambdacontrols.tooltip.max_left_x_value": "Changes what the mod considers the highest value for the left X axis. Useful if your axis does not use the full range and seems slow.", 135 | "lambdacontrols.tooltip.max_left_y_value": "Changes what the mod considers the highest value for the left Y axis. Useful if your axis does not use the full range and seems slow.", 136 | "lambdacontrols.tooltip.max_right_x_value": "Changes what the mod considers the highest value for the right X axis. Useful if your axis does not use the full range and seems slow.", 137 | "lambdacontrols.tooltip.max_right_y_value": "Changes what the mod considers the highest value for the right Y axis. Useful if your axis does not use the full range and seems slow.", 138 | "lambdacontrols.tooltip.mouse_speed": "The controller's emulated mouse speed.", 139 | "lambdacontrols.tooltip.reacharound.horizontal": "Enables front block placing, §cmight be considered cheating on some servers§r.", 140 | "lambdacontrols.tooltip.reacharound.vertical": "Enables vertical reacharound, §cmight be considered cheating on some servers§r.", 141 | "lambdacontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file.", 142 | "lambdacontrols.tooltip.right_dead_zone": "The dead zone for the controller's right analogue stick.", 143 | "lambdacontrols.tooltip.rotation_speed": "The camera rotation speed in controller mode.", 144 | "lambdacontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused.", 145 | "lambdacontrols.tooltip.virtual_mouse": "Enable the virtual mouse which is handful in the case of a splitscreen.", 146 | "lambdacontrols.virtual_mouse.skin.default_light": "Default Light", 147 | "lambdacontrols.virtual_mouse.skin.default_dark": "Default Dark", 148 | "lambdacontrols.virtual_mouse.skin.second_light": "Second Light", 149 | "lambdacontrols.virtual_mouse.skin.second_dark": "Second Dark" 150 | } -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/lang/tr_tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "key.lambdacontrols.look_down": "Aşağı bak", 3 | "key.lambdacontrols.look_left": "Sola bak", 4 | "key.lambdacontrols.look_right": "Sağa bak", 5 | "key.lambdacontrols.look_up": "Yukarıya bak", 6 | "key.lambdacontrols.ring": "Kontroller halkasını göster", 7 | "lambdacontrols.action.attack": "Saldırma/Kazma", 8 | "lambdacontrols.action.back": "Geri", 9 | "lambdacontrols.action.chat": "Sohbeti Açma", 10 | "lambdacontrols.action.drop_item": "Seçili Eşyayı Bırakma", 11 | "lambdacontrols.action.exit": "Çık", 12 | "lambdacontrols.action.forward": "İleri", 13 | "lambdacontrols.action.hit": "Vurma", 14 | "lambdacontrols.action.hotbar_left": "Sık Kullanılanlar'da sola git", 15 | "lambdacontrols.action.hotbar_right": "Sık Kullanılanlar'da sağa git", 16 | "lambdacontrols.action.inventory": "Envanter", 17 | "lambdacontrols.action.jump": "Zıplama", 18 | "lambdacontrols.action.left": "Sol", 19 | "lambdacontrols.action.pause_game": "Oyunu durdur", 20 | "lambdacontrols.action.pick_block": "Blok Seçme", 21 | "lambdacontrols.action.pickup": "Al", 22 | "lambdacontrols.action.pickup_all": "Hepsini Al", 23 | "lambdacontrols.action.place": "Yerleştir", 24 | "lambdacontrols.action.player_list": "Oyuncu Listesi", 25 | "lambdacontrols.action.quick_move": "Hızlı Hareket", 26 | "lambdacontrols.action.right": "Sağ", 27 | "lambdacontrols.action.screenshot": "Ekran Görüntüsü Alma", 28 | "lambdacontrols.action.sneak": "Eğilme", 29 | "lambdacontrols.action.sprint": "Koşma", 30 | "lambdacontrols.action.swap_hands": "Ögeyi Elden Ele Değiştir", 31 | "lambdacontrols.action.toggle_perspective": "Perspektifi Değiştirme", 32 | "lambdacontrols.action.toggle_smooth_camera": "Sinemaitk Kameraya Geçme", 33 | "lambdacontrols.action.use": "Kullanma", 34 | "lambdacontrols.action.zoom": "Büyütme", 35 | "lambdacontrols.action.zoom_in": "Büyütmeyi Arttır", 36 | "lambdacontrols.action.zoom_out": "Büyütmeyi Azalt", 37 | "lambdacontrols.action.zoom_reset": "Büyütmeyi Sıfırla", 38 | "lambdacontrols.button.a": "A", 39 | "lambdacontrols.button.b": "B", 40 | "lambdacontrols.button.x": "X", 41 | "lambdacontrols.button.y": "Y", 42 | "lambdacontrols.button.left_bumper": "Sol yassı tuş", 43 | "lambdacontrols.button.right_bumper": "Sağ yassı tuş", 44 | "lambdacontrols.button.back": "Back", 45 | "lambdacontrols.button.start": "Start", 46 | "lambdacontrols.button.guide": "Guide", 47 | "lambdacontrols.button.left_thumb": "Sol çubuk", 48 | "lambdacontrols.button.right_thumb": "Sağ çubuk", 49 | "lambdacontrols.button.dpad_up": "Yukarı yön tuşu", 50 | "lambdacontrols.button.dpad_right": "Sağ yön tuşu", 51 | "lambdacontrols.button.dpad_down": "Aşağı yön tuşu", 52 | "lambdacontrols.button.dpad_left": "Sol yön tuşu", 53 | "lambdacontrols.axis.left_x+": "Sol X+", 54 | "lambdacontrols.axis.left_y+": "Sol Y+", 55 | "lambdacontrols.axis.right_x+": "Sağ X+", 56 | "lambdacontrols.axis.right_y+": "Sağ Y+", 57 | "lambdacontrols.axis.left_trigger": "Sol tetik tuşu", 58 | "lambdacontrols.axis.right_trigger": "Sağ tetik tuşu", 59 | "lambdacontrols.axis.left_x-": "Sol X-", 60 | "lambdacontrols.axis.left_y-": "Sol Y-", 61 | "lambdacontrols.axis.right_x-": "Sağ X-", 62 | "lambdacontrols.axis.right_y-": "Sağ Y-", 63 | "lambdacontrols.button.unknown": "Bilinmeyen (%d)", 64 | "lambdacontrols.controller.connected": "%d oyun kolu bağlandı.", 65 | "lambdacontrols.controller.disconnected": "%d oyun kolunun bağlantısı kesildi.", 66 | "lambdacontrols.controller.mappings.1": "Oyun kolunun tuş eşleştirme ayarını yapacaksanız, lütfen sunu kullanın: %sSDL2 Gamepad Tool%s", 67 | "lambdacontrols.controller.mappings.3": "ve eşleştirme dosyasını da şuraya koyun: `%s.minecraft/config/gamecontrollerdb.txt%s`.", 68 | "lambdacontrols.controller.mappings.error": "Eşleştirme yüklenirken hata oluştu.", 69 | "lambdacontrols.controller.mappings.error.write": "Dosyaya eşleştirme yazılırken hata oluştu.", 70 | "lambdacontrols.controller.mappings.updated": "Eşleştirme güncellendi!", 71 | "lambdacontrols.controller_type.default": "varsayılan", 72 | "lambdacontrols.controller_type.dualshock": "DualShock", 73 | "lambdacontrols.controller_type.switch": "Switch", 74 | "lambdacontrols.controller_type.xbox": "Xbox", 75 | "lambdacontrols.controller_type.steam": "Steam", 76 | "lambdacontrols.controller_type.ouya": "OUYA", 77 | "lambdacontrols.controls_mode.default": "Klavye/Fare", 78 | "lambdacontrols.controls_mode.controller": "Oyun Kolu", 79 | "lambdacontrols.controls_mode.touchscreen": "Dokunmatik Ekran", 80 | "lambdacontrols.hud_side.left": "sol", 81 | "lambdacontrols.hud_side.right": "sağ", 82 | "lambdacontrols.menu.auto_switch_mode": "Otomatik Değiştirme Modu", 83 | "lambdacontrols.menu.controller": "Oyun Kolu", 84 | "lambdacontrols.menu.controller2": "İkincil Oyun Kolu", 85 | "lambdacontrols.menu.controller_type": "Oyun Kolu Türü", 86 | "lambdacontrols.menu.controls_mode": "Mod", 87 | "lambdacontrols.menu.dead_zone": "Ölü Bölge", 88 | "lambdacontrols.menu.fast_block_placing": "Hızlı Blok Yerleştirme", 89 | "lambdacontrols.menu.fly_drifting": "Kayarak Uç", 90 | "lambdacontrols.menu.fly_drifting_vertical": "Dikey uçuşta kayaaak git", 91 | "lambdacontrols.menu.hud_enable": "HUD'u Etkinleştir", 92 | "lambdacontrols.menu.hud_side": "HUD Yanı", 93 | "lambdacontrols.menu.invert_right_x_axis": "Sağ X'i Terse Çevir", 94 | "lambdacontrols.menu.invert_right_y_axis": "Sağ Y'i Terse Çevir.", 95 | "lambdacontrols.menu.keyboard_controls": "Klavye Kontrolleri...", 96 | "lambdacontrols.menu.mappings.open_input_str": "Eşleştirme Dosya Editörünü Aç", 97 | "lambdacontrols.menu.mouse_speed": "Fare Hızı", 98 | "lambdacontrols.menu.reacharound.horizontal": "Alt Öne Blok Koyma", 99 | "lambdacontrols.menu.reacharound.vertical": "En Alta Blok Koyma", 100 | "lambdacontrols.menu.reload_controller_mappings": "Oyun Kolu Eşleştirmelerini Yenile", 101 | "lambdacontrols.menu.rotation_speed": "Dönme Hızı", 102 | "lambdacontrols.menu.title": "LambdaControls - Ayarlar", 103 | "lambdacontrols.menu.title.controller": "Oyun Kolu Seçenekleri", 104 | "lambdacontrols.menu.title.controller_controls": "Oyun Kolu Kontrolleri", 105 | "lambdacontrols.menu.title.gameplay": "Oynanış Seçenekleri", 106 | "lambdacontrols.menu.title.general": "Genel Seçenekler", 107 | "lambdacontrols.menu.title.hud": "HUD Seçenekleri", 108 | "lambdacontrols.menu.title.mappings.string": "Eşleştirme Dosya Editörü", 109 | "lambdacontrols.menu.unfocused_input": "Odaklanmamış Giriş Aygıtı", 110 | "lambdacontrols.menu.virtual_mouse": "Sanal Fare", 111 | "lambdacontrols.menu.virtual_mouse.skin": "Sanal Fare Görünümü", 112 | "lambdacontrols.narrator.unbound": "%s Atanmamış", 113 | "lambdacontrols.not_bound": "Tuş ataması yok", 114 | "lambdacontrols.tooltip.auto_switch_mode": "Eğer bir tanesi bağlandıysa, kontrol modu Oyun Kolu olarak değişmeli.", 115 | "lambdacontrols.tooltip.controller2": "Kullanılacak ikinci oyun kolu, örnek olarak Joy-Con desteği de mümkün.", 116 | "lambdacontrols.tooltip.controller_type": "Doğru tuşları göstermesi için oyun kolu türü.", 117 | "lambdacontrols.tooltip.controls_mode": "Kontrol Modu", 118 | "lambdacontrols.tooltip.dead_zone": "Oyun kolunun analog çubukları için ayarlanan ölü bölge/dead zone", 119 | "lambdacontrols.tooltip.fast_block_placing": "Yaratıcı modda uçarken, hızına bağlı olarak hızlı blok koymayı etkinleştirir. §cBazı sunucular bunun hile olduğunu düşünebilir.", 120 | "lambdacontrols.tooltip.fly_drifting": "Uçarken, Vanilla'daki gibi ani duruşlarda kayma efektini etkinleştirir.", 121 | "lambdacontrols.tooltip.fly_drifting_vertical": "Yukarı/aşağı uçarken, Vanilla'daki gibi ani duruşlarda kayma efektini etkinleştirir.", 122 | "lambdacontrols.tooltip.hud_enable": "Ekranın üstünde oyun kolu tuşu göstergesini açar/kapatır.", 123 | "lambdacontrols.tooltip.hud_side": "HUD'un konumu", 124 | "lambdacontrols.tooltip.mouse_speed": "Oyun kolunun taklit edilen fare hızı.", 125 | "lambdacontrols.tooltip.reacharound.horizontal": "Hızlı blok koymayı etkinleştirir. §cBazı sunucular bunun hile olduğunu düşünebilir.§r.", 126 | "lambdacontrols.tooltip.reacharound.vertical": "En alta blok koymayı etkinleştirir. §cBazı sunucular bunun hile olduğunu düşünebilir.§r.", 127 | "lambdacontrols.tooltip.reload_controller_mappings": "Oyun kolu için eşleştirme dosyasını yeniler.", 128 | "lambdacontrols.tooltip.rotation_speed": "Oyun kolu modunda olan kamera dönme hızı", 129 | "lambdacontrols.tooltip.unfocused_input": "Oyun penceresinde değilken oyun kolu girişine izine verir.", 130 | "lambdacontrols.tooltip.virtual_mouse": "Sanal fareyi etkinleştirir. Çift ekran oynanılacağı zaman işe yarar.", 131 | "lambdacontrols.virtual_mouse.skin.default_light": "Varsayılan Aydınlık Tema", 132 | "lambdacontrols.virtual_mouse.skin.default_dark": "Varsayılan Karanlık Tema", 133 | "lambdacontrols.virtual_mouse.skin.second_light": "İkincil Aydınlık Tema", 134 | "lambdacontrols.virtual_mouse.skin.second_dark": "İkincil Karanlık Tema" 135 | } 136 | -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "key.lambdacontrols.look_down": "视角下移", 3 | "key.lambdacontrols.look_left": "视角左移", 4 | "key.lambdacontrols.look_right": "视角右移", 5 | "key.lambdacontrols.look_up": "视角上移", 6 | "key.lambdacontrols.ring": "显示额外按键菜单", 7 | "lambdacontrols.action.attack": "攻击", 8 | "lambdacontrols.action.back": "向后移动", 9 | "lambdacontrols.action.chat": "打开聊天栏", 10 | "lambdacontrols.action.drop_item": "丢弃所选物品", 11 | "lambdacontrols.action.exit": "退出", 12 | "lambdacontrols.action.forward": "向前移动", 13 | "lambdacontrols.action.hit": "挖掘", 14 | "lambdacontrols.action.hotbar_left": "向左循环选择快捷栏", 15 | "lambdacontrols.action.hotbar_right": "向右循环选择快捷栏", 16 | "lambdacontrols.action.inventory": "物品栏", 17 | "lambdacontrols.action.jump": "跳跃", 18 | "lambdacontrols.action.left": "向左移动", 19 | "lambdacontrols.action.pause_game": "暂停游戏", 20 | "lambdacontrols.action.pick_block": "选取方块", 21 | "lambdacontrols.action.pickup": "拿取一个/拿取一半", 22 | "lambdacontrols.action.pickup_all": "拿取一组/拿取全部", 23 | "lambdacontrols.action.place": "放置方块", 24 | "lambdacontrols.action.player_list": "玩家列表", 25 | "lambdacontrols.action.quick_move": "快速移动物品", 26 | "lambdacontrols.action.right": "向右移动", 27 | "lambdacontrols.action.screenshot": "截图", 28 | "lambdacontrols.action.sneak": "潜行", 29 | "lambdacontrols.action.sprint": "疾跑", 30 | "lambdacontrols.action.swap_hands": "与副手交换", 31 | "lambdacontrols.action.toggle_perspective": "切换视角", 32 | "lambdacontrols.action.toggle_smooth_camera": "切换电影视角", 33 | "lambdacontrols.action.use": "使用物品/放置方块", 34 | "lambdacontrols.action.zoom": "视野缩放", 35 | "lambdacontrols.action.zoom_in": "缩放时将视野推近", 36 | "lambdacontrols.action.zoom_out": "缩放时将视野拉远", 37 | "lambdacontrols.action.zoom_reset": "缩放时重置缩放距离", 38 | "lambdacontrols.button.a": "A", 39 | "lambdacontrols.button.b": "B", 40 | "lambdacontrols.button.x": "X", 41 | "lambdacontrols.button.y": "Y", 42 | "lambdacontrols.button.left_bumper": "左肩键", 43 | "lambdacontrols.button.right_bumper": "右肩键", 44 | "lambdacontrols.button.back": "选择键", 45 | "lambdacontrols.button.start": "开始键", 46 | "lambdacontrols.button.guide": "功能键", 47 | "lambdacontrols.button.left_thumb": "左摇杆(按压)", 48 | "lambdacontrols.button.right_thumb": "右摇杆(按压)", 49 | "lambdacontrols.button.dpad_up": "十字键上", 50 | "lambdacontrols.button.dpad_right": "十字键右", 51 | "lambdacontrols.button.dpad_down": "十字键下", 52 | "lambdacontrols.button.dpad_left": "十字键左", 53 | "lambdacontrols.axis.left_x+": "左摇杆右(X轴正向)", 54 | "lambdacontrols.axis.left_y+": "左摇杆上(Y轴正向)", 55 | "lambdacontrols.axis.right_x+": "右摇杆右(X轴正向)", 56 | "lambdacontrols.axis.right_y+": "右摇杆上(Y轴正向)", 57 | "lambdacontrols.axis.left_trigger": "左扳机键", 58 | "lambdacontrols.axis.right_trigger": "右扳机键", 59 | "lambdacontrols.axis.left_x-": "左摇杆左(X轴负向)", 60 | "lambdacontrols.axis.left_y-": "左摇杆下(Y轴负向)", 61 | "lambdacontrols.axis.right_x-": "右摇杆左(X轴负向)", 62 | "lambdacontrols.axis.right_y-": "右摇杆下(Y轴负向)", 63 | "lambdacontrols.button.unknown": "未知(%d)", 64 | "lambdacontrols.controller.connected": "手柄 %d 已连接。", 65 | "lambdacontrols.controller.disconnected": "手柄 %d 已断开。", 66 | "lambdacontrols.controller.mappings.1": "请使用 %s 配置手柄按键映射", 67 | "lambdacontrols.controller.mappings.3": "并将按键映射文件放入此路径:`%s.minecraft/config/gamecontrollerdb.txt%s`。", 68 | "lambdacontrols.controller.mappings.error": "发生错误,无法读取按键映射文件。", 69 | "lambdacontrols.controller.mappings.error.write": "发生错误,无法保存按键映射文件。", 70 | "lambdacontrols.controller.mappings.updated": "按键映射已更新!", 71 | "lambdacontrols.controller_type.default": "默认", 72 | "lambdacontrols.controller_type.dualshock": "DualShock", 73 | "lambdacontrols.controller_type.switch": "Switch", 74 | "lambdacontrols.controller_type.xbox": "Xbox", 75 | "lambdacontrols.controller_type.steam": "Steam", 76 | "lambdacontrols.controller_type.ouya": "OUYA", 77 | "lambdacontrols.controls_mode.default": "键鼠", 78 | "lambdacontrols.controls_mode.controller": "手柄", 79 | "lambdacontrols.controls_mode.touchscreen": "触摸屏", 80 | "lambdacontrols.hud_side.left": "左侧", 81 | "lambdacontrols.hud_side.right": "右侧", 82 | "lambdacontrols.menu.analog_movement": "识别摇杆输入的精确值", 83 | "lambdacontrols.menu.auto_switch_mode": "自动切换模式", 84 | "lambdacontrols.menu.controller": "手柄", 85 | "lambdacontrols.menu.controller2": "额外手柄", 86 | "lambdacontrols.menu.controller_type": "手柄类型", 87 | "lambdacontrols.menu.controls_mode": "模式", 88 | "lambdacontrols.menu.fast_block_placing": "方块快速放置", 89 | "lambdacontrols.menu.fly_drifting": "水平方向飞行惯性", 90 | "lambdacontrols.menu.fly_drifting_vertical": "垂直方向飞行惯性", 91 | "lambdacontrols.menu.hud_enable": "启用HUD", 92 | "lambdacontrols.menu.hud_side": "HUD位置", 93 | "lambdacontrols.menu.invert_right_x_axis": "反转右摇杆X轴", 94 | "lambdacontrols.menu.invert_right_y_axis": "反转右摇杆Y轴", 95 | "lambdacontrols.menu.keyboard_controls": "键盘控制…", 96 | "lambdacontrols.menu.left_dead_zone": "左摇杆死区", 97 | "lambdacontrols.menu.mappings.open_input_str": "编辑按键映射文件", 98 | "lambdacontrols.menu.max_left_x_value": "左摇杆X轴最大值识别范围", 99 | "lambdacontrols.menu.max_left_y_value": "左摇杆Y轴最大值识别范围", 100 | "lambdacontrols.menu.max_right_x_value": "右摇杆X轴最大值识别范围", 101 | "lambdacontrols.menu.max_right_y_value": "右摇杆Y轴最大值识别范围", 102 | "lambdacontrols.menu.mouse_speed": "鼠标移动速度", 103 | "lambdacontrols.menu.reacharound.horizontal": "水平方向方块放置辅助", 104 | "lambdacontrols.menu.reacharound.vertical": "垂直方向方块放置辅助", 105 | "lambdacontrols.menu.reload_controller_mappings": "重新加载手柄按键映射", 106 | "lambdacontrols.menu.right_dead_zone": "右摇杆死区", 107 | "lambdacontrols.menu.rotation_speed": "镜头旋转速度", 108 | "lambdacontrols.menu.separator.controller": "手柄", 109 | "lambdacontrols.menu.separator.general": "通用", 110 | "lambdacontrols.menu.title": "LambdaControls — 设置", 111 | "lambdacontrols.menu.title.controller": "手柄选项", 112 | "lambdacontrols.menu.title.controller_controls": "手柄控制", 113 | "lambdacontrols.menu.title.gameplay": "游戏内容选项", 114 | "lambdacontrols.menu.title.general": "通用选项", 115 | "lambdacontrols.menu.title.hud": "HUD选项", 116 | "lambdacontrols.menu.title.mappings.string": "编辑按键映射文件", 117 | "lambdacontrols.menu.title.visual": "界面选项", 118 | "lambdacontrols.menu.unfocused_input": "非活动状态输入", 119 | "lambdacontrols.menu.virtual_mouse": "虚拟鼠标", 120 | "lambdacontrols.menu.virtual_mouse.skin": "虚拟鼠标指针样式", 121 | "lambdacontrols.narrator.unbound": "取消绑定 %s", 122 | "lambdacontrols.not_bound": "未绑定", 123 | "lambdacontrols.tooltip.analog_movement": "若游戏机制允许,则可根据推动摇杆的力度与幅度决定移动的速度。", 124 | "lambdacontrols.tooltip.auto_switch_mode": "如果已有手柄连接,则自动切换为手柄操作模式。", 125 | "lambdacontrols.tooltip.controller2": "使用额外的手柄,比如将一左一右的两个 Joy-Con 合为一个功能完全的手柄。", 126 | "lambdacontrols.tooltip.controller_type": "选择手柄类型,以显示对应的按键图标。", 127 | "lambdacontrols.tooltip.controls_mode": "操作模式", 128 | "lambdacontrols.tooltip.fast_block_placing": "在创造模式中处于飞行状态时,可以根据你飞行的速度快速放置方块。\n§c在部分服务器可能会被认定为作弊。", 129 | "lambdacontrols.tooltip.fly_drifting": "处于飞行状态时,启用原版的水平方向飞行惯性(缓停滑行)。", 130 | "lambdacontrols.tooltip.fly_drifting_vertical": "处于飞行状态时,启用原版的垂直方向飞行惯性(缓停滑行)。", 131 | "lambdacontrols.tooltip.hud_enable": "显示手柄按键操作提示。", 132 | "lambdacontrols.tooltip.hud_side": "HUD的位置位于画面的哪一侧。", 133 | "lambdacontrols.tooltip.left_dead_zone": "左摇杆配置的死区。\n死区决定摇杆要偏离中心位置多远才能让摇杆的输入有效。", 134 | "lambdacontrols.tooltip.max_left_x_value": "更改左摇杆X轴最大值的识别范围。\n若感觉即便推满摇杆也未达到最大的输入值,导致在识别摇杆输入的精确值的情况下,左右移动较为缓慢等问题,本项可能会有所帮助。", 135 | "lambdacontrols.tooltip.max_left_y_value": "更改左摇杆Y轴最大值的识别范围。\n若感觉即便推满摇杆也未达到最大的输入值,导致在识别摇杆输入的精确值的情况下,前后移动较为缓慢等问题,本项可能会有所帮助。", 136 | "lambdacontrols.tooltip.max_right_x_value": "更改右摇杆X轴最大值的识别范围。\n若感觉即便推满摇杆也未达到最大的输入值,导致镜头左右旋转较为缓慢等问题,本项可能会有所帮助。", 137 | "lambdacontrols.tooltip.max_right_y_value": "更改右摇杆Y轴最大值的识别范围。\n若感觉即便推满摇杆也未达到最大的输入值,导致镜头上下旋转较为缓慢等问题,本项可能会有所帮助。", 138 | "lambdacontrols.tooltip.mouse_speed": "手柄模拟的鼠标的移动速度。", 139 | "lambdacontrols.tooltip.reacharound.horizontal": "启用水平方向方块放置辅助,可在脚下方块的前方放置方块。\n§c在部分服务器可能会被认定为作弊。", 140 | "lambdacontrols.tooltip.reacharound.vertical": "启用垂直方向方块放置辅助,可在脚下方块的下方放置方块。\n§c在部分服务器可能会被认定为作弊。", 141 | "lambdacontrols.tooltip.reload_controller_mappings": "重新加载手柄的按键映射文件。", 142 | "lambdacontrols.tooltip.right_dead_zone": "右摇杆配置的死区。\n死区决定摇杆要偏离中心位置多远才能让摇杆的输入有效。", 143 | "lambdacontrols.tooltip.rotation_speed": "手柄操作模式下的镜头旋转速度。", 144 | "lambdacontrols.tooltip.unfocused_input": "即使游戏窗口处于非活动状态,也允许手柄进行按键输入。", 145 | "lambdacontrols.tooltip.virtual_mouse": "启用虚拟鼠标,在分屏的情况下很有用。", 146 | "lambdacontrols.virtual_mouse.skin.default_light": "默认样式(白色)", 147 | "lambdacontrols.virtual_mouse.skin.default_dark": "默认样式(黑色)", 148 | "lambdacontrols.virtual_mouse.skin.second_light": "额外样式(白色)", 149 | "lambdacontrols.virtual_mouse.skin.second_dark": "额外样式(黑色)" 150 | } 151 | -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/textures/gui/controller_axis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/src/main/resources/assets/lambdacontrols/textures/gui/controller_axis.png -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/textures/gui/controller_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/src/main/resources/assets/lambdacontrols/textures/gui/controller_buttons.png -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/textures/gui/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/src/main/resources/assets/lambdacontrols/textures/gui/cursor.png -------------------------------------------------------------------------------- /src/main/resources/assets/lambdacontrols/textures/gui/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LambdAurora/LambdaControls/bfaa4f5d9adf396c888a2004d0c6feeaf1c04884/src/main/resources/assets/lambdacontrols/textures/gui/widgets.png -------------------------------------------------------------------------------- /src/main/resources/config.toml: -------------------------------------------------------------------------------- 1 | # LambdaControls configuration. 2 | 3 | # The controls mode. Available modes: default, controller, touchscreen 4 | controls = "default" 5 | # Auto switch mode. 6 | auto_switch_mode = false 7 | # Debug mode 8 | debug = false 9 | 10 | [hud] 11 | # Enables the HUD. 12 | enable = true 13 | # Dertermines where the movements buttons are. 14 | side = "left" 15 | 16 | # Gameplay settings 17 | [gameplay] 18 | # Enables fast block placing like in Bedrock Edition. 19 | fast_block_placing = true 20 | # Enables analogic movement if possible. 21 | analog_movement = true 22 | # Fly behaviors 23 | [gameplay.fly] 24 | # Enables fly drifting. 25 | drifting = false 26 | # Enables vertical fly drifting. 27 | vertical_drifting = true 28 | [gameplay.reacharound] 29 | # Enables front block placing like in Bedrock Edition. 30 | horizontal = false 31 | # Enables vertical reacharound. 32 | vertical = false 33 | # Enables front block placing outline. 34 | outline = true 35 | # The color in a hexadecimal format of the outline. 36 | outline_color = "#ffffff66" 37 | 38 | # Controller settings 39 | [controller] 40 | # Controller to use. 41 | id = 0 42 | # Second controller to use. 43 | id2 = -1 44 | # Controller's type. 45 | type = "default" 46 | # Controller's dead zone. 47 | dead_zone = 0.20 48 | # Rotation speed for look directions. 49 | rotation_speed = 10.0 50 | # Mouse speed in GUI. 51 | mouse_speed = 30.0 52 | # Inverts the right X axis. 53 | invert_right_x_axis = false 54 | # Inverts the right Y axis. 55 | invert_right_y_axis = false 56 | # Allow unfocused input. 57 | unfocused_input = false 58 | # Virtual mouse. 59 | virtual_mouse = false 60 | # Virtual mouse skin 61 | virtual_mouse_skin = "default_light" 62 | # Controller controls. 63 | [controller.controls] 64 | # Attack control. 65 | attack = "105" 66 | # Back control. 67 | back = "201" 68 | # Open chat control. 69 | chat = "12" 70 | # Drop item control. 71 | drop_item = "1" 72 | # Forward control. 73 | forward = "101" 74 | # Hot-bar left control. 75 | hotbar_left = "4" 76 | # Hot-bar right control. 77 | hotbar_right = "5" 78 | # Inventory control. 79 | inventory = "3" 80 | # Jump control. 81 | jump = "0" 82 | # Left movement control. 83 | left = "200" 84 | # Pause game control. 85 | pause_game = "7" 86 | # Pick block control. 87 | pick_block = "14" 88 | # Show player list control. 89 | player_list = "6" 90 | # Right movement control. 91 | right = "100" 92 | # Take screenshot control. 93 | screenshot = "11+0" 94 | # Down slot control. 95 | slot_down = "13" 96 | # Left slot control. 97 | slot_left = "14" 98 | # Right slot control. 99 | slot_right = "12" 100 | # Up slot control. 101 | slot_up = "11" 102 | # Sneak control. 103 | sneak = "10" 104 | # Sprint control. 105 | sprint = "9" 106 | # Swap hands control. 107 | swap_hands = "2" 108 | # Switch to back tab control. 109 | tab_back = "4" 110 | # Switch to next tab control. 111 | tab_next = "5" 112 | # Toggle perspective control. 113 | toggle_perspective = "11+3" 114 | # Toggle smooth camera control. 115 | toggle_smooth_camera = "-1" 116 | # Use control. 117 | use = "104" 118 | # Zoom control. 119 | zoom = "11+2" 120 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "lambdacontrols", 4 | "name": "LambdaControls", 5 | "version": "${version}", 6 | "description": "Adds better controls, and controller support.", 7 | "authors": [ 8 | "LambdAurora" 9 | ], 10 | "contact": { 11 | "homepage": "https://modrinth.com/mod/lambdacontrols", 12 | "sources": "https://github.com/LambdAurora/LambdaControls.git", 13 | "issues": "https://github.com/LambdAurora/LambdaControls/issues" 14 | }, 15 | "license": "MIT", 16 | "icon": "assets/lambdacontrols/icon.png", 17 | "environment": "client", 18 | "entrypoints": { 19 | "main": [ 20 | "dev.lambdaurora.lambdacontrols.LambdaControls" 21 | ], 22 | "client": [ 23 | "dev.lambdaurora.lambdacontrols.client.LambdaControlsClient" 24 | ], 25 | "modmenu": [ 26 | "dev.lambdaurora.lambdacontrols.client.LambdaControlsModMenu" 27 | ] 28 | }, 29 | "accessWidener": "lambdacontrols.accesswidener", 30 | "mixins": [ 31 | "lambdacontrols.mixins.json", 32 | "lambdacontrols_compat.mixins.json" 33 | ], 34 | "depends": { 35 | "fabricloader": ">=0.11.3", 36 | "fabric": ">=0.36.0", 37 | "minecraft": ">=1.17", 38 | "spruceui": ">=3.2.0", 39 | "java": ">=16" 40 | }, 41 | "recommends": { 42 | "modmenu": ">=1.12.2" 43 | }, 44 | "suggests": { 45 | "flamingo": "*" 46 | }, 47 | "breaks": { 48 | "modmenu": "<1.12.2", 49 | "optifabric": "*" 50 | }, 51 | "custom": { 52 | "modupdater": { 53 | "strategy": "curseforge", 54 | "projectID": 354231 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/resources/lambdacontrols.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v1 named 2 | 3 | accessible class net/minecraft/client/gui/widget/EntryListWidget$MoveDirection -------------------------------------------------------------------------------- /src/main/resources/lambdacontrols.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "dev.lambdaurora.lambdacontrols.client.mixin", 4 | "compatibilityLevel": "JAVA_16", 5 | "client": [ 6 | "ClickableWidgetAccessor", 7 | "AdvancementsScreenAccessor", 8 | "ClientPlayerEntityMixin", 9 | "ControlsOptionsScreenMixin", 10 | "CreativeInventoryScreenAccessor", 11 | "EntryListWidgetAccessor", 12 | "GameOptionsMixin", 13 | "GameRendererMixin", 14 | "HandledScreenMixin", 15 | "KeyBindingMixin", 16 | "MinecraftClientMixin", 17 | "MouseMixin", 18 | "OptionsScreenMixin", 19 | "RecipeBookWidgetAccessor", 20 | "WorldRendererMixin" 21 | ], 22 | "injectors": { 23 | "defaultRequire": 1 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/lambdacontrols_compat.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "dev.lambdaurora.lambdacontrols.client.compat.mixin", 4 | "plugin": "dev.lambdaurora.lambdacontrols.client.compat.LambdaControlsMixinPlugin", 5 | "compatibilityLevel": "JAVA_16", 6 | "client": [ 7 | ], 8 | "injectors": { 9 | "defaultRequire": 1 10 | } 11 | } 12 | --------------------------------------------------------------------------------