From c8498f8603c8527d203b87d4e0979b4fc1a6d0d8 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Sat, 5 Jul 2025 19:32:59 -0400 Subject: [PATCH 01/16] (hackely) updated code to atleast load into 7.3_01. --- build.gradle | 133 +++++++++++++----- gradle.properties | 15 +- settings.gradle | 18 ++- .../java/fiveavian/proxvc/ProxVCServer.java | 1 + .../fiveavian/proxvc/api/ClientEvents.java | 4 +- .../proxvc/gui/MicrophoneListComponent.java | 10 +- .../proxvc/mixin/client/ALC10Mixin.java | 34 ----- .../mixin/client/NetClientHandlerMixin.java | 14 +- .../mixin/client/SoundManagerMixin.java | 19 --- .../fiveavian/proxvc/vc/AudioInputDevice.java | 25 +++- .../proxvc/vc/client/VCInputClient.java | 6 + .../proxvc/vc/server/VCRelayServer.java | 15 +- src/main/resources/fabric.mod.json | 8 +- src/main/resources/{ => gui}/proxvc.png | Bin src/main/resources/proxvc.mixins.json | 4 +- 15 files changed, 170 insertions(+), 136 deletions(-) delete mode 100644 src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java delete mode 100644 src/main/java/fiveavian/proxvc/mixin/client/SoundManagerMixin.java rename src/main/resources/{ => gui}/proxvc.png (100%) diff --git a/build.gradle b/build.gradle index 6224c3e..46ad8e3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,21 @@ plugins { - id "babric-loom" version "1.4.+" - id "java" + id 'fabric-loom' version '1.7.bta' + id 'java' +} + +import org.gradle.internal.os.OperatingSystem + +project.ext.lwjglVersion = "3.3.3" + +switch (OperatingSystem.current()) { + case OperatingSystem.LINUX: + project.ext.lwjglNatives = "natives-linux" + break + case OperatingSystem.WINDOWS: + project.ext.lwjglNatives = "natives-windows" + break + case OperatingSystem.MAC_OS: + project.ext.lwjglNatives = "natives-macos" } group = project.mod_group @@ -8,68 +23,104 @@ archivesBaseName = project.mod_name version = project.mod_version loom { - gluedMinecraftJar() noIntermediateMappings() - customMinecraftManifest.set("https://github.com/Turnip-Labs/bta-manifest-repo/releases/download/v${project.bta_version}/${project.bta_version}.json") - accessWidenerPath = file("src/main/resources/proxvc.accesswidener") + customMinecraftMetadata.set("https://downloads.betterthanadventure.net/bta-client/${project.bta_channel}/v${project.bta_version}/manifest.json") } repositories { mavenCentral() + maven { url = "https://jitpack.io" } + maven { + name = 'Babric' + url = 'https://maven.glass-launcher.net/babric' + } + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + maven { + name = 'SignalumMavenInfrastructure' + url = 'https://maven.thesignalumproject.net/infrastructure' + } + maven { + name = 'SignalumMavenReleases' + url = 'https://maven.thesignalumproject.net/releases' + } ivy { - name = "Minecraft" - url = "https://piston-data.mojang.com" + url = "https://github.com/Better-than-Adventure" patternLayout { - artifact "v1/[organisation]/[revision]/[module].jar" + artifact "[organisation]/releases/download/v[revision]/[module].jar" m2compatible = true } - metadataSources { - artifact() - } + metadataSources { artifact() } } ivy { - name = "BTA" - url = "https://github.com/Better-than-Adventure" + url = "https://downloads.betterthanadventure.net/bta-client/${project.bta_channel}/" patternLayout { - artifact "[organisation]/releases/download/v[revision]/[module].jar" + artifact "/v[revision]/client.jar" m2compatible = true } - metadataSources { - artifact() - } - } - maven { - name = "Babric" - url = "https://maven.glass-launcher.net/babric" + metadataSources { artifact() } } ivy { - name = "Fabric Loader, HalpLibe, Mod Menu" - url = "https://github.com/Turnip-Labs" + url = "https://downloads.betterthanadventure.net/bta-server/${project.bta_channel}/" patternLayout { - artifact "[organisation]/releases/download/[revision]/[module]-[revision].jar" + artifact "/v[revision]/server.jar" m2compatible = true } - metadataSources { - artifact() + metadataSources { artifact() } + } + ivy { + url = "https://piston-data.mojang.com" + patternLayout { + artifact "v1/[organisation]/[revision]/[module].jar" + m2compatible = true } + metadataSources { artifact() } } + } dependencies { - minecraft "bta-download-repo:bta:${project.bta_version}" + minecraft "::${project.bta_version}" mappings loom.layered() {} - // https://piston-data.mojang.com/v1/objects/43db9b498cb67058d2e12d394e6507722e71bb45/client.jar - modRuntimeOnly "objects:client:43db9b498cb67058d2e12d394e6507722e71bb45" - modImplementation "fabric-loader:fabric-loader:${project.loader_version}" - implementation "org.apache.logging.log4j:log4j-core:2.20.0" + modRuntimeOnly "objects:client:43db9b498cb67058d2e12d394e6507722e71bb45" // https://piston-data.mojang.com/v1/objects/43db9b498cb67058d2e12d394e6507722e71bb45/client.jar + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - modRuntimeOnly "bta-halplibe:halplibe:${project.halplibe_version}" - implementation "org.apache.logging.log4j:log4j-1.2-api:2.20.0" + // Helper library + // If you do not need Halplibe you can comment this line out or delete this line + modImplementation("turniplabs:halplibe:${project.halplibe_version}") + + modImplementation("turniplabs:modmenu-bta:${project.mod_menu_version}") + + implementation "org.slf4j:slf4j-api:1.8.0-beta4" implementation "org.apache.logging.log4j:log4j-slf4j18-impl:2.16.0" - implementation "com.google.guava:guava:33.0.0-jre" - modRuntimeOnly "ModMenu:ModMenu-bta:${project.mod_menu_version}" + implementation 'com.google.guava:guava:33.0.0-jre' + implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1' + var log4jVersion = "2.20.0" + implementation("org.apache.logging.log4j:log4j-core:${log4jVersion}") + implementation("org.apache.logging.log4j:log4j-api:${log4jVersion}") + implementation("org.apache.logging.log4j:log4j-1.2-api:${log4jVersion}") + + include(implementation("org.apache.commons:commons-lang3:3.12.0")) + + modImplementation("com.github.Better-than-Adventure:legacy-lwjgl3:1.0.5") + implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion") + + runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives" + runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives" + runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives" + runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives" + runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives" + runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives" + implementation "org.lwjgl:lwjgl:$lwjglVersion" + implementation "org.lwjgl:lwjgl-assimp:$lwjglVersion" + implementation "org.lwjgl:lwjgl-glfw:$lwjglVersion" + implementation "org.lwjgl:lwjgl-openal:$lwjglVersion" + implementation "org.lwjgl:lwjgl-opengl:$lwjglVersion" + implementation "org.lwjgl:lwjgl-stb:$lwjglVersion" } java { @@ -88,9 +139,15 @@ jar { } } +configurations.configureEach { + // Removes LWJGL2 dependencies + exclude group: "org.lwjgl.lwjgl" +} + processResources { - inputs.property "mod_version", project.mod_version + inputs.property "version", version + filesMatching("fabric.mod.json") { - expand "mod_version": project.mod_version + expand "version": version } -} +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 180c8ad..c9f4a75 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,11 +1,16 @@ org.gradle.jvmargs=-Xmx2G -bta_version=7.2_01 -loader_version=0.15.6-babric.6-bta +# BTA +bta_version=7.3_01 +bta_channel=release -halplibe_version=4.1.3 -mod_menu_version=2.0.6 +# Loader +loader_version=0.15.6-bta.7 -mod_version=1.5.2 +# Other Mods +mod_menu_version=3.0.0 +halplibe_version=5.2.2 + +mod_version=1.5.3 mod_group=fiveavian mod_name=proxvc diff --git a/settings.gradle b/settings.gradle index 68b7cc5..d6615a3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,12 +2,20 @@ pluginManagement { repositories { gradlePluginPortal() maven { - name = "Fabric" - url = "https://maven.fabricmc.net/" + name = 'Fabric' + url = 'https://maven.fabricmc.net/' } maven { - name = "Babric" - url = "https://maven.glass-launcher.net/babric" + name = 'Jitpack' + url = 'https://jitpack.io' + } + maven { + name = 'Babric' + url = 'https://maven.glass-launcher.net/babric' + } + maven { + name = 'SignalumMavenInfrastructure' + url = 'https://maven.thesignalumproject.net/infrastructure' } } -} +} \ No newline at end of file diff --git a/src/main/java/fiveavian/proxvc/ProxVCServer.java b/src/main/java/fiveavian/proxvc/ProxVCServer.java index 0620316..4530d30 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCServer.java +++ b/src/main/java/fiveavian/proxvc/ProxVCServer.java @@ -29,6 +29,7 @@ private void start(MinecraftServer server) { int port = server.propertyManager.getIntProperty("server-port", 25565); socket = new DatagramSocket(port, ip.isEmpty() ? null : InetAddress.getByName(ip)); relayThread = new Thread(new VCRelayServer(this)); + System.out.println("Starting ProxVC server on " + socket.getLocalSocketAddress()); relayThread.start(); } catch (SocketException | UnknownHostException ex) { System.out.println("Failed to start the ProxVC server because of an exception."); diff --git a/src/main/java/fiveavian/proxvc/api/ClientEvents.java b/src/main/java/fiveavian/proxvc/api/ClientEvents.java index 9a25ad7..40165db 100644 --- a/src/main/java/fiveavian/proxvc/api/ClientEvents.java +++ b/src/main/java/fiveavian/proxvc/api/ClientEvents.java @@ -2,7 +2,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.render.WorldRenderer; -import net.minecraft.core.net.packet.Packet1Login; +import net.minecraft.core.net.packet.PacketLogin; import java.util.ArrayList; import java.util.List; @@ -15,6 +15,6 @@ public class ClientEvents { public static final List> TICK = new ArrayList<>(); public static final List> RENDER = new ArrayList<>(); - public static final List> LOGIN = new ArrayList<>(); + public static final List> LOGIN = new ArrayList<>(); public static final List> DISCONNECT = new ArrayList<>(); } diff --git a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java index 56dab6e..92ce853 100644 --- a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java +++ b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java @@ -3,8 +3,8 @@ import fiveavian.proxvc.vc.AudioInputDevice; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.options.components.OptionsComponent; -import net.minecraft.client.option.StringOption; -import net.minecraft.client.render.FontRenderer; +import net.minecraft.client.option.OptionString; +import net.minecraft.client.render.Font; import net.minecraft.client.render.tessellator.Tessellator; import net.minecraft.core.lang.I18n; import org.lwjgl.opengl.GL11; @@ -17,12 +17,12 @@ public class MicrophoneListComponent implements OptionsComponent { private static final int BUTTON_HEIGHT_WITH_MARGIN = BUTTON_HEIGHT + MARGIN; private final AudioInputDevice device; - private final StringOption specifierOption; + private final OptionString specifierOption; private Minecraft mc; private String[] specifiers; private int updateTickCount = 0; - public MicrophoneListComponent(AudioInputDevice device, StringOption specifierOption) { + public MicrophoneListComponent(AudioInputDevice device, OptionString specifierOption) { this.device = device; this.specifierOption = specifierOption; } @@ -71,7 +71,7 @@ public int getHeight() { @Override public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY) { Tessellator tessellator = Tessellator.instance; - FontRenderer fontRenderer = mc.fontRenderer; + Font fontRenderer = mc.font; I18n i18n = I18n.getInstance(); if (specifiers.length == 0) { fontRenderer.drawCenteredString(i18n.translateKey("gui.options.page.proxvc.label.no_devices"), x + width / 2, y + 4, 0x5F7F7F7F); diff --git a/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java b/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java deleted file mode 100644 index ea54145..0000000 --- a/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package fiveavian.proxvc.mixin.client; - -import org.lwjgl.openal.ALC10; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.nio.ByteBuffer; -import java.nio.charset.*; - -/** - * Ensures that Minecraft doesn't crash on certain devices. - */ -@Mixin(value = ALC10.class, remap = false) -public class ALC10Mixin { - @Unique - private static final CharsetDecoder DECODER = StandardCharsets.UTF_8.newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - - @Redirect(method = "alcGetString", at = @At(value = "INVOKE", target = "Lorg/lwjgl/MemoryUtil;decodeUTF8(Ljava/nio/ByteBuffer;)Ljava/lang/String;")) - private static String decodeUTF8(ByteBuffer buffer) { - if (buffer == null) { - return null; - } - try { - return DECODER.decode(buffer).toString(); - } catch (CharacterCodingException ex) { - // This should not happen! The decoder has been configured to not throw these exceptions. - throw new RuntimeException(ex); - } - } -} diff --git a/src/main/java/fiveavian/proxvc/mixin/client/NetClientHandlerMixin.java b/src/main/java/fiveavian/proxvc/mixin/client/NetClientHandlerMixin.java index 571db35..02bce25 100644 --- a/src/main/java/fiveavian/proxvc/mixin/client/NetClientHandlerMixin.java +++ b/src/main/java/fiveavian/proxvc/mixin/client/NetClientHandlerMixin.java @@ -2,9 +2,9 @@ import fiveavian.proxvc.api.ClientEvents; import net.minecraft.client.Minecraft; -import net.minecraft.client.net.handler.NetClientHandler; -import net.minecraft.core.net.packet.Packet1Login; -import net.minecraft.core.net.packet.Packet255KickDisconnect; +import net.minecraft.client.net.handler.PacketHandlerClient; +import net.minecraft.core.net.packet.PacketLogin; +import net.minecraft.core.net.packet.PacketDisconnect; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -15,7 +15,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -@Mixin(value = NetClientHandler.class, remap = false) +@Mixin(value = PacketHandlerClient.class, remap = false) public class NetClientHandlerMixin { @Shadow @Final @@ -24,14 +24,14 @@ public class NetClientHandlerMixin { private boolean disconnected; @Inject(method = "handleLogin", at = @At("TAIL")) - public void handleLogin(Packet1Login packet, CallbackInfo ci) { - for (BiConsumer listener : ClientEvents.LOGIN) { + public void handleLogin(PacketLogin packet, CallbackInfo ci) { + for (BiConsumer listener : ClientEvents.LOGIN) { listener.accept(mc, packet); } } @Inject(method = "handleKickDisconnect", at = @At("HEAD")) - public void handleKickDisconnect(Packet255KickDisconnect packet, CallbackInfo ci) { + public void handleKickDisconnect(PacketDisconnect packet, CallbackInfo ci) { for (Consumer listener : ClientEvents.DISCONNECT) { listener.accept(mc); } diff --git a/src/main/java/fiveavian/proxvc/mixin/client/SoundManagerMixin.java b/src/main/java/fiveavian/proxvc/mixin/client/SoundManagerMixin.java deleted file mode 100644 index 4a8ee4b..0000000 --- a/src/main/java/fiveavian/proxvc/mixin/client/SoundManagerMixin.java +++ /dev/null @@ -1,19 +0,0 @@ -package fiveavian.proxvc.mixin.client; - -import net.minecraft.client.option.GameSettings; -import net.minecraft.client.sound.SoundManager; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -/** - * Ensures that Minecraft doesn't crash - * when starting the game with no volume. - */ -@Mixin(value = SoundManager.class, remap = false) -public class SoundManagerMixin { - @Redirect(method = "loadSoundSettings", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/sound/SoundCategoryHelper;isAnyEnabled(Lnet/minecraft/client/option/GameSettings;)Z")) - public boolean isAnyEnabled(GameSettings category) { - return true; - } -} diff --git a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java index cba247e..4cce473 100644 --- a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java +++ b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java @@ -5,27 +5,34 @@ import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.List; public class AudioInputDevice implements AutoCloseable { private static final int NUM_DEVICE_BUFFERS = 8; private final ByteBuffer samples = BufferUtils.createByteBuffer(VCProtocol.BUFFER_SIZE); private final IntBuffer ints = BufferUtils.createIntBuffer(1); - private ALCdevice device = null; + private Long device = null; public static String[] getSpecifiers() { - String result = null; + List result = null; try { - result = ALC10.alcGetString(null, ALC11.ALC_CAPTURE_DEVICE_SPECIFIER); - } catch (OpenALException ex) { + result = ALUtil.getStringList(0, ALC11.ALC_CAPTURE_DEVICE_SPECIFIER); + + } catch (Exception ex) { ex.printStackTrace(); } - return result == null ? new String[0] : result.split("\0"); + System.out.println("Raw device specifiers: " + (result == null ? "dunno" : result)); // Debugging output + + return result == null ? new String[0] : result.toArray(new String[0]); } public synchronized void open(String deviceName) { close(); - if (deviceName == null) { + System.out.println("Opening audio input device: " + deviceName); // Debugging output + + + if (deviceName == null || deviceName.isEmpty()) { device = null; } else { device = ALC11.alcCaptureOpenDevice( @@ -35,6 +42,7 @@ public synchronized void open(String deviceName) { VCProtocol.SAMPLE_COUNT * NUM_DEVICE_BUFFERS ); ALC11.alcCaptureStart(device); + System.out.println("Opened audio input device: " + deviceName); // Debugging output } } @@ -47,7 +55,7 @@ public synchronized ByteBuffer pollSamples() { return null; } ints.rewind(); - ALC10.alcGetInteger(device, ALC11.ALC_CAPTURE_SAMPLES, ints); + ALC10.alcGetInteger(device, ALC11.ALC_CAPTURE_SAMPLES); if (ints.get(0) < VCProtocol.SAMPLE_COUNT) { return null; } @@ -58,6 +66,9 @@ public synchronized ByteBuffer pollSamples() { @Override public synchronized void close() { + if (device == null) { + return; + } if (isClosed()) return; ALC11.alcCaptureStop(device); diff --git a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java index d989460..c552cf4 100644 --- a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java +++ b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java @@ -54,12 +54,17 @@ public void run() { private void sendNextPacket() throws Exception { if (sources.isEmpty()) { + System.out.println("No active audio sources."); return; } ByteBuffer samples = device.pollSamples(); + if (samples == null) { + System.out.println("No audio samples available."); + } packet.buffer.rewind(); packet.buffer.putInt(client.thePlayer.id); if (vcClient.isMuted.value || (vcClient.usePushToTalk.value && !vcClient.keyPushToTalk.isPressed()) || samples == null) { + System.out.println("Sending noop packet."); ticksUntilNoopPacket -= 1; if (ticksUntilNoopPacket > 0) { return; @@ -70,6 +75,7 @@ private void sendNextPacket() throws Exception { ticksUntilNoopPacket = TICKS_UNTIL_NOOP_PACKET; } samples.rewind(); + System.out.println("Encrypting and sending audio packet."); BufferAES.encrypt(AES.clientKeyChain, samples, packet.buffer); packet.send(vcClient.serverAddress); } diff --git a/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java b/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java index 4b41b7f..dec722c 100644 --- a/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java +++ b/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java @@ -6,7 +6,7 @@ import fiveavian.proxvc.vc.VCProtocol; import net.minecraft.core.util.helper.AES; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.player.EntityPlayerMP; +import net.minecraft.server.entity.player.PlayerServer; import java.net.DatagramSocket; import java.net.SocketAddress; @@ -20,7 +20,7 @@ public class VCRelayServer implements Runnable { private final DatagramSocket socket; private final DatagramPacketWrapper packet; - private final HashMap connections = new HashMap<>(); + private final HashMap connections = new HashMap<>(); private final ByteBuffer samples = ByteBuffer.allocate(VCProtocol.BUFFER_SIZE + 16); public VCRelayServer(ProxVCServer vcServer) { @@ -47,7 +47,7 @@ private void handleNextPacket() throws Exception { packet.receive(); SocketAddress address = packet.packet.getSocketAddress(); int entityId = packet.buffer.getInt(); - EntityPlayerMP player = getPlayerById(entityId); + PlayerServer player = getPlayerById(entityId); if (player == null) { return; } @@ -59,12 +59,13 @@ private void handleNextPacket() throws Exception { connections.put(packet.packet.getSocketAddress(), player); connections.entrySet().removeIf(this::isConnectionOffline); for (SocketAddress key : connections.keySet()) { + // System.out.println("Sharing samples from " + player.username + " to " + connections.get(key).username); // Debugging output shareSamples(address, player, key, connections.get(key)); } } - private EntityPlayerMP getPlayerById(int id) { - for (EntityPlayerMP player : server.playerList.playerEntities) { + private PlayerServer getPlayerById(int id) { + for (PlayerServer player : server.playerList.playerEntities) { if (player.id == id) { return player; } @@ -72,11 +73,11 @@ private EntityPlayerMP getPlayerById(int id) { return null; } - private boolean isConnectionOffline(Map.Entry entry) { + private boolean isConnectionOffline(Map.Entry entry) { return getPlayerById(entry.getValue().id) == null; } - private void shareSamples(SocketAddress sourceAddress, EntityPlayerMP sourcePlayer, SocketAddress address, EntityPlayerMP player) throws Exception { + private void shareSamples(SocketAddress sourceAddress, PlayerServer sourcePlayer, SocketAddress address, PlayerServer player) throws Exception { if (sourceAddress.equals(address) || sourcePlayer.id == player.id || sourcePlayer.distanceTo(player) > 32f) { return; } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 0338f18..21970da 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "proxvc", - "version": "${mod_version}", + "version": "1.5.3", "name": "ProxVC", "description": "A primitive voice chat mod for Better Than Adventure!", "authors": [ @@ -24,8 +24,8 @@ ], "accessWidener": "proxvc.accesswidener", "depends": { - "minecraft": "~7.2", - "fabricloader": ">=0.15.5", - "halplibe": ">=3.5.4" + "minecraft": "~7.3", + "fabricloader": ">=0.15.6-bta.7", + "halplibe": ">=5.2.2" } } diff --git a/src/main/resources/proxvc.png b/src/main/resources/gui/proxvc.png similarity index 100% rename from src/main/resources/proxvc.png rename to src/main/resources/gui/proxvc.png diff --git a/src/main/resources/proxvc.mixins.json b/src/main/resources/proxvc.mixins.json index 1f47755..75d8cac 100644 --- a/src/main/resources/proxvc.mixins.json +++ b/src/main/resources/proxvc.mixins.json @@ -4,11 +4,9 @@ "package": "fiveavian.proxvc.mixin", "compatibilityLevel": "JAVA_8", "client": [ - "client.ALC10Mixin", "client.MinecraftMixin", "client.NetClientHandlerMixin", - "client.WorldRendererMixin", - "client.SoundManagerMixin" + "client.WorldRendererMixin" ], "server": [ "server.MinecraftServerMixin" From 509f99ca137a57a2a87e528edee572bfac966e02 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Sun, 6 Jul 2025 01:26:51 -0400 Subject: [PATCH 02/16] Updated for 7.3 and added talking state just because --- .../fiveavian/proxvc/vc/AudioInputDevice.java | 60 ++++++++++++++----- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java index 4cce473..9ed765b 100644 --- a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java +++ b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java @@ -1,7 +1,10 @@ package fiveavian.proxvc.vc; import org.lwjgl.BufferUtils; -import org.lwjgl.openal.*; +import org.lwjgl.openal.AL10; +import org.lwjgl.openal.ALC10; +import org.lwjgl.openal.ALC11; +import org.lwjgl.openal.ALUtil; import java.nio.ByteBuffer; import java.nio.IntBuffer; @@ -13,6 +16,7 @@ public class AudioInputDevice implements AutoCloseable { private final ByteBuffer samples = BufferUtils.createByteBuffer(VCProtocol.BUFFER_SIZE); private final IntBuffer ints = BufferUtils.createIntBuffer(1); private Long device = null; + private boolean isTalking = false; public static String[] getSpecifiers() { List result = null; @@ -28,20 +32,21 @@ public static String[] getSpecifiers() { } public synchronized void open(String deviceName) { + close(); System.out.println("Opening audio input device: " + deviceName); // Debugging output - if (deviceName == null || deviceName.isEmpty()) { device = null; } else { - device = ALC11.alcCaptureOpenDevice( - deviceName, - VCProtocol.SAMPLE_RATE, - AL10.AL_FORMAT_MONO16, - VCProtocol.SAMPLE_COUNT * NUM_DEVICE_BUFFERS - ); - ALC11.alcCaptureStart(device); + + try { + device = ALC11.alcCaptureOpenDevice(deviceName, VCProtocol.SAMPLE_RATE, AL10.AL_FORMAT_MONO16, VCProtocol.SAMPLE_COUNT * NUM_DEVICE_BUFFERS); + ALC11.alcCaptureStart(device); + } catch (Exception ex) { + ex.printStackTrace(); + device = null; + } System.out.println("Opened audio input device: " + deviceName); // Debugging output } } @@ -55,22 +60,45 @@ public synchronized ByteBuffer pollSamples() { return null; } ints.rewind(); - ALC10.alcGetInteger(device, ALC11.ALC_CAPTURE_SAMPLES); - if (ints.get(0) < VCProtocol.SAMPLE_COUNT) { + + int is = ALC10.alcGetInteger(device, ALC11.ALC_CAPTURE_SAMPLES); + + if (is < VCProtocol.SAMPLE_COUNT) { return null; } + samples.rewind(); ALC11.alcCaptureSamples(device, samples, VCProtocol.SAMPLE_COUNT); + + isTalking = !isSilent(samples); return samples; } + public synchronized boolean isTalking() { + if (isClosed()) { + return false; + } + return isTalking; + } + + // did not write this lolll + private boolean isSilent(ByteBuffer samples) { + if (samples.remaining() < 2) { // Assuming 16-bit samples (2 bytes) + return true; // Not enough data to determine silence + } + + for (int i = 0; i < samples.remaining(); i += 2) { + short sample = samples.getShort(i); // Read 16-bit sample + if (Math.abs(sample) > 1) { + return false; // Found a sample above the silence threshold + } + } + return true; // All samples are below the threshold + } + @Override public synchronized void close() { - if (device == null) { - return; - } - if (isClosed()) - return; + if (isClosed()) return; ALC11.alcCaptureStop(device); ALC11.alcCaptureCloseDevice(device); } From 855eb74c9e9f0f0f1df78aae64f93e1d9c3a888c Mon Sep 17 00:00:00 2001 From: IsLocal Date: Sun, 6 Jul 2025 19:40:31 -0400 Subject: [PATCH 03/16] Added Volume Mixer, volume mixed saving to config, fixed some crashes, added mic indicator, cleaned up logs, reintroduced crash fix. --- .../java/fiveavian/proxvc/ProxVCClient.java | 164 ++++++++++++------ .../proxvc/gui/MicrophoneListComponent.java | 11 +- .../proxvc/mixin/client/SoundEngineMixer.java | 19 ++ .../proxvc/screens/VolumeMixerScreen.java | 66 +++++++ .../fiveavian/proxvc/util/MixerStore.java | 77 ++++++++ .../proxvc/vc/StreamingAudioSource.java | 18 +- .../proxvc/vc/client/VCInputClient.java | 13 +- .../proxvc/vc/server/VCRelayServer.java | 2 +- .../proxvc/widgets/PlayerVolumeElement.java | 37 ++++ src/main/resources/gui/proxvc.png | Bin 578 -> 956 bytes src/main/resources/lang/proxvc/en_US.lang | 1 + src/main/resources/proxvc.mixins.json | 3 +- 12 files changed, 348 insertions(+), 63 deletions(-) create mode 100644 src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixer.java create mode 100644 src/main/java/fiveavian/proxvc/screens/VolumeMixerScreen.java create mode 100644 src/main/java/fiveavian/proxvc/util/MixerStore.java create mode 100644 src/main/java/fiveavian/proxvc/widgets/PlayerVolumeElement.java diff --git a/src/main/java/fiveavian/proxvc/ProxVCClient.java b/src/main/java/fiveavian/proxvc/ProxVCClient.java index e833935..2717e27 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCClient.java +++ b/src/main/java/fiveavian/proxvc/ProxVCClient.java @@ -2,6 +2,8 @@ import fiveavian.proxvc.api.ClientEvents; import fiveavian.proxvc.gui.MicrophoneListComponent; +import fiveavian.proxvc.screens.VolumeMixerScreen; +import fiveavian.proxvc.util.MixerStore; import fiveavian.proxvc.util.OptionStore; import fiveavian.proxvc.vc.AudioInputDevice; import fiveavian.proxvc.vc.StreamingAudioSource; @@ -10,23 +12,26 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.options.components.*; +import net.minecraft.client.gui.options.components.BooleanOptionComponent; +import net.minecraft.client.gui.options.components.FloatOptionComponent; +import net.minecraft.client.gui.options.components.KeyBindingComponent; +import net.minecraft.client.gui.options.components.OptionsCategory; import net.minecraft.client.gui.options.data.OptionsPage; import net.minecraft.client.gui.options.data.OptionsPages; import net.minecraft.client.input.InputDevice; import net.minecraft.client.option.*; -import net.minecraft.client.render.tessellator.Tessellator; import net.minecraft.client.render.WorldRenderer; -import net.minecraft.core.block.Block; -import net.minecraft.core.entity.Entity; -import net.minecraft.core.entity.player.EntityPlayer; -import net.minecraft.core.net.packet.Packet1Login; -import net.minecraft.core.util.phys.Vec3d; +import net.minecraft.client.render.tessellator.Tessellator; +import net.minecraft.core.block.Blocks; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.net.packet.PacketLogin; +import net.minecraft.core.util.phys.Vec3; import org.lwjgl.input.Keyboard; import org.lwjgl.openal.AL10; import org.lwjgl.openal.AL11; import org.lwjgl.opengl.GL11; +import java.lang.reflect.Field; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketAddress; @@ -42,20 +47,24 @@ public class ProxVCClient implements ClientModInitializer { public DatagramSocket socket; public AudioInputDevice device; public final Map sources = new HashMap<>(); + public MixerStore mixerStore = new MixerStore(); public SocketAddress serverAddress; private Thread inputThread; private Thread outputThread; public final KeyBinding keyMute = new KeyBinding("key.mute").setDefault(InputDevice.keyboard, Keyboard.KEY_M); public final KeyBinding keyPushToTalk = new KeyBinding("key.push_to_talk").setDefault(InputDevice.keyboard, Keyboard.KEY_V); - public final KeyBinding[] keyBindings = {keyMute, keyPushToTalk}; - public FloatOption voiceChatVolume; - public BooleanOption isMuted; - public BooleanOption usePushToTalk; - public StringOption selectedInputDevice; + public final KeyBinding keyMixer = new KeyBinding("key.volume_mixer").setDefault(InputDevice.keyboard, Keyboard.KEY_Y); + public final KeyBinding[] keyBindings = {keyMute, keyPushToTalk, keyMixer}; + public OptionFloat voiceChatVolume; + public OptionBoolean isMuted; + public OptionBoolean isDebug; + public OptionBoolean usePushToTalk; + public OptionString selectedInputDevice; public Option[] options; public Path optionFilePath; private boolean isMutePressed = false; + private boolean saved = false; public boolean isDisconnected() { return !client.isMultiplayerWorld() || serverAddress == null; @@ -69,18 +78,25 @@ public void onInitializeClient() { ClientEvents.RENDER.add(this::render); ClientEvents.LOGIN.add(this::login); ClientEvents.DISCONNECT.add(this::disconnect); + } + private void start(Minecraft client) { this.client = client; - voiceChatVolume = new FloatOption(client.gameSettings, "sound.voice_chat", 1.0f); - isMuted = new BooleanOption(client.gameSettings, "is_muted", false); - usePushToTalk = new BooleanOption(client.gameSettings, "use_push_to_talk", false); - selectedInputDevice = new StringOption(client.gameSettings, "selected_input_device", null); + voiceChatVolume = new OptionFloat(client.gameSettings, "sound.voice_chat", 1.0f); + isMuted = new OptionBoolean(client.gameSettings, "is_muted", false); + usePushToTalk = new OptionBoolean(client.gameSettings, "use_push_to_talk", false); + selectedInputDevice = new OptionString(client.gameSettings, "selected_input_device", null); + isDebug = new OptionBoolean(client.gameSettings, "is_debug", false); + options = new Option[]{voiceChatVolume, isMuted, usePushToTalk, selectedInputDevice}; optionFilePath = FabricLoader.getInstance().getConfigDir().resolve("proxvc_client.properties"); + OptionStore.loadOptions(optionFilePath, options, keyBindings); OptionStore.saveOptions(optionFilePath, options, keyBindings); + mixerStore.load(); + try { socket = new DatagramSocket(); device = new AudioInputDevice(); @@ -90,20 +106,20 @@ private void start(Minecraft client) { inputThread.start(); outputThread.start(); - OptionsCategory generalCategory = new OptionsCategory("gui.options.page.proxvc.category.general") - .withComponent(new FloatOptionComponent(voiceChatVolume)) - .withComponent(new BooleanOptionComponent(isMuted)) - .withComponent(new BooleanOptionComponent(usePushToTalk)); - OptionsCategory devicesCategory = new OptionsCategory("gui.options.page.proxvc.category.devices") - .withComponent(new MicrophoneListComponent(device, selectedInputDevice)); + OptionsCategory generalCategory = new OptionsCategory("gui.options.page.proxvc.category.general").withComponent(new FloatOptionComponent(voiceChatVolume)).withComponent(new BooleanOptionComponent(isMuted)).withComponent(new BooleanOptionComponent(usePushToTalk)).withComponent(new BooleanOptionComponent(isDebug)); + OptionsCategory devicesCategory = new OptionsCategory("gui.options.page.proxvc.category.devices").withComponent(new MicrophoneListComponent(device, selectedInputDevice)); OptionsCategory controlsCategory = new OptionsCategory("gui.options.page.proxvc.category.controls") .withComponent(new KeyBindingComponent(keyMute)) - .withComponent(new KeyBindingComponent(keyPushToTalk)); - OptionsPages.register(new OptionsPage("gui.options.page.proxvc.title", Block.noteblock.getDefaultStack())) - .withComponent(generalCategory) - .withComponent(devicesCategory) - .withComponent(controlsCategory); + .withComponent(new KeyBindingComponent(keyPushToTalk)) + .withComponent(new KeyBindingComponent(keyMixer)); + + + OptionsPages.register(new OptionsPage("gui.options.page.proxvc.title", Blocks.NOTEBLOCK.getDefaultStack())).withComponent(generalCategory).withComponent(devicesCategory).withComponent(controlsCategory); + device.open(selectedInputDevice.value); + + System.out.println("ProxVC successfully started."); + } catch (SocketException ex) { System.out.println("Failed to start the ProxVC client because of an exception."); System.out.println("Continuing without ProxVC."); @@ -112,8 +128,8 @@ private void start(Minecraft client) { } private void stop(Minecraft client) { - if (optionFilePath != null) - OptionStore.saveOptions(optionFilePath, options, keyBindings); + if (optionFilePath != null) OptionStore.saveOptions(optionFilePath, options, keyBindings); + try { if (socket != null) { socket.close(); @@ -127,6 +143,7 @@ private void stop(Minecraft client) { if (device != null) { device.close(); } + } catch (InterruptedException ex) { System.out.println("Failed to stop the ProxVC client because of an exception."); ex.printStackTrace(); @@ -134,48 +151,77 @@ private void stop(Minecraft client) { } private void tick(Minecraft client) { - if (isDisconnected()) + if (isDisconnected()) { + if (!saved) { + saved = true; + for (StreamingAudioSource source : sources.values()) { + mixerStore.setMixerProperty(source.entityId, source.volume); + } + mixerStore.save(); + } return; + } + Set toRemove = new HashSet<>(sources.keySet()); Set toAdd = new HashSet<>(); - for (Entity entity : client.theWorld.loadedEntityList) { - if (entity instanceof EntityPlayer && entity.id != client.thePlayer.id) { + for (Player entity : client.currentWorld.players) { + if (entity != null && entity.id != client.thePlayer.id) { + toRemove.remove(entity.id); toAdd.add(entity.id); } } for (int entityId : toRemove) { + mixerStore.setMixerProperty(entityId, sources.get(entityId).volume); sources.remove(entityId).close(); } for (int entityId : toAdd) { + if (!sources.containsKey(entityId)) { - sources.put(entityId, new StreamingAudioSource()); + String playerName = null; + + for (Player entity : client.currentWorld.players) { + if (entity.id == entityId) { + playerName = entity.username; + break; + } + } + + sources.put(entityId, new StreamingAudioSource(entityId, playerName)); + sources.get(entityId).volume = mixerStore.getMixerProperty(entityId); } } if (client.currentScreen == null) { - if (keyMute.isPressEvent(InputDevice.keyboard)) - isMutePressed = true; - if (keyMute.isReleaseEvent(InputDevice.keyboard) && isMutePressed) { + if (keyMixer.isPressed()) { + client.displayScreen(new VolumeMixerScreen(sources)); + } + if (keyMute.isPressed()) { + if (!isMutePressed) { + isMutePressed = true; + isMuted.value = !isMuted.value; + } + } else { isMutePressed = false; - isMuted.value = !isMuted.value; + } + } - for (Entity entity : client.theWorld.loadedEntityList) { + for (Player entity : client.currentWorld.players) { StreamingAudioSource source = sources.get(entity.id); if (source == null) { continue; } - Vec3d look = entity.getLookAngle(); + Vec3 look = entity.getLookAngle(); AL10.alDistanceModel(AL11.AL_LINEAR_DISTANCE); AL10.alSourcef(source.source, AL10.AL_MAX_DISTANCE, 32f); AL10.alSourcef(source.source, AL10.AL_REFERENCE_DISTANCE, 16f); AL10.alSource3f(source.source, AL10.AL_POSITION, (float) entity.x, (float) entity.y, (float) entity.z); - AL10.alSource3f(source.source, AL10.AL_DIRECTION, (float) look.xCoord, (float) look.yCoord, (float) look.zCoord); + AL10.alSource3f(source.source, AL10.AL_DIRECTION, (float) look.x, (float) look.y, (float) look.z); AL10.alSource3f(source.source, AL10.AL_VELOCITY, (float) entity.xd, (float) entity.yd, (float) entity.zd); - AL10.alSourcef(source.source, AL10.AL_GAIN, voiceChatVolume.value); + AL10.alSourcef(source.source, AL10.AL_GAIN, voiceChatVolume.value * source.volume); } } @@ -183,32 +229,52 @@ private void render(Minecraft client, WorldRenderer renderer) { if (isDisconnected() || !client.gameSettings.immersiveMode.drawOverlays()) { return; } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, client.renderEngine.getTexture("/proxvc.png")); + client.textureManager.loadTexture("/gui/proxvc.png").bind(); // Bind the texture GL11.glColor4d(1.0, 1.0, 1.0, 1.0); double u = 0.0; if (isMuted.value) { - u = 0.25; + u = 0.2; } else if (device.isClosed()) { - u = 0.5; + u = 0.4; } else if (usePushToTalk.value && !keyPushToTalk.isPressed()) { - u = 0.75; + u = 0.6; + } else if (device.isClosed()) { + u = 0.2; + } else if (device.isTalking()) { + u = 0.8; } Tessellator.instance.startDrawingQuads(); Tessellator.instance.setColorRGBA_F(1f, 1f, 1f, 0.5f); - Tessellator.instance.drawRectangleWithUV(4, client.resolution.scaledHeight - 24 - 4, 24, 24, u, 0.0, 0.25, 1.0); + Tessellator.instance.drawRectangleWithUV(4, client.resolution.getScaledHeightScreenCoords() - 24 - 4, 24, 24, u, 0.0, 0.20, 1.0); Tessellator.instance.draw(); } - private void login(Minecraft client, Packet1Login packet) { - Socket socket = client.getSendQueue().netManager.networkSocket; - serverAddress = socket.getRemoteSocketAddress(); + private void login(Minecraft client, PacketLogin packet) { + // After + try { + saved = false; + Field netManagerField = client.getSendQueue().getClass().getDeclaredField("netManager"); + netManagerField.setAccessible(true); + Object netManager = netManagerField.get(client.getSendQueue()); + Field networkSocketField = netManager.getClass().getDeclaredField("socket"); + networkSocketField.setAccessible(true); + Socket socket = (Socket) networkSocketField.get(netManager); + serverAddress = socket.getRemoteSocketAddress(); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + + } private void disconnect(Minecraft client) { serverAddress = null; + for (StreamingAudioSource source : sources.values()) { source.close(); } + sources.clear(); + } } diff --git a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java index 92ce853..5bf58f8 100644 --- a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java +++ b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java @@ -98,7 +98,7 @@ public void render(int x, int y, int width, int relativeMouseX, int relativeMous tessellator.draw(); GL11.glEnable(GL11.GL_TEXTURE_2D); } - fontRenderer.drawString(specifier, x + 1, y + 4, 0xFFFFFF); + fontRenderer.drawString(specifier.replace("OpenAL Soft on", ""), x + 1, y + 4, 0xFFFFFF); y += BUTTON_HEIGHT_WITH_MARGIN; } } @@ -122,13 +122,16 @@ public void onMouseClick(int mouseButton, int x, int y, int width, int relativeM } @Override - public void onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) {} + public void onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) { + } @Override - public void onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {} + public void onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) { + } @Override - public void onKeyPress(int keyCode, char character) {} + public void onKeyPress(int keyCode, char character) { + } @Override public boolean matchesSearchTerm(String string) { diff --git a/src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixer.java b/src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixer.java new file mode 100644 index 0000000..d93cc78 --- /dev/null +++ b/src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixer.java @@ -0,0 +1,19 @@ +package fiveavian.proxvc.mixin.client; + +import net.minecraft.client.option.GameSettings; +import net.minecraft.client.sound.SoundEngine; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +/** + * Ensures that Minecraft doesn't crash + * when starting the game with no volume. + */ +@Mixin(value = SoundEngine.class, remap = false) +public class SoundEngineMixer { + @Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/sound/SoundCategoryHelper;isAnyEnabled(Lnet/minecraft/client/option/GameSettings;)Z")) + public boolean isAnyEnabled(GameSettings category) { + return true; + } +} \ No newline at end of file diff --git a/src/main/java/fiveavian/proxvc/screens/VolumeMixerScreen.java b/src/main/java/fiveavian/proxvc/screens/VolumeMixerScreen.java new file mode 100644 index 0000000..72f621e --- /dev/null +++ b/src/main/java/fiveavian/proxvc/screens/VolumeMixerScreen.java @@ -0,0 +1,66 @@ +package fiveavian.proxvc.screens; + +import fiveavian.proxvc.vc.StreamingAudioSource; +import fiveavian.proxvc.widgets.PlayerVolumeElement; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ListLayout; +import net.minecraft.client.gui.Screen; +import net.minecraft.client.gui.SliderElement; + +import java.util.Map; + +public class VolumeMixerScreen extends Screen { + + public final Map sources; + public final ListLayout layout; + + public VolumeMixerScreen(Map sources) { + super(null); + this.sources = sources; + this.layout = new ListLayout(this); + } + + public void init() { + //grid + int x = width / 2 - 100; + int y = height / 2 - (sources.size() * 24) / 2; + + int i = 0; + + for (StreamingAudioSource source : sources.values()) { + if (source.lastHeard < System.currentTimeMillis() - 10000) { + continue; // skip sources that haven't been heard from in the last 10 seconds + } + SliderElement mixer = new PlayerVolumeElement(source, x, y + i * 24, sources); + + this.add(mixer); + i++; + } + + + super.init(); + } + + + @Override + public void render(int mx, int my, float partialTick) { + if (this.sources.isEmpty() || this.buttons.isEmpty()) { + this.drawStringCentered(this.font, "No players in range.", width / 2, height / 2 - 20, 0xFFFFFF); + + } + super.render(mx, my, partialTick); + } + + @Override + public void opened(Minecraft mc, int width, int height) { + + super.opened(mc, width, height); + + } + + @Override + public void keyPressed(char eventCharacter, int eventKey, int mx, int my) { + + super.keyPressed(eventCharacter, eventKey, mx, my); + } +} diff --git a/src/main/java/fiveavian/proxvc/util/MixerStore.java b/src/main/java/fiveavian/proxvc/util/MixerStore.java new file mode 100644 index 0000000..b4fe1db --- /dev/null +++ b/src/main/java/fiveavian/proxvc/util/MixerStore.java @@ -0,0 +1,77 @@ +package fiveavian.proxvc.util; + +import net.fabricmc.loader.api.FabricLoader; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +public class MixerStore { + + public Path configPath = FabricLoader.getInstance().getConfigDir().resolve("proxvc_mixer.properties"); + public Map mixerData = new HashMap<>(); + + + public void load() { + try { + if (!Files.exists(configPath)) { + return; + } + Properties properties = new Properties(); + properties.load(Files.newInputStream(configPath)); + + for (String key : properties.stringPropertyNames()) { + try { + int entityId = Integer.parseInt(key); + float volume = Float.parseFloat(properties.getProperty(key)); + mixerData.put(entityId, volume); + } catch (NumberFormatException e) { + System.out.println("Invalid entry in mixer properties: " + key + " = " + properties.getProperty(key)); + } + } + } catch (IOException ex) { + System.out.println("Failed to load options."); + ex.printStackTrace(); + } + } + + public float getMixerProperty(int entityId) { + if (mixerData.containsKey(entityId)) { + return mixerData.get(entityId); + } + return 1.0f; // default volume + } + + public void setMixerProperty(int entityId, float volume) { + if (volume == 1.0f) { + mixerData.remove(entityId); + return; + } + mixerData.put(entityId, volume); + } + + public void save() { + try { + if (!Files.exists(configPath)) { + Files.createFile(configPath); + } + + Properties properties = new Properties(); + + for (Map.Entry entry : mixerData.entrySet()) { + properties.setProperty(entry.getKey().toString(), entry.getValue().toString()); + } + + properties.store(Files.newOutputStream(configPath), null); + } catch (IOException ex) { + System.out.println("Failed to save options."); + ex.printStackTrace(); + } + } +} + + + diff --git a/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java b/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java index 3090ae9..69b0517 100644 --- a/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java +++ b/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java @@ -10,12 +10,25 @@ public class StreamingAudioSource implements AutoCloseable { private static final int NUM_BUFFERS = 8; - public final int source = AL10.alGenSources(); + public final int source ; private final IntBuffer buffers = BufferUtils.createIntBuffer(NUM_BUFFERS); private int bufferIndex = 0; private int numBuffersAvailable = NUM_BUFFERS; + public final int entityId; + public final String playerName; + public float volume = 1.0f; + public long lastHeard = System.currentTimeMillis(); + + public StreamingAudioSource(int entityId, String playerName) { + this.entityId = entityId; + this.playerName = playerName; + + try { + source = AL10.alGenSources(); + } catch (Exception e) { + throw new RuntimeException("Failed to generate OpenAL source. Is OpenAL initialized? Check if your volume is set to 0!", e); + } - public StreamingAudioSource() { AL10.alGenBuffers(buffers); AL10.alDistanceModel(AL11.AL_LINEAR_DISTANCE); AL10.alSourcef(source, AL10.AL_MAX_DISTANCE, 32f); @@ -23,6 +36,7 @@ public StreamingAudioSource() { } public boolean queueSamples(ByteBuffer samples) { + lastHeard = System.currentTimeMillis(); int numBuffersToUnqueue = AL10.alGetSourcei(source, AL10.AL_BUFFERS_PROCESSED); numBuffersAvailable += numBuffersToUnqueue; for (int i = 0; i < numBuffersToUnqueue; i++) { diff --git a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java index c552cf4..57df782 100644 --- a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java +++ b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java @@ -53,18 +53,19 @@ public void run() { } private void sendNextPacket() throws Exception { + if (sources.isEmpty()) { - System.out.println("No active audio sources."); + // System.out.println("No active audio sources."); return; } ByteBuffer samples = device.pollSamples(); - if (samples == null) { - System.out.println("No audio samples available."); - } +// if (samples == null) { +// System.out.println("No audio samples available."); +// } packet.buffer.rewind(); packet.buffer.putInt(client.thePlayer.id); if (vcClient.isMuted.value || (vcClient.usePushToTalk.value && !vcClient.keyPushToTalk.isPressed()) || samples == null) { - System.out.println("Sending noop packet."); + //System.out.println("Sending noop packet."); ticksUntilNoopPacket -= 1; if (ticksUntilNoopPacket > 0) { return; @@ -75,7 +76,7 @@ private void sendNextPacket() throws Exception { ticksUntilNoopPacket = TICKS_UNTIL_NOOP_PACKET; } samples.rewind(); - System.out.println("Encrypting and sending audio packet."); + //System.out.println("Encrypting and sending audio packet."); BufferAES.encrypt(AES.clientKeyChain, samples, packet.buffer); packet.send(vcClient.serverAddress); } diff --git a/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java b/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java index dec722c..d6ee75c 100644 --- a/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java +++ b/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java @@ -59,7 +59,7 @@ private void handleNextPacket() throws Exception { connections.put(packet.packet.getSocketAddress(), player); connections.entrySet().removeIf(this::isConnectionOffline); for (SocketAddress key : connections.keySet()) { - // System.out.println("Sharing samples from " + player.username + " to " + connections.get(key).username); // Debugging output + // System.out.println("Sharing samples from " + player.username + " to " + connections.get(key).username); // Debugging output shareSamples(address, player, key, connections.get(key)); } } diff --git a/src/main/java/fiveavian/proxvc/widgets/PlayerVolumeElement.java b/src/main/java/fiveavian/proxvc/widgets/PlayerVolumeElement.java new file mode 100644 index 0000000..c847e89 --- /dev/null +++ b/src/main/java/fiveavian/proxvc/widgets/PlayerVolumeElement.java @@ -0,0 +1,37 @@ +package fiveavian.proxvc.widgets; + +import fiveavian.proxvc.vc.StreamingAudioSource; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.SliderElement; + +import java.util.Map; + +public class PlayerVolumeElement extends SliderElement { + public final StreamingAudioSource source; + public final Map sources; + + + public PlayerVolumeElement(StreamingAudioSource source, int x, int y, Map sources) { + + super(source.entityId, x, y, 200, 20, "Player " + source.playerName + " Volume: ", source.volume/2.5f); + this.source = source; + this.sources = sources; + } + + @Override + public void mouseDragged(Minecraft mc, int mouseX, int mouseY) { + super.mouseDragged(mc, mouseX, mouseY); + float volume = (float) this.sliderValue * 2.5f; + + this.displayString = "Player " + source.playerName + " Volume: " + (int) ((volume/2.5) * 250) + "%"; + + if (!sources.containsKey(source.entityId)) { + // player disconnected while the volume mixer was open + this.visible = false; + + return; + } + source.volume = volume; + + } +} diff --git a/src/main/resources/gui/proxvc.png b/src/main/resources/gui/proxvc.png index 1645e9b9435fd8d1a6b977d0b57ca8338a85143d..e29ed97b47db1030bec01fd4feba3df59f17c81c 100644 GIT binary patch literal 956 zcmeAS@N?(olHy`uVBq!ia0vp^0YEIk!3HE7J%1boQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4ude`@%$AjKtYKT*NBqf{Irtt#G+J&fW*wa5@05M2Ej7GDRfti6}0y_f>P=$e!u>s=(h^ZhQtP3C}O#!k&fC*?0 z6If-Cr3H`$)n#a40Fr%q^_#`1TRBxgb=jUSjv*25Z>Je%-*yl=UY{kEq~qh0Rq(y- zLBb=~?qzk|PPy3fz) zo4jUoY(_?1!WWgj`|o{@@3%f^T;CtIT6Ol>WhU#NFAZCLvbnigeQCaTWcWwV-Mahd z%vb;NtCqpv{$l3Vs3Hp)rhv6!FH5Xe?ljBVI;*Clf?+{`MnP@uTSk|C`i!p@2R{4! zXR*e`A1}gfjqj_ht&8)!m0MX{%N_zy9`p`diJAE`0V^<%QmvK586_H}2i@Q=NqQCj*1rEo>Tf%EBSNZ8`16}(Y@z_FQ!|qZfQQKVBA0Dy^Z+Z-bac4 z>x>$^N?)&EdR_eN8uJAKlb4^1{i^0DZ~`dx%RMk@*5^%~zqHD(-7b@v-u~zPuXLFo Z%qO`{-{qOKHyD%zJzf1=);T3K0RVTrfg%6^ literal 578 zcmV-I0=@l-P)Px${7FPXR9J=Wl`)IkKoEsL#W6M(#=$W-eGcQ}up2e1@-G6pF0CPje!|t4B5i8_ zh4g}RrRoX?;j7$VaRD17B-Zk#IAmnAYio5b5|Rf(tCiorc{8Ii{D&T%=gG-rBCGO; z!=W4u27ff)(!KCJPc9Y<0Q&tt)9Fbn&577SgkvFSP0LDo;)Yn0qfOF!<<0Ej|d=c-`&&u_= zp$x`#U0JW!0T4p$_JbfO6?~EZ{r(;>Gq2L0uWqqkzb!QjOyXB|KoA60yWJ*^V}uZN zyWP^}i~K6)Rr>SQZCR>u{K^D4j*4!; z>Gmy7`y1Ca<`?zBtn%lGe~0mSELH1c2yI)2wk>C^maM{mseTpy(ahw;`FwsdgR1{| z6TS+q%bBdw0XbfzUmO}`Dv(#cDqp4Fx|~US6w0dn%KEB_X>!Ql&i|+I8|@5l4gA4w QAOHXW07*qoM6N<$f=pH!h5!Hn diff --git a/src/main/resources/lang/proxvc/en_US.lang b/src/main/resources/lang/proxvc/en_US.lang index 5900e90..518e646 100644 --- a/src/main/resources/lang/proxvc/en_US.lang +++ b/src/main/resources/lang/proxvc/en_US.lang @@ -6,6 +6,7 @@ gui.options.page.proxvc.label.no_devices=No microphones found :( key.mute=Mute Microphone key.push_to_talk=Push-to-Talk +key.volume_mixer=Open Volume Mixer options.sound.voice_chat=Voice Chat Volume options.is_muted=Is Muted diff --git a/src/main/resources/proxvc.mixins.json b/src/main/resources/proxvc.mixins.json index 75d8cac..f3a4683 100644 --- a/src/main/resources/proxvc.mixins.json +++ b/src/main/resources/proxvc.mixins.json @@ -6,7 +6,8 @@ "client": [ "client.MinecraftMixin", "client.NetClientHandlerMixin", - "client.WorldRendererMixin" + "client.WorldRendererMixin", + "client.SoundEngineMixer" ], "server": [ "server.MinecraftServerMixin" From 3b076353139e1f06600f253809ec9601496ade62 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Mon, 7 Jul 2025 16:46:26 -0400 Subject: [PATCH 04/16] Resolved issues with build.gradle, reintroduced AccessWideners, fixed socket implementation, reformating, fixed some naming oversights, optimized texture loading. --- build.gradle | 13 ++-- .../java/fiveavian/proxvc/ProxVCClient.java | 63 +++++++++---------- .../proxvc/gui/MicrophoneListComponent.java | 11 ++-- ...xin.java => PacketHandlerClientMixin.java} | 4 +- src/main/resources/fabric.mod.json | 2 +- src/main/resources/proxvc.accesswidener | 10 +-- src/main/resources/proxvc.mixins.json | 4 +- 7 files changed, 52 insertions(+), 55 deletions(-) rename src/main/java/fiveavian/proxvc/mixin/client/{NetClientHandlerMixin.java => PacketHandlerClientMixin.java} (97%) diff --git a/build.gradle b/build.gradle index 46ad8e3..2798deb 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ version = project.mod_version loom { noIntermediateMappings() + accessWidenerPath = file("src/main/resources/proxvc.accesswidener") customMinecraftMetadata.set("https://downloads.betterthanadventure.net/bta-client/${project.bta_channel}/v${project.bta_version}/manifest.json") } @@ -47,6 +48,7 @@ repositories { url = 'https://maven.thesignalumproject.net/releases' } ivy { + name = "BTA Repo" url = "https://github.com/Better-than-Adventure" patternLayout { artifact "[organisation]/releases/download/v[revision]/[module].jar" @@ -55,6 +57,7 @@ repositories { metadataSources { artifact() } } ivy { + name = "BTA-client" url = "https://downloads.betterthanadventure.net/bta-client/${project.bta_channel}/" patternLayout { artifact "/v[revision]/client.jar" @@ -63,6 +66,7 @@ repositories { metadataSources { artifact() } } ivy { + name = "BTA-server" url = "https://downloads.betterthanadventure.net/bta-server/${project.bta_channel}/" patternLayout { artifact "/v[revision]/server.jar" @@ -71,6 +75,7 @@ repositories { metadataSources { artifact() } } ivy { + name = "Minecraft" url = "https://piston-data.mojang.com" patternLayout { artifact "v1/[organisation]/[revision]/[module].jar" @@ -145,9 +150,9 @@ configurations.configureEach { } processResources { - inputs.property "version", version - + inputs.property "mod_version", project.mod_version filesMatching("fabric.mod.json") { - expand "version": version + expand "mod_version": project.mod_version } -} \ No newline at end of file +} + diff --git a/src/main/java/fiveavian/proxvc/ProxVCClient.java b/src/main/java/fiveavian/proxvc/ProxVCClient.java index 2717e27..ea8abdc 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCClient.java +++ b/src/main/java/fiveavian/proxvc/ProxVCClient.java @@ -22,6 +22,7 @@ import net.minecraft.client.option.*; import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.render.tessellator.Tessellator; +import net.minecraft.client.render.texture.Texture; import net.minecraft.core.block.Blocks; import net.minecraft.core.entity.player.Player; import net.minecraft.core.net.packet.PacketLogin; @@ -31,7 +32,6 @@ import org.lwjgl.openal.AL11; import org.lwjgl.opengl.GL11; -import java.lang.reflect.Field; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketAddress; @@ -51,6 +51,7 @@ public class ProxVCClient implements ClientModInitializer { public SocketAddress serverAddress; private Thread inputThread; private Thread outputThread; + public Texture statusIconTexture; public final KeyBinding keyMute = new KeyBinding("key.mute").setDefault(InputDevice.keyboard, Keyboard.KEY_M); public final KeyBinding keyPushToTalk = new KeyBinding("key.push_to_talk").setDefault(InputDevice.keyboard, Keyboard.KEY_V); @@ -58,7 +59,6 @@ public class ProxVCClient implements ClientModInitializer { public final KeyBinding[] keyBindings = {keyMute, keyPushToTalk, keyMixer}; public OptionFloat voiceChatVolume; public OptionBoolean isMuted; - public OptionBoolean isDebug; public OptionBoolean usePushToTalk; public OptionString selectedInputDevice; public Option[] options; @@ -78,17 +78,15 @@ public void onInitializeClient() { ClientEvents.RENDER.add(this::render); ClientEvents.LOGIN.add(this::login); ClientEvents.DISCONNECT.add(this::disconnect); - } - private void start(Minecraft client) { this.client = client; + statusIconTexture = client.textureManager.loadTexture("/gui/proxvc.png"); voiceChatVolume = new OptionFloat(client.gameSettings, "sound.voice_chat", 1.0f); isMuted = new OptionBoolean(client.gameSettings, "is_muted", false); usePushToTalk = new OptionBoolean(client.gameSettings, "use_push_to_talk", false); selectedInputDevice = new OptionString(client.gameSettings, "selected_input_device", null); - isDebug = new OptionBoolean(client.gameSettings, "is_debug", false); options = new Option[]{voiceChatVolume, isMuted, usePushToTalk, selectedInputDevice}; optionFilePath = FabricLoader.getInstance().getConfigDir().resolve("proxvc_client.properties"); @@ -106,20 +104,22 @@ private void start(Minecraft client) { inputThread.start(); outputThread.start(); - OptionsCategory generalCategory = new OptionsCategory("gui.options.page.proxvc.category.general").withComponent(new FloatOptionComponent(voiceChatVolume)).withComponent(new BooleanOptionComponent(isMuted)).withComponent(new BooleanOptionComponent(usePushToTalk)).withComponent(new BooleanOptionComponent(isDebug)); - OptionsCategory devicesCategory = new OptionsCategory("gui.options.page.proxvc.category.devices").withComponent(new MicrophoneListComponent(device, selectedInputDevice)); + OptionsCategory generalCategory = new OptionsCategory("gui.options.page.proxvc.category.general") + .withComponent(new FloatOptionComponent(voiceChatVolume)) + .withComponent(new BooleanOptionComponent(isMuted)) + .withComponent(new BooleanOptionComponent(usePushToTalk)); + OptionsCategory devicesCategory = new OptionsCategory("gui.options.page.proxvc.category.devices") + .withComponent(new MicrophoneListComponent(device, selectedInputDevice)); OptionsCategory controlsCategory = new OptionsCategory("gui.options.page.proxvc.category.controls") .withComponent(new KeyBindingComponent(keyMute)) .withComponent(new KeyBindingComponent(keyPushToTalk)) .withComponent(new KeyBindingComponent(keyMixer)); - - - OptionsPages.register(new OptionsPage("gui.options.page.proxvc.title", Blocks.NOTEBLOCK.getDefaultStack())).withComponent(generalCategory).withComponent(devicesCategory).withComponent(controlsCategory); - + OptionsPages.register(new OptionsPage("gui.options.page.proxvc.title", Blocks.NOTEBLOCK.getDefaultStack())) + .withComponent(generalCategory) + .withComponent(devicesCategory) + .withComponent(controlsCategory); device.open(selectedInputDevice.value); - System.out.println("ProxVC successfully started."); - } catch (SocketException ex) { System.out.println("Failed to start the ProxVC client because of an exception."); System.out.println("Continuing without ProxVC."); @@ -128,7 +128,8 @@ private void start(Minecraft client) { } private void stop(Minecraft client) { - if (optionFilePath != null) OptionStore.saveOptions(optionFilePath, options, keyBindings); + if (optionFilePath != null) + OptionStore.saveOptions(optionFilePath, options, keyBindings); try { if (socket != null) { @@ -162,12 +163,10 @@ private void tick(Minecraft client) { return; } - Set toRemove = new HashSet<>(sources.keySet()); Set toAdd = new HashSet<>(); for (Player entity : client.currentWorld.players) { if (entity != null && entity.id != client.thePlayer.id) { - toRemove.remove(entity.id); toAdd.add(entity.id); } @@ -177,7 +176,6 @@ private void tick(Minecraft client) { sources.remove(entityId).close(); } for (int entityId : toAdd) { - if (!sources.containsKey(entityId)) { String playerName = null; @@ -187,7 +185,6 @@ private void tick(Minecraft client) { break; } } - sources.put(entityId, new StreamingAudioSource(entityId, playerName)); sources.get(entityId).volume = mixerStore.getMixerProperty(entityId); } @@ -206,14 +203,16 @@ private void tick(Minecraft client) { isMutePressed = false; } - } + Map Copy = new HashMap<>(sources); for (Player entity : client.currentWorld.players) { StreamingAudioSource source = sources.get(entity.id); + Copy.remove(entity.id); if (source == null) { continue; } + Vec3 look = entity.getLookAngle(); AL10.alDistanceModel(AL11.AL_LINEAR_DISTANCE); AL10.alSourcef(source.source, AL10.AL_MAX_DISTANCE, 32f); @@ -223,13 +222,19 @@ private void tick(Minecraft client) { AL10.alSource3f(source.source, AL10.AL_VELOCITY, (float) entity.xd, (float) entity.yd, (float) entity.zd); AL10.alSourcef(source.source, AL10.AL_GAIN, voiceChatVolume.value * source.volume); } + // I'm honestly not sure if this cleanup is needed. + for (StreamingAudioSource source : Copy.values()) { + source.close(); + sources.remove(source.entityId); + System.out.println("Closed audio source for entity " + source.entityId + " because they are no longer in the world."); + } } private void render(Minecraft client, WorldRenderer renderer) { if (isDisconnected() || !client.gameSettings.immersiveMode.drawOverlays()) { return; } - client.textureManager.loadTexture("/gui/proxvc.png").bind(); // Bind the texture + statusIconTexture.bind(); GL11.glColor4d(1.0, 1.0, 1.0, 1.0); double u = 0.0; if (isMuted.value) { @@ -250,31 +255,21 @@ private void render(Minecraft client, WorldRenderer renderer) { } private void login(Minecraft client, PacketLogin packet) { - // After try { saved = false; - Field netManagerField = client.getSendQueue().getClass().getDeclaredField("netManager"); - netManagerField.setAccessible(true); - Object netManager = netManagerField.get(client.getSendQueue()); - Field networkSocketField = netManager.getClass().getDeclaredField("socket"); - networkSocketField.setAccessible(true); - Socket socket = (Socket) networkSocketField.get(netManager); + Socket socket = (Socket) client.getSendQueue().netManager.socket; serverAddress = socket.getRemoteSocketAddress(); - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); + } catch (Exception ex) { + System.out.println("Failed to get server address during login."); + ex.printStackTrace(); } - - } private void disconnect(Minecraft client) { serverAddress = null; - for (StreamingAudioSource source : sources.values()) { source.close(); } - sources.clear(); - } } diff --git a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java index 5bf58f8..c5fe83f 100644 --- a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java +++ b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java @@ -98,7 +98,7 @@ public void render(int x, int y, int width, int relativeMouseX, int relativeMous tessellator.draw(); GL11.glEnable(GL11.GL_TEXTURE_2D); } - fontRenderer.drawString(specifier.replace("OpenAL Soft on", ""), x + 1, y + 4, 0xFFFFFF); + fontRenderer.drawString(specifier.replaceFirst("OpenAL Soft on\\s+(?!($|\\s+$))", ""), x + 1, y + 4, 0xFFFFFF); y += BUTTON_HEIGHT_WITH_MARGIN; } } @@ -122,16 +122,13 @@ public void onMouseClick(int mouseButton, int x, int y, int width, int relativeM } @Override - public void onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) { - } + public void onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) {} @Override - public void onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) { - } + public void onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {} @Override - public void onKeyPress(int keyCode, char character) { - } + public void onKeyPress(int keyCode, char character) {} @Override public boolean matchesSearchTerm(String string) { diff --git a/src/main/java/fiveavian/proxvc/mixin/client/NetClientHandlerMixin.java b/src/main/java/fiveavian/proxvc/mixin/client/PacketHandlerClientMixin.java similarity index 97% rename from src/main/java/fiveavian/proxvc/mixin/client/NetClientHandlerMixin.java rename to src/main/java/fiveavian/proxvc/mixin/client/PacketHandlerClientMixin.java index 02bce25..577f662 100644 --- a/src/main/java/fiveavian/proxvc/mixin/client/NetClientHandlerMixin.java +++ b/src/main/java/fiveavian/proxvc/mixin/client/PacketHandlerClientMixin.java @@ -3,8 +3,8 @@ import fiveavian.proxvc.api.ClientEvents; import net.minecraft.client.Minecraft; import net.minecraft.client.net.handler.PacketHandlerClient; -import net.minecraft.core.net.packet.PacketLogin; import net.minecraft.core.net.packet.PacketDisconnect; +import net.minecraft.core.net.packet.PacketLogin; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -16,7 +16,7 @@ import java.util.function.Consumer; @Mixin(value = PacketHandlerClient.class, remap = false) -public class NetClientHandlerMixin { +public class PacketHandlerClientMixin { @Shadow @Final private Minecraft mc; diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 21970da..de60557 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "proxvc", - "version": "1.5.3", + "version": "${mod_version}", "name": "ProxVC", "description": "A primitive voice chat mod for Better Than Adventure!", "authors": [ diff --git a/src/main/resources/proxvc.accesswidener b/src/main/resources/proxvc.accesswidener index fe76733..f7ecb82 100644 --- a/src/main/resources/proxvc.accesswidener +++ b/src/main/resources/proxvc.accesswidener @@ -1,8 +1,8 @@ accessWidener v2 named -accessible field net/minecraft/server/net/handler/NetServerHandler mcServer Lnet/minecraft/server/MinecraftServer; -accessible field net/minecraft/server/net/handler/NetServerHandler playerEntity Lnet/minecraft/server/entity/player/EntityPlayerMP; -accessible field net/minecraft/server/entity/EntityTracker trackedEntityHashTable Lnet/minecraft/core/world/pathfinder/IdHashMap; -accessible field net/minecraft/client/net/handler/NetClientHandler netManager Lnet/minecraft/core/net/NetworkManager; -accessible field net/minecraft/core/net/NetworkManager networkSocket Ljava/net/Socket; +accessible field net/minecraft/server/net/handler/PacketHandlerServer mcServer Lnet/minecraft/server/MinecraftServer; +accessible field net/minecraft/server/net/handler/PacketHandlerServer playerEntity Lnet/minecraft/server/entity/player/PlayerServer; +accessible field net/minecraft/server/entity/EntityTrackerImpl trackedEntityHashTable Lnet/minecraft/core/util/collection/IntHashMap; +accessible field net/minecraft/client/net/handler/PacketHandlerClient netManager Lnet/minecraft/core/net/NetworkManager; +accessible field net/minecraft/core/net/NetworkManager socket Ljava/net/Socket; accessible field net/minecraft/client/Minecraft mcDataDir Ljava/io/File; diff --git a/src/main/resources/proxvc.mixins.json b/src/main/resources/proxvc.mixins.json index f3a4683..d461a0b 100644 --- a/src/main/resources/proxvc.mixins.json +++ b/src/main/resources/proxvc.mixins.json @@ -5,9 +5,9 @@ "compatibilityLevel": "JAVA_8", "client": [ "client.MinecraftMixin", - "client.NetClientHandlerMixin", + "client.PacketHandlerClientMixin", "client.WorldRendererMixin", - "client.SoundEngineMixer" + "client.SoundEngineMixin" ], "server": [ "server.MinecraftServerMixin" From ab8eac188e01c981fedef36f1299115fc64ff754 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Mon, 7 Jul 2025 16:56:20 -0400 Subject: [PATCH 05/16] fixed typo --- .../client/{SoundEngineMixer.java => SoundEngineMixin.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/fiveavian/proxvc/mixin/client/{SoundEngineMixer.java => SoundEngineMixin.java} (95%) diff --git a/src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixer.java b/src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixin.java similarity index 95% rename from src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixer.java rename to src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixin.java index d93cc78..9b8b363 100644 --- a/src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixer.java +++ b/src/main/java/fiveavian/proxvc/mixin/client/SoundEngineMixin.java @@ -11,7 +11,7 @@ * when starting the game with no volume. */ @Mixin(value = SoundEngine.class, remap = false) -public class SoundEngineMixer { +public class SoundEngineMixin { @Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/sound/SoundCategoryHelper;isAnyEnabled(Lnet/minecraft/client/option/GameSettings;)Z")) public boolean isAnyEnabled(GameSettings category) { return true; From 9e1fc05dd386fbaa46eb635c8cd5348f1dd95edc Mon Sep 17 00:00:00 2001 From: IsLocal Date: Tue, 8 Jul 2025 15:51:19 -0400 Subject: [PATCH 06/16] Prevent trying to read player before loaded. --- .../fiveavian/proxvc/vc/client/VCInputClient.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java index 57df782..e2f52bb 100644 --- a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java +++ b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java @@ -55,13 +55,15 @@ public void run() { private void sendNextPacket() throws Exception { if (sources.isEmpty()) { - // System.out.println("No active audio sources."); + return; + } + if (client.thePlayer == null) { return; } ByteBuffer samples = device.pollSamples(); -// if (samples == null) { -// System.out.println("No audio samples available."); -// } + if (samples == null) { + return; + } packet.buffer.rewind(); packet.buffer.putInt(client.thePlayer.id); if (vcClient.isMuted.value || (vcClient.usePushToTalk.value && !vcClient.keyPushToTalk.isPressed()) || samples == null) { @@ -76,7 +78,6 @@ private void sendNextPacket() throws Exception { ticksUntilNoopPacket = TICKS_UNTIL_NOOP_PACKET; } samples.rewind(); - //System.out.println("Encrypting and sending audio packet."); BufferAES.encrypt(AES.clientKeyChain, samples, packet.buffer); packet.send(vcClient.serverAddress); } From e37d40008e37661edf0a590f8dc5ba772d8284b5 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Tue, 8 Jul 2025 16:03:35 -0400 Subject: [PATCH 07/16] Removed Mixer Feature from main branch --- .../java/fiveavian/proxvc/ProxVCClient.java | 29 +------ .../proxvc/screens/VolumeMixerScreen.java | 66 ---------------- .../fiveavian/proxvc/util/MixerStore.java | 77 ------------------- .../proxvc/widgets/PlayerVolumeElement.java | 37 --------- 4 files changed, 2 insertions(+), 207 deletions(-) delete mode 100644 src/main/java/fiveavian/proxvc/screens/VolumeMixerScreen.java delete mode 100644 src/main/java/fiveavian/proxvc/util/MixerStore.java delete mode 100644 src/main/java/fiveavian/proxvc/widgets/PlayerVolumeElement.java diff --git a/src/main/java/fiveavian/proxvc/ProxVCClient.java b/src/main/java/fiveavian/proxvc/ProxVCClient.java index ea8abdc..2436775 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCClient.java +++ b/src/main/java/fiveavian/proxvc/ProxVCClient.java @@ -2,8 +2,6 @@ import fiveavian.proxvc.api.ClientEvents; import fiveavian.proxvc.gui.MicrophoneListComponent; -import fiveavian.proxvc.screens.VolumeMixerScreen; -import fiveavian.proxvc.util.MixerStore; import fiveavian.proxvc.util.OptionStore; import fiveavian.proxvc.vc.AudioInputDevice; import fiveavian.proxvc.vc.StreamingAudioSource; @@ -47,7 +45,6 @@ public class ProxVCClient implements ClientModInitializer { public DatagramSocket socket; public AudioInputDevice device; public final Map sources = new HashMap<>(); - public MixerStore mixerStore = new MixerStore(); public SocketAddress serverAddress; private Thread inputThread; private Thread outputThread; @@ -55,8 +52,7 @@ public class ProxVCClient implements ClientModInitializer { public final KeyBinding keyMute = new KeyBinding("key.mute").setDefault(InputDevice.keyboard, Keyboard.KEY_M); public final KeyBinding keyPushToTalk = new KeyBinding("key.push_to_talk").setDefault(InputDevice.keyboard, Keyboard.KEY_V); - public final KeyBinding keyMixer = new KeyBinding("key.volume_mixer").setDefault(InputDevice.keyboard, Keyboard.KEY_Y); - public final KeyBinding[] keyBindings = {keyMute, keyPushToTalk, keyMixer}; + public final KeyBinding[] keyBindings = {keyMute, keyPushToTalk}; public OptionFloat voiceChatVolume; public OptionBoolean isMuted; public OptionBoolean usePushToTalk; @@ -64,7 +60,6 @@ public class ProxVCClient implements ClientModInitializer { public Option[] options; public Path optionFilePath; private boolean isMutePressed = false; - private boolean saved = false; public boolean isDisconnected() { return !client.isMultiplayerWorld() || serverAddress == null; @@ -93,7 +88,6 @@ private void start(Minecraft client) { OptionStore.loadOptions(optionFilePath, options, keyBindings); OptionStore.saveOptions(optionFilePath, options, keyBindings); - mixerStore.load(); try { socket = new DatagramSocket(); @@ -112,8 +106,7 @@ private void start(Minecraft client) { .withComponent(new MicrophoneListComponent(device, selectedInputDevice)); OptionsCategory controlsCategory = new OptionsCategory("gui.options.page.proxvc.category.controls") .withComponent(new KeyBindingComponent(keyMute)) - .withComponent(new KeyBindingComponent(keyPushToTalk)) - .withComponent(new KeyBindingComponent(keyMixer)); + .withComponent(new KeyBindingComponent(keyPushToTalk)); OptionsPages.register(new OptionsPage("gui.options.page.proxvc.title", Blocks.NOTEBLOCK.getDefaultStack())) .withComponent(generalCategory) .withComponent(devicesCategory) @@ -153,13 +146,6 @@ private void stop(Minecraft client) { private void tick(Minecraft client) { if (isDisconnected()) { - if (!saved) { - saved = true; - for (StreamingAudioSource source : sources.values()) { - mixerStore.setMixerProperty(source.entityId, source.volume); - } - mixerStore.save(); - } return; } @@ -172,7 +158,6 @@ private void tick(Minecraft client) { } } for (int entityId : toRemove) { - mixerStore.setMixerProperty(entityId, sources.get(entityId).volume); sources.remove(entityId).close(); } for (int entityId : toAdd) { @@ -186,14 +171,10 @@ private void tick(Minecraft client) { } } sources.put(entityId, new StreamingAudioSource(entityId, playerName)); - sources.get(entityId).volume = mixerStore.getMixerProperty(entityId); } } if (client.currentScreen == null) { - if (keyMixer.isPressed()) { - client.displayScreen(new VolumeMixerScreen(sources)); - } if (keyMute.isPressed()) { if (!isMutePressed) { isMutePressed = true; @@ -255,14 +236,8 @@ private void render(Minecraft client, WorldRenderer renderer) { } private void login(Minecraft client, PacketLogin packet) { - try { - saved = false; Socket socket = (Socket) client.getSendQueue().netManager.socket; serverAddress = socket.getRemoteSocketAddress(); - } catch (Exception ex) { - System.out.println("Failed to get server address during login."); - ex.printStackTrace(); - } } private void disconnect(Minecraft client) { diff --git a/src/main/java/fiveavian/proxvc/screens/VolumeMixerScreen.java b/src/main/java/fiveavian/proxvc/screens/VolumeMixerScreen.java deleted file mode 100644 index 72f621e..0000000 --- a/src/main/java/fiveavian/proxvc/screens/VolumeMixerScreen.java +++ /dev/null @@ -1,66 +0,0 @@ -package fiveavian.proxvc.screens; - -import fiveavian.proxvc.vc.StreamingAudioSource; -import fiveavian.proxvc.widgets.PlayerVolumeElement; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.ListLayout; -import net.minecraft.client.gui.Screen; -import net.minecraft.client.gui.SliderElement; - -import java.util.Map; - -public class VolumeMixerScreen extends Screen { - - public final Map sources; - public final ListLayout layout; - - public VolumeMixerScreen(Map sources) { - super(null); - this.sources = sources; - this.layout = new ListLayout(this); - } - - public void init() { - //grid - int x = width / 2 - 100; - int y = height / 2 - (sources.size() * 24) / 2; - - int i = 0; - - for (StreamingAudioSource source : sources.values()) { - if (source.lastHeard < System.currentTimeMillis() - 10000) { - continue; // skip sources that haven't been heard from in the last 10 seconds - } - SliderElement mixer = new PlayerVolumeElement(source, x, y + i * 24, sources); - - this.add(mixer); - i++; - } - - - super.init(); - } - - - @Override - public void render(int mx, int my, float partialTick) { - if (this.sources.isEmpty() || this.buttons.isEmpty()) { - this.drawStringCentered(this.font, "No players in range.", width / 2, height / 2 - 20, 0xFFFFFF); - - } - super.render(mx, my, partialTick); - } - - @Override - public void opened(Minecraft mc, int width, int height) { - - super.opened(mc, width, height); - - } - - @Override - public void keyPressed(char eventCharacter, int eventKey, int mx, int my) { - - super.keyPressed(eventCharacter, eventKey, mx, my); - } -} diff --git a/src/main/java/fiveavian/proxvc/util/MixerStore.java b/src/main/java/fiveavian/proxvc/util/MixerStore.java deleted file mode 100644 index b4fe1db..0000000 --- a/src/main/java/fiveavian/proxvc/util/MixerStore.java +++ /dev/null @@ -1,77 +0,0 @@ -package fiveavian.proxvc.util; - -import net.fabricmc.loader.api.FabricLoader; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -public class MixerStore { - - public Path configPath = FabricLoader.getInstance().getConfigDir().resolve("proxvc_mixer.properties"); - public Map mixerData = new HashMap<>(); - - - public void load() { - try { - if (!Files.exists(configPath)) { - return; - } - Properties properties = new Properties(); - properties.load(Files.newInputStream(configPath)); - - for (String key : properties.stringPropertyNames()) { - try { - int entityId = Integer.parseInt(key); - float volume = Float.parseFloat(properties.getProperty(key)); - mixerData.put(entityId, volume); - } catch (NumberFormatException e) { - System.out.println("Invalid entry in mixer properties: " + key + " = " + properties.getProperty(key)); - } - } - } catch (IOException ex) { - System.out.println("Failed to load options."); - ex.printStackTrace(); - } - } - - public float getMixerProperty(int entityId) { - if (mixerData.containsKey(entityId)) { - return mixerData.get(entityId); - } - return 1.0f; // default volume - } - - public void setMixerProperty(int entityId, float volume) { - if (volume == 1.0f) { - mixerData.remove(entityId); - return; - } - mixerData.put(entityId, volume); - } - - public void save() { - try { - if (!Files.exists(configPath)) { - Files.createFile(configPath); - } - - Properties properties = new Properties(); - - for (Map.Entry entry : mixerData.entrySet()) { - properties.setProperty(entry.getKey().toString(), entry.getValue().toString()); - } - - properties.store(Files.newOutputStream(configPath), null); - } catch (IOException ex) { - System.out.println("Failed to save options."); - ex.printStackTrace(); - } - } -} - - - diff --git a/src/main/java/fiveavian/proxvc/widgets/PlayerVolumeElement.java b/src/main/java/fiveavian/proxvc/widgets/PlayerVolumeElement.java deleted file mode 100644 index c847e89..0000000 --- a/src/main/java/fiveavian/proxvc/widgets/PlayerVolumeElement.java +++ /dev/null @@ -1,37 +0,0 @@ -package fiveavian.proxvc.widgets; - -import fiveavian.proxvc.vc.StreamingAudioSource; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.SliderElement; - -import java.util.Map; - -public class PlayerVolumeElement extends SliderElement { - public final StreamingAudioSource source; - public final Map sources; - - - public PlayerVolumeElement(StreamingAudioSource source, int x, int y, Map sources) { - - super(source.entityId, x, y, 200, 20, "Player " + source.playerName + " Volume: ", source.volume/2.5f); - this.source = source; - this.sources = sources; - } - - @Override - public void mouseDragged(Minecraft mc, int mouseX, int mouseY) { - super.mouseDragged(mc, mouseX, mouseY); - float volume = (float) this.sliderValue * 2.5f; - - this.displayString = "Player " + source.playerName + " Volume: " + (int) ((volume/2.5) * 250) + "%"; - - if (!sources.containsKey(source.entityId)) { - // player disconnected while the volume mixer was open - this.visible = false; - - return; - } - source.volume = volume; - - } -} From 77e62f6f111a44fc59202cbaed534db7037f3aa6 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Tue, 8 Jul 2025 16:16:40 -0400 Subject: [PATCH 08/16] renamed fontRender variable to font for clarity. --- .../java/fiveavian/proxvc/gui/MicrophoneListComponent.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java index c5fe83f..06f4e36 100644 --- a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java +++ b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java @@ -71,10 +71,10 @@ public int getHeight() { @Override public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY) { Tessellator tessellator = Tessellator.instance; - Font fontRenderer = mc.font; + Font font = mc.font; I18n i18n = I18n.getInstance(); if (specifiers.length == 0) { - fontRenderer.drawCenteredString(i18n.translateKey("gui.options.page.proxvc.label.no_devices"), x + width / 2, y + 4, 0x5F7F7F7F); + font.drawCenteredString(i18n.translateKey("gui.options.page.proxvc.label.no_devices"), x + width / 2, y + 4, 0x5F7F7F7F); return; } y += MARGIN; @@ -98,7 +98,7 @@ public void render(int x, int y, int width, int relativeMouseX, int relativeMous tessellator.draw(); GL11.glEnable(GL11.GL_TEXTURE_2D); } - fontRenderer.drawString(specifier.replaceFirst("OpenAL Soft on\\s+(?!($|\\s+$))", ""), x + 1, y + 4, 0xFFFFFF); + font.drawString(specifier.replaceFirst("OpenAL Soft on\\s+(?!($|\\s+$))", ""), x + 1, y + 4, 0xFFFFFF); y += BUTTON_HEIGHT_WITH_MARGIN; } } From 817dd36ca5a8f8fbfdfae39c780287b7f47d23cc Mon Sep 17 00:00:00 2001 From: IsLocal Date: Tue, 8 Jul 2025 16:29:28 -0400 Subject: [PATCH 09/16] Cleaned up formating for parity with main fork, removed dev comments/logs, and removed redundant functions from port. Reformatting for parity. Removed left over mixer lang definition. --- build.gradle | 4 +-- gradle.properties | 10 ++----- .../java/fiveavian/proxvc/ProxVCClient.java | 30 ++----------------- .../java/fiveavian/proxvc/ProxVCServer.java | 1 - .../fiveavian/proxvc/vc/AudioInputDevice.java | 23 +++++--------- .../proxvc/vc/StreamingAudioSource.java | 9 +----- .../proxvc/vc/client/VCInputClient.java | 4 +-- .../proxvc/vc/server/VCRelayServer.java | 1 - src/main/resources/lang/proxvc/en_US.lang | 1 - 9 files changed, 17 insertions(+), 66 deletions(-) diff --git a/build.gradle b/build.gradle index 2798deb..c9a5313 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ repositories { url = 'https://maven.thesignalumproject.net/releases' } ivy { - name = "BTA Repo" + name = "BTA" url = "https://github.com/Better-than-Adventure" patternLayout { artifact "[organisation]/releases/download/v[revision]/[module].jar" @@ -83,7 +83,6 @@ repositories { } metadataSources { artifact() } } - } dependencies { @@ -155,4 +154,3 @@ processResources { expand "mod_version": project.mod_version } } - diff --git a/gradle.properties b/gradle.properties index c9f4a75..de8c053 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,16 +1,12 @@ org.gradle.jvmargs=-Xmx2G -# BTA bta_version=7.3_01 -bta_channel=release - -# Loader loader_version=0.15.6-bta.7 +bta_channel=release -# Other Mods -mod_menu_version=3.0.0 halplibe_version=5.2.2 +mod_menu_version=3.0.0 -mod_version=1.5.3 +mod_version=1.5.2 mod_group=fiveavian mod_name=proxvc diff --git a/src/main/java/fiveavian/proxvc/ProxVCClient.java b/src/main/java/fiveavian/proxvc/ProxVCClient.java index 2436775..bf69cf6 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCClient.java +++ b/src/main/java/fiveavian/proxvc/ProxVCClient.java @@ -82,13 +82,10 @@ private void start(Minecraft client) { isMuted = new OptionBoolean(client.gameSettings, "is_muted", false); usePushToTalk = new OptionBoolean(client.gameSettings, "use_push_to_talk", false); selectedInputDevice = new OptionString(client.gameSettings, "selected_input_device", null); - options = new Option[]{voiceChatVolume, isMuted, usePushToTalk, selectedInputDevice}; optionFilePath = FabricLoader.getInstance().getConfigDir().resolve("proxvc_client.properties"); - OptionStore.loadOptions(optionFilePath, options, keyBindings); OptionStore.saveOptions(optionFilePath, options, keyBindings); - try { socket = new DatagramSocket(); device = new AudioInputDevice(); @@ -123,7 +120,6 @@ private void start(Minecraft client) { private void stop(Minecraft client) { if (optionFilePath != null) OptionStore.saveOptions(optionFilePath, options, keyBindings); - try { if (socket != null) { socket.close(); @@ -137,7 +133,6 @@ private void stop(Minecraft client) { if (device != null) { device.close(); } - } catch (InterruptedException ex) { System.out.println("Failed to stop the ProxVC client because of an exception."); ex.printStackTrace(); @@ -145,9 +140,8 @@ private void stop(Minecraft client) { } private void tick(Minecraft client) { - if (isDisconnected()) { + if (isDisconnected()) return; - } Set toRemove = new HashSet<>(sources.keySet()); Set toAdd = new HashSet<>(); @@ -162,15 +156,7 @@ private void tick(Minecraft client) { } for (int entityId : toAdd) { if (!sources.containsKey(entityId)) { - String playerName = null; - - for (Player entity : client.currentWorld.players) { - if (entity.id == entityId) { - playerName = entity.username; - break; - } - } - sources.put(entityId, new StreamingAudioSource(entityId, playerName)); + sources.put(entityId, new StreamingAudioSource()); } } @@ -182,18 +168,14 @@ private void tick(Minecraft client) { } } else { isMutePressed = false; - } } - Map Copy = new HashMap<>(sources); for (Player entity : client.currentWorld.players) { StreamingAudioSource source = sources.get(entity.id); - Copy.remove(entity.id); if (source == null) { continue; } - Vec3 look = entity.getLookAngle(); AL10.alDistanceModel(AL11.AL_LINEAR_DISTANCE); AL10.alSourcef(source.source, AL10.AL_MAX_DISTANCE, 32f); @@ -201,13 +183,7 @@ private void tick(Minecraft client) { AL10.alSource3f(source.source, AL10.AL_POSITION, (float) entity.x, (float) entity.y, (float) entity.z); AL10.alSource3f(source.source, AL10.AL_DIRECTION, (float) look.x, (float) look.y, (float) look.z); AL10.alSource3f(source.source, AL10.AL_VELOCITY, (float) entity.xd, (float) entity.yd, (float) entity.zd); - AL10.alSourcef(source.source, AL10.AL_GAIN, voiceChatVolume.value * source.volume); - } - // I'm honestly not sure if this cleanup is needed. - for (StreamingAudioSource source : Copy.values()) { - source.close(); - sources.remove(source.entityId); - System.out.println("Closed audio source for entity " + source.entityId + " because they are no longer in the world."); + AL10.alSourcef(source.source, AL10.AL_GAIN, voiceChatVolume.value); } } diff --git a/src/main/java/fiveavian/proxvc/ProxVCServer.java b/src/main/java/fiveavian/proxvc/ProxVCServer.java index 4530d30..0620316 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCServer.java +++ b/src/main/java/fiveavian/proxvc/ProxVCServer.java @@ -29,7 +29,6 @@ private void start(MinecraftServer server) { int port = server.propertyManager.getIntProperty("server-port", 25565); socket = new DatagramSocket(port, ip.isEmpty() ? null : InetAddress.getByName(ip)); relayThread = new Thread(new VCRelayServer(this)); - System.out.println("Starting ProxVC server on " + socket.getLocalSocketAddress()); relayThread.start(); } catch (SocketException | UnknownHostException ex) { System.out.println("Failed to start the ProxVC server because of an exception."); diff --git a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java index 9ed765b..3d3ea40 100644 --- a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java +++ b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java @@ -22,32 +22,29 @@ public static String[] getSpecifiers() { List result = null; try { result = ALUtil.getStringList(0, ALC11.ALC_CAPTURE_DEVICE_SPECIFIER); - } catch (Exception ex) { ex.printStackTrace(); } - System.out.println("Raw device specifiers: " + (result == null ? "dunno" : result)); // Debugging output - return result == null ? new String[0] : result.toArray(new String[0]); } public synchronized void open(String deviceName) { - close(); - System.out.println("Opening audio input device: " + deviceName); // Debugging output - if (deviceName == null || deviceName.isEmpty()) { device = null; } else { - try { - device = ALC11.alcCaptureOpenDevice(deviceName, VCProtocol.SAMPLE_RATE, AL10.AL_FORMAT_MONO16, VCProtocol.SAMPLE_COUNT * NUM_DEVICE_BUFFERS); + device = ALC11.alcCaptureOpenDevice( + deviceName, + VCProtocol.SAMPLE_RATE, + AL10.AL_FORMAT_MONO16, + VCProtocol.SAMPLE_COUNT * NUM_DEVICE_BUFFERS + ); ALC11.alcCaptureStart(device); } catch (Exception ex) { ex.printStackTrace(); device = null; } - System.out.println("Opened audio input device: " + deviceName); // Debugging output } } @@ -60,16 +57,12 @@ public synchronized ByteBuffer pollSamples() { return null; } ints.rewind(); - int is = ALC10.alcGetInteger(device, ALC11.ALC_CAPTURE_SAMPLES); - if (is < VCProtocol.SAMPLE_COUNT) { return null; } - samples.rewind(); ALC11.alcCaptureSamples(device, samples, VCProtocol.SAMPLE_COUNT); - isTalking = !isSilent(samples); return samples; } @@ -86,7 +79,6 @@ private boolean isSilent(ByteBuffer samples) { if (samples.remaining() < 2) { // Assuming 16-bit samples (2 bytes) return true; // Not enough data to determine silence } - for (int i = 0; i < samples.remaining(); i += 2) { short sample = samples.getShort(i); // Read 16-bit sample if (Math.abs(sample) > 1) { @@ -98,7 +90,8 @@ private boolean isSilent(ByteBuffer samples) { @Override public synchronized void close() { - if (isClosed()) return; + if (isClosed()) + return; ALC11.alcCaptureStop(device); ALC11.alcCaptureCloseDevice(device); } diff --git a/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java b/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java index 69b0517..83808fb 100644 --- a/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java +++ b/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java @@ -14,14 +14,8 @@ public class StreamingAudioSource implements AutoCloseable { private final IntBuffer buffers = BufferUtils.createIntBuffer(NUM_BUFFERS); private int bufferIndex = 0; private int numBuffersAvailable = NUM_BUFFERS; - public final int entityId; - public final String playerName; - public float volume = 1.0f; - public long lastHeard = System.currentTimeMillis(); - public StreamingAudioSource(int entityId, String playerName) { - this.entityId = entityId; - this.playerName = playerName; + public StreamingAudioSource() { try { source = AL10.alGenSources(); @@ -36,7 +30,6 @@ public StreamingAudioSource(int entityId, String playerName) { } public boolean queueSamples(ByteBuffer samples) { - lastHeard = System.currentTimeMillis(); int numBuffersToUnqueue = AL10.alGetSourcei(source, AL10.AL_BUFFERS_PROCESSED); numBuffersAvailable += numBuffersToUnqueue; for (int i = 0; i < numBuffersToUnqueue; i++) { diff --git a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java index e2f52bb..f8a5680 100644 --- a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java +++ b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java @@ -53,7 +53,6 @@ public void run() { } private void sendNextPacket() throws Exception { - if (sources.isEmpty()) { return; } @@ -66,8 +65,7 @@ private void sendNextPacket() throws Exception { } packet.buffer.rewind(); packet.buffer.putInt(client.thePlayer.id); - if (vcClient.isMuted.value || (vcClient.usePushToTalk.value && !vcClient.keyPushToTalk.isPressed()) || samples == null) { - //System.out.println("Sending noop packet."); + if (vcClient.isMuted.value || (vcClient.usePushToTalk.value && !vcClient.keyPushToTalk.isPressed())) { ticksUntilNoopPacket -= 1; if (ticksUntilNoopPacket > 0) { return; diff --git a/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java b/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java index d6ee75c..c70b585 100644 --- a/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java +++ b/src/main/java/fiveavian/proxvc/vc/server/VCRelayServer.java @@ -59,7 +59,6 @@ private void handleNextPacket() throws Exception { connections.put(packet.packet.getSocketAddress(), player); connections.entrySet().removeIf(this::isConnectionOffline); for (SocketAddress key : connections.keySet()) { - // System.out.println("Sharing samples from " + player.username + " to " + connections.get(key).username); // Debugging output shareSamples(address, player, key, connections.get(key)); } } diff --git a/src/main/resources/lang/proxvc/en_US.lang b/src/main/resources/lang/proxvc/en_US.lang index 518e646..5900e90 100644 --- a/src/main/resources/lang/proxvc/en_US.lang +++ b/src/main/resources/lang/proxvc/en_US.lang @@ -6,7 +6,6 @@ gui.options.page.proxvc.label.no_devices=No microphones found :( key.mute=Mute Microphone key.push_to_talk=Push-to-Talk -key.volume_mixer=Open Volume Mixer options.sound.voice_chat=Voice Chat Volume options.is_muted=Is Muted From aaef7d589728792a49220b5ad0fb22e93c8ad552 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Tue, 8 Jul 2025 17:34:45 -0400 Subject: [PATCH 10/16] Reintroduced ALC10Mixin and fixed mixin failure on newer java versions. --- .../proxvc/mixin/client/ALC10Mixin.java | 37 +++++++++++++++++++ src/main/resources/proxvc.mixins.json | 4 +- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java diff --git a/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java b/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java new file mode 100644 index 0000000..9bb674f --- /dev/null +++ b/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java @@ -0,0 +1,37 @@ +package fiveavian.proxvc.mixin.client; + +import org.lwjgl.openal.ALC10; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.nio.ByteBuffer; +import java.nio.charset.*; + +/** + * Ensures that Minecraft doesn't crash on certain devices. + */ +@Pseudo +@Mixin(value = ALC10.class, remap = false) + +public class ALC10Mixin { + @Unique + private static final CharsetDecoder DECODER = StandardCharsets.UTF_8.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + + @Redirect(method = "alcGetString", at = @At(value = "INVOKE", target = "Lorg/lwjgl/MemoryUtil;decodeUTF8(Ljava/nio/ByteBuffer;)Ljava/lang/String;"), require = 0) + private static String decodeUTF8(ByteBuffer buffer) { + if (buffer == null) { + return null; + } + try { + return DECODER.decode(buffer).toString(); + } catch (CharacterCodingException ex) { + // This should not happen! The decoder has been configured to not throw these exceptions. + throw new RuntimeException(ex); + } + } +} \ No newline at end of file diff --git a/src/main/resources/proxvc.mixins.json b/src/main/resources/proxvc.mixins.json index d461a0b..d54c798 100644 --- a/src/main/resources/proxvc.mixins.json +++ b/src/main/resources/proxvc.mixins.json @@ -7,12 +7,14 @@ "client.MinecraftMixin", "client.PacketHandlerClientMixin", "client.WorldRendererMixin", - "client.SoundEngineMixin" + "client.SoundEngineMixin", + "client.ALC10Mixin" ], "server": [ "server.MinecraftServerMixin" ], "injectors": { "defaultRequire": 1 + } } From 9292eff7c83a036e965d536dbee4655467263b9e Mon Sep 17 00:00:00 2001 From: IsLocal Date: Tue, 8 Jul 2025 17:40:31 -0400 Subject: [PATCH 11/16] Reformating. --- src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java | 1 - src/main/resources/proxvc.mixins.json | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java b/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java index 9bb674f..53baab0 100644 --- a/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java +++ b/src/main/java/fiveavian/proxvc/mixin/client/ALC10Mixin.java @@ -15,7 +15,6 @@ */ @Pseudo @Mixin(value = ALC10.class, remap = false) - public class ALC10Mixin { @Unique private static final CharsetDecoder DECODER = StandardCharsets.UTF_8.newDecoder() diff --git a/src/main/resources/proxvc.mixins.json b/src/main/resources/proxvc.mixins.json index d54c798..8e5ba45 100644 --- a/src/main/resources/proxvc.mixins.json +++ b/src/main/resources/proxvc.mixins.json @@ -15,6 +15,5 @@ ], "injectors": { "defaultRequire": 1 - } } From ac9848e497c95a00cdd849ea82c0e46e656ac4c7 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Tue, 8 Jul 2025 18:43:21 -0400 Subject: [PATCH 12/16] fixed incorrect change to loadedEntityList. --- src/main/java/fiveavian/proxvc/ProxVCClient.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/fiveavian/proxvc/ProxVCClient.java b/src/main/java/fiveavian/proxvc/ProxVCClient.java index bf69cf6..ca58035 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCClient.java +++ b/src/main/java/fiveavian/proxvc/ProxVCClient.java @@ -22,6 +22,7 @@ import net.minecraft.client.render.tessellator.Tessellator; import net.minecraft.client.render.texture.Texture; import net.minecraft.core.block.Blocks; +import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.player.Player; import net.minecraft.core.net.packet.PacketLogin; import net.minecraft.core.util.phys.Vec3; @@ -145,8 +146,8 @@ private void tick(Minecraft client) { Set toRemove = new HashSet<>(sources.keySet()); Set toAdd = new HashSet<>(); - for (Player entity : client.currentWorld.players) { - if (entity != null && entity.id != client.thePlayer.id) { + for (Entity entity : client.currentWorld.loadedEntityList) { + if (entity instanceof Player && entity.id != client.thePlayer.id) { toRemove.remove(entity.id); toAdd.add(entity.id); } @@ -171,7 +172,7 @@ private void tick(Minecraft client) { } } - for (Player entity : client.currentWorld.players) { + for (Entity entity : client.currentWorld.loadedEntityList) { StreamingAudioSource source = sources.get(entity.id); if (source == null) { continue; From a6312e940f45a99ed4d66b61fa81cd27aae3d002 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Wed, 9 Jul 2025 03:07:05 -0400 Subject: [PATCH 13/16] corrected redundant build.gradle changes. --- build.gradle | 106 ++++++++++++++++----------------------------------- 1 file changed, 32 insertions(+), 74 deletions(-) diff --git a/build.gradle b/build.gradle index c9a5313..6dbc600 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,6 @@ plugins { } import org.gradle.internal.os.OperatingSystem - project.ext.lwjglVersion = "3.3.3" switch (OperatingSystem.current()) { @@ -24,107 +23,66 @@ version = project.mod_version loom { noIntermediateMappings() - accessWidenerPath = file("src/main/resources/proxvc.accesswidener") customMinecraftMetadata.set("https://downloads.betterthanadventure.net/bta-client/${project.bta_channel}/v${project.bta_version}/manifest.json") + accessWidenerPath = file("src/main/resources/proxvc.accesswidener") } repositories { mavenCentral() - maven { url = "https://jitpack.io" } - maven { - name = 'Babric' - url = 'https://maven.glass-launcher.net/babric' - } - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - maven { - name = 'SignalumMavenInfrastructure' - url = 'https://maven.thesignalumproject.net/infrastructure' - } - maven { - name = 'SignalumMavenReleases' - url = 'https://maven.thesignalumproject.net/releases' - } ivy { - name = "BTA" - url = "https://github.com/Better-than-Adventure" + name = "Minecraft" + url = "https://piston-data.mojang.com" patternLayout { - artifact "[organisation]/releases/download/v[revision]/[module].jar" + artifact "v1/[organisation]/[revision]/[module].jar" m2compatible = true } - metadataSources { artifact() } - } - ivy { - name = "BTA-client" - url = "https://downloads.betterthanadventure.net/bta-client/${project.bta_channel}/" - patternLayout { - artifact "/v[revision]/client.jar" - m2compatible = true + metadataSources { + artifact() } - metadataSources { artifact() } } ivy { - name = "BTA-server" - url = "https://downloads.betterthanadventure.net/bta-server/${project.bta_channel}/" + name = "BTA" + url = "https://github.com/Better-than-Adventure" patternLayout { - artifact "/v[revision]/server.jar" + artifact "[organisation]/releases/download/v[revision]/[module].jar" m2compatible = true } - metadataSources { artifact() } + metadataSources { + artifact() + } + } + maven { + name = "Babric" + url = "https://maven.glass-launcher.net/babric" } ivy { - name = "Minecraft" - url = "https://piston-data.mojang.com" + name = "Fabric Loader, HalpLibe, Mod Menu" + url = "https://github.com/Turnip-Labs" patternLayout { - artifact "v1/[organisation]/[revision]/[module].jar" + artifact "[organisation]/releases/download/[revision]/[module]-[revision].jar" m2compatible = true } - metadataSources { artifact() } + metadataSources { + artifact() + } } } dependencies { - minecraft "::${project.bta_version}" + minecraft "bta-download-repo:bta:${project.bta_version}" mappings loom.layered() {} - modRuntimeOnly "objects:client:43db9b498cb67058d2e12d394e6507722e71bb45" // https://piston-data.mojang.com/v1/objects/43db9b498cb67058d2e12d394e6507722e71bb45/client.jar - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - // Helper library - // If you do not need Halplibe you can comment this line out or delete this line - modImplementation("turniplabs:halplibe:${project.halplibe_version}") + // https://piston-data.mojang.com/v1/objects/43db9b498cb67058d2e12d394e6507722e71bb45/client.jar + modRuntimeOnly "objects:client:43db9b498cb67058d2e12d394e6507722e71bb45" + modImplementation "fabric-loader:fabric-loader:${project.loader_version}" + implementation "org.apache.logging.log4j:log4j-core:2.20.0" - modImplementation("turniplabs:modmenu-bta:${project.mod_menu_version}") - - implementation "org.slf4j:slf4j-api:1.8.0-beta4" + modRuntimeOnly "bta-halplibe:halplibe:${project.halplibe_version}" + implementation "org.apache.logging.log4j:log4j-1.2-api:2.20.0" implementation "org.apache.logging.log4j:log4j-slf4j18-impl:2.16.0" + implementation "com.google.guava:guava:33.0.0-jre" - implementation 'com.google.guava:guava:33.0.0-jre' - implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1' - var log4jVersion = "2.20.0" - implementation("org.apache.logging.log4j:log4j-core:${log4jVersion}") - implementation("org.apache.logging.log4j:log4j-api:${log4jVersion}") - implementation("org.apache.logging.log4j:log4j-1.2-api:${log4jVersion}") - - include(implementation("org.apache.commons:commons-lang3:3.12.0")) - - modImplementation("com.github.Better-than-Adventure:legacy-lwjgl3:1.0.5") - implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion") - - runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives" - implementation "org.lwjgl:lwjgl:$lwjglVersion" - implementation "org.lwjgl:lwjgl-assimp:$lwjglVersion" - implementation "org.lwjgl:lwjgl-glfw:$lwjglVersion" - implementation "org.lwjgl:lwjgl-openal:$lwjglVersion" - implementation "org.lwjgl:lwjgl-opengl:$lwjglVersion" - implementation "org.lwjgl:lwjgl-stb:$lwjglVersion" + modRuntimeOnly "ModMenu:ModMenu-bta:${project.mod_menu_version}" } java { @@ -144,7 +102,7 @@ jar { } configurations.configureEach { - // Removes LWJGL2 dependencies + // Removes LWJGL2 dependencies. exclude group: "org.lwjgl.lwjgl" } From b0767b6a944e5b2b5afe2b257e06ad50821ab2f9 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Wed, 9 Jul 2025 18:44:39 -0400 Subject: [PATCH 14/16] reformating and corrected change made in pollSamples(). --- src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java | 5 ++--- src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java index 3d3ea40..acc11ab 100644 --- a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java +++ b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java @@ -57,8 +57,8 @@ public synchronized ByteBuffer pollSamples() { return null; } ints.rewind(); - int is = ALC10.alcGetInteger(device, ALC11.ALC_CAPTURE_SAMPLES); - if (is < VCProtocol.SAMPLE_COUNT) { + ALC11.alcGetIntegerv(device, ALC11.ALC_CAPTURE_SAMPLES, ints); + if (ints.get(0) < VCProtocol.SAMPLE_COUNT) { return null; } samples.rewind(); @@ -74,7 +74,6 @@ public synchronized boolean isTalking() { return isTalking; } - // did not write this lolll private boolean isSilent(ByteBuffer samples) { if (samples.remaining() < 2) { // Assuming 16-bit samples (2 bytes) return true; // Not enough data to determine silence diff --git a/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java b/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java index 83808fb..8e57a3d 100644 --- a/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java +++ b/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java @@ -16,13 +16,11 @@ public class StreamingAudioSource implements AutoCloseable { private int numBuffersAvailable = NUM_BUFFERS; public StreamingAudioSource() { - try { source = AL10.alGenSources(); } catch (Exception e) { throw new RuntimeException("Failed to generate OpenAL source. Is OpenAL initialized? Check if your volume is set to 0!", e); } - AL10.alGenBuffers(buffers); AL10.alDistanceModel(AL11.AL_LINEAR_DISTANCE); AL10.alSourcef(source, AL10.AL_MAX_DISTANCE, 32f); From 1ae31ba801741a6d30300ff1ae5b111a338fe8d7 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Thu, 10 Jul 2025 12:23:14 -0400 Subject: [PATCH 15/16] final touches. --- src/main/java/fiveavian/proxvc/ProxVCClient.java | 9 +++------ src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java | 5 +---- .../java/fiveavian/proxvc/vc/client/VCInputClient.java | 5 +---- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/main/java/fiveavian/proxvc/ProxVCClient.java b/src/main/java/fiveavian/proxvc/ProxVCClient.java index ca58035..e80b54b 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCClient.java +++ b/src/main/java/fiveavian/proxvc/ProxVCClient.java @@ -10,22 +10,19 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.options.components.BooleanOptionComponent; -import net.minecraft.client.gui.options.components.FloatOptionComponent; -import net.minecraft.client.gui.options.components.KeyBindingComponent; -import net.minecraft.client.gui.options.components.OptionsCategory; +import net.minecraft.client.gui.options.components.*; import net.minecraft.client.gui.options.data.OptionsPage; import net.minecraft.client.gui.options.data.OptionsPages; import net.minecraft.client.input.InputDevice; import net.minecraft.client.option.*; -import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.render.tessellator.Tessellator; -import net.minecraft.client.render.texture.Texture; +import net.minecraft.client.render.WorldRenderer; import net.minecraft.core.block.Blocks; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.player.Player; import net.minecraft.core.net.packet.PacketLogin; import net.minecraft.core.util.phys.Vec3; +import net.minecraft.client.render.texture.Texture; import org.lwjgl.input.Keyboard; import org.lwjgl.openal.AL10; import org.lwjgl.openal.AL11; diff --git a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java index acc11ab..8ca5460 100644 --- a/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java +++ b/src/main/java/fiveavian/proxvc/vc/AudioInputDevice.java @@ -1,10 +1,7 @@ package fiveavian.proxvc.vc; import org.lwjgl.BufferUtils; -import org.lwjgl.openal.AL10; -import org.lwjgl.openal.ALC10; -import org.lwjgl.openal.ALC11; -import org.lwjgl.openal.ALUtil; +import org.lwjgl.openal.*; import java.nio.ByteBuffer; import java.nio.IntBuffer; diff --git a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java index f8a5680..c2d402a 100644 --- a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java +++ b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java @@ -60,12 +60,9 @@ private void sendNextPacket() throws Exception { return; } ByteBuffer samples = device.pollSamples(); - if (samples == null) { - return; - } packet.buffer.rewind(); packet.buffer.putInt(client.thePlayer.id); - if (vcClient.isMuted.value || (vcClient.usePushToTalk.value && !vcClient.keyPushToTalk.isPressed())) { + if (vcClient.isMuted.value || (vcClient.usePushToTalk.value && !vcClient.keyPushToTalk.isPressed()) || samples == null) { ticksUntilNoopPacket -= 1; if (ticksUntilNoopPacket > 0) { return; From 2d86958d235c60c831d07d66e6128de26b85fc45 Mon Sep 17 00:00:00 2001 From: IsLocal Date: Sun, 13 Jul 2025 09:11:49 -0400 Subject: [PATCH 16/16] Updated loom version, added lwjgl dependencies, resolved some issues. --- build.gradle | 21 ++++++++++++++++--- .../java/fiveavian/proxvc/ProxVCClient.java | 4 ++-- .../proxvc/gui/MicrophoneListComponent.java | 5 ++++- .../proxvc/vc/StreamingAudioSource.java | 4 ++-- .../proxvc/vc/client/VCInputClient.java | 5 +---- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 6dbc600..6685fe0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,10 @@ plugins { - id 'fabric-loom' version '1.7.bta' - id 'java' + id("fabric-loom") version "1.10.0-bta" + id("java") } import org.gradle.internal.os.OperatingSystem -project.ext.lwjglVersion = "3.3.3" +project.ext.lwjglVersion = "3.3.4" switch (OperatingSystem.current()) { case OperatingSystem.LINUX: @@ -83,6 +83,21 @@ dependencies { implementation "com.google.guava:guava:33.0.0-jre" modRuntimeOnly "ModMenu:ModMenu-bta:${project.mod_menu_version}" + + implementation(platform("org.lwjgl:lwjgl-bom:$lwjglVersion")) + + runtimeOnly("org.lwjgl:lwjgl::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-assimp::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-glfw::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-openal::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-opengl::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-stb::$lwjglNatives") + implementation("org.lwjgl:lwjgl:$lwjglVersion") + implementation("org.lwjgl:lwjgl-assimp:$lwjglVersion") + implementation("org.lwjgl:lwjgl-glfw:$lwjglVersion") + implementation("org.lwjgl:lwjgl-openal:$lwjglVersion") + implementation("org.lwjgl:lwjgl-opengl:$lwjglVersion") + implementation("org.lwjgl:lwjgl-stb:$lwjglVersion") } java { diff --git a/src/main/java/fiveavian/proxvc/ProxVCClient.java b/src/main/java/fiveavian/proxvc/ProxVCClient.java index e80b54b..123d5cc 100644 --- a/src/main/java/fiveavian/proxvc/ProxVCClient.java +++ b/src/main/java/fiveavian/proxvc/ProxVCClient.java @@ -210,8 +210,8 @@ private void render(Minecraft client, WorldRenderer renderer) { } private void login(Minecraft client, PacketLogin packet) { - Socket socket = (Socket) client.getSendQueue().netManager.socket; - serverAddress = socket.getRemoteSocketAddress(); + Socket socket = (Socket) client.getSendQueue().netManager.socket; + serverAddress = socket.getRemoteSocketAddress(); } private void disconnect(Minecraft client) { diff --git a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java index 06f4e36..c393cc3 100644 --- a/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java +++ b/src/main/java/fiveavian/proxvc/gui/MicrophoneListComponent.java @@ -10,11 +10,14 @@ import org.lwjgl.opengl.GL11; import java.util.Objects; +import java.util.regex.Pattern; public class MicrophoneListComponent implements OptionsComponent { private static final int MARGIN = 3; private static final int BUTTON_HEIGHT = 16; private static final int BUTTON_HEIGHT_WITH_MARGIN = BUTTON_HEIGHT + MARGIN; + // I ended up using a negative look ahead at the end plus the end modifier to prevent replacing entire string with blank + private static final Pattern SPECIFIER_PATTERN = Pattern.compile("OpenAL Soft on\\s+(?!($|\\s+$))"); private final AudioInputDevice device; private final OptionString specifierOption; @@ -98,7 +101,7 @@ public void render(int x, int y, int width, int relativeMouseX, int relativeMous tessellator.draw(); GL11.glEnable(GL11.GL_TEXTURE_2D); } - font.drawString(specifier.replaceFirst("OpenAL Soft on\\s+(?!($|\\s+$))", ""), x + 1, y + 4, 0xFFFFFF); + font.drawString(SPECIFIER_PATTERN.matcher(specifier).replaceFirst(""), x + 1, y + 4, 0xFFFFFF); y += BUTTON_HEIGHT_WITH_MARGIN; } } diff --git a/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java b/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java index 8e57a3d..64cbcb6 100644 --- a/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java +++ b/src/main/java/fiveavian/proxvc/vc/StreamingAudioSource.java @@ -10,7 +10,7 @@ public class StreamingAudioSource implements AutoCloseable { private static final int NUM_BUFFERS = 8; - public final int source ; + public final int source; private final IntBuffer buffers = BufferUtils.createIntBuffer(NUM_BUFFERS); private int bufferIndex = 0; private int numBuffersAvailable = NUM_BUFFERS; @@ -19,7 +19,7 @@ public StreamingAudioSource() { try { source = AL10.alGenSources(); } catch (Exception e) { - throw new RuntimeException("Failed to generate OpenAL source. Is OpenAL initialized? Check if your volume is set to 0!", e); + throw new RuntimeException("Failed to generate OpenAL source. Something terrible happened, report it to our github! https://github.com/5Avian/proxvc/issues", e); } AL10.alGenBuffers(buffers); AL10.alDistanceModel(AL11.AL_LINEAR_DISTANCE); diff --git a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java index c2d402a..fe70c94 100644 --- a/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java +++ b/src/main/java/fiveavian/proxvc/vc/client/VCInputClient.java @@ -53,10 +53,7 @@ public void run() { } private void sendNextPacket() throws Exception { - if (sources.isEmpty()) { - return; - } - if (client.thePlayer == null) { + if (sources.isEmpty() || client.thePlayer == null) { return; } ByteBuffer samples = device.pollSamples();