Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -1257,10 +1257,22 @@ opencomputers {
# Note: also applies to the motion sensor.
inputUsername: true

# Enables batching mode for clipboard pasting.
# When set to true, clipboard signals are sent in fixed-size chunks
# rather than line-by-line.
# WARNING: Enabling this changes the 'clipboard' signal behavior and
# may break existing Lua scripts that expect per-line signals.
enableClipboardBatching: false

# The maximum total length of pasted clipboard content.
# Note: Only applied if enableClipboardBatching = false.
maxClipboardSize: 65536

# The maximum length of each clipboard signal. Clipboard contents are
# split into chunks of this size, independent of line breaks, so one
# signal can contain multiple short lines.
maxClipboard: 256
# Note: Only applied if enableClipboardBatching = true.
clipboardBatchSize: 256

# The TTL (Time-To-Live) upon creation of a network packet. When a packet
# passes through a Relay, its TTL is decremented. If a Relay receives a
Expand Down
11 changes: 10 additions & 1 deletion src/main/scala/li/cil/oc/Settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,16 @@ class Settings(val config: Config) {
val maxScreenWidth = config.getInt("misc.maxScreenWidth") max 1
val maxScreenHeight = config.getInt("misc.maxScreenHeight") max 1
val inputUsername = config.getBoolean("misc.inputUsername")
val maxClipboard = config.getInt("misc.maxClipboard") max 1
val enableClipboardBatching = config.getBoolean("misc.enableClipboardBatching")
val maxClipboardSize = config.getInt("misc.maxClipboardSize")
val clipboardBatchSize = config.getInt("misc.clipboardBatchSize") max 1
def maxClipboardLength: Int = {
if (enableClipboardBatching) {
val value = clipboardBatchSize.toLong * maxSignalQueueSize.toLong
if (value > Int.MaxValue) Int.MaxValue else value.toInt
}
else maxClipboardSize
}
val initialNetworkPacketTTL = config.getInt("misc.initialNetworkPacketTTL") max 5
val maxNetworkPacketSize = config.getInt("misc.maxNetworkPacketSize") max 0
// Need at least 4 for nanomachine protocol. Because I can!
Expand Down
8 changes: 1 addition & 7 deletions src/main/scala/li/cil/oc/client/PacketSender.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ import net.minecraft.util.ResourceLocation
import net.minecraftforge.common.util.ForgeDirection

object PacketSender {
// The server can queue this many clipboard chunks. Keep the client-side
// whole-paste limit in line with that capacity instead of imposing the
// unrelated historical 64 KiB limit.
private def maxClipboardLength: Long =
Settings.get.maxClipboard.toLong * Settings.get.maxSignalQueueSize

// Timestamp after which the next clipboard message may be sent. Used to
// avoid spamming large packets on key repeat.
protected var clipboardCooldown = 0L
Expand Down Expand Up @@ -78,7 +72,7 @@ object PacketSender {

def sendClipboard(address: String, value: String) {
if (value != null && !value.isEmpty) {
if (value.length.toLong > maxClipboardLength || System.currentTimeMillis() < clipboardCooldown) {
if (value.length > Settings.get.maxClipboardLength || System.currentTimeMillis() < clipboardCooldown) {
val player = Minecraft.getMinecraft.thePlayer
val handler = Minecraft.getMinecraft.getSoundHandler
handler.playSound(new PositionedSoundRecord(new ResourceLocation("note.harp"), 1, 1, player.posX.toFloat, player.posY.toFloat, player.posZ.toFloat))
Expand Down
8 changes: 3 additions & 5 deletions src/main/scala/li/cil/oc/server/PacketHandler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package li.cil.oc.server

import cpw.mods.fml.common.eventhandler.SubscribeEvent
import cpw.mods.fml.common.network.FMLNetworkEvent.ServerCustomPacketEvent
import li.cil.oc.Localization
import li.cil.oc.OpenComputers
import li.cil.oc.api
import li.cil.oc.{Localization, OpenComputers, Settings, api}
import li.cil.oc.api.internal.Server
import li.cil.oc.api.machine.Machine
import li.cil.oc.common.Achievement
Expand Down Expand Up @@ -211,7 +209,7 @@ object PacketHandler extends CommonPacketHandler {
def onClipboard(p: PacketParser): Unit = {
val address = p.readUTF()
val copy = p.readUTF()
if (copy.length > maxClientTextLength) return // Oversized; likely a forged client.
if (copy.length > Settings.get.maxClipboardLength) return // Oversized; likely a forged client.
ComponentTracker.get(p.player.worldObj, address) match {
case Some(buffer: api.internal.TextBuffer) => buffer.clipboard(copy, p.player.asInstanceOf[EntityPlayer])
case _ => // Invalid Packet
Expand Down Expand Up @@ -393,4 +391,4 @@ object PacketHandler extends CommonPacketHandler {
case _ => // Invalid packet.
}
}
}
}
13 changes: 7 additions & 6 deletions src/main/scala/li/cil/oc/server/component/Keyboard.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,8 @@ class Keyboard(val host: EnvironmentHost) extends prefab.ManagedEnvironment with
}
case Array(p: EntityPlayer, value: String) if message.name == "keyboard.clipboard" =>
if (isUseableByPlayer(p)) {
// linesWithSeparators is used here deliberately: unlike lines it
// retains the newline characters. The helper then fills parts by
// character capacity, crossing line boundaries when possible and
// splitting individual long lines when necessary.
for (part <- clipboardParts(value)) {
val it = if (Settings.get.enableClipboardBatching) clipboardParts(value) else value.linesWithSeparators
for (part <- it) {
if (Settings.get.inputUsername) {
signal(p, "clipboard", part, p.getCommandSenderName)
}
Expand All @@ -106,8 +103,12 @@ class Keyboard(val host: EnvironmentHost) extends prefab.ManagedEnvironment with
}
}

// linesWithSeparators is used here deliberately: unlike lines it
// retains the newline characters. The helper then fills parts by
// character capacity, crossing line boundaries when possible and
// splitting individual long lines when necessary.
private def clipboardParts(value: String): Iterator[String] = {
val limit = Settings.get.maxClipboard max 1
val limit = Settings.get.clipboardBatchSize max 1
val parts = mutable.ArrayBuffer.empty[String]
val current = new mutable.StringBuilder

Expand Down