From 87d57cad8f2876d67deb29c551a6099b86f5ce13 Mon Sep 17 00:00:00 2001 From: Adrian Siekierka Date: Sun, 4 Jun 2023 09:28:23 +0200 Subject: [PATCH] update changelog, networking sync rework --- changelog.md | 5 ++ src/main/resources/application.conf | 20 ++++++-- src/main/scala/li/cil/oc/Settings.scala | 6 ++- .../li/cil/oc/client/PacketHandler.scala | 2 +- .../li/cil/oc/common/PacketBuilder.scala | 49 ++++++++++++++++--- .../scala/li/cil/oc/server/PacketSender.scala | 27 +++++----- 6 files changed, 79 insertions(+), 30 deletions(-) diff --git a/changelog.md b/changelog.md index 1ec48f5ea..00f452818 100644 --- a/changelog.md +++ b/changelog.md @@ -5,11 +5,16 @@ * [#3013] Fixed rare server-side deadlock when sending disk activity update packets. * Added Spanish translation. * Fixed string.gmatch not supporting the "init" argument on Lua 5.4. +* Tweaks to server->client networking code: + * Added support for configuring the maximum packet distance for effects, sounds, and all client packets. + * Improved the method of synchronizing tile entity updates with the client. + * Robot light colors are now sent to all observers of the tile entity, preventing a potential (rare) glitch. * Update GNU Unifont to 15.0.04. ## OpenOS fixes/improvements * [#3371] Fix minor bug in rm.lua. +* Fix "ls -l" command on Lua 5.4. * General minor improvements to the codebase. ## List of contributors diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 3ce0fe914..b82383639 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1400,14 +1400,24 @@ opencomputers { # While the transposer can transfer an unlimited amount in a single # operation, it will block the computer for a duration matching the # limit set in this config option. - transposerFluidTransferRate=4000 + transposerFluidTransferRate: 4000 - # Disk activity update packet delay specified in milliseconds. + # Delay between disk activity sounds, specified in milliseconds. # If set to -1, no disk activity update packets are sent. - diskActivityPacketDelay=500 + diskActivitySoundDelay: 500 - # Disk activity update packet maximum distance. - diskActivityPacketMaxDistance=64.0 + # Maximum distance for updates sent from the client to the server, in blocks. + # This is further modulated by the server's maximum view distance. + # If set to 0, this option is ignored. + maxNetworkClientPacketDistance: 0.0 + + # Maximum distance for visual effects sent from the client to the server. + # These are non-essential - losing them should not cause glitches on the client side. + maxNetworkClientEffectPacketDistance: 64.0 + + # Maximum distance for sound effects sent from the client to the server. + # These are non-essential - losing them should not cause glitches on the client side. + maxNetworkClientSoundPacketDistance: 32.0 } # Settings for mod integration (the mod previously known as OpenComponents). diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index f63f9b19f..295c22afe 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -480,8 +480,10 @@ class Settings(val config: Config) { val bitbltCost: Double = if (config.hasPath("gpu.bitbltCost")) config.getDouble("gpu.bitbltCost") else 0.5 // >= 1.8.2 - val diskActivityPacketDelay: Int = config.getInt("misc.diskActivityPacketDelay") max -1 - val diskActivityPacketMaxDistance: Double = config.getDouble("misc.diskActivityPacketMaxDistance") max 0 + val diskActivitySoundDelay: Int = config.getInt("misc.diskActivitySoundDelay") max -1 + val maxNetworkClientPacketDistance: Double = config.getDouble("misc.maxNetworkClientPacketDistance") max 0 + val maxNetworkClientEffectPacketDistance: Double = config.getDouble("misc.maxNetworkClientEffectPacketDistance") max 0 + val maxNetworkClientSoundPacketDistance: Double = config.getDouble("misc.maxNetworkClientSoundPacketDistance") max 0 } object Settings { diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 713f7b540..ccf46a956 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -391,7 +391,7 @@ object PacketHandler extends CommonPacketHandler { val velocity = p.readDouble() val direction = p.readDirection() val name = p.readUTF() - val count = p.readUnsignedByte() + val count = p.readUnsignedByte() / (1 << Minecraft.getMinecraft.gameSettings.particleSetting) for (i <- 0 until count) { def rv(f: ForgeDirection => Int) = direction match { diff --git a/src/main/scala/li/cil/oc/common/PacketBuilder.scala b/src/main/scala/li/cil/oc/common/PacketBuilder.scala index c1713b5b6..cf5b661b6 100644 --- a/src/main/scala/li/cil/oc/common/PacketBuilder.scala +++ b/src/main/scala/li/cil/oc/common/PacketBuilder.scala @@ -6,11 +6,10 @@ import java.io.DataOutputStream import java.io.OutputStream import java.util.zip.Deflater import java.util.zip.DeflaterOutputStream - import cpw.mods.fml.common.FMLCommonHandler import cpw.mods.fml.common.network.internal.FMLProxyPacket import io.netty.buffer.Unpooled -import li.cil.oc.OpenComputers +import li.cil.oc.{OpenComputers, Settings} import li.cil.oc.api.network.EnvironmentHost import net.minecraft.entity.Entity import net.minecraft.entity.player.EntityPlayerMP @@ -18,7 +17,7 @@ import net.minecraft.item.ItemStack import net.minecraft.nbt.CompressedStreamTools import net.minecraft.nbt.NBTTagCompound import net.minecraft.tileentity.TileEntity -import net.minecraft.world.World +import net.minecraft.world.{World, WorldServer} import net.minecraftforge.common.util.ForgeDirection import org.apache.logging.log4j.LogManager @@ -70,18 +69,52 @@ abstract class PacketBuilder(stream: OutputStream) extends DataOutputStream(stre def sendToPlayersNearEntity(e: Entity, range: Option[Double] = None): Unit = sendToNearbyPlayers(e.worldObj, e.posX, e.posY, e.posZ, range) - def sendToPlayersNearTileEntity(t: TileEntity, range: Option[Double] = None): Unit = sendToNearbyPlayers(t.getWorldObj, t.xCoord + 0.5, t.yCoord + 0.5, t.zCoord + 0.5, range) + def sendToPlayersNearHost(host: EnvironmentHost, range: Option[Double] = None): Unit = { + host match { + case t: TileEntity => sendToPlayersNearTileEntity(t, range) + case _ => sendToNearbyPlayers(host.world, host.xPosition, host.yPosition, host.zPosition, range) + } + } - def sendToPlayersNearHost(host: EnvironmentHost, range: Option[Double] = None): Unit = sendToNearbyPlayers(host.world, host.xPosition, host.yPosition, host.zPosition, range) + def sendToPlayersNearTileEntity(t: TileEntity, range: Option[Double] = None) { + t.getWorldObj match { + case w: WorldServer => + val chunkX = t.xCoord >> 4 + val chunkZ = t.zCoord >> 4 + + val manager = FMLCommonHandler.instance.getMinecraftServerInstance.getConfigurationManager + var maxPacketRange = range.getOrElse((manager.getViewDistance + 1) * 16.0) + val maxPacketRangeConfig = Settings.get.maxNetworkClientPacketDistance + if (maxPacketRangeConfig > 0.0D) { + maxPacketRange = maxPacketRange min maxPacketRangeConfig + } + val maxPacketRangeSq = maxPacketRange * maxPacketRange + + for (e <- w.playerEntities) e match { + case player: EntityPlayerMP => + if (w.getPlayerManager.isPlayerWatchingChunk(player, chunkX, chunkZ)) { + if (player.getDistanceSq(t.xCoord + 0.5D, t.yCoord + 0.5D, t.zCoord + 0.5D) <= maxPacketRangeSq) + sendToPlayer(player) + } + } + case _ => sendToNearbyPlayers(t.getWorldObj, t.xCoord + 0.5D, t.yCoord + 0.5D, t.zCoord + 0.5D, range) + } + } def sendToNearbyPlayers(world: World, x: Double, y: Double, z: Double, range: Option[Double]) { val dimension = world.provider.dimensionId val server = FMLCommonHandler.instance.getMinecraftServerInstance val manager = server.getConfigurationManager + + var maxPacketRange = range.getOrElse((manager.getViewDistance + 1) * 16.0) + val maxPacketRangeConfig = Settings.get.maxNetworkClientPacketDistance + if (maxPacketRangeConfig > 0.0D) { + maxPacketRange = maxPacketRange min maxPacketRangeConfig + } + val maxPacketRangeSq = maxPacketRange * maxPacketRange + for (player <- manager.playerEntityList.map(_.asInstanceOf[EntityPlayerMP]) if player.dimension == dimension) { - val playerRenderDistance = 16 // ObfuscationReflectionHelper.getPrivateValue(classOf[EntityPlayerMP], player, "renderDistance").asInstanceOf[Integer] - val playerSpecificRange = range.getOrElse((manager.getViewDistance min playerRenderDistance) * 16.0) - if (player.getDistanceSq(x, y, z) < playerSpecificRange * playerSpecificRange) { + if (player.getDistanceSq(x, y, z) <= maxPacketRangeSq) { sendToPlayer(player) } } diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index cbda59785..cdf9c76e3 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -130,10 +130,9 @@ object PacketSender { private val fileSystemAccessTimeouts = mutable.WeakHashMap.empty[Node, Cache[String, java.lang.Long]] def sendFileSystemActivity(node: Node, host: EnvironmentHost, name: String) = { - val diskActivityPacketDelay = Settings.get.diskActivityPacketDelay - val diskActivityPacketMaxDistance = Settings.get.diskActivityPacketMaxDistance + val diskActivityPacketDelay = Settings.get.diskActivitySoundDelay - if (diskActivityPacketDelay >= 0 && diskActivityPacketMaxDistance > 0) { + if (diskActivityPacketDelay >= 0) { val hostTimeouts = fileSystemAccessTimeouts.synchronized { fileSystemAccessTimeouts.getOrElseUpdate(node, CacheBuilder.newBuilder().concurrencyLevel(Settings.get.threads).maximumSize(250).expireAfterWrite(diskActivityPacketDelay, TimeUnit.MILLISECONDS).build[String, java.lang.Long]()) } @@ -163,7 +162,7 @@ object PacketSender { pb.writeDouble(event.getZ) } - pb.sendToPlayersNearHost(host, Option(diskActivityPacketMaxDistance)) + pb.sendToPlayersNearHost(host, Option(Settings.get.maxNetworkClientSoundPacketDistance)) } } } @@ -193,7 +192,7 @@ object PacketSender { pb.writeDouble(event.getZ) } - pb.sendToPlayersNearHost(host, Option(64)) + pb.sendToPlayersNearHost(host, Option(Settings.get.maxNetworkClientEffectPacketDistance)) } } @@ -399,7 +398,7 @@ object PacketSender { pb.writeUTF(name) pb.writeByte(count.toByte) - pb.sendToNearbyPlayers(position.world.get, position.x, position.y, position.z, Some(32.0)) + pb.sendToNearbyPlayers(position.world.get, position.x, position.y, position.z, Some(Settings.get.maxNetworkClientEffectPacketDistance / 2.0D)) } def sendPetVisibility(name: Option[String] = None, player: Option[EntityPlayerMP] = None) { @@ -528,7 +527,7 @@ object PacketSender { pb.writeTileEntity(t.proxy) pb.writeInt(t.animationTicksTotal) - pb.sendToPlayersNearTileEntity(t, Option(64)) + pb.sendToPlayersNearTileEntity(t, Option(Settings.get.maxNetworkClientEffectPacketDistance)) } def sendRobotAnimateTurn(t: tileentity.Robot) { @@ -538,7 +537,7 @@ object PacketSender { pb.writeByte(t.turnAxis) pb.writeInt(t.animationTicksTotal) - pb.sendToPlayersNearTileEntity(t, Option(64)) + pb.sendToPlayersNearTileEntity(t, Option(Settings.get.maxNetworkClientEffectPacketDistance)) } def sendRobotInventory(t: tileentity.Robot, slot: Int, stack: ItemStack) { @@ -557,7 +556,7 @@ object PacketSender { pb.writeTileEntity(t.proxy) pb.writeInt(t.info.lightColor) - pb.sendToPlayersNearTileEntity(t, Option(64)) + pb.sendToPlayersNearTileEntity(t) } def sendRobotNameChange(t: tileentity.Robot) { @@ -580,7 +579,7 @@ object PacketSender { pb.writeTileEntity(t.proxy) pb.writeInt(t.selectedSlot) - pb.sendToPlayersNearTileEntity(t, Option(16)) + pb.sendToPlayersNearTileEntity(t, Option(Settings.get.maxNetworkClientEffectPacketDistance / 4.0D)) } def sendRotatableState(t: Rotatable) { @@ -598,7 +597,7 @@ object PacketSender { pb.writeTileEntity(t) - pb.sendToPlayersNearTileEntity(t, Option(64)) + pb.sendToPlayersNearTileEntity(t, Option(Settings.get.maxNetworkClientEffectPacketDistance)) } def appendTextBufferColorChange(pb: PacketBuilder, foreground: PackedColor.Color, background: PackedColor.Color) { @@ -784,7 +783,7 @@ object PacketSender { pb.writeShort(frequency.toShort) pb.writeShort(duration.toShort) - pb.sendToNearbyPlayers(world, x, y, z, Option(32)) + pb.sendToNearbyPlayers(world, x, y, z, Option(Settings.get.maxNetworkClientSoundPacketDistance)) } def sendSound(world: World, x: Double, y: Double, z: Double, pattern: String) { @@ -797,7 +796,7 @@ object PacketSender { pb.writeInt(blockPos.z) pb.writeUTF(pattern) - pb.sendToNearbyPlayers(world, x, y, z, Option(32)) + pb.sendToNearbyPlayers(world, x, y, z, Option(Settings.get.maxNetworkClientSoundPacketDistance)) } def sendTransposerActivity(t: tileentity.Transposer) { @@ -805,7 +804,7 @@ object PacketSender { pb.writeTileEntity(t) - pb.sendToPlayersNearTileEntity(t, Option(32)) + pb.sendToPlayersNearTileEntity(t, Option(Settings.get.maxNetworkClientEffectPacketDistance / 2.0D)) } def sendWaypointLabel(t: Waypoint): Unit = {