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

CptMercury

Members
  • Content Count

    54
  • Joined

  • Last visited

  • Days Won

    7

Posts posted by CptMercury

  1. It would be helpful to see the entire code of drawText, not only lines 39 - 50, but I may have found your problem.

    It seem like you named your variable 'string', is that right? If so, you are either overriding the global string variable, if you declared 'string' as a public variable, or if you used local, your code is not actually looking for the global 'string' variable, but for your local one. So basically, either way you don't have access to the string functions.

    In oder to solve this, you should not name your variables after globally ones unless you don't need to have access to them.

    Ok, for your code, you want a program that does a gpu set using a string or a number as input? And if it is a string, you want to replace all \n with ""?

    Then this might help:

    local function set(str, gpuProxy)
      checkArg(1, str, "number", "string")
      checkArg(2, gpuProxy, "table")
      -- checkArg to ensure you don't have any false input
      -- but you don't really need it
      
      if type(str) == "number" then
        str = tostring(str)
      elseif type(str) == "string" then
        str = str:gsub("\n", "")
      end
      gpuProxy.set(x, y, str)
    end

     

  2. The inputs for gpu.copy() are x, y, width, height, x_offset (relative position to x; so the new rectangle starts at coordinate x - tx), y_offset (same as for x_offset).

    So basically if you want to copy the lower part to the upper part, you have to call: 

    gpu.copy(1, y/2, x, y, 0, -y/2)
    -- x_offset is 0 because you want to have the rectangle at the same x position as the old one
    -- y_offset is -y/2 (-25 for tier 3 screen), because the rectangle starts at a smaller y value compared to the old one

     

  3. Alright, so I tried to incorporate a function for exporting into the searching algorithm. It does not contain all features your code has, but I think the message and red stone stuff is not too important for the search function, I hope you'll be able to add all the stuff that I left out.

    local component = require"component"
    local sides = require"sides"
    local event = require"event"
    
    local database = component.database
    local exportBus = component.me_exportbus
    local controller = component.me_controller
    
    
    local sleep = os.sleep
    
    -- exports an item stack using the connected export bus and the database
    -- @param label: lable of item (string)
    -- @param side: side (number)
    -- @param slot: slot number for export (number or nil, default: 1=
    
    local function export(label, side, slot)
      slot = slot or 1
      database.clear(1)
      controller.store({label = label}, database.address, 1)
      exportBus.setExportConfiguration(side, slot, database.address, 1)
      exportBus.exportIntoSlot(side, slot)
      sleep(0)
    end
    
    -- get a table of all items in the inventory
    local tbl = controller.getItemsInNetwork()
    
    -- fuzzy search allows you to specify one or multiple variables
    -- use nil for variables you don#t want to specify
    -- fuzzySearch(nil, 32, nil); fuzzySearch(nil, nil, 45) etc
    -- @param x: x value for label (number or nil if x shouldn t be specified)
    -- @param y: y value for label (number or nil)
    -- @param z: z value for label (number or nil)
    -- @param side: side of inventory (number)
    -- @param slot: slot number of inventory (number or nil, default: 1)
    
    local function fuzzySearch(x, y, z, side, slot)
      local pattern = (x or '%d+')..'%-'..(y or '%d+')..'%-'..(z or '%d+')
      for _, item in ipairs(tbl) do
        local label = string.match(item.label, pattern)
        if label then
          export(label, side, slot)
        end
      end
    end
    
    local format = '%d+-%d+-%d+'
    
    -- fuzzySearch2 uses a modified format string as input
    -- you can replace one or multiple '%d+' for a real number
    -- @param pattern: modified pattern (string)
    -- @param side: side of inventory (number)
    -- @param slot: slot of inventory (number or nil)
    
    local function fuzzySearch2(pattern, side, slot)
      for _, items in ipairs(tbl) do
        local label = string.match(items.label, pattern)
        if label then
         export(label, side, slot)
        end
      end
    end

    I did not do too much testing yet since I didn't have a lot of time and since you're dealing with 3d-printers and I don't know your setup, it is kinda hard to run tests under the right conditions, so I hope it works for you.

  4. Ok, I have never worked with the database component before, so I don‘t know what its limits are. But is it really necessary to use the database? Isn‘t it enough to just use the ae2 methods and look for items‘ names? Or are the labels you set not visible for the ae2 api?

    I‘m currently kinda busy, but on friday I will have some time to do some investigation using the database. I will let you know when I found a solution.

  5. Hey, here is a list of all methods for ic2 reactors.

    local component = require'component'
    local reactor = component.reactor
    
    reactor.getHeat()
    reactor.getMaxHeat()
    reactor.getReactorEUOutput()
    reactor.getReactorEnergyOutput()
    reactor.producesEnergy()

    You have to connect the reactor via an adapter.

  6. Alright, I guess I know now what you want to do.

    I came up with some code that allows you to do some fuzzy search, just like you wanted..hopefully

    local tbl = require'component'.me_controller.getItemsInNetwork()
    -- tbl contains all items, from getItemsInNetwork methods 
    
    -- fuzzy search allows you to specify one or multiple variables
    -- use nil for variables you don#t want to specify
    -- fuzzySearch(nil, 32, nil); fuzzySearch(nil, nil, 45) etc
    -- this function currently looks for the 'name' entry in the table, you might need to change that
    
    local function fuzzySearch(x, y, z)
      local pattern = (x or '%d+')..'%-'..(y or '%d+')..'%-'..(z or '%d+')
      for _, items in ipairs(tbl) do
        if string.match(items.name, pattern) then
          -- do stuff
        end
      end
    end
    
    local format = '%d+%-%d+%-%d+'
    
    -- fuzzySearch2 uses a modified format string as input
    -- you can replace one or multiple '%d+' for a real number
    -- '%d+%-32%-%d+', '%d+%-%d+%-45', etc
    
    local function fuzzySearch2(pattern)
      for _, items in ipairs(tbl) do
        if string.match(items.name, pattern) then
          -- do stuff
        end
      end
    end

    You still have the issue that you actually have to traverse all items in the ME-system, but since Lua is a fast and efficient language, that shouldn't be a problem.I did some testing and traversing a table with 125000 entries took only around 0.03 s, so that should be fine.

    Hopefully this is what you were looking for and it actually helps.

  7. Hey,

    I might have an idea how to solve your issue, but some more information might help. With what method you get these specific labels? I've been using OC with AE2 a couple times and I do not remember any method that provided data about stored items in that specific format. If you could tell me in what kind of data structure you have stored these labels and stuff like that, I might be able to help you.

  8. I guess the geolyzer would be your best choice. I have not worked with them yet, but I guess you could do the following:

    You scan a large area using the geolyzer,  so you don't use the 'analyze' method but the 'scan' method, that way you can scan large areas at once. This is going to take a while, it takes (I think) 0.05 s to scan one block. The max column height is 64 blocks (32 up and 32 down) but sadly I can't tell you what's the radius of the geolyzer. You don't get the kind of block at each position but the 'density' and ores have a high density. That way you scan the entire area and know exactly where ores are and you don't waste time and energy digging around (since you said you would like to scan adjacent blocks I guess your robot would strip mine?). 

    Looking at Sangar's 'geo2holo' program might help understanding how the 'scan' method works. https://github.com/OpenPrograms/Sangar-Programs/blob/master/geo2holo.lua

  9. Hey!

    It is not that hard to run a program on multiple screens and being able to interact with all monitors. If you want to have the terminal on multiple screens you could modify the modules and then restart the computer, but there might be a better solution than this.

    One gpu can only be bound to one screen, so you could basically write a lib that will redirect any gpu call to a function that iterates through all screens, binding the gpu and call the function for every screen.

    Instead of doing this by hand for every function, we're going to use metatables (if you don't know about metatables, you should definitely check them out, they are a really powerful tool in Lua). 

    Basically metatables allow you to change the way how objects behave in different situations, for example when exposed to an arithmetic or relational operator (this way you can tell Lua how to add 2 tables, check for equality etc; in regular Lua, you can also change the metatables of strings, but opencomputers removes that ability). The most powerful meta methods are __index and __newindex. They are triggered when you look up (or modify) an absent key. Instead of returning nil, if present, these meta methods are invoked. 

    The __index meta method is what we're going to use for the implementation. We create a proxy table for the gpu, that will then return a function to iterate over all the screens.

    local component = require'component'
    local gpu = component.gpu
    
    
    -- # create table containing all screens
    local screens = component.list('screen')
    
    -- # instead of invoking 'component.list' every time we make a gpu call
    -- # we just update the list whenever a screen is added or removed
    local function updatescreens(event, addr, ctype)
      if ctype ~= 'screen' then return nil end
      if event == 'component_added' then
        screens[addr] = 'screen'
      else
        screens[addr] = nil
      end
    end
    
    -- # listening to component adding or removing events, invoking 'updatescreen' on event
    require'event'.listen('component_added', updatescreens)
    require'event'.listen('component_removed', updatescreens)
    
    -- # creating proxy table for gpu calls
    local vgpu = {}
    -- # making vgpu its own metatable
    setmetatable(vgpu, vgpu)
    
    -- # would not make sense to call 'bind' for every screen
    vgpu.bind = gpu.bind
    
    -- # '__index' function
    function vgpu.__index(self, key)
      -- # since some gpu methods return some data, we differentiate between 'setter' and 'getter' methods
      -- # most setter function have 'set' in their name, 'fill' and 'copy' are the exception 
      local setter = { copy = true; fill = true}
      if key:find('set') or setter[key] then
        -- # function that will only call the methods, does not return anything (for setters)
        return function(...)
          for addr in pairs(screens) do
            self.bind(addr)
            gpu[key](...)
          end
        end
      else
        -- # function that will return data (for getters)
        -- # returns table with screen address as key and table or single object as value
        -- # {'addr 1' = value1, 'addr 2' = value2, ...}
        return function(...)
          local res = {}
          for addr in pairs(screens) do
            self.bind(addr)
            local r = {gpu[key](...)}
            res[addr] = #r == 1 and r[1] or r
          end
          return res
        end
      end
    end
    
    -- returns gpu proxy, so it can be used as a module
    return vgpu

    If you have a keyboard attached to all screens, you are able to interact with all of them using a basic event handler.

    If you have any further questions, feel free to ask:)

  10. You can use io.open(path):read() to read a specific line, but only indirectly. But it might be easier to use the iterator io.lines(path).

    -- # use io.read to get the whole file, it returns a string; then use string.gmatch/string.match to extract the specific line
    -- # Examples:
    -- # Ex1: get line 5
    local path = "/somepath"
    local count = 1
    local targetline = 5
    local file = io.open(path):read("*all")
    
    for line in file:gmatch("[^\n]+") do
      if count == targetline then return line end
      count = count + 1
    end
    
    -- # Ex2: find line starting with #
    local path = "/somepath"
    local indicator = "#"
    local file = io.open(path):read("*all")
    
    return file:match("["..indicator.."][^\n]+")
    
    -- # io.lines iterator, returns new line whenever it's called
    -- # Examples:
    -- # Ex1: get line 5
    local path = "/somepath"
    local count = 1
    local targetline = 5
    
    for line in io.lines(path) do
      if count == targetline then return line end
      count = count + 1
    end
    
    -- # Ex2: find line starting with #
    local path = "/somepath"
    local indicator = "#"
    
    for line in io.lines(path) do
      if line:sub(1, #indicator) == indicator the return line end
    end

     

    I only got quotation marks in the  string returned by io.open():read() when I just ran io.open():read() in the Lua prompt; when I used print(io.open():read()) or io.write(io.open():read()) it printed the string without quotation marks in the output.

     

  11. Hey

    If you want to insert a variable into a existing string, you can use the concat operator .. (2 dots).

    io.open("/WH/db/"..LOC, "w")
    -- # this will create a string that starts with /WH/db/ and ends with the string contained by LOC

     

  12. Looking good, neat program!

    Some advice for dealing with strings:

    If you want to print some text on your screen and insert some numbers/other variables/returns of functions etc. into that text, instead of writing one part of the text, writing the number, and write the second part of the text you can just concatenate(connect) the different strings and the numbers using the concat operator ..  (2 dots), then print it. In other words, combine all the different parts of the text first, and then write it to the screen. This will reduce the number of lines in your code and less screen operations are performed.

    io.write("string1")
    io.write("string2")
    -- # -> string1string2
    
    -- # you get the same result with
    
    io.write("string1".."string2")
    -- # -> string1string2
    
    -- # you can include numbers with
    
    io.write("string"..1.."string"..2)
    -- # -> string1string2
    
    -- # you dont have to use the strings/numbers directly, variables containing strings and numbers work fine as well
    
    local s = "string"
    local num1 = 1
    local num2 = 2
    
    io.write(s..num1..s..num2)
    -- # -> string1string2
    
    -- # one example of your code would be: line 55 - 59
    term.write("Energy available/maximum: "..computer.energy().."/"..computer.maxEnergy().."\n")

    And one question: do you actually want the program to wait before printing a new set of information on the screen or do you just want to let your program yield in order to avoid "too long without yielding errors"?

  13. The main problem here is that "==" is used to compare two values and it returns true or false: 4 == 4 -> true; 4 == 5 -> false

    The other thing is that the response is not a string, but an iterator that will return the next line whenever you call it.

    local internet = require'internet'
    local url = '...'
    
    local response = interent.request(url)
    if response then
      for line in response do
        io.write(line.."\n")
      end
    end
    
    -- # response is an iterator, each time it's called it returns the next line/chunk, this is then stored in the var "line"
    -- # then you can use the var and print/write it, store it in a table etc

     

  14. Well, more practical might be not the best way to put it, but it'll reduce the amount of components you need to hook up to your computer, so reading the energy consumption of a few energy cells or of hundreds doesn't really make a difference. But you need a central place to set this system up and each energy connection cannot connect with others from this point on. It also might require some more coding than using that simple approach.

    2018-03-12_20_26_26.png.e3f91507d1b1c27341c34ca1b641f414.png

    Basically you have an array of 2 energy cells for each base. The robot will move back and forth placing down the adapter and applying the Redstone signal to toggle the input for a second. Then it will remove the adapter again and moves to the next position. The computer then can read the energy consumption of each energy cell. Of cause this system is kinda complicated and might take some time to be set up, but it would be easy to extend that system. Biggest downside is all the energy lines cannot be interconnected after that point. You would need to run individual power lines to each base or use some means of wireless power transportation. Even though being somewhat strange looking and not that resource efficient in terms of energy cells/ cabling required it's certainly the most "practical" way I can come up with to solve your issue.

  15. Ok, so how is your town‘s energy supply set up? Do you have central power generation and then transfer the energy to each base?

    If that‘s the case I might have a different approach that would make the setup smaller and more practical.

  16. Hey,

    I hope I interpreted your question correctly. You want to monitor how much energy your base actually consumes, the rf/t that leaves your energy storage device and not the relative difference between input and output, right?

    I did some testing and I came up with a solution that give you exactly that, the rf/t output of the storage device (used TE energy cell), now matter how much you input. This will stop the output of the cell for a limited amount of time tho (this is needed to do the calculation), so it's best to put a small energy storage device between the actual energy storage where you do the monitoring and your grid feeding your machines.

    Basically what I do is the following:

    1. measure the relative energy difference in the device for a given period of time, divided by the amount of ticks waited --> the DIFFERENCE between input and output ( in rf/t)

    2. disable the energy output of the device by applying a Redstone signal

    3. measure the energy difference again and reenabling the output again (again divided by amount of ticks) --> the TOTAL input (in rf/t)

    4. getting the difference between total input and relative change in rf --> the output (in rf/t)

    local component = require'component'
    local energyCell = component.energy_device
    local rs = component.redstone
    local side = 4      -- # side where your energy storage device is (relative to redstone i/o)
    local wait = .5     -- # time waiting between checking the energy level
    
    function getOutput()
      local init_rf = energyCell.getEnergyStored()  -- # rf base level
      os.sleep(wait)
      local rel_rf = (energyCell.getEnergyStored() - init_rf) / (wait + .05)  / 20 -- # rf difference
      rs.setOutput(side, 15)
      init_rf = energyCell.getEnergyStored()
      os.sleep(wait)
      local tot_rf_in = (energyCell.getEnergyStored() - init_rf) / (wait + .05)  / 20  -- # total rf input
      rs.setOutput(side, 0)
      local tot_rf_out = tot_rf_in - rel_rf  -- # total rf output
      return tot_rf_out
    end
    
    -- # apparently it takes one tick to read the rf level in the device, that's why I added .05 seconds
    -- # to the time waited in the rf/t calculations
    -- # the rf/t values are 100% correct, at least for TE energy cell

    you have to set the Redstone behavior to disable output when a Redstone signal is applied

  17. Ok, did some testing:

    You can see whats going on in a TE machine by using an adapter with an inventory controller inside, but you can not push items in/pull items out.

    For i/o interaction you have to use an robot equipped with an inventory controller. Then you can transfer items in and out of the machine using the robots inventory as a buffer.

    local component = require'component'
    local inv = component.inventory_controller
    local side = x -- #side where your inventory is attached
    
    -- #i/o stuff
    inv.suckFromSlot(side, slot, itemCount)
    inv.dropIntoSlot(side, slot, itemCount)
    
    -- #inventory checking
    inv.getStackInSlot(side, slot)
    inv.getInventorySize(side)

    Btw, the machine's side facing the robot/adapter must be set to the grey i/o configuration, in order to get access to all slots of the machine.

  18. You might be able to manage i/o with an adapter. Just place the adapter next to the machine and put an invetory controller inside the adapter. With this you should be able to interact with the item slots in the machine. You still can not access the mashine directly, you call functions on the controller. I‘ll try it later and let you know.

  19. Btw if you want to speed up the drawing process, here are some tips:

    A gpu can only perform a small amount of tasks each tick. 4 copy, 8 fill, 16 set, 8 setBackground and 8 setForeground; if you call more of these funtions, they are delayed, and it seems that you call a ton of these funtions. For example instead of using gpu.fill in order to set  a single character use gpu.set() since you can call it 16 times per tick. And if you want to fill a line in x direction with a string like "/" you can use gpu.set(x,y,string.rep("/", n)); the string "/" is replicated n times. This can also reduce the amount of fill commands and speeds up drawing. Using gpu.copy would increase your drawing speed the most. This copies one area of the screen and pastes it to a different area. So you would draw one of each objects on your screen, without the damage bar. Then you would copy the objects to all the desired locations and draw the damage bar. That way you wold be able to draw 80 objects per second, so a lot faster than you are currently be able to.

×
×
  • Create New...

Important Information

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