diff --git a/build.gradle.kts b/build.gradle.kts index a09fe27..5626adf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -118,6 +118,9 @@ dependencies { modImplementation(libs.immediately.fast) modRuntimeOnly("net.lenni0451:Reflect:1.1.0") + // simple-voice-chat compat + modImplementation(libs.simple.voice.chat) + // testmod "testmodImplementation"(sourceSets.main.get().output) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c6db844..3cd6a1c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,7 @@ quilt_json5 = "1.0.3" sodium = "mc1.20.1-0.5.0" iris = "1.6.5+1.20.1" immediately_fast = "1.1.25+1.20.1" +simple_voice_chat = "fabric-1.20.1-2.4.18" sdl2_jni = "2.28.2-26" [libraries] @@ -33,6 +34,7 @@ quilt_json5 = { module = "org.quiltmc:quilt-json5", version.ref = "quilt_json5" sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" } iris = { module = "maven.modrinth:iris", version.ref = "iris" } immediately_fast = { module = "maven.modrinth:immediatelyfast", version.ref = "immediately_fast" } +simple_voice_chat = { module = "maven.modrinth:simple-voice-chat", version.ref = "simple_voice_chat" } sdl2_jni = { module = "dev.isxander:sdl2-jni", version.ref = "sdl2_jni" } test_fabric_loader = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric_loader" } diff --git a/src/main/java/dev/isxander/controlify/Controlify.java b/src/main/java/dev/isxander/controlify/Controlify.java index 6ee04fa..2e7bc6e 100644 --- a/src/main/java/dev/isxander/controlify/Controlify.java +++ b/src/main/java/dev/isxander/controlify/Controlify.java @@ -3,6 +3,7 @@ package dev.isxander.controlify; import com.mojang.blaze3d.Blaze3D; import dev.isxander.controlify.api.ControlifyApi; import dev.isxander.controlify.api.entrypoint.ControlifyEntrypoint; +import dev.isxander.controlify.compatibility.ControlifyCompat; import dev.isxander.controlify.gui.controllers.ControllerBindHandler; import dev.isxander.controlify.gui.screen.ControllerCarouselScreen; import dev.isxander.controlify.controller.Controller; @@ -264,6 +265,7 @@ public class Controlify implements ControlifyApi { ReachAroundHandler.reachAroundPolicy = ReachAroundPolicy.UNSET; }); + ControlifyCompat.init(); FabricLoader.getInstance().getEntrypoints("controlify", ControlifyEntrypoint.class).forEach(entrypoint -> { try { entrypoint.onControlifyPreInit(this); diff --git a/src/main/java/dev/isxander/controlify/compatibility/ControlifyCompat.java b/src/main/java/dev/isxander/controlify/compatibility/ControlifyCompat.java index 4bcd1d2..81af84b 100644 --- a/src/main/java/dev/isxander/controlify/compatibility/ControlifyCompat.java +++ b/src/main/java/dev/isxander/controlify/compatibility/ControlifyCompat.java @@ -1,24 +1,39 @@ package dev.isxander.controlify.compatibility; import dev.isxander.controlify.compatibility.immediatelyfast.ImmediatelyFastCompat; +import dev.isxander.controlify.compatibility.simplevoicechat.SimpleVoiceChatCompat; +import dev.isxander.controlify.utils.Log; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.Util; + +import java.util.function.Function; public class ControlifyCompat { - public static final boolean IMMEDIATELY_FAST = mod("immediatelyfast"); + private static final Function modsLoaded = Util.memoize(modid -> + FabricLoader.getInstance().isModLoaded(modid)); + + public static final String IMMEDIATELY_FAST = "immediatelyfast"; + public static final String SIMPLE_VOICE_CHAT = "voicechat"; + + public static void init() { + wrapCompatCall(SIMPLE_VOICE_CHAT, SimpleVoiceChatCompat::init); + } public static void ifBeginHudBatching() { - if (IMMEDIATELY_FAST) { - ImmediatelyFastCompat.beginHudBatching(); - } + wrapCompatCall(IMMEDIATELY_FAST, ImmediatelyFastCompat::beginHudBatching); } public static void ifEndHudBatching() { - if (IMMEDIATELY_FAST) { - ImmediatelyFastCompat.endHudBatching(); - } + wrapCompatCall(IMMEDIATELY_FAST, ImmediatelyFastCompat::endHudBatching); } - private static boolean mod(String id) { - return FabricLoader.getInstance().isModLoaded(id); + private static void wrapCompatCall(String modid, Runnable runnable) { + if (modsLoaded.apply(modid)) { + try { + runnable.run(); + } catch (Throwable t) { + Log.LOGGER.error("Failed to run compatibility code for %s, potentially unsupported version?".formatted(modid), t); + } + } } } diff --git a/src/main/java/dev/isxander/controlify/compatibility/simplevoicechat/SimpleVoiceChatCompat.java b/src/main/java/dev/isxander/controlify/compatibility/simplevoicechat/SimpleVoiceChatCompat.java new file mode 100644 index 0000000..ff201da --- /dev/null +++ b/src/main/java/dev/isxander/controlify/compatibility/simplevoicechat/SimpleVoiceChatCompat.java @@ -0,0 +1,84 @@ +package dev.isxander.controlify.compatibility.simplevoicechat; + +import de.maxhenkel.voicechat.voice.client.ClientManager; +import de.maxhenkel.voicechat.voice.client.KeyEvents; +import dev.isxander.controlify.api.bind.BindingSupplier; +import dev.isxander.controlify.api.bind.ControlifyBindingsApi; +import dev.isxander.controlify.api.event.ControlifyEvents; +import dev.isxander.controlify.bindings.EmptyBind; +import dev.isxander.controlify.mixins.compat.simplevoicechat.KeyEventsAccessor; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public class SimpleVoiceChatCompat { + private static BindingSupplier pttHoldSupplier, pttToggleSupplier; + private static BindingSupplier whisperHoldSupplier, whisperToggleSupplier; + + private static boolean pttDown, whisperDown; + + public static void init() { + ControlifyBindingsApi.get().excludeVanillaBind(KeyEvents.KEY_PTT); + ControlifyBindingsApi.get().excludeVanillaBind(KeyEvents.KEY_WHISPER); + + Component category = Component.translatable("key.categories.voicechat"); + pttHoldSupplier = ControlifyBindingsApi.get().registerBind(new ResourceLocation("voicechat", "ptt_hold"), builder -> builder + .name(Component.translatable("key.push_to_talk").append(CommonComponents.SPACE).append(Component.translatable("controlify.compat.svc.hold"))) + .category(category) + .defaultBind(new EmptyBind<>())); + pttToggleSupplier = ControlifyBindingsApi.get().registerBind(new ResourceLocation("voicechat", "ptt_toggle"), builder -> builder + .name(Component.translatable("key.push_to_talk").append(CommonComponents.SPACE).append(Component.translatable("controlify.compat.svc.toggle"))) + .category(category) + .defaultBind(new EmptyBind<>())); + whisperHoldSupplier = ControlifyBindingsApi.get().registerBind(new ResourceLocation("voicechat", "whisper_hold"), builder -> builder + .name(Component.translatable("key.whisper").append(CommonComponents.SPACE).append(Component.translatable("controlify.compat.svc.hold"))) + .category(category) + .defaultBind(new EmptyBind<>())); + whisperToggleSupplier = ControlifyBindingsApi.get().registerBind(new ResourceLocation("voicechat", "whisper_toggle"), builder -> builder + .name(Component.translatable("key.whisper").append(CommonComponents.SPACE).append(Component.translatable("controlify.compat.svc.toggle"))) + .category(category) + .defaultBind(new EmptyBind<>())); + + ControlifyEvents.ACTIVE_CONTROLLER_TICKED.register(controller -> { + var pttHold = pttHoldSupplier.onController(controller); + var pttToggle = pttToggleSupplier.onController(controller); + var whisperHold = whisperHoldSupplier.onController(controller); + var whisperToggle = whisperToggleSupplier.onController(controller); + + if (pttToggle.justPressed()) { + pttDown = !pttDown; + checkConnected(); + } + if (whisperToggle.justPressed()) { + whisperDown = !whisperDown; + checkConnected(); + } + + if (pttHold.justPressed() || whisperHold.justPressed()) { + checkConnected(); + } + if (pttHold.held()) { + pttDown = true; + } else if (pttHold.justReleased()) { + pttDown = false; + } + if (whisperHold.held()) { + whisperDown = true; + } else if (whisperHold.justReleased()) { + whisperDown = false; + } + }); + } + + public static boolean isPTTDown() { + return pttDown; + } + + public static boolean isWhisperDown() { + return whisperDown; + } + + private static void checkConnected() { + ((KeyEventsAccessor) ClientManager.instance().getKeyEvents()).invokeCheckConnected(); + } +} diff --git a/src/main/java/dev/isxander/controlify/compatibility/yacl/YACLScreenProcessor.java b/src/main/java/dev/isxander/controlify/compatibility/yacl/YACLScreenProcessor.java index a3e1288..1c6c552 100644 --- a/src/main/java/dev/isxander/controlify/compatibility/yacl/YACLScreenProcessor.java +++ b/src/main/java/dev/isxander/controlify/compatibility/yacl/YACLScreenProcessor.java @@ -21,14 +21,4 @@ public class YACLScreenProcessor extends ScreenProcessor { super.handleButtons(controller); } - - @Override - public void onWidgetRebuild() { - //ButtonGuideApi.addGuideToButton(screen.finishedSaveButton, bindings -> bindings.GUI_ABSTRACT_ACTION_1, ButtonRenderPosition.TEXT, ButtonGuidePredicate.ALWAYS); - } - - @Override - protected void setInitialFocus() { -// screen.setFocused(screen.optionList); - } } diff --git a/src/main/java/dev/isxander/controlify/mixins/compat/simplevoicechat/KeyEventsAccessor.java b/src/main/java/dev/isxander/controlify/mixins/compat/simplevoicechat/KeyEventsAccessor.java new file mode 100644 index 0000000..f67dc50 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/compat/simplevoicechat/KeyEventsAccessor.java @@ -0,0 +1,13 @@ +package dev.isxander.controlify.mixins.compat.simplevoicechat; + +import de.maxhenkel.voicechat.voice.client.KeyEvents; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Pseudo +@Mixin(value = KeyEvents.class, remap = false) +public interface KeyEventsAccessor { + @Invoker + boolean invokeCheckConnected(); +} diff --git a/src/main/java/dev/isxander/controlify/mixins/compat/simplevoicechat/PTTKeyHandlerMixin.java b/src/main/java/dev/isxander/controlify/mixins/compat/simplevoicechat/PTTKeyHandlerMixin.java new file mode 100644 index 0000000..3877f22 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/compat/simplevoicechat/PTTKeyHandlerMixin.java @@ -0,0 +1,43 @@ +package dev.isxander.controlify.mixins.compat.simplevoicechat; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import de.maxhenkel.voicechat.voice.client.PTTKeyHandler; +import dev.isxander.controlify.compatibility.simplevoicechat.SimpleVoiceChatCompat; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; + +@Pseudo +@Mixin(value = PTTKeyHandler.class, remap = false) +public class PTTKeyHandlerMixin { + @ModifyExpressionValue( + method = { + "isPTTDown()Z", + "isAnyDown()Z", + }, + at = @At( + value = "FIELD", + target = "Lde/maxhenkel/voicechat/voice/client/PTTKeyHandler;pttKeyDown:Z", + opcode = Opcodes.GETFIELD + ) + ) + private boolean isControllerPTTDown(boolean keyDown) { + return keyDown || SimpleVoiceChatCompat.isPTTDown(); + } + + @ModifyExpressionValue( + method = { + "isWhisperDown()Z", + "isAnyDown()Z", + }, + at = @At( + value = "FIELD", + target = "Lde/maxhenkel/voicechat/voice/client/PTTKeyHandler;whisperKeyDown:Z", + opcode = Opcodes.GETFIELD + ) + ) + private boolean isControllerWhisperDown(boolean keyDown) { + return keyDown || SimpleVoiceChatCompat.isWhisperDown(); + } +} diff --git a/src/main/resources/assets/controlify/lang/en_us.json b/src/main/resources/assets/controlify/lang/en_us.json index 0dbc0de..533eac6 100644 --- a/src/main/resources/assets/controlify/lang/en_us.json +++ b/src/main/resources/assets/controlify/lang/en_us.json @@ -322,6 +322,9 @@ "controlify.command.vibratecontroller.entity.single": "Vibrated controller of 1 player from %s's position.", "controlify.command.vibratecontroller.entity.multiple": "Vibrated controller of %s players from %s's position.", + "controlify.compat.svc.hold": "(Hold)", + "controlify.compat.svc.toggle": "(Toggle)", + "controlify.hat_state.up": "Up", "controlify.hat_state.down": "Down", "controlify.hat_state.left": "Left", diff --git a/src/main/resources/controlify.mixins.json b/src/main/resources/controlify.mixins.json index 5c47581..5cfbcf5 100644 --- a/src/main/resources/controlify.mixins.json +++ b/src/main/resources/controlify.mixins.json @@ -9,6 +9,8 @@ "client": [ "compat.fapi.KeyBindingRegistryImplAccessor", "compat.iris.BaseOptionElementWidgetMixin", + "compat.simplevoicechat.KeyEventsAccessor", + "compat.simplevoicechat.PTTKeyHandlerMixin", "compat.sodium.CycleControlElementMixin", "compat.sodium.SliderControlElementMixin", "compat.sodium.SodiumOptionsGUIAccessor",