Merge branch 'master-MC1.7.10' of github.com:MightyPirates/OpenComputers into master-MC1.8

Conflicts:
	src/main/scala/li/cil/oc/common/item/Acid.scala
	src/main/scala/li/cil/oc/common/item/Nanomachines.scala
This commit is contained in:
Florian Nücke 2015-09-19 00:55:14 +02:00
commit a76bdb4552
10 changed files with 120 additions and 64 deletions

View File

@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*;
*/ */
public class API { public class API {
public static final String ID_OWNER = "OpenComputers|Core"; public static final String ID_OWNER = "OpenComputers|Core";
public static final String VERSION = "5.6.0"; public static final String VERSION = "5.6.1";
public static DriverAPI driver = null; public static DriverAPI driver = null;
public static FileSystemAPI fileSystem = null; public static FileSystemAPI fileSystem = null;

View File

@ -44,15 +44,24 @@ public interface Controller {
int getTotalInputCount(); int getTotalInputCount();
/** /**
* Get the total number of inputs that may be active at the same time * Get the number of inputs that may be active at the same time
* before negative effects are applied to the player. * before negative effects are applied to the player.
* <p/> * <p/>
* The number of active inputs may exceed this value, but this will * The number of active inputs may exceed this value, but this will
* have negative effects on the player. * have negative effects on the player.
* *
* @return the number of inputs that may safely be active at a time.
*/
int getSafeActiveInputs();
/**
* Get the total number of inputs that may be active at the same time.
* <p/>
* The number of active inputs cannot exceed this value.
*
* @return the number of inputs that may be active at a time. * @return the number of inputs that may be active at a time.
*/ */
int getSafeInputCount(); int getMaxActiveInputs();
/** /**
* Get whether the input with the specified index is active. * Get whether the input with the specified index is active.
@ -65,12 +74,16 @@ public interface Controller {
/** /**
* Set the state of the input with the specified index. * Set the state of the input with the specified index.
* <p/>
* This will fail if too many inputs are active already. It will also
* always fail when called on the client.
* *
* @param index the input index. * @param index the input index.
* @param value whether the input should be active. * @param value whether the input should be active.
* @return whether the input was changed successfully.
* @throws IndexOutOfBoundsException if <code>index &lt; 0</code> or <code>index &gt;= getInputCount</code>. * @throws IndexOutOfBoundsException if <code>index &lt; 0</code> or <code>index &gt;= getInputCount</code>.
*/ */
void setInput(int index, boolean value); boolean setInput(int index, boolean value);
/** /**
* Get the list of currently active behaviors, based on the current input states. * Get the list of currently active behaviors, based on the current input states.

View File

@ -1011,11 +1011,21 @@ opencomputers {
# How many input nodes may be active at the same time before negative # How many input nodes may be active at the same time before negative
# effects are applied to the player. # effects are applied to the player.
safeInputCount: 2 safeInputsActive: 2
# The time in seconds it takes to reconfigure the nanomachines. This is # Hard maximum number of active inputs. This is mainly to avoid people
# to avoid spamming reconfigurations. # bumping other nanomachines' inputs to max, killing them in a matter
reconfigureCooldown: 5 # of (milli)seconds.
maxInputsActive: 4
# Time in seconds it takes for the nanomachines to process a command
# and send a response.
commandDelay: 1
# The distance in blocks that nanomachines can communicate within. If
# a message comes from further away, it'll be ignored. When responding,
# the response will only be sent this far.
commandRange: 2
# Range of the item magnet behavior added for each active input. # Range of the item magnet behavior added for each active input.
magnetRange: 8 magnetRange: 8

View File

@ -4,4 +4,6 @@
This tasty [citation needed] concoction can be consumed if you ever feel the need for some... fun. Or ruining your digestive tract. Or both. It can also serve as ingredient in other, more useful items. This tasty [citation needed] concoction can be consumed if you ever feel the need for some... fun. Or ruining your digestive tract. Or both. It can also serve as ingredient in other, more useful items.
One of the main uses, however, is to remove [nanomachines](nanomachines.md) from your system, if you no longer want them in you. Drinking this is the only way of getting rid of them!
When using hard-mode recipes, it is used to etch [circuit boards](circuitBoard.md) before crafting [printed circuit boards](printedCircuitBoard.md). When using hard-mode recipes, it is used to etch [circuit boards](circuitBoard.md) before crafting [printed circuit boards](printedCircuitBoard.md).

View File

@ -8,22 +8,26 @@ Once injected, a new power indicator in your HUD will indicate how much energy y
Nanomachines provide a certain number of "inputs" that can be triggered, causing many different effects on the player, ranging from visual effects such as particles spawning near the player, to select potion effects and some more rare and special behaviors! Nanomachines provide a certain number of "inputs" that can be triggered, causing many different effects on the player, ranging from visual effects such as particles spawning near the player, to select potion effects and some more rare and special behaviors!
Which input triggers what effect depends on the current configuration of the nanomachines, the actual "connections" being random per configuration. This means you'll have to try enabling different inputs to see what they do. If you're unhappy with a configuration, you can always reconfigure your nanomachines. Beware that enabling too many inputs at a time has severe negative effects on you! Which input triggers what effect depends on the current configuration of the nanomachines, the actual "connections" being random per configuration. This means you'll have to try enabling different inputs to see what they do. If you're unhappy with a configuration, you can always reconfigure your nanomachines by injecting a new batch (just eat some more). To completely get rid of the nanomachines in you, consider drinking some [grog](acid.md). Beware that enabling too many inputs at a time has severe negative effects on you!
By default, the nanomachines will be on standby. You'll need to control them using wireless messages, so carrying a [tablet](tablet.md) with a [wireless network card](wlanCard.md) is strongly recommended. Nanomachines will only react to wireless signals emitted by devices no further than two meters away, but they will react to messages on any port, and from any device! By default, the nanomachines will be on standby. You'll need to control them using wireless messages, so carrying a [tablet](tablet.md) with a [wireless network card](wlanCard.md) is strongly recommended. Nanomachines will only react to wireless signals emitted by devices no further than two meters away, but they will react to messages on any port, and from any device!
Nanomachines react to a simple, proprietary protocol: each packet must consist of multiple parts, the first of which is the "header" and must equal the string `nanomachines`. The second part must be the command name. Additional parts are parameters for the command. The following commands are available, formatted as `commandName(arg1, ...)`: Nanomachines react to a simple, proprietary protocol: each packet must consist of multiple parts, the first of which is the "header" and must equal the string `nanomachines`. The second part must be the command name. Additional parts are parameters for the command. The following commands are available, formatted as `commandName(arg1, ...)`:
- `setResponsePort(port:number)` - Set the port nanomachines should send response messages to, for commands that have a response. - `setResponsePort(port:number)` - Set the port nanomachines should send response messages to, for commands that have a response.
- `dispose()` - Destroy all nanomachines currently in the player. - `getPowerState()` - Request the currently stored and maximum stored energy of the nanomachines.
- `reconfigure()` - Cause the nanomachines to enter a new configuration. - `getHealth()` - Request the player's health state.
- `getTotalInputCount()` - Request a message with the total number of available inputs. - `getHunger()` - Request the player's hunger state.
- `getSafeInputCount()` - Request a message with the number of *safe* inputs. - `getAge()` - Request the player's age in seconds.
- `getInput(index:number)` - Request a message with the current state of the input with the specified index. - `getName()` - Request the player's display name.
- `getExperience()` - Request the player's experience level.
- `getTotalInputCount()` - Request the total number of available inputs.
- `getSafeActiveInputs()` - Request the number of *safe* active inputs.
- `getMaxActiveInputs()` - Request the number of *maximum* active inputs.
- `getInput(index:number)` - Request the current state of the input with the specified index.
- `setInput(index:number, value:boolean)` - Set the state of the input with the specified index to the specified value. - `setInput(index:number, value:boolean)` - Set the state of the input with the specified index to the specified value.
- `getActiveEffects()` - Request a list of active effects. Note that some effects may not show up in this list. - `getActiveEffects()` - Request a list of active effects. Note that some effects may not show up in this list.
- `getPowerState()` - Request a message with the currently stored and maximum stored energy of the nanomachines.
For example, in OpenOS: For example, in OpenOS:
- `component.modem.broadcast(1, "nanomachines", "setInput", 1, true)` will enable the first input. - `component.modem.broadcast(1, "nanomachines", "setInput", 1, true)` will enable the first input.
- `component.modem.broadcast(1, "nanomachines", "reconfigure")` will reconfigure the nanomachines. - `component.modem.broadcast(1, "nanomachines", "getHealth")` will get the player's health info.

View File

@ -356,8 +356,10 @@ class Settings(val config: Config) {
val nanomachineConnectorQuota = config.getDouble("nanomachines.connectorQuota") max 0 val nanomachineConnectorQuota = config.getDouble("nanomachines.connectorQuota") max 0
val nanomachineMaxInputs = config.getInt("nanomachines.maxInputs") max 1 val nanomachineMaxInputs = config.getInt("nanomachines.maxInputs") max 1
val nanomachineMaxOutputs = config.getInt("nanomachines.maxOutputs") max 1 val nanomachineMaxOutputs = config.getInt("nanomachines.maxOutputs") max 1
val nanomachinesSafeInputCount = config.getInt("nanomachines.safeInputCount") max 0 val nanomachinesSafeInputsActive = config.getInt("nanomachines.safeInputsActive") max 0
val nanomachineReconfigureTimeout = config.getDouble("nanomachines.reconfigureCooldown") max 0 val nanomachinesMaxInputsActive = config.getInt("nanomachines.maxInputsActive") max 0
val nanomachinesCommandDelay = config.getDouble("nanomachines.commandDelay") max 0
val nanomachinesCommandRange = config.getDouble("nanomachines.commandRange") max 0
val nanomachineMagnetRange = config.getDouble("nanomachines.magnetRange") max 0 val nanomachineMagnetRange = config.getDouble("nanomachines.magnetRange") max 0
val nanomachineDisintegrationRange = config.getInt("nanomachines.disintegrationRange") max 0 val nanomachineDisintegrationRange = config.getInt("nanomachines.disintegrationRange") max 0
val nanomachinePotionWhitelist = config.getAnyRefList("nanomachines.potionWhitelist") val nanomachinePotionWhitelist = config.getAnyRefList("nanomachines.potionWhitelist")

View File

@ -1,5 +1,6 @@
package li.cil.oc.common.item package li.cil.oc.common.item
import li.cil.oc.api
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.EnumAction import net.minecraft.item.EnumAction
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
@ -23,11 +24,12 @@ class Acid(val parent: Delegator) extends traits.Delegate {
player.addPotionEffect(new PotionEffect(Potion.poison.id, 100)) player.addPotionEffect(new PotionEffect(Potion.poison.id, 100))
player.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, 600)) player.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, 600))
player.addPotionEffect(new PotionEffect(Potion.confusion.id, 1200)) player.addPotionEffect(new PotionEffect(Potion.confusion.id, 1200))
player.addPotionEffect(new PotionEffect(Potion.fireResistance.id, 6000))
player.addPotionEffect(new PotionEffect(Potion.saturation.id, 2000)) player.addPotionEffect(new PotionEffect(Potion.saturation.id, 2000))
stack.stackSize -= 1 // Remove nanomachines if installed.
api.Nanomachines.uninstallController(player)
} }
stack.stackSize -= 1
if (stack.stackSize > 0) stack if (stack.stackSize > 0) stack
else null else null
} }

View File

@ -11,9 +11,7 @@ class Nanomachines(val parent: Delegator) extends traits.Delegate {
override def rarity(stack: ItemStack): EnumRarity = EnumRarity.UNCOMMON override def rarity(stack: ItemStack): EnumRarity = EnumRarity.UNCOMMON
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = { override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
if (!api.Nanomachines.hasController(player)) { player.setItemInUse(stack, getMaxItemUseDuration(stack))
player.setItemInUse(stack, getMaxItemUseDuration(stack))
}
stack stack
} }
@ -22,11 +20,11 @@ class Nanomachines(val parent: Delegator) extends traits.Delegate {
override def getMaxItemUseDuration(stack: ItemStack): Int = 32 override def getMaxItemUseDuration(stack: ItemStack): Int = 32
override def onItemUseFinish(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = { override def onItemUseFinish(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
if (!world.isRemote && !api.Nanomachines.hasController(player)) { if (!world.isRemote) {
// Reconfigure if already installed.
api.Nanomachines.installController(player).reconfigure() api.Nanomachines.installController(player).reconfigure()
stack.stackSize -= 1
} }
stack.stackSize -= 1
if (stack.stackSize > 0) stack if (stack.stackSize > 0) stack
else null else null
} }

View File

@ -32,7 +32,7 @@ import scala.collection.mutable
class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessEndpoint { class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessEndpoint {
if (isServer) api.Network.joinWirelessNetwork(this) if (isServer) api.Network.joinWirelessNetwork(this)
final val MaxSenderDistance = 2f lazy val CommandRange = Settings.get.nanomachinesCommandRange * Settings.get.nanomachinesCommandRange
final val FullSyncInterval = 20 * 60 final val FullSyncInterval = 20 * 60
final val OverloadDamage = new DamageSourceWithRandomCause("oc.nanomachinesOverload", 3). final val OverloadDamage = new DamageSourceWithRandomCause("oc.nanomachinesOverload", 3).
@ -41,12 +41,13 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
var uuid = UUID.randomUUID.toString var uuid = UUID.randomUUID.toString
var responsePort = 0 var responsePort = 0
var commandDelay = 0
var queuedCommand: Option[() => Unit] = None
var storedEnergy = Settings.get.bufferNanomachines * 0.25 var storedEnergy = Settings.get.bufferNanomachines * 0.25
var hadPower = true var hadPower = true
val configuration = new NeuralNetwork(this) val configuration = new NeuralNetwork(this)
val activeBehaviors = mutable.Set.empty[Behavior] val activeBehaviors = mutable.Set.empty[Behavior]
var activeBehaviorsDirty = true var activeBehaviorsDirty = true
var configCooldown = 0
var hasSentConfiguration = false var hasSentConfiguration = false
override def world: World = player.getEntityWorld override def world: World = player.getEntityWorld
@ -58,10 +59,10 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
override def z: Int = BlockPosition(player).z override def z: Int = BlockPosition(player).z
override def receivePacket(packet: Packet, sender: WirelessEndpoint): Unit = { override def receivePacket(packet: Packet, sender: WirelessEndpoint): Unit = {
if (getLocalBuffer > 0 && !player.isDead) { if (getLocalBuffer > 0 && commandDelay < 1 && !player.isDead) {
val (dx, dy, dz) = ((sender.x + 0.5) - player.posX, (sender.y + 0.5) - player.posY, (sender.z + 0.5) - player.posZ) val (dx, dy, dz) = ((sender.x + 0.5) - player.posX, (sender.y + 0.5) - player.posY, (sender.z + 0.5) - player.posZ)
val dSquared = dx * dx + dy * dy + dz * dz val dSquared = dx * dx + dy * dy + dz * dz
if (dSquared < MaxSenderDistance * MaxSenderDistance) packet.data.headOption match { if (dSquared <= CommandRange) packet.data.headOption match {
case Some(header: Array[Byte]) if new String(header, Charsets.UTF_8) == "nanomachines" => case Some(header: Array[Byte]) if new String(header, Charsets.UTF_8) == "nanomachines" =>
val command = packet.data.drop(1).map { val command = packet.data.drop(1).map {
case value: Array[Byte] => new String(value, Charsets.UTF_8) case value: Array[Byte] => new String(value, Charsets.UTF_8)
@ -70,17 +71,27 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
command match { command match {
case Array("setResponsePort", port: java.lang.Number) => case Array("setResponsePort", port: java.lang.Number) =>
responsePort = port.intValue max 0 min 0xFFFF responsePort = port.intValue max 0 min 0xFFFF
respond(sender, "responsePort", responsePort) respond(sender, "port", responsePort)
case Array("dispose") => case Array("getPowerState") =>
api.Nanomachines.uninstallController(player) respond(sender, "power", getLocalBuffer, getLocalBufferSize)
respond(sender, "disposed")
case Array("reconfigure") => case Array("getHealth") =>
reconfigure() respond(sender, "health", player.getHealth, player.getMaxHealth)
respond(sender, "reconfigured") case Array("getHunger") =>
respond(sender, "hunger", player.getFoodStats.getFoodLevel, player.getFoodStats.getSaturationLevel)
case Array("getAge") =>
respond(sender, "age", (player.getAge / 20f).toInt)
case Array("getName") =>
respond(sender, "name", player.getDisplayName)
case Array("getExperience") =>
respond(sender, "experience", player.experienceLevel)
case Array("getTotalInputCount") => case Array("getTotalInputCount") =>
respond(sender, "totalInputCount", getTotalInputCount) respond(sender, "totalInputCount", getTotalInputCount)
case Array("getSafeInputCount") => case Array("getSafeActiveInputs") =>
respond(sender, "safeInputCount", getSafeInputCount) respond(sender, "safeActiveInputs", getSafeActiveInputs)
case Array("getMaxActiveInputs") =>
respond(sender, "maxActiveInputs", getMaxActiveInputs)
case Array("getInput", index: java.lang.Number) => case Array("getInput", index: java.lang.Number) =>
try { try {
val trigger = getInput(index.intValue - 1) val trigger = getInput(index.intValue - 1)
@ -92,8 +103,12 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
} }
case Array("setInput", index: java.lang.Number, value: java.lang.Boolean) => case Array("setInput", index: java.lang.Number, value: java.lang.Boolean) =>
try { try {
setInput(index.intValue - 1, value.booleanValue) if (setInput(index.intValue - 1, value.booleanValue)) {
respond(sender, "input", index.intValue, getInput(index.intValue - 1)) respond(sender, "input", index.intValue, getInput(index.intValue - 1))
}
else {
respond(sender, "input", "too many active inputs")
}
} }
catch { catch {
case _: Throwable => case _: Throwable =>
@ -103,10 +118,8 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
configuration.synchronized { configuration.synchronized {
val names = getActiveBehaviors.map(_.getNameHint).filterNot(Strings.isNullOrEmpty) val names = getActiveBehaviors.map(_.getNameHint).filterNot(Strings.isNullOrEmpty)
val joined = "{" + names.map(_.replace(',', '_').replace('"', '_')).mkString(",") + "}" val joined = "{" + names.map(_.replace(',', '_').replace('"', '_')).mkString(",") + "}"
respond(sender, "active", joined) respond(sender, "effects", joined)
} }
case Array("getPowerState") =>
respond(sender, "power", getLocalBuffer, getLocalBufferSize)
case _ => // Ignore. case _ => // Ignore.
} }
case _ => // Not for us. case _ => // Not for us.
@ -115,23 +128,25 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
} }
def respond(endpoint: WirelessEndpoint, data: Any*): Unit = { def respond(endpoint: WirelessEndpoint, data: Any*): Unit = {
if (responsePort > 0) { queuedCommand = Option(() => {
val cost = Settings.get.wirelessCostPerRange * 10 if (responsePort > 0) {
val epsilon = 0.1 val cost = Settings.get.wirelessCostPerRange * CommandRange
if (changeBuffer(-cost) > -epsilon) { val epsilon = 0.1
val packet = api.Network.newPacket(uuid, null, responsePort, (Iterable("nanomachines") ++ data.map(_.asInstanceOf[AnyRef])).toArray) if (changeBuffer(-cost) > -epsilon) {
api.Network.sendWirelessPacket(this, 10, packet) val packet = api.Network.newPacket(uuid, null, responsePort, (Iterable("nanomachines") ++ data.map(_.asInstanceOf[AnyRef])).toArray)
api.Network.sendWirelessPacket(this, CommandRange, packet)
}
} }
} })
commandDelay = (Settings.get.nanomachinesCommandDelay * 20).toInt
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def reconfigure() = { override def reconfigure() = {
if (isServer && configCooldown < 1) configuration.synchronized { if (isServer) configuration.synchronized {
configuration.reconfigure() configuration.reconfigure()
activeBehaviorsDirty = true activeBehaviorsDirty = true
configCooldown = (Settings.get.nanomachineReconfigureTimeout * 20).toInt
player match { player match {
case playerMP: EntityPlayerMP if playerMP.playerNetServerHandler != null => case playerMP: EntityPlayerMP if playerMP.playerNetServerHandler != null =>
@ -149,14 +164,19 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
override def getTotalInputCount: Int = configuration.synchronized(configuration.triggers.length) override def getTotalInputCount: Int = configuration.synchronized(configuration.triggers.length)
override def getSafeInputCount: Int = Settings.get.nanomachinesSafeInputCount override def getSafeActiveInputs: Int = Settings.get.nanomachinesSafeInputsActive
override def getMaxActiveInputs: Int = Settings.get.nanomachinesMaxInputsActive
override def getInput(index: Int): Boolean = configuration.synchronized(configuration.triggers(index).isActive) override def getInput(index: Int): Boolean = configuration.synchronized(configuration.triggers(index).isActive)
override def setInput(index: Int, value: Boolean): Unit = { override def setInput(index: Int, value: Boolean): Boolean = {
if (isServer && configCooldown < 1) configuration.synchronized { isServer && configuration.synchronized {
configuration.triggers(index).isActive = value (!value || configuration.triggers.count(_.isActive) < Settings.get.nanomachinesMaxInputsActive) && {
activeBehaviorsDirty = true configuration.triggers(index).isActive = value
activeBehaviorsDirty = true
true
}
} }
} }
@ -191,14 +211,16 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
} }
if (isServer) { if (isServer) {
if (commandDelay > 0) {
commandDelay -= 1
if (commandDelay == 0) {
queuedCommand.foreach(_())
queuedCommand = None
}
}
api.Network.updateWirelessNetwork(this) api.Network.updateWirelessNetwork(this)
} }
if (configCooldown > 0) {
configCooldown -= 1
return
}
var hasPower = getLocalBuffer > 0 || Settings.get.ignorePower var hasPower = getLocalBuffer > 0 || Settings.get.ignorePower
lazy val active = getActiveBehaviors.toIterable // Wrap once. lazy val active = getActiveBehaviors.toIterable // Wrap once.
lazy val activeInputs = configuration.triggers.count(_.isActive) lazy val activeInputs = configuration.triggers.count(_.isActive)
@ -220,7 +242,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
PacketSender.sendNanomachinePower(player) PacketSender.sendNanomachinePower(player)
} }
val overload = activeInputs - getSafeInputCount val overload = activeInputs - getSafeActiveInputs
if (!player.capabilities.isCreativeMode && overload > 0 && player.getEntityWorld.getTotalWorldTime % 20 == 0) { if (!player.capabilities.isCreativeMode && overload > 0 && player.getEntityWorld.getTotalWorldTime % 20 == 0) {
player.attackEntityFrom(OverloadDamage, overload) player.attackEntityFrom(OverloadDamage, overload)
} }

View File

@ -698,7 +698,10 @@ object Network extends api.detail.NetworkAPI {
acc + (arg match { acc + (arg match {
case null | Unit | None => 4 case null | Unit | None => 4
case _: java.lang.Boolean => 4 case _: java.lang.Boolean => 4
case _: java.lang.Byte => 4
case _: java.lang.Short => 4
case _: java.lang.Integer => 4 case _: java.lang.Integer => 4
case _: java.lang.Float => 8
case _: java.lang.Double => 8 case _: java.lang.Double => 8
case value: java.lang.String => value.length max 1 case value: java.lang.String => value.length max 1
case value: Array[Byte] => value.length max 1 case value: Array[Byte] => value.length max 1