├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── controller-compatibility-request.md │ ├── feature_request.md │ └── mod-conflict.md ├── README.md └── workflows │ └── build.yml ├── .gitignore ├── .run ├── Build (Active).run.xml ├── Build (All).run.xml ├── Run Dev Client (Active).run.xml └── Run Prod Client (Active).run.xml ├── LICENSE ├── assets ├── button icons.psd ├── controlify-banner.png ├── icon.png └── icon.psd ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── dev │ └── isxander │ └── controlify │ ├── Project.kt │ └── project.gradle.kts ├── changelog.md ├── crowdin.yml ├── docs ├── .assets │ └── item │ │ └── images │ │ ├── button-glyph-atlas.png │ │ └── options-button-with-glyph.png ├── _meta.json ├── architecture │ ├── _meta.json │ ├── controllers.mdx │ └── mod-comparison.mdx ├── reference │ ├── _meta.json │ ├── builtin-bindings.mdx │ ├── builtin-controller-namespaces.mdx │ └── builtin-inputs.mdx ├── resource-packs │ ├── _meta.json │ ├── custom-controller-identification.mdx │ ├── default-binds.mdx │ └── input-glyphs.mdx └── sinytra-wiki.json ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts ├── src ├── main │ ├── java │ │ └── dev │ │ │ └── isxander │ │ │ └── controlify │ │ │ ├── Controlify.java │ │ │ ├── ControlifyBootstrap.java │ │ │ ├── InputMode.java │ │ │ ├── api │ │ │ ├── ControlifyApi.java │ │ │ ├── bind │ │ │ │ ├── ControlifyBindApi.java │ │ │ │ ├── InputBinding.java │ │ │ │ ├── InputBindingBuilder.java │ │ │ │ ├── InputBindingSupplier.java │ │ │ │ └── RadialIcon.java │ │ │ ├── buttonguide │ │ │ │ ├── ButtonGuideApi.java │ │ │ │ ├── ButtonGuidePredicate.java │ │ │ │ └── ButtonRenderPosition.java │ │ │ ├── entrypoint │ │ │ │ └── ControlifyEntrypoint.java │ │ │ ├── event │ │ │ │ └── ControlifyEvents.java │ │ │ ├── guide │ │ │ │ ├── ActionPriority.java │ │ │ │ └── GuideActionNameSupplier.java │ │ │ ├── ingameguide │ │ │ │ ├── ActionLocation.java │ │ │ │ ├── IngameGuideContext.java │ │ │ │ └── IngameGuideRegistry.java │ │ │ ├── ingameinput │ │ │ │ └── LookInputModifier.java │ │ │ └── vmousesnapping │ │ │ │ ├── ISnapBehaviour.java │ │ │ │ └── SnapPoint.java │ │ │ ├── bindings │ │ │ ├── BindContext.java │ │ │ ├── ControlifyBindApiImpl.java │ │ │ ├── ControlifyBindings.java │ │ │ ├── InputBindingBuilderImpl.java │ │ │ ├── InputBindingImpl.java │ │ │ ├── KeyMappingHandle.java │ │ │ ├── RadialIcons.java │ │ │ ├── StateAccess.java │ │ │ ├── defaults │ │ │ │ ├── DefaultBindManager.java │ │ │ │ ├── DefaultBindProvider.java │ │ │ │ ├── LayeredDefaultBindProvider.java │ │ │ │ └── MapBackedDefaultBindProvider.java │ │ │ ├── input │ │ │ │ ├── AxisInput.java │ │ │ │ ├── ButtonInput.java │ │ │ │ ├── EmptyInput.java │ │ │ │ ├── HatInput.java │ │ │ │ ├── Input.java │ │ │ │ └── InputType.java │ │ │ └── output │ │ │ │ ├── AnalogueOutput.java │ │ │ │ ├── BindingOutput.java │ │ │ │ ├── DigitalOutput.java │ │ │ │ ├── GuiPressOutput.java │ │ │ │ ├── JustPressedOutput.java │ │ │ │ ├── JustReleasedOutput.java │ │ │ │ ├── JustTappedOutput.java │ │ │ │ ├── KeyMappingEmulationOutput.java │ │ │ │ ├── SimpleAnalogueOutput.java │ │ │ │ └── SimpleDigitalOutput.java │ │ │ ├── compatibility │ │ │ ├── CompatMixinPlugin.java │ │ │ ├── ControlifyCompat.java │ │ │ ├── fancymenu │ │ │ │ ├── FancyMenuCompat.java │ │ │ │ └── OpenControllerCarouselAction.java │ │ │ ├── iris │ │ │ │ ├── IrisMixinPlugin.java │ │ │ │ ├── mixins │ │ │ │ │ └── BaseOptionElementWidgetMixin.java │ │ │ │ └── screenop │ │ │ │ │ └── BaseOptionElementComponentProcessor.java │ │ │ ├── rso │ │ │ │ ├── RSOMixinPlugin.java │ │ │ │ └── mixins │ │ │ │ │ ├── AbstractFrameAccessor.java │ │ │ │ │ ├── SodiumVideoOptionsScreenMixin.java │ │ │ │ │ └── TabFrameAccessor.java │ │ │ ├── simplevoicechat │ │ │ │ ├── SVCMixinPlugin.java │ │ │ │ ├── SimpleVoiceChatCompat.java │ │ │ │ └── mixins │ │ │ │ │ ├── KeyEventsAccessor.java │ │ │ │ │ └── PTTKeyHandlerMixin.java │ │ │ ├── sodium │ │ │ │ ├── SodiumMixinPlugin.java │ │ │ │ ├── mixins │ │ │ │ │ ├── AbstractWidgetMixin.java │ │ │ │ │ ├── CycleControlElementMixin.java │ │ │ │ │ ├── FlatButtonWidgetAccessor.java │ │ │ │ │ ├── FlatButtonWidgetMixin.java │ │ │ │ │ ├── SliderControlElementMixin.java │ │ │ │ │ ├── SodiumOptionsGUIMixin.java │ │ │ │ │ └── TickBoxControlElementMixin.java │ │ │ │ └── screenop │ │ │ │ │ ├── CycleControlProcessor.java │ │ │ │ │ ├── SliderControlProcessor.java │ │ │ │ │ ├── SodiumGuiScreenProcessor.java │ │ │ │ │ ├── SodiumScreenOperations.java │ │ │ │ │ └── TickBoxControlProcessor.java │ │ │ └── yacl │ │ │ │ ├── YACLMixinPlugin.java │ │ │ │ ├── mixins │ │ │ │ ├── ControllerWidgetAccessor.java │ │ │ │ ├── CyclingControllerElementMixin.java │ │ │ │ ├── SliderControllerElementMixin.java │ │ │ │ ├── YACLScreenCategoryTabAccessor.java │ │ │ │ ├── YACLScreenCategoryTabMixin.java │ │ │ │ └── YACLScreenMixin.java │ │ │ │ └── screenop │ │ │ │ ├── CyclingControllerElementComponentProcessor.java │ │ │ │ ├── SliderControllerElementComponentProcessor.java │ │ │ │ └── YACLScreenProcessor.java │ │ │ ├── config │ │ │ ├── ControlifyConfig.java │ │ │ ├── GlobalSettings.java │ │ │ ├── ModMenuIntegration.java │ │ │ └── TypeAdapters.java │ │ │ ├── controller │ │ │ ├── ControllerEntity.java │ │ │ ├── ECSComponent.java │ │ │ ├── ECSEntity.java │ │ │ ├── GamepadControllerConfig.java │ │ │ ├── GenericControllerConfig.java │ │ │ ├── JoystickControllerConfig.java │ │ │ ├── SingleValueComponent.java │ │ │ ├── battery │ │ │ │ ├── BatteryLevelComponent.java │ │ │ │ └── PowerState.java │ │ │ ├── dualsense │ │ │ │ └── DualSenseComponent.java │ │ │ ├── gyro │ │ │ │ ├── GyroButtonMode.java │ │ │ │ ├── GyroComponent.java │ │ │ │ ├── GyroState.java │ │ │ │ ├── GyroStateC.java │ │ │ │ └── GyroYawMode.java │ │ │ ├── haptic │ │ │ │ ├── CompleteSoundData.java │ │ │ │ ├── HDHapticComponent.java │ │ │ │ ├── HapticEffects.java │ │ │ │ └── SimpleHapticComponent.java │ │ │ ├── id │ │ │ │ ├── ControllerType.java │ │ │ │ └── ControllerTypeManager.java │ │ │ ├── impl │ │ │ │ ├── ConfigImpl.java │ │ │ │ ├── ControllerStateImpl.java │ │ │ │ └── ECSEntityImpl.java │ │ │ ├── info │ │ │ │ ├── ControllerInfo.java │ │ │ │ ├── DriverNameComponent.java │ │ │ │ ├── GUIDComponent.java │ │ │ │ └── UIDComponent.java │ │ │ ├── input │ │ │ │ ├── ControllerState.java │ │ │ │ ├── ControllerStateView.java │ │ │ │ ├── DeadzoneControllerStateView.java │ │ │ │ ├── DeadzoneGroup.java │ │ │ │ ├── GamepadInputs.java │ │ │ │ ├── HatState.java │ │ │ │ ├── InputComponent.java │ │ │ │ ├── Inputs.java │ │ │ │ ├── JoystickInputs.java │ │ │ │ ├── ModifiableControllerState.java │ │ │ │ └── mapping │ │ │ │ │ ├── ControllerMapping.java │ │ │ │ │ ├── ControllerMappingStorage.java │ │ │ │ │ ├── MapType.java │ │ │ │ │ ├── MappingEntry.java │ │ │ │ │ ├── MappingEntryTypeAdapter.java │ │ │ │ │ └── StateMapper.java │ │ │ ├── keyboard │ │ │ │ └── NativeKeyboardComponent.java │ │ │ ├── misc │ │ │ │ └── BluetoothDeviceComponent.java │ │ │ ├── rumble │ │ │ │ ├── RumbleComponent.java │ │ │ │ └── TriggerRumbleComponent.java │ │ │ ├── serialization │ │ │ │ ├── ConfigClass.java │ │ │ │ ├── ConfigHolder.java │ │ │ │ ├── CustomSaveLoadConfig.java │ │ │ │ └── IConfig.java │ │ │ ├── steamdeck │ │ │ │ └── SteamDeckComponent.java │ │ │ └── touchpad │ │ │ │ ├── TouchpadComponent.java │ │ │ │ └── Touchpads.java │ │ │ ├── controllermanager │ │ │ ├── AbstractControllerManager.java │ │ │ ├── ControllerManager.java │ │ │ ├── GLFWControllerManager.java │ │ │ ├── SDLControllerManager.java │ │ │ └── UniqueControllerID.java │ │ │ ├── debug │ │ │ └── DebugProperties.java │ │ │ ├── driver │ │ │ ├── ComponentAdderDriver.java │ │ │ ├── CompoundDriver.java │ │ │ ├── Driver.java │ │ │ ├── glfw │ │ │ │ ├── GLFWGamepadDriver.java │ │ │ │ └── GLFWJoystickDriver.java │ │ │ ├── sdl │ │ │ │ ├── DecodedGUID.java │ │ │ │ ├── SDL3GamepadDriver.java │ │ │ │ ├── SDL3JoystickDriver.java │ │ │ │ ├── SDL3NativesManager.java │ │ │ │ ├── SDLCommonDriver.java │ │ │ │ ├── SDLException.java │ │ │ │ ├── SDLJoystickConnectionState.java │ │ │ │ ├── SDLUtil.java │ │ │ │ └── dualsense │ │ │ │ │ ├── DS5EffectsState.java │ │ │ │ │ └── DualsenseTriggerEffects.java │ │ │ └── steamdeck │ │ │ │ ├── CEFDebuggerFileResult.java │ │ │ │ ├── SteamDeckDriver.java │ │ │ │ ├── SteamDeckMode.java │ │ │ │ └── SteamDeckUtil.java │ │ │ ├── fixes │ │ │ └── boatfix │ │ │ │ └── AnalogBoatInput.java │ │ │ ├── font │ │ │ ├── BindingFontHelper.java │ │ │ └── InputFontMapper.java │ │ │ ├── gui │ │ │ ├── ButtonGuideRenderer.java │ │ │ ├── DrawSize.java │ │ │ ├── components │ │ │ │ └── FakePositionPlainTextButton.java │ │ │ ├── controllers │ │ │ │ ├── BindController.java │ │ │ │ ├── Deadzone2DImageRenderer.java │ │ │ │ └── FormattableStringController.java │ │ │ ├── guide │ │ │ │ ├── ContainerGuideCtx.java │ │ │ │ ├── GuideAction.java │ │ │ │ ├── GuideActionRenderer.java │ │ │ │ └── InGameButtonGuide.java │ │ │ ├── layout │ │ │ │ ├── AbstractLayoutComponent.java │ │ │ │ ├── AnchorPoint.java │ │ │ │ ├── ColumnLayoutComponent.java │ │ │ │ ├── PositionedComponent.java │ │ │ │ ├── RenderComponent.java │ │ │ │ └── RowLayoutComponent.java │ │ │ └── screen │ │ │ │ ├── AskToMapControllerScreen.java │ │ │ │ ├── BindConsumerScreen.java │ │ │ │ ├── BluetoothWarningScreen.java │ │ │ │ ├── ControllerCalibrationScreen.java │ │ │ │ ├── ControllerCarouselScreen.java │ │ │ │ ├── ControllerConfigScreenFactory.java │ │ │ │ ├── ControllerMappingMakerScreen.java │ │ │ │ ├── DontInteruptScreen.java │ │ │ │ ├── DownloadingSDLScreen.java │ │ │ │ ├── GlobalSettingsScreenFactory.java │ │ │ │ ├── ModConfigOpenerScreen.java │ │ │ │ ├── NoSDLScreen.java │ │ │ │ ├── RadialItems.java │ │ │ │ ├── RadialMenuScreen.java │ │ │ │ ├── SDLOnboardingScreen.java │ │ │ │ ├── SteamDeckAlerts.java │ │ │ │ └── SubmitUnknownControllerScreen.java │ │ │ ├── hid │ │ │ ├── ControllerHIDService.java │ │ │ ├── HIDDevice.java │ │ │ └── HIDIdentifier.java │ │ │ ├── ingame │ │ │ ├── ControllerPlayerMovement.java │ │ │ ├── DualInput.java │ │ │ ├── InGameInputHandler.java │ │ │ └── PickBlockAccessor.java │ │ │ ├── mixins │ │ │ ├── core │ │ │ │ ├── ClientPacketListenerMixin.java │ │ │ │ ├── GLXMixin.java │ │ │ │ ├── GuiGraphicsMixin.java │ │ │ │ ├── GuiMixin.java │ │ │ │ ├── KeyboardHandlerMixin.java │ │ │ │ ├── MinecraftMixin.java │ │ │ │ └── MouseHandlerMixin.java │ │ │ └── feature │ │ │ │ ├── accessibility │ │ │ │ └── LocalPlayerMixin.java │ │ │ │ ├── bind │ │ │ │ ├── ClientPacketListenerMixin.java │ │ │ │ ├── GuiMixin.java │ │ │ │ ├── KeyMappingMixin.java │ │ │ │ ├── MinecraftMixin.java │ │ │ │ └── ToggleKeyMappingMixin.java │ │ │ │ ├── font │ │ │ │ ├── FontAccessor.java │ │ │ │ ├── KeybindContentsMixin.java │ │ │ │ └── TranslatableContentsMixin.java │ │ │ │ ├── guide │ │ │ │ ├── ingame │ │ │ │ │ ├── ClientPacketListenerMixin.java │ │ │ │ │ ├── GuiMixin.java │ │ │ │ │ └── PlayerAccessor.java │ │ │ │ └── screen │ │ │ │ │ ├── AbstractContainerScreenAccessor.java │ │ │ │ │ ├── AbstractWidgetMixin.java │ │ │ │ │ └── TabNavigationBarMixin.java │ │ │ │ ├── hdhaptics │ │ │ │ ├── SoundBufferAccessor.java │ │ │ │ ├── SoundEngineAccessor.java │ │ │ │ └── SoundManagerAccessor.java │ │ │ │ ├── input │ │ │ │ ├── DebugScreenOverlayAccessor.java │ │ │ │ └── MinecraftMixin.java │ │ │ │ ├── nomousetutorial │ │ │ │ └── MovementTutorialStepInstanceMixin.java │ │ │ │ ├── oofinput │ │ │ │ └── GameRendererMixin.java │ │ │ │ ├── patches │ │ │ │ └── boatfix │ │ │ │ │ ├── BoatMixin.java │ │ │ │ │ └── LocalPlayerMixin.java │ │ │ │ ├── reacharound │ │ │ │ └── GameRendererMixin.java │ │ │ │ ├── rumble │ │ │ │ ├── MinecraftMixin.java │ │ │ │ ├── blockbreak │ │ │ │ │ └── MultiPlayerGameModeMixin.java │ │ │ │ ├── damage │ │ │ │ │ ├── LivingEntityMixin.java │ │ │ │ │ ├── LocalPlayerMixin.java │ │ │ │ │ └── PlayerMixin.java │ │ │ │ ├── explosion │ │ │ │ │ ├── ClientPacketListenerMixin.java │ │ │ │ │ └── LightningBoltMixin.java │ │ │ │ ├── fishing │ │ │ │ │ └── FishingHookMixin.java │ │ │ │ ├── itembreak │ │ │ │ │ ├── LivingEntityMixin.java │ │ │ │ │ └── LocalPlayerMixin.java │ │ │ │ ├── levelevents │ │ │ │ │ └── LevelRendererMixin.java │ │ │ │ ├── slowblock │ │ │ │ │ └── LocalPlayerMixin.java │ │ │ │ ├── useitem │ │ │ │ │ ├── ClientPacketListenerMixin.java │ │ │ │ │ ├── LivingEntityMixin.java │ │ │ │ │ └── LocalPlayerMixin.java │ │ │ │ └── waterland │ │ │ │ │ ├── LocalPlayerMixin.java │ │ │ │ │ └── PlayerMixin.java │ │ │ │ ├── screenkeyboard │ │ │ │ ├── ChatComponentMixin.java │ │ │ │ ├── ChatScreenMixin.java │ │ │ │ └── CommandSuggestionsMixin.java │ │ │ │ ├── screenop │ │ │ │ ├── ContainerEventHandlerMixin.java │ │ │ │ ├── MinecraftMixin.java │ │ │ │ ├── ScreenAccessor.java │ │ │ │ ├── ScreenMixin.java │ │ │ │ └── vanilla │ │ │ │ │ ├── AbstractButtonMixin.java │ │ │ │ │ ├── AbstractContainerEventHandlerMixin.java │ │ │ │ │ ├── AbstractContainerScreenMixin.java │ │ │ │ │ ├── AbstractRecipeBookScreenMixin.java │ │ │ │ │ ├── AbstractSelectionListMixin.java │ │ │ │ │ ├── AbstractSignEditScreenMixin.java │ │ │ │ │ ├── AbstractSliderButtonMixin.java │ │ │ │ │ ├── BookEditScreenMixin.java │ │ │ │ │ ├── ContainerObjectSelectionListEntryMixin.java │ │ │ │ │ ├── CreateWorldScreenMixin.java │ │ │ │ │ ├── CreativeModeInventoryScreenMixin.java │ │ │ │ │ ├── EditBoxMixin.java │ │ │ │ │ ├── JoinMultiplayerScreenAccessor.java │ │ │ │ │ ├── JoinMultiplayerScreenMixin.java │ │ │ │ │ ├── LanguageSelectionListEntryMixin.java │ │ │ │ │ ├── MerchantScreenMixin.java │ │ │ │ │ ├── OptionsSubScreenAccessor.java │ │ │ │ │ ├── PauseScreenAccessor.java │ │ │ │ │ ├── PauseScreenMixin.java │ │ │ │ │ ├── SelectWorldScreenAccessor.java │ │ │ │ │ ├── SelectWorldScreenMixin.java │ │ │ │ │ ├── ServerSelectionListEntryMixin.java │ │ │ │ │ ├── TabNavigationBarAccessor.java │ │ │ │ │ ├── TitleScreenMixin.java │ │ │ │ │ ├── WorldSelectionListEntryMixin.java │ │ │ │ │ └── bundle │ │ │ │ │ └── BundleMouseActionsMixin.java │ │ │ │ ├── settingsbutton │ │ │ │ └── ControlsScreenMixin.java │ │ │ │ ├── steamdeck │ │ │ │ └── ScreenshotAccessor.java │ │ │ │ ├── ui │ │ │ │ └── AbstractSelectionListAccessor.java │ │ │ │ ├── util │ │ │ │ └── ConnectScreenMixin.java │ │ │ │ └── virtualmouse │ │ │ │ ├── InputConstantsMixin.java │ │ │ │ ├── KeyboardHandlerAccessor.java │ │ │ │ ├── MinecraftMixin.java │ │ │ │ ├── MouseHandlerAccessor.java │ │ │ │ ├── MouseHandlerMixin.java │ │ │ │ └── snapping │ │ │ │ ├── AbstractContainerScreenMixin.java │ │ │ │ ├── AbstractRecipeBookScreenMixin.java │ │ │ │ ├── CreativeModeInventoryScreenMixin.java │ │ │ │ ├── EnchantmentScreenMixin.java │ │ │ │ ├── LoomMixin.java │ │ │ │ ├── RecipeBookComponentAccessor.java │ │ │ │ ├── RecipeBookPageAccessor.java │ │ │ │ ├── ScreenMixin.java │ │ │ │ └── StonecutterScreenMixin.java │ │ │ ├── platform │ │ │ ├── ArrayBackedEventHandler.java │ │ │ ├── Environment.java │ │ │ ├── Event.java │ │ │ ├── EventHandler.java │ │ │ ├── client │ │ │ │ ├── CreativeTabHelper.java │ │ │ │ ├── HudRenderLayer.java │ │ │ │ ├── PlatformClientUtil.java │ │ │ │ ├── PlatformClientUtilImpl.java │ │ │ │ ├── events │ │ │ │ │ ├── DisconnectedEvent.java │ │ │ │ │ ├── LifecycleEvent.java │ │ │ │ │ ├── ScreenRenderEvent.java │ │ │ │ │ └── TickEvent.java │ │ │ │ ├── fabric │ │ │ │ │ ├── FAPIApiCreativeTabHelper.java │ │ │ │ │ └── FabricPlatformClientImpl.java │ │ │ │ ├── neoforge │ │ │ │ │ ├── NeoforgeCreativeTabHelper.java │ │ │ │ │ └── NeoforgePlatformClientImpl.java │ │ │ │ └── resource │ │ │ │ │ ├── ControlifyReloadListener.java │ │ │ │ │ └── SimpleControlifyReloadListener.java │ │ │ ├── fabric │ │ │ │ ├── FabricBackedEventHandler.java │ │ │ │ └── mixins │ │ │ │ │ ├── CreativeModeInventoryScreenAccessor.java │ │ │ │ │ └── KeyBindingRegistryImplAccessor.java │ │ │ ├── main │ │ │ │ ├── PlatformMainUtil.java │ │ │ │ ├── PlatformMainUtilImpl.java │ │ │ │ ├── events │ │ │ │ │ ├── CommandRegistrationCallbackEvent.java │ │ │ │ │ ├── HandshakeCompletionEvent.java │ │ │ │ │ └── PlayerJoinedEvent.java │ │ │ │ ├── fabric │ │ │ │ │ └── FabricPlatformMainImpl.java │ │ │ │ └── neoforge │ │ │ │ │ └── NeoforgePlatformMainImpl.java │ │ │ ├── neoforge │ │ │ │ ├── VanillaKeyMappingHolder.java │ │ │ │ └── mixins │ │ │ │ │ ├── CreativeModeInventoryScreenAccessor.java │ │ │ │ │ └── OptionsMixin.java │ │ │ └── network │ │ │ │ ├── C2SNetworkApi.java │ │ │ │ ├── S2CNetworkApi.java │ │ │ │ ├── SidedNetworkApi.java │ │ │ │ ├── fabric │ │ │ │ ├── C2SNetworkApiFabric.java │ │ │ │ ├── FabricPacketWrapper.java │ │ │ │ └── S2CNetworkApiFabric.java │ │ │ │ └── neoforge │ │ │ │ ├── C2SNetworkApiNeoforge.java │ │ │ │ └── S2CNetworkApiNeoforge.java │ │ │ ├── reacharound │ │ │ ├── ReachAroundHandler.java │ │ │ └── ReachAroundMode.java │ │ │ ├── rumble │ │ │ ├── BasicRumbleEffect.java │ │ │ ├── ContinuousRumbleEffect.java │ │ │ ├── RumbleCapable.java │ │ │ ├── RumbleEffect.java │ │ │ ├── RumbleManager.java │ │ │ ├── RumbleSource.java │ │ │ ├── RumbleState.java │ │ │ ├── TriggerRumbleState.java │ │ │ └── effects │ │ │ │ └── UseItemEffectHolder.java │ │ │ ├── screenkeyboard │ │ │ ├── ChatKeyboardDucky.java │ │ │ ├── ChatKeyboardWidget.java │ │ │ ├── KeyPressConsumer.java │ │ │ └── KeyboardWidget.java │ │ │ ├── screenop │ │ │ ├── ComponentProcessor.java │ │ │ ├── ComponentProcessorProvider.java │ │ │ ├── CustomFocus.java │ │ │ ├── Registry.java │ │ │ ├── ScreenControllerEventListener.java │ │ │ ├── ScreenProcessor.java │ │ │ ├── ScreenProcessorFactory.java │ │ │ ├── ScreenProcessorProvider.java │ │ │ └── compat │ │ │ │ ├── AbstractSliderComponentProcessor.java │ │ │ │ └── vanilla │ │ │ │ ├── AbstractButtonComponentProcessor.java │ │ │ │ ├── AbstractContainerScreenProcessor.java │ │ │ │ ├── AbstractSignEditScreenProcessor.java │ │ │ │ ├── BundleItemSlotControllerAction.java │ │ │ │ ├── CreateWorldScreenProcessor.java │ │ │ │ ├── CreativeModeInventoryScreenProcessor.java │ │ │ │ ├── EditBoxComponentProcessor.java │ │ │ │ ├── ItemSlotControllerAction.java │ │ │ │ ├── JoinMultiplayerScreenProcessor.java │ │ │ │ ├── LanguageSelectionListComponentProcessor.java │ │ │ │ ├── PauseScreenProcessor.java │ │ │ │ ├── RecipeBookScreenProcessor.java │ │ │ │ ├── SelectWorldScreenProcessor.java │ │ │ │ ├── ServerSelectionListEntryComponentProcessor.java │ │ │ │ ├── SliderComponentProcessor.java │ │ │ │ ├── TitleScreenProcessor.java │ │ │ │ └── WorldListEntryComponentProcessor.java │ │ │ ├── server │ │ │ ├── ControlifyHandshake.java │ │ │ ├── ControlifyServer.java │ │ │ ├── ControlifyServerConfig.java │ │ │ ├── ServerPolicies.java │ │ │ ├── ServerPolicy.java │ │ │ ├── VibrateCommand.java │ │ │ └── packets │ │ │ │ ├── EntityVibrationPacket.java │ │ │ │ ├── OriginVibrationPacket.java │ │ │ │ ├── ServerPolicyPacket.java │ │ │ │ └── VibrationPacket.java │ │ │ ├── sound │ │ │ └── ControlifyClientSounds.java │ │ │ ├── utils │ │ │ ├── CUtil.java │ │ │ ├── ClientUtils.java │ │ │ ├── ColorUtils.java │ │ │ ├── ControllerSetupWizard.java │ │ │ ├── ControllerUtils.java │ │ │ ├── DebugDump.java │ │ │ ├── DebugLog.java │ │ │ ├── DebugOverlayHelper.java │ │ │ ├── DummyMixinTarget.java │ │ │ ├── Easings.java │ │ │ ├── FuzzyMapCodec.java │ │ │ ├── GsonCodecAdapter.java │ │ │ ├── HoldRepeatHelper.java │ │ │ ├── InitialScreenRegistryDuck.java │ │ │ ├── JsonTreeParser.java │ │ │ ├── MouseMinecraftCallNotifier.java │ │ │ ├── MthExt.java │ │ │ ├── Platform.java │ │ │ ├── ResizableRingBuffer.java │ │ │ ├── StrictEitherMapCodec.java │ │ │ ├── ToastUtils.java │ │ │ ├── TrackingBodySubscriber.java │ │ │ ├── TrackingConsumer.java │ │ │ ├── UnhandledCompletableFutures.java │ │ │ ├── animation │ │ │ │ ├── api │ │ │ │ │ ├── Animatable.java │ │ │ │ │ ├── Animation.java │ │ │ │ │ ├── AnimationGroup.java │ │ │ │ │ ├── AnimationSequence.java │ │ │ │ │ └── EasingFunction.java │ │ │ │ └── impl │ │ │ │ │ ├── AnimationGroupImpl.java │ │ │ │ │ ├── AnimationImpl.java │ │ │ │ │ ├── AnimationSequenceImpl.java │ │ │ │ │ └── Animator.java │ │ │ ├── log │ │ │ │ ├── AbstractControlifyLogger.java │ │ │ │ ├── ControlifyLogger.java │ │ │ │ ├── ControlifyMasterLogger.java │ │ │ │ ├── ControlifySubLogger.java │ │ │ │ ├── ControlifySubLoggerImpl.java │ │ │ │ ├── LogLevel.java │ │ │ │ └── LogMessage.java │ │ │ └── render │ │ │ │ ├── BaseRenderState.java │ │ │ │ ├── Blit.java │ │ │ │ ├── CGuiElementRenderState.java │ │ │ │ ├── CGuiPose.java │ │ │ │ ├── GuiRenderStateSink.java │ │ │ │ └── elements │ │ │ │ └── CircleElementRenderState.java │ │ │ ├── virtualmouse │ │ │ ├── SnapUtils.java │ │ │ ├── VirtualMouseBehaviour.java │ │ │ └── VirtualMouseHandler.java │ │ │ └── wireless │ │ │ └── LowBatteryNotifier.java │ ├── resources │ │ ├── META-INF │ │ │ └── accesstransformer.cfg │ │ ├── assets │ │ │ └── controlify │ │ │ │ ├── controllers │ │ │ │ ├── controller_identification.json5 │ │ │ │ ├── default_bind │ │ │ │ │ ├── default.json │ │ │ │ │ ├── dualsense.json │ │ │ │ │ └── switch.json │ │ │ │ ├── font_mappings │ │ │ │ │ ├── default.json │ │ │ │ │ ├── dualsense.json │ │ │ │ │ ├── dualshock3.json │ │ │ │ │ ├── dualshock4.json │ │ │ │ │ ├── steam_deck.json │ │ │ │ │ ├── switch.json │ │ │ │ │ └── xbox_one.json │ │ │ │ ├── gamecontrollerdb-sdl2.txt │ │ │ │ └── gamecontrollerdb-sdl3.txt │ │ │ │ ├── font │ │ │ │ └── controller │ │ │ │ │ ├── default.json │ │ │ │ │ ├── dualsense.json │ │ │ │ │ ├── dualshock3.json │ │ │ │ │ ├── dualshock4.json │ │ │ │ │ ├── steam_deck.json │ │ │ │ │ ├── switch.json │ │ │ │ │ └── xbox_one.json │ │ │ │ ├── haptics │ │ │ │ └── navigate.ogg │ │ │ │ ├── lang │ │ │ │ ├── af_za.json │ │ │ │ ├── ar_sa.json │ │ │ │ ├── ca_es.json │ │ │ │ ├── cs_cz.json │ │ │ │ ├── da_dk.json │ │ │ │ ├── de_de.json │ │ │ │ ├── el_gr.json │ │ │ │ ├── en_gb.json │ │ │ │ ├── en_us.json │ │ │ │ ├── es_es.json │ │ │ │ ├── es_mx.json │ │ │ │ ├── fi_fi.json │ │ │ │ ├── fr_fr.json │ │ │ │ ├── he_il.json │ │ │ │ ├── hu_hu.json │ │ │ │ ├── it_it.json │ │ │ │ ├── ja_jp.json │ │ │ │ ├── ko_kr.json │ │ │ │ ├── ms_my.json │ │ │ │ ├── nl_nl.json │ │ │ │ ├── no_no.json │ │ │ │ ├── pl_pl.json │ │ │ │ ├── pt_br.json │ │ │ │ ├── pt_pt.json │ │ │ │ ├── ro_ro.json │ │ │ │ ├── ru_ru.json │ │ │ │ ├── sv_se.json │ │ │ │ ├── tr_tr.json │ │ │ │ ├── uk_ua.json │ │ │ │ ├── vi_vn.json │ │ │ │ ├── zh_cn.json │ │ │ │ └── zh_tw.json │ │ │ │ ├── sounds.json │ │ │ │ ├── sounds │ │ │ │ └── ui_focus.ogg │ │ │ │ └── textures │ │ │ │ ├── font │ │ │ │ └── controller │ │ │ │ │ ├── default.png │ │ │ │ │ ├── dualsense.png │ │ │ │ │ ├── dualshock3.png │ │ │ │ │ ├── dualshock4.png │ │ │ │ │ ├── steam_deck.png │ │ │ │ │ ├── switch.png │ │ │ │ │ └── xbox_one.png │ │ │ │ ├── gui │ │ │ │ ├── controllerdiagram │ │ │ │ │ ├── dpad_down.png │ │ │ │ │ ├── dpad_left.png │ │ │ │ │ ├── dpad_right.png │ │ │ │ │ ├── dpad_up.png │ │ │ │ │ ├── face_down.png │ │ │ │ │ ├── face_left.png │ │ │ │ │ ├── face_right.png │ │ │ │ │ ├── face_up.png │ │ │ │ │ ├── faceview.png │ │ │ │ │ ├── left_bumper.png │ │ │ │ │ ├── left_special.png │ │ │ │ │ ├── left_stick_down.png │ │ │ │ │ ├── left_stick_left.png │ │ │ │ │ ├── left_stick_press.png │ │ │ │ │ ├── left_stick_right.png │ │ │ │ │ ├── left_stick_up.png │ │ │ │ │ ├── left_trigger.png │ │ │ │ │ ├── right_bumper.png │ │ │ │ │ ├── right_special.png │ │ │ │ │ ├── right_stick_down.png │ │ │ │ │ ├── right_stick_left.png │ │ │ │ │ ├── right_stick_press.png │ │ │ │ │ ├── right_stick_right.png │ │ │ │ │ ├── right_stick_up.png │ │ │ │ │ ├── right_trigger.png │ │ │ │ │ ├── triggerview.png │ │ │ │ │ └── triggerview.psd │ │ │ │ ├── joystick │ │ │ │ │ └── icon.png │ │ │ │ ├── radial-buttons.png │ │ │ │ ├── sprites │ │ │ │ │ ├── controllers │ │ │ │ │ │ ├── default.png │ │ │ │ │ │ ├── default_alt.png │ │ │ │ │ │ ├── dualsense.png │ │ │ │ │ │ ├── dualshock3.png │ │ │ │ │ │ ├── dualshock4.png │ │ │ │ │ │ ├── psp.png │ │ │ │ │ │ ├── steam_deck.png │ │ │ │ │ │ ├── switch.png │ │ │ │ │ │ └── xbox_one.png │ │ │ │ │ └── keyboard │ │ │ │ │ │ ├── key.png │ │ │ │ │ │ └── key.png.mcmeta │ │ │ │ ├── virtual_mouse.png │ │ │ │ └── xbox-controller.png │ │ │ │ └── screenshots │ │ │ │ ├── ingame-button-guide.png │ │ │ │ ├── reach-around-placement.webp │ │ │ │ ├── reduce-aim-sensitivity.webp │ │ │ │ └── screen-button-guide.webp │ │ ├── controlify-compat.iris.mixins.json │ │ ├── controlify-compat.reeses-sodium-options.mixins.json │ │ ├── controlify-compat.simple-voice-chat.mixins.json │ │ ├── controlify-compat.sodium.mixins.json │ │ ├── controlify-compat.yacl.mixins.json │ │ ├── controlify-platform.fabric.mixins.json │ │ ├── controlify-platform.neoforge.mixins.json │ │ ├── controlify.accesswidener │ │ ├── controlify.mixins.json │ │ ├── icon.png │ │ └── resourcepacks │ │ │ └── legacy_console │ │ │ ├── assets │ │ │ └── controlify │ │ │ │ ├── controllers │ │ │ │ └── default_bind │ │ │ │ │ ├── default.json │ │ │ │ │ ├── dualsense.json │ │ │ │ │ └── dualshock4.json │ │ │ │ └── textures │ │ │ │ ├── font │ │ │ │ └── controller │ │ │ │ │ ├── dualsense.png │ │ │ │ │ ├── dualshock3.png │ │ │ │ │ ├── dualshock4.png │ │ │ │ │ ├── xbox_360.png │ │ │ │ │ └── xbox_one.png │ │ │ │ └── gui │ │ │ │ └── sprites │ │ │ │ └── controllers │ │ │ │ └── dualshock3.png │ │ │ └── pack.png │ └── templates │ │ ├── META-INF │ │ └── neoforge.mods.toml │ │ ├── fabric.mod.json │ │ └── resourcepacks │ │ └── legacy_console │ │ └── pack.mcmeta └── testharness │ └── java │ └── dev │ └── isxander │ └── controlify │ └── testharness │ └── TestHarness.java ├── stonecutter.gradle.kts └── versions ├── 1.21.1-fabric └── gradle.properties ├── 1.21.1-neoforge └── gradle.properties ├── 1.21.3-fabric └── gradle.properties ├── 1.21.3-neoforge └── gradle.properties ├── 1.21.4-fabric └── gradle.properties ├── 1.21.4-neoforge └── gradle.properties ├── 1.21.5-fabric └── gradle.properties ├── 1.21.5-neoforge └── gradle.properties ├── 1.21.6-fabric └── gradle.properties ├── current └── versions.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.tiny] 8 | indent_size = 4 9 | indent_style = tab 10 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: isxander 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/controller-compatibility-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Controller compatibility request 3 | about: Get your controller to be detected out-of-box by Controlify 4 | title: "[Controller Request] " 5 | labels: controller-compat 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Controller name** 11 | 12 | Replace the name of your controller with this text 13 | 14 | **Conroller VID & PID** 15 | 16 | Replace this text with the vendor and product ID of he controller. This can usually be found within latest.log with Controlify detected. Attach here if you cannot find it. 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/mod-conflict.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Mod conflict 3 | about: Report an issue with another mod loaded 4 | title: " Conflict" 5 | labels: mod-compatibility 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Mod Info (fill out the following information)** 11 | - Mod name: [e.g. Create mod] 12 | - Mod version: [e.g. 0.5.0 for 1.19.3] 13 | 14 | **Describe the problem** 15 | A clear and concise description of what the problem with the mod is. 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior: 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | **Expected behavior** 25 | A clear and concise description of what you expected to happen. 26 | 27 | **Screenshots** 28 | If applicable, add screenshots to help explain your problem. 29 | 30 | **Minecraft Info (please complete the following information):** 31 | - OS: [e.g. Windows 11] 32 | - Minecraft Version: [e.g. 22w05a] 33 | - Controlify Version: [e.g. 0.1.0+1.19.4] 34 | 35 | **Additional context** 36 | Add any other context about the problem here. 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | run 2 | runserver 3 | build 4 | /.idea 5 | .gradle 6 | !.gitkeep 7 | .kotlin 8 | -------------------------------------------------------------------------------- /.run/Build (Active).run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 18 | true 19 | true 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /.run/Build (All).run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 18 | true 19 | true 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /.run/Run Dev Client (Active).run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 18 | true 19 | true 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /.run/Run Prod Client (Active).run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 18 | true 19 | true 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /assets/button icons.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/assets/button icons.psd -------------------------------------------------------------------------------- /assets/controlify-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/assets/controlify-banner.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/assets/icon.png -------------------------------------------------------------------------------- /assets/icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/assets/icon.psd -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | gradlePluginPortal() 8 | maven("https://maven.fabricmc.net") 9 | maven("https://maven.neoforged.net/releases") 10 | exclusiveContent { 11 | forRepository { 12 | maven("https://maven.kikugie.dev/releases") 13 | maven("https://maven.kikugie.dev/snapshots") 14 | } 15 | filter { 16 | includeGroupAndSubgroups("dev.kikugie") 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | fun plugin(id: String, version: String) = "$id:$id.gradle.plugin:$version" 23 | 24 | implementation(plugin("dev.isxander.modstitch.base", "0.5.16-unstable")) 25 | implementation(plugin("dev.kikugie.stonecutter", "0.7-alpha.17")) 26 | implementation(plugin("fabric-loom", "1.10.5")) 27 | implementation(plugin("net.neoforged.moddev", "2.0.80")) 28 | } 29 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Controlify {version} 2 | 3 | This version has the following targets: 4 | {targets} 5 | 6 | [![](https://short.isxander.dev/bisect-img)](https://short.isxander.dev/bisect) 7 | 8 | **By donating on my [Ko-Fi](https://ko-fi.com/isxander), you will gain access to builds of Controlify for snapshot 9 | builds of Minecraft.** 10 | 11 | ## Fixes 12 | 13 | - Fix startup crash on literally every target 14 | 15 | 16 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: src/main/resources/assets/controlify/lang/en_us.json 3 | translation: /src/main/resources/assets/controlify/lang/%locale_with_underscore%.json 4 | -------------------------------------------------------------------------------- /docs/.assets/item/images/button-glyph-atlas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/docs/.assets/item/images/button-glyph-atlas.png -------------------------------------------------------------------------------- /docs/.assets/item/images/options-button-with-glyph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/docs/.assets/item/images/options-button-with-glyph.png -------------------------------------------------------------------------------- /docs/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "resource-packs": { 3 | "name": "Resource Packs", 4 | "icon": null 5 | }, 6 | "reference": { 7 | "name": "Reference", 8 | "icon": null 9 | }, 10 | "architecture": { 11 | "name": "Architecture", 12 | "icon": null 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docs/architecture/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "controllers.mdx": "Controllers", 3 | "mod-comparison.mdx": "Mod Comparison" 4 | } 5 | -------------------------------------------------------------------------------- /docs/reference/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "builtin-bindings.mdx": "Built-in bindings", 3 | "builtin-inputs.mdx": "Built-in inputs", 4 | "builtin-controller-namespaces": "Built-in controller namespaces", 5 | } 6 | -------------------------------------------------------------------------------- /docs/reference/builtin-controller-namespaces.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Built-in controller namespaces 3 | --- 4 | 5 | Controlify already includes some built-in controller namespaces for common controllers. 6 | 7 | For more info on what controller namespaces are, see the 8 | [custom controller identification](../resource-packs/custom-controller-identification) page. 9 | 10 | - `controlify:xbox_one` (**All** Xbox controllers, not just Xbox One, this includes 360, Series, Elite controllers) 11 | - `controlify:dualsense` (PS5 controllers, includes DualSense Edge) 12 | - `controlify:dualshock4` (PS4 controllers, includes third-party controllers) 13 | - `controlify:dualshock3` (PS3 controllers, includes third-party controllers) 14 | - `controlify:switch` (Switch Pro controllers, includes all controllers "built for the switch", like 8BitDo controllers in Switch Mode) 15 | - `controlify:steam_deck` (Steam Deck, both LCD and OLED models) 16 | -------------------------------------------------------------------------------- /docs/resource-packs/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom-controller-identification.mdx": "Custom Controller Identification", 3 | "default-binds.mdx": "Default Binds", 4 | "input-glyphs.mdx": "Input Glyphs" 5 | } 6 | -------------------------------------------------------------------------------- /docs/sinytra-wiki.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "controlify", 3 | "platforms": { 4 | "modrinth": "controlify", 5 | "curseforge": "controlify" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | org.gradle.parallel=true 3 | 4 | modVersion=2.1.1 5 | modId=controlify 6 | modName=Controlify 7 | modDescription=The most advanced controller mod for Minecraft. 8 | 9 | curseforgeId=835847 10 | curseforgeSlug=controlify 11 | modrinthId=DOUdJVEm 12 | githubProject=isXander/Controlify 13 | 14 | deps.fabricLoader=0.16.12 15 | deps.sdl3Target=3.1.9.075c033 16 | deps.sdl34jBuild=66 17 | deps.hid4java=0.8.0 18 | deps.quiltparsers=0.3.0 19 | deps.steamdeck4j=1.1.7 20 | deps.mixinExtras=0.5.0-beta.4 21 | 22 | deps.fancyMenu.noRuntime=true 23 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/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.13-all.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenCentral() 4 | gradlePluginPortal() 5 | maven("https://maven.fabricmc.net") 6 | maven("https://maven.quiltmc.org/repository/release") 7 | maven("https://maven.architectury.dev") 8 | maven("https://maven.neoforged.net/releases/") 9 | maven("https://maven.minecraftforge.net/") 10 | maven("https://maven.kikugie.dev/releases") 11 | maven("https://maven.kikugie.dev/snapshots") 12 | maven("https://maven.isxander.dev/releases") 13 | } 14 | } 15 | 16 | plugins { 17 | id("dev.kikugie.stonecutter") version "0.7-alpha.17" 18 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" 19 | } 20 | 21 | stonecutter { 22 | val ciSingleBuild: String? = System.getenv("CI_SINGLE_BUILD") 23 | 24 | if (ciSingleBuild != null) { 25 | val split = ciSingleBuild.split(":") 26 | create(rootProject) { 27 | vers(split[0], split[1]) 28 | } 29 | } else { 30 | create(rootProject, file("versions/versions.json")) 31 | } 32 | } 33 | 34 | rootProject.name = "Controlify" 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/InputMode.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify; 2 | 3 | public enum InputMode { 4 | KEYBOARD_MOUSE, 5 | CONTROLLER, 6 | MIXED; 7 | 8 | public boolean isKeyboardMouse() { 9 | return this != CONTROLLER; 10 | } 11 | 12 | public boolean isController() { 13 | return this != KEYBOARD_MOUSE; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/bind/RadialIcon.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.bind; 2 | 3 | import net.minecraft.client.gui.GuiGraphics; 4 | 5 | @FunctionalInterface 6 | public interface RadialIcon { 7 | RadialIcon EMPTY = (graphics, x, y, tickDelta) -> {}; 8 | 9 | void draw(GuiGraphics graphics, int x, int y, float tickDelta); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/buttonguide/ButtonGuidePredicate.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.buttonguide; 2 | 3 | import net.minecraft.client.gui.components.AbstractButton; 4 | import net.minecraft.client.gui.components.AbstractWidget; 5 | 6 | @FunctionalInterface 7 | public interface ButtonGuidePredicate { 8 | boolean shouldDisplay(T button); 9 | 10 | static ButtonGuidePredicate focusOnly() { 11 | return AbstractWidget::isFocused; 12 | } 13 | 14 | /** Always display the button guide. */ 15 | static ButtonGuidePredicate always() { 16 | return btn -> true; 17 | } 18 | 19 | /** Always display the button guide. */ 20 | @Deprecated 21 | ButtonGuidePredicate ALWAYS = btn -> true; 22 | 23 | /** Only display the button guide when the button is focused. */ 24 | @Deprecated 25 | ButtonGuidePredicate FOCUS_ONLY = AbstractWidget::isFocused; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/buttonguide/ButtonRenderPosition.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.buttonguide; 2 | 3 | /** 4 | * Where the guide should be rendered relative to the button. 5 | */ 6 | @Deprecated 7 | public enum ButtonRenderPosition { 8 | /** 9 | * Renders outside the button the left edge of the screen. 10 | */ 11 | LEFT, 12 | /** 13 | * Renders outside the button the right edge of the screen. 14 | */ 15 | RIGHT, 16 | /** 17 | * Renders inside the button on the left of the button text. 18 | */ 19 | TEXT 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/entrypoint/ControlifyEntrypoint.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.entrypoint; 2 | 3 | import dev.isxander.controlify.api.ControlifyApi; 4 | 5 | public interface ControlifyEntrypoint { 6 | /** 7 | * Called once Controlify has been fully initialised. And all controllers have 8 | * been discovered and loaded. 9 | * Due to the nature of the resource-pack system, this is called 10 | * very late in the game's lifecycle (once the resources have been reloaded). 11 | */ 12 | void onControllersDiscovered(ControlifyApi controlify); 13 | 14 | /** 15 | * Called once Controlify has initialised some systems but controllers 16 | * have not yet been discovered and constructed. This is the ideal 17 | * time to register events in preparation for controller discovery. 18 | */ 19 | default void onControlifyInit(ControlifyApi controlify) { 20 | this.onControlifyPreInit(controlify); 21 | } 22 | 23 | 24 | @SuppressWarnings("DeprecatedIsStillUsed") 25 | @Deprecated 26 | default void onControlifyPreInit(ControlifyApi controlify) { 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/guide/ActionPriority.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.guide; 2 | 3 | /** 4 | * Defines how the action is sorted in the list. All default Controlify actions are {@link #NORMAL}. 5 | */ 6 | public enum ActionPriority { 7 | LOWEST, 8 | LOW, 9 | NORMAL, 10 | HIGH, 11 | HIGHEST 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/guide/GuideActionNameSupplier.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.guide; 2 | 3 | import net.minecraft.network.chat.Component; 4 | 5 | import java.util.Optional; 6 | 7 | /** 8 | * Supplies the text to display for a guide action based on the current id. 9 | * If return is empty, the action will not be displayed. 10 | *

11 | * This is supplied once every tick. 12 | */ 13 | @FunctionalInterface 14 | public interface GuideActionNameSupplier { 15 | Optional supply(T ctx); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/ingameguide/ActionLocation.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.ingameguide; 2 | 3 | /** 4 | * Whether the action should be on the left or right list. 5 | */ 6 | public enum ActionLocation { 7 | LEFT, RIGHT 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/ingameguide/IngameGuideContext.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.ingameguide; 2 | 3 | import dev.isxander.controlify.controller.ControllerEntity; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.client.multiplayer.ClientLevel; 6 | import net.minecraft.client.player.LocalPlayer; 7 | import net.minecraft.world.phys.HitResult; 8 | 9 | /** 10 | * All information available to a guide entry. 11 | * This may be added over time. 12 | * @param client the minecraft client 13 | * @param player local player 14 | * @param level the current world 15 | * @param hitResult where the player is currently looking 16 | * @param controller the controller for this guide renderer 17 | */ 18 | public record IngameGuideContext(Minecraft client, 19 | LocalPlayer player, 20 | ClientLevel level, 21 | HitResult hitResult, 22 | ControllerEntity controller) { 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/vmousesnapping/ISnapBehaviour.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.vmousesnapping; 2 | 3 | import java.util.Set; 4 | import java.util.function.Consumer; 5 | 6 | /** 7 | * An interface to implement by gui components to define snap points for virtual mouse snapping. 8 | * Can also be implemented in a mixin to improve compatibility. 9 | */ 10 | public interface ISnapBehaviour { 11 | default void controlify$collectSnapPoints(Consumer consumer) { 12 | for (SnapPoint point : getSnapPoints()) { 13 | consumer.accept(point); 14 | } 15 | } 16 | 17 | @Deprecated 18 | default Set getSnapPoints() { 19 | return Set.of(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/api/vmousesnapping/SnapPoint.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.api.vmousesnapping; 2 | 3 | import org.joml.Vector2i; 4 | import org.joml.Vector2ic; 5 | 6 | /** 7 | * Defines a point on the screen that the virtual mouse can snap to. 8 | * 9 | * @param position the position on the screen where the cursor will snap to 10 | * @param range how far away from the snap point the cursor can be and still snap to it 11 | */ 12 | public record SnapPoint(Vector2ic position, int range) { 13 | public SnapPoint(int x, int y, int range) { 14 | this(new Vector2i(x, y), range); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/KeyMappingHandle.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings; 2 | 3 | import dev.isxander.controlify.controller.ControllerEntity; 4 | 5 | import java.util.function.BooleanSupplier; 6 | 7 | public interface KeyMappingHandle { 8 | void controlify$setPressed(boolean isDown); 9 | 10 | void controlify$addToggleCondition(ControllerEntity controller, BooleanSupplier condition); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/StateAccess.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings; 2 | 3 | public interface StateAccess { 4 | float analogue(int history); 5 | 6 | boolean digital(int history); 7 | 8 | boolean isSuppressed(); 9 | 10 | boolean isValid(); 11 | 12 | int maxHistory(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/defaults/DefaultBindProvider.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.defaults; 2 | 3 | import dev.isxander.controlify.bindings.input.Input; 4 | import net.minecraft.resources.ResourceLocation; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | public interface DefaultBindProvider { 8 | @Nullable 9 | Input getDefaultBind(ResourceLocation bindId); 10 | 11 | DefaultBindProvider EMPTY = bind -> null; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/input/AxisInput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.input; 2 | 3 | import com.mojang.serialization.MapCodec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import dev.isxander.controlify.controller.input.ControllerStateView; 6 | import net.minecraft.resources.ResourceLocation; 7 | 8 | import java.util.List; 9 | 10 | public record AxisInput(ResourceLocation axis) implements Input { 11 | public static final String INPUT_ID = "axis"; 12 | 13 | public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( 14 | ResourceLocation.CODEC.fieldOf(INPUT_ID).forGetter(AxisInput::axis) 15 | ).apply(instance, AxisInput::new)); 16 | 17 | @Override 18 | public float state(ControllerStateView state) { 19 | return state.getAxisState(axis); 20 | } 21 | 22 | @Override 23 | public List getRelevantInputs() { 24 | return List.of(axis); 25 | } 26 | 27 | @Override 28 | public InputType type() { 29 | return InputType.AXIS; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/input/ButtonInput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.input; 2 | 3 | import com.mojang.serialization.MapCodec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import dev.isxander.controlify.controller.input.ControllerStateView; 6 | import net.minecraft.resources.ResourceLocation; 7 | 8 | import java.util.List; 9 | 10 | public record ButtonInput(ResourceLocation button) implements Input { 11 | public static final String INPUT_ID = "button"; 12 | 13 | public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( 14 | ResourceLocation.CODEC.fieldOf(INPUT_ID).forGetter(ButtonInput::button) 15 | ).apply(instance, ButtonInput::new)); 16 | 17 | @Override 18 | public float state(ControllerStateView state) { 19 | return state.isButtonDown(button) ? 1 : 0; 20 | } 21 | 22 | @Override 23 | public List getRelevantInputs() { 24 | return List.of(button); 25 | } 26 | 27 | @Override 28 | public InputType type() { 29 | return InputType.BUTTON; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/input/EmptyInput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.input; 2 | 3 | import com.mojang.serialization.MapCodec; 4 | import dev.isxander.controlify.controller.input.ControllerStateView; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | import java.util.List; 8 | 9 | public record EmptyInput() implements Input { 10 | public static final EmptyInput INSTANCE = new EmptyInput(); 11 | 12 | public static final String INPUT_ID = "empty"; 13 | public static final MapCodec CODEC = MapCodec.unit(() -> INSTANCE); 14 | 15 | @Override 16 | public float state(ControllerStateView state) { 17 | return 0; 18 | } 19 | 20 | @Override 21 | public List getRelevantInputs() { 22 | return List.of(); 23 | } 24 | 25 | @Override 26 | public InputType type() { 27 | return InputType.EMPTY; 28 | } 29 | 30 | public static boolean equals(Input input) { 31 | return input instanceof EmptyInput; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/input/Input.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.input; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.MapCodec; 5 | import dev.isxander.controlify.controller.input.ControllerStateView; 6 | import net.minecraft.resources.ResourceLocation; 7 | 8 | import java.util.List; 9 | 10 | public interface Input { 11 | MapCodec MAP_CODEC = InputType.createCodec(InputType.TYPES, InputType::codec, Input::type, "type"); 12 | Codec CODEC = MAP_CODEC.codec(); 13 | 14 | float state(ControllerStateView state); 15 | 16 | List getRelevantInputs(); 17 | 18 | InputType type(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/output/AnalogueOutput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.output; 2 | 3 | public interface AnalogueOutput extends BindingOutput { 4 | float get(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/output/BindingOutput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.output; 2 | 3 | public interface BindingOutput { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/output/DigitalOutput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.output; 2 | 3 | /** 4 | * An interface that is responsible for consuming a binding's raw 5 | * state and outputting a relevant value from that. 6 | */ 7 | public interface DigitalOutput extends BindingOutput { 8 | boolean get(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/output/JustPressedOutput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.output; 2 | 3 | import dev.isxander.controlify.api.bind.InputBinding; 4 | import dev.isxander.controlify.bindings.StateAccess; 5 | 6 | public class JustPressedOutput implements DigitalOutput { 7 | private final StateAccess stateAccess; 8 | 9 | public JustPressedOutput(InputBinding binding) { 10 | this.stateAccess = binding.createStateAccess(2); 11 | } 12 | 13 | @Override 14 | public boolean get() { 15 | if (stateAccess.isSuppressed()) 16 | return false; 17 | 18 | return stateAccess.digital(0) && !stateAccess.digital(1); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/output/JustReleasedOutput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.output; 2 | 3 | import dev.isxander.controlify.api.bind.InputBinding; 4 | import dev.isxander.controlify.bindings.StateAccess; 5 | 6 | public class JustReleasedOutput implements DigitalOutput { 7 | private final StateAccess stateAccess; 8 | 9 | public JustReleasedOutput(InputBinding binding) { 10 | this.stateAccess = binding.createStateAccess(2); 11 | } 12 | 13 | @Override 14 | public boolean get() { 15 | if (stateAccess.isSuppressed()) 16 | return false; 17 | 18 | return !stateAccess.digital(0) && stateAccess.digital(1); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/output/SimpleAnalogueOutput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.output; 2 | 3 | import dev.isxander.controlify.api.bind.InputBinding; 4 | import dev.isxander.controlify.bindings.StateAccess; 5 | 6 | public class SimpleAnalogueOutput implements AnalogueOutput { 7 | private final StateAccess stateAccess; 8 | private final int history; 9 | 10 | public SimpleAnalogueOutput(InputBinding binding, int history) { 11 | this.stateAccess = binding.createStateAccess(history + 1); 12 | this.history = history; 13 | } 14 | 15 | @Override 16 | public float get() { 17 | if (stateAccess.isSuppressed()) 18 | return 0f; 19 | 20 | return stateAccess.analogue(history); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/bindings/output/SimpleDigitalOutput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.bindings.output; 2 | 3 | import dev.isxander.controlify.api.bind.InputBinding; 4 | import dev.isxander.controlify.bindings.StateAccess; 5 | 6 | public class SimpleDigitalOutput implements DigitalOutput { 7 | private final StateAccess stateAccess; 8 | private final int history; 9 | 10 | public SimpleDigitalOutput(InputBinding binding, int history) { 11 | this.stateAccess = binding.createStateAccess(history + 1); 12 | this.history = history; 13 | } 14 | 15 | @Override 16 | public boolean get() { 17 | if (stateAccess.isSuppressed()) 18 | return false; 19 | 20 | return stateAccess.digital(history); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/fancymenu/FancyMenuCompat.java: -------------------------------------------------------------------------------- 1 | //? if fancy-menu { 2 | package dev.isxander.controlify.compatibility.fancymenu; 3 | 4 | import de.keksuccino.fancymenu.customization.action.ActionRegistry; 5 | 6 | public final class FancyMenuCompat { 7 | public static void registerActions() { 8 | ActionRegistry.register(new OpenControllerCarouselAction()); 9 | } 10 | } 11 | //?} 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/iris/IrisMixinPlugin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.iris; 2 | 3 | import dev.isxander.controlify.compatibility.CompatMixinPlugin; 4 | 5 | public class IrisMixinPlugin extends CompatMixinPlugin { 6 | @Override 7 | public String getModId() { 8 | return "iris"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/iris/screenop/BaseOptionElementComponentProcessor.java: -------------------------------------------------------------------------------- 1 | //? if iris { 2 | package dev.isxander.controlify.compatibility.iris.screenop; 3 | 4 | import dev.isxander.controlify.screenop.compat.AbstractSliderComponentProcessor; 5 | 6 | import java.util.function.Consumer; 7 | 8 | public class BaseOptionElementComponentProcessor extends AbstractSliderComponentProcessor { 9 | private final Consumer cycleMethod; 10 | 11 | public BaseOptionElementComponentProcessor(Consumer cycleMethod) { 12 | this.cycleMethod = cycleMethod; 13 | } 14 | 15 | @Override 16 | protected void incrementSlider(boolean reverse) { 17 | this.cycleMethod.accept(reverse); 18 | } 19 | } 20 | //?} 21 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/rso/RSOMixinPlugin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.rso; 2 | 3 | import dev.isxander.controlify.compatibility.CompatMixinPlugin; 4 | 5 | public class RSOMixinPlugin extends CompatMixinPlugin { 6 | @Override 7 | public String getModId() { 8 | return "reeses-sodium-options"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/rso/mixins/AbstractFrameAccessor.java: -------------------------------------------------------------------------------- 1 | //? if reeses-sodium-options { 2 | package dev.isxander.controlify.compatibility.rso.mixins; 3 | 4 | import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.AbstractFrame; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import java.util.List; 9 | 10 | import net.caffeinemc.mods.sodium.client.gui.options.control.ControlElement; 11 | 12 | @Mixin(value = AbstractFrame.class, remap = false) 13 | public interface AbstractFrameAccessor { 14 | @Accessor 15 | List> getControlElements(); 16 | } 17 | //?} 18 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/rso/mixins/TabFrameAccessor.java: -------------------------------------------------------------------------------- 1 | //? if reeses-sodium-options { 2 | package dev.isxander.controlify.compatibility.rso.mixins; 3 | 4 | import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.AbstractFrame; 5 | import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.tab.Tab; 6 | import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.tab.TabFrame; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | import java.util.List; 11 | import java.util.Optional; 12 | 13 | @Mixin(value = TabFrame.class, remap = false) 14 | public interface TabFrameAccessor { 15 | @Accessor 16 | List> getTabs(); 17 | 18 | @Accessor 19 | Optional> 20 | getSelectedTab(); 21 | 22 | @Accessor 23 | AbstractFrame getSelectedFrame(); 24 | } 25 | //?} 26 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/simplevoicechat/SVCMixinPlugin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.simplevoicechat; 2 | 3 | import dev.isxander.controlify.compatibility.CompatMixinPlugin; 4 | 5 | public class SVCMixinPlugin extends CompatMixinPlugin { 6 | @Override 7 | public String getModId() { 8 | return "voicechat"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/simplevoicechat/mixins/KeyEventsAccessor.java: -------------------------------------------------------------------------------- 1 | //? if simple-voice-chat { 2 | package dev.isxander.controlify.compatibility.simplevoicechat.mixins; 3 | 4 | import de.maxhenkel.voicechat.voice.client.KeyEvents; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | 8 | @Mixin(value = KeyEvents.class, remap = false) 9 | public interface KeyEventsAccessor { 10 | @Invoker 11 | boolean invokeCheckConnected(); 12 | } 13 | //?} 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/sodium/SodiumMixinPlugin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.sodium; 2 | 3 | import dev.isxander.controlify.compatibility.CompatMixinPlugin; 4 | 5 | public class SodiumMixinPlugin extends CompatMixinPlugin { 6 | @Override 7 | public String getModId() { 8 | return "sodium"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/sodium/mixins/AbstractWidgetMixin.java: -------------------------------------------------------------------------------- 1 | /*? if sodium {*/ 2 | package dev.isxander.controlify.compatibility.sodium.mixins; 3 | 4 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 5 | import dev.isxander.controlify.Controlify; 6 | import net.minecraft.client.InputType; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | 10 | import net.caffeinemc.mods.sodium.client.gui.widgets.AbstractWidget; 11 | 12 | @Mixin(AbstractWidget.class) 13 | public class AbstractWidgetMixin { 14 | @ModifyExpressionValue(method = "setFocused", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;getLastInputType()Lnet/minecraft/client/InputType;")) 15 | private InputType forceSetFocusedOnController(InputType type) { 16 | if (Controlify.instance().currentInputMode().isController()) { 17 | return InputType.KEYBOARD_ARROW; 18 | } 19 | return type; 20 | } 21 | } 22 | /*?}*/ 23 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/sodium/mixins/CycleControlElementMixin.java: -------------------------------------------------------------------------------- 1 | //? if sodium { 2 | package dev.isxander.controlify.compatibility.sodium.mixins; 3 | 4 | import dev.isxander.controlify.compatibility.sodium.screenop.CycleControlProcessor; 5 | import dev.isxander.controlify.screenop.ComponentProcessor; 6 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.Unique; 10 | 11 | @Mixin(targets = "net.caffeinemc.mods.sodium.client.gui.options.control.CyclingControl$CyclingControlElement", remap = false) 12 | public abstract class CycleControlElementMixin implements ComponentProcessorProvider { 13 | @Shadow public abstract void cycleControl(boolean reverse); 14 | 15 | @Unique private final ComponentProcessor controlify$componentProcessor 16 | = new CycleControlProcessor(this::cycleControl); 17 | 18 | @Override 19 | public ComponentProcessor componentProcessor() { 20 | return controlify$componentProcessor; 21 | } 22 | } 23 | //?} 24 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/sodium/mixins/FlatButtonWidgetAccessor.java: -------------------------------------------------------------------------------- 1 | //? if sodium { 2 | package dev.isxander.controlify.compatibility.sodium.mixins; 3 | 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Invoker; 6 | 7 | import net.caffeinemc.mods.sodium.client.gui.widgets.FlatButtonWidget; 8 | 9 | @Mixin(value = FlatButtonWidget.class, remap = false) 10 | public interface FlatButtonWidgetAccessor { 11 | @Invoker 12 | void invokeDoAction(); 13 | } 14 | //?} 15 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/sodium/mixins/TickBoxControlElementMixin.java: -------------------------------------------------------------------------------- 1 | //? if sodium { 2 | package dev.isxander.controlify.compatibility.sodium.mixins; 3 | 4 | import dev.isxander.controlify.compatibility.sodium.screenop.TickBoxControlProcessor; 5 | import dev.isxander.controlify.screenop.ComponentProcessor; 6 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.Unique; 10 | 11 | @Mixin(targets = "net.caffeinemc.mods.sodium.client.gui.options.control.TickBoxControl$TickBoxControlElement", remap = false) 12 | public abstract class TickBoxControlElementMixin implements ComponentProcessorProvider { 13 | @Shadow public abstract void toggleControl(); 14 | 15 | @Unique private final ComponentProcessor controlify$componentProcessor 16 | = new TickBoxControlProcessor(this::toggleControl); 17 | 18 | @Override 19 | public ComponentProcessor componentProcessor() { 20 | return controlify$componentProcessor; 21 | } 22 | } 23 | //?} 24 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/sodium/screenop/SliderControlProcessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.sodium.screenop; 2 | 3 | import dev.isxander.controlify.screenop.compat.AbstractSliderComponentProcessor; 4 | 5 | import java.util.function.Consumer; 6 | 7 | public class SliderControlProcessor extends AbstractSliderComponentProcessor { 8 | private final Consumer cycleMethod; 9 | 10 | public SliderControlProcessor(Consumer cycleMethod) { 11 | this.cycleMethod = cycleMethod; 12 | } 13 | 14 | @Override 15 | protected void incrementSlider(boolean reverse) { 16 | cycleMethod.accept(reverse); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/sodium/screenop/SodiumScreenOperations.java: -------------------------------------------------------------------------------- 1 | //? if sodium { 2 | package dev.isxander.controlify.compatibility.sodium.screenop; 3 | 4 | import net.caffeinemc.mods.sodium.client.gui.widgets.FlatButtonWidget; 5 | 6 | public interface SodiumScreenOperations { 7 | void controlify$nextPage(); 8 | 9 | void controlify$prevPage(); 10 | 11 | FlatButtonWidget controlify$getApplyButton(); 12 | 13 | FlatButtonWidget controlify$getCloseButton(); 14 | 15 | FlatButtonWidget controlify$getUndoButton(); 16 | } 17 | //?} 18 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/yacl/YACLMixinPlugin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.yacl; 2 | 3 | import dev.isxander.controlify.compatibility.CompatMixinPlugin; 4 | 5 | public class YACLMixinPlugin extends CompatMixinPlugin { 6 | @Override 7 | public String getModId() { 8 | return "yet_another_config_lib_v3"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/yacl/mixins/ControllerWidgetAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.yacl.mixins; 2 | 3 | import dev.isxander.yacl3.api.Controller; 4 | import dev.isxander.yacl3.gui.controllers.ControllerWidget; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(value = ControllerWidget.class, remap = false) 9 | public interface ControllerWidgetAccessor { 10 | @Accessor 11 | Controller getControl(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/yacl/mixins/CyclingControllerElementMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.yacl.mixins; 2 | 3 | import dev.isxander.controlify.screenop.ComponentProcessor; 4 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 5 | import dev.isxander.controlify.compatibility.yacl.screenop.CyclingControllerElementComponentProcessor; 6 | import dev.isxander.yacl3.gui.controllers.cycling.CyclingControllerElement; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(CyclingControllerElement.class) 11 | public class CyclingControllerElementMixin implements ComponentProcessorProvider { 12 | @Unique private final CyclingControllerElementComponentProcessor controlify$processor 13 | = new CyclingControllerElementComponentProcessor((CyclingControllerElement) (Object) this); 14 | 15 | @Override 16 | public ComponentProcessor componentProcessor() { 17 | return controlify$processor; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/yacl/mixins/SliderControllerElementMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.yacl.mixins; 2 | 3 | import dev.isxander.controlify.screenop.ComponentProcessor; 4 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 5 | import dev.isxander.controlify.compatibility.yacl.screenop.SliderControllerElementComponentProcessor; 6 | import dev.isxander.yacl3.gui.controllers.slider.SliderControllerElement; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(SliderControllerElement.class) 11 | public class SliderControllerElementMixin implements ComponentProcessorProvider { 12 | @Unique private final SliderControllerElementComponentProcessor controlify$processor 13 | = new SliderControllerElementComponentProcessor((SliderControllerElement) (Object) this); 14 | 15 | @Override 16 | public ComponentProcessor componentProcessor() { 17 | return controlify$processor; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/yacl/mixins/YACLScreenCategoryTabAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.yacl.mixins; 2 | 3 | import dev.isxander.yacl3.gui.OptionListWidget; 4 | import dev.isxander.yacl3.gui.YACLScreen; 5 | import dev.isxander.yacl3.gui.tab.ListHolderWidget; 6 | import net.minecraft.client.gui.components.Button; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | @Mixin(value = YACLScreen.CategoryTab.class, remap = false) 11 | public interface YACLScreenCategoryTabAccessor { 12 | @Accessor 13 | Button getSaveFinishedButton(); 14 | 15 | @Accessor 16 | ListHolderWidget getOptionList(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/compatibility/yacl/mixins/YACLScreenMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.compatibility.yacl.mixins; 2 | 3 | import dev.isxander.controlify.screenop.ScreenProcessor; 4 | import dev.isxander.controlify.screenop.ScreenProcessorProvider; 5 | import dev.isxander.controlify.compatibility.yacl.screenop.YACLScreenProcessor; 6 | import dev.isxander.yacl3.gui.YACLScreen; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(YACLScreen.class) 11 | public class YACLScreenMixin implements ScreenProcessorProvider { 12 | @Unique private final YACLScreenProcessor controlify$processor = new YACLScreenProcessor((YACLScreen) (Object) this); 13 | 14 | @Override 15 | public ScreenProcessor screenProcessor() { 16 | return controlify$processor; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/config/ModMenuIntegration.java: -------------------------------------------------------------------------------- 1 | /*? if mod-menu {*/ 2 | package dev.isxander.controlify.config; 3 | 4 | import com.terraformersmc.modmenu.api.ConfigScreenFactory; 5 | import com.terraformersmc.modmenu.api.ModMenuApi; 6 | import dev.isxander.controlify.gui.screen.ModConfigOpenerScreen; 7 | 8 | public class ModMenuIntegration implements ModMenuApi { 9 | @Override 10 | public ConfigScreenFactory getModConfigScreenFactory() { 11 | return ModConfigOpenerScreen::new; 12 | } 13 | } 14 | /*?}*/ 15 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/config/TypeAdapters.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.config; 2 | 3 | import com.google.gson.*; 4 | 5 | import java.lang.reflect.Type; 6 | 7 | public final class TypeAdapters { 8 | public static class ClassTypeAdapter implements JsonSerializer>, JsonDeserializer> { 9 | @Override 10 | public Class deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 11 | try { 12 | return Class.forName(json.getAsString()); 13 | } catch (ClassNotFoundException e) { 14 | throw new RuntimeException(e); 15 | } 16 | } 17 | 18 | @Override 19 | public JsonElement serialize(Class src, Type typeOfSrc, JsonSerializationContext context) { 20 | return new JsonPrimitive(src.getName()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/ECSComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | 5 | public interface ECSComponent { 6 | ResourceLocation id(); 7 | 8 | default void finalise() { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/ECSEntity.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | 5 | import java.util.Collection; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Optional; 9 | 10 | public interface ECSEntity { 11 | Map getAllComponents(); 12 | 13 | boolean setComponent(T component); 14 | 15 | boolean removeComponent(ResourceLocation id); 16 | 17 | Optional getComponent(ResourceLocation id); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/GamepadControllerConfig.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller; 2 | 3 | import dev.isxander.controlify.controller.serialization.ConfigClass; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public class GamepadControllerConfig implements ConfigClass { 8 | public static final ResourceLocation ID = CUtil.rl("config/gamepad"); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/GenericControllerConfig.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller; 2 | 3 | import dev.isxander.controlify.controller.serialization.ConfigClass; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class GenericControllerConfig implements ConfigClass { 9 | public static final ResourceLocation ID = CUtil.rl("config/generic"); 10 | 11 | @Nullable 12 | public String nickname = null; 13 | 14 | public boolean autoJump = false; 15 | public boolean toggleSprint = true; 16 | public boolean toggleSneak = true; 17 | public boolean disableFlyDrifting = false; 18 | 19 | public boolean showIngameGuide = true; 20 | public boolean ingameGuideBottom = false; 21 | public boolean showScreenGuides = true; 22 | 23 | public boolean showOnScreenKeyboard = true; 24 | 25 | public boolean dontShowControllerSubmission = false; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/JoystickControllerConfig.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller; 2 | 3 | import dev.isxander.controlify.controller.serialization.ConfigClass; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public class JoystickControllerConfig implements ConfigClass { 8 | public static final ResourceLocation ID = CUtil.rl("config/joystick"); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/SingleValueComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | 5 | public class SingleValueComponent implements ECSComponent { 6 | private final T value; 7 | private final ResourceLocation id; 8 | 9 | public SingleValueComponent(T value, ResourceLocation id) { 10 | this.value = value; 11 | this.id = id; 12 | } 13 | 14 | public T value() { 15 | return this.value; 16 | } 17 | 18 | @Override 19 | public ResourceLocation id() { 20 | return this.id; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/battery/BatteryLevelComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.battery; 2 | 3 | import dev.isxander.controlify.controller.ECSComponent; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public class BatteryLevelComponent implements ECSComponent { 8 | public static final ResourceLocation ID = CUtil.rl("battery_level"); 9 | 10 | private PowerState batteryLevel = new PowerState.Unknown(); 11 | 12 | public PowerState getBatteryLevel() { 13 | return this.batteryLevel; 14 | } 15 | 16 | public void setBatteryLevel(PowerState batteryLevel) { 17 | this.batteryLevel = batteryLevel; 18 | } 19 | 20 | @Override 21 | public ResourceLocation id() { 22 | return ID; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/battery/PowerState.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.battery; 2 | 3 | public sealed interface PowerState { 4 | default int percent() { 5 | return -1; 6 | } 7 | 8 | record Depleting(int percent) implements PowerState {} 9 | record Charging(int percent) implements PowerState {} 10 | record Full() implements PowerState { 11 | @Override 12 | public int percent() { 13 | return 100; 14 | } 15 | } 16 | record WiredOnly() implements PowerState {} 17 | record Unknown() implements PowerState {} 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/gyro/GyroButtonMode.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.gyro; 2 | 3 | public enum GyroButtonMode { 4 | ON, 5 | INVERT, 6 | TOGGLE, 7 | OFF 8 | } -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/gyro/GyroStateC.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.gyro; 2 | 3 | import org.joml.Vector3fc; 4 | 5 | /** 6 | * Represents the current gyro delta in radians per second. 7 | */ 8 | public interface GyroStateC extends Vector3fc { 9 | GyroStateC ZERO = new GyroState(0, 0, 0); 10 | 11 | default float pitch() { 12 | return x(); 13 | } 14 | 15 | default float yaw() { 16 | return y(); 17 | } 18 | 19 | default float roll() { 20 | return z(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/gyro/GyroYawMode.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.gyro; 2 | 3 | public enum GyroYawMode { 4 | YAW, 5 | ROLL, 6 | BOTH 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/haptic/CompleteSoundData.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.haptic; 2 | 3 | import javax.sound.sampled.AudioFormat; 4 | 5 | public record CompleteSoundData(byte[] audio, AudioFormat format) { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/haptic/HapticEffects.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.haptic; 2 | 3 | import dev.isxander.controlify.utils.CUtil; 4 | import net.minecraft.resources.ResourceLocation; 5 | 6 | public final class HapticEffects { 7 | public static final ResourceLocation NAVIGATE = CUtil.rl("haptics/navigate.ogg"); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/info/ControllerInfo.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.info; 2 | 3 | import dev.isxander.controlify.controller.id.ControllerType; 4 | import dev.isxander.controlify.controllermanager.UniqueControllerID; 5 | import dev.isxander.controlify.hid.HIDDevice; 6 | 7 | import java.util.Optional; 8 | 9 | public record ControllerInfo(UniqueControllerID ucid, ControllerType type, Optional hid) { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/info/DriverNameComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.info; 2 | 3 | import dev.isxander.controlify.controller.SingleValueComponent; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public class DriverNameComponent extends SingleValueComponent { 8 | public static final ResourceLocation ID = CUtil.rl("driver_name"); 9 | 10 | public DriverNameComponent(String value) { 11 | super(value, ID); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/info/GUIDComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.info; 2 | 3 | import dev.isxander.controlify.controller.SingleValueComponent; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public class GUIDComponent extends SingleValueComponent { 8 | public static final ResourceLocation ID = CUtil.rl("guid"); 9 | 10 | public GUIDComponent(String value) { 11 | super(value, ID); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/info/UIDComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.info; 2 | 3 | import dev.isxander.controlify.controller.SingleValueComponent; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public class UIDComponent extends SingleValueComponent { 8 | public static final ResourceLocation ID = CUtil.rl("uid"); 9 | 10 | public UIDComponent(String value) { 11 | super(value, ID); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/input/ControllerState.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.input; 2 | 3 | import dev.isxander.controlify.controller.impl.ControllerStateImpl; 4 | 5 | public interface ControllerState extends ControllerStateView { 6 | ControllerState EMPTY = new ControllerStateImpl(); 7 | 8 | void clearState(); 9 | 10 | default void close() {} 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/input/ControllerStateView.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.input; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | 5 | import java.util.Set; 6 | 7 | public interface ControllerStateView { 8 | boolean isButtonDown(ResourceLocation button); 9 | 10 | Set getButtons(); 11 | 12 | float getAxisState(ResourceLocation axis); 13 | Set getAxes(); 14 | 15 | float getAxisResting(ResourceLocation axis); 16 | 17 | HatState getHatState(ResourceLocation hat); 18 | Set getHats(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/input/DeadzoneGroup.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.input; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | 5 | import java.util.List; 6 | 7 | public record DeadzoneGroup( 8 | ResourceLocation name, 9 | List axes 10 | ) { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/input/Inputs.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.input; 2 | 3 | import net.minecraft.network.chat.Component; 4 | import net.minecraft.network.chat.MutableComponent; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | import java.util.Collection; 8 | 9 | public final class Inputs { 10 | private Inputs() { 11 | } 12 | 13 | public static MutableComponent getInputComponent(ResourceLocation input) { 14 | return Component.translatable("controlify.input." + input.getNamespace() + "." + input.getPath()); 15 | } 16 | 17 | public static MutableComponent getInputComponentAnd(Collection inputs) { 18 | if (inputs.isEmpty()) 19 | return Component.empty(); 20 | 21 | MutableComponent component = inputs.stream() 22 | .map(Inputs::getInputComponent) 23 | .reduce(Component.empty(), (a, b) -> a.append(b).append(" + ")); 24 | 25 | // remove the last ' + ' 26 | component.getSiblings().remove(component.getSiblings().size() - 1); 27 | 28 | return component; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/input/ModifiableControllerState.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.input; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | 5 | public interface ModifiableControllerState extends ControllerState { 6 | void setButton(ResourceLocation button, boolean pressed); 7 | 8 | void setAxis(ResourceLocation axis, float value); 9 | 10 | void setHat(ResourceLocation hat, HatState state); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/input/mapping/MapType.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.input.mapping; 2 | 3 | public enum MapType { 4 | BUTTON, 5 | AXIS, 6 | HAT, 7 | NOTHING 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/input/mapping/StateMapper.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.input.mapping; 2 | 3 | import dev.isxander.controlify.controller.input.ControllerState; 4 | 5 | public interface StateMapper { 6 | ControllerState mapState(ControllerState state); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/misc/BluetoothDeviceComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.misc; 2 | 3 | import dev.isxander.controlify.controller.serialization.ConfigClass; 4 | import dev.isxander.controlify.controller.serialization.ConfigHolder; 5 | import dev.isxander.controlify.controller.ECSComponent; 6 | import dev.isxander.controlify.controller.serialization.IConfig; 7 | import dev.isxander.controlify.controller.impl.ConfigImpl; 8 | import dev.isxander.controlify.utils.CUtil; 9 | import net.minecraft.resources.ResourceLocation; 10 | 11 | public class BluetoothDeviceComponent implements ECSComponent, ConfigHolder { 12 | public static final ResourceLocation ID = CUtil.rl("bluetooth"); 13 | 14 | private final IConfig config = new ConfigImpl<>(Config::new, Config.class); 15 | 16 | @Override 17 | public IConfig config() { 18 | return config; 19 | } 20 | 21 | @Override 22 | public ResourceLocation id() { 23 | return ID; 24 | } 25 | 26 | public static class Config implements ConfigClass { 27 | public boolean dontShowWarningAgain = false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/rumble/TriggerRumbleComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.rumble; 2 | 3 | import dev.isxander.controlify.controller.ECSComponent; 4 | import dev.isxander.controlify.rumble.TriggerRumbleState; 5 | import dev.isxander.controlify.utils.CUtil; 6 | import net.minecraft.resources.ResourceLocation; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.Optional; 10 | 11 | public class TriggerRumbleComponent implements ECSComponent { 12 | public static final ResourceLocation ID = CUtil.rl("trigger_rumble"); 13 | 14 | private TriggerRumbleState state = null; 15 | 16 | public void queueTriggerRumble(@NotNull TriggerRumbleState state) { 17 | this.state = state; 18 | } 19 | 20 | public Optional consumeTriggerRumble() { 21 | TriggerRumbleState state = this.state; 22 | this.state = null; 23 | return Optional.ofNullable(state); 24 | } 25 | 26 | @Override 27 | public ResourceLocation id() { 28 | return ID; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/serialization/ConfigClass.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.serialization; 2 | 3 | import dev.isxander.controlify.controller.ControllerEntity; 4 | 5 | public interface ConfigClass { 6 | default void onConfigSaveLoad(ControllerEntity controller) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/serialization/ConfigHolder.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.serialization; 2 | 3 | public interface ConfigHolder { 4 | IConfig config(); 5 | 6 | default T confObj() { 7 | return this.config().config(); 8 | } 9 | 10 | default T defObj() { 11 | return this.config().defaultConfig(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/serialization/CustomSaveLoadConfig.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.serialization; 2 | 3 | import com.google.gson.JsonObject; 4 | 5 | public interface CustomSaveLoadConfig { 6 | void fromJson(JsonObject json); 7 | 8 | void toJson(JsonObject json); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/serialization/IConfig.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.serialization; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import dev.isxander.controlify.controller.ControllerEntity; 6 | import dev.isxander.controlify.controller.ECSComponent; 7 | import org.apache.commons.lang3.SerializationException; 8 | 9 | public interface IConfig extends ECSComponent { 10 | T config(); 11 | 12 | T defaultConfig(); 13 | 14 | JsonElement serialize(Gson gson, ControllerEntity controller) throws SerializationException; 15 | 16 | void deserialize(JsonElement element, Gson gson, ControllerEntity controller) throws SerializationException; 17 | 18 | void resetToDefault(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/steamdeck/SteamDeckComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.steamdeck; 2 | 3 | import dev.isxander.controlify.controller.ECSComponent; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public class SteamDeckComponent implements ECSComponent { 8 | public static final ResourceLocation ID = CUtil.rl("steam_deck"); 9 | 10 | @Override 11 | public ResourceLocation id() { 12 | return ID; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controller/touchpad/TouchpadComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controller.touchpad; 2 | 3 | import dev.isxander.controlify.controller.ECSComponent; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.List; 10 | 11 | public class TouchpadComponent implements ECSComponent { 12 | public static final ResourceLocation ID = CUtil.rl("touchpad"); 13 | 14 | private final Touchpads touchpads; 15 | 16 | public TouchpadComponent(Touchpads touchpads) { 17 | this.touchpads = touchpads; 18 | } 19 | 20 | public Touchpads.Touchpad[] touchpads() { 21 | return touchpads.touchpads(); 22 | } 23 | 24 | @Override 25 | public ResourceLocation id() { 26 | return ID; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controllermanager/ControllerManager.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controllermanager; 2 | 3 | import dev.isxander.controlify.controller.ControllerEntity; 4 | import dev.isxander.controlify.hid.ControllerHIDService; 5 | 6 | import java.util.List; 7 | import java.util.Optional; 8 | 9 | public interface ControllerManager { 10 | void discoverControllers(); 11 | 12 | void tick(boolean outOfFocus); 13 | 14 | boolean probeConnectedControllers(); 15 | 16 | List getConnectedControllers(); 17 | 18 | boolean isControllerConnected(String uid); 19 | 20 | boolean isControllerGamepad(UniqueControllerID ucid); 21 | 22 | Optional reinitController(ControllerEntity controller, ControllerHIDService.ControllerHIDInfo hidInfo); 23 | 24 | void closeController(String uid); 25 | 26 | void close(); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/controllermanager/UniqueControllerID.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.controllermanager; 2 | 3 | /** 4 | * A unique, abstract identifier for a controller. 5 | * Each implementation of {@link ControllerManager} will have a different implementation. 6 | */ 7 | public interface UniqueControllerID { 8 | @Override 9 | boolean equals(Object obj); 10 | 11 | @Override 12 | String toString(); 13 | 14 | @Override 15 | int hashCode(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/driver/ComponentAdderDriver.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.driver; 2 | 3 | import dev.isxander.controlify.controller.ControllerEntity; 4 | 5 | import java.util.function.Consumer; 6 | 7 | public class ComponentAdderDriver implements Driver { 8 | private final Consumer componentAdder; 9 | 10 | public ComponentAdderDriver(Consumer componentAdder) { 11 | this.componentAdder = componentAdder; 12 | } 13 | 14 | @Override 15 | public void addComponents(ControllerEntity controller) { 16 | componentAdder.accept(controller); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/driver/Driver.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.driver; 2 | 3 | import dev.isxander.controlify.controller.ControllerEntity; 4 | 5 | public interface Driver { 6 | default void addComponents(ControllerEntity controller) {} 7 | 8 | default void update(ControllerEntity controller, boolean outOfFocus) {} 9 | 10 | default void close() {} 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/driver/sdl/SDLException.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.driver.sdl; 2 | 3 | import static dev.isxander.sdl3java.api.error.SdlError.SDL_GetError; 4 | 5 | public class SDLException extends RuntimeException { 6 | public SDLException(String message) { 7 | super(message); 8 | } 9 | 10 | public static SDLException useSDLError(String message) { 11 | return new SDLException(message + ": " + SDL_GetError()); 12 | } 13 | 14 | public static SDLException useSDLError() { 15 | return useSDLError("SDL error"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/driver/sdl/SDLJoystickConnectionState.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.driver.sdl; 2 | 3 | public enum SDLJoystickConnectionState { 4 | INVALID(-1), 5 | UNKNOWN(0), 6 | WIRED(1), 7 | WIRELESS(2); 8 | 9 | private final int asInt; 10 | SDLJoystickConnectionState(int asInt) { 11 | this.asInt = asInt; 12 | } 13 | 14 | public int asInt() { 15 | return asInt; 16 | } 17 | 18 | public static SDLJoystickConnectionState fromInt(int asInt) { 19 | for (SDLJoystickConnectionState state : values()) { 20 | if (state.asInt() == asInt) { 21 | return state; 22 | } 23 | } 24 | throw new IllegalArgumentException("Invalid connection state: " + asInt); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/driver/sdl/SDLUtil.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.driver.sdl; 2 | 3 | import dev.isxander.sdl3java.api.gamepad.SDL_Gamepad; 4 | import dev.isxander.sdl3java.api.joystick.SDL_Joystick; 5 | import dev.isxander.sdl3java.api.joystick.SDL_JoystickID; 6 | 7 | import static dev.isxander.sdl3java.api.gamepad.SdlGamepad.SDL_OpenGamepad; 8 | import static dev.isxander.sdl3java.api.joystick.SdlJoystick.SDL_OpenJoystick; 9 | 10 | public class SDLUtil { 11 | public static SDL_Gamepad openGamepad(SDL_JoystickID jid) { 12 | SDL_Gamepad gamepad = SDL_OpenGamepad(jid); 13 | if (gamepad == null) { 14 | throw SDLException.useSDLError("Failed to open gamepad"); 15 | } 16 | return gamepad; 17 | } 18 | 19 | public static SDL_Joystick openJoystick(SDL_JoystickID jid) { 20 | SDL_Joystick joystick = SDL_OpenJoystick(jid); 21 | if (joystick == null) { 22 | throw SDLException.useSDLError("Failed to open joystick"); 23 | } 24 | return joystick; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/driver/steamdeck/CEFDebuggerFileResult.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.driver.steamdeck; 2 | 3 | public enum CEFDebuggerFileResult { 4 | /** The file has just been created, but requires steam to restart to take effect **/ 5 | REQUIRES_RESTART, 6 | /** An exception occurred when attempting to create the file **/ 7 | FAILED_TO_CREATE, 8 | /** The file exists, but the deck is currently on desktop mode, meaning it can't be used. **/ 9 | PRESENT_BUT_DESKTOP, 10 | /** The deck is in gaming mode, Controlify has an established connection to the CEF debugger **/ 11 | WORKING, 12 | /** Controlify can't check whether the file exists because it is sandboxed and can't access the file system, but even in Gaming mode, Controlify can't establish a connection to CEF **/ 13 | SANDBOXED_ERROR, 14 | /** The device is not a steam deck **/ 15 | NOT_STEAM_DECK 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/driver/steamdeck/SteamDeckMode.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.driver.steamdeck; 2 | 3 | public enum SteamDeckMode { 4 | GAMING_MODE, 5 | DESKTOP_MODE, 6 | NOT_STEAM_DECK; 7 | 8 | public boolean isSteamDeck() { 9 | return this != NOT_STEAM_DECK; 10 | } 11 | public boolean isGamingMode() { 12 | return this == GAMING_MODE; 13 | } 14 | public boolean isDesktopMode() { 15 | return this == DESKTOP_MODE; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/fixes/boatfix/AnalogBoatInput.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.fixes.boatfix; 2 | 3 | import dev.isxander.controlify.mixins.feature.patches.boatfix.BoatMixin; 4 | 5 | /** 6 | * @see BoatMixin 7 | */ 8 | public interface AnalogBoatInput { 9 | void controlify$setAnalogInput(float forward, float right); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/DrawSize.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui; 2 | 3 | public record DrawSize(int width, int height) { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/controllers/FormattableStringController.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui.controllers; 2 | 3 | import dev.isxander.yacl3.api.Option; 4 | import dev.isxander.yacl3.api.controller.ValueFormatter; 5 | import dev.isxander.yacl3.gui.controllers.string.StringController; 6 | import net.minecraft.network.chat.Component; 7 | 8 | public class FormattableStringController extends StringController { 9 | private final ValueFormatter formatter; 10 | 11 | /** 12 | * Constructs a string controller 13 | * 14 | * @param option bound option 15 | * @param formatter the formatter to use 16 | */ 17 | public FormattableStringController(Option option, ValueFormatter formatter) { 18 | super(option); 19 | this.formatter = formatter; 20 | } 21 | 22 | @Override 23 | public Component formatValue() { 24 | return formatter.format(getString()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/guide/ContainerGuideCtx.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui.guide; 2 | 3 | import net.minecraft.world.inventory.Slot; 4 | import net.minecraft.world.item.ItemStack; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | public record ContainerGuideCtx(@Nullable Slot hoveredSlot, ItemStack holdingItem, boolean cursorOutsideContainer) { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/guide/GuideAction.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui.guide; 2 | 3 | import dev.isxander.controlify.api.guide.ActionPriority; 4 | import dev.isxander.controlify.api.guide.GuideActionNameSupplier; 5 | import dev.isxander.controlify.api.bind.InputBinding; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public record GuideAction(InputBinding binding, GuideActionNameSupplier name, ActionPriority priority) implements Comparable> { 9 | public GuideAction(InputBinding binding, GuideActionNameSupplier name) { 10 | this(binding, name, ActionPriority.NORMAL); 11 | } 12 | 13 | @Override 14 | public int compareTo(@NotNull GuideAction o) { 15 | return this.priority().compareTo(o.priority()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/layout/AnchorPoint.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui.layout; 2 | 3 | import org.joml.Vector2i; 4 | 5 | public enum AnchorPoint { 6 | TOP_LEFT(0, 0), 7 | TOP_CENTER(0.5f, 0), 8 | TOP_RIGHT(1, 0), 9 | CENTER_LEFT(0, 0.5f), 10 | CENTER(0.5f, 0.5f), 11 | CENTER_RIGHT(0.5f, 1), 12 | BOTTOM_LEFT(0f, 1f), 13 | BOTTOM_CENTER(0.5f, 1f), 14 | BOTTOM_RIGHT(1f, 1f); 15 | 16 | public final float anchorX, anchorY; 17 | 18 | AnchorPoint(float anchorX, float anchorY) { 19 | this.anchorX = anchorX; 20 | this.anchorY = anchorY; 21 | } 22 | 23 | public Vector2i getAnchorPosition(int w, int h) { 24 | return new Vector2i((int) (w * anchorX), (int) (h * anchorY)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/layout/RenderComponent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui.layout; 2 | import net.minecraft.client.gui.GuiGraphics; 3 | import org.joml.Vector2ic; 4 | 5 | public interface RenderComponent { 6 | void render(GuiGraphics graphics, int x, int y, float deltaTime); 7 | 8 | Vector2ic size(); 9 | 10 | default boolean isVisible() { 11 | return true; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/screen/DontInteruptScreen.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui.screen; 2 | 3 | public interface DontInteruptScreen { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/screen/ModConfigOpenerScreen.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui.screen; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.screens.Screen; 5 | import net.minecraft.network.chat.Component; 6 | 7 | public class ModConfigOpenerScreen extends Screen { 8 | private final Screen lastScreen; 9 | 10 | public ModConfigOpenerScreen(Screen lastScreen) { 11 | super(Component.empty()); 12 | this.lastScreen = lastScreen; 13 | } 14 | 15 | @Override 16 | public void added() { 17 | // need to make sure fabric api has registered all its events 18 | // because calling setScreen before this will cause fapi to freak 19 | // out that it has no remove event and crash the whole game lol 20 | Minecraft minecraft = Minecraft.getInstance(); 21 | this.init(minecraft, minecraft.getWindow().getGuiScaledWidth(), minecraft.getWindow().getGuiScaledHeight()); 22 | 23 | ControllerCarouselScreen.openConfigScreen(lastScreen); 24 | } 25 | 26 | @Override 27 | public void triggerImmediateNarration(boolean useTranslationsCache) { 28 | // no-op narration 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/gui/screen/NoSDLScreen.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.gui.screen; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.screens.AlertScreen; 5 | import net.minecraft.client.gui.screens.Screen; 6 | import net.minecraft.network.chat.CommonComponents; 7 | import net.minecraft.network.chat.Component; 8 | 9 | public class NoSDLScreen extends AlertScreen { 10 | public NoSDLScreen(Runnable actionHandler, Screen parent) { 11 | super( 12 | () -> { 13 | actionHandler.run(); 14 | Minecraft.getInstance().setScreen(parent); 15 | }, 16 | Component.translatable("controlify.gui.no_sdl.title"), 17 | Component.translatable("controlify.gui.no_sdl.message"), 18 | CommonComponents.GUI_OK, 19 | false 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/hid/HIDIdentifier.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.hid; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.DataResult; 5 | 6 | import java.util.HexFormat; 7 | import java.util.List; 8 | 9 | public record HIDIdentifier(int vendorId, int productId) { 10 | public static final Codec LIST_CODEC = Codec.list(Codec.INT).comapFlatMap( 11 | parts -> { 12 | if (parts.size() != 2) { 13 | return DataResult.error(() -> "HID identifier list must have exactly two elements, found " + parts.size()); 14 | } 15 | return DataResult.success(new HIDIdentifier(parts.get(0), parts.get(1))); 16 | }, 17 | hid -> List.of(hid.vendorId(), hid.productId()) 18 | ); 19 | 20 | @Override 21 | public String toString() { 22 | var hex = HexFormat.of(); 23 | return "HID[" + 24 | "VID=0x" + hex.toHexDigits(vendorId, 4) + 25 | ", PID=0x" + hex.toHexDigits(productId, 4) + 26 | ']'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/ingame/PickBlockAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.ingame; 2 | 3 | public interface PickBlockAccessor { 4 | void controlify$pickBlock(); 5 | 6 | void controlify$pickBlockWithNbt(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/core/GLXMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.core; 2 | 3 | import com.mojang.blaze3d.platform.GLX; 4 | import org.lwjgl.glfw.GLFW; 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.CallbackInfoReturnable; 9 | 10 | import java.util.function.LongSupplier; 11 | 12 | @Mixin(value = GLX.class, remap = false) 13 | public class GLXMixin { 14 | @Inject(method = "_initGlfw", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwInit()Z")) 15 | private static void addInitHints(CallbackInfoReturnable cir) { 16 | // stops GLFW adding hats to button list (backward compat) 17 | GLFW.glfwInitHint(GLFW.GLFW_JOYSTICK_HAT_BUTTONS, GLFW.GLFW_FALSE); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/core/GuiMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.core; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 4 | import dev.isxander.controlify.Controlify; 5 | import dev.isxander.controlify.ingame.InGameInputHandler; 6 | import net.minecraft.client.gui.Gui; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | 10 | @Mixin(Gui.class) 11 | public class GuiMixin { 12 | @ModifyExpressionValue(method = "renderTabList", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyMapping;isDown()Z")) 13 | private boolean shouldShowPlayerList(boolean keyDown) { 14 | return keyDown || Controlify.instance().inGameInputHandler().map(InGameInputHandler::shouldShowPlayerList).orElse(false); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/accessibility/LocalPlayerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.accessibility; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 4 | import dev.isxander.controlify.InputMode; 5 | import dev.isxander.controlify.api.ControlifyApi; 6 | import net.minecraft.client.player.LocalPlayer; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | 10 | @Mixin(LocalPlayer.class) 11 | public class LocalPlayerMixin { 12 | @ModifyExpressionValue(method = "sendPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/OptionInstance;get()Ljava/lang/Object;")) 13 | private Object shouldUseAutoJump(Object keyboardAutoJump) { 14 | if (ControlifyApi.get().currentInputMode().isController()) { 15 | return ControlifyApi.get().getCurrentController() 16 | .map(controller -> controller.genericConfig().config().autoJump) 17 | .orElse(false); 18 | } 19 | return keyboardAutoJump; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/bind/GuiMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.bind; 2 | 3 | import dev.isxander.controlify.gui.screen.RadialMenuScreen; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.client.gui.Gui; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import org.spongepowered.asm.mixin.Final; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(Gui.class) 15 | public class GuiMixin { 16 | @Shadow @Final private Minecraft minecraft; 17 | 18 | @Inject(method = "renderCrosshair", at = @At("HEAD"), cancellable = true) 19 | private void shouldRenderCrosshair(CallbackInfo ci) { 20 | if (minecraft.screen instanceof RadialMenuScreen) { 21 | ci.cancel(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/bind/MinecraftMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.bind; 2 | 3 | import dev.isxander.controlify.api.ControlifyApi; 4 | import dev.isxander.controlify.controller.ControllerEntity; 5 | import dev.isxander.controlify.controller.input.InputComponent; 6 | import net.minecraft.client.Minecraft; 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(Minecraft.class) 13 | public class MinecraftMixin { 14 | @Inject(method = "setScreen", at = @At("HEAD")) 15 | private void notifyBindGuiOutputOfScreenChange(CallbackInfo ci) { 16 | ControlifyApi.get().getCurrentController().flatMap(ControllerEntity::input) 17 | .ifPresent(InputComponent::notifyGuiPressOutputsOfNavigate); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/font/FontAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.font; 2 | 3 | import net.minecraft.client.gui.Font; 4 | import net.minecraft.client.gui.font.FontSet; 5 | import net.minecraft.resources.ResourceLocation; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Invoker; 8 | 9 | @Mixin(Font.class) 10 | public interface FontAccessor { 11 | @Invoker 12 | FontSet invokeGetFontSet(ResourceLocation id); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/guide/ingame/GuiMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.guide.ingame; 2 | 3 | import dev.isxander.controlify.Controlify; 4 | import dev.isxander.controlify.gui.guide.InGameButtonGuide; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.Gui; 7 | import org.spongepowered.asm.mixin.Final; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(Gui.class) 15 | public class GuiMixin { 16 | @Shadow @Final private Minecraft minecraft; 17 | 18 | @Inject(method = "tick()V", at = @At("RETURN")) 19 | private void tickButtonGuide(CallbackInfo ci) { 20 | if (minecraft.level == null) return; 21 | 22 | Controlify.instance().inGameButtonGuide().ifPresent(InGameButtonGuide::tick); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/guide/ingame/PlayerAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.guide.ingame; 2 | 3 | import net.minecraft.world.entity.player.Player; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Invoker; 6 | 7 | @Mixin(Player.class) 8 | public interface PlayerAccessor { 9 | //? if >=1.21.2 { 10 | @Invoker 11 | boolean callCanGlide(); 12 | //?} 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/guide/screen/AbstractContainerScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.guide.screen; 2 | 3 | import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; 4 | import net.minecraft.world.inventory.Slot; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | import org.spongepowered.asm.mixin.gen.Invoker; 8 | 9 | @Mixin(AbstractContainerScreen.class) 10 | public interface AbstractContainerScreenAccessor { 11 | @Accessor 12 | Slot getHoveredSlot(); 13 | 14 | @Invoker 15 | boolean invokeHasClickedOutside(double mouseX, double mouseY, int left, int top, int button); 16 | 17 | @Accessor 18 | int getLeftPos(); 19 | 20 | @Accessor 21 | int getTopPos(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/hdhaptics/SoundBufferAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.hdhaptics; 2 | 3 | import com.mojang.blaze3d.audio.SoundBuffer; 4 | import org.jetbrains.annotations.Nullable; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import javax.sound.sampled.AudioFormat; 9 | import java.nio.ByteBuffer; 10 | 11 | @Mixin(SoundBuffer.class) 12 | public interface SoundBufferAccessor { 13 | @Accessor 14 | @Nullable ByteBuffer getData(); 15 | 16 | @Accessor 17 | AudioFormat getFormat(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/hdhaptics/SoundEngineAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.hdhaptics; 2 | 3 | import net.minecraft.client.sounds.SoundBufferLibrary; 4 | import net.minecraft.client.sounds.SoundEngine; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(SoundEngine.class) 9 | public interface SoundEngineAccessor { 10 | @Accessor 11 | SoundBufferLibrary getSoundBuffers(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/hdhaptics/SoundManagerAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.hdhaptics; 2 | 3 | import net.minecraft.client.sounds.SoundEngine; 4 | import net.minecraft.client.sounds.SoundManager; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(SoundManager.class) 9 | public interface SoundManagerAccessor { 10 | @Accessor 11 | SoundEngine getSoundEngine(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/input/DebugScreenOverlayAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.input; 2 | 3 | import net.minecraft.client.gui.components.DebugScreenOverlay; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(DebugScreenOverlay.class) 8 | public interface DebugScreenOverlayAccessor { 9 | @Accessor 10 | boolean isRenderDebug(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/nomousetutorial/MovementTutorialStepInstanceMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.nomousetutorial; 2 | 3 | import dev.isxander.controlify.api.ControlifyApi; 4 | import net.minecraft.client.tutorial.MovementTutorialStepInstance; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(MovementTutorialStepInstance.class) 12 | public class MovementTutorialStepInstanceMixin { 13 | @Shadow 14 | private int lookCompleted; 15 | 16 | @Shadow 17 | private int timeLooked; 18 | 19 | @Inject(method = "", at = @At("RETURN")) 20 | private void stopLookTutorial(CallbackInfo ci) { 21 | if (ControlifyApi.get().currentInputMode().isController()) { 22 | this.lookCompleted = 100; // anything other than -1 seems to work 23 | this.timeLooked = 41; // anything >40 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/oofinput/GameRendererMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.oofinput; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 4 | import dev.isxander.controlify.Controlify; 5 | import net.minecraft.client.renderer.GameRenderer; 6 | import org.objectweb.asm.Opcodes; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | 10 | @Mixin(GameRenderer.class) 11 | public class GameRendererMixin { 12 | @ModifyExpressionValue(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/Options;pauseOnLostFocus:Z", opcode = Opcodes.GETFIELD)) 13 | private boolean shouldPauseOnLossFocus(boolean original) { 14 | return original && !(Controlify.instance().config().globalSettings().outOfFocusInput && Controlify.instance().getCurrentController().isPresent()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/rumble/MinecraftMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.rumble; 2 | 3 | import dev.isxander.controlify.api.ControlifyApi; 4 | import dev.isxander.controlify.controller.ControllerEntity; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.screens.Screen; 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(Minecraft.class) 13 | public class MinecraftMixin { 14 | @Inject(method = "disconnect(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At("HEAD")) 15 | private void clearRumbleEffects(Screen disconnectScreen, CallbackInfo ci) { 16 | ControlifyApi.get().getCurrentController() 17 | .flatMap(ControllerEntity::rumble) 18 | .ifPresent(controller -> controller.rumbleManager().clearEffects()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/rumble/damage/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.rumble.damage; 2 | 3 | import net.minecraft.world.damagesource.DamageSource; 4 | import net.minecraft.world.entity.LivingEntity; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(LivingEntity.class) 12 | public class LivingEntityMixin { 13 | @Shadow 14 | public int hurtDuration; 15 | 16 | @Shadow 17 | public int hurtTime; 18 | 19 | @Inject(method = "handleDamageEvent", at = @At("HEAD")) 20 | protected void onHealthChangedDamage(DamageSource source, CallbackInfo ci) { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/rumble/damage/PlayerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.rumble.damage; 2 | 3 | import net.minecraft.world.entity.player.Player; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | @Mixin(Player.class) 10 | public class PlayerMixin extends LivingEntityMixin { 11 | @Inject(method = "animateHurt", at = @At("HEAD")) 12 | protected void onEntityHurtMeDamage(float yaw, CallbackInfo ci) { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/rumble/itembreak/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.rumble.itembreak; 2 | 3 | import net.minecraft.world.entity.LivingEntity; 4 | import net.minecraft.world.item.ItemStack; 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 | @Mixin(LivingEntity.class) 11 | public class LivingEntityMixin { 12 | @Inject(method = "breakItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;spawnItemParticles(Lnet/minecraft/world/item/ItemStack;I)V")) 13 | protected void onBreakItemParticles(ItemStack stack, CallbackInfo ci) { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/rumble/waterland/PlayerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.rumble.waterland; 2 | 3 | import net.minecraft.world.entity.EntityType; 4 | import net.minecraft.world.entity.LivingEntity; 5 | import net.minecraft.world.entity.player.Player; 6 | import net.minecraft.world.level.Level; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 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 | @Mixin(Player.class) 14 | public abstract class PlayerMixin extends LivingEntity { 15 | @Shadow 16 | public abstract boolean isSpectator(); 17 | 18 | protected PlayerMixin(EntityType entityType, Level level) { 19 | super(entityType, level); 20 | } 21 | 22 | @Inject(method = "doWaterSplashEffect", at = @At("HEAD")) 23 | protected void splashRumble(CallbackInfo ci) { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/ContainerEventHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop; 2 | 3 | import dev.isxander.controlify.screenop.CustomFocus; 4 | import net.minecraft.client.gui.components.events.ContainerEventHandler; 5 | import net.minecraft.client.gui.components.events.GuiEventListener; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | 10 | @Mixin(ContainerEventHandler.class) 11 | public interface ContainerEventHandlerMixin extends CustomFocus { 12 | @Shadow 13 | @Nullable GuiEventListener getFocused(); 14 | 15 | @Override 16 | default GuiEventListener getCustomFocus() { 17 | return this.getFocused(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/MinecraftMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop; 2 | 3 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 4 | import dev.isxander.controlify.screenop.ScreenProcessorProvider; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.screens.Screen; 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(Minecraft.class) 13 | public class MinecraftMixin { 14 | @Inject(method = "setScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;updateTitle()V")) 15 | private void changeScreen(Screen screen, CallbackInfo ci) { 16 | ComponentProcessorProvider.REGISTRY.clearCache(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/ScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop; 2 | 3 | import net.minecraft.client.gui.ComponentPath; 4 | import net.minecraft.client.gui.components.Renderable; 5 | import net.minecraft.client.gui.navigation.FocusNavigationEvent; 6 | import net.minecraft.client.gui.navigation.ScreenDirection; 7 | import net.minecraft.client.gui.screens.Screen; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.gen.Accessor; 10 | import org.spongepowered.asm.mixin.gen.Invoker; 11 | 12 | import java.util.List; 13 | 14 | @Mixin(Screen.class) 15 | public interface ScreenAccessor { 16 | @Invoker 17 | FocusNavigationEvent.ArrowNavigation invokeCreateArrowEvent(ScreenDirection direction); 18 | 19 | @Invoker 20 | void invokeChangeFocus(ComponentPath path); 21 | 22 | @Invoker 23 | void invokeClearFocus(); 24 | 25 | @Accessor 26 | List getRenderables(); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/AbstractButtonMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.ComponentProcessor; 4 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 5 | import dev.isxander.controlify.screenop.compat.vanilla.AbstractButtonComponentProcessor; 6 | import net.minecraft.client.gui.components.AbstractButton; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(AbstractButton.class) 11 | public class AbstractButtonMixin implements ComponentProcessorProvider { 12 | @Unique private final AbstractButtonComponentProcessor controlify$processor 13 | = new AbstractButtonComponentProcessor((AbstractButton) (Object) this); 14 | 15 | @Override 16 | public ComponentProcessor componentProcessor() { 17 | return controlify$processor; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/AbstractContainerEventHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.CustomFocus; 4 | import net.minecraft.client.gui.components.events.AbstractContainerEventHandler; 5 | import net.minecraft.client.gui.components.events.GuiEventListener; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | 10 | @Mixin(AbstractContainerEventHandler.class) 11 | public abstract class AbstractContainerEventHandlerMixin implements CustomFocus { 12 | @Shadow public abstract @Nullable GuiEventListener getFocused(); 13 | 14 | @Override 15 | public GuiEventListener getCustomFocus() { 16 | return getFocused(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/AbstractSelectionListMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 4 | import dev.isxander.controlify.Controlify; 5 | import dev.isxander.controlify.InputMode; 6 | import net.minecraft.client.gui.components.AbstractSelectionList; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | 10 | @Mixin(AbstractSelectionList.class) 11 | public class AbstractSelectionListMixin { 12 | @ModifyExpressionValue(method = "setFocused", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/InputType;isKeyboard()Z")) 13 | private boolean shouldEnsureEntryVisible(boolean keyboard) { 14 | return keyboard || Controlify.instance().currentInputMode().isController(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/AbstractSignEditScreenMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.ScreenProcessor; 4 | import dev.isxander.controlify.screenop.ScreenProcessorProvider; 5 | import dev.isxander.controlify.screenop.compat.vanilla.AbstractSignEditScreenProcessor; 6 | import net.minecraft.client.gui.screens.inventory.AbstractSignEditScreen; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(AbstractSignEditScreen.class) 11 | public class AbstractSignEditScreenMixin implements ScreenProcessorProvider { 12 | @Unique private final AbstractSignEditScreenProcessor screenProcessor = 13 | new AbstractSignEditScreenProcessor((AbstractSignEditScreen) (Object) this); 14 | 15 | @Override 16 | public ScreenProcessor screenProcessor() { 17 | return screenProcessor; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/ContainerObjectSelectionListEntryMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.CustomFocus; 4 | import net.minecraft.client.gui.components.ContainerObjectSelectionList; 5 | import net.minecraft.client.gui.components.events.GuiEventListener; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | 10 | @Mixin(ContainerObjectSelectionList.Entry.class) 11 | public abstract class ContainerObjectSelectionListEntryMixin implements CustomFocus { 12 | @Shadow public abstract @Nullable GuiEventListener getFocused(); 13 | 14 | @Override 15 | public GuiEventListener getCustomFocus() { 16 | return getFocused(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/EditBoxMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.ComponentProcessor; 4 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 5 | import dev.isxander.controlify.screenop.compat.vanilla.EditBoxComponentProcessor; 6 | import net.minecraft.client.gui.components.EditBox; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(EditBox.class) 11 | public class EditBoxMixin implements ComponentProcessorProvider { 12 | @Unique private final ComponentProcessor processor = new EditBoxComponentProcessor(); 13 | 14 | @Override 15 | public ComponentProcessor componentProcessor() { 16 | return processor; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/JoinMultiplayerScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import net.minecraft.client.gui.components.Button; 4 | import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(JoinMultiplayerScreen.class) 9 | public interface JoinMultiplayerScreenAccessor { 10 | @Accessor 11 | Button getSelectButton(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/OptionsSubScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import net.minecraft.client.gui.screens.options.OptionsSubScreen; 4 | import net.minecraft.client.gui.screens.Screen; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(OptionsSubScreen.class) 9 | public interface OptionsSubScreenAccessor { 10 | @Accessor 11 | Screen getLastScreen(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/PauseScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import net.minecraft.client.gui.screens.PauseScreen; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(PauseScreen.class) 8 | public interface PauseScreenAccessor { 9 | @Accessor 10 | boolean getShowPauseMenu(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/PauseScreenMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.ScreenProcessor; 4 | import dev.isxander.controlify.screenop.ScreenProcessorProvider; 5 | import dev.isxander.controlify.screenop.compat.vanilla.PauseScreenProcessor; 6 | import net.minecraft.client.gui.components.Button; 7 | import net.minecraft.client.gui.screens.PauseScreen; 8 | import org.jetbrains.annotations.Nullable; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.Unique; 13 | 14 | @Mixin(PauseScreen.class) 15 | public class PauseScreenMixin implements ScreenProcessorProvider { 16 | @Shadow private @Nullable Button disconnectButton; 17 | 18 | @Unique private final PauseScreenProcessor processor = 19 | new PauseScreenProcessor((PauseScreen) (Object) this, () -> disconnectButton); 20 | 21 | @Override 22 | public ScreenProcessor screenProcessor() { 23 | return processor; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/SelectWorldScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import net.minecraft.client.gui.components.Button; 4 | import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; 5 | import net.minecraft.client.gui.screens.worldselection.WorldSelectionList; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | @Mixin(SelectWorldScreen.class) 10 | public interface SelectWorldScreenAccessor { 11 | @Accessor 12 | Button getSelectButton(); 13 | 14 | @Accessor 15 | WorldSelectionList getList(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/ServerSelectionListEntryMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.ComponentProcessor; 4 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 5 | import dev.isxander.controlify.screenop.compat.vanilla.ServerSelectionListEntryComponentProcessor; 6 | import net.minecraft.client.gui.screens.multiplayer.ServerSelectionList; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(ServerSelectionList.Entry.class) 11 | public class ServerSelectionListEntryMixin implements ComponentProcessorProvider { 12 | @Unique private final ServerSelectionListEntryComponentProcessor controlify$componentProcessor 13 | = new ServerSelectionListEntryComponentProcessor(); 14 | 15 | @Override 16 | public ComponentProcessor componentProcessor() { 17 | return ((ServerSelectionList.Entry) (Object) this) instanceof ServerSelectionList.LANHeader 18 | ? ComponentProcessor.EMPTY 19 | : controlify$componentProcessor; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/TabNavigationBarAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import net.minecraft.client.gui.components.tabs.Tab; 5 | import net.minecraft.client.gui.components.tabs.TabManager; 6 | import net.minecraft.client.gui.components.tabs.TabNavigationBar; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | @Mixin(TabNavigationBar.class) 11 | public interface TabNavigationBarAccessor { 12 | @Accessor 13 | ImmutableList getTabs(); 14 | 15 | @Accessor 16 | TabManager getTabManager(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/TitleScreenMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.ScreenProcessor; 4 | import dev.isxander.controlify.screenop.ScreenProcessorProvider; 5 | import dev.isxander.controlify.screenop.compat.vanilla.TitleScreenProcessor; 6 | import net.minecraft.client.gui.screens.TitleScreen; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(TitleScreen.class) 11 | public class TitleScreenMixin implements ScreenProcessorProvider { 12 | @Unique private final ScreenProcessor processor 13 | = new TitleScreenProcessor((TitleScreen) (Object) this); 14 | 15 | @Override 16 | public ScreenProcessor screenProcessor() { 17 | return processor; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/WorldSelectionListEntryMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.screenop.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.ComponentProcessor; 4 | import dev.isxander.controlify.screenop.ComponentProcessorProvider; 5 | import dev.isxander.controlify.screenop.compat.vanilla.WorldListEntryComponentProcessor; 6 | import net.minecraft.client.gui.screens.worldselection.WorldSelectionList; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Unique; 9 | 10 | @Mixin(WorldSelectionList.WorldListEntry.class) 11 | public class WorldSelectionListEntryMixin implements ComponentProcessorProvider { 12 | @Unique 13 | private final WorldListEntryComponentProcessor controlify$processor = new WorldListEntryComponentProcessor(); 14 | 15 | @Override 16 | public ComponentProcessor componentProcessor() { 17 | return controlify$processor; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/steamdeck/ScreenshotAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.steamdeck; 2 | 3 | import net.minecraft.client.Screenshot; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Invoker; 6 | 7 | import java.io.File; 8 | 9 | @Mixin(Screenshot.class) 10 | public interface ScreenshotAccessor { 11 | @Invoker 12 | static File invokeGetFile(File file) { 13 | throw new AssertionError(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/ui/AbstractSelectionListAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.ui; 2 | 3 | import net.minecraft.client.gui.components.AbstractSelectionList; 4 | import net.minecraft.resources.ResourceLocation; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(AbstractSelectionList.class) 9 | public interface AbstractSelectionListAccessor { 10 | @Accessor("MENU_LIST_BACKGROUND") 11 | static ResourceLocation getMenuListBackground() { 12 | throw new AssertionError(); 13 | } 14 | 15 | @Accessor("INWORLD_MENU_LIST_BACKGROUND") 16 | static ResourceLocation getInWorldMenuListBackground() { 17 | throw new AssertionError(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/util/ConnectScreenMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.util; 2 | 3 | import dev.isxander.controlify.Controlify; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.client.gui.screens.ConnectScreen; 6 | import net.minecraft.client.multiplayer.ServerData; 7 | import net.minecraft.client.multiplayer.TransferState; 8 | import net.minecraft.client.multiplayer.resolver.ServerAddress; 9 | import org.jetbrains.annotations.Nullable; 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 | @Mixin(ConnectScreen.class) 16 | public class ConnectScreenMixin { 17 | @Inject(method = "connect", at = @At("HEAD")) 18 | private void onConnect( 19 | Minecraft client, 20 | ServerAddress address, @Nullable ServerData serverInfo, 21 | @Nullable TransferState transferState, 22 | CallbackInfo ci 23 | ) { 24 | Controlify.instance().notifyNewServer(serverInfo); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/virtualmouse/KeyboardHandlerAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.virtualmouse; 2 | 3 | import net.minecraft.client.KeyboardHandler; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Invoker; 6 | 7 | @Mixin(KeyboardHandler.class) 8 | public interface KeyboardHandlerAccessor { 9 | @Invoker 10 | void invokeKeyPress(long window, int key, int scancode, int action, int modifiers); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/virtualmouse/MouseHandlerAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.virtualmouse; 2 | 3 | import net.minecraft.client.MouseHandler; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | 8 | @Mixin(MouseHandler.class) 9 | public interface MouseHandlerAccessor { 10 | @Invoker 11 | void invokeOnMove(long window, double x, double y); 12 | 13 | @Invoker 14 | void invokeOnPress(long window, int button, int action, int modifiers); 15 | 16 | @Invoker 17 | void invokeOnScroll(long window, double scrollDeltaX, double scrollDeltaY); 18 | 19 | @Accessor 20 | void setMouseGrabbed(boolean mouseGrabbed); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/virtualmouse/MouseHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.virtualmouse; 2 | 3 | import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; 4 | import dev.isxander.controlify.Controlify; 5 | import dev.isxander.controlify.InputMode; 6 | import net.minecraft.client.MouseHandler; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | 10 | @Mixin(MouseHandler.class) 11 | public class MouseHandlerMixin { 12 | @WrapWithCondition(method = "releaseMouse", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/InputConstants;grabOrReleaseMouse(JIDD)V")) 13 | private boolean shouldReleaseMouse(long window, int newMouseState, double x, double y) { 14 | // mouse cursor appears for a split second when going into guis on controller input 15 | return Controlify.instance().currentInputMode() != InputMode.CONTROLLER; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/virtualmouse/snapping/RecipeBookComponentAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.virtualmouse.snapping; 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 | 10 | import java.util.List; 11 | 12 | @Mixin(RecipeBookComponent.class) 13 | public interface RecipeBookComponentAccessor { 14 | @Accessor 15 | RecipeBookPage getRecipeBookPage(); 16 | 17 | @Accessor 18 | List getTabButtons(); 19 | 20 | @Accessor 21 | RecipeBookTabButton getSelectedTab(); 22 | 23 | @Accessor 24 | StateSwitchingButton getFilterButton(); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/mixins/feature/virtualmouse/snapping/RecipeBookPageAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.mixins.feature.virtualmouse.snapping; 2 | 3 | import net.minecraft.client.gui.components.StateSwitchingButton; 4 | import net.minecraft.client.gui.screens.recipebook.RecipeBookPage; 5 | import net.minecraft.client.gui.screens.recipebook.RecipeButton; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | import java.util.List; 10 | 11 | @Mixin(RecipeBookPage.class) 12 | public interface RecipeBookPageAccessor { 13 | @Accessor 14 | List getButtons(); 15 | 16 | @Accessor 17 | StateSwitchingButton getForwardButton(); 18 | 19 | @Accessor 20 | StateSwitchingButton getBackButton(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/ArrayBackedEventHandler.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class ArrayBackedEventHandler implements EventHandler { 7 | private final List> callbacks = new ArrayList<>(); 8 | 9 | @Override 10 | public void register(Callback event) { 11 | this.callbacks.add(event); 12 | } 13 | 14 | @Override 15 | public void invoke(T event) { 16 | this.callbacks.forEach(c -> c.onEvent(event)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/Environment.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform; 2 | 3 | public enum Environment { 4 | CLIENT, 5 | SERVER, 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/Event.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform; 2 | 3 | public interface Event { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/EventHandler.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform; 2 | 3 | public interface EventHandler { 4 | void register(Callback event); 5 | 6 | void invoke(T event); 7 | 8 | static EventHandler createPlatformBackedEvent() { 9 | //? if fabric { 10 | return new dev.isxander.controlify.platform.fabric.FabricBackedEventHandler<>(); 11 | //?} else { 12 | /*return new ArrayBackedEventHandler<>(); 13 | *///?} 14 | } 15 | 16 | @FunctionalInterface 17 | interface Callback { 18 | void onEvent(T event); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/client/CreativeTabHelper.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.client; 2 | 3 | import net.minecraft.world.item.CreativeModeTab; 4 | 5 | import java.util.List; 6 | 7 | public interface CreativeTabHelper { 8 | void setCurrentPage(int page); 9 | 10 | int getCurrentPage(); 11 | 12 | int getPageCount(); 13 | 14 | List getTabsForPage(int page); 15 | 16 | CreativeModeTab getSelectedTab(); 17 | 18 | void setSelectedTab(CreativeModeTab tab); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/client/HudRenderLayer.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.client; 2 | 3 | import net.minecraft.client.DeltaTracker; 4 | import net.minecraft.client.gui.GuiGraphics; 5 | 6 | @FunctionalInterface 7 | public interface HudRenderLayer { 8 | void render(GuiGraphics graphics, DeltaTracker deltaTracker); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/client/events/DisconnectedEvent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.client.events; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.multiplayer.ClientPacketListener; 5 | 6 | @FunctionalInterface 7 | public interface DisconnectedEvent { 8 | void onDisconnected(Minecraft minecraft); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/client/events/LifecycleEvent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.client.events; 2 | 3 | import net.minecraft.client.Minecraft; 4 | 5 | @FunctionalInterface 6 | public interface LifecycleEvent { 7 | void onLifecycle(Minecraft minecraft); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/client/events/ScreenRenderEvent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.client.events; 2 | 3 | import net.minecraft.client.gui.GuiGraphics; 4 | import net.minecraft.client.gui.screens.Screen; 5 | 6 | @FunctionalInterface 7 | public interface ScreenRenderEvent { 8 | void onRender(Screen screen, GuiGraphics graphics, int mouseX, int mouseY, float tickDelta); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/client/events/TickEvent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.client.events; 2 | 3 | import net.minecraft.client.Minecraft; 4 | 5 | @FunctionalInterface 6 | public interface TickEvent { 7 | void onTick(Minecraft minecraft); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/client/resource/ControlifyReloadListener.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.client.resource; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | import net.minecraft.server.packs.resources.PreparableReloadListener; 5 | 6 | import java.util.Collection; 7 | import java.util.Collections; 8 | 9 | public interface ControlifyReloadListener 10 | extends PreparableReloadListener 11 | //? if fabric 12 | ,net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener 13 | { 14 | ResourceLocation getReloadId(); 15 | 16 | default Collection getDependencies() { 17 | return Collections.emptyList(); 18 | } 19 | 20 | //? if fabric { 21 | @Override 22 | default ResourceLocation getFabricId() { 23 | return this.getReloadId(); 24 | } 25 | 26 | @Override 27 | default Collection getFabricDependencies() { 28 | return this.getDependencies(); 29 | } 30 | //?} 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/fabric/FabricBackedEventHandler.java: -------------------------------------------------------------------------------- 1 | //? if fabric { 2 | package dev.isxander.controlify.platform.fabric; 3 | 4 | import dev.isxander.controlify.platform.EventHandler; 5 | import net.fabricmc.fabric.api.event.EventFactory; 6 | 7 | public class FabricBackedEventHandler implements EventHandler { 8 | private final net.fabricmc.fabric.api.event.Event> backedEvent; 9 | 10 | public FabricBackedEventHandler() { 11 | this.backedEvent = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { 12 | for (Callback callback : callbacks) { 13 | callback.onEvent(event); 14 | } 15 | }); 16 | } 17 | 18 | @Override 19 | public void register(Callback event) { 20 | this.backedEvent.register(event); 21 | } 22 | 23 | @Override 24 | public void invoke(T event) { 25 | this.backedEvent.invoker().onEvent(event); 26 | } 27 | } 28 | //?} 29 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/fabric/mixins/CreativeModeInventoryScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.fabric.mixins; 2 | 3 | import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen; 4 | import net.minecraft.world.item.CreativeModeTab; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | import org.spongepowered.asm.mixin.gen.Invoker; 8 | 9 | @Mixin(CreativeModeInventoryScreen.class) 10 | public interface CreativeModeInventoryScreenAccessor { 11 | @Accessor 12 | static CreativeModeTab getSelectedTab() { 13 | throw new AssertionError(); 14 | } 15 | 16 | @Invoker 17 | void invokeSelectTab(CreativeModeTab tab); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/fabric/mixins/KeyBindingRegistryImplAccessor.java: -------------------------------------------------------------------------------- 1 | //? if fabric { 2 | package dev.isxander.controlify.platform.fabric.mixins; 3 | 4 | import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl; 5 | import net.minecraft.client.KeyMapping; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | import java.util.List; 10 | 11 | @SuppressWarnings("UnstableApiUsage") 12 | @Mixin(value = KeyBindingRegistryImpl.class, remap = false) 13 | public interface KeyBindingRegistryImplAccessor { 14 | @Accessor("MODDED_KEY_BINDINGS") 15 | static List getCustomKeys() { 16 | throw new AssertionError(); 17 | } 18 | } 19 | //?} 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/main/events/CommandRegistrationCallbackEvent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.main.events; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import net.minecraft.commands.CommandBuildContext; 5 | import net.minecraft.commands.CommandSourceStack; 6 | import net.minecraft.commands.Commands; 7 | 8 | @FunctionalInterface 9 | public interface CommandRegistrationCallbackEvent { 10 | void onRegister(CommandDispatcher dispatcher, CommandBuildContext ctx, Commands.CommandSelection env); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/main/events/HandshakeCompletionEvent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.main.events; 2 | 3 | import net.minecraft.server.network.ServerLoginPacketListenerImpl; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | @FunctionalInterface 7 | public interface HandshakeCompletionEvent { 8 | void onCompletion(@Nullable I packet, ServerLoginPacketListenerImpl handler); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/main/events/PlayerJoinedEvent.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.main.events; 2 | 3 | import net.minecraft.server.level.ServerPlayer; 4 | 5 | @FunctionalInterface 6 | public interface PlayerJoinedEvent { 7 | void onInit(ServerPlayer player); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/neoforge/VanillaKeyMappingHolder.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.neoforge; 2 | 3 | import net.minecraft.client.KeyMapping; 4 | 5 | public interface VanillaKeyMappingHolder { 6 | KeyMapping[] controlify$getVanillaKeys(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/neoforge/mixins/CreativeModeInventoryScreenAccessor.java: -------------------------------------------------------------------------------- 1 | //? if neoforge { 2 | /*package dev.isxander.controlify.platform.neoforge.mixins; 3 | 4 | import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen; 5 | import net.minecraft.world.item.CreativeModeTab; 6 | import net.neoforged.neoforge.client.gui.CreativeTabsScreenPage; 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 | @Mixin(CreativeModeInventoryScreen.class) 14 | public interface CreativeModeInventoryScreenAccessor { 15 | @Accessor 16 | static CreativeModeTab getSelectedTab() { 17 | throw new AssertionError(); 18 | } 19 | 20 | @Invoker 21 | void invokeSelectTab(CreativeModeTab tab); 22 | 23 | @Accessor 24 | List getPages(); 25 | } 26 | *///?} 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/network/C2SNetworkApi.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.network; 2 | 3 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 4 | import net.minecraft.resources.ResourceLocation; 5 | import net.minecraft.server.level.ServerPlayer; 6 | 7 | public interface C2SNetworkApi extends SidedNetworkApi { 8 | void sendPacket(ResourceLocation channel, T packet); 9 | 10 | CustomPacketPayload createPayload(ResourceLocation channel, T packet); 11 | 12 | void listenForPacket(ResourceLocation channel, PacketListener listener); 13 | 14 | @FunctionalInterface 15 | interface PacketListener { 16 | void listen(T packet, ServerPlayer sender); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/network/S2CNetworkApi.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.network; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | import net.minecraft.server.level.ServerPlayer; 5 | 6 | public interface S2CNetworkApi extends SidedNetworkApi { 7 | void sendPacket(ServerPlayer recipient, ResourceLocation channel, T packet); 8 | 9 | void listenForPacket(ResourceLocation channel, PacketListener listener); 10 | 11 | @FunctionalInterface 12 | interface PacketListener { 13 | void listen(T packet); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/network/SidedNetworkApi.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.network; 2 | 3 | import net.minecraft.network.FriendlyByteBuf; 4 | import net.minecraft.network.codec.StreamCodec; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public interface SidedNetworkApi { 8 | static C2SNetworkApi C2S() { 9 | //? if fabric 10 | return dev.isxander.controlify.platform.network.fabric.C2SNetworkApiFabric.INSTANCE; 11 | //? if neoforge 12 | /*return dev.isxander.controlify.platform.network.neoforge.C2SNetworkApiNeoforge.INSTANCE;*/ 13 | } 14 | 15 | static S2CNetworkApi S2C() { 16 | //? if fabric 17 | return dev.isxander.controlify.platform.network.fabric.S2CNetworkApiFabric.INSTANCE; 18 | //? if neoforge 19 | /*return dev.isxander.controlify.platform.network.neoforge.S2CNetworkApiNeoforge.INSTANCE;*/ 20 | } 21 | 22 | void registerPacket(ResourceLocation channel, StreamCodec handler); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/platform/network/neoforge/S2CNetworkApiNeoforge.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.platform.network.neoforge; 2 | 3 | import dev.isxander.controlify.platform.network.S2CNetworkApi; 4 | import net.minecraft.network.FriendlyByteBuf; 5 | import net.minecraft.network.codec.StreamCodec; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.minecraft.server.level.ServerPlayer; 8 | 9 | public class S2CNetworkApiNeoforge implements S2CNetworkApi { 10 | public static final S2CNetworkApiNeoforge INSTANCE = new S2CNetworkApiNeoforge(); 11 | 12 | @Override 13 | public void sendPacket(ServerPlayer recipient, ResourceLocation channel, T packet) { 14 | // TODO 15 | } 16 | 17 | @Override 18 | public void listenForPacket(ResourceLocation channel, PacketListener listener) { 19 | // TODO 20 | } 21 | 22 | @Override 23 | public void registerPacket(ResourceLocation channel, StreamCodec handler) { 24 | // TODO 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/rumble/RumbleCapable.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.rumble; 2 | 3 | public interface RumbleCapable { 4 | boolean setRumble(float strongMagnitude, float weakMagnitude); 5 | 6 | boolean supportsRumble(); 7 | 8 | RumbleState applyRumbleSourceStrength(RumbleState state, RumbleSource source); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/rumble/RumbleEffect.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.rumble; 2 | 3 | public interface RumbleEffect extends Comparable { 4 | void tick(); 5 | RumbleState currentState(); 6 | 7 | boolean isFinished(); 8 | 9 | int priority(); 10 | int age(); 11 | 12 | @Override 13 | default int compareTo(RumbleEffect o) { 14 | int priorityCompare = Integer.compare(o.priority(), this.priority()); 15 | if (priorityCompare != 0) return priorityCompare; 16 | return Integer.compare(this.age(), o.age()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/rumble/RumbleState.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.rumble; 2 | 3 | import com.mojang.serialization.Codec; 4 | 5 | public record RumbleState(float strong, float weak) { 6 | public static final Codec CODEC = Codec.INT 7 | .xmap(RumbleState::unpackFromInt, RumbleState::packToInt); 8 | 9 | public static final RumbleState NONE = new RumbleState(0.0F, 0.0F); 10 | 11 | public boolean isZero() { 12 | return strong == 0.0F && weak == 0.0F; 13 | } 14 | 15 | public RumbleState mul(float multiplier) { 16 | return new RumbleState(strong * multiplier, weak * multiplier); 17 | } 18 | 19 | public static RumbleState unpackFromInt(int packed) { 20 | float strong = (short)(packed >> 16) / 32767.0F; 21 | float weak = (short)packed / 32767.0F; 22 | return new RumbleState(strong, weak); 23 | } 24 | 25 | public static int packToInt(RumbleState state) { 26 | int high = (int)(state.strong() * 32767.0F); 27 | int low = (int)(state.weak() * 32767.0F); 28 | return (high << 16) | (low & 0xFFFF); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/rumble/TriggerRumbleState.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.rumble; 2 | 3 | public record TriggerRumbleState(float left, float right) { 4 | public static final TriggerRumbleState NONE = new TriggerRumbleState(0.0F, 0.0F); 5 | 6 | public boolean isZero() { 7 | return left == 0.0F && right == 0.0F; 8 | } 9 | 10 | public TriggerRumbleState mul(float multiplier) { 11 | return new TriggerRumbleState(left * multiplier, right * multiplier); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/rumble/effects/UseItemEffectHolder.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.rumble.effects; 2 | 3 | import dev.isxander.controlify.rumble.ContinuousRumbleEffect; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | public interface UseItemEffectHolder { 7 | @Nullable ContinuousRumbleEffect controlify$getUseItemEffect(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenkeyboard/ChatKeyboardDucky.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenkeyboard; 2 | 3 | import net.minecraft.client.gui.screens.ChatScreen; 4 | 5 | public interface ChatKeyboardDucky { 6 | float controlify$keyboardShiftAmount(); 7 | 8 | static float getKeyboardShiftAmount(ChatScreen screen) { 9 | return ((ChatKeyboardDucky) screen).controlify$keyboardShiftAmount(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenkeyboard/KeyPressConsumer.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenkeyboard; 2 | 3 | public interface KeyPressConsumer { 4 | void acceptKeyCode(int keycode, int scancode, int modifiers); 5 | 6 | void acceptChar(char codePoint, int modifiers); 7 | 8 | static KeyPressConsumer of(KeyCodeConsumer keyCodeConsumer, CharConsumer charConsumer) { 9 | return new KeyPressConsumer() { 10 | @Override 11 | public void acceptKeyCode(int keycode, int scancode, int modifiers) { 12 | keyCodeConsumer.accept(keycode, scancode, modifiers); 13 | } 14 | 15 | @Override 16 | public void acceptChar(char codePoint, int modifiers) { 17 | charConsumer.accept(codePoint, modifiers); 18 | } 19 | }; 20 | } 21 | 22 | interface KeyCodeConsumer { 23 | void accept(int keycode, int scancode, int modifiers); 24 | } 25 | 26 | interface CharConsumer { 27 | void accept(char codePoint, int modifiers); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/ComponentProcessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop; 2 | 3 | import dev.isxander.controlify.controller.ControllerEntity; 4 | 5 | public interface ComponentProcessor extends ComponentProcessorProvider { 6 | ComponentProcessor EMPTY = new ComponentProcessor(){}; 7 | 8 | default boolean overrideControllerNavigation(ScreenProcessor screen, ControllerEntity controller) { 9 | return false; 10 | } 11 | 12 | default boolean overrideControllerButtons(ScreenProcessor screen, ControllerEntity controller) { 13 | return false; 14 | } 15 | 16 | default void onFocusGained(ScreenProcessor screen, ControllerEntity controller) { 17 | } 18 | 19 | default boolean shouldKeepFocusOnKeyboardMode(ScreenProcessor screen) { 20 | return false; 21 | } 22 | 23 | @Override 24 | default ComponentProcessor componentProcessor() { 25 | return this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/ComponentProcessorProvider.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop; 2 | 3 | import net.minecraft.client.gui.components.events.GuiEventListener; 4 | 5 | public interface ComponentProcessorProvider { 6 | ComponentProcessor componentProcessor(); 7 | 8 | static ComponentProcessor provide(GuiEventListener component) { 9 | if (component instanceof ComponentProcessorProvider provider) 10 | return provider.componentProcessor(); 11 | 12 | return REGISTRY.get(component).orElse(ComponentProcessor.EMPTY); 13 | 14 | } 15 | 16 | Registry REGISTRY = new Registry<>(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/CustomFocus.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop; 2 | 3 | import net.minecraft.client.gui.components.events.GuiEventListener; 4 | 5 | public interface CustomFocus { 6 | GuiEventListener getCustomFocus(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/ScreenControllerEventListener.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop; 2 | 3 | import dev.isxander.controlify.controller.ControllerEntity; 4 | 5 | public interface ScreenControllerEventListener { 6 | default void onControllerInput(ControllerEntity controller) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/ScreenProcessorProvider.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop; 2 | 3 | import net.minecraft.client.gui.screens.Screen; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.function.Function; 7 | 8 | public interface ScreenProcessorProvider { 9 | ScreenProcessor screenProcessor(); 10 | 11 | static ScreenProcessor provide(@NotNull Screen screen) { 12 | return ((ScreenProcessorProvider) screen).screenProcessor(); 13 | } 14 | 15 | static void registerProvider(@NotNull Class screenClass, @NotNull ScreenProcessorFactory.Factory factory) { 16 | ScreenProcessorFactory.registerProvider(screenClass, factory); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/compat/vanilla/CreateWorldScreenProcessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop.compat.vanilla; 2 | 3 | import dev.isxander.controlify.bindings.ControlifyBindings; 4 | import dev.isxander.controlify.controller.ControllerEntity; 5 | import dev.isxander.controlify.screenop.ScreenProcessor; 6 | import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen; 7 | 8 | public class CreateWorldScreenProcessor extends ScreenProcessor { 9 | private final Runnable onCreateButton; 10 | 11 | public CreateWorldScreenProcessor(CreateWorldScreen screen, Runnable onCreateButton) { 12 | super(screen); 13 | this.onCreateButton = onCreateButton; 14 | } 15 | 16 | @Override 17 | protected void handleButtons(ControllerEntity controller) { 18 | if (ControlifyBindings.GUI_ABSTRACT_ACTION_1.on(controller).justPressed()) { 19 | this.onCreateButton.run(); 20 | playClackSound(); 21 | } 22 | 23 | super.handleButtons(controller); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/compat/vanilla/EditBoxComponentProcessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop.compat.vanilla; 2 | 3 | import dev.isxander.controlify.screenop.ComponentProcessor; 4 | import dev.isxander.controlify.screenop.ScreenProcessor; 5 | 6 | public class EditBoxComponentProcessor implements ComponentProcessor { 7 | @Override 8 | public boolean shouldKeepFocusOnKeyboardMode(ScreenProcessor screen) { 9 | return true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/compat/vanilla/ItemSlotControllerAction.java: -------------------------------------------------------------------------------- 1 | //? if >=1.21.2 { 2 | package dev.isxander.controlify.screenop.compat.vanilla; 3 | 4 | import dev.isxander.controlify.controller.ControllerEntity; 5 | import net.minecraft.client.gui.ItemSlotMouseAction; 6 | import net.minecraft.world.item.ItemStack; 7 | 8 | public interface ItemSlotControllerAction extends ItemSlotMouseAction { 9 | boolean controlify$onControllerInput( 10 | ItemStack stack, 11 | int hoveredSlotIndex, 12 | ControllerEntity controller 13 | ); 14 | } 15 | //?} 16 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/compat/vanilla/ServerSelectionListEntryComponentProcessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop.compat.vanilla; 2 | 3 | import dev.isxander.controlify.bindings.ControlifyBindings; 4 | import dev.isxander.controlify.controller.ControllerEntity; 5 | import dev.isxander.controlify.screenop.ScreenProcessor; 6 | import dev.isxander.controlify.screenop.ComponentProcessor; 7 | import dev.isxander.controlify.mixins.feature.screenop.vanilla.JoinMultiplayerScreenAccessor; 8 | 9 | public class ServerSelectionListEntryComponentProcessor implements ComponentProcessor { 10 | @Override 11 | public boolean overrideControllerButtons(ScreenProcessor screen, ControllerEntity controller) { 12 | if (ControlifyBindings.GUI_PRESS.on(controller).justPressed()) { 13 | screen.screen.setFocused(((JoinMultiplayerScreenAccessor) screen.screen).getSelectButton()); 14 | return true; 15 | } 16 | 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/screenop/compat/vanilla/WorldListEntryComponentProcessor.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.screenop.compat.vanilla; 2 | 3 | import dev.isxander.controlify.bindings.ControlifyBindings; 4 | import dev.isxander.controlify.controller.ControllerEntity; 5 | import dev.isxander.controlify.screenop.ScreenProcessor; 6 | import dev.isxander.controlify.screenop.ComponentProcessor; 7 | import dev.isxander.controlify.mixins.feature.screenop.vanilla.SelectWorldScreenAccessor; 8 | import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; 9 | 10 | public class WorldListEntryComponentProcessor implements ComponentProcessor { 11 | @Override 12 | public boolean overrideControllerButtons(ScreenProcessor screen, ControllerEntity controller) { 13 | if (ControlifyBindings.GUI_PRESS.on(controller).justPressed()) { 14 | var selectWorldScreen = (SelectWorldScreen) screen.screen; 15 | selectWorldScreen.setFocused(((SelectWorldScreenAccessor) selectWorldScreen).getSelectButton()); 16 | 17 | return true; 18 | } 19 | 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/server/ControlifyServerConfig.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.server; 2 | 3 | import dev.isxander.controlify.platform.main.PlatformMainUtil; 4 | import dev.isxander.controlify.utils.CUtil; 5 | import dev.isxander.yacl3.config.v2.api.ConfigClassHandler; 6 | import dev.isxander.yacl3.config.v2.api.SerialEntry; 7 | import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; 8 | 9 | public class ControlifyServerConfig { 10 | public static final ConfigClassHandler HANDLER = ConfigClassHandler.createBuilder(ControlifyServerConfig.class) 11 | .id(CUtil.rl("config")) 12 | .serializer(config -> GsonConfigSerializerBuilder.create(config) 13 | .setPath(PlatformMainUtil.getConfigDir().resolve("controlify.json")) 14 | .build()) 15 | .build(); 16 | 17 | @SerialEntry public boolean reachAroundPolicy = true; 18 | @SerialEntry public boolean noFlyDriftPolicy = true; 19 | @SerialEntry public boolean enforceKeyboardLikeMovement = false; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/server/ServerPolicy.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.server; 2 | 3 | public enum ServerPolicy { 4 | ALLOWED, 5 | DISALLOWED, 6 | UNSET; 7 | 8 | public boolean isAllowed() { 9 | return this != DISALLOWED; 10 | } 11 | 12 | public static ServerPolicy fromBoolean(boolean value) { 13 | return value ? ALLOWED : DISALLOWED; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/server/packets/ServerPolicyPacket.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.server.packets; 2 | 3 | import dev.isxander.controlify.utils.CUtil; 4 | import net.minecraft.network.FriendlyByteBuf; 5 | import net.minecraft.network.codec.StreamCodec; 6 | import net.minecraft.resources.ResourceLocation; 7 | 8 | public record ServerPolicyPacket(String id, boolean allowed) { 9 | public static final ResourceLocation CHANNEL = CUtil.rl("server_policy"); 10 | 11 | public static final StreamCodec CODEC = StreamCodec.of( 12 | (buf, packet) -> { 13 | buf.writeUtf(packet.id()); 14 | buf.writeBoolean(packet.allowed()); 15 | }, 16 | buf -> new ServerPolicyPacket( 17 | buf.readUtf(), 18 | buf.readBoolean() 19 | ) 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/sound/ControlifyClientSounds.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.sound; 2 | 3 | import dev.isxander.controlify.utils.CUtil; 4 | import net.minecraft.resources.ResourceLocation; 5 | import net.minecraft.sounds.SoundEvent; 6 | 7 | import java.util.function.Supplier; 8 | 9 | public final class ControlifyClientSounds { 10 | public static final Supplier SCREEN_FOCUS_CHANGE = register("controlify.ui.focus"); 11 | 12 | private static Supplier register(String id) { 13 | ResourceLocation location = CUtil.rl(id); 14 | 15 | // don't actually register the event, so it isn't synced with the server 16 | SoundEvent sound = SoundEvent.createVariableRangeEvent(location); 17 | return () -> sound; 18 | } 19 | 20 | public static void init() { 21 | // calling init now calls which is where the sounds are registered 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/DebugLog.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | import dev.isxander.controlify.debug.DebugProperties; 4 | 5 | public class DebugLog { 6 | public static void log(String message, Object... args) { 7 | if (DebugProperties.DEBUG_LOGGING) { 8 | CUtil.LOGGER.debugLog(message, args); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/DummyMixinTarget.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | /** 4 | * This class is used when you need stonecutter to comment out a mixin completely, 5 | * but the file must have a mixin class and the mixin has to have a valid target. 6 | */ 7 | public final class DummyMixinTarget { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/Easings.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | import net.minecraft.util.Mth; 4 | 5 | import java.util.function.UnaryOperator; 6 | 7 | public class Easings { 8 | public static double easeInSine(double t) { 9 | return 1 - Mth.cos((float) ((t * Math.PI) / 2)); 10 | } 11 | 12 | public static double easeInQuad(double t) { 13 | return t * t; 14 | } 15 | 16 | public static double easeOutQuad(double t) { 17 | return 1 - (1 - t) * (1 - t); 18 | } 19 | 20 | public static double easeOutExpo(double t) { 21 | return t == 1 ? 1 : 1 - (float) Math.pow(2, -10 * t); 22 | } 23 | 24 | public static UnaryOperator toFloat(UnaryOperator easing) { 25 | return f -> easing.apply(f.doubleValue()).floatValue(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/GsonCodecAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | import com.google.gson.*; 4 | import com.mojang.serialization.Codec; 5 | import com.mojang.serialization.JsonOps; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | /** 10 | * Allows codecs to be used as Json(De)Serializers for GSON usage. 11 | * @param codec codec to use 12 | * @param type to encode/decode 13 | */ 14 | public record GsonCodecAdapter(Codec codec) implements JsonSerializer, JsonDeserializer { 15 | @Override 16 | public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) { 17 | return codec.encodeStart(JsonOps.INSTANCE, src).getOrThrow(); 18 | } 19 | 20 | @Override 21 | public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 22 | return codec.parse(JsonOps.INSTANCE, json).getOrThrow(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/InitialScreenRegistryDuck.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.screens.Screen; 5 | 6 | import java.util.function.Function; 7 | 8 | public interface InitialScreenRegistryDuck { 9 | void controlify$registerInitialScreen(Function screenFactory); 10 | 11 | static void registerInitialScreen(Function screenFactory) { 12 | ((InitialScreenRegistryDuck) Minecraft.getInstance()).controlify$registerInitialScreen(screenFactory); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/MouseMinecraftCallNotifier.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | public interface MouseMinecraftCallNotifier { 4 | void imFromMinecraftSetScreen(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/MthExt.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | import net.minecraft.util.Mth; 4 | 5 | public final class MthExt { 6 | private MthExt() { 7 | } 8 | 9 | public static float remap(float value, float minIn, float maxIn, float minOut, float maxOut) { 10 | return Mth.lerp(Mth.inverseLerp(value, minIn, maxIn), minOut, maxOut); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/Platform.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | public enum Platform { 4 | UNKNOWN, 5 | MAC, 6 | LINUX, 7 | WINDOWS, 8 | ANDROID, 9 | IOS; 10 | 11 | private static final Platform currentPlatform; 12 | static { 13 | String osName = System.getProperty("os.name"); 14 | 15 | if (osName.startsWith("Linux")) { 16 | if ("dalvik".equalsIgnoreCase(System.getProperty("java.vm.name"))) { 17 | currentPlatform = ANDROID; 18 | } else { 19 | currentPlatform = LINUX; 20 | } 21 | } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) { 22 | currentPlatform = MAC; 23 | } else if (osName.startsWith("Windows")) { 24 | currentPlatform = WINDOWS; 25 | } else if (osName.startsWith("iOS")) { 26 | currentPlatform = IOS; 27 | } else { 28 | CUtil.LOGGER.log("Unable to determine platform: " + osName); 29 | currentPlatform = UNKNOWN; 30 | } 31 | } 32 | 33 | public static Platform current() { 34 | return currentPlatform; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/ToastUtils.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.components.toasts.SystemToast; 5 | import net.minecraft.network.chat.Component; 6 | 7 | public class ToastUtils { 8 | public static void sendToast(Component title, Component message, boolean longer) { 9 | SystemToast toast = SystemToast.multiline( 10 | Minecraft.getInstance(), 11 | longer ? SystemToast.SystemToastId.UNSECURE_SERVER_WARNING : SystemToast.SystemToastId.PERIODIC_NOTIFICATION, 12 | title, 13 | message 14 | ); 15 | //? if >=1.21.2 { 16 | Minecraft.getInstance().getToastManager().addToast(toast); 17 | //?} else { 18 | /*Minecraft.getInstance().getToasts().addToast(toast); 19 | *///?} 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/TrackingConsumer.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils; 2 | 3 | import java.util.Optional; 4 | import java.util.function.BiConsumer; 5 | import java.util.function.Consumer; 6 | 7 | public record TrackingConsumer(Consumer start, BiConsumer progressConsumer, Consumer> onComplete) { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/animation/impl/Animator.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils.animation.impl; 2 | 3 | import dev.isxander.controlify.utils.animation.api.Animatable; 4 | import it.unimi.dsi.fastutil.objects.ObjectArrayList; 5 | 6 | import java.util.List; 7 | 8 | public final class Animator { 9 | public static final Animator INSTANCE = new Animator(); 10 | 11 | private final List animatables; 12 | 13 | private Animator() { 14 | this.animatables = new ObjectArrayList<>(); 15 | } 16 | 17 | public void add(Animatable animatable) { 18 | animatables.add(animatable); 19 | } 20 | 21 | public void tick(float tickDelta) { 22 | animatables.removeIf(animatable -> { 23 | animatable.tick(tickDelta); 24 | return animatable.isDone(); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/log/ControlifySubLogger.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils.log; 2 | 3 | public interface ControlifySubLogger extends ControlifyLogger { 4 | String name(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/utils/log/LogLevel.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.utils.log; 2 | 3 | public enum LogLevel { 4 | INFO, 5 | WARN, 6 | ERROR, 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/dev/isxander/controlify/virtualmouse/VirtualMouseBehaviour.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.virtualmouse; 2 | 3 | public enum VirtualMouseBehaviour { 4 | DEFAULT, 5 | ENABLED, 6 | DISABLED, 7 | CURSOR_ONLY; 8 | 9 | public boolean hasCursor() { 10 | return this != DISABLED; 11 | } 12 | 13 | public boolean isDefaultOr(VirtualMouseBehaviour behaviour) { 14 | return this == DEFAULT || this == behaviour; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/accesstransformer.cfg: -------------------------------------------------------------------------------- 1 | public net.minecraft.client.gui.GuiGraphics$ScissorStack 2 | public net.minecraft.client.gui.GuiGraphics$ScissorStack peek()Lnet/minecraft/client/gui/navigation/ScreenRectangle; 3 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/controllers/default_bind/dualsense.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaults": { 3 | "voicechat:mute_microphone": { 4 | "button": "controlify:button/misc_1" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/controllers/default_bind/switch.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaults": { 3 | "controlify:take_screenshot": { 4 | "button": "controlify:button/misc_1" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/font/controller/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | { 4 | "type": "bitmap", 5 | "file": "controlify:font/controller/default.png", 6 | "ascent": 11, 7 | "height": 16, 8 | "chars": [ 9 | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007", 10 | "\u0008\u0009\u000A\u000B\u000C\u000D\u000E", 11 | "\u000F\u0010\u0011\u0012\u0013\u0014\u001B", 12 | "\u0015\u0016\u0017\u0018\u0019\u001A\u0000", 13 | "\u001C\u001D\u001E\u001F\u0000\u0000\u0000" 14 | ] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/font/controller/dualsense.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | { 4 | "type": "bitmap", 5 | "file": "controlify:font/controller/dualsense.png", 6 | "ascent": 11, 7 | "height": 16, 8 | "chars": [ 9 | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007", 10 | "\u0008\u0009\u000A\u000B\u000C\u000D\u000E", 11 | "\u000F\u0010\u0011\u0012\u0013\u0014\u001B", 12 | "\u0015\u0016\u0017\u0018\u0019\u001A\u0000" 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/font/controller/dualshock3.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | { 4 | "type": "bitmap", 5 | "file": "controlify:font/controller/dualshock3.png", 6 | "ascent": 11, 7 | "height": 16, 8 | "chars": [ 9 | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007", 10 | "\u0008\u0009\u000A\u000B\u000C\u000D\u000E", 11 | "\u000F\u0010\u0011\u0012\u0013\u0014\u0000", 12 | "\u0015\u0016\u0017\u0018\u0019\u0000\u0000" 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/font/controller/dualshock4.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | { 4 | "type": "bitmap", 5 | "file": "controlify:font/controller/dualshock4.png", 6 | "ascent": 11, 7 | "height": 16, 8 | "chars": [ 9 | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007", 10 | "\u0008\u0009\u000A\u000B\u000C\u000D\u000E", 11 | "\u000F\u0010\u0011\u0012\u0013\u0014\u0000", 12 | "\u0015\u0016\u0017\u0018\u0019\u001A\u0000" 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/font/controller/steam_deck.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | { 4 | "type": "bitmap", 5 | "file": "controlify:font/controller/steam_deck.png", 6 | "ascent": 11, 7 | "height": 16, 8 | "chars": [ 9 | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007", 10 | "\u0008\u0009\u000A\u000B\u000C\u000D\u000E", 11 | "\u000F\u0010\u0011\u0012\u0013\u0014\u0000", 12 | "\u0015\u0016\u0017\u0018\u0019\u001A\u001B", 13 | "\u001C\u001D\u001E\u001F\u0000\u0000\u0000" 14 | ] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/font/controller/switch.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | { 4 | "type": "bitmap", 5 | "file": "controlify:font/controller/switch.png", 6 | "ascent": 11, 7 | "height": 16, 8 | "chars": [ 9 | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007", 10 | "\u0008\u0009\u000A\u000B\u000C\u000D\u000E", 11 | "\u000F\u0010\u0011\u0012\u0013\u0014\u001B", 12 | "\u0015\u0016\u0017\u0018\u0019\u0000\u0000" 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/font/controller/xbox_one.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | { 4 | "type": "bitmap", 5 | "file": "controlify:font/controller/xbox_one.png", 6 | "ascent": 11, 7 | "height": 16, 8 | "chars": [ 9 | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007", 10 | "\u0008\u0009\u000A\u000B\u000C\u000D\u000E", 11 | "\u000F\u0010\u0011\u0012\u0013\u0014\u0015", 12 | "\u0016\u0017\u0018\u0019\u001A\u0000\u0000" 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/haptics/navigate.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/haptics/navigate.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/sounds.json: -------------------------------------------------------------------------------- 1 | { 2 | "controlify.ui.focus": { 3 | "sounds": [ 4 | "controlify:ui_focus" 5 | ] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/sounds/ui_focus.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/sounds/ui_focus.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/font/controller/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/font/controller/default.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/font/controller/dualsense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/font/controller/dualsense.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/font/controller/dualshock3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/font/controller/dualshock3.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/font/controller/dualshock4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/font/controller/dualshock4.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/font/controller/steam_deck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/font/controller/steam_deck.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/font/controller/switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/font/controller/switch.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/font/controller/xbox_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/font/controller/xbox_one.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/dpad_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/dpad_down.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/dpad_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/dpad_left.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/dpad_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/dpad_right.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/dpad_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/dpad_up.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/face_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/face_down.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/face_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/face_left.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/face_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/face_right.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/face_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/face_up.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/faceview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/faceview.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_bumper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_bumper.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_special.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_special.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_down.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_left.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_press.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_right.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_stick_up.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/left_trigger.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_bumper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_bumper.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_special.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_special.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_down.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_left.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_press.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_right.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_stick_up.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/right_trigger.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/triggerview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/triggerview.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/controllerdiagram/triggerview.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/controllerdiagram/triggerview.psd -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/joystick/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/joystick/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/radial-buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/radial-buttons.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/default.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/default_alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/default_alt.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/dualsense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/dualsense.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/dualshock3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/dualshock3.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/dualshock4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/dualshock4.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/psp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/psp.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/steam_deck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/steam_deck.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/switch.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/controllers/xbox_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/controllers/xbox_one.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/keyboard/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/sprites/keyboard/key.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/sprites/keyboard/key.png.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "gui": { 3 | "scaling": { 4 | "type": "nine_slice", 5 | "width": 30, 6 | "height": 24, 7 | "border": { 8 | "left": 1, 9 | "right": 1, 10 | "top": 3, 11 | "bottom": 3 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/virtual_mouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/virtual_mouse.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/gui/xbox-controller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/gui/xbox-controller.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/screenshots/ingame-button-guide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/screenshots/ingame-button-guide.png -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/screenshots/reach-around-placement.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/screenshots/reach-around-placement.webp -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/screenshots/reduce-aim-sensitivity.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/screenshots/reduce-aim-sensitivity.webp -------------------------------------------------------------------------------- /src/main/resources/assets/controlify/textures/screenshots/screen-button-guide.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/assets/controlify/textures/screenshots/screen-button-guide.webp -------------------------------------------------------------------------------- /src/main/resources/controlify-compat.iris.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "dev.isxander.controlify.compatibility.iris.mixins", 3 | "required": false, 4 | "minVersion": "0.8", 5 | "minMixinExtrasVersion": "0.5.0-beta.1", 6 | "injectors": { 7 | "defaultRequire": 1 8 | }, 9 | "plugin": "dev.isxander.controlify.compatibility.iris.IrisMixinPlugin", 10 | "compatibilityLevel": "JAVA_17", 11 | "client": [ 12 | ], 13 | "mixins": [ 14 | "BaseOptionElementWidgetMixin" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/controlify-compat.reeses-sodium-options.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "dev.isxander.controlify.compatibility.rso.mixins", 3 | "required": false, 4 | "minVersion": "0.8", 5 | "minMixinExtrasVersion": "0.5.0-beta.1", 6 | "injectors": { 7 | "defaultRequire": 1 8 | }, 9 | "plugin": "dev.isxander.controlify.compatibility.rso.RSOMixinPlugin", 10 | "compatibilityLevel": "JAVA_17", 11 | "client": [ 12 | "SodiumVideoOptionsScreenMixin" 13 | ], 14 | "mixins": [ 15 | "AbstractFrameAccessor", 16 | "TabFrameAccessor" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/controlify-compat.simple-voice-chat.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "dev.isxander.controlify.compatibility.simplevoicechat.mixins", 3 | "required": false, 4 | "minVersion": "0.8", 5 | "minMixinExtrasVersion": "0.5.0-beta.1", 6 | "injectors": { 7 | "defaultRequire": 1 8 | }, 9 | "plugin": "dev.isxander.controlify.compatibility.simplevoicechat.SVCMixinPlugin", 10 | "compatibilityLevel": "JAVA_17", 11 | "client": [ 12 | ], 13 | "mixins": [ 14 | "KeyEventsAccessor", 15 | "PTTKeyHandlerMixin" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/controlify-compat.sodium.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "dev.isxander.controlify.compatibility.sodium.mixins", 3 | "required": false, 4 | "minVersion": "0.8", 5 | "minMixinExtrasVersion": "0.5.0-beta.1", 6 | "injectors": { 7 | "defaultRequire": 1 8 | }, 9 | "plugin": "dev.isxander.controlify.compatibility.sodium.SodiumMixinPlugin", 10 | "compatibilityLevel": "JAVA_17", 11 | "client": [ 12 | "SodiumOptionsGUIMixin" 13 | ], 14 | "mixins": [ 15 | "AbstractWidgetMixin", 16 | "CycleControlElementMixin", 17 | "FlatButtonWidgetAccessor", 18 | "FlatButtonWidgetMixin", 19 | "SliderControlElementMixin", 20 | "TickBoxControlElementMixin" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/controlify-compat.yacl.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "dev.isxander.controlify.compatibility.yacl.mixins", 3 | "required": true, 4 | "minVersion": "0.8", 5 | "minMixinExtrasVersion": "0.5.0-beta.1", 6 | "injectors": { 7 | "defaultRequire": 1 8 | }, 9 | "plugin": "dev.isxander.controlify.compatibility.yacl.YACLMixinPlugin", 10 | "compatibilityLevel": "JAVA_17", 11 | "client": [ 12 | "CyclingControllerElementMixin", 13 | "SliderControllerElementMixin", 14 | "YACLScreenCategoryTabAccessor", 15 | "YACLScreenCategoryTabMixin", 16 | "YACLScreenMixin" 17 | ], 18 | "mixins": [ 19 | "ControllerWidgetAccessor" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/controlify-platform.fabric.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "dev.isxander.controlify.platform.fabric.mixins", 3 | "required": true, 4 | "minVersion": "0.8", 5 | "minMixinExtrasVersion": "0.5.0-beta.1", 6 | "injectors": { 7 | "defaultRequire": 1 8 | }, 9 | "compatibilityLevel": "JAVA_17", 10 | "client": [ 11 | "CreativeModeInventoryScreenAccessor", 12 | "KeyBindingRegistryImplAccessor" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/controlify-platform.neoforge.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "dev.isxander.controlify.platform.neoforge.mixins", 3 | "required": true, 4 | "minVersion": "0.8", 5 | "minMixinExtrasVersion": "0.5.0-beta.1", 6 | "injectors": { 7 | "defaultRequire": 1 8 | }, 9 | "compatibilityLevel": "JAVA_17", 10 | "client": [ 11 | "CreativeModeInventoryScreenAccessor", 12 | "OptionsMixin" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/controlify.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v2 named 2 | 3 | #? if >=1.21.6 { 4 | accessible class net/minecraft/client/gui/GuiGraphics$ScissorStack 5 | accessible method net/minecraft/client/gui/GuiGraphics$ScissorStack peek ()Lnet/minecraft/client/gui/navigation/ScreenRectangle; 6 | #? } 7 | -------------------------------------------------------------------------------- /src/main/resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/icon.png -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/assets/controlify/controllers/default_bind/dualsense.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaults": { 3 | "controlify:show_player_list": { 4 | "button": "controlify:button/touchpad" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/assets/controlify/controllers/default_bind/dualshock4.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaults": { 3 | "controlify:show_player_list": { 4 | "button": "controlify:button/touchpad" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/dualsense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/dualsense.png -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/dualshock3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/dualshock3.png -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/dualshock4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/dualshock4.png -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/xbox_360.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/xbox_360.png -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/xbox_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/font/controller/xbox_one.png -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/gui/sprites/controllers/dualshock3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/resourcepacks/legacy_console/assets/controlify/textures/gui/sprites/controllers/dualshock3.png -------------------------------------------------------------------------------- /src/main/resources/resourcepacks/legacy_console/pack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isXander/Controlify/b34869b381584f4e51392573b9b9dafd60267e26/src/main/resources/resourcepacks/legacy_console/pack.png -------------------------------------------------------------------------------- /src/main/templates/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "[1,)" 3 | #issueTrackerURL = "" 4 | license = "${mod_license}" 5 | 6 | [[mods]] 7 | modId = "${mod_id}" 8 | version = "${mod_version}" 9 | displayName = "${mod_name}" 10 | authors = "${mod_author}" 11 | description = ''' 12 | ${mod_description} 13 | ''' 14 | logoFile = "icon.png" 15 | 16 | [[dependencies."${mod_id}"]] 17 | modId = "minecraft" 18 | mandatory = true 19 | versionRange = "${mc}" 20 | ordering = "NONE" 21 | side = "BOTH" 22 | 23 | [[dependencies."${mod_id}"]] 24 | modId = "yet_another_config_lib_v3" 25 | mandatory = true 26 | ordering = "NONE" 27 | side = "BOTH" 28 | -------------------------------------------------------------------------------- /src/main/templates/resourcepacks/legacy_console/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": { "translate": "controlify.extra_pack.legacy_console.desc" }, 4 | "pack_format": ${pack_format} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/testharness/java/dev/isxander/controlify/testharness/TestHarness.java: -------------------------------------------------------------------------------- 1 | package dev.isxander.controlify.testharness; 2 | 3 | public class TestHarness { 4 | } 5 | -------------------------------------------------------------------------------- /versions/1.21.1-fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=loom 2 | 3 | mcVersion=1.21.1 4 | packFormat=34 5 | 6 | parchment.version=2024.11.17 7 | 8 | deps.fabricApi=0.104.0+1.21.1 9 | deps.yacl=3.7.0+1.21.1-fabric 10 | deps.modMenu=11.0.2 11 | deps.sodium=mc1.21.1-0.6.5-fabric 12 | deps.iris=1.8.1+1.21.1-fabric 13 | deps.immediatelyFast=1.2.21+1.21.1-fabric 14 | deps.simpleVoiceChat=fabric-1.21.1-2.5.22 15 | deps.reesesSodiumOptions=mc1.21.3-1.8.0+fabric 16 | deps.fancyMenu=3.2.5-1.21-fabric 17 | 18 | meta.mcDep=~1.21 <1.21.2 19 | meta.fapiDep=>=0.100.0 20 | 21 | pub.stableMC=1.21,1.21.1 22 | -------------------------------------------------------------------------------- /versions/1.21.1-neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=moddevgradle 2 | 3 | mcVersion=1.21.1 4 | packFormat=34 5 | 6 | parchment.version=2024.11.17 7 | 8 | deps.neoForge=21.1.97 9 | deps.yacl=3.7.0+1.21.1-neoforge 10 | deps.sodium=mc1.21.1-0.6.5-neoforge 11 | deps.iris=1.8.1+1.21.1-neoforge 12 | deps.reesesSodiumOptions=mc1.21.3-1.8.0+neoforge 13 | deps.immediatelyFast=1.2.21+1.21.1-neoforge 14 | deps.simpleVoiceChat=neoforge-1.21.1-2.5.22 15 | deps.fancyMenu=3.2.6-1.21.1-neoforge 16 | 17 | meta.mcDep=[1.21,1.21.1] 18 | meta.loaderDep=[21,) 19 | 20 | pub.stableMC=1.21,1.21.1 21 | -------------------------------------------------------------------------------- /versions/1.21.3-fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=loom 2 | 3 | mcVersion=1.21.3 4 | packFormat=42 5 | 6 | parchment.version=2024.12.07 7 | 8 | deps.fabricApi=0.106.1+1.21.3 9 | deps.yacl=3.7.0+1.21.3-fabric 10 | deps.modMenu=12.0.0 11 | deps.sodium=mc1.21.3-0.6.5-fabric 12 | deps.iris=1.8.1+1.21.3-fabric 13 | deps.immediatelyFast=1.3.3+1.21.3-fabric 14 | deps.simpleVoiceChat=fabric-1.21.3-2.5.27 15 | deps.reesesSodiumOptions=mc1.21.3-1.8.0+fabric 16 | deps.fancyMenu=3.2.5-1.21-fabric 17 | deps.fancyMenu.noRuntime=true 18 | 19 | meta.mcDep=>=1.21.2 <1.21.4 20 | meta.fapiDep=>=0.106.1 21 | 22 | pub.stableMC=1.21.2,1.21.3 23 | -------------------------------------------------------------------------------- /versions/1.21.3-neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=moddevgradle 2 | 3 | mcVersion=1.21.3 4 | packFormat=42 5 | 6 | parchment.version=2024.12.07 7 | 8 | deps.neoForge=21.3.58 9 | deps.yacl=3.7.0+1.21.3-neoforge 10 | deps.sodium=mc1.21.3-0.6.5-neoforge 11 | deps.iris=1.8.1+1.21.3-neoforge 12 | deps.reesesSodiumOptions=mc1.21.3-1.8.0+neoforge 13 | deps.immediatelyFast=1.3.4+1.21.3-neoforge 14 | deps.simpleVoiceChat=neoforge-1.21.3-2.5.27 15 | deps.fancyMenu=3.2.6-1.21.1-neoforge 16 | deps.fancyMenu.noRuntime=true 17 | 18 | meta.mcDep=[1.21.2,1.21.3] 19 | meta.loaderDep=[21,) 20 | 21 | pub.stableMC=1.21.2,1.21.3 22 | -------------------------------------------------------------------------------- /versions/1.21.4-fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=loom 2 | 3 | mcVersion=1.21.4 4 | packFormat=46 5 | 6 | parchment.version=2024.12.29 7 | 8 | deps.fabricApi=0.111.0+1.21.4 9 | deps.yacl=3.7.0+1.21.4-fabric 10 | deps.modMenu=13.0.0-beta.1 11 | deps.sodium=mc1.21.4-0.6.6-fabric 12 | deps.iris=1.8.5+1.21.4-fabric 13 | deps.immediatelyFast=1.3.3+1.21.4-fabric 14 | deps.simpleVoiceChat=fabric-1.21.4-2.5.26 15 | deps.reesesSodiumOptions=mc1.21.4-1.8.3+fabric 16 | deps.fancyMenu=3.2.5-1.21-fabric 17 | deps.fancyMenu.noRuntime=true 18 | 19 | meta.mcDep=~1.21.4 20 | meta.fapiDep=>=0.111.0 21 | 22 | pub.stableMC=1.21.4 23 | -------------------------------------------------------------------------------- /versions/1.21.4-neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=moddevgradle 2 | 3 | mcVersion=1.21.4 4 | packFormat=46 5 | 6 | parchment.version=2024.12.29 7 | 8 | deps.neoForge=21.4.84-beta 9 | deps.yacl=3.7.0+1.21.4-neoforge 10 | deps.sodium=mc1.21.4-0.6.6-neoforge 11 | deps.iris=1.8.5+1.21.4-neoforge 12 | deps.reesesSodiumOptions=mc1.21.4-1.8.2+neoforge 13 | deps.immediatelyFast=1.3.3+1.21.4-neoforge 14 | deps.simpleVoiceChat=neoforge-1.21.4-2.5.27 15 | deps.fancyMenu=3.2.6-1.21.1-neoforge 16 | deps.fancyMenu.noRuntime=true 17 | 18 | meta.mcDep=[1.21.4,1.21.5) 19 | meta.loaderDep=[21,) 20 | 21 | pub.stableMC=1.21.4 22 | -------------------------------------------------------------------------------- /versions/1.21.5-fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=loom 2 | 3 | mcVersion=1.21.5 4 | packFormat=55 5 | 6 | parchment.version=2024.12.29 7 | # parchment doesn't offer snapshot versions 8 | parchment.minecraft=1.21.4 9 | 10 | deps.fabricApi=0.119.4+1.21.5 11 | deps.yacl=3.7.0+1.21.5-fabric 12 | deps.modMenu=14.0.0-rc.2 13 | deps.sodium=mc1.21.5-0.6.11-fabric 14 | deps.sodium.noRuntime=true 15 | deps.iris=1.8.9+1.21.5-fabric 16 | deps.iris.noRuntime=true 17 | deps.immediatelyFast=1.3.3+1.21.4-fabric 18 | deps.immediatelyFast.noRuntime=true 19 | deps.simpleVoiceChat=fabric-1.21.4-2.5.26 20 | deps.simpleVoiceChat.noRuntime=true 21 | deps.reesesSodiumOptions=mc1.21.4-1.8.2+fabric 22 | deps.reesesSodiumOptions.noRuntime=true 23 | deps.fancyMenu=3.2.5-1.21-fabric 24 | deps.fancyMenu.noRuntime=true 25 | 26 | meta.mcDep=1.21.5 27 | meta.fapiDep=>=0.119.2 28 | 29 | pub.stableMC=1.21.5 30 | -------------------------------------------------------------------------------- /versions/1.21.5-neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=moddevgradle 2 | 3 | mcVersion=1.21.5 4 | packFormat=55 5 | 6 | parchment.version=2024.12.29 7 | parchment.minecraft=1.21.4 8 | 9 | deps.neoForge=21.5.0-beta 10 | deps.yacl=3.7.0+1.21.5-neoforge 11 | deps.sodium=mc1.21.4-0.6.6-neoforge 12 | deps.sodium.noRuntime=true 13 | deps.iris=1.8.5+1.21.4-neoforge 14 | deps.iris.noRuntime=true 15 | deps.reesesSodiumOptions=mc1.21.4-1.8.2+neoforge 16 | deps.reesesSodiumOptions.noRuntime=true 17 | deps.immediatelyFast=1.3.3+1.21.4-neoforge 18 | deps.immediatelyFast.noRuntime=true 19 | deps.simpleVoiceChat=neoforge-1.21.4-2.5.27 20 | deps.simpleVoiceChat.noRuntime=true 21 | deps.fancyMenu=3.2.6-1.21.1-neoforge 22 | deps.fancyMenu.noRuntime=true 23 | 24 | meta.mcDep=[1.21.5,1.22) 25 | meta.loaderDep=[21,) 26 | 27 | pub.stableMC=1.21.5 28 | -------------------------------------------------------------------------------- /versions/1.21.6-fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | modstitch.platform=loom 2 | 3 | mcVersion=25w21a 4 | packFormat=62 5 | 6 | parchment.version=2025.04.19 7 | # parchment doesn't offer snapshot versions 8 | parchment.minecraft=1.21.5 9 | 10 | deps.fabricApi=0.124.4+1.21.6 11 | deps.yacl=3.7.0+1.21.6-fabric 12 | deps.modMenu=14.0.0-rc.2 13 | deps.modMenu.noRuntime=true 14 | deps.sodium=mc1.21.5-0.6.11-fabric 15 | deps.sodium.noRuntime=true 16 | deps.iris=1.8.9+1.21.5-fabric 17 | deps.iris.noRuntime=true 18 | deps.immediatelyFast=1.3.3+1.21.4-fabric 19 | deps.immediatelyFast.noRuntime=true 20 | deps.simpleVoiceChat=fabric-1.21.4-2.5.26 21 | deps.simpleVoiceChat.noRuntime=true 22 | deps.reesesSodiumOptions=mc1.21.4-1.8.2+fabric 23 | deps.reesesSodiumOptions.noRuntime=true 24 | deps.fancyMenu=3.2.5-1.21-fabric 25 | deps.fancyMenu.noRuntime=true 26 | 27 | meta.mcDep=~1.21.6- 28 | meta.fapiDep=>=0.124.4 29 | 30 | pub.modrinthMC=25w21a 31 | pub.curseMC=1.21.6-Snapshot 32 | -------------------------------------------------------------------------------- /versions/current: -------------------------------------------------------------------------------- 1 | 1.21.5-fabric -------------------------------------------------------------------------------- /versions/versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://codeberg.org/stonecutter/stonecutter/raw/branch/0.7/tools/settings-schema.json", 3 | "vcs": "1.21.5-fabric", 4 | "branches": { 5 | "": [ 6 | "1.21.6-fabric:1.21.6", 7 | "1.21.5-fabric:1.21.5", "1.21.5-neoforge:1.21.5", 8 | "1.21.4-fabric:1.21.4", "1.21.4-neoforge:1.21.4", 9 | "1.21.3-fabric:1.21.3", "1.21.3-neoforge:1.21.3", 10 | "1.21.1-fabric:1.21.1", "1.21.1-neoforge:1.21.1" 11 | ] 12 | } 13 | } 14 | --------------------------------------------------------------------------------