├── .gitattributes
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .idea
└── scopes
│ ├── Fabric_sources.xml
│ └── Forge_sources.xml
├── LICENSE
├── LICENSE_ControllableSDL
├── LICENSE_GameControllerDB
├── Project.xml
├── README.md
├── build.gradle
├── buildSrc
├── build.gradle
└── src
│ └── main
│ └── groovy
│ ├── multiloader-common.gradle
│ └── multiloader-loader.gradle
├── common
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── mrcrayfish
│ │ └── controllable
│ │ ├── Config.java
│ │ ├── Constants.java
│ │ ├── Controllable.java
│ │ ├── client
│ │ ├── Action.java
│ │ ├── ActionDescriptions.java
│ │ ├── CameraHandler.java
│ │ ├── ClientBootstrap.java
│ │ ├── ControllerEvents.java
│ │ ├── InputHandler.java
│ │ ├── InputProcessor.java
│ │ ├── RadialMenu.java
│ │ ├── RumbleHandler.java
│ │ ├── ScrollingHandler.java
│ │ ├── VirtualCursor.java
│ │ ├── binding
│ │ │ ├── BindingRegistry.java
│ │ │ ├── ButtonBinding.java
│ │ │ ├── ButtonBindings.java
│ │ │ ├── KeyAdapterBinding.java
│ │ │ ├── context
│ │ │ │ ├── BindingContext.java
│ │ │ │ ├── GlobalContext.java
│ │ │ │ ├── InGameContext.java
│ │ │ │ ├── InGameWithScreenContext.java
│ │ │ │ ├── InScreenContext.java
│ │ │ │ └── rule
│ │ │ │ │ ├── ContextRule.java
│ │ │ │ │ ├── HasPlayerRule.java
│ │ │ │ │ ├── HasScreenRule.java
│ │ │ │ │ └── NoScreenRule.java
│ │ │ └── handlers
│ │ │ │ ├── ButtonHandler.java
│ │ │ │ ├── EmptyHandler.java
│ │ │ │ ├── MovementInputHandler.java
│ │ │ │ ├── OnPressAndReleaseHandler.java
│ │ │ │ ├── OnPressHandler.java
│ │ │ │ ├── OnReleaseHandler.java
│ │ │ │ ├── RenderingHandler.java
│ │ │ │ ├── TickingHandler.java
│ │ │ │ ├── action
│ │ │ │ ├── BindingMovementInput.java
│ │ │ │ ├── BindingOnRender.java
│ │ │ │ ├── BindingOnTick.java
│ │ │ │ ├── BindingPressed.java
│ │ │ │ ├── BindingReleased.java
│ │ │ │ └── context
│ │ │ │ │ ├── Context.java
│ │ │ │ │ ├── MovementInputContext.java
│ │ │ │ │ └── RenderingContext.java
│ │ │ │ └── impl
│ │ │ │ ├── AttackHandler.java
│ │ │ │ ├── DropHandler.java
│ │ │ │ ├── QuickMoveHandler.java
│ │ │ │ └── SneakHandler.java
│ │ ├── gui
│ │ │ ├── ControllerAxis.java
│ │ │ ├── ControllerButton.java
│ │ │ ├── ISearchable.java
│ │ │ ├── Icons.java
│ │ │ ├── RadialItemList.java
│ │ │ ├── RadialMenuAction.java
│ │ │ ├── components
│ │ │ │ ├── ButtonBindingList.java
│ │ │ │ ├── ControllerList.java
│ │ │ │ ├── FilteredItem.java
│ │ │ │ ├── FilteredTabSelectionList.java
│ │ │ │ ├── TabOptionBaseItem.java
│ │ │ │ ├── TabOptionEnumItem.java
│ │ │ │ ├── TabOptionSliderItem.java
│ │ │ │ ├── TabOptionTitleItem.java
│ │ │ │ ├── TabOptionToggleItem.java
│ │ │ │ └── TabSelectionList.java
│ │ │ ├── navigation
│ │ │ │ ├── BasicNavigationPoint.java
│ │ │ │ ├── HideCursor.java
│ │ │ │ ├── ListEntryNavigationPoint.java
│ │ │ │ ├── ListWidgetNavigationPoint.java
│ │ │ │ ├── Navigatable.java
│ │ │ │ ├── NavigationPoint.java
│ │ │ │ ├── SkipItem.java
│ │ │ │ ├── SlotNavigationPoint.java
│ │ │ │ └── WidgetNavigationPoint.java
│ │ │ ├── screens
│ │ │ │ ├── ButtonBindingListMenuScreen.java
│ │ │ │ ├── ConfirmationScreen.java
│ │ │ │ ├── ControllerLayoutScreen.java
│ │ │ │ ├── KeyBindingListMenuScreen.java
│ │ │ │ ├── ListMenuScreen.java
│ │ │ │ ├── PendingScreen.java
│ │ │ │ ├── RadialMenuAddBindingsScreen.java
│ │ │ │ ├── RadialMenuConfigureScreen.java
│ │ │ │ ├── SelectKeyBindingScreen.java
│ │ │ │ ├── SettingsScreen.java
│ │ │ │ └── ThumbstickSettingsScreen.java
│ │ │ ├── toasts
│ │ │ │ └── ConnectionToast.java
│ │ │ └── widget
│ │ │ │ ├── BackgroundStringWidget.java
│ │ │ │ ├── ButtonBindingButton.java
│ │ │ │ ├── ColorButton.java
│ │ │ │ ├── ControllerButton.java
│ │ │ │ ├── ImageButton.java
│ │ │ │ ├── LazySlider.java
│ │ │ │ ├── TabListWidget.java
│ │ │ │ └── TabNavigationHint.java
│ │ ├── input
│ │ │ ├── AdaptiveControllerManager.java
│ │ │ ├── ButtonStates.java
│ │ │ ├── Buttons.java
│ │ │ ├── Controller.java
│ │ │ ├── DeviceInfo.java
│ │ │ ├── InputLibrary.java
│ │ │ ├── MultiController.java
│ │ │ ├── glfw
│ │ │ │ ├── GLFWController.java
│ │ │ │ └── GLFWControllerManager.java
│ │ │ └── sdl2
│ │ │ │ ├── SDL2Controller.java
│ │ │ │ └── SDL2ControllerManager.java
│ │ ├── overlay
│ │ │ ├── ActionHintOverlay.java
│ │ │ ├── IOverlay.java
│ │ │ ├── OverlayRenderer.java
│ │ │ ├── PaperDollPlayerOverlay.java
│ │ │ ├── RadialMenuOverlay.java
│ │ │ ├── RecipeBookOverlay.java
│ │ │ ├── TabNavigationOverlay.java
│ │ │ └── VirtualCursorOverlay.java
│ │ ├── settings
│ │ │ ├── ActionVisibility.java
│ │ │ ├── AnalogMovement.java
│ │ │ ├── ButtonIcons.java
│ │ │ ├── CursorStyle.java
│ │ │ ├── SettingEnum.java
│ │ │ ├── SettingProvider.java
│ │ │ ├── SneakMode.java
│ │ │ ├── SprintMode.java
│ │ │ ├── Thumbstick.java
│ │ │ └── VanillaSetting.java
│ │ └── util
│ │ │ ├── ClientHelper.java
│ │ │ ├── EventHelper.java
│ │ │ ├── InputHelper.java
│ │ │ ├── MouseHooks.java
│ │ │ ├── MutableClientInput.java
│ │ │ └── ScreenHelper.java
│ │ ├── event
│ │ ├── ControllerEvents.java
│ │ └── Value.java
│ │ ├── integration
│ │ ├── ControllableJeiPlugin.java
│ │ ├── EmiSupport.java
│ │ ├── JeiSupport.java
│ │ └── ReiSupport.java
│ │ ├── mixin
│ │ └── client
│ │ │ ├── ClientRecipeBookMixin.java
│ │ │ ├── ContainerScreenMixin.java
│ │ │ ├── GameRendererMixin.java
│ │ │ ├── GuiMixin.java
│ │ │ ├── LocalPlayerMixin.java
│ │ │ ├── MinecraftMixin.java
│ │ │ ├── MouseHandlerMixin.java
│ │ │ ├── MouseHelperMixin.java
│ │ │ ├── OverlayRecipeComponentAccessor.java
│ │ │ ├── RecipeBookComponentAccessor.java
│ │ │ ├── RecipeBookPageAccessor.java
│ │ │ ├── RecipeBookPageMixin.java
│ │ │ ├── TimerAccessor.java
│ │ │ ├── jei
│ │ │ ├── GuiIconToggleButtonMixin.java
│ │ │ ├── IngredientGridMixin.java
│ │ │ ├── IngredientGridWithNavigationMixin.java
│ │ │ ├── IngredientListOverlayMixin.java
│ │ │ ├── MouseUtilMixin.java
│ │ │ └── PageNavigationMixin.java
│ │ │ └── rei
│ │ │ └── PointHelperMixin.java
│ │ ├── platform
│ │ ├── ClientServices.java
│ │ ├── Services.java
│ │ └── services
│ │ │ ├── IClientHelper.java
│ │ │ └── IPlatformHelper.java
│ │ └── util
│ │ └── Utils.java
│ └── resources
│ ├── assets
│ └── controllable
│ │ ├── background.png
│ │ ├── banner.png
│ │ ├── font
│ │ ├── buttons.json
│ │ └── icons.json
│ │ ├── icon.png
│ │ ├── lang
│ │ ├── en_gb.json
│ │ ├── en_us.json
│ │ ├── fr_fr.json
│ │ └── zh_tw.json
│ │ └── textures
│ │ └── gui
│ │ ├── buttons.png
│ │ ├── controller.png
│ │ ├── cursor.png
│ │ ├── icons.png
│ │ └── sprites
│ │ └── toast
│ │ └── connection.png
│ ├── controllable.common.mixins.json
│ ├── gamecontrollerdb.txt
│ ├── mappings
│ └── defender_game_racer_x7.json
│ └── pack.mcmeta
├── fabric
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── mrcrayfish
│ │ └── controllable
│ │ ├── ControllableMod.java
│ │ ├── client
│ │ ├── ClientControllableMod.java
│ │ └── util
│ │ │ └── ReflectUtil.java
│ │ ├── integration
│ │ └── ArchitecturySupport.java
│ │ ├── mixin
│ │ ├── ControllableMixinPlugin.java
│ │ └── client
│ │ │ ├── FabricGuiMixin.java
│ │ │ ├── FabricKeyMappingMixin.java
│ │ │ ├── FabricMinecraftMixin.java
│ │ │ └── FabricRecipeBookPageMixin.java
│ │ └── platform
│ │ ├── FabricClientHelper.java
│ │ └── FabricPlatformHelper.java
│ └── resources
│ ├── META-INF
│ └── services
│ │ ├── com.mrcrayfish.controllable.platform.services.IClientHelper
│ │ └── com.mrcrayfish.controllable.platform.services.IPlatformHelper
│ ├── controllable.accesswidener
│ ├── controllable.fabric.mixins.json
│ └── fabric.mod.json
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── neoforge
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── mrcrayfish
│ │ │ └── controllable
│ │ │ ├── ControllableMod.java
│ │ │ ├── client
│ │ │ ├── ClientEvents.java
│ │ │ ├── binding
│ │ │ │ └── context
│ │ │ │ │ └── NeoForgeKeyContext.java
│ │ │ └── util
│ │ │ │ └── ReflectUtil.java
│ │ │ ├── mixin
│ │ │ ├── ControllableMixinPlugin.java
│ │ │ └── client
│ │ │ │ ├── GuiLayerManagerMixin.java
│ │ │ │ ├── NeoForgeKeyMappingMixin.java
│ │ │ │ └── NeoForgeRecipeBookPageMixin.java
│ │ │ └── platform
│ │ │ ├── NeoForgeClientHelper.java
│ │ │ └── NeoForgePlatformHelper.java
│ └── resources
│ │ ├── META-INF
│ │ ├── accesstransformer.cfg
│ │ ├── neoforge.mods.toml
│ │ └── services
│ │ │ ├── com.mrcrayfish.controllable.platform.services.IClientHelper
│ │ │ └── com.mrcrayfish.controllable.platform.services.IPlatformHelper
│ │ └── controllable.neoforge.mixins.json
│ └── test
│ └── java
│ └── test
│ └── ScreenRuleTest.java
├── release_build
└── settings.gradle
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
2 | *.bat text eol=crlf
3 | *.patch text eol=lf
4 | *.java text eol=lf
5 | *.gradle text eol=crlf
6 | *.png binary
7 | *.gif binary
8 | *.exe binary
9 | *.dll binary
10 | *.jar binary
11 | *.lzma binary
12 | *.zip binary
13 | *.pyd binary
14 | *.cfg text eol=lf
15 | *.jks binary
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # eclipse
2 | bin
3 | *.launch
4 | .settings
5 | .metadata
6 | .classpath
7 | .project
8 |
9 | # idea
10 | out
11 | *.ipr
12 | *.iws
13 | *.iml
14 | .idea/*
15 | !.idea/scopes
16 |
17 | # gradle
18 | build
19 | .gradle
20 |
21 | # other
22 | eclipse
23 | /fabric/run/
24 | /neoforge/runs/
25 | /forge/
26 |
--------------------------------------------------------------------------------
/.idea/scopes/Fabric_sources.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/scopes/Forge_sources.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 MrCrayfish
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.
--------------------------------------------------------------------------------
/LICENSE_ControllableSDL:
--------------------------------------------------------------------------------
1 | This software is provided 'as-is', without any express or implied
2 | warranty. In no event will the authors be held liable for any damages
3 | arising from the use of this software.
4 |
5 | Permission is granted to anyone to use this software for any purpose,
6 | including commercial applications, and to alter it and redistribute it
7 | freely, subject to the following restrictions:
8 |
9 | 1. The origin of this software must not be misrepresented; you must not
10 | claim that you wrote the original software. If you use this software
11 | in a product, an acknowledgment in the product documentation would be
12 | appreciated but is not required.
13 | 2. Altered source versions must be plainly marked as such, and must not be
14 | misrepresented as being the original software.
15 | 3. This notice may not be removed or altered from any source distribution.
--------------------------------------------------------------------------------
/LICENSE_GameControllerDB:
--------------------------------------------------------------------------------
1 | Copyright (C) 1997-2025 Sam Lantinga
2 |
3 | This software is provided 'as-is', without any express or implied
4 | warranty. In no event will the authors be held liable for any damages
5 | arising from the use of this software.
6 |
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it
9 | freely, subject to the following restrictions:
10 |
11 | 1. The origin of this software must not be misrepresented; you must not
12 | claim that you wrote the original software. If you use this software
13 | in a product, an acknowledgment in the product documentation would be
14 | appreciated but is not required.
15 | 2. Altered source versions must be plainly marked as such, and must not be
16 | misrepresented as being the original software.
17 | 3. This notice may not be removed or altered from any source distribution.
--------------------------------------------------------------------------------
/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'fabric-loom' version '1.10-SNAPSHOT' apply false
3 | id 'net.neoforged.moddev' version '2.0.73' apply false
4 | }
--------------------------------------------------------------------------------
/buildSrc/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'groovy-gradle-plugin'
3 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/groovy/multiloader-loader.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'multiloader-common'
3 | }
4 |
5 | configurations {
6 | commonJava {
7 | canBeResolved = true
8 | }
9 | commonResources {
10 | canBeResolved = true
11 | }
12 | }
13 |
14 | dependencies {
15 | compileOnly(project(':common')) {
16 | capabilities {
17 | requireCapability "$group:$mod_id"
18 | }
19 | }
20 | commonJava project(path: ':common', configuration: 'commonJava')
21 | commonResources project(path: ':common', configuration: 'commonResources')
22 | }
23 |
24 | tasks.named('compileJava', JavaCompile) {
25 | dependsOn(configurations.commonJava)
26 | source(configurations.commonJava)
27 | }
28 |
29 | processResources {
30 | dependsOn(configurations.commonResources)
31 | from(configurations.commonResources)
32 | }
33 |
34 | tasks.named('javadoc', Javadoc).configure {
35 | dependsOn(configurations.commonJava)
36 | source(configurations.commonJava)
37 | }
38 |
39 | tasks.named("sourcesJar", Jar) {
40 | dependsOn(configurations.commonJava)
41 | from(configurations.commonJava)
42 | dependsOn(configurations.commonResources)
43 | from(configurations.commonResources)
44 | }
--------------------------------------------------------------------------------
/common/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'multiloader-common'
3 | id 'net.neoforged.moddev'
4 | id 'de.undercouch.download' version '5.4.0'
5 | }
6 |
7 | neoForge {
8 | // Look for versions on https://projects.neoforged.net/neoforged/neoform
9 | neoFormVersion = neo_form_version
10 |
11 | // Automatically enable AccessTransformers if the file exists
12 | def at = file('src/main/resources/META-INF/accesstransformer.cfg')
13 | if (at.exists()) {
14 | accessTransformers.add(at.absolutePath)
15 | }
16 | }
17 |
18 | dependencies {
19 | compileOnly "com.mrcrayfish:framework-common:${minecraft_version}-${framework_version}"
20 | compileOnly "mezz.jei:jei-${jei_minecraft_version}-common:${jei_version}"
21 | compileOnly "mezz.jei:jei-${jei_minecraft_version}-gui:${jei_version}"
22 | compileOnly "mezz.jei:jei-${jei_minecraft_version}-lib:${jei_version}"
23 | compileOnly "com.mrcrayfish:controllable-sdl:${controllable_sdl_version}"
24 | compileOnly "dev.emi:emi-xplat-mojmap:${emi_version}"
25 | compileOnly "me.shedaniel:RoughlyEnoughItems-neoforge:${rei_version}"
26 | compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.7'
27 | compileOnly group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.4.1'
28 | annotationProcessor group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.4.1'
29 | }
30 |
31 | tasks.register('downloadMappings', Download) {
32 | src 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt'
33 | dest 'src/main/resources/gamecontrollerdb.txt'
34 | }
35 |
36 | configurations {
37 | commonJava {
38 | canBeResolved = false
39 | canBeConsumed = true
40 | }
41 | commonResources {
42 | canBeResolved = false
43 | canBeConsumed = true
44 | }
45 | }
46 |
47 | artifacts {
48 | commonJava sourceSets.main.java.sourceDirectories.singleFile
49 | commonResources sourceSets.main.resources.sourceDirectories.singleFile
50 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/Constants.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | /**
7 | * Author: MrCrayfish
8 | */
9 | public class Constants
10 | {
11 | public static final String MOD_ID = "controllable";
12 | public static final String MOD_NAME = "Controllable";
13 | public static final Logger LOG = LoggerFactory.getLogger(MOD_NAME);
14 | }
15 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/Action.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client;
2 |
3 | import net.minecraft.network.chat.Component;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | import java.util.Comparator;
7 |
8 | /**
9 | * Author: MrCrayfish
10 | */
11 | public class Action implements Comparable
12 | {
13 | private Component description;
14 | private Side side;
15 |
16 | public Action(Component description, Side side)
17 | {
18 | this.description = description;
19 | this.side = side;
20 | }
21 |
22 | public Component getDescription()
23 | {
24 | return this.description;
25 | }
26 |
27 | public void setDescription(Component description)
28 | {
29 | this.description = description;
30 | }
31 |
32 | public Side getSide()
33 | {
34 | return this.side;
35 | }
36 |
37 | public void setSide(Side side)
38 | {
39 | this.side = side;
40 | }
41 |
42 | @Override
43 | public int compareTo(@NotNull Action o)
44 | {
45 | int result = this.side.compareTo(o.side);
46 | if(result == 0)
47 | {
48 | return o.description.getString().compareTo(o.description.getString());
49 | }
50 | return result;
51 | }
52 |
53 | public enum Side
54 | {
55 | LEFT, RIGHT;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/ActionDescriptions.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client;
2 |
3 | import net.minecraft.network.chat.Component;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public class ActionDescriptions
9 | {
10 | public static final Component PICKUP_STACK = Component.translatable("controllable.action.pickup_stack");
11 | public static final Component SPLIT_STACK = Component.translatable("controllable.action.split_stack");
12 | public static final Component QUICK_MOVE = Component.translatable("controllable.action.quick_move");
13 | public static final Component PLACE_STACK = Component.translatable("controllable.action.place_stack");
14 | public static final Component PLACE_ITEM = Component.translatable("controllable.action.place_item");
15 | public static final Component PERFORM_ACTION = Component.translatable("controllable.action.radial.perform_action");
16 | public static final Component CLOSE_MENU = Component.translatable("controllable.action.radial.close_menu");
17 | public static final Component BREAK = Component.translatable("controllable.action.break");
18 | public static final Component ATTACK = Component.translatable("controllable.action.attack");
19 | public static final Component EAT = Component.translatable("controllable.action.eat");
20 | public static final Component DRINK = Component.translatable("controllable.action.drink");
21 | public static final Component BLOCK = Component.translatable("controllable.action.block");
22 | public static final Component PULL_BOW = Component.translatable("controllable.action.pull_bow");
23 | public static final Component PLACE_BLOCK = Component.translatable("controllable.action.place_block");
24 | public static final Component USE_ITEM = Component.translatable("controllable.action.use_item");
25 | public static final Component INTERACT = Component.translatable("controllable.action.interact");
26 | public static final Component JUMP = Component.translatable("controllable.action.jump");
27 | public static final Component OPEN_INVENTORY = Component.translatable("controllable.action.inventory");
28 | public static final Component CLOSE_INVENTORY = Component.translatable("controllable.action.close_inventory");
29 | public static final Component SWAP_HANDS = Component.translatable("controllable.action.swap_hands");
30 | public static final Component DISMOUNT = Component.translatable("controllable.action.dismount");
31 | public static final Component SNEAK = Component.translatable("controllable.action.sneak");
32 | public static final Component DROP_ITEM = Component.translatable("controllable.action.drop_item");
33 | }
34 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/ClientBootstrap.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.overlay.OverlayRenderer;
5 |
6 | /**
7 | * Author: MrCrayfish
8 | */
9 | public class ClientBootstrap
10 | {
11 | public static void init()
12 | {
13 | Controllable.init();
14 | ControllerEvents.init();
15 | OverlayRenderer.init();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/ControllerEvents.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.binding.ButtonBinding;
5 | import com.mrcrayfish.controllable.client.gui.screens.SettingsScreen;
6 | import com.mrcrayfish.controllable.client.gui.widget.ControllerButton;
7 | import com.mrcrayfish.controllable.client.input.Controller;
8 | import com.mrcrayfish.framework.api.event.client.FrameworkScreenEvents;
9 | import net.minecraft.client.Minecraft;
10 | import net.minecraft.client.gui.components.AbstractWidget;
11 | import net.minecraft.client.gui.components.Button;
12 | import net.minecraft.client.gui.screens.Screen;
13 | import net.minecraft.client.gui.screens.options.OptionsScreen;
14 | import net.minecraft.network.chat.Component;
15 |
16 | import java.util.List;
17 | import java.util.Optional;
18 | import java.util.function.Consumer;
19 |
20 | /**
21 | * Author: MrCrayfish
22 | */
23 | public class ControllerEvents
24 | {
25 | public static void init()
26 | {
27 | FrameworkScreenEvents.INIT.register(ControllerEvents::onModifyScreenWidgets);
28 | }
29 |
30 | private static void onModifyScreenWidgets(Screen screen, List widgets, Consumer add, Consumer remove)
31 | {
32 | ButtonBinding.resetButtonStates();
33 |
34 | // Fixes an issue where using item is not stopped after opening a screen
35 | Controller controller = Controllable.getController();
36 | if(controller != null && controller.isBeingUsed())
37 | {
38 | Minecraft mc = Minecraft.getInstance();
39 | if(mc.gameMode != null && mc.player != null && mc.player.isUsingItem())
40 | {
41 | mc.gameMode.releaseUsingItem(mc.player);
42 | }
43 | }
44 |
45 | if(screen instanceof OptionsScreen)
46 | {
47 | Optional btn = widgets.stream().filter(widget -> widget instanceof Button button &&
48 | button.getMessage().equals(Component.translatable("options.controls"))).findFirst();
49 | btn.ifPresent(widget -> add.accept(new ControllerButton(widget, button -> {
50 | Minecraft.getInstance().setScreen(new SettingsScreen(screen));
51 | })));
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/KeyAdapterBinding.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.EmptyHandler;
4 | import com.mrcrayfish.controllable.platform.ClientServices;
5 | import net.minecraft.client.KeyMapping;
6 | import net.minecraft.client.Minecraft;
7 | import net.minecraft.client.gui.screens.Screen;
8 | import org.lwjgl.glfw.GLFW;
9 |
10 | /**
11 | * A special binding that translates button presses to key presses. This binding does not need to be
12 | * registered and is added by players during runtime.
13 | *
14 | * Author: MrCrayfish
15 | */
16 | public final class KeyAdapterBinding extends ButtonBinding
17 | {
18 | private final KeyMapping keyMapping;
19 | private final String labelKey;
20 |
21 | public KeyAdapterBinding(int button, KeyMapping mapping)
22 | {
23 | super(button, mapping.getName() + ".custom", "key.categories.controllable_custom", ClientServices.CLIENT.createBindingContext(mapping), EmptyHandler.INSTANCE);
24 | this.keyMapping = mapping;
25 | this.labelKey = mapping.getName();
26 | }
27 |
28 | @Override
29 | public String getLabelKey()
30 | {
31 | return this.labelKey;
32 | }
33 |
34 | public KeyMapping getKeyMapping()
35 | {
36 | return this.keyMapping;
37 | }
38 |
39 | @Override
40 | protected void setPressed(boolean pressed)
41 | {
42 | boolean wasPressed = this.isButtonDown();
43 | super.setPressed(pressed);
44 | this.keyMapping.setDown(pressed);
45 | if(!wasPressed && pressed)
46 | {
47 | this.updateKeyBindPressTime();
48 | int key = ClientServices.CLIENT.getKeyValue(this.keyMapping);
49 | this.handlePressed(GLFW.GLFW_PRESS, key, 0);
50 | }
51 | else if(wasPressed && !pressed)
52 | {
53 | int key = ClientServices.CLIENT.getKeyValue(this.keyMapping);
54 | this.handlePressed(GLFW.GLFW_RELEASE, key, 0);
55 | }
56 | }
57 |
58 | private void updateKeyBindPressTime()
59 | {
60 | ClientServices.CLIENT.setKeyPressTime(this.keyMapping, 1);
61 | }
62 |
63 | private void handlePressed(int action, int key, int modifiers)
64 | {
65 | Screen screen = Minecraft.getInstance().screen;
66 | if(screen != null && ClientServices.CLIENT.sendScreenInput(screen, key, action, modifiers))
67 | return;
68 | ClientServices.CLIENT.sendKeyInputEvent(key, 0, action, modifiers);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/context/GlobalContext.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context;
2 |
3 | import com.mrcrayfish.controllable.client.binding.context.rule.ContextRule;
4 | import com.mrcrayfish.controllable.util.Utils;
5 | import net.minecraft.resources.ResourceLocation;
6 |
7 | import java.util.Set;
8 |
9 | /**
10 | *
11 | *
12 | * Author: MrCrayfish
13 | */
14 | public class GlobalContext extends BindingContext
15 | {
16 | public static final GlobalContext INSTANCE = new GlobalContext(Utils.resource("global"));
17 |
18 | protected GlobalContext(ResourceLocation id)
19 | {
20 | super(id);
21 | }
22 |
23 | @Override
24 | protected Set createRules()
25 | {
26 | return Set.of();
27 | }
28 |
29 | @Override
30 | public int priority()
31 | {
32 | return 0;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/context/InGameContext.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context;
2 |
3 | import com.mrcrayfish.controllable.client.binding.context.rule.ContextRule;
4 | import com.mrcrayfish.controllable.client.binding.context.rule.HasPlayerRule;
5 | import com.mrcrayfish.controllable.client.binding.context.rule.NoScreenRule;
6 | import com.mrcrayfish.controllable.util.Utils;
7 | import net.minecraft.resources.ResourceLocation;
8 |
9 | import java.util.Set;
10 |
11 | /**
12 | * Author: MrCrayfish
13 | */
14 | public class InGameContext extends BindingContext
15 | {
16 | public static final InGameContext INSTANCE = new InGameContext(Utils.resource("in_game"));
17 |
18 | protected InGameContext(ResourceLocation id)
19 | {
20 | super(id);
21 | }
22 |
23 | @Override
24 | public Set createRules()
25 | {
26 | return Set.of(NoScreenRule.get(), HasPlayerRule.get());
27 | }
28 |
29 | @Override
30 | public int priority()
31 | {
32 | return 0;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/context/InGameWithScreenContext.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context;
2 |
3 | import com.mrcrayfish.controllable.client.binding.context.rule.ContextRule;
4 | import com.mrcrayfish.controllable.client.binding.context.rule.HasPlayerRule;
5 | import com.mrcrayfish.controllable.client.binding.context.rule.HasScreenRule;
6 | import com.mrcrayfish.controllable.util.Utils;
7 | import net.minecraft.resources.ResourceLocation;
8 |
9 | import java.util.Set;
10 |
11 | /**
12 | * Author: MrCrayfish
13 | */
14 | public class InGameWithScreenContext extends InScreenContext
15 | {
16 | public static final InGameWithScreenContext INSTANCE = new InGameWithScreenContext(Utils.resource("in_game_with_screen"));
17 |
18 | protected InGameWithScreenContext(ResourceLocation id)
19 | {
20 | super(id);
21 | }
22 |
23 | @Override
24 | public Set createRules()
25 | {
26 | return Set.of(HasScreenRule.any(), HasPlayerRule.get());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/context/InScreenContext.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context;
2 |
3 | import com.mrcrayfish.controllable.client.binding.context.rule.ContextRule;
4 | import com.mrcrayfish.controllable.client.binding.context.rule.HasScreenRule;
5 | import com.mrcrayfish.controllable.util.Utils;
6 | import net.minecraft.resources.ResourceLocation;
7 |
8 | import java.util.Set;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | public class InScreenContext extends BindingContext
14 | {
15 | public static final InScreenContext INSTANCE = new InScreenContext(Utils.resource("in_screen"));
16 |
17 | protected InScreenContext(ResourceLocation id)
18 | {
19 | super(id);
20 | }
21 |
22 | @Override
23 | public Set createRules()
24 | {
25 | return Set.of(HasScreenRule.any());
26 | }
27 |
28 | @Override
29 | public int priority()
30 | {
31 | return 0;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/context/rule/ContextRule.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context.rule;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public abstract sealed class ContextRule permits HasPlayerRule, NoScreenRule, HasScreenRule
7 | {
8 | public abstract boolean isActive();
9 |
10 | public abstract boolean matches(ContextRule other);
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/context/rule/HasPlayerRule.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context.rule;
2 |
3 | import net.minecraft.client.Minecraft;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public final class HasPlayerRule extends ContextRule
9 | {
10 | private static final HasPlayerRule INSTANCE = new HasPlayerRule();
11 |
12 | private HasPlayerRule() {}
13 |
14 | @Override
15 | public boolean isActive()
16 | {
17 | Minecraft mc = Minecraft.getInstance();
18 | return mc.player != null;
19 | }
20 |
21 | @Override
22 | public boolean matches(ContextRule other)
23 | {
24 | return other == INSTANCE;
25 | }
26 |
27 | public static HasPlayerRule get()
28 | {
29 | return INSTANCE;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/context/rule/HasScreenRule.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context.rule;
2 |
3 | import net.minecraft.client.Minecraft;
4 | import net.minecraft.client.gui.screens.Screen;
5 |
6 | import java.util.Collections;
7 | import java.util.Set;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public final class HasScreenRule extends ContextRule
13 | {
14 | private final Set> validScreens;
15 |
16 | private HasScreenRule(Set> validScreens)
17 | {
18 | this.validScreens = Set.copyOf(validScreens);
19 | }
20 |
21 | @Override
22 | public boolean isActive()
23 | {
24 | Minecraft mc = Minecraft.getInstance();
25 | return mc.screen != null && (this.validScreens.isEmpty() || this.validScreens.contains(mc.screen.getClass()));
26 | }
27 |
28 | @Override
29 | public boolean matches(ContextRule other)
30 | {
31 | if(!(other instanceof HasScreenRule that))
32 | return false;
33 | if(this.validScreens.isEmpty())
34 | return true;
35 | if(that.validScreens.isEmpty())
36 | return true;
37 | return !Collections.disjoint(this.validScreens, that.validScreens);
38 | }
39 |
40 | public static HasScreenRule any()
41 | {
42 | return new HasScreenRule(Set.of());
43 | }
44 |
45 | public static HasScreenRule of(Set> screenClasses)
46 | {
47 | return new HasScreenRule(screenClasses);
48 | }
49 |
50 | @Override
51 | public int hashCode()
52 | {
53 | // Enforces that only one type of screen rule can be added to binding contexts
54 | return HasScreenRule.class.hashCode();
55 | }
56 |
57 | @Override
58 | public boolean equals(Object obj)
59 | {
60 | // Enforces that only one type of screen rule can be added to binding contexts
61 | return obj != null && obj.getClass() == HasScreenRule.class;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/context/rule/NoScreenRule.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context.rule;
2 |
3 | import net.minecraft.client.Minecraft;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public final class NoScreenRule extends ContextRule
9 | {
10 | private static final NoScreenRule INSTANCE = new NoScreenRule();
11 |
12 | private NoScreenRule() {}
13 |
14 | @Override
15 | public boolean isActive()
16 | {
17 | return Minecraft.getInstance().screen == null;
18 | }
19 |
20 | @Override
21 | public boolean matches(ContextRule other)
22 | {
23 | return other == INSTANCE;
24 | }
25 |
26 | public static NoScreenRule get()
27 | {
28 | return INSTANCE;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/ButtonHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public sealed class ButtonHandler permits MovementInputHandler, OnPressAndReleaseHandler, OnPressHandler, OnReleaseHandler, RenderingHandler, TickingHandler
7 | {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/EmptyHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
4 |
5 | import java.util.Optional;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public final class EmptyHandler extends OnPressHandler
11 | {
12 | public static final EmptyHandler INSTANCE = new EmptyHandler();
13 |
14 | private EmptyHandler() {}
15 |
16 | @Override
17 | public Optional createPressedHandler(Context context)
18 | {
19 | return Optional.of(() -> {});
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/MovementInputHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.MovementInputContext;
5 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingMovementInput;
6 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingPressed;
7 |
8 | import java.util.Optional;
9 | import java.util.function.Consumer;
10 |
11 | /**
12 | * Author: MrCrayfish
13 | */
14 | public abstract non-sealed class MovementInputHandler extends ButtonHandler implements BindingPressed, BindingMovementInput
15 | {
16 | @Override
17 | public Optional createPressedHandler(Context context)
18 | {
19 | // Must capture on pressed for movement input to be run
20 | return Optional.of(() -> {});
21 | }
22 |
23 | public static MovementInputHandler create(Consumer inputHandler)
24 | {
25 | return new MovementInputHandler()
26 | {
27 | @Override
28 | public void handleMovementInput(MovementInputContext context)
29 | {
30 | inputHandler.accept(context);
31 | }
32 | };
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/OnPressAndReleaseHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingPressed;
5 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingReleased;
6 |
7 | import java.util.Optional;
8 | import java.util.function.Function;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | public abstract non-sealed class OnPressAndReleaseHandler extends ButtonHandler implements BindingPressed, BindingReleased
14 | {
15 | public static OnPressAndReleaseHandler create(Function> pressHandler, Function releaseHandler)
16 | {
17 | return new OnPressAndReleaseHandler()
18 | {
19 | @Override
20 | public Optional createPressedHandler(Context context)
21 | {
22 | return pressHandler.apply(context);
23 | }
24 |
25 | @Override
26 | public boolean handleReleased(Context context)
27 | {
28 | return releaseHandler.apply(context);
29 | }
30 | };
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/OnPressHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingPressed;
5 |
6 | import java.util.Optional;
7 | import java.util.function.Function;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public abstract non-sealed class OnPressHandler extends ButtonHandler implements BindingPressed
13 | {
14 | public static OnPressHandler create(Function> handler)
15 | {
16 | return new OnPressHandler()
17 | {
18 | @Override
19 | public Optional createPressedHandler(Context context)
20 | {
21 | return handler.apply(context);
22 | }
23 | };
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/OnReleaseHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingPressed;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
5 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingReleased;
6 |
7 | import java.util.Optional;
8 | import java.util.function.Function;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | public abstract non-sealed class OnReleaseHandler extends ButtonHandler implements BindingPressed, BindingReleased
14 | {
15 | @Override
16 | public Optional createPressedHandler(Context context)
17 | {
18 | return Optional.of(() -> {});
19 | }
20 |
21 | public static OnReleaseHandler create(Function handler)
22 | {
23 | return new OnReleaseHandler()
24 | {
25 | @Override
26 | public boolean handleReleased(Context context)
27 | {
28 | return handler.apply(context);
29 | }
30 | };
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/RenderingHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingPressed;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
5 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.RenderingContext;
6 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingOnRender;
7 |
8 | import java.util.Optional;
9 | import java.util.function.Consumer;
10 |
11 | /**
12 | * Author: MrCrayfish
13 | */
14 | public abstract non-sealed class RenderingHandler extends ButtonHandler implements BindingPressed, BindingOnRender
15 | {
16 | @Override
17 | public Optional createPressedHandler(Context context)
18 | {
19 | return Optional.of(() -> {});
20 | }
21 |
22 | public static RenderingHandler create(RenderPhase phase, Consumer handler)
23 | {
24 | return new RenderingHandler()
25 | {
26 | @Override
27 | public RenderPhase phase()
28 | {
29 | return phase;
30 | }
31 |
32 | @Override
33 | public void handleRender(RenderingContext context)
34 | {
35 | handler.accept(context);
36 | }
37 | };
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/TickingHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingPressed;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
5 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingOnTick;
6 |
7 | import java.util.Optional;
8 | import java.util.function.Function;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | public abstract non-sealed class TickingHandler extends ButtonHandler implements BindingPressed, BindingOnTick
14 | {
15 | @Override
16 | public Optional createPressedHandler(Context context)
17 | {
18 | return Optional.of(() -> {});
19 | }
20 |
21 | public static TickingHandler create(TickPhase phase, Function handler)
22 | {
23 | return new TickingHandler()
24 | {
25 | @Override
26 | public TickPhase phase()
27 | {
28 | return phase;
29 | }
30 |
31 | @Override
32 | public void handleTick(Context context)
33 | {
34 | handler.apply(context);
35 | }
36 | };
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/action/BindingMovementInput.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.action;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.MovementInputContext;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public interface BindingMovementInput
9 | {
10 | void handleMovementInput(MovementInputContext context);
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/action/BindingOnRender.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.action;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.RenderingContext;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public interface BindingOnRender
9 | {
10 | RenderPhase phase();
11 |
12 | void handleRender(RenderingContext context);
13 |
14 | enum RenderPhase
15 | {
16 | START_RENDER,
17 | END_RENDER
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/action/BindingOnTick.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.action;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public interface BindingOnTick
9 | {
10 | TickPhase phase();
11 |
12 | void handleTick(Context context);
13 |
14 | enum TickPhase
15 | {
16 | START_CLIENT,
17 | END_CLIENT,
18 | START_PLAYER,
19 | END_PLAYER
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/action/BindingPressed.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.action;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
4 |
5 | import java.util.Optional;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public interface BindingPressed
11 | {
12 | /**
13 | * Creates a runnable to execute or return empty if unable to run action. Returning a non-empty
14 | * optional indicates that the runnable be executed. For example,
15 | *
16 | * @param context
17 | * @return
18 | */
19 | Optional createPressedHandler(Context context);
20 | }
21 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/action/BindingReleased.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.action;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public interface BindingReleased
9 | {
10 | boolean handleReleased(Context context);
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/action/context/Context.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.action.context;
2 |
3 | import com.mrcrayfish.controllable.client.binding.ButtonBinding;
4 | import com.mrcrayfish.controllable.client.input.Controller;
5 | import net.minecraft.client.Minecraft;
6 | import net.minecraft.client.gui.screens.Screen;
7 | import net.minecraft.client.player.LocalPlayer;
8 | import net.minecraft.world.level.Level;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import java.util.Optional;
12 |
13 | /**
14 | * Author: MrCrayfish
15 | */
16 | public class Context
17 | {
18 | private final ButtonBinding binding;
19 | private final Controller controller;
20 | private final Minecraft minecraft;
21 | private final @Nullable LocalPlayer player;
22 | private final @Nullable Level level;
23 | private final @Nullable Screen screen;
24 | private final boolean simulated;
25 |
26 | public Context(ButtonBinding binding, Controller controller, Minecraft minecraft, @Nullable LocalPlayer player, @Nullable Level level, @Nullable Screen screen, boolean simulated)
27 | {
28 | this.binding = binding;
29 | this.controller = controller;
30 | this.minecraft = minecraft;
31 | this.player = player;
32 | this.level = level;
33 | this.screen = screen;
34 | this.simulated = simulated;
35 | }
36 |
37 | public ButtonBinding binding()
38 | {
39 | return this.binding;
40 | }
41 |
42 | public Controller controller()
43 | {
44 | return this.controller;
45 | }
46 |
47 | public Minecraft minecraft()
48 | {
49 | return this.minecraft;
50 | }
51 |
52 | public Optional player()
53 | {
54 | return Optional.ofNullable(this.player);
55 | }
56 |
57 | public Optional level()
58 | {
59 | return Optional.ofNullable(this.level);
60 | }
61 |
62 | public Optional screen()
63 | {
64 | return Optional.ofNullable(this.screen);
65 | }
66 |
67 | public boolean simulated()
68 | {
69 | return this.simulated;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/action/context/MovementInputContext.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.action.context;
2 |
3 | import com.mrcrayfish.controllable.client.binding.ButtonBinding;
4 | import com.mrcrayfish.controllable.client.input.Controller;
5 | import com.mrcrayfish.controllable.client.util.MutableClientInput;
6 | import net.minecraft.client.Minecraft;
7 | import net.minecraft.client.gui.screens.Screen;
8 | import net.minecraft.client.player.ClientInput;
9 | import net.minecraft.client.player.LocalPlayer;
10 | import net.minecraft.world.level.Level;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | /**
14 | * Author: MrCrayfish
15 | */
16 | public class MovementInputContext extends Context
17 | {
18 | private final ClientInput input;
19 | private final MutableClientInput mutableInput;
20 |
21 | public MovementInputContext(ButtonBinding binding, Controller controller, Minecraft minecraft, @Nullable LocalPlayer player, @Nullable Level level, @Nullable Screen screen, boolean simulated, ClientInput input)
22 | {
23 | super(binding, controller, minecraft, player, level, screen, simulated);
24 | this.input = input;
25 | this.mutableInput = new MutableClientInput(input);
26 | }
27 |
28 | public ClientInput input()
29 | {
30 | return this.input;
31 | }
32 |
33 | public MutableClientInput mutableInput()
34 | {
35 | return this.mutableInput;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/action/context/RenderingContext.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.action.context;
2 |
3 | import com.mrcrayfish.controllable.client.binding.ButtonBinding;
4 | import com.mrcrayfish.controllable.client.input.Controller;
5 | import net.minecraft.client.DeltaTracker;
6 | import net.minecraft.client.Minecraft;
7 | import net.minecraft.client.gui.screens.Screen;
8 | import net.minecraft.client.player.LocalPlayer;
9 | import net.minecraft.world.level.Level;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | /**
13 | * Author: MrCrayfish
14 | */
15 | public class RenderingContext extends Context
16 | {
17 | private final DeltaTracker tracker;
18 |
19 | public RenderingContext(ButtonBinding binding, Controller controller, Minecraft minecraft, @Nullable LocalPlayer player, @Nullable Level level, @Nullable Screen screen, boolean simulated, DeltaTracker tracker)
20 | {
21 | super(binding, controller, minecraft, player, level, screen, simulated);
22 | this.tracker = tracker;
23 | }
24 |
25 | public DeltaTracker tracker()
26 | {
27 | return this.tracker;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/impl/AttackHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.impl;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.OnPressHandler;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
5 | import com.mrcrayfish.controllable.platform.ClientServices;
6 |
7 | import java.util.Optional;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public class AttackHandler extends OnPressHandler
13 | {
14 | private static boolean preventContinue;
15 |
16 | @Override
17 | public Optional createPressedHandler(Context context)
18 | {
19 | return Optional.of(() -> {
20 | context.player().ifPresent(player -> {
21 | if(!player.isUsingItem()) {
22 | preventContinue = ClientServices.CLIENT.startAttack(context.minecraft());
23 | }
24 | });
25 | });
26 | }
27 |
28 | public static boolean shouldPreventContinue()
29 | {
30 | boolean result = preventContinue;
31 | preventContinue = false;
32 | return result;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/impl/DropHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.impl;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.TickingHandler;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.BindingReleased;
5 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
6 |
7 | import java.util.Optional;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public final class DropHandler extends TickingHandler implements BindingReleased
13 | {
14 | private int timer;
15 | private boolean dropped;
16 |
17 | @Override
18 | public TickPhase phase()
19 | {
20 | return TickPhase.START_CLIENT;
21 | }
22 |
23 | @Override
24 | public void handleTick(Context context)
25 | {
26 | if(context.screen().isEmpty())
27 | {
28 | context.controller().updateInputTime();
29 | if(!this.dropped && this.timer++ >= 10)
30 | {
31 | this.dropped = true;
32 | context.player().ifPresent(player -> {
33 | if(!player.isSpectator()) {
34 | player.drop(true);
35 | }
36 | });
37 | }
38 | }
39 | }
40 |
41 | @Override
42 | public Optional createPressedHandler(Context context)
43 | {
44 | return Optional.of(() -> {
45 | if(context.screen().isEmpty()) {
46 | this.timer = 0;
47 | this.dropped = false;
48 | }
49 | });
50 | }
51 |
52 | @Override
53 | public boolean handleReleased(Context context)
54 | {
55 | if(context.screen().isEmpty())
56 | {
57 | if(this.timer < 10)
58 | {
59 | this.dropped = true;
60 | context.player().ifPresent(player -> {
61 | player.drop(false);
62 | });
63 | context.controller().updateInputTime();
64 | return true;
65 | }
66 | }
67 | return false;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/impl/QuickMoveHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.impl;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.OnPressHandler;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
5 | import com.mrcrayfish.controllable.client.util.MouseHooks;
6 | import org.lwjgl.glfw.GLFW;
7 |
8 | import java.util.Optional;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | public class QuickMoveHandler extends OnPressHandler
14 | {
15 | @Override
16 | public Optional createPressedHandler(Context context)
17 | {
18 | return context.screen().map(screen -> () -> {
19 | context.player().ifPresent(player -> {
20 | if(player.inventoryMenu.getCarried().isEmpty()) {
21 | MouseHooks.invokeMouseClick(screen, GLFW.GLFW_MOUSE_BUTTON_LEFT);
22 | } else {
23 | MouseHooks.invokeMouseReleased(screen, GLFW.GLFW_MOUSE_BUTTON_RIGHT);
24 | }
25 | });
26 | });
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/binding/handlers/impl/SneakHandler.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.handlers.impl;
2 |
3 | import com.mrcrayfish.controllable.client.binding.handlers.MovementInputHandler;
4 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.Context;
5 | import com.mrcrayfish.controllable.client.binding.handlers.action.context.MovementInputContext;
6 |
7 | import java.util.Optional;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public class SneakHandler extends MovementInputHandler
13 | {
14 | @Override
15 | public Optional createPressedHandler(Context context)
16 | {
17 | return Optional.of(() ->
18 | {
19 | if(context.minecraft().options.toggleCrouch().get())
20 | {
21 | context.minecraft().options.keyShift.setDown(true);
22 | }
23 | });
24 | }
25 |
26 | @Override
27 | public void handleMovementInput(MovementInputContext context)
28 | {
29 | if(!context.minecraft().options.toggleCrouch().get())
30 | {
31 | context.mutableInput().setShift(true);
32 | context.controller().updateInputTime();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerAxis.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.gui.screens.ControllerLayoutScreen;
5 | import com.mrcrayfish.controllable.client.input.Controller;
6 | import net.minecraft.client.gui.GuiGraphics;
7 |
8 | /**
9 | * Author: MrCrayfish
10 | */
11 | public class ControllerAxis extends ControllerButton
12 | {
13 | public ControllerAxis(ControllerLayoutScreen screen, int button, int x, int y, int u, int v, int width, int height, int scale)
14 | {
15 | super(screen, button, x, y, u, v, width, height, scale);
16 | }
17 |
18 | @Override
19 | public void draw(GuiGraphics graphics, int x, int y, int mouseX, int mouseY, boolean selected)
20 | {
21 | graphics.pose().pushMatrix();
22 | Controller controller = Controllable.getController();
23 | if(controller != null)
24 | {
25 | /*GLFWGamepadState gamepad = controller.getGamepadState();
26 | switch(this.button)
27 | {
28 | case Buttons.LEFT_THUMB_STICK ->
29 | {
30 | float leftX = gamepad.axes(this.screen.getEntry().isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X : GLFW.GLFW_GAMEPAD_AXIS_LEFT_X);
31 | float leftY = gamepad.axes(this.screen.getEntry().isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y : GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y);
32 | leftX *= this.screen.getEntry().isFlipLeftX() ? -1 : 1;
33 | leftY *= this.screen.getEntry().isFlipLeftY() ? -1 : 1;
34 | poseStack.translate(leftX * 5, leftY * 5, 0);
35 | }
36 | case Buttons.RIGHT_THUMB_STICK ->
37 | {
38 | float rightX = gamepad.axes(this.screen.getEntry().isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_LEFT_X : GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X);
39 | float rightY = gamepad.axes(this.screen.getEntry().isThumbsticksSwitched() ? GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y : GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y);
40 | rightX *= this.screen.getEntry().isFlipRightX() ? -1 : 1;
41 | rightY *= this.screen.getEntry().isFlipRightY() ? -1 : 1;
42 | poseStack.translate(rightX * 5, rightY * 5, 0);
43 | }
44 | }*/
45 |
46 | if(!this.screen.isButtonPressed(this.button))
47 | {
48 | graphics.pose().translate(0, -5);
49 | }
50 | }
51 | super.draw(graphics, x, y, mouseX, mouseY, selected);
52 | graphics.pose().popMatrix();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/ControllerButton.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui;
2 |
3 | import com.mojang.blaze3d.systems.RenderSystem;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.gui.screens.ControllerLayoutScreen;
6 | import com.mrcrayfish.controllable.client.input.Controller;
7 | import net.minecraft.client.gui.GuiGraphics;
8 | import net.minecraft.client.renderer.RenderPipelines;
9 | import net.minecraft.client.renderer.RenderType;
10 |
11 | /**
12 | * Author: MrCrayfish
13 | */
14 | public class ControllerButton
15 | {
16 | protected ControllerLayoutScreen screen;
17 | protected int button;
18 | private final int x, y;
19 | private final int u, v;
20 | private final int width, height;
21 | private final int scale;
22 | private boolean hovered;
23 |
24 | public ControllerButton(ControllerLayoutScreen screen, int button, int x, int y, int u, int v, int width, int height, int scale)
25 | {
26 | this.screen = screen;
27 | this.button = button;
28 | this.x = x;
29 | this.y = y;
30 | this.u = u;
31 | this.v = v;
32 | this.width = width;
33 | this.height = height;
34 | this.scale = scale;
35 | }
36 |
37 | public void draw(GuiGraphics graphics, int x, int y, int mouseX, int mouseY, boolean selected)
38 | {
39 | int buttonU = this.u;
40 | int buttonV = this.v;
41 | int buttonX = x + this.x * this.scale;
42 | int buttonY = y + this.y * this.scale;
43 | int buttonWidth = this.width * this.scale;
44 | int buttonHeight = this.height * this.scale;
45 | Controller controller = Controllable.getController();
46 | this.hovered = mouseX >= buttonX && mouseY >= buttonY && mouseX < buttonX + buttonWidth && mouseY < buttonY + buttonHeight;
47 | if(this.hovered)
48 | {
49 | buttonV += this.height * 2;
50 | }
51 | else if(controller != null && this.screen.isButtonPressed(this.button) || selected)
52 | {
53 | buttonV += this.height;
54 | }
55 | graphics.blit(RenderPipelines.GUI_TEXTURED, ControllerLayoutScreen.TEXTURE, buttonX, buttonY, buttonU, buttonV, this.width * this.scale, this.height * this.scale, this.width, this.height, 256, 256);
56 | }
57 |
58 | public int getButton()
59 | {
60 | return this.button;
61 | }
62 |
63 | public boolean isHovered()
64 | {
65 | return this.hovered;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/ISearchable.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui;
2 |
3 | import net.minecraft.network.chat.Component;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public interface ISearchable
9 | {
10 | Component getLabel();
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/Icons.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui;
2 |
3 | import com.mrcrayfish.controllable.util.Utils;
4 | import net.minecraft.resources.ResourceLocation;
5 |
6 | /**
7 | * Author: MrCrayfish
8 | */
9 | public enum Icons
10 | {
11 | CONTROLLER,
12 | SETTINGS,
13 | BINDINGS,
14 | ADD,
15 | RESET,
16 | WORLD,
17 | DOWNLOAD,
18 | CROSS,
19 | SAVE,
20 | KEY_CAP,
21 | LINK,
22 | INFO;
23 |
24 | public static final ResourceLocation TEXTURE = Utils.resource("textures/gui/icons.png");
25 | public static final int TEXTURE_WIDTH = Icons.values().length * 11;
26 | public static final int TEXTURE_HEIGHT = 11;
27 | }
28 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/RadialMenuAction.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui;
2 |
3 | import com.mrcrayfish.controllable.client.binding.ButtonBinding;
4 | import net.minecraft.ChatFormatting;
5 |
6 | /**
7 | * Author: MrCrayfish
8 | */
9 | public class RadialMenuAction
10 | {
11 | private final ButtonBinding binding;
12 | private ChatFormatting color;
13 |
14 | public RadialMenuAction(ButtonBinding binding, ChatFormatting color)
15 | {
16 | this.binding = binding;
17 | this.color = color;
18 | }
19 |
20 | public ButtonBinding getBinding()
21 | {
22 | return binding;
23 | }
24 |
25 | public ChatFormatting getColor()
26 | {
27 | return color;
28 | }
29 |
30 | public void setColor(ChatFormatting color)
31 | {
32 | this.color = color;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/components/FilteredItem.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.components;
2 |
3 | public interface FilteredItem
4 | {
5 | boolean isVisible();
6 | }
7 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/components/FilteredTabSelectionList.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.components;
2 |
3 | import net.minecraft.client.Minecraft;
4 | import net.minecraft.client.gui.components.ContainerObjectSelectionList;
5 |
6 | import java.util.LinkedList;
7 | import java.util.List;
8 |
9 | public class FilteredTabSelectionList> extends TabSelectionList
10 | {
11 | private final List original = new LinkedList<>();
12 |
13 | public FilteredTabSelectionList(Minecraft mc, int itemHeight)
14 | {
15 | super(mc, itemHeight);
16 | }
17 |
18 | public void rebuildList(boolean scroll)
19 | {
20 | List newEntries = this.original.stream().filter(e -> {
21 | if(e instanceof FilteredItem item) {
22 | return item.isVisible();
23 | }
24 | return true;
25 | }).toList();
26 | this.replaceEntries(newEntries);
27 | if(scroll)
28 | {
29 | this.setScrollAmount(this.maxScrollAmount());
30 | }
31 | }
32 |
33 | @Override
34 | public int addEntry(E entry)
35 | {
36 | this.original.add(entry);
37 | return super.addEntry(entry);
38 | }
39 |
40 | @Override
41 | protected void addEntryToTop(E entry)
42 | {
43 | this.original.addFirst(entry);
44 | super.addEntryToTop(entry);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/components/TabOptionTitleItem.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.components;
2 |
3 | import com.mrcrayfish.controllable.client.gui.navigation.SkipItem;
4 | import com.mrcrayfish.controllable.client.util.ScreenHelper;
5 | import net.minecraft.client.Minecraft;
6 | import net.minecraft.client.gui.Font;
7 | import net.minecraft.client.gui.GuiGraphics;
8 | import net.minecraft.client.gui.components.events.GuiEventListener;
9 | import net.minecraft.client.gui.narration.NarratableEntry;
10 | import net.minecraft.network.chat.Component;
11 |
12 | import java.util.Collections;
13 | import java.util.List;
14 |
15 | /**
16 | * Author: MrCrayfish
17 | */
18 | public class TabOptionTitleItem extends TabOptionBaseItem implements SkipItem
19 | {
20 | public TabOptionTitleItem(Component label)
21 | {
22 | super(label);
23 | }
24 |
25 | @Override
26 | public void render(GuiGraphics graphics, int x, int top, int left, int width, int height, int mouseX, int mouseY, boolean selected, float partialTicks)
27 | {
28 | Font font = Minecraft.getInstance().font;
29 | int labelWidth = font.width(this.label) + 2;
30 | ScreenHelper.drawRoundedBox(graphics, left + width / 2 - labelWidth / 2, top + 2, labelWidth, 14, 0x88000000);
31 | graphics.drawCenteredString(font, this.label, left + width / 2, top + 5, 0xFFFFFFFF);
32 | }
33 |
34 | @Override
35 | public List extends NarratableEntry> narratables()
36 | {
37 | return Collections.emptyList();
38 | }
39 |
40 | @Override
41 | public List extends GuiEventListener> children()
42 | {
43 | return Collections.emptyList();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/BasicNavigationPoint.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.navigation;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public class BasicNavigationPoint extends NavigationPoint
7 | {
8 | public BasicNavigationPoint(double x, double y)
9 | {
10 | super(x, y, Type.BASIC);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/HideCursor.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.navigation;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public interface HideCursor
7 | {
8 | }
9 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/ListWidgetNavigationPoint.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.navigation;
2 |
3 | import com.mrcrayfish.controllable.platform.ClientServices;
4 | import net.minecraft.client.gui.components.AbstractButton;
5 | import net.minecraft.client.gui.components.AbstractSelectionList;
6 | import net.minecraft.client.gui.components.AbstractWidget;
7 | import net.minecraft.client.gui.components.Button;
8 | import net.minecraft.client.gui.components.TabButton;
9 | import net.minecraft.client.gui.components.events.GuiEventListener;
10 |
11 | /**
12 | * Author: MrCrayfish
13 | */
14 | @SuppressWarnings("IntegerDivisionInFloatingPointContext")
15 | public class ListWidgetNavigationPoint extends NavigationPoint
16 | {
17 | private final AbstractWidget widget;
18 | private final AbstractSelectionList> list;
19 | private final GuiEventListener listEntry;
20 |
21 | public ListWidgetNavigationPoint(AbstractWidget widget, AbstractSelectionList> list, GuiEventListener listEntry)
22 | {
23 | super(0, 0, Type.WIDGET);
24 | this.widget = widget;
25 | this.list = list;
26 | this.listEntry = listEntry;
27 | }
28 |
29 | @Override
30 | public double distanceTo(double x, double y)
31 | {
32 | return Math.sqrt(Math.pow(this.getX() - x, 2) + Math.pow(this.getY() - y, 2));
33 | }
34 |
35 | @Override
36 | public double getX()
37 | {
38 | return this.widget.getX() + this.widget.getWidth() / 2;
39 | }
40 |
41 | @Override
42 | public double getY()
43 | {
44 | return this.widget.getY() + this.widget.getHeight() / 2;
45 | }
46 |
47 | @Override
48 | public void onNavigate()
49 | {
50 | int itemHeight = ClientServices.CLIENT.getListItemHeight(this.list);
51 | int index = this.list.children().indexOf(this.listEntry);
52 | int rowTop = ClientServices.CLIENT.getAbstractListRowTop(this.list, index);
53 | int rowBottom = ClientServices.CLIENT.getAbstractListRowBottom(this.list, index);
54 | int listTop = ClientServices.CLIENT.getAbstractListTop(this.list);
55 | int listBottom = ClientServices.CLIENT.getAbstractListBottom(this.list);
56 | if(rowTop < listTop)
57 | {
58 | double scroll = this.list.children().indexOf(this.listEntry) * itemHeight - itemHeight / 2;
59 | this.list.setScrollAmount(scroll);
60 | }
61 | if(rowBottom > listBottom) // Is not/partially visible
62 | {
63 | double scroll = this.list.children().indexOf(this.listEntry) * itemHeight + itemHeight - (listBottom - listTop) + 4 + itemHeight / 2;
64 | this.list.setScrollAmount(scroll);
65 | }
66 | }
67 |
68 | @Override
69 | public boolean shouldHide()
70 | {
71 | return this.widget instanceof AbstractButton || this.widget instanceof TabButton || this.widget instanceof HideCursor;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/Navigatable.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.navigation;
2 |
3 | import net.minecraft.client.gui.components.events.GuiEventListener;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public interface Navigatable
11 | {
12 | List elements();
13 | }
14 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/NavigationPoint.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.navigation;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public abstract class NavigationPoint
7 | {
8 | private final double x, y;
9 | private final Type type;
10 |
11 | public NavigationPoint(double x, double y, Type type)
12 | {
13 | this.x = x;
14 | this.y = y;
15 | this.type = type;
16 | }
17 |
18 | public double distanceTo(double x, double y)
19 | {
20 | return Math.sqrt(Math.pow(this.x - x, 2) + Math.pow(this.y - y, 2));
21 | }
22 |
23 | public double getX()
24 | {
25 | return this.x;
26 | }
27 |
28 | public double getY()
29 | {
30 | return this.y;
31 | }
32 |
33 | public Type getType()
34 | {
35 | return this.type;
36 | }
37 |
38 | public boolean shouldHide()
39 | {
40 | return false;
41 | }
42 |
43 | /**
44 | * Called when the cursor navigates to this point
45 | */
46 | public void onNavigate() {}
47 |
48 | protected enum Type
49 | {
50 | BASIC,
51 | WIDGET,
52 | SLOT;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/SkipItem.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.navigation;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public interface SkipItem
7 | {
8 | }
9 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/SlotNavigationPoint.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.navigation;
2 |
3 | import net.minecraft.world.inventory.Slot;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public class SlotNavigationPoint extends NavigationPoint
9 | {
10 | private final Slot slot;
11 |
12 | public SlotNavigationPoint(double x, double y, Slot slot)
13 | {
14 | super(x, y, Type.SLOT);
15 | this.slot = slot;
16 | }
17 |
18 | public Slot getSlot()
19 | {
20 | return this.slot;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/navigation/WidgetNavigationPoint.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.navigation;
2 |
3 | import net.minecraft.client.gui.components.AbstractButton;
4 | import net.minecraft.client.gui.components.AbstractWidget;
5 | import net.minecraft.client.gui.components.Button;
6 | import net.minecraft.client.gui.components.TabButton;
7 |
8 | /**
9 | * Author: MrCrayfish
10 | */
11 | public class WidgetNavigationPoint extends NavigationPoint
12 | {
13 | private final AbstractWidget widget;
14 |
15 | public WidgetNavigationPoint(AbstractWidget widget)
16 | {
17 | super(widget.getX() + widget.getWidth() / 2.0, widget.getY() + widget.getHeight() / 2.0, Type.WIDGET);
18 | this.widget = widget;
19 | }
20 |
21 | public AbstractWidget getWidget()
22 | {
23 | return this.widget;
24 | }
25 |
26 | @Override
27 | public boolean shouldHide()
28 | {
29 | return this.widget instanceof AbstractButton || this.widget instanceof TabButton || this.widget instanceof HideCursor;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/screens/PendingScreen.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.screens;
2 |
3 | import com.mojang.blaze3d.vertex.PoseStack;
4 | import net.minecraft.Util;
5 | import net.minecraft.client.gui.GuiGraphics;
6 | import net.minecraft.client.gui.screens.Screen;
7 | import net.minecraft.network.chat.Component;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public class PendingScreen extends Screen
13 | {
14 | public PendingScreen(Component title)
15 | {
16 | super(title);
17 | }
18 |
19 | @Override
20 | public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick)
21 | {
22 | super.render(graphics, mouseX, mouseY, partialTick);
23 | String loadingBar = switch((int) (Util.getMillis() / 300L % 4L)) {
24 | case 1, 3 -> "o O o";
25 | case 2 -> "o o O";
26 | default -> "O o o";
27 | };
28 | int centerX = this.width / 2;
29 | int centerY = this.height / 2;
30 | graphics.drawCenteredString(this.font, loadingBar, centerX, centerY - 9, -1);
31 | graphics.drawCenteredString(this.font, this.title, centerX, centerY + 5, 0x808080);
32 | }
33 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/screens/RadialMenuConfigureScreen.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.screens;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.gui.RadialMenuAction;
5 | import com.mrcrayfish.controllable.client.gui.Icons;
6 | import com.mrcrayfish.controllable.client.gui.RadialItemList;
7 | import com.mrcrayfish.controllable.client.util.ClientHelper;
8 | import com.mrcrayfish.controllable.client.util.ScreenHelper;
9 | import net.minecraft.client.gui.components.StringWidget;
10 | import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
11 | import net.minecraft.client.gui.layouts.LinearLayout;
12 | import net.minecraft.client.gui.screens.Screen;
13 | import net.minecraft.network.chat.CommonComponents;
14 | import net.minecraft.network.chat.Component;
15 | import org.jetbrains.annotations.Nullable;
16 |
17 | import java.util.ArrayList;
18 | import java.util.LinkedHashSet;
19 | import java.util.List;
20 | import java.util.Objects;
21 |
22 | /**
23 | * Author: MrCrayfish
24 | */
25 | public class RadialMenuConfigureScreen extends Screen
26 | {
27 | private final @Nullable Screen parent;
28 | private final List actions = new ArrayList<>();
29 | protected final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this);
30 | private RadialItemList list;
31 |
32 | public RadialMenuConfigureScreen(@Nullable Screen parent)
33 | {
34 | super(Component.translatable("controllable.gui.title.radial_menu_configure"));
35 | this.parent = parent;
36 | this.actions.addAll(Controllable.getRadialMenu().getActions());
37 | }
38 |
39 | @Override
40 | protected void init()
41 | {
42 | LinearLayout headerLayout = this.layout.addToHeader(LinearLayout.vertical());
43 | headerLayout.addChild(new StringWidget(this.title, this.font));
44 |
45 | this.list = new RadialItemList(this.minecraft, this.actions);
46 | this.layout.addToContents(this.list);
47 |
48 | LinearLayout footerLayout = this.layout.addToFooter(LinearLayout.horizontal().spacing(4));
49 | Component saveLabel = ClientHelper.join(Icons.SAVE, Component.translatable("controllable.gui.save"));
50 | footerLayout.addChild(ScreenHelper.button(this.width / 2 - 155, this.height - 29, 100, 20, saveLabel, buttons -> {
51 | Controllable.getRadialMenu().setActions(this.actions);
52 | Objects.requireNonNull(this.minecraft).setScreen(this.parent);
53 | }));
54 | Component addLabel = ClientHelper.join(Icons.ADD, Component.translatable("controllable.gui.add_binding"));
55 | footerLayout.addChild(ScreenHelper.button(this.width / 2 - 50, this.height - 29, 100, 20, addLabel, buttons -> {
56 | Objects.requireNonNull(this.minecraft).setScreen(new RadialMenuAddBindingsScreen(this));
57 | }));
58 | footerLayout.addChild(ScreenHelper.button(this.width / 2 + 55, this.height - 29, 100, 20, CommonComponents.GUI_CANCEL, buttons -> {
59 | Objects.requireNonNull(this.minecraft).setScreen(this.parent);
60 | }));
61 |
62 | this.layout.visitWidgets(this::addRenderableWidget);
63 | this.repositionElements();
64 | }
65 |
66 | @Override
67 | protected void repositionElements()
68 | {
69 | this.layout.arrangeElements();
70 | this.list.updateEntries();
71 | this.list.updateSize(this.width, this.layout);
72 | }
73 |
74 | public List getActions()
75 | {
76 | return this.actions;
77 | }
78 |
79 | public void scrollToBottomAndSelectLast()
80 | {
81 | this.list.setScrollAmount(this.list.maxScrollAmount());
82 | this.list.setSelected(this.list.children().getLast());
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/screens/ThumbstickSettingsScreen.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.screens;
2 |
3 | import com.mrcrayfish.controllable.client.util.ScreenHelper;
4 | import net.minecraft.client.gui.GuiGraphics;
5 | import net.minecraft.client.gui.components.OptionsList;
6 | import net.minecraft.client.gui.screens.Screen;
7 | import net.minecraft.network.chat.CommonComponents;
8 | import net.minecraft.network.chat.Component;
9 |
10 | import java.util.Objects;
11 |
12 | /**
13 | * Author: MrCrayfish
14 | */
15 | public class ThumbstickSettingsScreen extends Screen
16 | {
17 | private OptionsList optionsRowList;
18 | private final ControllerLayoutScreen layoutScreen;
19 |
20 | protected ThumbstickSettingsScreen(ControllerLayoutScreen layoutScreen)
21 | {
22 | super(Component.translatable("controllable.gui.title.thumbstick_settings"));
23 | this.layoutScreen = layoutScreen;
24 | }
25 |
26 | @Override
27 | protected void init()
28 | {
29 | //this.optionsRowList = new OptionsList(Objects.requireNonNull(this.minecraft), this.width, this.height, 32, this.height - 32, 25);
30 |
31 | /*this.optionsRowList.addBig(ControllerOptions.createOnOff("controllable.options.switchThumbsticks", gameSettings -> {
32 | return this.layoutScreen.getEntry().isThumbsticksSwitched();
33 | }, (options, option, value) -> {
34 | this.layoutScreen.getEntry().setSwitchThumbsticks(value);
35 | }));
36 |
37 | this.optionsRowList.addSmall(ControllerOptions.createOnOff("controllable.options.flipLeftThumbstickX", gameSettings -> {
38 | return this.layoutScreen.getEntry().isFlipLeftX();
39 | }, (options, option, value) -> {
40 | this.layoutScreen.getEntry().setFlipLeftX(value);
41 | }), ControllerOptions.createOnOff("controllable.options.flipRightThumbstickX", gameSettings -> {
42 | return this.layoutScreen.getEntry().isFlipRightX();
43 | }, (options, option, value) -> {
44 | this.layoutScreen.getEntry().setFlipRightX(value);
45 | }));
46 |
47 | this.optionsRowList.addSmall(ControllerOptions.createOnOff("controllable.options.flipLeftThumbstickY", gameSettings -> {
48 | return this.layoutScreen.getEntry().isFlipLeftY();
49 | }, (options, option, value) -> {
50 | this.layoutScreen.getEntry().setFlipLeftY(value);
51 | }), ControllerOptions.createOnOff("controllable.options.flipRightThumbstickY", gameSettings -> {
52 | return this.layoutScreen.getEntry().isFlipRightY();
53 | }, (options, option, value) -> {
54 | this.layoutScreen.getEntry().setFlipRightY(value);
55 | }));*/
56 |
57 | //this.addWidget(this.optionsRowList);
58 |
59 | this.addRenderableWidget(ScreenHelper.button(this.width / 2 - 100, this.height - 27, 200, 20, CommonComponents.GUI_BACK, (button) -> {
60 | this.minecraft.setScreen(this.layoutScreen);
61 | }));
62 | }
63 |
64 | @Override
65 | public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks)
66 | {
67 | //this.optionsRowList.render(graphics, mouseX, mouseY, partialTicks);
68 | graphics.drawCenteredString(this.font, this.title, this.width / 2, 20, 0xFFFFFFFF);
69 | super.render(graphics, mouseX, mouseY, partialTicks);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/toasts/ConnectionToast.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.toasts;
2 |
3 | import com.mrcrayfish.controllable.client.gui.screens.ControllerLayoutScreen;
4 | import com.mrcrayfish.controllable.util.Utils;
5 | import net.minecraft.ChatFormatting;
6 | import net.minecraft.client.gui.Font;
7 | import net.minecraft.client.gui.GuiGraphics;
8 | import net.minecraft.client.gui.components.toasts.Toast;
9 | import net.minecraft.client.gui.components.toasts.ToastManager;
10 | import net.minecraft.client.renderer.RenderPipelines;
11 | import net.minecraft.client.renderer.RenderType;
12 | import net.minecraft.network.chat.Component;
13 | import net.minecraft.resources.ResourceLocation;
14 |
15 | /**
16 | * Author: MrCrayfish
17 | */
18 | public class ConnectionToast implements Toast
19 | {
20 | private static final ResourceLocation BACKGROUND_SPRITE = Utils.resource("toast/connection");
21 | private static final Component LABEL_CONNECTED = Component.translatable("controllable.toast.connected").withStyle(ChatFormatting.BLUE).withStyle(ChatFormatting.BOLD);
22 | private static final Component LABEL_DISCONNECTED = Component.translatable("controllable.toast.disconnected").withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD);
23 |
24 | private final boolean connected;
25 | private final Component controllerName;
26 | private Visibility visibility = Visibility.HIDE;
27 |
28 | public ConnectionToast(boolean connected, String controllerName)
29 | {
30 | this.connected = connected;
31 | this.controllerName = Component.literal(controllerName);
32 | }
33 |
34 | @Override
35 | public Visibility getWantedVisibility()
36 | {
37 | return this.visibility;
38 | }
39 |
40 | @Override
41 | public void update(ToastManager manager, long delta)
42 | {
43 | long displayTime = (long) (3000L * manager.getNotificationDisplayTimeMultiplier());
44 | this.visibility = delta < displayTime ? Visibility.SHOW : Visibility.HIDE;
45 | }
46 |
47 | @Override
48 | public void render(GuiGraphics graphics, Font font, long delta)
49 | {
50 | graphics.blitSprite(RenderPipelines.GUI_TEXTURED, BACKGROUND_SPRITE, 0, 0, 160, 32);
51 | graphics.blit(RenderPipelines.GUI_TEXTURED, ControllerLayoutScreen.TEXTURE, 8, 8, 20, 43, 20, 16, 256, 256);
52 | String title = font.plainSubstrByWidth(this.controllerName.getString(), 120);
53 | graphics.drawString(font, title, 35, 7, 0xFFFFFFFF, false);
54 | Component message = this.connected ? LABEL_CONNECTED : LABEL_DISCONNECTED;
55 | graphics.drawString(font, message, 35, 18, 0xFFFFFF00, false);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/widget/BackgroundStringWidget.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.widget;
2 |
3 | import com.mrcrayfish.controllable.client.util.ScreenHelper;
4 | import net.minecraft.client.gui.Font;
5 | import net.minecraft.client.gui.GuiGraphics;
6 | import net.minecraft.client.gui.components.AbstractStringWidget;
7 | import net.minecraft.network.chat.Component;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public class BackgroundStringWidget extends AbstractStringWidget
13 | {
14 | public BackgroundStringWidget(Component message, Font font)
15 | {
16 | this(0, 0, message, font);
17 | }
18 |
19 | public BackgroundStringWidget(int x, int y, Component message, Font font)
20 | {
21 | super(x, y, font.width(message.getVisualOrderText()) + 4, font.lineHeight + 4, message, font);
22 | }
23 |
24 | @Override
25 | public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick)
26 | {
27 | ScreenHelper.drawRoundedBox(graphics, this.getX(), this.getY(), this.getWidth(), this.getHeight(), 0x55000000);
28 | graphics.drawString(this.getFont(), this.getMessage().getVisualOrderText(), this.getX() + 2, this.getY() + 2, this.getColor());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ButtonBindingButton.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.widget;
2 |
3 | import com.mojang.blaze3d.systems.RenderSystem;
4 | import com.mrcrayfish.controllable.Config;
5 | import com.mrcrayfish.controllable.client.binding.ButtonBinding;
6 | import com.mrcrayfish.controllable.client.settings.ButtonIcons;
7 | import net.minecraft.client.Minecraft;
8 | import net.minecraft.client.gui.GuiGraphics;
9 | import net.minecraft.client.gui.components.Button;
10 | import net.minecraft.client.renderer.RenderPipelines;
11 | import net.minecraft.client.renderer.RenderType;
12 | import net.minecraft.network.chat.CommonComponents;
13 |
14 | /**
15 | * Author: MrCrayfish
16 | */
17 | public class ButtonBindingButton extends Button
18 | {
19 | private final ButtonBinding binding;
20 | private final ButtonOnPress onPress;
21 |
22 | public ButtonBindingButton(int x, int y, ButtonBinding binding, ButtonOnPress onPress)
23 | {
24 | super(x, y, 40, 20, CommonComponents.EMPTY, btn -> {}, DEFAULT_NARRATION);
25 | this.binding = binding;
26 | this.onPress = onPress;
27 | }
28 |
29 | public ButtonBinding getBinding()
30 | {
31 | return this.binding;
32 | }
33 |
34 | @Override
35 | public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks)
36 | {
37 | super.renderWidget(graphics, mouseX, mouseY, partialTicks);
38 | if(this.binding.getButton() < 0)
39 | return;
40 | int texU = this.binding.getButton() * 13;
41 | int texV = Config.CLIENT.options.controllerIcons.get().ordinal() * 13;
42 | int size = 13;
43 | graphics.blit(RenderPipelines.GUI_TEXTURED, ButtonIcons.TEXTURE, this.getX() + (this.width - size) / 2 + 1, this.getY() + 3, texU, texV, size, size, ButtonIcons.TEXTURE_WIDTH, ButtonIcons.TEXTURE_HEIGHT);
44 | }
45 |
46 | @Override
47 | public boolean mouseClicked(double mouseX, double mouseY, int button)
48 | {
49 | if(this.active && this.visible && this.isMouseOver(mouseX, mouseY))
50 | {
51 | if(this.onPress.onPress(button))
52 | {
53 | this.playDownSound(Minecraft.getInstance().getSoundManager());
54 | }
55 | return true;
56 | }
57 | return false;
58 | }
59 |
60 | public interface ButtonOnPress
61 | {
62 | boolean onPress(int button);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ColorButton.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.widget;
2 |
3 | import com.mojang.blaze3d.systems.RenderSystem;
4 | import net.minecraft.ChatFormatting;
5 | import net.minecraft.client.gui.GuiGraphics;
6 | import net.minecraft.client.gui.components.Button;
7 | import net.minecraft.network.chat.CommonComponents;
8 | import org.apache.commons.lang3.ArrayUtils;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | public class ColorButton extends Button
14 | {
15 | private static final ChatFormatting[] COLORS = {
16 | ChatFormatting.BLACK,
17 | ChatFormatting.DARK_BLUE,
18 | ChatFormatting.DARK_GREEN,
19 | ChatFormatting.DARK_AQUA,
20 | ChatFormatting.DARK_RED,
21 | ChatFormatting.DARK_PURPLE,
22 | ChatFormatting.GOLD,
23 | ChatFormatting.GRAY,
24 | ChatFormatting.DARK_GRAY,
25 | ChatFormatting.BLUE,
26 | ChatFormatting.GREEN,
27 | ChatFormatting.AQUA,
28 | ChatFormatting.RED,
29 | ChatFormatting.LIGHT_PURPLE,
30 | ChatFormatting.YELLOW,
31 | ChatFormatting.WHITE
32 | };
33 |
34 | private int index = 14;
35 |
36 | public ColorButton(int x, int y, OnPress onPress)
37 | {
38 | super(x, y, 20, 20, CommonComponents.EMPTY, onPress, DEFAULT_NARRATION);
39 | }
40 |
41 | public void setColor(ChatFormatting color)
42 | {
43 | int index = ArrayUtils.indexOf(COLORS, color);
44 | if(index != -1)
45 | {
46 | this.index = index;
47 | }
48 | }
49 |
50 | public ChatFormatting getColor()
51 | {
52 | return COLORS[this.index];
53 | }
54 |
55 | @Override
56 | public void onClick(double mouseX, double mouseY)
57 | {
58 | this.index = (this.index + 1) % COLORS.length;
59 | super.onClick(mouseX, mouseY);
60 | }
61 |
62 | @Override
63 | public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks)
64 | {
65 | super.renderWidget(graphics, mouseX, mouseY, partialTicks);
66 | graphics.fill(this.getX() + 4, this.getY() + 4, this.getX() + 16, this.getY() + 16, 0xFF000000);
67 | graphics.fill(this.getX() + 5, this.getY() + 5, this.getX() + 15, this.getY() + 15, COLORS[this.index].getColor() + 0xFF000000);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ControllerButton.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.widget;
2 |
3 | import com.mojang.blaze3d.systems.RenderSystem;
4 | import com.mrcrayfish.controllable.client.util.ScreenHelper;
5 | import com.mrcrayfish.controllable.util.Utils;
6 | import net.minecraft.client.gui.GuiGraphics;
7 | import net.minecraft.client.gui.components.AbstractWidget;
8 | import net.minecraft.client.gui.components.Button;
9 | import net.minecraft.client.renderer.RenderPipelines;
10 | import net.minecraft.client.renderer.RenderType;
11 | import net.minecraft.network.chat.CommonComponents;
12 | import net.minecraft.resources.ResourceLocation;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | /**
16 | * Author: MrCrayfish
17 | */
18 | public class ControllerButton extends Button
19 | {
20 | private static final ResourceLocation TEXTURE = Utils.resource("textures/gui/controller.png");
21 | private final AbstractWidget widget;
22 |
23 | public ControllerButton(AbstractWidget widget, OnPress onPress)
24 | {
25 | super(0, 0, 20, 20, CommonComponents.EMPTY, onPress, DEFAULT_NARRATION);
26 | this.widget = widget;
27 | }
28 |
29 | @Override
30 | public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks)
31 | {
32 | this.setX(this.widget.getRight() + 4);
33 | this.setY(this.widget.getY());
34 | super.renderWidget(graphics, mouseX, mouseY, partialTicks);
35 | boolean mouseOver = ScreenHelper.isMouseWithin(mouseX, mouseY, this.getX(), this.getY(), this.width, this.height);
36 | int textureV = 43;
37 | if(mouseOver)
38 | {
39 | textureV += this.height;
40 | }
41 | graphics.blit(RenderPipelines.GUI_TEXTURED, TEXTURE, this.getX(), this.getY(), 0, textureV, this.width, this.height, 256, 256);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/widget/ImageButton.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.widget;
2 |
3 | import com.mojang.blaze3d.systems.RenderSystem;
4 | import com.mojang.blaze3d.vertex.PoseStack;
5 | import net.minecraft.client.gui.GuiGraphics;
6 | import net.minecraft.client.gui.components.Button;
7 | import net.minecraft.client.renderer.GameRenderer;
8 | import net.minecraft.client.renderer.RenderPipelines;
9 | import net.minecraft.client.renderer.RenderType;
10 | import net.minecraft.network.chat.CommonComponents;
11 | import net.minecraft.resources.ResourceLocation;
12 | import net.minecraft.util.ARGB;
13 |
14 | /**
15 | * Author: MrCrayfish
16 | */
17 | public class ImageButton extends Button
18 | {
19 | private final ResourceLocation texture;
20 | private final int imageU, imageV;
21 | private final int imageWidth, imageHeight;
22 | private final int textureWidth, textureHeight;
23 |
24 | public ImageButton(int x, int y, int width, ResourceLocation texture, int imageU, int imageV, int imageWidth, int imageHeight, OnPress onPress)
25 | {
26 | this(x, y, width, texture, imageU, imageV, imageWidth, imageHeight, 256, 256, onPress);
27 | }
28 |
29 | public ImageButton(int x, int y, int width, ResourceLocation texture, int imageU, int imageV, int imageWidth, int imageHeight, int textureWidth, int textureHeight, OnPress onPress)
30 | {
31 | super(x, y, width, 20, CommonComponents.EMPTY, onPress, DEFAULT_NARRATION);
32 | this.texture = texture;
33 | this.imageU = imageU;
34 | this.imageV = imageV;
35 | this.imageWidth = imageWidth;
36 | this.imageHeight = imageHeight;
37 | this.textureWidth = textureWidth;
38 | this.textureHeight = textureHeight;
39 | }
40 |
41 | @Override
42 | public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks)
43 | {
44 | super.renderWidget(graphics, mouseX, mouseY, partialTicks);
45 | graphics.blit(RenderPipelines.GUI_TEXTURED, this.texture, this.getX() + (this.width - this.imageWidth) / 2, this.getY() + (this.height - this.imageHeight) / 2, this.imageU, this.imageV, this.imageWidth, this.imageHeight, this.textureWidth, this.textureHeight, !this.active ? ARGB.white(0.5F) : ARGB.white(1));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/widget/TabListWidget.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.widget;
2 |
3 | import com.google.common.collect.ImmutableList;
4 | import com.mojang.blaze3d.vertex.PoseStack;
5 | import com.mrcrayfish.controllable.client.gui.components.TabSelectionList;
6 | import net.minecraft.client.gui.GuiGraphics;
7 | import net.minecraft.client.gui.components.AbstractWidget;
8 | import net.minecraft.client.gui.components.events.ContainerEventHandler;
9 | import net.minecraft.client.gui.components.events.GuiEventListener;
10 | import net.minecraft.client.gui.narration.NarrationElementOutput;
11 | import net.minecraft.client.gui.navigation.ScreenRectangle;
12 | import net.minecraft.network.chat.CommonComponents;
13 |
14 | import org.jetbrains.annotations.Nullable;
15 | import java.util.List;
16 | import java.util.function.Supplier;
17 |
18 | /**
19 | * Author: MrCrayfish
20 | */
21 | public class TabListWidget extends AbstractWidget implements ContainerEventHandler
22 | {
23 | private final Supplier dimensions;
24 | private final TabSelectionList list;
25 |
26 | public TabListWidget(Supplier dimensions, TabSelectionList list)
27 | {
28 | super(0, 0, 100, 0, CommonComponents.EMPTY);
29 | this.dimensions = dimensions;
30 | this.list = list;
31 | }
32 |
33 | @Override
34 | public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick)
35 | {
36 | ScreenRectangle dimensions = this.dimensions.get();
37 | this.setX(dimensions.left());
38 | this.setY(dimensions.top());
39 | this.width = dimensions.width();
40 | this.height = dimensions.height();
41 | this.list.updateDimensions(dimensions);
42 | this.list.render(graphics, mouseX, mouseY, partialTick);
43 | }
44 |
45 | @Override
46 | protected void updateWidgetNarration(NarrationElementOutput output)
47 | {
48 | this.list.updateNarration(output);
49 | }
50 |
51 | @Override
52 | public List extends GuiEventListener> children()
53 | {
54 | return ImmutableList.of(this.list);
55 | }
56 |
57 | @Override
58 | public boolean mouseClicked(double mouseX, double mouseY, int button)
59 | {
60 | return this.list.mouseClicked(mouseX, mouseY, button);
61 | }
62 |
63 | @Override
64 | public boolean mouseDragged(double $$0, double $$1, int $$2, double $$3, double $$4)
65 | {
66 | return this.list.mouseDragged($$0, $$1, $$2, $$3, $$4);
67 | }
68 |
69 | @Override
70 | public boolean mouseReleased(double $$0, double $$1, int $$2)
71 | {
72 | return this.list.mouseReleased($$0, $$1, $$2);
73 | }
74 |
75 | @Override
76 | public boolean mouseScrolled(double mouseX, double mouseY, double xScroll, double yScroll)
77 | {
78 | return this.list.mouseScrolled(mouseX, mouseY, xScroll, yScroll);
79 | }
80 |
81 | @Override
82 | public boolean isDragging()
83 | {
84 | return this.list.isDragging();
85 | }
86 |
87 | @Override
88 | public void setDragging(boolean dragging)
89 | {
90 | this.list.setDragging(dragging);
91 | }
92 |
93 | @Nullable
94 | @Override
95 | public GuiEventListener getFocused()
96 | {
97 | return this.list.getFocused();
98 | }
99 |
100 | @Override
101 | public void setFocused(@Nullable GuiEventListener listener)
102 | {
103 | this.list.setFocused(listener);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/gui/widget/TabNavigationHint.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.gui.widget;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.input.Buttons;
5 | import com.mrcrayfish.controllable.client.input.Controller;
6 | import com.mrcrayfish.controllable.client.util.ClientHelper;
7 | import net.minecraft.client.gui.GuiGraphics;
8 | import net.minecraft.client.gui.components.Renderable;
9 | import net.minecraft.client.gui.components.events.GuiEventListener;
10 | import net.minecraft.client.gui.navigation.ScreenRectangle;
11 |
12 | import java.util.List;
13 |
14 | /**
15 | * Author: MrCrayfish
16 | */
17 | public class TabNavigationHint implements Renderable
18 | {
19 | private final List extends GuiEventListener> tabs;
20 |
21 | public TabNavigationHint(List extends GuiEventListener> tabs)
22 | {
23 | this.tabs = tabs;
24 | }
25 |
26 | @Override
27 | public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick)
28 | {
29 | // Don't render if tabs can't be navigated
30 | Controller controller = Controllable.getController();
31 | if(controller == null || !controller.isBeingUsed())
32 | return;
33 |
34 | ScreenRectangle firstTab = this.tabs.get(0).getRectangle();
35 | ClientHelper.drawButton(graphics, firstTab.left() - 18, (firstTab.height() - 11) / 2, Buttons.LEFT_BUMPER);
36 |
37 | ScreenRectangle lastTab = this.tabs.get(this.tabs.size() - 1).getRectangle();
38 | ClientHelper.drawButton(graphics, lastTab.right() + 5, (lastTab.height() - 11) / 2, Buttons.RIGHT_BUMPER);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/input/ButtonStates.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.input;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public class ButtonStates
7 | {
8 | private final boolean[] states;
9 |
10 | public ButtonStates()
11 | {
12 | this.states = new boolean[Buttons.LENGTH];
13 | }
14 |
15 | public boolean getState(int index)
16 | {
17 | if(index < 0 || index >= states.length)
18 | return false;
19 | return this.states[index];
20 | }
21 |
22 | public void setState(int index, boolean state)
23 | {
24 | if(index < 0 || index >= states.length)
25 | return;
26 | this.states[index] = state;
27 | }
28 |
29 | public int getSize()
30 | {
31 | return this.states.length;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/input/InputLibrary.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.input;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public enum InputLibrary
7 | {
8 | GLFW,
9 | SDL2 // Default
10 | }
11 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/overlay/IOverlay.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.overlay;
2 |
3 | import net.minecraft.client.DeltaTracker;
4 | import net.minecraft.client.gui.GuiGraphics;
5 |
6 | /**
7 | * Author: MrCrayfish
8 | */
9 | public interface IOverlay
10 | {
11 | boolean isVisible();
12 |
13 | default void tick() {}
14 |
15 | void render(GuiGraphics graphics, int mouseX, int mouseY, DeltaTracker tracker);
16 | }
17 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/overlay/OverlayRenderer.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.overlay;
2 |
3 | import com.google.common.collect.ImmutableList;
4 | import com.mrcrayfish.framework.api.event.client.FrameworkClientTickEvents;
5 | import net.minecraft.Util;
6 | import net.minecraft.client.DeltaTracker;
7 | import net.minecraft.client.gui.GuiGraphics;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * Author: MrCrayfish
13 | */
14 | public class OverlayRenderer
15 | {
16 | private static final List OVERLAYS = Util.make(() -> {
17 | ImmutableList.Builder builder = new ImmutableList.Builder<>();
18 | builder.add(new TabNavigationOverlay());
19 | builder.add(new RecipeBookOverlay());
20 | builder.add(new PaperDollPlayerOverlay());
21 | builder.add(new RadialMenuOverlay());
22 | builder.add(new ActionHintOverlay());
23 | builder.add(new VirtualCursorOverlay());
24 | return builder.build();
25 | });
26 |
27 | public static void init()
28 | {
29 | FrameworkClientTickEvents.START_CLIENT.register(() -> OVERLAYS.forEach(IOverlay::tick));
30 | }
31 |
32 | public static void draw(GuiGraphics graphics, int mouseX, int mouseY, DeltaTracker tracker)
33 | {
34 | for(IOverlay overlay : OVERLAYS)
35 | {
36 | if(overlay.isVisible())
37 | {
38 | overlay.render(graphics, mouseX, mouseY, tracker);
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/overlay/PaperDollPlayerOverlay.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.overlay;
2 |
3 | import com.mrcrayfish.controllable.Config;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.input.Controller;
6 | import com.mrcrayfish.controllable.client.util.EventHelper;
7 | import net.minecraft.client.DeltaTracker;
8 | import net.minecraft.client.Minecraft;
9 | import net.minecraft.client.gui.GuiGraphics;
10 | import net.minecraft.client.gui.screens.inventory.InventoryScreen;
11 |
12 | /**
13 | * Author: MrCrayfish
14 | */
15 | public class PaperDollPlayerOverlay implements IOverlay
16 | {
17 | @Override
18 | public boolean isVisible()
19 | {
20 | Controller controller = Controllable.getController();
21 | return !Minecraft.getInstance().options.hideGui && controller != null && (!Config.CLIENT.options.overlayTimeout.get() || controller.isBeingUsed());
22 | }
23 |
24 | @Override
25 | public void render(GuiGraphics graphics, int mouseX, int mouseY, DeltaTracker tracker)
26 | {
27 | Minecraft mc = Minecraft.getInstance();
28 | if(mc.player != null && mc.screen == null && Config.CLIENT.options.paperDoll.get())
29 | {
30 | if(!EventHelper.postRenderMiniPlayer())
31 | {
32 | InventoryScreen.renderEntityInInventoryFollowsMouse(graphics, 0, 0, 50, 70, 20, 0.0625F, 25, 35, mc.player);
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/overlay/RadialMenuOverlay.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.overlay;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import net.minecraft.client.DeltaTracker;
5 | import net.minecraft.client.gui.GuiGraphics;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public class RadialMenuOverlay implements IOverlay
11 | {
12 | @Override
13 | public boolean isVisible()
14 | {
15 | return true;
16 | }
17 |
18 | @Override
19 | public void render(GuiGraphics graphics, int mouseX, int mouseY, DeltaTracker tracker)
20 | {
21 | Controllable.getRadialMenu().onRenderEnd(graphics, tracker);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/overlay/TabNavigationOverlay.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.overlay;
2 |
3 | import com.mrcrayfish.controllable.Config;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.binding.ButtonBindings;
6 | import com.mrcrayfish.controllable.client.input.Buttons;
7 | import com.mrcrayfish.controllable.client.input.Controller;
8 | import com.mrcrayfish.controllable.client.util.ClientHelper;
9 | import net.minecraft.client.DeltaTracker;
10 | import net.minecraft.client.Minecraft;
11 | import net.minecraft.client.gui.GuiGraphics;
12 | import net.minecraft.client.gui.components.events.GuiEventListener;
13 | import net.minecraft.client.gui.components.tabs.TabNavigationBar;
14 | import net.minecraft.client.gui.navigation.ScreenRectangle;
15 | import net.minecraft.client.gui.screens.Screen;
16 |
17 | import java.util.List;
18 |
19 | /**
20 | * Author: MrCrayfish
21 | */
22 | public class TabNavigationOverlay implements IOverlay
23 | {
24 | private TabNavigationBar navigationBar;
25 |
26 | @Override
27 | public void tick()
28 | {
29 | this.navigationBar = null;
30 | Minecraft mc = Minecraft.getInstance();
31 | Screen screen = mc.screen;
32 | if(screen != null)
33 | {
34 | this.navigationBar = screen.children().stream().filter(e -> e instanceof TabNavigationBar).map(listener -> (TabNavigationBar) listener).findFirst().orElse(null);
35 | }
36 | }
37 |
38 | @Override
39 | public boolean isVisible()
40 | {
41 | Controller controller = Controllable.getController();
42 | return controller != null && (!Config.CLIENT.options.overlayTimeout.get() || controller.isBeingUsed()) && this.navigationBar != null;
43 | }
44 |
45 | @Override
46 | public void render(GuiGraphics graphics, int mouseX, int mouseY, DeltaTracker tracker)
47 | {
48 | List extends GuiEventListener> tabs = this.navigationBar.children();
49 | ScreenRectangle firstTab = tabs.get(0).getRectangle();
50 | ClientHelper.drawButton(graphics, firstTab.left() - 18, (firstTab.height() - 11) / 2, ButtonBindings.NEXT_RECIPE_TAB.getButton());
51 | ScreenRectangle lastTab = tabs.get(tabs.size() - 1).getRectangle();
52 | ClientHelper.drawButton(graphics, lastTab.right() + 5, (lastTab.height() - 11) / 2, ButtonBindings.PREVIOUS_RECIPE_TAB.getButton());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/overlay/VirtualCursorOverlay.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.overlay;
2 |
3 | import com.mojang.blaze3d.vertex.PoseStack;
4 | import com.mrcrayfish.controllable.Config;
5 | import com.mrcrayfish.controllable.Controllable;
6 | import com.mrcrayfish.controllable.client.input.Controller;
7 | import com.mrcrayfish.controllable.client.settings.CursorStyle;
8 | import com.mrcrayfish.controllable.platform.ClientServices;
9 | import net.minecraft.client.DeltaTracker;
10 | import net.minecraft.client.Minecraft;
11 | import net.minecraft.client.gui.GuiGraphics;
12 | import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
13 | import net.minecraft.client.renderer.RenderPipelines;
14 | import net.minecraft.client.renderer.RenderType;
15 | import net.minecraft.world.inventory.Slot;
16 |
17 | /**
18 | * Author: MrCrayfish
19 | */
20 | public class VirtualCursorOverlay implements IOverlay
21 | {
22 | @Override
23 | public boolean isVisible()
24 | {
25 | Controller controller = Controllable.getController();
26 | return Minecraft.getInstance().getOverlay() == null && Minecraft.getInstance().screen != null && controller != null && controller.isUsingVirtualCursor() && Controllable.getCursor().isVisible();
27 | }
28 |
29 | @Override
30 | public void render(GuiGraphics graphics, int mouseX, int mouseY, DeltaTracker tracker)
31 | {
32 | graphics.pose().pushMatrix();
33 | Minecraft mc = Minecraft.getInstance();
34 | CursorStyle type = Config.CLIENT.options.cursorType.get();
35 | if(mc.player == null || (mc.player.inventoryMenu.getCarried().isEmpty() || type.getBehaviour() == CursorStyle.ItemHeldBehaviour.SHOW))
36 | {
37 | double guiScale = mc.getWindow().getGuiScale();
38 | double cursorX = Controllable.getCursor().getRenderX();
39 | double cursorY = Controllable.getCursor().getRenderY();
40 | graphics.pose().translate((float) (cursorX / guiScale), (float) (cursorY / guiScale));
41 | boolean isHoveringSlot = this.isHoveringFilledContainerSlot();
42 | if(isHoveringSlot && type.isScaleHover())
43 | {
44 | graphics.pose().scale(1.33F, 1.33F);
45 | }
46 | graphics.blit(RenderPipelines.GUI_TEXTURED, CursorStyle.TEXTURE, -8, -8, isHoveringSlot ? 32 : 0, type.ordinal() * 32, 16, 16, 32, 32, 64, CursorStyle.values().length * 32);
47 | }
48 | graphics.pose().popMatrix();
49 | }
50 |
51 | /**
52 | * @return True if the cursor is hovering a container slot
53 | */
54 | private boolean isHoveringFilledContainerSlot()
55 | {
56 | Minecraft mc = Minecraft.getInstance();
57 | if(mc.screen instanceof AbstractContainerScreen> screen)
58 | {
59 | Slot slot = ClientServices.CLIENT.getSlotUnderMouse(screen);
60 | return slot != null && slot.hasItem();
61 | }
62 | return false;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/ActionVisibility.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public enum ActionVisibility implements SettingEnum
7 | {
8 | ALL("controllable.action_visibility.all"),
9 | MINIMAL("controllable.action_visibility.minimal"),
10 | NONE("controllable.action_visibility.none");
11 |
12 | private final String key;
13 |
14 | ActionVisibility(String key)
15 | {
16 | this.key = key;
17 | }
18 |
19 | @Override
20 | public String getKey()
21 | {
22 | return this.key;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/AnalogMovement.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public enum AnalogMovement implements SettingEnum
7 | {
8 | DISABLED("controllable.analog_movement.disabled"),
9 | LOCAL_ONLY("controllable.analog_movement.local_only"),
10 | ALWAYS("controllable.analog_movement.always");
11 |
12 | private final String key;
13 |
14 | AnalogMovement(String key)
15 | {
16 | this.key = key;
17 | }
18 |
19 | @Override
20 | public String getKey()
21 | {
22 | return this.key;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/ButtonIcons.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | import com.mrcrayfish.controllable.client.input.Buttons;
4 | import com.mrcrayfish.controllable.util.Utils;
5 | import net.minecraft.resources.ResourceLocation;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public enum ButtonIcons implements SettingEnum
11 | {
12 | DEFAULT("controllable.controller.default"),
13 | PLAYSTATION_5("controllable.controller.playstation_5"),
14 | PLAYSTATION_4("controllable.controller.playstation_4"),
15 | PLAYSTATION_3("controllable.controller.playstation_3"),
16 | XBOX_ONE("controllable.controller.xbox_one"),
17 | XBOX_360("controllable.controller.xbox_360"),
18 | SWITCH_JOYCONS("controllable.controller.switch_joycons"),
19 | SWITCH_CONTROLLER("controllable.controller.switch_controller"),
20 | GAMECUBE("controllable.controller.gamecube"),
21 | STEAM("controllable.controller.steam");
22 |
23 | public static final ResourceLocation TEXTURE = Utils.resource("textures/gui/buttons.png");
24 | public static final int TEXTURE_WIDTH = Buttons.LENGTH * 13;
25 | public static final int TEXTURE_HEIGHT = values().length * 13;
26 |
27 | private final String key;
28 |
29 | ButtonIcons(String key)
30 | {
31 | this.key = key;
32 | }
33 |
34 | @Override
35 | public String getKey()
36 | {
37 | return this.key;
38 | }
39 |
40 | public static void main(String[] args)
41 | {
42 | System.out.print("\"");
43 | for(int i = 0; i < values().length * Buttons.LENGTH; i++)
44 | {
45 | System.out.print("\\u" + Integer.toHexString((33 + i) | 0x10000).substring(1));
46 | if(i > 0 && (i + 1) % Buttons.LENGTH == 0)
47 | {
48 | System.out.print("\",");
49 | System.out.println();
50 | System.out.print("\"");
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/CursorStyle.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | import com.mrcrayfish.controllable.util.Utils;
4 | import net.minecraft.resources.ResourceLocation;
5 |
6 | /**
7 | * Author: MrCrayfish
8 | */
9 | public enum CursorStyle implements SettingEnum
10 | {
11 | LIGHT("controllable.cursor.light", ItemHeldBehaviour.HIDE, true),
12 | DARK("controllable.cursor.dark", ItemHeldBehaviour.HIDE, true),
13 | CONSOLE("controllable.cursor.console", ItemHeldBehaviour.SHOW, false),
14 | CONSOLE_PLUS("controllable.cursor.console_plus", ItemHeldBehaviour.HIDE, true),
15 | LEGACY_LIGHT("controllable.cursor.legacy_light", ItemHeldBehaviour.HIDE, true),
16 | LEGACY_DARK("controllable.cursor.legacy_dark", ItemHeldBehaviour.HIDE, true);
17 |
18 | public static final ResourceLocation TEXTURE = Utils.resource("textures/gui/cursor.png");
19 |
20 | private final String key;
21 | private final ItemHeldBehaviour behaviour;
22 | private final boolean scaleHover;
23 |
24 | CursorStyle(String key, ItemHeldBehaviour behaviour, boolean scaleHover)
25 | {
26 | this.key = key;
27 | this.behaviour = behaviour;
28 | this.scaleHover = scaleHover;
29 | }
30 |
31 | @Override
32 | public String getKey()
33 | {
34 | return this.key;
35 | }
36 |
37 | public ItemHeldBehaviour getBehaviour()
38 | {
39 | return this.behaviour;
40 | }
41 |
42 | public boolean isScaleHover()
43 | {
44 | return this.scaleHover;
45 | }
46 |
47 | public enum ItemHeldBehaviour
48 | {
49 | SHOW, HIDE;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/SettingEnum.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | import net.minecraft.network.chat.Component;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public interface SettingEnum
9 | {
10 | String getKey();
11 |
12 | default Component getLabel()
13 | {
14 | return Component.translatable(this.getKey());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/SettingProvider.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | import net.minecraft.client.gui.components.AbstractWidget;
4 |
5 | import java.util.function.Supplier;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public interface SettingProvider
11 | {
12 | Supplier createWidget(int x, int y, int width, int height);
13 | }
14 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/SneakMode.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public enum SneakMode implements SettingEnum
7 | {
8 | TOGGLE("controllable.sneak_mode.toggle"),
9 | HOLD("controllable.sneak_mode.hold");
10 |
11 | private final String key;
12 |
13 | SneakMode(String key)
14 | {
15 | this.key = key;
16 | }
17 |
18 | @Override
19 | public String getKey()
20 | {
21 | return this.key;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/SprintMode.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public enum SprintMode implements SettingEnum
7 | {
8 | TOGGLE("controllable.sprint_mode.toggle"),
9 | ONCE("controllable.sprint_mode.once");
10 |
11 | private final String key;
12 |
13 | SprintMode(String key)
14 | {
15 | this.key = key;
16 | }
17 |
18 | @Override
19 | public String getKey()
20 | {
21 | return this.key;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/Thumbstick.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public enum Thumbstick implements SettingEnum
7 | {
8 | LEFT("controllable.thumbstick.left"),
9 | RIGHT("controllable.thumbstick.right");
10 |
11 | private final String key;
12 |
13 | Thumbstick(String key)
14 | {
15 | this.key = key;
16 | }
17 |
18 | @Override
19 | public String getKey()
20 | {
21 | return this.key;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/settings/VanillaSetting.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.settings;
2 |
3 | import net.minecraft.client.Minecraft;
4 | import net.minecraft.client.OptionInstance;
5 | import net.minecraft.client.gui.components.AbstractWidget;
6 |
7 | import java.util.function.Supplier;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public class VanillaSetting implements SettingProvider
13 | {
14 | private final Supplier> optionSupplier;
15 |
16 | public VanillaSetting(Supplier> optionSupplier)
17 | {
18 | this.optionSupplier = optionSupplier;
19 | }
20 |
21 | @Override
22 | public Supplier createWidget(int x, int y, int width, int height)
23 | {
24 | return () -> this.optionSupplier.get().createButton(Minecraft.getInstance().options, x, y, width);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/util/EventHelper.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.util;
2 |
3 | import com.mrcrayfish.controllable.client.input.Controller;
4 | import com.mrcrayfish.controllable.event.ControllerEvents;
5 | import com.mrcrayfish.controllable.event.Value;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public class EventHelper
11 | {
12 | public static boolean postMoveEvent()
13 | {
14 | return ControllerEvents.UPDATE_MOVEMENT.post().handle();
15 | }
16 |
17 | public static boolean postInputEvent(Controller controller, Value newButton, int button, boolean state)
18 | {
19 | return ControllerEvents.INPUT.post().handle(controller, newButton, button, state);
20 | }
21 |
22 | public static boolean postButtonEvent(Controller controller)
23 | {
24 | return ControllerEvents.BUTTON.post().handle(controller);
25 | }
26 |
27 | public static boolean postUpdateCameraEvent(Value yawSpeed, Value pitchSpeed)
28 | {
29 | return ControllerEvents.UPDATE_CAMERA.post().handle(yawSpeed, pitchSpeed);
30 | }
31 |
32 | public static boolean postRenderMiniPlayer()
33 | {
34 | return ControllerEvents.RENDER_MINI_PLAYER.post().handle();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/util/InputHelper.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.util;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.binding.ButtonBinding;
5 | import com.mrcrayfish.controllable.client.binding.ButtonBindings;
6 | import com.mrcrayfish.controllable.client.input.Controller;
7 | import net.minecraft.util.Mth;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | public class InputHelper
13 | {
14 | public static float getCombinedPressedValue(Controller controller, ButtonBinding first, ButtonBinding second)
15 | {
16 | ButtonBinding active = Controllable.getInputHandler().getActiveVirtualBinding();
17 | float firstValue = active == first ? controller.getPressedValue(ButtonBindings.RADIAL_MENU.getButton()) : controller.getPressedValue(first.getButton());
18 | float secondValue = active == second ? controller.getPressedValue(ButtonBindings.RADIAL_MENU.getButton()) : controller.getPressedValue(second.getButton());
19 | if(firstValue > 0 && secondValue > 0) // Both pressed equals centered
20 | return 0;
21 | return secondValue - firstValue;
22 | }
23 |
24 | public static float applyDeadzone(float input, float deadZone)
25 | {
26 | return Mth.sign(input) * Math.max(Mth.abs(input) - deadZone, 0.0F) / (1.0F - deadZone);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/client/util/MutableClientInput.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.util;
2 |
3 | import com.mrcrayfish.controllable.platform.ClientServices;
4 | import net.minecraft.client.player.ClientInput;
5 | import net.minecraft.world.entity.player.Input;
6 | import org.joml.Vector2f;
7 |
8 | /**
9 | * Author: MrCrayfish
10 | */
11 | public class MutableClientInput
12 | {
13 | private final ClientInput original;
14 | private boolean changed;
15 | private boolean forward;
16 | private boolean backward;
17 | private boolean left;
18 | private boolean right;
19 | private boolean jump;
20 | private boolean shift;
21 | private boolean sprint;
22 | private final Vector2f moveVector;
23 |
24 | public MutableClientInput(ClientInput input)
25 | {
26 | this.original = input;
27 | this.moveVector = new Vector2f(input.getMoveVector().x, input.getMoveVector().y);
28 | }
29 |
30 | public void apply()
31 | {
32 | if(this.changed)
33 | {
34 | this.original.keyPresses = new Input(
35 | this.original.keyPresses.forward() || this.forward,
36 | this.original.keyPresses.backward() || this.backward,
37 | this.original.keyPresses.left() || this.left,
38 | this.original.keyPresses.right() || this.right,
39 | this.original.keyPresses.jump() || this.jump,
40 | this.original.keyPresses.shift() || this.shift,
41 | this.original.keyPresses.sprint() || this.sprint
42 | );
43 | ClientServices.CLIENT.updateMoveVector(this.original, this.moveVector);
44 | }
45 | }
46 |
47 | public void setForward(boolean forward)
48 | {
49 | this.forward = forward;
50 | this.changed = true;
51 | }
52 |
53 | public void setBackward(boolean backward)
54 | {
55 | this.backward = backward;
56 | this.changed = true;
57 | }
58 |
59 | public void setLeft(boolean left)
60 | {
61 | this.left = left;
62 | this.changed = true;
63 | }
64 |
65 | public void setRight(boolean right)
66 | {
67 | this.right = right;
68 | this.changed = true;
69 | }
70 |
71 | public void setJump(boolean jump)
72 | {
73 | this.jump = jump;
74 | this.changed = true;
75 | }
76 |
77 | public void setShift(boolean shift)
78 | {
79 | this.shift = shift;
80 | this.changed = true;
81 | }
82 |
83 | public void setSprint(boolean sprint)
84 | {
85 | this.sprint = sprint;
86 | this.changed = true;
87 | }
88 |
89 | public void setLeftImpulse(float leftImpulse)
90 | {
91 | this.moveVector.set(leftImpulse, this.moveVector.y);
92 | this.changed = true;
93 | }
94 |
95 | public void setForwardImpulse(float forwardImpulse)
96 | {
97 | this.moveVector.set(this.moveVector.x, forwardImpulse);
98 | this.changed = true;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/event/Value.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.event;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public class Value
7 | {
8 | private T value;
9 |
10 | public Value(T initialValue)
11 | {
12 | this.value = initialValue;
13 | }
14 |
15 | public void set(T value)
16 | {
17 | this.value = value;
18 | }
19 |
20 | public T get()
21 | {
22 | return this.value;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/integration/ControllableJeiPlugin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.integration;
2 |
3 | import com.mrcrayfish.controllable.Constants;
4 | import com.mrcrayfish.controllable.util.Utils;
5 | import mezz.jei.api.IModPlugin;
6 | import mezz.jei.api.JeiPlugin;
7 | import mezz.jei.api.runtime.IJeiRuntime;
8 | import net.minecraft.resources.ResourceLocation;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | @JeiPlugin
14 | public class ControllableJeiPlugin implements IModPlugin
15 | {
16 | private static final ResourceLocation ID = Utils.resource("jei_plugin");
17 |
18 | private static IJeiRuntime runtime;
19 |
20 | @Override
21 | public ResourceLocation getPluginUid()
22 | {
23 | return ID;
24 | }
25 |
26 | @Override
27 | public void onRuntimeAvailable(IJeiRuntime runtime)
28 | {
29 | ControllableJeiPlugin.runtime = runtime;
30 | }
31 |
32 | @Override
33 | public void onRuntimeUnavailable()
34 | {
35 | ControllableJeiPlugin.runtime = null;
36 | }
37 |
38 | public static IJeiRuntime getRuntime()
39 | {
40 | return runtime;
41 | }
42 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/integration/JeiSupport.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.integration;
2 |
3 | import com.mrcrayfish.controllable.client.gui.navigation.BasicNavigationPoint;
4 | import com.mrcrayfish.controllable.client.gui.navigation.NavigationPoint;
5 | import com.mrcrayfish.controllable.client.gui.navigation.WidgetNavigationPoint;
6 | import com.mrcrayfish.controllable.mixin.client.jei.GuiIconToggleButtonMixin;
7 | import com.mrcrayfish.controllable.mixin.client.jei.IngredientGridMixin;
8 | import com.mrcrayfish.controllable.mixin.client.jei.IngredientGridWithNavigationMixin;
9 | import com.mrcrayfish.controllable.mixin.client.jei.IngredientListOverlayMixin;
10 | import com.mrcrayfish.controllable.mixin.client.jei.PageNavigationMixin;
11 | import mezz.jei.common.util.ImmutableRect2i;
12 | import mezz.jei.gui.PageNavigation;
13 | import mezz.jei.gui.elements.GuiIconButton;
14 | import mezz.jei.gui.elements.GuiIconToggleButton;
15 | import mezz.jei.gui.overlay.IngredientGrid;
16 | import mezz.jei.gui.overlay.IngredientGridWithNavigation;
17 | import mezz.jei.gui.overlay.IngredientListRenderer;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 | import java.util.Optional;
22 |
23 | /**
24 | * Author: MrCrayfish
25 | */
26 | public class JeiSupport
27 | {
28 | public static List getNavigationPoints()
29 | {
30 | List points = new ArrayList<>();
31 | Optional.ofNullable(ControllableJeiPlugin.getRuntime()).ifPresent(runtime ->
32 | {
33 | if(runtime.getIngredientListOverlay().isListDisplayed())
34 | {
35 | // JEI just needs getters, and I wouldn't have to do this mess
36 | IngredientGridWithNavigation ingredientGridWithNavigation = ((IngredientListOverlayMixin) runtime.getIngredientListOverlay()).controllableGetContents();
37 | IngredientGrid ingredientGrid = ((IngredientGridWithNavigationMixin) ingredientGridWithNavigation).controllableGetIngredientGrid();
38 | IngredientListRenderer ingredientListRenderer = ((IngredientGridMixin) ingredientGrid).controllableGetIngredientListRenderer();
39 |
40 | // Add each item on the screen as a navigation point
41 | ingredientListRenderer.getSlots().forEach(slot ->
42 | {
43 | ImmutableRect2i area = slot.getArea();
44 | points.add(new BasicNavigationPoint(area.getX() + area.getWidth() / 2.0, area.getY() + area.getHeight() / 2.0));
45 | });
46 |
47 | PageNavigation navigation = ((IngredientGridWithNavigationMixin) ingredientGridWithNavigation).controllableGetNavigation();
48 | GuiIconButton backButton = ((PageNavigationMixin) navigation).controllableGetBackButton();
49 | points.add(new WidgetNavigationPoint(backButton));
50 | GuiIconButton nextButton = ((PageNavigationMixin) navigation).controllableGetNextButton();
51 | points.add(new WidgetNavigationPoint(nextButton));
52 |
53 | GuiIconToggleButton configToggleButton = ((IngredientListOverlayMixin) runtime.getIngredientListOverlay()).controllableGetConfigButton();
54 | GuiIconButton configButton = ((GuiIconToggleButtonMixin) configToggleButton).controllableGetButton();
55 | points.add(new WidgetNavigationPoint(nextButton));
56 | }
57 | });
58 | return points;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/ClientRecipeBookMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
4 | import com.mrcrayfish.controllable.Config;
5 | import net.minecraft.client.ClientRecipeBook;
6 | import org.spongepowered.asm.mixin.Mixin;
7 | import org.spongepowered.asm.mixin.injection.At;
8 |
9 | @Mixin(ClientRecipeBook.class)
10 | public class ClientRecipeBookMixin
11 | {
12 | /*
13 | * Prevents grouping recipes in the recipe book when quick craft mode is enabled. Interacting
14 | * with grouped recipes is difficult on controller, so flattening them all to single entries
15 | * feels a lot better. If quick craft option is toggled on or off during runtime, it will
16 | * automatically group/ungroup the recipes.
17 | */
18 | @ModifyExpressionValue(method = "categorizeAndGroupRecipes", at = @At(value = "INVOKE", target = "Ljava/util/OptionalInt;isEmpty()Z"))
19 | private static boolean test(boolean original)
20 | {
21 | return original || Config.CLIENT.options.quickCraft.get();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/ContainerScreenMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.binding.ButtonBindings;
6 | import com.mrcrayfish.controllable.client.input.Controller;
7 | import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.injection.At;
10 |
11 | /**
12 | * Author: MrCrayfish
13 | */
14 | @Mixin(AbstractContainerScreen.class)
15 | public abstract class ContainerScreenMixin
16 | {
17 | @ModifyExpressionValue(method = "mouseClicked", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/InputConstants;isKeyDown(JI)Z", ordinal = 0))
18 | private boolean isQuickMovePressedOnClick(boolean original)
19 | {
20 | Controller controller = Controllable.getController();
21 | if(controller != null && ButtonBindings.QUICK_MOVE.isButtonDown())
22 | {
23 | return true;
24 | }
25 | return original;
26 | }
27 |
28 | @ModifyExpressionValue(method = "mouseReleased", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/InputConstants;isKeyDown(JI)Z", ordinal = 0))
29 | private boolean isQuickMovePressedOnReleased(boolean original)
30 | {
31 | Controller controller = Controllable.getController();
32 | if(controller != null && ButtonBindings.QUICK_MOVE.isButtonDown())
33 | {
34 | return true;
35 | }
36 | return original;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/GameRendererMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.llamalad7.mixinextras.sugar.Local;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.input.Controller;
6 | import com.mrcrayfish.controllable.client.overlay.OverlayRenderer;
7 | import net.minecraft.client.DeltaTracker;
8 | import net.minecraft.client.Minecraft;
9 | import net.minecraft.client.gui.GuiGraphics;
10 | import net.minecraft.client.renderer.GameRenderer;
11 | import org.spongepowered.asm.mixin.Final;
12 | import org.spongepowered.asm.mixin.Mixin;
13 | import org.spongepowered.asm.mixin.Shadow;
14 | import org.spongepowered.asm.mixin.Unique;
15 | import org.spongepowered.asm.mixin.injection.At;
16 | import org.spongepowered.asm.mixin.injection.Inject;
17 | import org.spongepowered.asm.mixin.injection.ModifyVariable;
18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
19 |
20 | /**
21 | * Author: MrCrayfish
22 | */
23 | @Mixin(GameRenderer.class)
24 | public class GameRendererMixin
25 | {
26 | @Unique
27 | private int controllable$captureMouseX;
28 |
29 | @Unique
30 | private int controllable$captureMouseY;
31 |
32 | @Unique
33 | private GuiGraphics controllable$graphics;
34 |
35 | @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;getOverlay()Lnet/minecraft/client/gui/screens/Overlay;", ordinal = 0))
36 | private void captureLocals(DeltaTracker tracker, boolean p_109096_, CallbackInfo ci, @Local(ordinal = 0) int mouseX, @Local(ordinal = 1) int mouseY, @Local(ordinal = 0) GuiGraphics graphics)
37 | {
38 | this.controllable$captureMouseX = mouseX;
39 | this.controllable$captureMouseY = mouseY;
40 | this.controllable$graphics = graphics;
41 | }
42 |
43 | @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/render/GuiRenderer;render(Lcom/mojang/blaze3d/buffers/GpuBufferSlice;)V"))
44 | private void renderOverlay(DeltaTracker tracker, boolean p_109096_, CallbackInfo ci)
45 | {
46 | if(this.controllable$graphics != null)
47 | {
48 | OverlayRenderer.draw(this.controllable$graphics, this.controllable$captureMouseX, this.controllable$captureMouseY, tracker);
49 | this.controllable$graphics = null;
50 | }
51 | }
52 |
53 | @ModifyVariable(method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/CommandEncoder;clearDepthTexture(Lcom/mojang/blaze3d/textures/GpuTexture;D)V", remap = false, ordinal = 0), index = 4, ordinal = 0, require = 1)
54 | private int controllableModifyMouseX(int original)
55 | {
56 | Controller controller = Controllable.getController();
57 | if(controller != null && controller.isUsingVirtualCursor())
58 | {
59 | return (int) Controllable.getCursor().getRenderScreenX();
60 | }
61 | return original;
62 | }
63 |
64 | @ModifyVariable(method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/CommandEncoder;clearDepthTexture(Lcom/mojang/blaze3d/textures/GpuTexture;D)V", remap = false, ordinal = 0), index = 5, ordinal = 1, require = 1)
65 | private int controllableModifyMouseY(int original)
66 | {
67 | Controller controller = Controllable.getController();
68 | if(controller != null && controller.isUsingVirtualCursor())
69 | {
70 | return (int) Controllable.getCursor().getRenderScreenY();
71 | }
72 | return original;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/GuiMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
4 | import com.mrcrayfish.controllable.Config;
5 | import com.mrcrayfish.controllable.Controllable;
6 | import com.mrcrayfish.controllable.client.binding.ButtonBindings;
7 | import net.minecraft.client.DeltaTracker;
8 | import net.minecraft.client.gui.Gui;
9 | import net.minecraft.client.gui.GuiGraphics;
10 | import org.spongepowered.asm.mixin.Mixin;
11 | import org.spongepowered.asm.mixin.injection.At;
12 | import org.spongepowered.asm.mixin.injection.Inject;
13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14 |
15 | /**
16 | * Author: MrCrayfish
17 | */
18 | @Mixin(Gui.class)
19 | public class GuiMixin
20 | {
21 | @ModifyExpressionValue(method = "renderTabList", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;isDown()Z"))
22 | private boolean controllableRenderPlayerList(boolean original)
23 | {
24 | return original || Controllable.getController() != null && ButtonBindings.PLAYER_LIST.isButtonDown();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/LocalPlayerMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import net.minecraft.client.player.LocalPlayer;
5 | import net.minecraft.util.Mth;
6 | import org.spongepowered.asm.mixin.Mixin;
7 | import org.spongepowered.asm.mixin.Unique;
8 | import org.spongepowered.asm.mixin.injection.At;
9 | import org.spongepowered.asm.mixin.injection.Inject;
10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
11 |
12 | /**
13 | * Author: MrCrayfish
14 | */
15 | @Mixin(LocalPlayer.class)
16 | public class LocalPlayerMixin
17 | {
18 | @Unique
19 | private float controllable$lastHealth;
20 |
21 | @Inject(method = "hurtTo", at = @At(value = "HEAD"))
22 | private void controllableOnPlayerDamage(float newHealth, CallbackInfo ci)
23 | {
24 | if(newHealth < this.controllable$lastHealth)
25 | {
26 | float damage = Math.max(0, this.controllable$lastHealth - newHealth);
27 | LocalPlayer player = (LocalPlayer) (Object) this;
28 | Controllable.getRumbleHandler().onDamage(player, damage);
29 | }
30 | this.controllable$lastHealth = newHealth;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/MouseHandlerMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.VirtualCursor;
5 | import net.minecraft.client.Minecraft;
6 | import net.minecraft.client.MouseHandler;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.injection.At;
9 | import org.spongepowered.asm.mixin.injection.Inject;
10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
11 |
12 | @Mixin(MouseHandler.class)
13 | public class MouseHandlerMixin
14 | {
15 | @Inject(method = "onMove", at = @At(value = "HEAD"))
16 | private void controllableOnMouseMoved(long windowId, double mouseX, double mouseY, CallbackInfo ci)
17 | {
18 | if(windowId == Minecraft.getInstance().getWindow().getWindow())
19 | {
20 | Controllable.getCursor().setMode(VirtualCursor.CursorMode.MOUSE);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/MouseHelperMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.InputHandler;
5 | import com.mrcrayfish.controllable.client.input.Controller;
6 | import net.minecraft.client.Minecraft;
7 | import net.minecraft.client.MouseHandler;
8 | import org.spongepowered.asm.mixin.Final;
9 | import org.spongepowered.asm.mixin.Mixin;
10 | import org.spongepowered.asm.mixin.Shadow;
11 | import org.spongepowered.asm.mixin.Unique;
12 | import org.spongepowered.asm.mixin.injection.At;
13 | import org.spongepowered.asm.mixin.injection.Inject;
14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
15 |
16 | /**
17 | * Author: MrCrayfish
18 | */
19 | @Mixin(MouseHandler.class)
20 | public abstract class MouseHelperMixin
21 | {
22 | @Unique
23 | private boolean controllable$releaseBypass;
24 |
25 | @Shadow
26 | private double accumulatedDX;
27 |
28 | @Shadow
29 | private double accumulatedDY;
30 |
31 | @Shadow
32 | public abstract void releaseMouse();
33 |
34 | /*
35 | * In Controllable, the mouse remains grabbed (aka hidden) when in screens like the inventory.
36 | * However, this allows the player to turn the camera while in a screen, something that isn't
37 | * normally possible. To fix that, as soon as we detect movement from the mouse, we make it
38 | * appear again.
39 | */
40 | @Inject(method = "handleAccumulatedMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;isMouseGrabbed()Z"), cancellable = true)
41 | private void controllableBeforeUpdateLook(CallbackInfo ci)
42 | {
43 | Minecraft minecraft = Minecraft.getInstance();
44 | if(minecraft.screen != null)
45 | {
46 | if(Math.abs(this.accumulatedDX) > 0 || Math.abs(this.accumulatedDY) > 0)
47 | {
48 | this.controllable$releaseBypass = true;
49 | this.releaseMouse(); // Release mouse since it may be grabbed
50 | this.controllable$releaseBypass = false;
51 | this.accumulatedDX = 0;
52 | this.accumulatedDY = 0;
53 | ci.cancel();
54 | }
55 | }
56 | }
57 |
58 | /*
59 | * Prevents the cursor from being released when opening screens when using a controller. Since
60 | * Controllable uses a virtual cursor, it doesn't make sense to have the system cursor appear
61 | * when opening a screen (like the inventory).
62 | */
63 | @Inject(method = "releaseMouse", at = @At(value = "HEAD"), cancellable = true)
64 | private void controllableGrabCursor(CallbackInfo ci)
65 | {
66 | Controller controller = Controllable.getController();
67 | if(controller != null && controller.isUsingVirtualCursor() && !this.controllable$releaseBypass)
68 | {
69 | ci.cancel();
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/OverlayRecipeComponentAccessor.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import net.minecraft.client.gui.components.AbstractWidget;
4 | import net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.gen.Accessor;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | @Mixin(OverlayRecipeComponent.class)
14 | public interface OverlayRecipeComponentAccessor
15 | {
16 | @Accessor("recipeButtons")
17 | List controllableGetRecipeButtons();
18 | }
19 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookComponentAccessor.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import net.minecraft.client.gui.components.StateSwitchingButton;
4 | import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
5 | import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
6 | import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.gen.Accessor;
9 | import org.spongepowered.asm.mixin.gen.Invoker;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Author: MrCrayfish
15 | */
16 | @Mixin(RecipeBookComponent.class)
17 | public interface RecipeBookComponentAccessor
18 | {
19 | @Accessor("filterButton")
20 | StateSwitchingButton controllableGetFilterButton();
21 |
22 | @Accessor("tabButtons")
23 | List controllableGetRecipeTabs();
24 |
25 | @Accessor("recipeBookPage")
26 | RecipeBookPage controllableGetRecipeBookPage();
27 |
28 | @Accessor("selectedTab")
29 | RecipeBookTabButton controllableGetCurrentTab();
30 |
31 | @Accessor("selectedTab")
32 | void controllableSetCurrentTab(RecipeBookTabButton tab);
33 |
34 | @Invoker("updateCollections")
35 | void controllableUpdateCollections(boolean resetPages, boolean filtering);
36 |
37 | @Accessor("tabButtons")
38 | List controllableGetTabButtons();
39 |
40 | @Invoker("isFiltering")
41 | boolean controllableIsFiltering();
42 | }
43 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookPageAccessor.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import net.minecraft.client.gui.components.StateSwitchingButton;
4 | import net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent;
5 | import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
6 | import net.minecraft.client.gui.screens.recipebook.RecipeButton;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.gen.Accessor;
9 | import org.spongepowered.asm.mixin.gen.Invoker;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Author: MrCrayfish
15 | */
16 | @Mixin(RecipeBookPage.class)
17 | public interface RecipeBookPageAccessor
18 | {
19 | @Accessor("buttons")
20 | List controllableGetButtons();
21 |
22 | @Accessor("forwardButton")
23 | StateSwitchingButton controllableGetForwardButton();
24 |
25 | @Accessor("backButton")
26 | StateSwitchingButton controllableGetBackButton();
27 |
28 | @Accessor("currentPage")
29 | int controllableGetCurrentPage();
30 |
31 | @Accessor("currentPage")
32 | void controllableSetCurrentPage(int page);
33 |
34 | @Invoker("updateButtonsForPage")
35 | void controllableUpdateButtonsForPage();
36 |
37 | @Accessor("overlay")
38 | OverlayRecipeComponent controllableGetOverlay();
39 | }
40 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/RecipeBookPageMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mrcrayfish.controllable.Config;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.binding.ButtonBindings;
6 | import com.mrcrayfish.controllable.client.input.Controller;
7 | import com.mrcrayfish.controllable.client.util.ClientHelper;
8 | import com.mrcrayfish.controllable.platform.ClientServices;
9 | import net.minecraft.ChatFormatting;
10 | import net.minecraft.client.Minecraft;
11 | import net.minecraft.client.gui.GuiGraphics;
12 | import net.minecraft.client.gui.components.AbstractWidget;
13 | import net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent;
14 | import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
15 | import net.minecraft.network.chat.Component;
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 | import java.util.List;
24 |
25 | /**
26 | * Author: MrCrayfish
27 | */
28 | @Mixin(RecipeBookPage.class)
29 | public class RecipeBookPageMixin
30 | {
31 | @Shadow
32 | @Final
33 | private OverlayRecipeComponent overlay;
34 |
35 | @Shadow
36 | private Minecraft minecraft;
37 |
38 | @Inject(method = "renderTooltip", at = @At(value = "TAIL"))
39 | private void controllableRenderTooltipTail(GuiGraphics graphics, int mouseX, int mouseY, CallbackInfo ci)
40 | {
41 | Controller controller = Controllable.getController();
42 | if(controller == null || !controller.isBeingUsed() || !Config.CLIENT.options.quickCraft.get())
43 | return;
44 |
45 | if(this.minecraft.screen == null || !this.overlay.isVisible())
46 | return;
47 |
48 | List recipeButtons = ClientHelper.mixinGetRecipeButtons(this.overlay);
49 | recipeButtons.stream().filter(AbstractWidget::isHoveredOrFocused).findFirst().ifPresent(btn -> {
50 | if(ClientServices.CLIENT.isOverlayRecipeButtonCraftable(btn)) {
51 | Component craftText = Component.translatable("controllable.tooltip.craft", ClientHelper.getButtonComponent(ButtonBindings.PICKUP_ITEM.getButton())).withStyle(ChatFormatting.YELLOW);
52 | graphics.setTooltipForNextFrame(craftText, mouseX, mouseY);
53 | }
54 | });
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/TimerAccessor.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import net.minecraft.client.DeltaTracker;
4 | import org.spongepowered.asm.mixin.Mixin;
5 | import org.spongepowered.asm.mixin.gen.Accessor;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | @Mixin(DeltaTracker.Timer.class)
11 | public interface TimerAccessor
12 | {
13 | @Accessor("deltaTickResidual")
14 | float controllable$DeltaTickResidual();
15 | }
16 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/GuiIconToggleButtonMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client.jei;
2 |
3 | import mezz.jei.gui.elements.GuiIconButton;
4 | import mezz.jei.gui.elements.GuiIconToggleButton;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.Pseudo;
7 | import org.spongepowered.asm.mixin.gen.Accessor;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | @Pseudo
13 | @Mixin(GuiIconToggleButton.class)
14 | public interface GuiIconToggleButtonMixin
15 | {
16 | @Accessor(value = "button", remap = false)
17 | GuiIconButton controllableGetButton();
18 | }
19 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientGridMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client.jei;
2 |
3 | import mezz.jei.gui.overlay.IngredientGrid;
4 | import mezz.jei.gui.overlay.IngredientListRenderer;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.Pseudo;
7 | import org.spongepowered.asm.mixin.gen.Accessor;
8 |
9 | /**
10 | * Yes this is terrible. You should never Mixin to other mods. Do I expect mezz to
11 | * support Controllable? No. This is the terrible solution we have to live with.
12 | *
13 | * Author: MrCrayfish
14 | */
15 | @Pseudo
16 | @Mixin(IngredientGrid.class)
17 | public interface IngredientGridMixin
18 | {
19 | @Accessor(value = "ingredientListRenderer", remap = false)
20 | IngredientListRenderer controllableGetIngredientListRenderer();
21 | }
22 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientGridWithNavigationMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client.jei;
2 |
3 | import mezz.jei.gui.PageNavigation;
4 | import mezz.jei.gui.overlay.IngredientGrid;
5 | import mezz.jei.gui.overlay.IngredientGridWithNavigation;
6 | import org.spongepowered.asm.mixin.Mixin;
7 | import org.spongepowered.asm.mixin.Pseudo;
8 | import org.spongepowered.asm.mixin.gen.Accessor;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | @Pseudo
14 | @Mixin(IngredientGridWithNavigation.class)
15 | public interface IngredientGridWithNavigationMixin
16 | {
17 | @Accessor(value = "navigation", remap = false)
18 | PageNavigation controllableGetNavigation();
19 |
20 | @Accessor(value = "ingredientGrid", remap = false)
21 | IngredientGrid controllableGetIngredientGrid();
22 | }
23 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/IngredientListOverlayMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client.jei;
2 |
3 | import mezz.jei.gui.elements.GuiIconToggleButton;
4 | import mezz.jei.gui.overlay.IngredientGridWithNavigation;
5 | import mezz.jei.gui.overlay.IngredientListOverlay;
6 | import org.spongepowered.asm.mixin.Mixin;
7 | import org.spongepowered.asm.mixin.Pseudo;
8 | import org.spongepowered.asm.mixin.gen.Accessor;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | @Pseudo
14 | @Mixin(IngredientListOverlay.class)
15 | public interface IngredientListOverlayMixin
16 | {
17 | @Accessor(value = "contents", remap = false)
18 | IngredientGridWithNavigation controllableGetContents();
19 |
20 | @Accessor(value = "configButton", remap = false)
21 | GuiIconToggleButton controllableGetConfigButton();
22 | }
23 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/MouseUtilMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client.jei;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import com.mrcrayfish.controllable.client.input.Controller;
5 | import mezz.jei.gui.input.MouseUtil;
6 | import net.minecraft.client.Minecraft;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.Pseudo;
9 | import org.spongepowered.asm.mixin.injection.At;
10 | import org.spongepowered.asm.mixin.injection.Inject;
11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
12 |
13 | /**
14 | * JEI has a utility class to get the X and Y position of the mouse when it's not possible to
15 | * retrieve them. This causes issues when virtual mouse is turned on (which is most of the time).
16 | * This fixes compatibility with the mod.
17 | *
18 | * Author: MrCrayfish
19 | */
20 | @Pseudo
21 | @Mixin(MouseUtil.class)
22 | public class MouseUtilMixin
23 | {
24 | @Inject(method = "getX", at = @At(value = "TAIL"), remap = false, cancellable = true)
25 | private static void controllableGetX(CallbackInfoReturnable cir)
26 | {
27 | Controller controller = Controllable.getController();
28 | if(controller != null && controller.isUsingVirtualCursor())
29 | {
30 | cir.setReturnValue(Controllable.getCursor().getRenderScreenX());
31 | }
32 | }
33 |
34 | @Inject(method = "getY", at = @At(value = "TAIL"), remap = false, cancellable = true)
35 | private static void controllableGetY(CallbackInfoReturnable cir)
36 | {
37 | Controller controller = Controllable.getController();
38 | if(controller != null && controller.isUsingVirtualCursor())
39 | {
40 | cir.setReturnValue(Controllable.getCursor().getRenderScreenY());
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/jei/PageNavigationMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client.jei;
2 |
3 | import mezz.jei.gui.PageNavigation;
4 | import mezz.jei.gui.elements.GuiIconButton;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.Pseudo;
7 | import org.spongepowered.asm.mixin.gen.Accessor;
8 |
9 | /**
10 | * Author: MrCrayfish
11 | */
12 | @Pseudo
13 | @Mixin(PageNavigation.class)
14 | public interface PageNavigationMixin
15 | {
16 | @Accessor(value = "nextButton", remap = false)
17 | GuiIconButton controllableGetNextButton();
18 |
19 | @Accessor(value = "backButton", remap = false)
20 | GuiIconButton controllableGetBackButton();
21 | }
22 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/mixin/client/rei/PointHelperMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client.rei;
2 | import com.mrcrayfish.controllable.Controllable;
3 | import com.mrcrayfish.controllable.client.input.Controller;
4 | import me.shedaniel.math.FloatingPoint;
5 | import me.shedaniel.math.Point;
6 | import me.shedaniel.math.impl.PointHelper;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.Pseudo;
9 | import org.spongepowered.asm.mixin.injection.At;
10 | import org.spongepowered.asm.mixin.injection.Inject;
11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
12 |
13 | /**
14 | * Author: MrCrayfish
15 | */
16 | @Pseudo
17 | @Mixin(PointHelper.class)
18 | public class PointHelperMixin
19 | {
20 | @Inject(method = "ofMouse", at = @At(value = "HEAD"), cancellable = true, remap = false)
21 | private static void controllableMouse(CallbackInfoReturnable cir)
22 | {
23 | Controller controller = Controllable.getController();
24 | if(controller != null && controller.isUsingVirtualCursor())
25 | {
26 | double mouseX = Controllable.getCursor().getRenderScreenX();
27 | double mouseY = Controllable.getCursor().getRenderScreenY();
28 | cir.setReturnValue(new Point(mouseX, mouseY));
29 | }
30 | }
31 |
32 | @Inject(method = "ofFloatingMouse", at = @At(value = "HEAD"), cancellable = true, remap = false)
33 | private static void controllableFloatMouse(CallbackInfoReturnable cir)
34 | {
35 | Controller controller = Controllable.getController();
36 | if(controller != null && controller.isUsingVirtualCursor())
37 | {
38 | double mouseX = Controllable.getCursor().getRenderScreenX();
39 | double mouseY = Controllable.getCursor().getRenderScreenY();
40 | cir.setReturnValue(new FloatingPoint(mouseX, mouseY));
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/platform/ClientServices.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.platform;
2 |
3 | import com.mrcrayfish.controllable.platform.services.IClientHelper;
4 |
5 | public class ClientServices
6 | {
7 | public static final IClientHelper CLIENT = Services.load(IClientHelper.class);
8 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/platform/Services.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.platform;
2 |
3 | import com.mrcrayfish.controllable.platform.services.IPlatformHelper;
4 | import com.mrcrayfish.framework.Constants;
5 |
6 | import java.util.ServiceLoader;
7 |
8 | /**
9 | * Author: MrCrayfish
10 | */
11 | public class Services
12 | {
13 | public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class);
14 |
15 | public static T load(Class clazz)
16 | {
17 | final T loadedService = ServiceLoader.load(clazz).findFirst().orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName()));
18 | Constants.LOG.debug("Loaded {} for service {}", loadedService, clazz);
19 | return loadedService;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/platform/services/IPlatformHelper.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.platform.services;
2 |
3 | /**
4 | * Author: MrCrayfish
5 | */
6 | public interface IPlatformHelper
7 | {
8 | default boolean isNeoForge()
9 | {
10 | return false;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/common/src/main/java/com/mrcrayfish/controllable/util/Utils.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.util;
2 |
3 | import com.mrcrayfish.controllable.Constants;
4 | import net.minecraft.resources.ResourceLocation;
5 |
6 | import java.nio.file.Path;
7 |
8 | /**
9 | * Author: MrCrayfish
10 | */
11 | public class Utils
12 | {
13 | public static ResourceLocation resource(String name)
14 | {
15 | return ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, name);
16 | }
17 |
18 | public static Path getGamePath()
19 | {
20 | return com.mrcrayfish.framework.platform.Services.CONFIG.getGamePath();
21 | }
22 |
23 | public static Path getConfigDirectory()
24 | {
25 | return com.mrcrayfish.framework.platform.Services.CONFIG.getConfigPath();
26 | }
27 |
28 | public static boolean isModLoaded(String modId)
29 | {
30 | return com.mrcrayfish.framework.platform.Services.PLATFORM.isModLoaded(modId);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/common/src/main/resources/assets/controllable/background.png
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/common/src/main/resources/assets/controllable/banner.png
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/font/buttons.json:
--------------------------------------------------------------------------------
1 | {
2 | "providers": [
3 | {
4 | "type": "space",
5 | "advances": {
6 | " ": 4
7 | }
8 | },
9 | {
10 | "type": "bitmap",
11 | "file": "controllable:gui/buttons.png",
12 | "height": 12,
13 | "ascent": 9,
14 | "chars": [
15 | "\u0021\u0022\u0023\u0024\u0025\u0026\u0027\u0028\u0029\u002a\u002b\u002c\u002d\u002e\u002f\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003a\u003b\u003c\u003d\u003e\u003f",
16 | "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005a\u005b\u005c\u005d\u005e",
17 | "\u005f\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007a\u007b\u007c\u007d",
18 | "\u007e\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c",
19 | "\u009d\u009e\u009f\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb",
20 | "\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9\u00da",
21 | "\u00db\u00dc\u00dd\u00de\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7\u00f8\u00f9",
22 | "\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff\u0100\u0101\u0102\u0103\u0104\u0105\u0106\u0107\u0108\u0109\u010a\u010b\u010c\u010d\u010e\u010f\u0110\u0111\u0112\u0113\u0114\u0115\u0116\u0117\u0118",
23 | "\u0119\u011a\u011b\u011c\u011d\u011e\u011f\u0120\u0121\u0122\u0123\u0124\u0125\u0126\u0127\u0128\u0129\u012a\u012b\u012c\u012d\u012e\u012f\u0130\u0131\u0132\u0133\u0134\u0135\u0136\u0137",
24 | "\u0138\u0139\u013a\u013b\u013c\u013d\u013e\u013f\u0140\u0141\u0142\u0143\u0144\u0145\u0146\u0147\u0148\u0149\u014a\u014b\u014c\u014d\u014e\u014f\u0150\u0151\u0152\u0153\u0154\u0155\u0156"
25 | ]
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/font/icons.json:
--------------------------------------------------------------------------------
1 | {
2 | "providers": [
3 | {
4 | "type": "space",
5 | "advances": {
6 | " ": 4
7 | }
8 | },
9 | {
10 | "type": "bitmap",
11 | "file": "controllable:gui/icons.png",
12 | "height": 11,
13 | "ascent": 9,
14 | "chars": [
15 | "\u0021\u0022\u0023\u0024\u0025\u0026\u0027\u0028\u0029\u002A\u002B\u002C"
16 | ]
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/common/src/main/resources/assets/controllable/icon.png
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/textures/gui/buttons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/common/src/main/resources/assets/controllable/textures/gui/buttons.png
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/textures/gui/controller.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/common/src/main/resources/assets/controllable/textures/gui/controller.png
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/textures/gui/cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/common/src/main/resources/assets/controllable/textures/gui/cursor.png
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/textures/gui/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/common/src/main/resources/assets/controllable/textures/gui/icons.png
--------------------------------------------------------------------------------
/common/src/main/resources/assets/controllable/textures/gui/sprites/toast/connection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/common/src/main/resources/assets/controllable/textures/gui/sprites/toast/connection.png
--------------------------------------------------------------------------------
/common/src/main/resources/controllable.common.mixins.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": true,
3 | "package": "com.mrcrayfish.controllable.mixin",
4 | "compatibilityLevel": "JAVA_21",
5 | "minVersion": "0.8",
6 | "refmap": "controllable.refmap.json",
7 | "client": [
8 | "client.ClientRecipeBookMixin",
9 | "client.ContainerScreenMixin",
10 | "client.GameRendererMixin",
11 | "client.GuiMixin",
12 | "client.LocalPlayerMixin",
13 | "client.MinecraftMixin",
14 | "client.MouseHandlerMixin",
15 | "client.MouseHelperMixin",
16 | "client.OverlayRecipeComponentAccessor",
17 | "client.RecipeBookComponentAccessor",
18 | "client.RecipeBookPageAccessor",
19 | "client.RecipeBookPageMixin",
20 | "client.TimerAccessor",
21 | "client.jei.GuiIconToggleButtonMixin",
22 | "client.jei.IngredientGridMixin",
23 | "client.jei.IngredientGridWithNavigationMixin",
24 | "client.jei.IngredientListOverlayMixin",
25 | "client.jei.MouseUtilMixin",
26 | "client.jei.PageNavigationMixin",
27 | "client.rei.PointHelperMixin"
28 | ],
29 | "injectors": {
30 | "defaultRequire": 1
31 | }
32 | }
--------------------------------------------------------------------------------
/common/src/main/resources/mappings/defender_game_racer_x7.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "Defender Game Racer X7",
3 | "name": "Defender Game Racer X7",
4 | "reassign": [
5 | {
6 | "index": 0,
7 | "with": 3
8 | },
9 | {
10 | "index": 2,
11 | "with": 0
12 | },
13 | {
14 | "index": 3,
15 | "with": 2
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/common/src/main/resources/pack.mcmeta:
--------------------------------------------------------------------------------
1 | {
2 | "pack": {
3 | "description": "${mod_name}",
4 | "pack_format": 12,
5 | "forge:resource_pack_format": 12,
6 | "forge:data_pack_format": 10
7 | }
8 | }
--------------------------------------------------------------------------------
/fabric/build.gradle:
--------------------------------------------------------------------------------
1 | import net.fabricmc.loom.task.RemapJarTask
2 |
3 | plugins {
4 | id 'multiloader-loader'
5 | id 'fabric-loom'
6 | }
7 |
8 | dependencies {
9 | minecraft "com.mojang:minecraft:${minecraft_version}"
10 | mappings loom.officialMojangMappings()
11 | modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}"
12 | modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
13 | modImplementation "com.mrcrayfish:framework-fabric:${minecraft_version}-${framework_version}"
14 | modCompileOnly ("dev.architectury:architectury-fabric:${architectury_api_version}") transitive false
15 | modCompileOnly ("mezz.jei:jei-${jei_minecraft_version}-fabric:${jei_version}") transitive false
16 | modCompileOnly ("dev.emi:emi-fabric:${emi_version}") transitive false
17 | modCompileOnly ("me.shedaniel:RoughlyEnoughItems-fabric:${rei_version}") transitive false
18 | modCompileOnly ("me.shedaniel.cloth:cloth-config-fabric:18.0.145")
19 | //modRuntimeOnly "squeek.appleskin:appleskin-fabric:mc1.21.3-3.0.6"
20 | library include("com.mrcrayfish:controllable-sdl:${controllable_sdl_version}") {
21 | transitive false
22 | }
23 | implementation "com.google.code.findbugs:jsr305:3.0.1"
24 | }
25 |
26 | sourceSets.main.resources.srcDir 'src/generated/resources'
27 |
28 | fabricApi {
29 | configureDataGeneration {
30 | outputDirectory.set(file("src/generated/resources"))
31 | }
32 | }
33 |
34 | loom {
35 | def aw = file("src/main/resources/${mod_id}.accesswidener")
36 | if (aw.exists()) {
37 | accessWidenerPath.set(aw)
38 | }
39 | mixin {
40 | defaultRefmapName.set("${mod_id}.refmap.json")
41 | }
42 | runs {
43 | client {
44 | client()
45 | setConfigName("Fabric Client")
46 | ideConfigGenerated(true)
47 | runDir("run")
48 | }
49 | server {
50 | server()
51 | setConfigName("Fabric Server")
52 | ideConfigGenerated(true)
53 | runDir("run")
54 | }
55 | }
56 | }
57 |
58 | remapJar {
59 | addNestedDependencies = false
60 | }
61 |
62 | task releaseJar(type: RemapJarTask) {
63 | dependsOn tasks.jar
64 | input = tasks.jar.archiveFile
65 | addNestedDependencies = true
66 | archiveClassifier = 'release'
67 | }
68 | build.finalizedBy(releaseJar)
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/ControllableMod.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable;
2 |
3 | import com.mrcrayfish.framework.FrameworkSetup;
4 | import net.fabricmc.api.ModInitializer;
5 |
6 | public class ControllableMod implements ModInitializer
7 | {
8 | @Override
9 | public void onInitialize()
10 | {
11 | // On Fabric, no guarantee Framework initialization happens before Controllable
12 | // So we need to run the setup ourselves.
13 | FrameworkSetup.run();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/client/ClientControllableMod.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import net.fabricmc.api.ClientModInitializer;
5 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public class ClientControllableMod implements ClientModInitializer
11 | {
12 | @Override
13 | public void onInitializeClient()
14 | {
15 | ClientBootstrap.init();
16 | ClientLifecycleEvents.CLIENT_STOPPING.register(client -> {
17 | Controllable.getControllerManager().dispose();
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/integration/ArchitecturySupport.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.integration;
2 |
3 | import dev.architectury.event.events.client.ClientScreenInputEvent;
4 | import net.minecraft.client.Minecraft;
5 | import net.minecraft.client.gui.screens.Screen;
6 |
7 | /**
8 | * Author: MrCrayfish
9 | */
10 | public class ArchitecturySupport
11 | {
12 | public static void sendScreenMouseReleased(Screen screen, double mouseX, double mouseY, int button)
13 | {
14 | Minecraft mc = Minecraft.getInstance();
15 | if(ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(mc, screen, mouseX, mouseY, button).isPresent())
16 | return;
17 | if(screen.mouseReleased(mouseX, mouseY, button))
18 | return;
19 | ClientScreenInputEvent.MOUSE_RELEASED_POST.invoker().mouseReleased(mc, screen, mouseX, mouseY, button);
20 | }
21 |
22 | public static void sendScreenMouseClick(Screen screen, double mouseX, double mouseY, int button)
23 | {
24 | Minecraft mc = Minecraft.getInstance();
25 | if(ClientScreenInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(mc, screen, mouseX, mouseY, button).isPresent())
26 | return;
27 | if(screen.mouseClicked(mouseX, mouseY, button))
28 | return;
29 | ClientScreenInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(mc, screen, mouseX, mouseY, button);
30 | }
31 |
32 | public static void sendMouseDrag(Screen screen, double finalMouseX, double finalMouseY, double finalDragX, double finalDragY, int activeButton)
33 | {
34 | Minecraft mc = Minecraft.getInstance();
35 | if(ClientScreenInputEvent.MOUSE_DRAGGED_PRE.invoker().mouseDragged(mc, screen, finalMouseX, finalMouseY, activeButton, finalDragX, finalDragY).isPresent())
36 | return;
37 | if(screen.mouseDragged(finalMouseX, finalMouseY, activeButton, finalDragX, finalDragY))
38 | return;
39 | ClientScreenInputEvent.MOUSE_DRAGGED_POST.invoker().mouseDragged(mc, screen, finalMouseX, finalMouseY, activeButton, finalDragX, finalDragY);
40 | }
41 |
42 | public static boolean sendScreenKeyReleased(Screen screen, int key, int scanCode, int modifiers)
43 | {
44 | Minecraft mc = Minecraft.getInstance();
45 | if(ClientScreenInputEvent.KEY_RELEASED_PRE.invoker().keyReleased(mc, screen, key, scanCode, modifiers).isPresent())
46 | return true;
47 | if(screen.keyReleased(key, -1, modifiers))
48 | return true;
49 | return ClientScreenInputEvent.KEY_RELEASED_POST.invoker().keyReleased(mc, screen, key, scanCode, modifiers).isPresent();
50 | }
51 |
52 | public static boolean sendScreenKeyPressed(Screen screen, int key, int scanCode, int modifiers)
53 | {
54 | Minecraft mc = Minecraft.getInstance();
55 | if(ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(mc, screen, key, scanCode, modifiers).isPresent())
56 | return true;
57 | if(screen.keyPressed(key, -1, modifiers))
58 | return true;
59 | return ClientScreenInputEvent.KEY_PRESSED_POST.invoker().keyPressed(mc, screen, key, scanCode, modifiers).isPresent();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/mixin/ControllableMixinPlugin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin;
2 |
3 | import org.objectweb.asm.tree.ClassNode;
4 | import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
5 | import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
6 |
7 | import java.util.List;
8 | import java.util.Set;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | public class ControllableMixinPlugin implements IMixinConfigPlugin
14 | {
15 | private boolean frameworkLoaded;
16 |
17 | @Override
18 | public void onLoad(String mixinPackage)
19 | {
20 | this.frameworkLoaded = this.isClassAvailable("com.mrcrayfish.framework.Constants");
21 | }
22 |
23 | @Override
24 | public String getRefMapperConfig()
25 | {
26 | return null;
27 | }
28 |
29 | @Override
30 | public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
31 | {
32 | // Prevent any loading of mixins if Framework is not installed.
33 | return this.frameworkLoaded;
34 | }
35 |
36 | @Override
37 | public void acceptTargets(Set myTargets, Set otherTargets)
38 | {
39 |
40 | }
41 |
42 | @Override
43 | public List getMixins()
44 | {
45 | return null;
46 | }
47 |
48 | @Override
49 | public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo)
50 | {
51 |
52 | }
53 |
54 | @Override
55 | public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo)
56 | {
57 |
58 | }
59 |
60 | private boolean isClassAvailable(String className)
61 | {
62 | try
63 | {
64 | Class.forName(className, false, getClass().getClassLoader());
65 | return true;
66 | }
67 | catch (ClassNotFoundException e)
68 | {
69 | return false;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/mixin/client/FabricGuiMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mrcrayfish.controllable.Config;
4 | import net.minecraft.client.DeltaTracker;
5 | import net.minecraft.client.gui.Gui;
6 | import net.minecraft.client.gui.GuiGraphics;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.injection.At;
9 | import org.spongepowered.asm.mixin.injection.Inject;
10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
11 |
12 | /**
13 | * Author: MrCrayfish
14 | */
15 | @Mixin(Gui.class)
16 | public class FabricGuiMixin
17 | {
18 | @Inject(method = "renderHotbarAndDecorations", at = @At(value = "HEAD"))
19 | private void consoleHotbarOffsetHead(GuiGraphics graphics, DeltaTracker tracker, CallbackInfo ci)
20 | {
21 | if(Config.CLIENT.options.consoleHotbar.get())
22 | {
23 | graphics.pose().pushMatrix();
24 | graphics.pose().translate(0, -25);
25 | }
26 | }
27 |
28 | @Inject(method = "renderHotbarAndDecorations", at = @At(value = "TAIL"))
29 | private void consoleHotbarOffsetTail(GuiGraphics graphics, DeltaTracker tracker, CallbackInfo ci)
30 | {
31 | if(Config.CLIENT.options.consoleHotbar.get())
32 | {
33 | graphics.pose().popMatrix();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/mixin/client/FabricKeyMappingMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mojang.blaze3d.platform.InputConstants;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.binding.BindingRegistry;
6 | import com.mrcrayfish.controllable.client.binding.KeyAdapterBinding;
7 | import net.minecraft.client.KeyMapping;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.Shadow;
10 | import org.spongepowered.asm.mixin.Unique;
11 | import org.spongepowered.asm.mixin.injection.At;
12 | import org.spongepowered.asm.mixin.injection.Inject;
13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
14 |
15 | /**
16 | * Author: MrCrayfish
17 | */
18 | @Mixin(KeyMapping.class)
19 | public abstract class FabricKeyMappingMixin
20 | {
21 | @Shadow
22 | private InputConstants.Key key;
23 |
24 | @Shadow
25 | private boolean isDown;
26 |
27 | @Shadow
28 | public abstract String getName();
29 |
30 | @Inject(method = "isDown", at = @At(value = "HEAD"), cancellable = true)
31 | private void controllableIsDown(CallbackInfoReturnable cir)
32 | {
33 | if(this.isDown && this.controllable$IsActiveAndMatches(this.key))
34 | {
35 | cir.setReturnValue(true);
36 | }
37 | }
38 |
39 | // TODO needs testing
40 | @Unique
41 | private boolean controllable$IsActiveAndMatches(InputConstants.Key keyCode)
42 | {
43 | String customKey = this.getName() + ".custom";
44 | KeyAdapterBinding adapter = Controllable.getBindingRegistry().getKeyAdapters().get(customKey);
45 | if(adapter != null && adapter.isButtonDown())
46 | {
47 | return true;
48 | }
49 | return keyCode != InputConstants.UNKNOWN && keyCode.equals(this.key);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/mixin/client/FabricMinecraftMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mrcrayfish.controllable.Controllable;
4 | import net.minecraft.client.Minecraft;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.injection.At;
7 | import org.spongepowered.asm.mixin.injection.Inject;
8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | @Mixin(Minecraft.class)
14 | public class FabricMinecraftMixin
15 | {
16 | @Inject(method = "onGameLoadFinished", at = @At(value = "HEAD"))
17 | private void controllableGameLoaded(CallbackInfo ci)
18 | {
19 | Controllable.getBindingRegistry().completeSetup();
20 | Controllable.getControllerManager().completeSetup();
21 | Controllable.getCursor().resetToCenter();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/mixin/client/FabricRecipeBookPageMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mrcrayfish.controllable.Config;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.binding.ButtonBindings;
6 | import com.mrcrayfish.controllable.client.input.Controller;
7 | import com.mrcrayfish.controllable.client.util.ClientHelper;
8 | import net.minecraft.ChatFormatting;
9 | import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
10 | import net.minecraft.network.chat.Component;
11 | import net.minecraft.network.chat.contents.TranslatableContents;
12 | import org.spongepowered.asm.mixin.Mixin;
13 | import org.spongepowered.asm.mixin.injection.At;
14 | import org.spongepowered.asm.mixin.injection.ModifyArg;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * Author: MrCrayfish
20 | */
21 | @Mixin(RecipeBookPage.class)
22 | public class FabricRecipeBookPageMixin
23 | {
24 | @ModifyArg(method = "renderTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;setComponentTooltipForNextFrame(Lnet/minecraft/client/gui/Font;Ljava/util/List;IILnet/minecraft/resources/ResourceLocation;)V"), index = 1)
25 | private List controllableModifyRenderToolTip(List components)
26 | {
27 | Controller controller = Controllable.getController();
28 | if(controller != null && controller.isBeingUsed() && Config.CLIENT.options.quickCraft.get())
29 | {
30 | if(components.removeIf(c -> c.getContents() instanceof TranslatableContents t && t.getKey().equals("gui.recipebook.moreRecipes")))
31 | {
32 | components.add(Component.translatable("controllable.tooltip.more_recipes", ClientHelper.getButtonComponent(ButtonBindings.SPLIT_STACK.getButton())).withStyle(ChatFormatting.YELLOW));
33 | }
34 | components.add(Component.translatable("controllable.tooltip.craft", ClientHelper.getButtonComponent(ButtonBindings.PICKUP_ITEM.getButton())).withStyle(ChatFormatting.YELLOW));
35 | }
36 | return components;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/fabric/src/main/java/com/mrcrayfish/controllable/platform/FabricPlatformHelper.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.platform;
2 |
3 | import com.mrcrayfish.controllable.platform.services.IPlatformHelper;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public class FabricPlatformHelper implements IPlatformHelper
9 | {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/fabric/src/main/resources/META-INF/services/com.mrcrayfish.controllable.platform.services.IClientHelper:
--------------------------------------------------------------------------------
1 | com.mrcrayfish.controllable.platform.FabricClientHelper
--------------------------------------------------------------------------------
/fabric/src/main/resources/META-INF/services/com.mrcrayfish.controllable.platform.services.IPlatformHelper:
--------------------------------------------------------------------------------
1 | com.mrcrayfish.controllable.platform.FabricPlatformHelper
--------------------------------------------------------------------------------
/fabric/src/main/resources/controllable.accesswidener:
--------------------------------------------------------------------------------
1 | accessWidener v1 named
2 | accessible field net/minecraft/client/Minecraft rightClickDelay I
3 | accessible field net/minecraft/client/MouseHandler activeButton I
4 | accessible field net/minecraft/client/MouseHandler lastHandleMovementTime D
5 | accessible field net/minecraft/client/gui/components/ChatComponent trimmedMessages Ljava/util/List;
6 | accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScreen hoveredSlot Lnet/minecraft/world/inventory/Slot;
7 | accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScreen topPos I
8 | accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScreen leftPos I
9 | accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScreen imageWidth I
10 | accessible field net/minecraft/client/gui/screens/inventory/AbstractContainerScreen imageHeight I
11 | accessible field net/minecraft/client/OptionInstance caption Lnet/minecraft/network/chat/Component;
12 | accessible field net/minecraft/client/OptionInstance tooltip Lnet/minecraft/client/OptionInstance$TooltipSupplier;
13 | accessible field net/minecraft/client/gui/components/AbstractSelectionList itemHeight I
14 | accessible field net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen scrollOffs F
15 | accessible field net/minecraft/client/KeyMapping clickCount I
16 | accessible field net/minecraft/client/gui/components/Tooltip cachedTooltip Ljava/util/List;
17 | accessible field net/minecraft/client/gui/screens/inventory/StonecutterScreen startIndex I
18 | accessible field net/minecraft/client/gui/screens/inventory/LoomScreen startRow I
19 | accessible field net/minecraft/client/gui/screens/recipebook/OverlayRecipeComponent$OverlayRecipeButton isCraftable Z
20 | accessible method net/minecraft/client/Minecraft startUseItem ()V
21 | accessible method net/minecraft/client/Minecraft startAttack ()Z
22 | accessible method net/minecraft/client/Minecraft pickBlock ()V
23 | accessible method net/minecraft/client/Minecraft openChatScreen (Ljava/lang/String;)V
24 | accessible method net/minecraft/client/player/LocalPlayer canStartSprinting ()Z
25 | accessible class net/minecraft/client/gui/screens/recipebook/OverlayRecipeComponent$OverlayRecipeButton
26 | accessible class net/minecraft/client/gui/components/AbstractSelectionList$Entry
27 |
--------------------------------------------------------------------------------
/fabric/src/main/resources/controllable.fabric.mixins.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": true,
3 | "minVersion": "0.8",
4 | "package": "com.mrcrayfish.controllable.mixin",
5 | "plugin": "com.mrcrayfish.controllable.mixin.ControllableMixinPlugin",
6 | "compatibilityLevel": "JAVA_21",
7 | "refmap": "controllable.refmap.json",
8 | "client": [
9 | "client.FabricGuiMixin",
10 | "client.FabricKeyMappingMixin",
11 | "client.FabricMinecraftMixin",
12 | "client.FabricRecipeBookPageMixin"
13 | ],
14 | "injectors": {
15 | "defaultRequire": 1
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/fabric/src/main/resources/fabric.mod.json:
--------------------------------------------------------------------------------
1 | {
2 | "schemaVersion": 1,
3 | "id": "${mod_id}",
4 | "version": "${mod_version}",
5 | "name": "${mod_name}",
6 | "description": "${mod_desc}",
7 | "authors": [ "${mod_author}" ],
8 | "contact": {
9 | "homepage": "${mod_homepage}",
10 | "sources": "${mod_source}",
11 | "issues": "${mod_issues}"
12 | },
13 | "license": "${mod_license}",
14 | "icon": "assets/${mod_id}/icon.png",
15 | "environment": "client",
16 | "entrypoints": {
17 | "main": [
18 | "com.mrcrayfish.controllable.ControllableMod"
19 | ],
20 | "client": [
21 | "com.mrcrayfish.controllable.client.ClientControllableMod"
22 | ]
23 | },
24 | "mixins": [
25 | "controllable.common.mixins.json",
26 | "controllable.fabric.mixins.json"
27 | ],
28 | "accessWidener": "controllable.accesswidener",
29 | "depends": {
30 | "fabricloader": ">=${fabric_loader_version}",
31 | "fabric": "*",
32 | "minecraft": "${minecraft_version}",
33 | "java": ">=21",
34 | "framework": ">=${framework_version}"
35 | },
36 | "breaks": {
37 | "jei": "<${jei_version}",
38 | "emi": "<${emi_version}",
39 | "roughlyenoughitems": "<${rei_version}"
40 | },
41 | "custom": {
42 | "framework": {
43 | "configs": [
44 | "com.mrcrayfish.controllable.Config"
45 | ]
46 | },
47 | "configured": {
48 | "configs": [],
49 | "background": "minecraft:textures/block/dirt.png"
50 | },
51 | "catalogue": {
52 | "banner": "assets/${mod_id}/banner.png",
53 | "background": "assets/${mod_id}/background.png"
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project
2 | group=com.mrcrayfish
3 |
4 | # Java
5 | java_version=21
6 |
7 | # Common
8 | minecraft_version=1.21.7
9 | neo_form_version=1.21.7-20250630.141722
10 |
11 | # Fabric
12 | fabric_version=0.128.1+1.21.7
13 | fabric_loader_version=0.16.14
14 |
15 | # NeoForge
16 | neoforge_version=21.7.1-beta
17 | neoforge_version_range=[21.7,)
18 | neoforge_loader_version_range=[2,)
19 |
20 | # Mod options
21 | mod_version=0.25.2
22 | mod_name=Controllable
23 | mod_author=MrCrayfish
24 | mod_id=controllable
25 | mod_desc=Adds the ability to use a controller to play Minecraft
26 | mod_homepage=https://mrcrayfish.com/mods?id=controllable
27 | mod_source=https://github.com/MrCrayfish/Controllable
28 | mod_issues=https://github.com/MrCrayfish/Controllable/issues
29 | mod_license=MIT
30 |
31 | # Dependency options
32 | controllable_sdl_version=2.32.8-1.1.0
33 | framework_version=0.12.3
34 | architectury_api_version=17.0.6
35 | jei_version=19.14.1.144
36 | jei_minecraft_version=1.21.1
37 | emi_version=1.1.19+1.21.1
38 | rei_version=18.0.796
39 |
40 | # Gradle
41 | org.gradle.jvmargs=-Xmx3G
42 | org.gradle.daemon=false
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrCrayfish/Controllable/a177d203b5e0ef86c401a7819df72af5936e6153/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-8.12-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
--------------------------------------------------------------------------------
/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 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/neoforge/build.gradle:
--------------------------------------------------------------------------------
1 | import net.neoforged.gradle.common.tasks.PotentiallySignJar
2 |
3 | plugins {
4 | id 'multiloader-loader'
5 | id 'net.neoforged.gradle.userdev' version '7.0.184'
6 | }
7 |
8 | def at = file('src/main/resources/META-INF/accesstransformer.cfg')
9 | if (at.exists()) {
10 | minecraft.accessTransformers.file at
11 | }
12 |
13 | jarJar.enable()
14 |
15 | /*mixin {
16 | add sourceSets.main, "controllable.refmap.json"
17 | config 'controllable.common.mixins.json'
18 | config 'controllable.neoforge.mixins.json'
19 | }*/
20 |
21 | sourceSets {
22 | test {
23 | compileClasspath += project(':common').sourceSets.main.output
24 | runtimeClasspath += project(':common').sourceSets.main.output
25 | }
26 | }
27 |
28 | configurations {
29 | testImplementation.extendsFrom implementation
30 | testRuntimeOnly.extendsFrom runtimeOnly
31 | }
32 |
33 | runs {
34 | configureEach {
35 | modSource project.sourceSets.main
36 | dependencies {
37 | runtime project.configurations.library
38 | }
39 | }
40 | }
41 |
42 | sourceSets.main.resources { srcDir 'src/generated/resources' }
43 |
44 | dependencies {
45 | // Core dependencies
46 | implementation "net.neoforged:neoforge:${neoforge_version}"
47 | implementation "com.mrcrayfish:framework-neoforge:${minecraft_version}-${framework_version}"
48 |
49 | // JEI
50 | compileOnly "mezz.jei:jei-${jei_minecraft_version}-common-api:${jei_version}"
51 | compileOnly "mezz.jei:jei-${jei_minecraft_version}-neoforge:${jei_version}"
52 |
53 | // EMI
54 | compileOnly "dev.emi:emi-neoforge:${emi_version}"
55 |
56 | // Roughly Enough Items
57 | compileOnly "me.shedaniel:RoughlyEnoughItems-neoforge:${rei_version}"
58 |
59 | // AppleSkin
60 | //rumtimeOnly "squeek.appleskin:appleskin-neoforge:mc1.21.3-3.0.6"
61 |
62 | // Controllable SDL (https://github.com/MrCrayfish/ControllableSDL)
63 | library jarJar("com.mrcrayfish:controllable-sdl:${controllable_sdl_version}") {
64 | transitive(false)
65 | }
66 |
67 |
68 | testImplementation "org.junit.jupiter:junit-jupiter:5.7.2"
69 | testRuntimeOnly "org.junit.platform:junit-platform-launcher"
70 | }
71 |
72 | tasks.jarJar.configure {
73 | archiveClassifier = 'release'
74 | from(rootProject.file("LICENSE_LibSDL4J"))
75 | from(rootProject.file("LICENSE")) {
76 | rename { "${it}_${mod_name}" }
77 | }
78 | }
79 |
80 | tasks.register('signJar', PotentiallySignJar) {
81 | dependsOn jar
82 | onlyIf {
83 | hasProperty('keyStore') || System.getenv("KEYSTORE")
84 | }
85 | keyStore = findProperty('keyStore') ?: System.getenv("KEYSTORE")
86 | alias = findProperty('keyStoreAlias') ?: System.getenv("KEYSTORE_ALIAS")
87 | storePass = findProperty('keyStorePass') ?: System.getenv("KEYSTORE_PASS")
88 | input = jar.archiveFile
89 | }
90 |
91 | jar.finalizedBy 'signJar'
92 |
93 | idea {
94 | module {
95 | downloadSources = true
96 | downloadJavadoc = true
97 | }
98 | }
99 |
100 | test {
101 | useJUnitPlatform()
102 | }
103 |
--------------------------------------------------------------------------------
/neoforge/src/main/java/com/mrcrayfish/controllable/ControllableMod.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable;
2 |
3 | import com.mrcrayfish.controllable.client.ClientBootstrap;
4 | import net.neoforged.api.distmarker.Dist;
5 | import net.neoforged.bus.api.SubscribeEvent;
6 | import net.neoforged.fml.common.EventBusSubscriber;
7 | import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
8 | import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | @EventBusSubscriber(value = Dist.CLIENT, modid = Constants.MOD_ID)
14 | public class ControllableMod
15 | {
16 | @SubscribeEvent
17 | private static void onClientSetup(FMLClientSetupEvent event)
18 | {
19 | event.enqueueWork(ClientBootstrap::init);
20 | }
21 |
22 | @SubscribeEvent
23 | private static void onLoadComplete(FMLLoadCompleteEvent event)
24 | {
25 | event.enqueueWork(() -> {
26 | Controllable.getBindingRegistry().completeSetup();
27 | Controllable.getControllerManager().completeSetup();
28 | Controllable.getCursor().resetToCenter();
29 | });
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/neoforge/src/main/java/com/mrcrayfish/controllable/client/ClientEvents.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client;
2 |
3 | import com.mojang.blaze3d.vertex.PoseStack;
4 | import com.mrcrayfish.controllable.Config;
5 | import com.mrcrayfish.controllable.Constants;
6 | import com.mrcrayfish.controllable.Controllable;
7 | import net.minecraft.Util;
8 | import net.minecraft.client.Minecraft;
9 | import net.minecraft.client.gui.Gui;
10 | import net.minecraft.client.gui.GuiGraphics;
11 | import net.minecraft.resources.ResourceLocation;
12 | import net.neoforged.api.distmarker.Dist;
13 | import net.neoforged.bus.api.EventPriority;
14 | import net.neoforged.bus.api.SubscribeEvent;
15 | import net.neoforged.fml.common.EventBusSubscriber;
16 | import net.neoforged.neoforge.client.event.RenderGuiEvent;
17 | import net.neoforged.neoforge.client.event.RenderGuiLayerEvent;
18 | import net.neoforged.neoforge.client.gui.GuiLayerManager;
19 | import net.neoforged.neoforge.client.gui.VanillaGuiLayers;
20 | import net.neoforged.neoforge.event.GameShuttingDownEvent;
21 |
22 | import java.util.HashSet;
23 | import java.util.Set;
24 |
25 | /**
26 | * Author: MrCrayfish
27 | */
28 | @EventBusSubscriber(modid = Constants.MOD_ID, value = Dist.CLIENT)
29 | public class ClientEvents
30 | {
31 | private static final int CONSOLE_HOTBAR_OFFSET = 25;
32 |
33 | private static final Set OFFSET_LAYERS = Util.make(new HashSet<>(), set -> {
34 | set.add(VanillaGuiLayers.HOTBAR);
35 | set.add(VanillaGuiLayers.CONTEXTUAL_INFO_BAR);
36 | set.add(VanillaGuiLayers.CONTEXTUAL_INFO_BAR_BACKGROUND);
37 | set.add(VanillaGuiLayers.SPECTATOR_TOOLTIP);
38 | set.add(VanillaGuiLayers.EXPERIENCE_LEVEL);
39 | set.add(VanillaGuiLayers.SELECTED_ITEM_NAME);
40 | set.add(VanillaGuiLayers.CHAT);
41 | });
42 |
43 | @SubscribeEvent
44 | public static void onGameShuttingDown(GameShuttingDownEvent event)
45 | {
46 | Controllable.getControllerManager().dispose();
47 | }
48 |
49 | @SuppressWarnings("UnstableApiUsage")
50 | public static void beforeRenderLayer(GuiGraphics graphics, GuiLayerManager.NamedLayer layer)
51 | {
52 | if(Config.CLIENT.options.consoleHotbar.get() && OFFSET_LAYERS.contains(layer.name()))
53 | {
54 | graphics.pose().pushMatrix();
55 | graphics.pose().translate(0, -CONSOLE_HOTBAR_OFFSET);
56 | }
57 | }
58 |
59 | @SubscribeEvent(priority = EventPriority.LOWEST)
60 | public static void onRenderLayer(RenderGuiLayerEvent.Post event)
61 | {
62 | if(Config.CLIENT.options.consoleHotbar.get() && OFFSET_LAYERS.contains(event.getName()))
63 | {
64 | event.getGuiGraphics().pose().popMatrix();
65 | }
66 | }
67 |
68 | @SubscribeEvent(priority = EventPriority.LOWEST)
69 | public static void onRenderGui(RenderGuiEvent.Pre event)
70 | {
71 | if(Config.CLIENT.options.consoleHotbar.get())
72 | {
73 | Minecraft.getInstance().gui.leftHeight += CONSOLE_HOTBAR_OFFSET;
74 | Minecraft.getInstance().gui.rightHeight += CONSOLE_HOTBAR_OFFSET;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/neoforge/src/main/java/com/mrcrayfish/controllable/client/binding/context/NeoForgeKeyContext.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.client.binding.context;
2 |
3 | import com.mrcrayfish.controllable.client.binding.context.rule.ContextRule;
4 | import com.mrcrayfish.controllable.client.binding.context.rule.HasPlayerRule;
5 | import com.mrcrayfish.controllable.client.binding.context.rule.HasScreenRule;
6 | import com.mrcrayfish.controllable.client.binding.context.rule.NoScreenRule;
7 | import net.minecraft.resources.ResourceLocation;
8 | import net.neoforged.neoforge.client.settings.IKeyConflictContext;
9 | import net.neoforged.neoforge.client.settings.KeyConflictContext;
10 |
11 | import java.util.Set;
12 | import java.util.UUID;
13 |
14 | /**
15 | * Author: MrCrayfish
16 | */
17 | public class NeoForgeKeyContext extends BindingContext
18 | {
19 | private final IKeyConflictContext context;
20 |
21 | public NeoForgeKeyContext(IKeyConflictContext context)
22 | {
23 | super(generateId(context));
24 | this.context = context;
25 | }
26 |
27 | @Override
28 | public Set createRules()
29 | {
30 | return generateRules(this.context);
31 | }
32 |
33 | @Override
34 | public int priority()
35 | {
36 | return 0;
37 | }
38 |
39 | private static ResourceLocation generateId(IKeyConflictContext context)
40 | {
41 | if(context == KeyConflictContext.UNIVERSAL)
42 | {
43 | return ResourceLocation.fromNamespaceAndPath("neoforge", "universal");
44 | }
45 | if(context == KeyConflictContext.GUI)
46 | {
47 | return ResourceLocation.fromNamespaceAndPath("neoforge", "gui");
48 | }
49 | if(context == KeyConflictContext.IN_GAME)
50 | {
51 | return ResourceLocation.fromNamespaceAndPath("neoforge", "in_game");
52 | }
53 | return ResourceLocation.fromNamespaceAndPath("neoforge", UUID.randomUUID().toString());
54 | }
55 |
56 | private static Set generateRules(IKeyConflictContext context)
57 | {
58 | if(context == KeyConflictContext.GUI)
59 | {
60 | return Set.of(HasScreenRule.any());
61 | }
62 | if(context == KeyConflictContext.IN_GAME)
63 | {
64 | return Set.of(NoScreenRule.get(), HasPlayerRule.get());
65 | }
66 | return Set.of();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/neoforge/src/main/java/com/mrcrayfish/controllable/mixin/ControllableMixinPlugin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin;
2 |
3 | import org.objectweb.asm.tree.ClassNode;
4 | import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
5 | import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
6 |
7 | import java.util.List;
8 | import java.util.Set;
9 |
10 | /**
11 | * Author: MrCrayfish
12 | */
13 | public class ControllableMixinPlugin implements IMixinConfigPlugin
14 | {
15 | private boolean frameworkLoaded;
16 |
17 | @Override
18 | public void onLoad(String mixinPackage)
19 | {
20 | this.frameworkLoaded = this.isClassAvailable("com.mrcrayfish.framework.Constants");
21 | }
22 |
23 | @Override
24 | public String getRefMapperConfig()
25 | {
26 | return null;
27 | }
28 |
29 | @Override
30 | public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
31 | {
32 | // Prevent any loading of mixins if Framework is not installed.
33 | return this.frameworkLoaded;
34 | }
35 |
36 | @Override
37 | public void acceptTargets(Set myTargets, Set otherTargets) {}
38 |
39 | @Override
40 | public List getMixins()
41 | {
42 | return null;
43 | }
44 |
45 | @Override
46 | public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {}
47 |
48 | @Override
49 | public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {}
50 |
51 | private boolean isClassAvailable(String className)
52 | {
53 | try
54 | {
55 | Class.forName(className, false, getClass().getClassLoader());
56 | return true;
57 | }
58 | catch (ClassNotFoundException e)
59 | {
60 | return false;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/neoforge/src/main/java/com/mrcrayfish/controllable/mixin/client/GuiLayerManagerMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.llamalad7.mixinextras.sugar.Local;
4 | import com.mrcrayfish.controllable.client.ClientEvents;
5 | import net.minecraft.client.DeltaTracker;
6 | import net.minecraft.client.gui.GuiGraphics;
7 | import net.neoforged.neoforge.client.gui.GuiLayerManager;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.injection.At;
10 | import org.spongepowered.asm.mixin.injection.Inject;
11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
12 |
13 | /* DO NOT DO THIS. THIS IS LAST RESORT SINCE PRE EVENT CAN BE CANCELED */
14 | @Mixin(GuiLayerManager.class)
15 | public class GuiLayerManagerMixin
16 | {
17 | @Inject(method = "renderInner", at = @At(value = "INVOKE", target = "Lnet/neoforged/neoforge/client/gui/GuiLayer;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V"))
18 | private void controllableBeforeRenderLayer(GuiGraphics graphics, DeltaTracker tracker, CallbackInfo info, @Local(index = 4, ordinal = 0) GuiLayerManager.NamedLayer layer)
19 | {
20 | ClientEvents.beforeRenderLayer(graphics, layer);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/neoforge/src/main/java/com/mrcrayfish/controllable/mixin/client/NeoForgeKeyMappingMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mojang.blaze3d.platform.InputConstants;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.binding.BindingRegistry;
6 | import com.mrcrayfish.controllable.client.binding.KeyAdapterBinding;
7 | import net.minecraft.client.KeyMapping;
8 | import net.neoforged.neoforge.client.extensions.IKeyMappingExtension;
9 | import org.spongepowered.asm.mixin.Mixin;
10 | import org.spongepowered.asm.mixin.Shadow;
11 |
12 | /**
13 | * Author: MrCrayfish
14 | */
15 | @Mixin(KeyMapping.class)
16 | public abstract class NeoForgeKeyMappingMixin implements IKeyMappingExtension
17 | {
18 | @Shadow
19 | public abstract String getCategory();
20 |
21 | @Override
22 | public boolean isActiveAndMatches(InputConstants.Key keyCode)
23 | {
24 | String customKey = this.getCategory() + ".custom";
25 | KeyAdapterBinding adapter = Controllable.getBindingRegistry().getKeyAdapters().get(customKey);
26 | if(adapter != null && adapter.isButtonDown())
27 | {
28 | return true;
29 | }
30 | return keyCode != InputConstants.UNKNOWN && keyCode.equals(getKey()) && this.getKeyConflictContext().isActive() && this.getKeyModifier().isActive(this.getKeyConflictContext());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/neoforge/src/main/java/com/mrcrayfish/controllable/mixin/client/NeoForgeRecipeBookPageMixin.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.mixin.client;
2 |
3 | import com.mrcrayfish.controllable.Config;
4 | import com.mrcrayfish.controllable.Controllable;
5 | import com.mrcrayfish.controllable.client.binding.ButtonBindings;
6 | import com.mrcrayfish.controllable.client.input.Controller;
7 | import com.mrcrayfish.controllable.client.util.ClientHelper;
8 | import net.minecraft.ChatFormatting;
9 | import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
10 | import net.minecraft.network.chat.Component;
11 | import net.minecraft.network.chat.contents.TranslatableContents;
12 | import org.spongepowered.asm.mixin.Mixin;
13 | import org.spongepowered.asm.mixin.injection.At;
14 | import org.spongepowered.asm.mixin.injection.ModifyArg;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * Author: MrCrayfish
20 | */
21 | @Mixin(RecipeBookPage.class)
22 | public class NeoForgeRecipeBookPageMixin
23 | {
24 | @ModifyArg(method = "renderTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;setComponentTooltipForNextFrame(Lnet/minecraft/client/gui/Font;Ljava/util/List;IILnet/minecraft/resources/ResourceLocation;)V"), index = 1)
25 | private List controllableModifyRenderToolTip(List components)
26 | {
27 | Controller controller = Controllable.getController();
28 | if(controller != null && controller.isBeingUsed() && Config.CLIENT.options.quickCraft.get())
29 | {
30 | if(components.removeIf(c -> c.getContents() instanceof TranslatableContents t && t.getKey().equals("gui.recipebook.moreRecipes")))
31 | {
32 | components.add(Component.translatable("controllable.tooltip.more_recipes", ClientHelper.getButtonComponent(ButtonBindings.SPLIT_STACK.getButton())).withStyle(ChatFormatting.YELLOW));
33 | }
34 | components.add(Component.translatable("controllable.tooltip.craft", ClientHelper.getButtonComponent(ButtonBindings.PICKUP_ITEM.getButton())).withStyle(ChatFormatting.YELLOW));
35 | }
36 | return components;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/neoforge/src/main/java/com/mrcrayfish/controllable/platform/NeoForgePlatformHelper.java:
--------------------------------------------------------------------------------
1 | package com.mrcrayfish.controllable.platform;
2 |
3 | import com.mrcrayfish.controllable.platform.services.IPlatformHelper;
4 |
5 | /**
6 | * Author: MrCrayfish
7 | */
8 | public class NeoForgePlatformHelper implements IPlatformHelper
9 | {
10 | @Override
11 | public boolean isNeoForge()
12 | {
13 | return true;
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/neoforge/src/main/resources/META-INF/accesstransformer.cfg:
--------------------------------------------------------------------------------
1 | public net.minecraft.client.Minecraft startUseItem()V
2 | public net.minecraft.client.Minecraft startAttack()Z
3 | public net.minecraft.client.Minecraft pickBlock()V
4 | public net.minecraft.client.Minecraft rightClickDelay
5 | public net.minecraft.client.gui.components.ChatComponent trimmedMessages
6 | public net.minecraft.client.MouseHandler activeButton
7 | public net.minecraft.client.MouseHandler lastHandleMovementTime
8 | public net.minecraft.client.Minecraft getFramerateLimit()I
9 | public net.minecraft.client.OptionInstance caption
10 | public net.minecraft.client.OptionInstance tooltip
11 | public net.minecraft.client.gui.screens.inventory.LoomScreen startRow
12 | public net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent$OverlayRecipeButton
13 | public net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent$OverlayRecipeButton isCraftable # isCraftable
14 | public net.minecraft.client.gui.components.AbstractSelectionList$Entry
15 | public net.minecraft.client.Minecraft openChatScreen(Ljava/lang/String;)V
16 | public net.minecraft.client.gui.components.AbstractSelectionList getRowTop(I)I
17 | public net.minecraft.client.gui.components.AbstractSelectionList getRowBottom(I)I
18 | public net.minecraft.client.gui.components.AbstractSelectionList slotClicked(Lnet/minecraft/world/inventory/Slot;IILnet/minecraft/world/inventory/ClickType;)V
19 | public net.minecraft.client.player.LocalPlayer canStartSprinting()Z
--------------------------------------------------------------------------------
/neoforge/src/main/resources/META-INF/neoforge.mods.toml:
--------------------------------------------------------------------------------
1 | modLoader = "javafml"
2 | loaderVersion = "${neoforge_loader_version_range}"
3 | license = "${mod_license}"
4 | issueTrackerURL = "${mod_issues}"
5 |
6 | [[mods]]
7 | modId = "${mod_id}"
8 | version = "${mod_version}"
9 | displayName = "${mod_name}"
10 | # updateJSONURL = "https://mrcrayfish.com/modupdatejson?id=${mod_id}"
11 | displayURL = "${mod_homepage}"
12 | logoFile = "assets/${mod_id}/icon.png"
13 | logoBlur = false
14 | authors = "${mod_author}"
15 | description = '''${mod_desc}'''
16 |
17 | [[mixins]]
18 | config = "${mod_id}.common.mixins.json"
19 |
20 | [[mixins]]
21 | config = "${mod_id}.neoforge.mixins.json"
22 |
23 | [[dependencies.${ mod_id }]]
24 | modId = "neoforge"
25 | type = "required"
26 | versionRange = "${neoforge_version_range}"
27 | ordering = "NONE"
28 | side = "BOTH"
29 |
30 | [[dependencies.${ mod_id }]]
31 | modId = "minecraft"
32 | type = "required"
33 | versionRange = "[${minecraft_version},)"
34 | ordering = "NONE"
35 | side = "BOTH"
36 |
37 | [[dependencies.${ mod_id }]]
38 | modId = "framework"
39 | type = "required"
40 | versionRange = "[${framework_version},)"
41 | ordering = "NONE"
42 | side = "BOTH"
43 |
44 | [[dependencies.${ mod_id }]]
45 | modId = "jei"
46 | type = "optional"
47 | versionRange = "[${jei_version},)"
48 | ordering = "NONE"
49 | side = "CLIENT"
50 |
51 | [[dependencies.${ mod_id }]]
52 | modId = "emi"
53 | type = "optional"
54 | versionRange = "[${emi_version},)"
55 | ordering = "NONE"
56 | side = "CLIENT"
57 |
58 | [[dependencies.${ mod_id }]]
59 | modId = "roughlyenoughitems"
60 | type = "optional"
61 | versionRange = "[${rei_version},)"
62 | ordering = "NONE"
63 | side = "CLIENT"
64 |
65 | [modproperties."${mod_id}"]
66 | catalogueImageIcon = "assets/${mod_id}/icon.png"
67 | catalogueBackground = "assets/${mod_id}/background.png"
68 | configuredBackground = "minecraft:textures/block/stone.png"
69 |
--------------------------------------------------------------------------------
/neoforge/src/main/resources/META-INF/services/com.mrcrayfish.controllable.platform.services.IClientHelper:
--------------------------------------------------------------------------------
1 | com.mrcrayfish.controllable.platform.NeoForgeClientHelper
--------------------------------------------------------------------------------
/neoforge/src/main/resources/META-INF/services/com.mrcrayfish.controllable.platform.services.IPlatformHelper:
--------------------------------------------------------------------------------
1 | com.mrcrayfish.controllable.platform.NeoForgePlatformHelper
--------------------------------------------------------------------------------
/neoforge/src/main/resources/controllable.neoforge.mixins.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": true,
3 | "minVersion": "0.8",
4 | "package": "com.mrcrayfish.controllable.mixin",
5 | "plugin": "com.mrcrayfish.controllable.mixin.ControllableMixinPlugin",
6 | "compatibilityLevel": "JAVA_21",
7 | "refmap": "controllable.refmap.json",
8 | "client": [
9 | "client.GuiLayerManagerMixin",
10 | "client.NeoForgeKeyMappingMixin",
11 | "client.NeoForgeRecipeBookPageMixin"
12 | ],
13 | "injectors": {
14 | "defaultRequire": 1
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/release_build:
--------------------------------------------------------------------------------
1 | 4
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | mavenCentral()
5 | exclusiveContent {
6 | forRepository {
7 | maven {
8 | name = 'Fabric'
9 | url = uri('https://maven.fabricmc.net')
10 | }
11 | }
12 | filter {
13 | includeGroup('net.fabricmc')
14 | includeGroup('fabric-loom')
15 | }
16 | }
17 | exclusiveContent {
18 | forRepository {
19 | maven {
20 | name = 'NeoForge'
21 | url = uri("https://maven.neoforged.net/releases")
22 | }
23 | }
24 | filter {
25 | includeGroupAndSubgroups("net.neoforged")
26 | includeGroup("codechicken")
27 | }
28 | }
29 | exclusiveContent {
30 | forRepository {
31 | maven {
32 | name = 'Sponge'
33 | url = uri('https://repo.spongepowered.org/repository/maven-public')
34 | }
35 | }
36 | filter {
37 | includeGroupAndSubgroups("org.spongepowered")
38 | }
39 | }
40 | exclusiveContent {
41 | forRepository {
42 | maven {
43 | name = 'Forge'
44 | url = uri('https://maven.minecraftforge.net')
45 | }
46 | }
47 | filter {
48 | includeGroupAndSubgroups('net.minecraftforge')
49 | }
50 | }
51 | }
52 | }
53 |
54 | plugins {
55 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
56 | }
57 |
58 | def includeModloader(String name) {
59 | // If building with Github Actions, only include loader we want!
60 | String targetLoader = Boolean.getBoolean("CI") ?: System.getenv("TARGET_LOADER")
61 | if(targetLoader == null || targetLoader == name) {
62 | include(name)
63 | }
64 | }
65 |
66 | rootProject.name = 'Controllable'
67 | include("common")
68 | includeModloader("fabric")
69 | includeModloader("neoforge")
70 |
--------------------------------------------------------------------------------