From 3863555c8aa5abb3e9a17e7c03484dc2c72423f9 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 5 May 2026 16:58:52 +0200 Subject: [PATCH 1/4] fix world server leak caused by FakeNetworkManager --- src/main/scala/li/cil/oc/server/agent/FakeNetworkManager.scala | 2 +- src/main/scala/li/cil/oc/server/agent/Player.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/agent/FakeNetworkManager.scala b/src/main/scala/li/cil/oc/server/agent/FakeNetworkManager.scala index 595ba9393e..a81ba8333b 100644 --- a/src/main/scala/li/cil/oc/server/agent/FakeNetworkManager.scala +++ b/src/main/scala/li/cil/oc/server/agent/FakeNetworkManager.scala @@ -5,6 +5,6 @@ import io.netty.util.concurrent.GenericFutureListener import net.minecraft.network.NetworkManager import net.minecraft.network.Packet -object FakeNetworkManager extends NetworkManager(false) { +class FakeNetworkManager extends NetworkManager(false) { override def scheduleOutboundPacket(packet: Packet, listener: GenericFutureListener[_ <: Future[_]]*) {} } diff --git a/src/main/scala/li/cil/oc/server/agent/Player.scala b/src/main/scala/li/cil/oc/server/agent/Player.scala index dfdfeca957..824d82dbaf 100644 --- a/src/main/scala/li/cil/oc/server/agent/Player.scala +++ b/src/main/scala/li/cil/oc/server/agent/Player.scala @@ -129,7 +129,7 @@ object Player { } class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanceOf[WorldServer], Player.profileFor(agent)) { - playerNetServerHandler = new NetHandlerPlayServer(mcServer, FakeNetworkManager, this) + playerNetServerHandler = new NetHandlerPlayServer(mcServer, new FakeNetworkManager(), this) capabilities.allowFlying = true capabilities.disableDamage = true From 833ee8a808eac0bc7496758684ab41afc77768e0 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 5 May 2026 18:31:36 +0200 Subject: [PATCH 2/4] delete sound pre loading thread it never did anything --- src/main/scala/li/cil/oc/client/Sound.scala | 26 --------------------- 1 file changed, 26 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/Sound.scala b/src/main/scala/li/cil/oc/client/Sound.scala index 32fdc6e71b..c5848d31cc 100644 --- a/src/main/scala/li/cil/oc/client/Sound.scala +++ b/src/main/scala/li/cil/oc/client/Sound.scala @@ -8,7 +8,6 @@ import java.util.Timer import java.util.TimerTask import java.util.UUID -import com.google.common.base.Charsets import cpw.mods.fml.client.FMLClientHandler import cpw.mods.fml.common.eventhandler.SubscribeEvent import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent @@ -27,7 +26,6 @@ import net.minecraftforge.event.world.WorldEvent import paulscode.sound.SoundSystemConfig import scala.collection.mutable -import scala.io.Source object Sound { private val sources = mutable.Map.empty[TileEntity, PseudoLoopingStream] @@ -115,33 +113,9 @@ object Sound { manager = event.manager } - private var hasPreloaded = Settings.get.soundVolume <= 0 - @SubscribeEvent def onTick(e: ClientTickEvent) { if (soundSystem != null) { - if (!hasPreloaded) { - hasPreloaded = true - new Thread(new Runnable() { - override def run(): Unit = { - val preloadConfigLocation = new ResourceLocation(Settings.resourceDomain, "sounds/preload.cfg") - val preloadConfigResource = Minecraft.getMinecraft.getResourceManager.getResource(preloadConfigLocation) - for (location <- Source.fromInputStream(preloadConfigResource.getInputStream)(Charsets.UTF_8).getLines()) { - val url = getClass.getClassLoader.getResource(location) - if (url != null) try { - val sourceName = "preload_" + location - soundSystem.newSource(false, sourceName, url, location, true, 0, 0, 0, SoundSystemConfig.ATTENUATION_NONE, 16) - soundSystem.activate(sourceName) - soundSystem.removeSource(sourceName) - } catch { - case _: Throwable => // Meh. - } - else OpenComputers.log.warn(s"Couldn't preload sound $location!") - } - } - }) - } - sources.synchronized { updateCallable.foreach(_()) updateCallable = None From 16bb7556fd9802dcfc39287765c0819030b2f853 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 5 May 2026 18:50:58 +0200 Subject: [PATCH 3/4] remove off thread sound updater scheduler --- src/main/scala/li/cil/oc/client/Sound.scala | 50 +++++++-------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/Sound.scala b/src/main/scala/li/cil/oc/client/Sound.scala index c5848d31cc..347fe3ae18 100644 --- a/src/main/scala/li/cil/oc/client/Sound.scala +++ b/src/main/scala/li/cil/oc/client/Sound.scala @@ -1,22 +1,11 @@ package li.cil.oc.client -import java.net.MalformedURLException -import java.net.URL -import java.net.URLConnection -import java.net.URLStreamHandler -import java.util.Timer -import java.util.TimerTask -import java.util.UUID - import cpw.mods.fml.client.FMLClientHandler import cpw.mods.fml.common.eventhandler.SubscribeEvent -import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent -import li.cil.oc.OpenComputers -import li.cil.oc.Settings +import cpw.mods.fml.common.gameevent.TickEvent.{ClientTickEvent, Phase} +import li.cil.oc.{OpenComputers, Settings} import net.minecraft.client.Minecraft -import net.minecraft.client.audio.SoundCategory -import net.minecraft.client.audio.SoundManager -import net.minecraft.client.audio.SoundPoolEntry +import net.minecraft.client.audio.{SoundCategory, SoundManager, SoundPoolEntry} import net.minecraft.server.MinecraftServer import net.minecraft.server.integrated.IntegratedServer import net.minecraft.tileentity.TileEntity @@ -25,29 +14,16 @@ import net.minecraftforge.client.event.sound.SoundLoadEvent import net.minecraftforge.event.world.WorldEvent import paulscode.sound.SoundSystemConfig +import java.net.{MalformedURLException, URL, URLConnection, URLStreamHandler} +import java.util.UUID import scala.collection.mutable object Sound { - private val sources = mutable.Map.empty[TileEntity, PseudoLoopingStream] + private val sources = mutable.Map.empty[TileEntity, PseudoLoopingStream] private val commandQueue = mutable.PriorityQueue.empty[Command] - private var lastVolume = FMLClientHandler.instance.getClient.gameSettings.getSoundLevel(SoundCategory.BLOCKS) - private val updateTimer = new Timer("OpenComputers-SoundUpdater", true) - if (Settings.get.soundVolume > 0) { - updateTimer.scheduleAtFixedRate(new TimerTask { - override def run() { - sources.synchronized(updateCallable = Some(() => { - updateVolume() - processQueue() - })) - } - }, 500, 50) - } - - private var updateCallable = None: Option[() => Unit] - // Set in init event. var manager: SoundManager = _ @@ -113,12 +89,18 @@ object Sound { manager = event.manager } + private var tickCount = 0; + @SubscribeEvent def onTick(e: ClientTickEvent) { - if (soundSystem != null) { - sources.synchronized { - updateCallable.foreach(_()) - updateCallable = None + if (e.phase == Phase.START) return + if (soundSystem != null && Minecraft.getMinecraft.theWorld != null && Settings.get.soundVolume > 0) { + tickCount = tickCount + 1 + if (tickCount % 10 == 0) { + sources.synchronized { + updateVolume() + processQueue() + } } } } From 97ac54ffe7deb4bd8f6bade3e122f335d14ef9fc Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 5 May 2026 18:56:50 +0200 Subject: [PATCH 4/4] fix world client leak (hopefully) --- src/main/scala/li/cil/oc/client/Sound.scala | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/Sound.scala b/src/main/scala/li/cil/oc/client/Sound.scala index 347fe3ae18..f8cba56ae0 100644 --- a/src/main/scala/li/cil/oc/client/Sound.scala +++ b/src/main/scala/li/cil/oc/client/Sound.scala @@ -1,7 +1,7 @@ package li.cil.oc.client import cpw.mods.fml.client.FMLClientHandler -import cpw.mods.fml.common.eventhandler.SubscribeEvent +import cpw.mods.fml.common.eventhandler.{EventPriority, SubscribeEvent} import cpw.mods.fml.common.gameevent.TickEvent.{ClientTickEvent, Phase} import li.cil.oc.{OpenComputers, Settings} import net.minecraft.client.Minecraft @@ -25,9 +25,9 @@ object Sound { private var lastVolume = FMLClientHandler.instance.getClient.gameSettings.getSoundLevel(SoundCategory.BLOCKS) // Set in init event. - var manager: SoundManager = _ + private var manager: SoundManager = _ - def soundSystem = if (manager != null) manager.sndSystem else null + private def soundSystem = if (manager != null) manager.sndSystem else null private def updateVolume() { val volume = @@ -61,7 +61,7 @@ object Sound { } def startLoop(tileEntity: TileEntity, name: String, volume: Float = 1f, delay: Long = 0) { - if (Settings.get.soundVolume > 0) { + if (Settings.get.soundVolume > 0 && Minecraft.getMinecraft.theWorld != null) { commandQueue.synchronized { commandQueue += new StartCommand(System.currentTimeMillis() + delay, tileEntity, name, volume) } @@ -69,7 +69,7 @@ object Sound { } def stopLoop(tileEntity: TileEntity) { - if (Settings.get.soundVolume > 0) { + if (Settings.get.soundVolume > 0 && Minecraft.getMinecraft.theWorld != null) { commandQueue.synchronized { commandQueue += new StopCommand(tileEntity) } @@ -77,7 +77,7 @@ object Sound { } def updatePosition(tileEntity: TileEntity) { - if (Settings.get.soundVolume > 0) { + if (Settings.get.soundVolume > 0 && Minecraft.getMinecraft.theWorld != null) { commandQueue.synchronized { commandQueue += new UpdatePositionCommand(tileEntity) } @@ -105,13 +105,13 @@ object Sound { } } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOWEST) def onWorldUnload(event: WorldEvent.Unload) { - commandQueue.synchronized(commandQueue.clear()) sources.synchronized(try sources.foreach(_._2.stop()) catch { case _: Throwable => // Ignore. }) - sources.clear() + sources.synchronized(sources.clear()) + commandQueue.synchronized(commandQueue.clear()) } private abstract class Command(val when: Long, val tileEntity: TileEntity) extends Ordered[Command] {