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

Molinko

Members
  • Content Count

    451
  • Joined

  • Last visited

  • Days Won

    35

Posts posted by Molinko

  1. rsClient.lua

    local component = require "component"
    local event = require "event"
    
    local tunnel = assert(component.tunnel, "primary tunnel component required")
    local args, timeout = {...}, nil
    
    if args[1] and (args[1] == '-t' or args[1]:match "--timeout=%d+") then
      timeout = tonumber(args[2]) or tonumber(args[1]:match "--timeout=(%d+)")
    end
    
    tunnel.send("rs_info") -- # ask server for redstone interface details
    local isAnalog, side, level, color = select(6, event.pull(timeout or 5, 'modem_message', tunnel.address, nil, 0, 0))
    
    tunnel.send("rs_update", side, level < 15 and 15 or 0, isAnalog and nil or color) -- # toggle redstone output value
    local success, reason = select(6, event.pull(timeout or 5, "modem_message", tunnel.address, nil, 0, 0))
    
    if not success then
      io.stderr:write(reason..'\n')
    else
      print('redstone interface updated')
    end

    rsServ.lua

    --
    local component = require "component"
    local event = require "event"
    local colors = require "colors"
    local sides = require "sides"
    
    local tunnel = assert(component.tunnel, "primary tunnel component required")
    local rs_address, side, color = ...
    
    rs_address = assert(component.get(rs_address))
    side = assert(sides[side], "invalid side")
    
    if color then
      color = assert(colors[color] and color, "invalid color")
    end
    
    while true do
      local ev = {event.pullMultiple('interrupted', 'modem_message')}
    
      if ev[1] == 'interrupted' then
        break
      elseif ev[1] == 'modem_message' and ev[2] == tunnel.address then
        if ev[6] == 'rs_info' then
          local isAnalog = color and false or true
          local rs_state
    
          if isAnalog then
            rs_state = component.invoke(rs_address, 'getOutput', side)
            tunnel.send(true, side, rs_state)
          else
            rs_state = component.invoke(rs_address, 'getBundledOutput', side, color)
            tunnel.send(false, side, rs_state, color)
          end
        elseif ev[6] == 'rs_update' then
          local output_side, output_level, output_color = table.unpack(ev, 7)
          local success, reason
    
          if output_color then
            success, reason = pcall(component.invoke, rs_address, 'setBundledOutput', output_side, output_color, output_level)
          else
            success, reason = pcall(component.invoke, rs_address, 'setOutput', output_side, output_level)
          end
    
          tunnel.send(success, reason)
        end
      end
    end

    Should do the trick :)

    Start client with `rsClient 5`, will timeout in 5 seconds if it cant contact the server.

    Start server with `rsServ 45af south`, where '45af' is the abbreviated address of the redstone component and 'south' is the direction to output the signal.

  2. Line 4 of your script requires an 'end' to close the 'if' statement. The error mentions that the 'while' clause needs an 'end', but that's just because the interpreter thinks the 'end' on line 6 belongs if the 'if'.

  3. I don't know the current state of this issue but i have heard that certain mods bundled cable and OC don't integrate. I had this issue once and the substitute I used was another mods' bundled wire(immersive engineering). I'm not sure if this is OCs' 'fault' or the integrating mods' fault.. Personally I think somebody should just implement rs bundled cable/wire as a part of OC.

  4. This just isn't really possible in in much of a meaningful way.. a lot of websites are not static and have JavaScript, which can't be executed. Even if you downloaded a static site, rendering it in a meaningful way to the original would be almost surely impossible except for the most trivial of sites. Sites that are just text and hyperlinks and maybe some other very basic elements could be recreated. Maybe a Wikipedia without images or a simplified Reddit thread could be possible minus some novelties.

  5. A partial demo of your first script. Should get the ball rolling..

    local component = require "component"
    local thread = require "thread"
    local event = require "event"
    local text = require "text"
    local term = require "term"
    
    -- # make a function that formats part(s) of its input
    local function status_print(x, y, pat, format)
      return function(str)
        term.setCursor(x, y)
        -- # pad the output to wipe old overhanging chars from prev long outputs
        term.write(text.padRight(str:gsub(pat, format), 30))
      end
    end
    
    -- # NOTE: all the 'print format' functions below are using arbitrary values
    --      for things like `maxCaseTemp` and `warnCaseTemp`. Tweak bounds to
    --      your satisfaction.
    
    -- # `print energy cell power`
    -- # Usage: pECPower "Total Energy: 100001" -->  "Total Energy: \27[32m100001\27[37m"
    local pECPower = status_print(2, 3, "(%d+)", function(amount)
      -- # wrap power amount in vt100 color codes depending on int value
      -- # `\27[37m` resets fg color to white
      return (tonumber(amount) > 100000 and '\27[32m' or '\27[31m') .. amount .. '\27[37m'
    end)
    
    local energyLastTick = 0 -- # initial value so we don't crash as we start :3
    local pReactorPower = status_print(2, 6, "(%d+)", function(amount)
      -- # wrap amount in green if energy production is up, red if down.
      local output = (tonumber(amount) > energyLastTick and '\27[32m' or '\27[31m') .. amount .. '\27[37m'
      energyLastTick = tonumber(amount)
      return output
    end)
    
    -- # Tweak these bounds to signal properly
    local maxCaseTemp, warnCaseTemp = 1000000, 900000
    local pRCaseTemp = status_print(2, 8, "(%d+)", function(amount)
      -- # danger, warning, and normal color formats
      local temp = tonumber(amount)
      if temp >= maxCaseTemp then
        return '\27[31m' .. amount .. '\27[37m'
      elseif temp >= warnCaseTemp then
        return '\27[33m' .. amount .. '\27[37m'
      else
        return '\27[32m' .. amount .. '\27[37m'
      end
    end)
    
    -- # Tweak these too..
    local maxFuelTemp, warnFuelTemp = 1000000, 900000
    local pRFuelTemp = status_print(2, 9, "(%d+)", function(amount)
      -- # see pRCaseTemp().
      local temp = tonumber(amount)
      if temp >= maxFuelTemp then
        return '\27[31m' .. amount .. '\27[37m'
      elseif temp >= warnFuelTemp then
        return '\27[33m' .. amount .. '\27[37m'
      else
        return '\27[32m' .. amount .. '\27[37m'
      end
    end)
    
    
    -- # the meat.
    local function monitorPower(cells, ref_rate)
      while true do
        local sum = 0
        for address, _ in pairs(cells) do
          sum = sum + (component.invoke(address, 'getEnergyStored') or 0)
          -- # yield for a while so we dont spam component calls and because we have to somewhere..
          event.pull(ref_rate or .25)
        end
        pECPower("Total Power: " .. tostring(sum) .. 'rf')
      end
    end
    -- # more meat.
    local function monitorReactor(reactor, ref_rate)
      while true do
        pReactorPower("Power produced: " .. tostring(reactor.getEnergyProducedLastTick()) .. 'rf/t')
        pRCaseTemp("Case temp: " .. tostring(reactor.getCasingTemperature()) .. '°C')
        pRFuelTemp("Fuel temp: " .. tostring(reactor.getFuelTemperature()) .. '°C')
        -- # yield for a bit. consider it a 'refresh rate'
        event.pull(ref_rate or 1)
      end
    end
    
    -- # lies. virtual reactor. I dont want to build all this shit.. sorry
    -- # create your `monitorReactor` thread with a real reactor component proxy.
    local mockReactor = {
      getEnergyProducedLastTick = function() return math.random(5000, 1000000) end,
      getFuelTemperature = function() return math.random(500000, 1000001) end,
      getCasingTemperature = function() return math.random(500000, 1000001) end
    }
    
    -- # the things we do.
    local threads = {
      -- # TE energy cells are typed as `energy_device` in my pack. Tweak if needed
      thread.create(monitorPower, component.list('energy_device'), 1),
      thread.create(monitorReactor, mockReactor),
      -- # clean up thread. hit ctrl+c to exit program
      thread.create(function()
        local name
        repeat
          name = event.pull(0, 'interrupted')
        until name == 'interrupted'
        print "\nquitting.."
      end)
    }
    
    -- # do the stuff until we interrupt the fun.
    thread.waitForAny(threads)
    os.exit(0) -- # stab all the other threads to death so we can finish
    
    --[[
      #  ** I know this isn't your whole program but it should demo how to use threads.
      #  All of those format functions are just there to keep the threads as simple
      #  as possible. They bake in [x,y] coords and a formatting function that wraps
      #  text in 'vt100' color codes('cause I'm duckin' lazy thats why).
    ]]

     

  6. 10 hours ago, EntityinArray said:

    Server is expensive but ok, thanks

    It's not that you need an actual 'server' but 1 of a pair of programs that acts the role of server. The 'client' can send a message to a 'server' to request that it(the server) calls a component method. The server then sends the result of that call back to the client. Presto, the client is using components on a separate network. Let me know if this isn't clear...

  7. I'm not sure component networks can be shared that way because of the problem you mentioned. Component networks are usually separated by a relay or a power distributer. If you want to call components remotely, on a separate network, you can try using a client server approach. Server 'offers' access to components. Client can connect and remote call component methods... Yadayada

  8. In your example the variable `address` is never defined.. and thus it's nil.

    local event = require("event")
    while true do
      -- # note we get the address from the event data. `_` is the event name 'motion'
      local _, address, x, y, z, name = event.pull("motion")  
      print("Detected:", address, x, y, z, name)
    end

     

  9. I feel like I should add some more information.. Just some things I learned asking around and poking at the OpenOS source. So here it goes. Term "windows" aren't really a feature of the OS, they're kinda hidden, and in my quest to abuse them I learned that at the moment they're kinda 'half baked', although functional. If you look at the `term` library you'll see that a lot of methods take an optional `window` argument but the library lacks a documented way to create or get a new or active pty. Wtf mang. Another tip would be to note that the computer has no preference for screen and/or keyboard proximity, hence why you're in this mess in the first place. So it would be handy to know that the "boot screen" is what will become the "primary" screen component and thus the init process(highest process in the OS) will bind the boot screen and first gpu compatible with that screen. `tty.window`  is referenced in `process.info(init_index).data.window`

    You can see more of this reflected in the concept of primary components and that even extends to the /dev dir... i.e.

    -- # get the first non-'primary' component of `ctype`
    local function getSecondary(ctype)
      -- # dev component/ listings start at 0. Thus /dev/components/by-type/`ctype`/1 is the second gpu..
      local fd = assert(io.open('/dev/components/by-type/'..ctype..'/1/address', 'r'))
      local address = fd:read('*a')
      fd:close()
      return address
    end

    You could use this in my example above.

    local component = require "component"
    local process = require "process"
    local term = require "term"
    
    local function getSecondary(ctype)
      local fd = assert(io.open('/dev/components/by-type/'..ctype..'/1/address', 'r'))
      local address = fd:read('*a')
      fd:close()
      return address
    end
    
    -- # Get the first non-primary gpu and screen, assuming that this is in a condition where we want to switch the screen...
    local termGpuAddr, termScrAddr = getSecondary('gpu'), getSecondary('screen')
    
    local termGpu = component.proxy(termGpuAddr)
    termGpu.bind(termScrAddr)
    
    local window = term.internal.open()
    term.bind(termGpu, window)
    window.keyboard = component.invoke(termScrAddr, 'getKeyboards')[1]
    
    local init_index = 1
    while true do
      if process.info(init_index + 1) then
        init_index = init_index + 1
      else
        break
      end
    end
    
    process.info(init_index).data.window = window

    I hope some of this info may save you some time.. Good luck. And feel free to ask away bud

  10. Maybe, opening a term window shouldn't be such a pain.. I have done it before, just need to remember and test how I did it... I'll post back asap

    I figured a way to switch terminals. Dunno if its a "good" way or not but it should work.

    local component = require "component"
    local process = require "process"
    local term = require "term"
    
    local termGpuAddr, termScrAddr = ... -- # use whatever logic you would to get the relevant component address (this line will cause an error if you dont shove some address in)
    
    local termGpu = component.proxy(termGpuAddr)
    termGpu.bind(termScrAddr) -- # component bind
    
    -- # I thought you could get the current term window with `process.info().data.window` or `rawget(process.info().data, 'window')` or `term.internal.window()`
    -- # for some reason getting the current window was giving me nil, even with rawget :/
    local window = term.internal.open() -- # create new term window
    term.bind(termGpu, window) -- # bind pty to gpu
    window.keyboard = component.invoke(termScrAddr, 'getKeyboards')[1] -- # dont forget a keyboard or it will use the last term kb
    
    -- # lastly you have to assign the window to an actual process. here we'll assign the init process our window. all child processes will inherit this window
    local init_index = 1
    -- # find the highest process (init)
    while true do
      if process.info(init_index + 1) then
      	init_index = init_index + 1
      else
        break
      end
    end
    
    -- # cram 'er in there. If you only want the current process to use the pty just use `process.info().data.window = window`
    process.info(init_index).data.window = window

    This is tested and should work. It did for me anyway. just adjust for termGpuAddr and termScrAddr

  11. For reasons... Not sure why, but the doc on term.bind is incorrect. term.bind actually take a gpu proxy and a term window(internal hidden feature). If you want to control which screen is used you can do some thing like this...

    local termScreen = ... -- # the screen you want a term on
    local termGpu = ... -- # the gpu the term should use
    
    -- # bind the screen to the proper gpu
    termGpu = component.proxy(termGpu)
    termGpu.bind(termScreen)
    
    -- # if the term is not bound to our term gpu/screen pair
    term.bind(termGpu) -- # second arg is actually a process window. nil get current term process window

    Hope this clears shit up...

  12. event.pull has an optional first argument, a timeout. 

    local name, _, x, y = event.pull(0.1, "touch")
    
    if name then -- # name will be nil if event.pull(0.1, ...) times out after 0.1 sec
      if y == 1 and x < 30 and x > 18 and reactorOnline then
        r.setActive(false)
      elseif y == 1 and x < 30 and x > 21 then
        r.setActive(true)
      elseif y == 8 and x == 21 or x == 22 then
        r.setAllControlRodLevels(rodLevel - 10)
      elseif y == 8 and x == 28 or x == 29 then
        r.setAllControlRodLevels(rodLevel + 10) 
      end
    end

     

  13. Im not sure really what you're going for.. But I think the update function needs a little work. Also the event listeners you create in the update function might be acting funny because they're in threads, which are like little processes, and I think processes dump they're event registrations when they're complete(this may be nonsense...). One other note, you may want to stick to the term library instead of tty. tty is a core lib an subject to change. I think with your current setup update could look like this(below) and still hypothetically work.

    local function update()
      local ev = {event.pull(1, "modem_message")}
      
      if ev[1] == "modem_message" and ev[6] == "scanData" then
        recieveScanData(table.unpack(ev))
        gButtons.update()
      end
    end

     

  14. You might want to look into something like event.listen or event.timer.

    Basically every time an event occurs you can have a block of code run. Here's a small example.

    local event = require "event"
    
    local function printComp(ev, addr, ctype)
      print(string.format("component added: [type] %s  [address] %s", ctype, addr))
    end
    
    event.listen('component_added', printComp)
    
    -- some time later
    event.ignore('component_added', printComp)

    Here's a timer example.

    local event = require "event"
    
    local count = 0
    
    local handle = event.timer(1, function()
      count = count + 1
      print(string.format("timer tick #%d", count))
    end, 10) -- # (how often, callback(), how many times)

     

×
×
  • Create New...

Important Information

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