1548 posts
Location
That dark shadow under your bed...
Posted 18 July 2012 - 10:15 AM
Just quick query, can you convert a string to a function so you can end a string over rednet and then execute it as a function? I know you can do this:
local id,cmd,dist=rednet.receive()
turtle[cmd]()
and then if you send the string "forward" it moves forward but this is then limited to anything starting with turtle.
another problem is that while you can assign a function to a variable (eg. local me=turtle.forward and then call me()) you cannot then include that in a table and serialize it as it is trying to combine a function and a string, I know you can convert things with tonumber() and tostring(), can you convert a string to a function?
515 posts
Location
Australia
Posted 18 July 2012 - 12:36 PM
Just quick query, can you convert a string to a function so you can end a string over rednet and then execute it as a function? I know you can do this:
local id,cmd,dist=rednet.receive()
turtle[cmd]()
and then if you send the string "forward" it moves forward but this is then limited to anything starting with turtle.
another problem is that while you can assign a function to a variable (eg. local me=turtle.forward and then call me()) you cannot then include that in a table and serialize it as it is trying to combine a function and a string, I know you can convert things with tonumber() and tostring(), can you convert a string to a function?
It's possible. This is how the lua program does it
--In this, the variable "s" is the string function you want to execute
local nForcePrint = 0
local func, e = loadstring( s, "lua" )
local func2, e2 = loadstring( "return "..s, "lua" )
if not func then
if func2 then
func = func2
e = nil
nForcePrint = 1
end
else
if func2 then
func = func2
end
end
if func then
setfenv( func, tEnv )
local tResults = { pcall( function() return func() end ) }
if tResults[1] then
local n = 1
while (tResults[n + 1] ~= nil) or (n <= nForcePrint) do
print( tostring( tResults[n + 1] ) )
n = n + 1
end
else
print( tResults[2] )
end
else
print( e )
end
445 posts
Posted 18 July 2012 - 12:59 PM
uhm why not just
func = loadstring(s)
func()
1548 posts
Location
That dark shadow under your bed...
Posted 18 July 2012 - 01:41 PM
AHAH! perfection, thanks
515 posts
Location
Australia
Posted 18 July 2012 - 02:42 PM
uhm why not just
func = loadstring(s)
func()
Ohhhh. I actually didnt understand how the lua program works XD new thing I learnt! thanks
445 posts
Posted 18 July 2012 - 02:52 PM
Might be able to even to like loadstring(s)()
1548 posts
Location
That dark shadow under your bed...
Posted 18 July 2012 - 02:58 PM
you should, that was my plan, along with a few other mean and nasty things I plan on implementing, no-one will be able to pirate my computers ever again :P/>/> although I am developing an automatic pirating system to overwrite and modify all computers within range of my base that are not in my accepted list of IDs… cc is the most awesome part of mc by far
445 posts
Posted 18 July 2012 - 03:04 PM
I don't see how that would work but if you say so :P/>/>
1548 posts
Location
That dark shadow under your bed...
Posted 19 July 2012 - 03:03 PM
Here is what you do:
you set up a modified gps satellite, it accepts any message as a gps request and does not send anything back to the requester, it sends it to your PC which checks its ID to see if it is yours, if it isn't then you send out a turtle to reprogram it (which is a whole other story 8o )
1548 posts
Location
That dark shadow under your bed...
Posted 19 July 2012 - 03:13 PM
that way you get its exact location and there is a process in which you can place a disk drive next to the pc, insert one and restart the pc, the disk's startup then rewrites the pc, the turtle then removes the disk drive and the apparatus used to place it and returns to your base, you can then use the pirated pc as another modified gps satellite to extend the reach of your overwriting system or you can use it as a signal disruptor etc
1604 posts
Posted 19 July 2012 - 03:19 PM
that way you get its exact location and there is a process in which you can place a disk drive next to the pc, insert one and restart the pc, the disk's startup then rewrites the pc, the turtle then removes the disk drive and the apparatus used to place it and returns to your base, you can then use the pirated pc as another modified gps satellite to extend the reach of your overwriting system or you can use it as a signal disruptor etc
The only problem is that turtles can't insert disks in the disk drives :P/>/>
I made a system like that, wich locates any computer that broadcasts a message. It's on the program library.
1548 posts
Location
That dark shadow under your bed...
Posted 19 July 2012 - 03:50 PM
REDPOWER!!!! it can be done lol, use deployers and transposers
109 posts
Posted 19 July 2012 - 05:50 PM
The only problem is that turtles can't insert disks in the disk drives :P/>/>
turtle selects obsidian pipe
places it next to disk drive (compared from inventory)
turtle drops disk
OR
turtle places disk drive next to a computer
turtle places obsidian pipe above that
turtle drops floppy in
And yes, obsidian pipes work with disk drives. Just tested it to verify it (it is a storage device after all)
This would of course require that mod. But most computer craft servers are tekkit servers anyways. It's highly likely to have them available. If not, there may be other methods in the future.
8543 posts
Posted 19 July 2012 - 07:02 PM
The only problem is that turtles can't insert disks in the disk drives :P/>/>
turtle selects obsidian pipe
places it next to disk drive (compared from inventory)
turtle drops disk
OR
turtle places disk drive next to a computer
turtle places obsidian pipe above that
turtle drops floppy in
And yes, obsidian pipes work with disk drives. Just tested it to verify it (it is a storage device after all)
This would of course require that mod. But most computer craft servers are tekkit servers anyways. It's highly likely to have them available. If not, there may be other methods in the future.
In the current version of ComputerCraft, turtles are unable to place pipes, to my knowledge. Did you test this portion of your suggestion as well?
1548 posts
Location
That dark shadow under your bed...
Posted 19 July 2012 - 07:10 PM
use transposers, I have fully tested the process and it works, you also have to use a deployer to place the disk drive but an automated overwrite is possible
445 posts
Posted 20 July 2012 - 07:59 PM
[…], obsidian pipes […]
lol, bc :)/>/>
839 posts
Location
England
Posted 04 August 2012 - 01:33 PM
Or alternatively, destroy the computer, bring it back to base, place it somewhere else, load it where your foe can't find it
If you try to rewrite things there are many issues:
1- what if the diskdrive on the pc is full
2-what if all perimeters of the computer are occupied
3-what if the owner sees your turtle coming and destroys it first, your enemy just gained control of your turtle and anything in it
Just an idea for a quick method, especially since pipes are slow. And no matter what happens, your bound to destroy your foe's computer.
1548 posts
Location
That dark shadow under your bed...
Posted 04 August 2012 - 02:15 PM
you can make the startup disk delete everything on the PC, eliminating the space issue (which wasn't a problem in 1.3 - when this topic was created)
the turtle can mine out a space next to the computer
with your method the owner could still see it coming
what do pipes have to do with it? use a redpower transposer
7 posts
Posted 22 October 2012 - 01:11 AM
Hi there.
After 5 hours I have decided to give up. I can't get it working, this loadstring stuff.
My script:
function test()
print("Test")
end
local s = "test"
func = loadstring(s)
func()
Running above 'eval' program gives error:
eval :8: attempt to call nil
Can anybody help?
231 posts
Posted 22 October 2012 - 01:54 AM
You use loadstring on the actual body of a function, not the name. For example:
local s = "print('Loadsting test')"
func = loadstring(s)
func()
2005 posts
Posted 22 October 2012 - 05:36 AM
Make func local too. And only execute func if it is non-nil, loadstring also provides an error message if the string provided isn't valid lua. So:
lua_string = read()
local func,errmssg = loadstring(lua_string)
if func then func() else print(errmssg) end
That way you, if you messed up the lua input, you get a output saying what was wrong rather than exiting your program.
7 posts
Posted 22 October 2012 - 09:33 AM
Ok then, is there any way to call pre-scripted function using same method? I want to make simple callback.
I have got API with menu generator. I do
addMenuOption(title,callback)
Then I can generate menu. What I would like to do is - when I press enter on selected menu option, "callback function" will start. And I wish to have it outside API, but it is hard to script functions inside a string :)/>/>
1548 posts
Location
That dark shadow under your bed...
Posted 22 October 2012 - 10:24 AM
that is easy to do without even using loadstring. just use
a=function() addMenuOption(title,callback) end
then when you say a() it will execute the code
2447 posts
Posted 22 October 2012 - 10:55 AM
Or you can just pass the function itself to the menu option add function - and just execute it like callback().
7 posts
Posted 22 October 2012 - 11:35 AM
I think I need to explain it more. My menu is stored in two tables
menuTitles and menuCallback
Each time I call
addMenuOption("sometitle","someCallbackFunction()")
It adds it to this two tables. Then I display it and choose using arrow keys and enter (all this by os.pullEvent)
So basicly when I press enter I would like to run function stored for that menu option in table menuCallback. To get it I use
menuCallback[active]
so it would return for example string
someCallbackFunction()
how to run this function now? I am stuck…
1548 posts
Location
That dark shadow under your bed...
Posted 22 October 2012 - 11:38 AM
oh right. then just use
loadstring(menuCallback[active])()
of the return event
7 posts
Posted 22 October 2012 - 11:52 AM
So my test script from previous page
function test()
print("Test")
end
local s = "test"
func = loadstring(s)
func()
I just have to change
local s = "test"
func = loadstring(s)
func()
To
local s = "test()"
loadstring(s)()
Correct? I will test it at home, now I have got only phone to learn theory of lua :-)
1548 posts
Location
That dark shadow under your bed...
Posted 22 October 2012 - 12:35 PM
exactly, this will also work
local s = "test()"
func = loadstring(s)
func()
you just need the () to call test
EDIT: please note you cannot use shell commands in loadstring so shell.run will not work
2447 posts
Posted 22 October 2012 - 06:11 PM
Why the Hell are you using loadstring for it? It is unnecessary. Rather than passing the name of the function, you can pass the function itself. You can turn store that function in the table, then call it.
2005 posts
Posted 22 October 2012 - 08:22 PM
Yeah…loadstring is more for when you don't already have the function written, and won't need to use it again.
If you want you can pass the function into a file, then execute that file. This is safer than loadstring for a remote operated turtle and the like, because if the file can't be run (or only runs partway before erroring) the turtle still resumes it's remote operation program. If you use lua, then if the form is correct but the content is screwy, the turtle errors out of it's program and you lose control.
1548 posts
Location
That dark shadow under your bed...
Posted 22 October 2012 - 09:08 PM
it is so that you can call a function with parameters. you can load print('hi') rather than just print, I do not know what his menu is for so I figured just include as much functionality as possible. calling it within a program is also useful in the case of errors but it creates more files on the PC and I am assuming that bonzaii will be doing all of the coding, ironing out the bugs
2447 posts
Posted 22 October 2012 - 09:16 PM
You can still call a function with arguments by passing the direct function too.
1548 posts
Location
That dark shadow under your bed...
Posted 22 October 2012 - 09:24 PM
yeah I guess you're right but that's a whole other story… anyways to summarise
Cloudy is right, his method works. I think mine would too, just a matter of opinion and what you consider to be good coding practise. staying with functions is a clean way of doing things so go ahead
7 posts
Posted 23 October 2012 - 12:11 AM
I still cannot get it work.
local function test()
print("Test!")
end
local s = "test()"
loadstring(s)()
returns:
string:1: attempt to call nil
I just don't understand that…
Edit:
I tried this aswell:
local function thetest()
print("Test!")
end
local s = "thetest()"
local func,errmsg = loadstring(s)
if func then func() else print(errmsg) end
Throws out same error:
string:1: attempt to call nil
Any ideas?
Edit2:
I thought that mayby loadstring() is messed up but I tried raw lua on computer's console:
>lua
lua>loadstring("print("TEST")")()
TEST
lua>
I am frustrated…
Edit3:
If I put into a file code:
loadstring("print("TEST")")()
it works, but when I try to use this:
function test() print("TEST") end
loadstring("test()")()
it doesn't work. :-(
2005 posts
Posted 23 October 2012 - 01:05 AM
No…loadstring creates a fresh environment to execute stuff, you can't use anything from your current environment. That's not how you're supposed to pass the function. If you have the function then just call the function, don't use loadstring. that's exactly what Cloudy said not to do.
2005 posts
Posted 23 October 2012 - 01:10 AM
Also, in " if func then func() else print(errmsg) end " the point is to see the error message without having your program terminated. If you omit the "else print(errmsg)" part, then you shouldn't see the error message, because your program shouldn't have terminated and so the only way it would be displayed was if you printed it. Or you can say "else print("Whew, that was close, "..errmsg)" so that you can see the difference.
7 posts
Posted 23 October 2012 - 04:12 PM
Thing is I need to delay execution of passed function until menu option has been activated. And I want to keep it flexible, that is why I want to keep it in tables / vars.
There will be menu api and script file that runs and configures that api. I just need to be able to add some extra functions without changing api, but need to be able to call them when api processes menu item activation (pressing enter)
If this is still hard to understand I will produce my code to pastebin tonight at home.
PS: sorry for being pain in an ass, sorry for my english too. Hope it is not that hard to understand me.
2005 posts
Posted 23 October 2012 - 05:26 PM
That's okay, it's hard to discuss programming in without having the code to work with.
7 posts
Posted 23 October 2012 - 10:55 PM
I think I found a solution. Only excuse for me now is that I used to program in PHP a lot, so solution like this would never come to my mind:
function SomeCallback()
print("Callback")
end
function doAction(callback)
print("Doing some action!")
callback()
print("End of frustration")
end
doAction(SomeCallback)
and output
Doing some action!
Callback
End of frustration
Sorry I wasted that much time of you guys, but I didn't know that I can use function as a variable (and pass it like a variable without calling it). It works perfect for me in my programs! That is basically what I have been looking for all this time.
Solution found on
CC Wiki (which I went through again, desperate)
Thanks for all your help, probably if my English have been better and I had uploaded my code straight away we would have it solved earlier. Thanks!
2447 posts
Posted 24 October 2012 - 10:16 AM
I did tell you that at least twice ^_^/>/>
2005 posts
Posted 24 October 2012 - 11:18 AM
Yes, but to be fair we were previously on the topic of turning a string sent over rednet into a function, and apparently the concept of passing a function as an argument was new as well.