diff --git a/li/cil/oc/Settings.scala b/li/cil/oc/Settings.scala index 5254b7dc8..6ff0e98d8 100644 --- a/li/cil/oc/Settings.scala +++ b/li/cil/oc/Settings.scala @@ -37,6 +37,7 @@ class Settings(config: Config) { OpenComputers.log.warning("Bad number of RAM sizes, ignoring.") Array(64, 128, 256) } + val ramScaleFor64Bit = config.getDouble("computer.ramScaleFor64Bit") max 1 val canComputersBeOwned = config.getBoolean("computer.canComputersBeOwned") val maxUsers = config.getInt("computer.maxUsers") max 0 val maxUsernameLength = config.getInt("computer.maxUsernameLength") max 0 @@ -82,7 +83,7 @@ class Settings(config: Config) { // power val ignorePower = config.getBoolean("power.ignorePower") - val tickFrequency = config.getDouble("power.tickFrequency") + val tickFrequency = config.getDouble("power.tickFrequency") max 1 val ratioBuildCraft = config.getDouble("power.ratioBuildCraft").toFloat val ratioIndustrialCraft2 = config.getDouble("power.ratioIndustrialCraft2").toFloat val ratioUniversalElectricity = config.getDouble("power.ratioUniversalElectricity").toFloat @@ -100,12 +101,12 @@ class Settings(config: Config) { val robotCost = config.getDouble("power.cost.robot") max 0 val sleepCostFactor = config.getDouble("power.cost.sleepFactor") max 0 val screenCost = config.getDouble("power.cost.screen") max 0 - val hddReadCost = config.getDouble("power.cost.hddRead") max 0 - val hddWriteCost = config.getDouble("power.cost.hddWrite") max 0 - val gpuSetCost = config.getDouble("power.cost.gpuSet") max 0 - val gpuFillCost = config.getDouble("power.cost.gpuFill") max 0 - val gpuClearCost = config.getDouble("power.cost.gpuClear") max 0 - val gpuCopyCost = config.getDouble("power.cost.gpuCopy") max 0 + val hddReadCost = (config.getDouble("power.cost.hddRead") max 0) / 1024 + val hddWriteCost = (config.getDouble("power.cost.hddWrite") max 0) / 1024 + val gpuSetCost = (config.getDouble("power.cost.gpuSet") max 0) / Settings.basicScreenPixels + val gpuFillCost = (config.getDouble("power.cost.gpuFill") max 0) / Settings.basicScreenPixels + val gpuClearCost = (config.getDouble("power.cost.gpuClear") max 0) / Settings.basicScreenPixels + val gpuCopyCost = (config.getDouble("power.cost.gpuCopy") max 0) / Settings.basicScreenPixels val robotTurnCost = config.getDouble("power.cost.robotTurn") max 0 val robotMoveCost = config.getDouble("power.cost.robotMove") max 0 val robotExhaustionCost = config.getDouble("power.cost.robotExhaustion") max 0 @@ -153,6 +154,8 @@ object Settings { val screenResolutionsByTier = Array((50, 16), (80, 25), (160, 50)) val screenDepthsByTier = Array(PackedColor.Depth.OneBit, PackedColor.Depth.FourBit, PackedColor.Depth.EightBit) + def basicScreenPixels = screenResolutionsByTier(0)._1 * screenResolutionsByTier(0)._2 + private var settings: Settings = _ def get = settings diff --git a/li/cil/oc/server/component/Computer.scala b/li/cil/oc/server/component/Computer.scala index b05bf276c..10959ed27 100644 --- a/li/cil/oc/server/component/Computer.scala +++ b/li/cil/oc/server/component/Computer.scala @@ -52,6 +52,8 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con private val callCounts = mutable.Map.empty[String, mutable.Map[String, Int]] + private val ramScale = if (LuaStateFactory.is64Bit) Settings.get.ramScaleFor64Bit else 1.0 + // ----------------------------------------------------------------------- // private var timeStarted = 0L // Game-world time [ms] for os.uptime(). @@ -79,7 +81,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con l.setTotalMemory(Int.MaxValue) l.gc(LuaState.GcAction.COLLECT, 0) if (kernelMemory > 0) { - l.setTotalMemory(kernelMemory + owner.installedMemory) + l.setTotalMemory(kernelMemory + math.ceil(owner.installedMemory * ramScale).toInt) } case _ => } @@ -812,14 +814,14 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con lua.pushScalaFunction(lua => { // This is *very* unlikely, but still: avoid this getting larger than // what we report as the total memory. - lua.pushInteger(lua.getFreeMemory min (lua.getTotalMemory - kernelMemory)) + lua.pushInteger(((lua.getFreeMemory min (lua.getTotalMemory - kernelMemory)) / ramScale).toInt) 1 }) lua.setField(-2, "freeMemory") // Allow the system to read how much memory it uses and has available. lua.pushScalaFunction(lua => { - lua.pushInteger(lua.getTotalMemory - kernelMemory) + lua.pushInteger(((lua.getTotalMemory - kernelMemory) / ramScale).toInt) 1 }) lua.setField(-2, "totalMemory") diff --git a/li/cil/oc/util/LuaStateFactory.scala b/li/cil/oc/util/LuaStateFactory.scala index 9758a2114..04156d8eb 100644 --- a/li/cil/oc/util/LuaStateFactory.scala +++ b/li/cil/oc/util/LuaStateFactory.scala @@ -27,6 +27,10 @@ object LuaStateFactory { /** Set to true in initialization code below if available. */ private var haveNativeLibrary = false + private var _is64Bit = false + + def is64Bit = _is64Bit + // Since we use native libraries we have to do some work. This includes // figuring out what we're running on, so that we can load the proper shared // libraries compiled for that system. It also means we have to unpack the @@ -34,14 +38,22 @@ object LuaStateFactory { // load them directly from a JAR. breakable { // See http://lopica.sourceforge.net/os.html - val architecture = System.getProperty("os.arch").toLowerCase match { - case "i386" | "x86" => "32" - case "amd64" | "x86_64" => "64" - case "ppc" | "powerpc" => "ppc" - case _ => - OpenComputers.log.warning("Unsupported architecture, you won't be able to host games with working computers.") - break() - } + val architecture = + System.getProperty("sun.arch.data.model") match { + case "32" => "32" + case "64" => "64" + case _ => + System.getProperty("os.arch").toLowerCase match { + case "i386" | "x86" => "32" + case "amd64" | "x86_64" => "64" + case "ppc" | "powerpc" => "ppc" + case _ => + OpenComputers.log.warning("Unsupported architecture, you won't be able to host games with working computers.") + break() + } + } + _is64Bit = architecture == "64" + val extension = LWJGLUtil.getPlatform match { case LWJGLUtil.PLATFORM_LINUX => ".so" case LWJGLUtil.PLATFORM_MACOSX => ".dylib" diff --git a/mcmod.info b/mcmod.info index 6e9fdb46c..4e3eab36d 100644 --- a/mcmod.info +++ b/mcmod.info @@ -6,6 +6,7 @@ "credits" : "Inspired by ComputerCraft", "authors": ["Florian 'Sangar' Nücke", "Johannes 'Lord Joda' Lohrer"], "description": "This mod adds modular computers and robots that can be programmed in Lua.", - "logoFile" : "assets/opencomputers/textures/gui/logo.png" + "logoFile" : "assets/opencomputers/textures/gui/logo.png", + "url": "https://github.com/MightyPirates/OpenComputers/wiki" } ] diff --git a/reference.conf b/reference.conf index cacce2315..23c2c6b8e 100644 --- a/reference.conf +++ b/reference.conf @@ -90,6 +90,22 @@ opencomputers { 256 ] + # This setting allows you to fine-tune how RAM sizes are scaled internally + # on 64 Bit machines (i.e. when the Minecraft server runs in a 64 Bit VM). + # Why is this even necessary? Because objects consume more memory in a 64 + # Bit environment than in a 32 Bit one, due to pointers and possibly some + # integer types being twice as large. It's actually impossible to break + # this down to a single number, so this is really just a rough guess. If + # you notice this doesn't match what some Lua program would use on 32 bit, + # feel free to play with this and report your findings! + # Note that the values *displayed* to Lua via `computer.totalMemory` and + # `computer.freeMemory` will be scaled by the inverse, so that they always + # correspond to the "apparent" sizes of the installed memory modules. For + # example, when running a computer with a 64KB RAM module, even if it's + # scaled up to 96KB, `computer.totalMemory` will return 64KB, and if there + # are really 45KB free, `computer.freeMemory` will return 32KB. + ramScaleFor64Bit: 1.8 + # 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 @@ -123,10 +139,9 @@ opencomputers { # 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)`. + # an existing block face to place another block. Note that calling either + # `robot.place` or `robot.use` without a side will cause the robot to try + # all valid sides. canPlaceInAir: false # Whether robots may 'activate' blocks in the world. This includes @@ -221,8 +236,8 @@ opencomputers { # This is the amount of additional energy that fits into a robots # internal buffer for each level it gains. So with the default values, # at maximum level (30) a robot will have an internal buffer size of - # one million. - bufferPerLevel: 25000 + # two hundred thousand. + bufferPerLevel: 5000 # The additional "efficiency" a robot gains in using tools with each # level. This basically increases the chances of a tool not losing @@ -319,26 +334,26 @@ opencomputers { # Conversion ratio for BuildCraft's MJ. This is how many internal energy # units one MJ generates. - ratioBuildCraft: 5.0 + ratioBuildCraft: 1.0 # Conversion ratio for IndustrialCraft2's EU. This is how many internal # energy units one EU generates. - ratioIndustrialCraft2: 2.0 + ratioIndustrialCraft2: 0.4 # Conversion ratio for Universal Electricity's Joules. This is how many # internal energy units one Joule generates. - ratioUniversalElectricity: 5.0 + ratioUniversalElectricity: 1.0 # Conversion ratio for Thermal Expansion's RF. This is how many internal # energy units one RF generates. - ratioThermalExpansion: 0.5 + ratioThermalExpansion: 0.1 # The amount of energy a Charger transfers to each adjacent robot per tick # if a maximum strength redstone signal is set. Chargers load robots with # a controllable speed, based on the maximum strength of redstone signals # going into the block. So if a redstone signal of eight is set, it'll # charge robots at roughly half speed. - chargerChargeRate: 500.0 + chargerChargeRate: 100.0 # The energy efficiency of the generator upgrade. At 1.0 this will # generate as much energy as you'd get by burning the fuel in a BuildCraft @@ -349,23 +364,23 @@ opencomputers { buffer { # The amount of energy a single capacitor can store. - capacitor: 8000.0 + capacitor: 1600.0 # The amount of bonus energy a capacitor can store for each other # capacitor it shares a face with. This bonus applies to both of the # involved capacitors. It reaches a total of two blocks, where the # bonus is halved for the second neighbor. So three capacitors in a - # row will give a total of 44k storage with default values: - # (8 + 4 + 2)k + (4 + 8 + 4)k + (2 + 4 + 8)k - capacitorAdjacencyBonus: 4000.0 + # row will give a total of 8.8k storage with default values: + # (1.6 + 0.8 + 0.4)k + (0.8 + 1.6 + 0.8)k + (0.4 + 0.8 + 1.6)k + capacitorAdjacencyBonus: 800.0 # The amount of power robots can store in their internal buffer. - robot: 250000.0 + robot: 50000.0 } cost { # The amount of energy a computer consumes per tick when running. - computer: 1.0 + computer: 0.2 # The amount of energy a robot consumes per tick when running. This is # per default less than a normal computer uses because... well... they @@ -373,7 +388,7 @@ opencomputers { # interaction and whatnot, and the fact that robots cannot connect to # component networks directly, so they are no replacements for normal # computers. - robot: 0.5 + robot: 0.1 # The actual cost per tick for computers and robots is multiplied # with this value if they are currently in a "sleeping" state. They @@ -392,45 +407,58 @@ opencomputers { # energy per tick. screen: 0.1 - # Energy it takes read a single byte from a file system. Note that non + # Energy it takes read one kilobyte from a file system. Note that non # I/O operations on file systems such as `list` or `getFreeSpace` do - # *not* consume power. - hddRead: 0.000625 + # *not* consume power. Note that this very much determines how much + # energy you need in store to start a computer, since you need enough + # to have the computer read all the libraries, which is around 60KB + # at the time of writing. + # Note: internally this is adjusted to a cost per byte, and applied + # as such. It's just specified per kilobyte to be more intuitive. + hddRead: 0.1 - # Energy it takes to write a single byte to a file system. - hddWrite: 0.00125 + # Energy it takes to write one kilobyte to a file system. + # Note: internally this is adjusted to a cost per byte, and applied + # as such. It's just specified per kilobyte to be more intuitive. + hddWrite: 0.25 - # 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. - gpuSet: 0.0125 + # Energy it takes to change *every* 'pixel' via the set command of a + # basic screen via the `set` command. + # Note: internally this is adjusted to a cost per pixel, and applied + # as such, so this also implicitly defines the cost for higher tier + # screens. + gpuSet: 2.0 - # 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. - gpuFill: 0.01 + # Energy it takes to change a basic screen with the fill command. + # Note: internally this is adjusted to a cost per pixel, and applied + # as such, so this also implicitly defines the cost for higher tier + # screens. + gpuFill: 1.5 - # 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. - gpuClear: 0.0025 + # Energy it takes to clear a basic screen using the fill command with + # 'space' as the fill char. + # Note: internally this is adjusted to a cost per pixel, and applied + # as such, so this also implicitly defines the cost for higher tier + # screens. + gpuClear: 0.25 - # 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. - gpuCopy: 0.0050 + # Energy it takes to copy half of a basic screen via the copy command. + # Note: internally this is adjusted to a cost per pixel, and applied + # as such, so this also implicitly defines the cost for higher tier + # screens. + gpuCopy: 0.5 # The amount of energy it takes a robot to perform a 90 degree turn. - robotTurn: 10.0 + robotTurn: 2.5 # The amount of energy it takes a robot to move a single block. - robotMove: 60.0 + robotMove: 15.0 # The conversion rate of exhaustion from using items to energy # consumed. Zero means exhaustion does not require energy, one is a # one to one conversion. For example, breaking a block generates 0.025 # exhaustion, attacking an entity generates 0.3 exhaustion. - robotExhaustion: 20 + robotExhaustion: 10 # The amount of energy it costs to send a signal with strength one, # which means the signal reaches one block. This is scaled up