|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
package li.cil.oc
|
|
|
|
|
|
|
|
|
|
import java.io.File
|
|
|
|
|
import li.cil.oc.util.ExtendedConfiguration._
|
|
|
|
|
import li.cil.oc.util.PackedColor
|
|
|
|
|
|
|
|
|
|
object Config {
|
|
|
|
@ -67,7 +68,7 @@ object Config {
|
|
|
|
|
|
|
|
|
|
// server.filesystem
|
|
|
|
|
var fileCost = 512
|
|
|
|
|
var filesBuffered = true
|
|
|
|
|
var bufferChanges = true
|
|
|
|
|
var maxHandles = 16
|
|
|
|
|
var maxReadBuffer = 8 * 1024
|
|
|
|
|
|
|
|
|
@ -84,6 +85,8 @@ object Config {
|
|
|
|
|
var canAttackPlayers = false
|
|
|
|
|
var canPlaceInAir = false
|
|
|
|
|
var itemDamageRate = 0.05
|
|
|
|
|
var swingRange = 0.49
|
|
|
|
|
var useAndPlaceRange = 0.65
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- //
|
|
|
|
|
// robot.delays
|
|
|
|
@ -96,7 +99,6 @@ object Config {
|
|
|
|
|
var turnDelay = 0.4
|
|
|
|
|
var useDelay = 0.4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
def load(file: File) = {
|
|
|
|
@ -121,309 +123,331 @@ object Config {
|
|
|
|
|
config.getCategory("client").
|
|
|
|
|
setComment("Client side settings, presentation and performance related stuff.")
|
|
|
|
|
|
|
|
|
|
maxScreenTextRenderDistance = config.get("client", "maxScreenTextRenderDistance", maxScreenTextRenderDistance, "" +
|
|
|
|
|
"The maximum distance at which to render text on screens. Rendering text\n" +
|
|
|
|
|
"can be pretty expensive, so if you have a lot of screens you'll want\n" +
|
|
|
|
|
"to avoid huge numbers here. Note that this setting is client-sided, and\n" +
|
|
|
|
|
"only has an impact on render performance on clients.").
|
|
|
|
|
getDouble(maxScreenTextRenderDistance)
|
|
|
|
|
maxScreenTextRenderDistance = config.fetch("client.maxScreenTextRenderDistance", maxScreenTextRenderDistance,
|
|
|
|
|
"""|The maximum distance at which to render text on screens. Rendering text
|
|
|
|
|
|can be pretty expensive, so if you have a lot of screens you'll want
|
|
|
|
|
|to avoid huge numbers here. Note that this setting is client-sided, and
|
|
|
|
|
|only has an impact on render performance on clients.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
screenTextFadeStartDistance = config.get("client", "screenTextFadeStartDistance", screenTextFadeStartDistance, "" +
|
|
|
|
|
"The distance at which to start fading out the text on screens. This is\n" +
|
|
|
|
|
"purely cosmetic, to avoid text disappearing instantly when moving too far\n" +
|
|
|
|
|
"away from a screen. This should have no measurable impact on performance.\n" +
|
|
|
|
|
"Note that this needs OpenGL 1.4 to work, otherwise text will always just\n" +
|
|
|
|
|
"instantly disappear when moving away from the screen displaying it.").
|
|
|
|
|
getDouble(screenTextFadeStartDistance)
|
|
|
|
|
screenTextFadeStartDistance = config.fetch("client.screenTextFadeStartDistance", screenTextFadeStartDistance,
|
|
|
|
|
"""|The distance at which to start fading out the text on screens. This is
|
|
|
|
|
|purely cosmetic, to avoid text disappearing instantly when moving too far
|
|
|
|
|
|away from a screen. This should have no measurable impact on performance.
|
|
|
|
|
|Note that this needs OpenGL 1.4 to work, otherwise text will always just
|
|
|
|
|
|instantly disappear when moving away from the screen displaying it.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
textLinearFiltering = config.get("client", "textLinearFiltering", textLinearFiltering, "" +
|
|
|
|
|
"Whether to apply linear filtering for text displayed on screens when the\n" +
|
|
|
|
|
"screen has to be scaled down - i.e. the text is rendered at a resolution\n" +
|
|
|
|
|
"lower than their native one, e.g. when the GUI scale is less than one or\n" +
|
|
|
|
|
"when looking at a far away screen. This leads to smoother text for scaled\n" +
|
|
|
|
|
"down text but results in characters not perfectly connecting anymore (for\n" +
|
|
|
|
|
"example for box drawing characters. Look it up on Wikipedia.)").
|
|
|
|
|
getBoolean(textLinearFiltering)
|
|
|
|
|
textLinearFiltering = config.fetch("client.textLinearFiltering", textLinearFiltering,
|
|
|
|
|
"""|Whether to apply linear filtering for text displayed on screens when the
|
|
|
|
|
|screen has to be scaled down - i.e. the text is rendered at a resolution
|
|
|
|
|
|lower than their native one, e.g. when the GUI scale is less than one or
|
|
|
|
|
|when looking at a far away screen. This leads to smoother text for scaled
|
|
|
|
|
|down text but results in characters not perfectly connecting anymore (for
|
|
|
|
|
|example for box drawing characters. Look it up on Wikipedia.)""".stripMargin)
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
config.getCategory("power").
|
|
|
|
|
setComment("Power settings, buffer sizes and power consumption.")
|
|
|
|
|
|
|
|
|
|
ignorePower = config.get("power", "ignorePower", ignorePower, "" +
|
|
|
|
|
"Whether to ignore any power requirements. Whenever something requires\n" +
|
|
|
|
|
"power to function, it will try to get the amount of energy it needs from\n" +
|
|
|
|
|
"the buffer of its connector node, and in case it fails it won't perform\n" +
|
|
|
|
|
"the action / trigger a shutdown / whatever. Setting this to `true` will\n" +
|
|
|
|
|
"simply make the check 'is there enough energy' succeed unconditionally.\n" +
|
|
|
|
|
"Note that buffers are still filled and emptied following the usual rules,\n" +
|
|
|
|
|
"there just is no failure case anymore.").
|
|
|
|
|
getBoolean(ignorePower)
|
|
|
|
|
ignorePower = config.fetch("power.ignorePower", ignorePower,
|
|
|
|
|
"""|Whether to ignore any power requirements. Whenever something requires
|
|
|
|
|
|power to function, it will try to get the amount of energy it needs from
|
|
|
|
|
|the buffer of its connector node, and in case it fails it won't perform
|
|
|
|
|
|the action / trigger a shutdown / whatever. Setting this to `true` will
|
|
|
|
|
|simply make the check 'is there enough energy' succeed unconditionally.
|
|
|
|
|
|Note that buffers are still filled and emptied following the usual rules,
|
|
|
|
|
|there just is no failure case anymore.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
bufferCapacitor = config.get("power.buffer", "bufferCapacitor", bufferCapacitor, "" +
|
|
|
|
|
"The amount of energy a capacitor can store.").
|
|
|
|
|
getDouble(bufferCapacitor) max 0
|
|
|
|
|
bufferCapacitor = config.fetch("power.buffer.capacitor", bufferCapacitor,
|
|
|
|
|
"""|The amount of energy a capacitor can store.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
bufferConverter = config.get("power.buffer", "bufferConverter", bufferConverter, "" +
|
|
|
|
|
"The amount of energy a power converter can store.").
|
|
|
|
|
getDouble(bufferConverter) max 0
|
|
|
|
|
bufferConverter = config.fetch("power.buffer.converter", bufferConverter,
|
|
|
|
|
"""|The amount of energy a power converter can store.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
bufferPowerSupply = config.get("power.buffer", "bufferPowerSupply", bufferPowerSupply, "" +
|
|
|
|
|
"The amount of energy a power supply can store.").
|
|
|
|
|
getDouble(bufferPowerSupply) max 0
|
|
|
|
|
bufferPowerSupply = config.fetch("power.buffer.powerSupply", bufferPowerSupply,
|
|
|
|
|
"""|The amount of energy a power supply can store.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
computerCost = config.get("power.cost", "computerCost", computerCost, "" +
|
|
|
|
|
"The amount of energy a computer consumes per tick when running.").
|
|
|
|
|
getDouble(computerCost) max 0
|
|
|
|
|
computerCost = config.fetch("power.cost.computer", computerCost,
|
|
|
|
|
"""|The amount of energy a computer consumes per tick when running.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
gpuFillCost = config.get("power.cost", "gpuFillCost", gpuFillCost, "" +
|
|
|
|
|
"Energy it takes to change a single 'pixel' via the fill command. This\n" +
|
|
|
|
|
"means the total cost of the fill command will be its area times this.").
|
|
|
|
|
getDouble(gpuFillCost) max 0
|
|
|
|
|
gpuFillCost = config.fetch("power.cost.gpuFill", gpuFillCost,
|
|
|
|
|
"""|Energy it takes to change a single 'pixel' via the fill command. This
|
|
|
|
|
|means the total cost of the fill command will be its area times this.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
gpuClearCost = config.get("power.cost", "gpuClearCost", gpuClearCost, "" +
|
|
|
|
|
"Energy it takes to change a single 'pixel' to blank using the fill\n" +
|
|
|
|
|
"command. This means the total cost of the fill command will be its\n" +
|
|
|
|
|
"area times this.").
|
|
|
|
|
getDouble(gpuClearCost) max 0
|
|
|
|
|
gpuClearCost = config.fetch("power.cost.gpuClear", gpuClearCost,
|
|
|
|
|
"""|Energy it takes to change a single 'pixel' to blank using the fill
|
|
|
|
|
|command. This means the total cost of the fill command will be its
|
|
|
|
|
|area times this.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
gpuCopyCost = config.get("power.cost", "gpuCopyCost", gpuCopyCost, "" +
|
|
|
|
|
"Energy it takes to move a single 'pixel' via the copy command. This\n" +
|
|
|
|
|
"means the total cost of the copy command will be its area times this.").
|
|
|
|
|
getDouble(gpuCopyCost) max 0
|
|
|
|
|
gpuCopyCost = config.fetch("power.cost.gpuCopy", gpuCopyCost,
|
|
|
|
|
"""|Energy it takes to move a single 'pixel' via the copy command. This
|
|
|
|
|
|means the total cost of the copy command will be its area times this.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
gpuSetCost = config.get("power.cost", "gpuSetCost", gpuSetCost, "" +
|
|
|
|
|
"Energy it takes to change a single 'pixel' via the set command. For\n" +
|
|
|
|
|
"calls to set with a string, this means the total cost will be the\n" +
|
|
|
|
|
"string length times this.").
|
|
|
|
|
getDouble(gpuSetCost) max 0
|
|
|
|
|
gpuSetCost = config.fetch("power.cost.gpuSet", gpuSetCost,
|
|
|
|
|
"""|Energy it takes to change a single 'pixel' via the set command. For
|
|
|
|
|
|calls to set with a string, this means the total cost will be the
|
|
|
|
|
|string length times this.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
hddReadCost = config.get("power.cost", "hddReadCost", hddReadCost, "" +
|
|
|
|
|
"Energy it takes read a single byte from a file system. Note that non\n" +
|
|
|
|
|
"I/O operations on file systems such as `list` or `getFreeSpace` do\n" +
|
|
|
|
|
"*not* consume power.").
|
|
|
|
|
getDouble(hddReadCost) max 0
|
|
|
|
|
hddReadCost = config.fetch("power.cost.hddRead", hddReadCost,
|
|
|
|
|
"""|Energy it takes read a single byte from a file system. Note that non
|
|
|
|
|
|I/O operations on file systems such as `list` or `getFreeSpace` do
|
|
|
|
|
|*not* consume power.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
hddWriteCost = config.get("power.cost", "hddWriteCost", hddWriteCost, "" +
|
|
|
|
|
"Energy it takes to write a single byte to a file system.").
|
|
|
|
|
getDouble(hddWriteCost) max 0
|
|
|
|
|
hddWriteCost = config.fetch("power.cost.hddWrite", hddWriteCost,
|
|
|
|
|
"""|Energy it takes to write a single byte to a file system.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
powerSupplyCost = config.get("power.cost", "powerSupplyCost", powerSupplyCost, "" +
|
|
|
|
|
"The amount of energy a power supply (item) produces per tick. This is\n" +
|
|
|
|
|
"basically just a consumer, but instead of taking energy it puts it\n" +
|
|
|
|
|
"back into the network. This is slightly more than what a computer\n" +
|
|
|
|
|
"consumes per tick. It's meant as an easy way to powering a small\n" +
|
|
|
|
|
"setup, mostly for testing. ").
|
|
|
|
|
getDouble(powerSupplyCost)
|
|
|
|
|
powerSupplyCost = config.fetch("power.cost.powerSupply", powerSupplyCost,
|
|
|
|
|
"""|The amount of energy a power supply (item) produces per tick. This is
|
|
|
|
|
|basically just a consumer, but instead of taking energy it puts it
|
|
|
|
|
|back into the network. This is slightly more than what a computer
|
|
|
|
|
|consumes per tick. It's meant as an easy way to powering a small
|
|
|
|
|
|setup, mostly for testing.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
screenCost = config.get("power.cost", "screenCost", screenCost, "" +
|
|
|
|
|
"The amount of energy a screen consumes per tick. If a screen cannot\n" +
|
|
|
|
|
"consume the defined amount of energy it will stop rendering the text\n" +
|
|
|
|
|
"that should be displayed on it. It will *not* forget that text,\n" +
|
|
|
|
|
"however, so when enough power is available again it will restore the\n" +
|
|
|
|
|
"previously displayed text (with any changes possibly made in the\n" +
|
|
|
|
|
"meantime). Note that for multi-block screens *each* screen that is\n" +
|
|
|
|
|
"part of it will consume this amount of energy per tick.").
|
|
|
|
|
getDouble(screenCost) max 0
|
|
|
|
|
screenCost = config.fetch("power.cost.screen", screenCost,
|
|
|
|
|
"""|The amount of energy a screen consumes per displayed character per
|
|
|
|
|
|tick. If a screen cannot consume the defined amount of energy it will
|
|
|
|
|
|stop rendering the text that should be displayed on it. It will *not*
|
|
|
|
|
|forget that text, however, so when enough power is available again it
|
|
|
|
|
|will restore the previously displayed text (with any changes possibly
|
|
|
|
|
|made in the meantime). Note that for multi-block screens *each*
|
|
|
|
|
|screen that is part of it will consume this amount of energy per
|
|
|
|
|
|tick.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
wirelessCostPerRange = config.get("power.cost", "wirelessCostPerRange", wirelessCostPerRange, "" +
|
|
|
|
|
"The amount of energy it costs to send a signal with strength one,\n" +
|
|
|
|
|
"which means the signal reaches one block. This is scaled up linearly,\n" +
|
|
|
|
|
"so for example to send a signal 400 blocks a signal strength of 400\n" +
|
|
|
|
|
"is required, costing a total of 400 * `wirelessCostPerRange`. In\n" +
|
|
|
|
|
"other words, the higher this value, the higher the cost of wireless\n" +
|
|
|
|
|
"messages.\n" +
|
|
|
|
|
"See also: `maxWirelessRange`.").
|
|
|
|
|
getDouble(wirelessCostPerRange) max 0
|
|
|
|
|
wirelessCostPerRange = config.fetch("power.cost.wirelessStrength", wirelessCostPerRange,
|
|
|
|
|
"""|The amount of energy it costs to send a signal with strength one,
|
|
|
|
|
|which means the signal reaches one block. This is scaled up linearly,
|
|
|
|
|
|so for example to send a signal 400 blocks a signal strength of 400
|
|
|
|
|
|is required, costing a total of 400 * `wirelessCostPerRange`. In
|
|
|
|
|
|other words, the higher this value, the higher the cost of wireless
|
|
|
|
|
|messages.[nl]
|
|
|
|
|
|See also: `maxWirelessRange`.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
config.getCategory("server").
|
|
|
|
|
setComment("Server side settings, gameplay and security related stuff.")
|
|
|
|
|
|
|
|
|
|
baseMemory = config.get("server.computer", "baseMemory", baseMemory, "" +
|
|
|
|
|
"The base amount of memory made available in computers even if they\n" +
|
|
|
|
|
"have no RAM installed. Use this if you feel you can't get enough RAM\n" +
|
|
|
|
|
"using the given means, that being RAM components. Just keep in mind\n" +
|
|
|
|
|
"that this is global and applies to all computers!").
|
|
|
|
|
getInt(baseMemory)
|
|
|
|
|
baseMemory = config.fetch("server.computer.baseMemory", baseMemory,
|
|
|
|
|
"""|The base amount of memory made available in computers even if they
|
|
|
|
|
|have no RAM installed. Use this if you feel you can't get enough RAM
|
|
|
|
|
|using the given means, that being RAM components. Just keep in mind
|
|
|
|
|
|that this is global and applies to all computers!""".stripMargin)
|
|
|
|
|
|
|
|
|
|
canComputersBeOwned = config.get("server.computer", "canComputersBeOwned", canComputersBeOwned, "" +
|
|
|
|
|
"This determines whether computers can only be used by players that\n" +
|
|
|
|
|
"are registered as users on them. Per default a newly placed computer\n" +
|
|
|
|
|
"has no users. Whenever there are no users the computer is free for\n" +
|
|
|
|
|
"all. Users can be managed via the Lua API (os.addUser, os.removeUser,\n" +
|
|
|
|
|
"os.users). If this is true, the following interactions are only\n" +
|
|
|
|
|
"possible for users:\n" +
|
|
|
|
|
" - input via the keyboard.\n" +
|
|
|
|
|
" - inventory management.\n" +
|
|
|
|
|
" - breaking the computer block.\n" +
|
|
|
|
|
"If this is set to false, all computers will always be usable by all\n" +
|
|
|
|
|
"players, no matter the contents of the user list. Note that operators\n" +
|
|
|
|
|
"are treated as if they were in the user list of every computer, i.e.\n" +
|
|
|
|
|
"no restrictions apply to them.\n" +
|
|
|
|
|
"See also: `maxUsers` and `maxUsernameLength`.").
|
|
|
|
|
getBoolean(canComputersBeOwned)
|
|
|
|
|
canComputersBeOwned = config.fetch("server.computer.canComputersBeOwned", canComputersBeOwned,
|
|
|
|
|
"""|This determines whether computers can only be used by players that
|
|
|
|
|
|are registered as users on them. Per default a newly placed computer
|
|
|
|
|
|has no users. Whenever there are no users the computer is free for
|
|
|
|
|
|all. Users can be managed via the Lua API (os.addUser, os.removeUser,
|
|
|
|
|
|os.users). If this is true, the following interactions are only
|
|
|
|
|
|possible for users:[nl]
|
|
|
|
|
| - input via the keyboard.[nl]
|
|
|
|
|
| - inventory management.[nl]
|
|
|
|
|
| - breaking the computer block.[nl]
|
|
|
|
|
|If this is set to false, all computers will always be usable by all
|
|
|
|
|
|players, no matter the contents of the user list. Note that operators
|
|
|
|
|
|are treated as if they were in the user list of every computer, i.e.
|
|
|
|
|
|no restrictions apply to them.[nl]
|
|
|
|
|
|See also: `maxUsers` and `maxUsernameLength`.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
maxUsernameLength = config.get("server.computer", "maxUsernameLength", maxUsernameLength, "" +
|
|
|
|
|
"Sanity check for username length for users registered with computers.\n" +
|
|
|
|
|
"We store the actual user names instead of a hash to allow iterating\n" +
|
|
|
|
|
"the list of registered users on the Lua side.\n" +
|
|
|
|
|
"See also: `canComputersBeOwned`.").
|
|
|
|
|
getInt(maxUsernameLength) max 0
|
|
|
|
|
maxUsernameLength = config.fetch("server.computer.maxUsernameLength", maxUsernameLength,
|
|
|
|
|
"""|Sanity check for username length for users registered with computers.
|
|
|
|
|
|We store the actual user names instead of a hash to allow iterating
|
|
|
|
|
|the list of registered users on the Lua side.[nl]
|
|
|
|
|
|See also: `canComputersBeOwned`.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
maxUsers = config.get("server.computer", "maxUsers", maxUsers, "" +
|
|
|
|
|
"The maximum number of users that can be registered with a single\n" +
|
|
|
|
|
"computer. This is used to avoid computers allocating unchecked\n" +
|
|
|
|
|
"amounts of memory by registering an unlimited number of users.\n" +
|
|
|
|
|
"See also: `canComputersBeOwned`.").
|
|
|
|
|
getInt(maxUsers) max 0
|
|
|
|
|
maxUsers = config.fetch("server.computer.maxUsers", maxUsers,
|
|
|
|
|
"""|The maximum number of users that can be registered with a single
|
|
|
|
|
|computer. This is used to avoid computers allocating unchecked
|
|
|
|
|
|amounts of memory by registering an unlimited number of users.
|
|
|
|
|
|See also: `canComputersBeOwned`.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
startupDelay = config.get("server.computer", "startupDelay", startupDelay, "" +
|
|
|
|
|
"The time in seconds to wait after a computer has been restored before\n" +
|
|
|
|
|
"it continues to run. This is meant to allow the world around the\n" +
|
|
|
|
|
"computer to settle, avoiding issues such as components in neighboring\n" +
|
|
|
|
|
"chunks being removed and then re-connected and other odd things that\n" +
|
|
|
|
|
"might happen.").
|
|
|
|
|
getDouble(startupDelay) max 0
|
|
|
|
|
startupDelay = config.fetch("server.computer.startupDelay", startupDelay,
|
|
|
|
|
"""|The time in seconds to wait after a computer has been restored before
|
|
|
|
|
|it continues to run. This is meant to allow the world around the
|
|
|
|
|
|computer to settle, avoiding issues such as components in neighboring
|
|
|
|
|
|chunks being removed and then re-connected and other odd things that
|
|
|
|
|
|might happen.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
threads = config.get("server.computer", "threads", threads, "" +
|
|
|
|
|
"The overall number of threads to use to drive computers. Whenever a\n" +
|
|
|
|
|
"computer should run, for example because a signal should be processed\n" +
|
|
|
|
|
"or some sleep timer expired it is queued for execution by a worker\n" +
|
|
|
|
|
"thread. The higher the number of worker threads, the less likely it\n" +
|
|
|
|
|
"will be that computers block each other from running, but the higher\n" +
|
|
|
|
|
"the host system's load may become.").
|
|
|
|
|
getInt(threads) max 1
|
|
|
|
|
threads = config.fetch("server.computer.threads", threads,
|
|
|
|
|
"""|The overall number of threads to use to drive computers. Whenever a
|
|
|
|
|
|computer should run, for example because a signal should be processed
|
|
|
|
|
|or some sleep timer expired it is queued for execution by a worker
|
|
|
|
|
|thread. The higher the number of worker threads, the less likely it
|
|
|
|
|
|will be that computers block each other from running, but the higher
|
|
|
|
|
|the host system's load may become.""".stripMargin) max 1
|
|
|
|
|
|
|
|
|
|
timeout = config.get("server.computer", "timeout", timeout, "" +
|
|
|
|
|
"The time in seconds a program may run without yielding before it is\n" +
|
|
|
|
|
"forcibly aborted. This is used to avoid stupidly written or malicious\n" +
|
|
|
|
|
"programs blocking other computers by locking down the executor\n" +
|
|
|
|
|
"threads. Note that changing this won't have any effect on computers\n" +
|
|
|
|
|
"that are already running - they'll have to be rebooted for this to\n" +
|
|
|
|
|
"take effect.").
|
|
|
|
|
getDouble(timeout) max 0
|
|
|
|
|
timeout = config.fetch("server.computer.timeout", timeout,
|
|
|
|
|
"""|The time in seconds a program may run without yielding before it is
|
|
|
|
|
|forcibly aborted. This is used to avoid stupidly written or malicious
|
|
|
|
|
|programs blocking other computers by locking down the executor
|
|
|
|
|
|threads. Note that changing this won't have any effect on computers
|
|
|
|
|
|that are already running - they'll have to be rebooted for this to
|
|
|
|
|
|take effect.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
fileCost = config.get("server.filesystem", "fileCost", fileCost, "" +
|
|
|
|
|
"The base 'cost' of a single file or directory on a limited file\n" +
|
|
|
|
|
"system, such as hard drives. When computing the used space we add\n" +
|
|
|
|
|
"this cost to the real size of each file (and folders, which are zero\n" +
|
|
|
|
|
"sized otherwise). This is to ensure that users cannot spam the file\n" +
|
|
|
|
|
"system with an infinite number of files and/or folders. Note that the\n" +
|
|
|
|
|
"size returned via the API will always be the real file size, however.").
|
|
|
|
|
getInt(fileCost) max 0
|
|
|
|
|
fileCost = config.fetch("server.filesystem.fileCost", fileCost,
|
|
|
|
|
"""|The base 'cost' of a single file or directory on a limited file
|
|
|
|
|
|system, such as hard drives. When computing the used space we add
|
|
|
|
|
|this cost to the real size of each file (and folders, which are zero
|
|
|
|
|
|sized otherwise). This is to ensure that users cannot spam the file
|
|
|
|
|
|system with an infinite number of files and/or folders. Note that the
|
|
|
|
|
|size returned via the API will always be the real file size, however.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
filesBuffered = config.get("server.filesystem", "filesBuffered", filesBuffered, "" +
|
|
|
|
|
"Whether persistent file systems such as disk drivers should be\n" +
|
|
|
|
|
"'buffered', and only written to disk when the world is saved. This\n" +
|
|
|
|
|
"applies to all hard drives. The advantage of having this enabled is\n" +
|
|
|
|
|
"that data will never go 'out of sync' with the computer's state if\n" +
|
|
|
|
|
"the game crashes. The price is slightly higher memory consumption,\n" +
|
|
|
|
|
"since all loaded files have to be kept in memory (loaded as in when\n" +
|
|
|
|
|
"the hard drive is in a computer).").
|
|
|
|
|
getBoolean(filesBuffered)
|
|
|
|
|
bufferChanges = config.fetch("server.filesystem.bufferChanges", bufferChanges,
|
|
|
|
|
"""|Whether persistent file systems such as disk drivers should be
|
|
|
|
|
|'buffered', and only written to disk when the world is saved. This
|
|
|
|
|
|applies to all hard drives. The advantage of having this enabled is
|
|
|
|
|
|that data will never go 'out of sync' with the computer's state if
|
|
|
|
|
|the game crashes. The price is slightly higher memory consumption,
|
|
|
|
|
|since all loaded files have to be kept in memory (loaded as in when
|
|
|
|
|
|the hard drive is in a computer).""".stripMargin)
|
|
|
|
|
|
|
|
|
|
maxHandles = config.get("server.filesystem", "maxHandles", maxHandles, "" +
|
|
|
|
|
"The maximum number of file handles any single computer may have open\n" +
|
|
|
|
|
"at a time. Note that this is *per filesystem*. Also note that this is\n" +
|
|
|
|
|
"only enforced by the filesystem node - if an add-on decides to be\n" +
|
|
|
|
|
"fancy it may well ignore this. Since file systems are usually\n" +
|
|
|
|
|
"'virtual' this will usually not have any real impact on performance\n" +
|
|
|
|
|
"and won't be noticeable on the host operating system.")
|
|
|
|
|
.getInt(maxHandles) max 0
|
|
|
|
|
maxHandles = config.fetch("server.filesystem.maxHandles", maxHandles,
|
|
|
|
|
"""|The maximum number of file handles any single computer may have open
|
|
|
|
|
|at a time. Note that this is *per filesystem*. Also note that this is
|
|
|
|
|
|only enforced by the filesystem node - if an add-on decides to be
|
|
|
|
|
|fancy it may well ignore this. Since file systems are usually
|
|
|
|
|
|'virtual' this will usually not have any real impact on performance
|
|
|
|
|
|and won't be noticeable on the host operating system.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
maxReadBuffer = config.get("server.filesystem", "maxReadBuffer", maxReadBuffer, "" +
|
|
|
|
|
"The maximum block size that can be read in one 'read' call on a file\n" +
|
|
|
|
|
"system. This is used to limit the amount of memory a call from a user\n" +
|
|
|
|
|
"program can cause to be allocated on the host side: when 'read' is,\n" +
|
|
|
|
|
"called a byte array with the specified size has to be allocated. So\n" +
|
|
|
|
|
"if this weren't limited, a Lua program could trigger massive memory\n" +
|
|
|
|
|
"allocations regardless of the amount of RAM installed in the computer\n" +
|
|
|
|
|
"it runs on. As a side effect this pretty much determines the read\n" +
|
|
|
|
|
"performance of file systems.")
|
|
|
|
|
.getInt(maxReadBuffer) max 0
|
|
|
|
|
maxReadBuffer = config.fetch("server.filesystem.maxReadBuffer", maxReadBuffer,
|
|
|
|
|
"""|The maximum block size that can be read in one 'read' call on a file
|
|
|
|
|
|system. This is used to limit the amount of memory a call from a user
|
|
|
|
|
|program can cause to be allocated on the host side: when 'read' is,
|
|
|
|
|
|called a byte array with the specified size has to be allocated. So
|
|
|
|
|
|if this weren't limited, a Lua program could trigger massive memory
|
|
|
|
|
|allocations regardless of the amount of RAM installed in the computer
|
|
|
|
|
|it runs on. As a side effect this pretty much determines the read
|
|
|
|
|
|performance of file systems.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
commandUser = config.get("server.misc", "commandUser", commandUser, "" +
|
|
|
|
|
"The user name to specify when executing a command via a command\n" +
|
|
|
|
|
"block. If you leave this empty it will use the address of the network\n" +
|
|
|
|
|
"node that sent the execution request - which will usually be a\n" +
|
|
|
|
|
"computer.").
|
|
|
|
|
getString.trim
|
|
|
|
|
commandUser = config.fetch("server.misc.commandUser", commandUser,
|
|
|
|
|
"""|The user name to specify when executing a command via a command
|
|
|
|
|
|block. If you leave this empty it will use the address of the network
|
|
|
|
|
|node that sent the execution request - which will usually be a
|
|
|
|
|
|computer.""".stripMargin).trim
|
|
|
|
|
|
|
|
|
|
maxScreenHeight = config.get("server.misc", "maxScreenHeight", maxScreenHeight, "" +
|
|
|
|
|
"The maximum height of multi-block screens, in blocks. This is limited\n" +
|
|
|
|
|
"to avoid excessive computations for merging screens. If you really\n" +
|
|
|
|
|
"need bigger screens it's probably safe to bump this quite a bit\n" +
|
|
|
|
|
"before you notice anything, since at least incremental updates should\n" +
|
|
|
|
|
"be very efficient (i.e. when adding/removing a single screen).")
|
|
|
|
|
.getInt(maxScreenHeight) max 1
|
|
|
|
|
maxScreenHeight = config.fetch("server.misc.maxScreenHeight", maxScreenHeight,
|
|
|
|
|
"""|The maximum height of multi-block screens, in blocks. This is limited
|
|
|
|
|
|to avoid excessive computations for merging screens. If you really
|
|
|
|
|
|need bigger screens it's probably safe to bump this quite a bit
|
|
|
|
|
|before you notice anything, since at least incremental updates should
|
|
|
|
|
|be very efficient (i.e. when adding/removing a single screen).""".stripMargin) max 1
|
|
|
|
|
|
|
|
|
|
maxScreenWidth = config.get("server.misc", "maxScreenWidth", maxScreenWidth, "" +
|
|
|
|
|
"The maximum width of multi-block screens, in blocks.\n" +
|
|
|
|
|
"See also: `maxScreenHeight`.")
|
|
|
|
|
.getInt(maxScreenWidth) max 1
|
|
|
|
|
maxScreenWidth = config.fetch("server.misc.maxScreenWidth", maxScreenWidth,
|
|
|
|
|
"""|The maximum width of multi-block screens, in blocks.[nl]
|
|
|
|
|
|See also: `maxScreenHeight`.""".stripMargin) max 1
|
|
|
|
|
|
|
|
|
|
maxWirelessRange = config.get("server.misc", "maxWirelessRange", maxWirelessRange, "" +
|
|
|
|
|
"The maximum distance a wireless message can be sent. In other words,\n" +
|
|
|
|
|
"this is the maximum signal strength a wireless network card supports.\n" +
|
|
|
|
|
"This is used to limit the search range in which to check for modems,\n" +
|
|
|
|
|
"which may or may not lead to performance issues for ridiculous\n" +
|
|
|
|
|
"ranges - like, you know, more than the loaded area.\n" +
|
|
|
|
|
"See also: `wirelessCostPerRange`.").
|
|
|
|
|
getDouble(maxWirelessRange) max 0
|
|
|
|
|
maxWirelessRange = config.fetch("server.misc.maxWirelessRange", maxWirelessRange,
|
|
|
|
|
"""|The maximum distance a wireless message can be sent. In other words,
|
|
|
|
|
|this is the maximum signal strength a wireless network card supports.
|
|
|
|
|
|This is used to limit the search range in which to check for modems,
|
|
|
|
|
|which may or may not lead to performance issues for ridiculous
|
|
|
|
|
|ranges - like, you know, more than the loaded area.[nl]
|
|
|
|
|
|See also: `wirelessCostPerRange`.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
config.getCategory("robot").
|
|
|
|
|
setComment("Robot related settings, what they may do and general balancing.")
|
|
|
|
|
|
|
|
|
|
allowActivateBlocks = config.get("robot", "allowActivateBlocks", allowActivateBlocks, "" +
|
|
|
|
|
"Whether robots may 'activate' blocks in the world. This includes\n" +
|
|
|
|
|
"pressing buttons and flipping switches, for example. Disable this if\n" +
|
|
|
|
|
"it causes problems with some mod (but let me know!) or if you think\n" +
|
|
|
|
|
"this feature is too over-powered.").
|
|
|
|
|
getBoolean(allowActivateBlocks)
|
|
|
|
|
allowActivateBlocks = config.fetch("robot.allowActivateBlocks", allowActivateBlocks,
|
|
|
|
|
"""|Whether robots may 'activate' blocks in the world. This includes
|
|
|
|
|
|pressing buttons and flipping levers, for example. Disable this if
|
|
|
|
|
|it causes problems with some mod (but let me know!) or if you think
|
|
|
|
|
|this feature is too over-powered.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
canAttackPlayers = config.get("robot", "canAttackPlayers", canAttackPlayers, "" +
|
|
|
|
|
"Whether robots may damage players if they get in their way. This\n" +
|
|
|
|
|
"includes all 'player' entities, which may be more than just real\n" +
|
|
|
|
|
"players in the game.").
|
|
|
|
|
getBoolean(canAttackPlayers)
|
|
|
|
|
canAttackPlayers = config.fetch("robot.canAttackPlayers", canAttackPlayers,
|
|
|
|
|
"""|Whether robots may damage players if they get in their way. This
|
|
|
|
|
|includes all 'player' entities, which may be more than just real
|
|
|
|
|
|players in the game.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
canPlaceInAir = config.get("robot", "canPlaceInAir", canPlaceInAir, "" +
|
|
|
|
|
"Whether robots may place blocks in thin air, i.e. without a reference\n" +
|
|
|
|
|
"point (as is required for real players). Set this to true to emulate\n" +
|
|
|
|
|
"ComputerCraft's Turtles' behavior. When left false robots have to\n" +
|
|
|
|
|
"target an existing block face to place another block. For example,\n" +
|
|
|
|
|
"if the robots stands on a perfect plain, you have to call\n" +
|
|
|
|
|
"`robot.place(sides.down)` to place a block, instead of just\n" +
|
|
|
|
|
"`robot.place()`, which will default to `robot.place(sides.front)`.").
|
|
|
|
|
getBoolean(canPlaceInAir)
|
|
|
|
|
canPlaceInAir = config.fetch("robot.canPlaceInAir", canPlaceInAir,
|
|
|
|
|
"""|Whether robots may place blocks in thin air, i.e. without a reference
|
|
|
|
|
|point (as is required for real players). Set this to true to emulate
|
|
|
|
|
|ComputerCraft's Turtles' behavior. When left false robots have to
|
|
|
|
|
|target an existing block face to place another block. For example,
|
|
|
|
|
|if the robots stands on a perfect plane, you have to call
|
|
|
|
|
|`robot.place(sides.down)` to place a block, instead of just
|
|
|
|
|
|`robot.place()`, which will default to `robot.place(sides.front)`.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
itemDamageRate = config.get("robot", "itemDamageRate", itemDamageRate, "" +
|
|
|
|
|
"The rate at which items used as tools by robots take damage. A value\n" +
|
|
|
|
|
"of one means that items lose durability as quickly as when they are\n" +
|
|
|
|
|
"used by a real player. A value of zero means they will not lose any\n" +
|
|
|
|
|
"durability at all. This only applies to items that can actually be\n" +
|
|
|
|
|
"damaged (such as swords, pickaxes, axes and shovels).\n" +
|
|
|
|
|
"Note that this actually is the *chance* of an item losing durability\n" +
|
|
|
|
|
"when it is used. Or in other words, it's the inverse chance that the\n" +
|
|
|
|
|
"item will be automatically repaired for the damage it just took\n" +
|
|
|
|
|
"immediately after it was used.").
|
|
|
|
|
getDouble(itemDamageRate) max 0 min 1
|
|
|
|
|
itemDamageRate = config.fetch("robot.itemDamageRate", itemDamageRate,
|
|
|
|
|
"""|The rate at which items used as tools by robots take damage. A value
|
|
|
|
|
|of one means that items lose durability as quickly as when they are
|
|
|
|
|
|used by a real player. A value of zero means they will not lose any
|
|
|
|
|
|durability at all. This only applies to items that can actually be
|
|
|
|
|
|damaged (such as swords, pickaxes, axes and shovels).[nl]
|
|
|
|
|
|Note that this actually is the *chance* of an item losing durability
|
|
|
|
|
|when it is used. Or in other words, it's the inverse chance that the
|
|
|
|
|
|item will be automatically repaired for the damage it just took
|
|
|
|
|
|immediately after it was used.""".stripMargin) max 0 min 1
|
|
|
|
|
|
|
|
|
|
swingRange = config.fetch("robot.swingRange", swingRange,
|
|
|
|
|
"""|The 'range' of robots when swinging an equipped tool (left click).
|
|
|
|
|
|This is the distance to the center of block the robot swings the
|
|
|
|
|
|tool in to the side the tool is swung towards. I.e. for the collision
|
|
|
|
|
|check, which is performed via ray tracing, this determines the end
|
|
|
|
|
|point of the ray like so:[nl]
|
|
|
|
|
|`block_center + unit_vector_towards_side * swingRange`[nl]
|
|
|
|
|
|This defaults to a value just below 0.5 to ensure the robots will not
|
|
|
|
|
|hit anything that's actually outside said block.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
useAndPlaceRange = config.fetch("robot.useAndPlaceRange", useAndPlaceRange,
|
|
|
|
|
"""|The 'range' of robots when using an equipped tool (right click) or
|
|
|
|
|
|when placing items from their inventory. See `robot.swingRange`. This
|
|
|
|
|
|defaults to a value large enough to allow robots to detect 'farmland',
|
|
|
|
|
|i.e. tilled dirt, so that they can plant seeds.""".stripMargin)
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- //
|
|
|
|
|
// robot.delays
|
|
|
|
|
|
|
|
|
|
dropDelay = config.fetch("robot.delays.drop", dropDelay,
|
|
|
|
|
"""|The time in seconds to pause execution after an item was successfully
|
|
|
|
|
|dropped from a robot's inventory.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
moveDelay = config.fetch("robot.delays.move", moveDelay,
|
|
|
|
|
"""|The time in seconds to pause execution after a robot issued a
|
|
|
|
|
|successful move command. Note that this essentially determines how
|
|
|
|
|
|fast robots can move around, since this also determines the length of
|
|
|
|
|
|the move animation.""".stripMargin) max 0.1
|
|
|
|
|
|
|
|
|
|
placeDelay = config.fetch("robot.delays.place", placeDelay,
|
|
|
|
|
"""|The time in seconds to pause execution after a robot successfully
|
|
|
|
|
|placed an item from its inventory.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
suckDelay = config.fetch("robot.delays.suck", suckDelay,
|
|
|
|
|
"""|The time in seconds to pause execution after a robot successfully
|
|
|
|
|
|picked up an item after triggering a suck command.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
swingDelay = config.fetch("robot.delays.swing", swingDelay,
|
|
|
|
|
"""|The time in seconds to pause execution after a robot successfully
|
|
|
|
|
|swung a tool (or it's 'hands' if nothing is equipped). Successful in
|
|
|
|
|
|this case means that it hit something, either by attacking an entity
|
|
|
|
|
|or by breaking a block.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
turnDelay = config.fetch("robot.delays.turn", turnDelay,
|
|
|
|
|
"""|The time in seconds to pause execution after a robot turned either
|
|
|
|
|
|left or right. Note that this essentially determines hw fast robots
|
|
|
|
|
|can turn around, since this also determines the length of the turn
|
|
|
|
|
|animation.""".stripMargin) max 0.1
|
|
|
|
|
|
|
|
|
|
useDelay = config.fetch("robot.delays.use", useDelay,
|
|
|
|
|
"""|The time in seconds to pause execution after a robot successfully
|
|
|
|
|
|used an equipped tool (or it's 'hands' if nothing is equipped).
|
|
|
|
|
|Successful in this case means that it either used the equipped item,
|
|
|
|
|
|for example bone meal, or that it activated a block, for example by
|
|
|
|
|
|pushing a button.""".stripMargin) max 0
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
if (config.hasChanged)
|
|
|
|
|
if (config.hasChanged) {
|
|
|
|
|
config.save()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|