local main_cmd="turtle.dig"
local direction="Down"
local params="()"
shell.run(main_cmd..direction..params)
To be more straightforward, I want a way to use a string like "turtle.digDown()" and make the turtle execute that.
This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
Executing a string as a Command
Started by Neander_King, 22 July 2015 - 06:30 PMPosted 22 July 2015 - 08:30 PM
For a little background, I am making yet another wireless turtle remote control program, and I want to be able to have the vast majority of the code exist solely on the pocket computer "remote" and have a turtle with a program that only listens for commands on a specific protocol, sends a response, and executes the received command. However, I don't know how to, or if it's possible, to execute a string as if it were a command. For example, I wrote this code which should take the two strings, concatenate them, and execute the result.
Posted 22 July 2015 - 09:12 PM
Well, you could loadstring the 'command' (which is Lua code) and run that. But I'd suggest not to if you're playing on a server, because somebody might send a virus that your program will run unknowingly. If the functions you want to run are simply turtle.dig or turtle.forward, then I'd suggest not having the client send the code a turtle should execute but rather a command telling what to execute. So you'd simply send something like "MOVE_FORWARD" and then the turtle would interpret that as a turtle.forward:
You could even take this design further by putting all the commands in a table and simplifying everything:
Of course, you may actually need to send custom code to the turtle, but from your example I figured you want to run pretty straight forward commands.
local trusted_id = 5 --# the id of the sending computer
while true do
local id, message = rednet.receive()
if id == trusted_id then
if message = "MOVE_FORWARD" then
turtle.forward()
end
end
end
You could even take this design further by putting all the commands in a table and simplifying everything:
local trusted_id = 5 --# the id of the sending computer
local commands = {} --# a table holding all the commands as keys and their respective functions as values
command["MOVE_FORWARD"] = function () --# make a function with some logic inside
if not turtle.detect() then
turtle.forward()
end
end
command["MOVE_BACK"] = turtle.back --# or simply assign one of the functions directly
while true do
local id, message = rednet.receive()
if id == trusted_id then
local command = commands[message] --# get the command from the table
if command then --# if there is a command
command() --# execute it
end
end
end
Of course, you may actually need to send custom code to the turtle, but from your example I figured you want to run pretty straight forward commands.
Posted 22 July 2015 - 09:24 PM
Thank you so much for the extra effort to explain the security aspect. I will definitely take your advice and store the commands on the turtle despite their simple nature.
Posted 22 July 2015 - 09:57 PM
Well, you could loadstring the 'command' (which is Lua code) and run that. But I'd suggest not to if you're playing on a server, because somebody might send a virus that your program will run unknowingly. If the functions you want to run are simply turtle.dig or turtle.forward, then I'd suggest not having the client send the code a turtle should execute but rather a command telling what to execute. So you'd simply send something like "MOVE_FORWARD" and then the turtle would interpret that as a turtle.forward:local trusted_id = 5 --# the id of the sending computer while true do local id, message = rednet.receive() if id == trusted_id then if message = "MOVE_FORWARD" then turtle.forward() end end end
You could even take this design further by putting all the commands in a table and simplifying everything:local trusted_id = 5 --# the id of the sending computer local commands = {} --# a table holding all the commands as keys and their respective functions as values command["MOVE_FORWARD"] = function () --# make a function with some logic inside if not turtle.detect() then turtle.forward() end end command["MOVE_BACK"] = turtle.back --# or simply assign one of the functions directly while true do local id, message = rednet.receive() if id == trusted_id then local command = commands[message] --# get the command from the table if command then --# if there is a command command() --# execute it end end end
Of course, you may actually need to send custom code to the turtle, but from your example I figured you want to run pretty straight forward commands.
Instead of using IDs (= rednet) it would be a bit more secure to use the modem API and a "random" channel. If you want to go even further, you could use Diffie Hellman to find a private, random channel.
But, well ,this random channel could still be "bruteforced" as in using ~500 computers listening to all channels.
Edited on 22 July 2015 - 07:58 PM
Posted 23 July 2015 - 07:26 AM
Instead of using IDs (= rednet) it would be a bit more secure to use the modem API and a "random" channel. If you want to go even further, you could use Diffie Hellman to find a private, random channel.
But, well ,this random channel could still be "bruteforced" as in using ~500 computers listening to all channels.
Err, wouldn't you only need one? Just open every channel and wait for a message?
Plus, someone would have to know about your program, its flaw, and have a motive to infiltrate it.
Though I agree its better to store functions locally and wait for a message to run them, rather than sending code around.
Posted 23 July 2015 - 08:30 AM
Err, wouldn't you only need one? Just open every channel and wait for a message?
The maximum number of channels you can open on a single modem is 128, so you'd need a bunch of computers and modems to sniff all 65535 channels.
Posted 23 July 2015 - 04:29 PM
If the only commands you use are the turtle API calls, you could pass your input into it this wayErr, wouldn't you only need one? Just open every channel and wait for a message?
The maximum number of channels you can open on a single modem is 128, so you'd need a bunch of computers and modems to sniff all 65535 channels.
turtle[input]()
Which would run any turtle cmand you sent it, without the need for expansive if statements
Posted 23 July 2015 - 06:17 PM
If the only commands you use are the turtle API calls, you could pass your input into it this way
turtle[input]()
Which would run any turtle cmand you sent it, without the need for expansive if statements
My example code does pretty much the same thing, except rather than calling functions of the turtle API directly, letting you create your own commands and functions.
Posted 24 July 2015 - 08:59 AM
True, however it is quite the simplest to justMy example code does pretty much the same thing, except rather than calling functions of the turtle API directly, letting you create your own commands and functions.
if turtle[cmd] then turtle[cmd]() end
Of course you could expand that to ALSO allow extra functions, by combining the both ideas.
if turtle[cmd] then
turtle[cmd]()
elseif tbl[cmd] then
tbl[cmd]()
end
Posted 24 July 2015 - 10:42 PM
True, but as dragon pointed out its easier that way, and another perk is that if say the turtle API gets updated and gets new functions, the program still works with zero change, as you dint need to add an if statement into it.If the only commands you use are the turtle API calls, you could pass your input into it this way
turtle[input]()
Which would run any turtle cmand you sent it, without the need for expansive if statements
My example code does pretty much the same thing, except rather than calling functions of the turtle API directly, letting you create your own commands and functions.
If you wanted to add.more APIs you could also do
Function run(APIName, funcName)
if _G[APIName][funcName] then
_G[APIName][funcName]()
End
End
Which would allow you to use any function in any loaded APIEdited on 24 July 2015 - 08:42 PM
Posted 25 July 2015 - 02:24 AM
If you go this far, you should also add support for functions which are saved directly in _G.True, but as dragon pointed out its easier that way, and another perk is that if say the turtle API gets updated and gets new functions, the program still works with zero change, as you dint need to add an if statement into it.If the only commands you use are the turtle API calls, you could pass your input into it this way
turtle[input]()
Which would run any turtle cmand you sent it, without the need for expansive if statements
My example code does pretty much the same thing, except rather than calling functions of the turtle API directly, letting you create your own commands and functions.
If you wanted to add.more APIs you could also doWhich would allow you to use any function in any loaded APIFunction run(APIName, funcName) if _G[APIName][funcName] then _G[APIName][funcName]() End End
Posted 25 July 2015 - 03:39 AM
True, but as dragon pointed out its easier that way,
I wouldn't say it's "easier" - and I wouldn't say Dragon said that, either.
I mean, yeah, the code ends up shorter on the turtle's side, but as a result you need to send a lot more data over rednet to get the job done. Would you rather you just sent a "go forward" command and the turtle went forward, or would you rather that you had to send a "go forward" command, check on the result, send another command to make the turtle dig / attack if the movement failed, send another "go forward" command, etc, etc, etc…?
It's "easier" to handle such things locally, on the turtle itself. Granted, having both options (which is what Dragon is suggesting) is better again, but if I were going to choose between the two methods, I'd do the same as MKlegoman357.
Edited on 25 July 2015 - 01:40 AM
Posted 25 July 2015 - 07:27 AM
Why not just have a proper turtle API loaded up instead and use that? I've rarely if ever keptnthe standard turtle API I always end up replacing it as my needs and base hardware developed such as GPS and the such, which would render the if once again much more complex for no reasonTrue, but as dragon pointed out its easier that way,
I wouldn't say it's "easier" - and I wouldn't say Dragon said that, either.
I mean, yeah, the code ends up shorter on the turtle's side, but as a result you need to send a lot more data over rednet to get the job done. Would you rather you just sent a "go forward" command and the turtle went forward, or would you rather that you had to send a "go forward" command, check on the result, send another command to make the turtle dig / attack if the movement failed, send another "go forward" command, etc, etc, etc…?
It's "easier" to handle such things locally, on the turtle itself. Granted, having both options (which is what Dragon is suggesting) is better again, but if I were going to choose between the two methods, I'd do the same as MKlegoman357.