- Sky
- Blueberry
- Slate
- Blackcurrant
- Watermelon
- Strawberry
- Orange
- Banana
- Apple
- Emerald
- Chocolate
- Charcoal
CptMercury
-
Content Count
54 -
Joined
-
Last visited
-
Days Won
7
Posts posted by CptMercury
-
-
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
-
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.
-
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.
-
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.
-
Nice job! Keep up the great work!
-
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.
-
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.
-
Ok, then it might be a bug, but I can't think of a reason why.
Are you working with a computer or a robot? Could you send a screen shot of your setup? We might find a solution.
-
Hey,
don't know why oppm isn't working, but you can simply run this command: wget https://raw.githubusercontent.com/OpenPrograms/Sangar-Programs/master/geo2holo.lua geo2holo.lua
-
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
-
Hey!
That is very strange, as this should work. Try this, if this doesn't work, something must be wrong.
local component = require'component' for i = 0, 5 do print(component.inventory_controller.getStackInSlot(i, 1)) end
-
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:)
-
What also helps to speed up screen redrawing is to update your screen dynamically, so that you are only reprinting the areas that actually changed. Also if you are moving large areas on your screen, like scrolling or dragging, make sure to use the gpu.copy method.
-
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.
-
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
-
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"?
-
I think there might be a better solution, but this is what I came up with:
local info = computer.getDeviceInfo() local cputier for k in pairs(info) do if info[k].class == "processor" then cputier = tonumber((info[k].product):match("%d")) end end
-
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
-
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.
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.
-
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.
-
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
-
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.
-
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.
-
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.
Error with string.format()
in Programming
Posted
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: