Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal

Fingercomp

Members
  • Content Count

    120
  • Joined

  • Last visited

  • Days Won

    35

Posts posted by Fingercomp

  1. On 6/24/2021 at 10:36 PM, tt_thoma said:

    I'm pretty sure that the both programs are the same

    Unfortunately here, they only share the name and the purpose. For one, the program you've read about isn't even written in Lua, so you can't really expect it to run on OC.

    The one included in OpenOS cannot, in fact, download directories recursively. Nor do any of the fancy things the other program can. When searching for what an OpenOS program does, documentation for utilities included in a Linux distribution probably won't be useful. Instead, type man programname in the OpenOS shell, or look into the program's source code (edit /bin/programname).

  2. There was no IRC library for OpenComputers, so I've made one. Here's a demo bot that uses it:

    local com = require("component")
    local event = require("event")
    local thread = require("thread")
    
    local gpu = com.gpu
    
    local irc = require("irc")
    local events = irc.events
    
    local env = setmetatable({
      irc = irc,
      events = events,
    }, {__index = _G})
    
    local client = irc.builder()
      :connection {
        host = "irc.esper.net:6667",
        throttling = {
          maxDelay = 2,
          maxThroughput = 5,
        },
      }
      :auth {
        nickname = "oc-finger-irc",
        username = "fingercomp",
        realname = "OpenComputers IRC client library",
      }
      :bot {
        channels = {"#oc-finger-irc"},
        tracking = {
          users = true,
          modes = true,
          account = true,
          userInfo = true,
        },
      }
      :execution {
        threaded = true,
        reconnect = true,
        catchErrors = true,
      }
      :subscribe(events.irc.command, events.priority.high, function(self, client, evt)
        gpu.setForeground(0x00ff00)
        print("→ " .. evt.rawLine)
        gpu.setForeground(0xffffff)
      end)
      :subscribe(events.irc.write, events.priority.normal, function(self, client, evt)
        gpu.setForeground(0x00dbff)
        print("← " .. evt.line:gsub("[\r\n]*$", ""))
        gpu.setForeground(0xffffff)
      end)
      :subscribe(events.irc.message, irc.events.priority.normal, function(self, client, evt)
        if evt.source.nickname == "fingercomp" then
          if evt.message == "::quit" then
            evt:reply("Quitting.")
            evt.client:stop(("%s told me to quit."):format(evt.source.nickname))
          elseif evt.message == "::spam" then
            evt:reply("1")
            evt:reply("2")
            evt:reply("3")
            evt:reply("4")
            evt:reply("5")
          elseif evt.message == "::longmsg" then
            local msg = {}
            for i = 1, 256 do
              if i == 128 then
                table.insert(msg, tostring(i) .. " ")
              else
                table.insert(msg, tostring(i))
              end
            end
            evt:reply(table.concat(msg))
          elseif evt.message == "::error" then
            (nil).test()
          elseif evt.message:sub(1, #"::exec ") == "::exec " then
            local code = evt.message:sub(#"::exec " + 1)
    
            local chunk, reason = load("return " .. code, "=irc", "t", env)
    
            if not chunk then
              chunk, reason = load(code, "=irc", "t", env)
            end
    
            if not chunk then
              evt:reply(("\x0304Error:\x0f %s"):format(reason))
            else
              local result = table.pack(xpcall(chunk, debug.traceback))
              local success = table.remove(result, 1)
              result.n = result.n - 1
    
              for i = 1, result.n, 1 do
                if type(result) ~= "string" and type(result) ~= "number" and
                    type(result) ~= "boolean" and type(result) ~= "nil" then
                  result[i] = tostring(result[i])
                else
                  result[i] = ("%q"):format(result[i]):gsub("\\\n", "\n")
                end
              end
    
              if not success then
                evt:reply(("\x0304Error:\x0f %s"):format(result[1]:match("^[^\n]*")))
    
                io.stderr:write(("%s\r\n"):format(result[1]))
              elseif result.n > 0 then
                evt:reply(table.concat(result, "  ", i, result.n))
              else
                evt:reply("\x0309Success")
              end
            end
          end
        end
      end)
      :subscribe(events.irc.ctcpRequest, irc.events.priority.normal, function(self, client, evt)
        if evt.ctcpCommand == "TIME" then
          evt:reply(os.date("%F %T"))
        end
      end)
      :subscribe(events.client.error, irc.events.priority.top, function(self, client, evt)
        print("Caught: " .. evt.traceback)
        evt:cancel()
      end)
      :build()
    
    local t = thread.create(function()
      repeat
        local evt = event.pull("interrupted")
      until evt
    end)
    
    env.client = client
    client:run()
    
    thread.waitForAny({t, client.thread})
    client:stop("Quitting.")
    
    os.exit()

    I don't want to brag about it too much, but I think the code is pretty.

    Features

    • Threaded execution.
    • A nice API.
    • IRCv3.2 capability negotiation.
    • Throttling to prevent the bot from triggering anti-flood mechanisms.
    • Tracks channel members, modes, nick changes, account names, etc.
    • Automatically reconnects if it's disconnected from the IRC server.
    • Splits long messages over multiple lines.
    • The event bus can use coroutines as message handlers.

    Links

  3. TL;DR: set the resolution to 159×28.

    Displays automatically scale the content to fit the screen's inner area. If you decrease the resolution height, the display area will occupy more horizontal space.

    I'll assume that your screen is 8×3. The aspect ratio of the screen's inner area is (2 × (8×16 - 4.5)) : (3×16 - 4.5) = 494×87. The "- 4.5" terms are the screen borders, and the width is doubled because the cell width is half its height. If you set the resolution proportional to this ratio, it will fill the whole screen. Of course, you can't do this, as the maximum resolution is 160×50. So we have to compromise and choose the resolution that fits the screen the best.

    local function round(num)
      local integer, frac = math.modf(num)
    
      if frac >= 0.5 then
        integer = integer + 1
      end
    
      return integer
    end
    
    local data = {}
    
    for w = 1, 160, 1 do
      local h = math.max(math.min(round(w * 87 / 494), 160 * 50 / w, 160), 1)
      local area = w * h
      local delta = (w / h) - 494 / 87
    
      table.insert(data, {delta, area, ("%d×%d"):format(w, h)})
    end
    
    table.sort(data, function(lhs, rhs)
      return lhs[1] < rhs[1]
    end)
    
    local f = io.open("./data", "w")
    
    for k, v in ipairs(data) do
      f:write(("%.6f %d %s\n"):format(v[1], v[2], v[3]))
    end
    
    f:close()

    The above code creates an array and fills it with 160 possible resolutions by choosing a width and calculating the height such that the aspect ratio is the closest to what we're trying to achieve (494:87). Then it writes the data to a file so that we can plot it. Here's what we get:

    spacer.png

    Now it's clear that the best resolution is 159×28. Its aspect ratio differs from 494/87 by ~0.000411, which is really small. Let's go ahead and calculate the thickness of the black area.

    1. Let dw, dh be the dimensions of the display area, and iw, ih the dimensions of the inner area.
    2. dw/dh = 159/28; iw/ih = 494/87.
    3. 159/28 > 494/87, so the display area height is less than the screen's inner area height. Therefore, the width of the black area is dw = iw.
    4. The height equals 0.5 × (ih - dh) = 0.5 × (87/494 × iw - 28/159 × dw) = 0.5 × iw × (87/494 - 28/159) = 0.5 × 494/87 × ih × (87/494 - 28/159) = 1/27666 × ih.

    In other words, the height of the black area is 1/27666th of the whole inner area height, which is negligible.

  4. Pressing the button that is placed on the screen turns the screen on/off. Make sure the button is not adjacent to the screen.

    Also, you should use rs.getInput in yor problem. rs.getOutput returns the strength of the redstone signal emitted by the computer's redstone card.

  5. Of course there is. Assembling a drone with a leash upgrade produces a drone that can transport cows, horses, sheeps, and pigs. Like this:

    2014-12-28_11.13.44.png

    Or... like this:

    s2qlv2j.png

    Besides, drones are entities. They move in straight lines; they don't get stuck in the fence and can actually enter a house through a door. They move pretty fast — about 6 blocks a second (robots are at least 2 times slower). Drone's movement is asynchronous, so the machine can execute some other code in the middle of the flight. Drones can fly above the block height limit. The screenshot above was made while enjoying the flight at a height of 260 blocks, for example. Oh, they can fly below the bedrock, too.

    Also, drones look cool.

    Jobs at which drones clearly outperform robots include player transportation (thanks to the leash upgrade) and item transportation (due to their mobility). And, if used with robots, drones can be useful for crop farming, autocrafting, and construction, for example.

  6. It's a bit unclear for me what kind of problem you have. Is print also called twice per supposedly one sent modem message? Or is it only the doHarvestRoutine call that's repeated?

    If it's the former case (the print line is also run twice), it means your sent messages are somehow duplicated. First thing to check for is whether you have any relays nearby. These blocks LOVE to mess up with network packets. If you use them, I advice you to remove them and use linked cards or a network that checks for duplicates. If you don't, it's very likely that the sender program has a bug that causes it to send each packet twice.

  7. The last chapter mentions briefly the biggest problems that make sound reconstructed from the audio data sound bad, and I'm going to try to explain them.

    1. The program is quite simple.

    It's merely a proof of concept. It doesn't use modulation or non-sine waveforms.

    2. Most sounds are complex.

    Most sounds I hear are far from being purely sinusoidal. Perhaps it's different for you, or for someone else who happens to read this post. :) White noise is vastly different from a flute, and the flute isn't the same as a guitar. Each instrument has a unique timbre, and even a single instrument can have different timbres depending how performers play it.

    Sound can be decomposed into an infinite number of sinusoids that, when summed together, produce the original sound. This is what Fourier transform does, basically. So if you use it to decompose a sound of a violin playing, and filter the output, you'll see, indeed, multiple sine waves that construct the signal, which are called partials. When you reconstruct the sound back, to get better approximation, you need to sum more partials.

    3. Unfortunately, the sound card only has 8 channels (by default).

    This means that from the set of sinusoids that represent the encoded signal we have to choose eight of them. It's enough for a piano, but for some sounds (such as human speech) it's clearly too few of them, and what you get doesn't even seem to be similar to what was originally encoded.

    It's worth noting that if the program also analyzed the spectrum to use different waveforms, it could probably achieve a better resemblance.

    4. Furthermore, we discard phase.

    The Fourier transform produces two values for each sinusoid: the amplitude, and the phase. The phase is important. For example, if you have two sine waves that differ in phase by π, and have the same frequency and amplitude, you won't hear any sound. These sinusoids are opposite of each other: if, at some point, one has a value of 0.5, the other has the value of -0.5, so, when you sum them, you get zero everywhere.

    The sound card has no way of setting phase. It's possible to get the situation as described above: if the first channel accumulates phase of π, and then you initialize the second channel, you may hear no sound at all!

    Though, given the limited channel count, the fact that we discard the phase doesn't really make much difference.

    But the channel count can be changed in the configuration file.

    When I was testing the program, I had tried running it with 64 channels. It was quite noisy, because the program does not filter the output of Fourier transform, and doesn't set phase. It was also glitchy, caused by my computer, which was unable to process everything fast enough. But it was still better than 8 channels.

  8. A byte is an octet of bits, which can store 2⁸ = 256 possible values. To represent a character as a number, we need an encoding system. ASCII is one of them, and it assigns first 128 values to control characters, digits, English letters and punctuation. But people also use different languages, which need additional characters to be represented. Latin-1, for example, uses the remaining 128 values to define a few more characters from Latin-based scripts. Even with that, the character coverage was low: Chinese has several thousand different characters, for instance. Therefore, that was a need for an encoding system that allows to represent, ideally, characters from all scripts in use.

    Unicode is such a standard, and its latest revision has more than 130 thousand characters mapped to codepoints. Unicode has several possible encodings, e.g. UTF-8, UTF-16, and UTF-32, also defined by the Unicode standard. UTF-16 uses 16 bits (2 bytes) for each character, and UTF-32 uses 4 bytes. But they occupy too much data storage. UTF-8 has gained more use, at least on the web, and it uses 1 to 4 bytes to represent each character (so it usually uses less space). It's also the encoding used by OpenComputers.

    This is how UTF-8 encodes the string "¯\_(ツ)_/¯":

    Byte:  c2 af 5c 5f 28 e3 83 84 29 5f 2f c2 af
    Chars: \___/ \/ \/ \/ \______/ \/ \/ \/ \___/
             ¯    \  _  (    ツ     )  _  /   ¯

    As you can see, some characters are encoded with a single byte (such as _, (, ), /, \); some need 2 bytes (¯); the tsu character in the middle (ツ) needs 3 bytes.

    When you open a file, there's a question of what it should work with. There are two possible answers.

    • Non-binary. The stream works with UTF-8-encoded characters. Assuming the stream is at the beginning of the string "¯\_(ツ)_/¯", file:read(2) will return "¯\" — that's 3 bytes (#"¯\" == 3). This is the default mode.
    • Binary. The stream works with single bytes. With the same assumption, file:read(2) will return "¯", a single character. If you need to use it, you have to explicitly set it by adding the character "b" to the mode string (io.open(path, "rb"), for instance).

    In binary mode, CC is unable to store non-UTF-8-encoded data in its strings (in other words, it does support strings encoded with UTF-8, but not raw bytes), so it has to return a number instead. This is not how PUC-Rio's implementation of Lua, or OC's natives (which are based on the former) work — they return a string with a single byte instead. But you can get the byte number by using the function string.byte, and string.char to do the opposite.

    local str = "\xc2"
    local byte = string.byte(str)
    
    print(byte == 0xc2)  --> true
    print(string.char(byte) == str)  --> true

     

  9. On 8/19/2018 at 5:53 PM, noahthegame said:

    you mean like this, right:

    
    gfxb.clear()
    gfxb.drawChanges(true)

    if so then that doesn't work still nothing is drawen secount run

    This behaviour is strange and indicates there's a bug somewhere. Since the double buffering library is used by MineOS, it would have much more chance of being noticed, so it's more likely there's some problem in your code. Could you show the code you run, please?

  10. 2 hours ago, noahthegame said:

    so i give the infomation to the buffer (eg buffer.set(2,2,0xff0000, 0, " ")) and the buffer api will only do a gpu.set opration when it has to limting unnessary gpu.set's? is that how that works?

    Yeah, basically.

    1 hour ago, noahthegame said:

    i think i have found a bug in the that buffering api it works once but then i need to restart the computer for it to work again? do i need to close the buffer before my program ends or some thing?

    The buffer is a singleton. In other words, there's only a single buffer instance in the memory, which is kept there even if programs that required the library exited. An implication of this fact is that buffer may be non-empty when you start your program; therefore, before you use the buffer, you need to do a buffer.clear() followed by a forceful render: buffer.drawChanges(true). It's been a long time since I've used that library, though. Things might have changed. Considering there aren't proper releases and commit descriptions, it's rather difficult to navigate through the commit history.

  11. 23 minutes ago, noahthegame said:

    but the hole idea is to being able to draw pixel per pixel

    OC sets significant limits the GPU, which make it much harder to do more advanced graphics. You can optimize the calls at the cost of high RAM usage — storing data in a buffer and only drawing the cells that changed since the last buffer flush. It isn't really an easy thing to implement yourself, so you might want to use a buffering library someone else made — here's one that definitely works, for example. I was also making one, but it's not yet ready.

    23 minutes ago, noahthegame said:

    do you have any idea where OC gets the charector textures from?

    OpenComputers has a font.hex file, which is the font that's used to render characters on the screen. Since OC 1.6, asie's funscii font is used.

    28 minutes ago, noahthegame said:

    is there some kind of unicode api

    Let's make things clear.

    • Unicode is a standard that assigns numbers (codepoints) to a ton of characters (glyphs from different scripts, math symbols, emoji, and some other random things).
    • UTF-8 is one of the possible encodings for Unicode symbols, and it's fairly the most popular one used. It converts a character codepoint, like U+2588, to a sequence of bytes. We need an encoding because a byte can only contain 256 values, while Unicode has 137439 characters. OpenComputers (and a lot of other software) supports UTF-8 and uses it to encode characters.
    • OpenComputers provides the Unicode API for Lua 5.2 and Lua 5.3 architectures. You can use it to convert codepoints to characters and perform other operations on UTF-8 strings.
    • Lua 5.3 also exports the utf8 library. It has a few functions that Unicode API doesn't provide, but is unavailable for Lua 5.2.
  12. Yeah, there is a way to make it faster. In fact, way faster. One of the things that makes it slow is... gpu.setBackground. It's quite expensive in terms of perfomance (tier 3 GPUs consume 1/128 of the call budget when this method is called). Fortunately, your program only involves 4 colors, so it can be easily optimized.

    Actually, there are two ways to do it. A somewhat naive way would be to process all cells of one color first, then process all cells of another color, etc. That would solve the issue with gpu.setBackground, but there's another thing to worry about. The gpu.set method isn't free. In fact, that program does 160 × 50 = 8000 sets, assuming it's running on the max tier 3 resolution. And that is a lot.

    Fortunately, OC supports Unicode. In particular, there's a character in Unicode called a full block — █. On OC, I prefer to think of it as of an inverse of " " (a space). If the foreground and background colors are swapped, the space would look like the full block, and vice versa. And it can help us reduce amount of GPU calls significantly. Try replacing the loops with the following:

    -- i = 0
    gpu.setBackground(0xff0000)
    gpu.set(1, 1, " ")
    
    -- i = 1
    gpu.setBackground(0x00ff00)
    gpu.set(1, 2, " ")
    
    -- i = 2, 3
    gpu.setForeground(0xffff00)
    gpu.setBackground(0x0000ff)
    
    local fullBlock = "\u{2588}"
    local oddRow = (" " .. fullBlock):rep(math.floor(mx / 2))
    local evenRow = (fullBlock .. " "):rep(math.floor(mx / 2))
    
    for y = 1, my do
      local x = 1
    
      if y % 2 == 1 then
        if y == 1 then
          -- Shift the x by 2 to the right to avoid rewriting
          -- the first two characters.
          -- OC truncates everything that goes out of the screen bounds,
          -- so there's no need to worry about that.
          x = x + 2
        end
    
        gpu.set(x, y, oddRow)
      else
        gpu.set(x, y, evenRow)
      end
    end

    I can't launch Minecraft to run the program and measure the render time, but I can calculate the amount of call budget consumed by the GPU. Assuming the program runs on a tier 3 GPU and screen, there are 4 gpu.setForeground/gpu.setBackground calls, and 52 gpu.set calls. We get (4 × 1 / 128) + (52 × 1 / 256) = 15 / 64 ≈ 0.23. This is enough even if you have a tier 1 processor (whose call budget is 0.5), and the program should be able to run at 20 FPS, though it doesn't really change each frame.

    8 hours ago, noahthegame said:

    hmmm you're sure about this?

    Oh, I meant to say "T3" (tier 3), sorry. A tier 2 GPU can only perform 128 sets and 64 fills.

    8 hours ago, noahthegame said:

    where is the source?

    https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala#L55-L60

    Also, there's a comment a few lines above in that file, which reminds me of yet another reason OC makes indirect calls take 1 tick to run — synchronization. OpenComputers, very much unlike ComputerCraft, saves the state of running computers so that they can be resumed when the chunk is reloaded. Methods that interact with the world in some way (like moving items around) must perform synchronization with the Minecraft world to avoid, well, messing things up. The comment says it's especially important on world saves. Despite that, the GPU methods were made direct, although a "nasty trick" was needed to do this. Well, safe concurrency is hard to achieve.

  13. Please calm down.

    There are some component methods that block the computer for a tick when called, yes. Such methods usually interact with the world. For example, a transposer allows to transfer items between invetories by calling the transferItem method, which takes a tick to execute (so you get up to 20 stacks/second).

    On the other hand, there are a lot of direct methods, which can be called several times per tick. For example, the GPU's methods are direct. And the processor (as well as RAM) determines how many direct calls are allowed per tick. I think T2 T3 setup allows you to call gpu.get one thousand times every tick. Or 256 gpu.sets. Or 128 gpu.fills.

    I also believe you don't realize how bad ComputerCraft is for servers. A really simple and stupidly-written program can eat up all the memory the server has. That's why OC limits the memory available for an in-game computer. And running CPU-intensive tasks on a CC's computer makes the whole server run slow, whereas OC requires scripts to pause to allow other in-game computer to run. OpenComputers imposes the limits not because the mod developers want users to suffer (although I do sometimes think of that when I try to do some stupidly complex things with it), but to make it server-friendly.

    What's important is that OC allows you to configure these limits for your needs. Have you opened its configuration file? It is more than a 1.5k lines long, and has more than 300 settings you can change, each with a comment that explains the effect of the setting. There's callBudgets to increase the direct call number limit. Or decrease it. There's also the ramSizes setting for memory, and hddSizes for the HDD sizes.

    But even with all of these limits, OC can run a lot of programs, including graphical shells, 3D games, reactor control systems. It allows you to send HTTP requests to the real websites, and open raw TCP sockets to interact with network services. It can display 320x200 images. It can even play videos — inside the game, and on the default OC settings!

  14. The code below tries to make sure that the request finished, and then it reads the response. Unfortunately, I can't test the program in the game for various reasons. Could you try using it?

    local c = require("component")
    local computer = require("computer")
    local internet = require("internet")
    local f = io.open("test.txt", "wb")
    
    local imax = 0
    local xmax = 75
    local ymax = 180
    local zmax = 87
    
    local TIMEOUT = 5  -- in seconds
    
    local link = "https://raw.githubusercontent.com/LordNocturnus/sf-"
    local folder = "/master/"
    
    local pos = 0
    
    for i = 0, imax do
      for xb = pos, xmax do
        for yb = 0, ymax do
          for zb = 0, zmax do
            print(xb, yb, zb)
            local file = xb .. "-" .. yb .. "-" .. zb .. ".mb3d"
            local url = link .. i .. folder .. file
            local status, response = pcall(internet.request, url)
    
            if not status or not response then
              print("Download of " .. url .. " failed.")
            else
              local startTime = computer.uptime()
    
              while true do
                local result, isFinished = pcall(response.finishConnect)
                
                if result and isFinished then
                  break
                elseif not result then
                  print("Could not connect to " .. url .. ".")
                  os.exit()
                elseif computer.uptime() - startTime > TIMEOUT then
                  print("Request to " .. url .. " timed out")
                  os.exit()
                else
                  os.sleep(0.25)
                end
              end
    
              local f = io.open(file, "wb")
    
              for chunk in response do
                f:write(chunk)
              end
    
              f:close()
              socket:close()
            end
          end
        end
      end
    end

     

  15. There are a bunch of questions, so let me start from the easiest ones to solve.

    There is indeed no such thing as internet.close. You call the close method directly on the response object — and after you no longer need it. You can't read from a socket if you closed it.

    -- this code...
    local imax = 10
    
    do
      local i = 1
    
      while i <= imax do
        print(i)
        i = i + 1
      end
    end
    
    -- ...is equivalent to the following code:
    for i = 1, imax do
      print(i)
    end
    
    -- I recommend using for loops as there's less code to write

    Now, the main question: how to check if a file exists. The GitHub server returns HTTP 404 status code if a location, the file in our case, does not exist. And, fortunately, the response object provides a method to get the status code: response.response() (from the docstring: function():number, string, table -- Get response code, message and headers).

    local c = require("component")
    local internet = require("internet")
    local f = io.open("test.txt", "wb")
    
    local imax = 0
    local xmax = 75
    local ymax = 180
    local zmax = 87
    
    local link = "https://raw.githubusercontent.com/LordNocturnus/sf-"
    local folder = "/master/"
    
    local pos = 0
    
    for i = 0, imax do
      for xb = pos, xmax do
        for yb = 0, ymax do
          for zb = 0, zmax do
            print(xb, yb, zb)
            local file = xb .. "-" .. yb .. "-" .. zb .. ".mb3d"
            local status, response = pcall(internet.request, link .. i .. folder .. file)
    
            if not status or not response or response.response() >= 400 then
              print("Download of " .. link .. i .. folder .. file .. " failed.")
            else
              local f = io.open(file, "wb")
    
              for chunk in response do
                f:write(chunk)
              end
    
              f:close()
              socket:close()
            end
          end
        end
      end
    end

     

  16. Oh, too long without yielding... This error means the computer exceeded the timeout, but didn't yield; it's required to prevent "stupidly written or malicious programs" from blocking other computers from running. I can't say oppm is stupidly written (although it isn't certainly the most efficient program ever, either), nor is it malicious. The error can also be thrown if the MC host server (or, if you are playing in a SP world, your computer) is overloaded and causes the game — and the opencomputers — run slower. Less code is executed per second, so it can just be unable to reach an os.sleep call in the default five seconds. In this case, you may want to increase the timeout setting in the OpenComputers configuration file.

  17. My guess is that you didn't even install OpenOS, and now you're trying to install oppm on a read-only floppy disk. This won't work, of course. Insert a HDD, boot from the OpenOS floppy, run install, choose openos if you're asked, and reboot the computer when it's done. Then you can try to install oppm.

  18. Well, it executes exactly what's written in the code, and is the expected behavior. event.pull("modem_message") stops the program (more specifically, the thread) until it gets the modem_message event. You may want to set a timeout, so that the pull would stop early — returning nil in such case; for example, event.pull(1, "modem_message") sets the timeout to 1 second.

    Let's step through the program line by line. The first 5 lines don't cause any difficulties, so we skip them. There's the repeat-until loop, and the first iteration is run unconditionally. First, the string "hello" is printed to the screen. After that there's the event.pull line, which (as I said before) stops the program until it gets the modem message.

    The execution now does not go any further. The program is running — it just waits for a modem message now. You broadcast a stop message; the program gets it, and goes on. select is called, and the actual message is set to the cmd variable.

    Only then "hi" is written. As the condition is satisfied, the loop stops, and the program exits.

    if this is not what you wanted, please clarify the intended behavior.

  19. Actually, it's possible. Here's the program if you don't mind some Russian. Assemble a robot with:

    • an inventory upgrade;
    • an inventory controller upgrade;
    • a redstone card;
    • a solar generator upgrade (optional; you can use a charger instead).

    post-13296-0-73005000-1453315450.png

  20. The bug is really simple. To find it, follow through the code line-by-line, analyzing what happens at each line. (This is something I do quite often when debugging an obscure problem.)

    First, skip the first few dozens of lines until we get to the L65 (short for line 65), where the loop is defined. We then encounter the if block at L68, of which the first branch is actually run (page == "page1" as it was set to this value on L63), resulting in the pageOne call.

    The next line to examine is L79, where the program stops until it pulls the touch event. Here, I check that the event parameters weren't mixed up. All right, let's go on and press the button.

    The first condition, on L82, is satisfied (page == "page1", set on L63), so we get the page variable updated to the new value, "page2". But there's more code to run before we loop back! The second condition, on L89. The coodinate mess after the first and evaluates to true. What about page? Well, we've just set it to "page2", so... it, too, yields true. Therefore, the whole condition is satisfied. And the variable is set back to "page1". We loop back, and redraw the first page.

    This is how we've just spotted the bug. In case you wonder why Event 2 isn't written to the screen: well, it is written. At position (4, 45). You've just mistaken x for y (and vice versa): 4 is the column, 45 is the row. This is clearly beyond the viewport 58×18, so you see nothing actually printed.

    OK. How should you fix it? It's simple: use elseifs.

    if (x >= w / 2 - 5 and
        x <= w / 2 - 5 + 11 and
        y >= h / 2 - 1 and
        y <= h / 2 + 1) then
      if page == "page1" then
        mon.set(4, 10, "Event 1")
        table.insert(a, "X")
        page = "page2"
      elseif page == "page2" then
        mon.set(45, 10, "Event 2")
        page = "page1"
      end
    end
  21. The sound card is added by Computronics, a wonderful addon for OpenComputers. There are a few who actually know what it does. Even less people are able to use it. No one dares to understand how it works, or so I hope.

    Anyway, it appeared a few years (?) ago, and is still mostly undocumented. There is a page in the in-game manual, which fails to explain how great the card is. Of course it does! It has a heap of different methods, which you can use to cast many crazy magics to make the sound card sound, and it's impossible to teach someone to do magic by reading a single page.

    OK, I'm serious now. Last year I managed to understand how to use it, and even wrote a few posts about that. In Russian. Half a year later, I translated them to English. And now I thought of posting a topic here so that you could read them, too.

    Here's the link.

    The first two parts are all about basic things, like getting simple sounds, ADSR, and modulation. The third part features a little bit more complex things, like complex numbers and Fourier transforms. I tried to keep it simple, so I could get something wrong. If so, please leave a comment there pointing out the mistake. Grammar fixes are also highly appeciated.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.