This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
CaptainAether's profile picture

How can I request a variables value from user input?

Started by CaptainAether, 12 September 2013 - 04:05 AM
CaptainAether #1
Posted 12 September 2013 - 06:05 AM
Title: How can I request a variables value from user input?

I'm writing a custom program for the new Direwolf20 pack and using the Terminal Glasses. I've added a developer mode to my program to help me track the variables but have hit a snag. The glasses uses minecraft chat, and the command starts with $$. so my command for getting a value is $$getVar variable where variable is the variable I want it to check. In essence if I say $$getVar devMode, it should return saying that the variable "devMode" (which is a boolian) is "true" since the command can only be run when devMode is true. How can I take this user input, and get the value of a variable from that? I've included some snips of the code below.

This is what I have so far:


local function getVar()
  if devMode then
	var = tostring(words[1])
	value = words[1]
	Text.setText("The variable ~"..var.."~ is currently: "..value)
	sleep(resultTime)
	Text.setText("")
	return
  else
	Text.setText("This command only available in Developer Mode")
	sleep(resultTime)
	Text.setText("")
	return
  end
end

this is what grabs the user input:



local function command()

  while true do
  
  evt, command = os.pullEvent("chat_command")
  words = {}
  i = 0

  for word in string.gmatch(command, "%S+") do
	words[i] = word
	i = i + 1
  end

	if string.lower(words[0]) == "?" then
	variables["searchString"] = string.lower(tostring(words[1]))
	printSearch()
	elseif words[0] == "reset" then
	resetScreen()
	elseif words[0] == "newZone" then
	timeZone = tostring(words[1])
	changeZone()
	elseif string.lower(words[0]) == "!" then
	chat()
	elseif words[0] == "update" then
	update()
	elseif words[0] == "newSettings" then
	settings()
	elseif words[0] == "devToggle" then
	devToggle()
	elseif words[0] == "getVar" then
	getVar()
	else
	badCommand()
  end
end


however when I run $$getVar devMode it returns:

The variable ~devMode~ is currently: devMode


I've tired searching, but I cant quite seem to get the answer I was looking for, I was hoping someone here would know how to solve this.
Bubba #2
Posted 12 September 2013 - 08:31 AM
There are several ways to do this. The first and best way to do it would be to put all the variables you want to be accessible in a table like so:

local vars = {
  devMode = true,
  currentUser = "Bubba"
}

Next you need the words table that has the user input. It's easy to get the value of the variable by using the index in the table like so:

local function getVars(var)
  return "the value of "..var.."is "..tostring(vars[var])
end

You could also use global variablesand access them using the_G table:

devMode=true

function getVar(var)
  return "the value of "..var.." is "..tostring(_G[var])
end
CaptainAether #3
Posted 12 September 2013 - 01:54 PM
If I trun my variables into global variables, would there be any significant downsides that I should worry about?
Lyqyd #4
Posted 12 September 2013 - 02:47 PM
They will be global. Any other program running on that computer can access and modify them, and they'll stick around after your program ends.
CaptainAether #5
Posted 12 September 2013 - 03:06 PM
But as this is the only program on that computer I should be good. Awsome. Thank you both very much! I'll try this out later and see how it goes!
CaptainAether #6
Posted 12 September 2013 - 03:54 PM
So I tried this, and when I checked devMode, it returned as nil.
Bubba #7
Posted 12 September 2013 - 04:08 PM
Could we see the code?
CaptainAether #8
Posted 12 September 2013 - 05:49 PM

-- This version adds slight changes in the background of the code, as well as code optimization. Item list has also been changed slightly.

local itemIds = REDACTED DUE TO TABLE SIZE

-- This is the time that results and text other than clocks are displayed before clearing
resultTime = 5

-- DO NOT CHANGE ANYTHING BELOW THIS LINE

-- You no longer need to define these. The program will help you define them instead
defaultTimeZone = "notSet"
defaultTimeZoneCode = "notSet"
bridgeName = "notSet"

currentVersion = 5
updateCheck = false
devMode = false

bridge = peripheral.wrap("bottom") -- Location of Terminal Glasses Bridge
bridge.clear()

net = peripheral.wrap("back") -- Location of Wired Modem for ME Bridge
IGT = bridge.addText(2, 7, "", 0xffffff)
RLT = bridge.addText(4, 16, "", 0xffffff)
Text = bridge.addText(6, 25, "", 0xffffff)

if fs.exists("settings") then
    settingValues = nil
    filePath   = "settings"
    fileHandle = fs.open (filePath, 'r')
    settingValues = textutils.unserialize (fileHandle.readAll())
    fileHandle.close()
    defaultTimeZone = settingValues[1]
    defaultTimeZoneCode = settingValues[2]
    bridgeName = settingValues[3]
  else
    Text.setText("What time zone should I use? EX: $$America/Chicago")
    e, msg = os.pullEvent("chat_command")
    defaultTimeZone = msg
    Text.setText("What time zone code should I use? EX: $$CDT")
    e, msg = os.pullEvent("chat_command")
    defaultTimeZoneCode = msg
    Text.setText("What is the name assigned to your ME Bridge? EX: $$meBridge_0")
    e, msg = os.pullEvent("chat_command")
    bridgeName = tostring(msg)
    settingValues = {defaultTimeZone, defaultTimeZoneCode, bridgeName}
    filePath   = "settings"
    fileHandle = fs.open (filePath, 'w')
    fileHandle.write (textutils.serialize (settingValues))
    fileHandle.close()
    Text.setText("")
  end

variables = {
  ["searchString"] = "",
  ["controller"] = bridgeName,
  ["chatString"] = ""
}
displayStrings = {}

timeZone = defaultTimeZone
timeZoneCode = defaultTimeZoneCode

function printSearch()
  i = 1
  pxFromTop = 25

  tableInfo = net.callRemote(variables["controller"], "listItems")

  displayStr = bridge.addText(6, pxFromTop, "", 0xffffff)
  displayValue = string.format("ME search for '%s': ", variables["searchString"])
  displayStr.setText(displayValue)
  displayStrings[i] = displayStr
  -- key = itemId, value = amount
  for key, value in pairs(tableInfo) do
    if itemIds[key] ~= nil and string.find(string.lower(itemIds[key]), variables["searchString"]) then
	  i = i + 1
	  pxFromTop = pxFromTop + 10
	  displayStr = bridge.addText(16, pxFromTop, "", 0xffffff)
	  displayValue = string.format("- %s = %i", itemIds[key], value)
	  displayStr.setText(displayValue)
	  displayStrings[i] = displayStr
    end
  end

term.clear()
term.setCursorPos(1,1)
term.write("ME Search System")
term.setCursorPos(1,3)
term.write("Users Connected at last search:")
term.setCursorPos(1,2)
term.write("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
term.setCursorPos(1,5)

tableInfo = bridge.getUsers()
for key, value in pairs(tableInfo) do
  print(key .. " = " .. tostring(value))
end

  sleep(resultTime)

  for key, displayStr in ipairs(displayStrings) do
    displayStr.delete()
    displayStr = nil
  end
end

local function update()
    http.request("http://pastebin.com/raw.php?i=ek9NSCpd")
    requesting = true
    while requesting do
	 event, url, sourceText = os.pullEvent()
	 if event == "http_success" then
	  result = sourceText.readAll()
	  onlineVersion =  tonumber(result)
	  requesting = false
	    if currentVersion < onlineVersion then
		  Text.setText("An update is available, would you like to update? EX: $$yes or $$no")
		  e, msg = os.pullEvent("chat_command")
		  msg = string.lower(msg)
		    if msg == "yes" then
			  bridge.clear()
			  shell.run("update")
			  error()
		    elseif msg == "no" then
			  Text.setText("Update aborted.")
			  sleep(resultTime)
			  Text.setText("")
			  return
		    else
			  Text.setText("Unknown reply, update aborted.")
			  sleep(resultTime)
			  Text.setText("")
			  return
		    end
	    else
		  Text.setText("Your AetherVision is up-to-date.")
		  sleep(resultTime)
		  Text.setText("")
		  return
	    end
	 else
	  Text.setText("Server didn't respond, check aborted.")
	  sleep(resultTime)
	  Text.setText("")
	  requesting = false
	  return
	 end
    end
end

local function autoUpdateCheck()
  while true do
    if updateCheck then
	  update()
	  updateCheck = false
    end
  sleep(0.5)
  end
end

local function chat()
  message = ""
  chatMessage = bridge.addText(6, 25, "", 0xffffff)
    for i=1,#words do
	  message = message.." "..words[i]
    end
    chatMessage.setText(message)
    
    sleep(resultTime)

    chatMessage.delete()
    chatMessage = nil
end

local function resetScreen()
  timeZone = defaultTimeZone
  timeZoneCode = defaultTimeZoneCode
  bridge.clear()
  IGT.delete()
  RLT.delete()
  IGT = nil
  RLT = nil
  IGT = bridge.addText(2, 7, "", 0xffffff)
  RLT = bridge.addText(4, 16, "", 0xffffff)
end

local function badCommand()

  failure = bridge.addText(16, 24, "", 0xffffff)
  failure.setText("Unknown Command")
  sleep(resultTime)
  failure.setText("")
end

local function changeZone()
			    displayStr = bridge.addText(16, 24, "", 0xffffff)
			    displayStr.setText("What is the new zone code? EX: $$CDT")
			    while true do
					    local e, msg = os.pullEvent("chat_command")
					    timeZoneCode = msg
					    displayStr.setText("Clock updated!")
					    sleep(resultTime)
					    displayStr.setText("")
					    return
			    end
end

function getTime()
  while true do
    if not http then error("no http") end
    httpResponseHandle = http.get("http://artemix.hu/cctime.php?timezone="..timeZone)
	  if not httpResponseHandle then error("error fetching time") end
	    timeTable = textutils.unserialize(httpResponseHandle.readAll())
	    httpResponseHandle.close()
	    hour = timeTable.h
	    minute = timeTable.m
	    second = timeTable.s
	    empty = ""
 
    if not (second < 60) then
	    second = second - 60
	    minute = minute + 1
    end
    if not (minute < 60) then
	    minute = minute - 60
	    hour = hour + 1
    end
    if not (hour < 24) then
	    hour = hour - 24
    end
    if (hour > 12) then
	    hour = hour - 12
	    AP = "PM"
	  else
	    AP = "AM"
	    end
	  realTime = string.format("%02d:%02d %s %s", hour, minute, AP, timeZoneCode)

	  time = os.time()
	  time = textutils.formatTime(time, false)

	  if devMode then
	  time = time.." ~Dev Mode~"
	  end

	  IGT.setText("")
	  RLT.setText("")

	  IGT.setText(time)
	  RLT.setText(realTime)

	  if (hour==3) or (hour==6) or (hour==9) or (hour==12) then
	   if (minute==00) and (second==00) then
		 updateCheck = true
		 end
	  end
  sleep(0.5)    
  end
end

local function settings()
    Text.setText("What time zone should I use? Current: "..defaultTimeZone)
    e, msg = os.pullEvent("chat_command")
    defaultTimeZone = msg
    Text.setText("What time zone code should I use? Current: "..defaultTimeZoneCode)
    e, msg = os.pullEvent("chat_command")
    defaultTimeZoneCode = msg
    Text.setText("What is the name assigned to your ME Bridge? EX: $$meBridge_0")
    e, msg = os.pullEvent("chat_command")
    bridgeName = tostring(msg)
    settingValues = {defaultTimeZone, defaultTimeZoneCode, bridgeName}
    filePath   = "settings"
    fs.delete("filePath")
    fileHandle = fs.open (filePath, 'w')
    fileHandle.write (textutils.serialize (settingValues))
    fileHandle.close()
    Text.setText("")
end

local function devToggle()
  if devMode then
    Text.setText("Currently in Developer Mode. Turn off Developer Mode? $$Y/N")
    e, msg = os.pullEvent("chat_command")
	  if msg == "Y" then
	    Text.setText("Developer Mode disabled")
	    devMode = false
	    sleep(resultTime)
	    Text.setText("")
	    return
	  elseif msg == "N" then
	    Text.setText("Staying in Developer Mode")
	    sleep(resultTime)
	    Text.setText("")
	    return
	  else
	    Text.setText("Unknown reply. Staying in Developer Mode")
	    sleep(resultTime)
	    Text.setText("")
	    return
	  end
  else
    Text.setText("Currently not in Developer Mode. Turn on Developer Mode? $$Y/N")
    e, msg = os.pullEvent("chat_command")
	  if msg == "Y" then
	    Text.setText("Input developer password")
	    e, pass = os.pullEvent("chat_command")
		  if pass == "AV2248" then
		    Text.setText("Developer Mode enabled")
		    devMode = true
		    sleep(resultTime)
		    Text.setText("")
		    return
		  else
		    Text.setText("Incorrect password")
		    sleep(resultTime)
		    Text.setText("")
		    return
		  end
	  elseif msg == "N" then
	    Text.setText("Staying out of Developer Mode")
	    sleep(resultTime)
	    Text.setText("")
	    return
	  else
	    Text.setText("Unknown reply. Command aborted")
	    sleep(resultTime)
	    Text.setText("")
	    return
	  end
  end
end

local function getVar()
  if devMode then
    var = tostring(words[1])
    Text.setText("The variable ~"..var.."~ is currently: "..tostring(_G[var]))

    sleep(resultTime)
    Text.setText("")
    return
  else
    Text.setText("This command only available in Developer Mode")
    sleep(resultTime)
    Text.setText("")
    return
  end
end

local function command()

  while true do
 
  evt, command = os.pullEvent("chat_command")
  words = {}
  i = 0

  for word in string.gmatch(command, "%S+") do
    words[i] = word
    i = i + 1
  end

    if string.lower(words[0]) == "?" then
    variables["searchString"] = string.lower(tostring(words[1]))
    printSearch()
    elseif words[0] == "reset" then
    resetScreen()
    elseif words[0] == "newZone" then
    timeZone = tostring(words[1])
    changeZone()
    elseif string.lower(words[0]) == "!" then
    chat()
    elseif words[0] == "update" then
    update()
    elseif words[0] == "newSettings" then
    settings()
    elseif words[0] == "devToggle" then
    devToggle()
    elseif words[0] == "getVar" then
    getVar()
    else
    badCommand()
  end
end
end

parallel.waitForAny(getTime, command, autoUpdateCheck)
CaptainAether #9
Posted 14 September 2013 - 10:18 AM
Any suggestions?
Zudo #10
Posted 14 September 2013 - 12:58 PM
Any suggestions?

I am not a mod, but I detest bumping.
Bubba #11
Posted 14 September 2013 - 01:42 PM
Any suggestions?

I am not a mod, but I detest bumping.

Oh please. This guy just wants some help and has not had any after 3 days. Bumping is perfectly acceptable in this situation.

@OP - What is the exact error code (and line number) that you're getting? What are you typing to get the variable?
CaptainAether #12
Posted 14 September 2013 - 06:34 PM
There is no error, but when it runs the lookup feature, the result is Nil. It returns "The variable ~devMode~ is currently: nil" when it should be true
kreezxil #13
Posted 14 September 2013 - 08:51 PM
Spoiler

local function getVar()
  if devMode then
	var = tostring(words[1])
	Text.setText("The variable ~"..var.."~ is currently: "..tostring(_G[var]))

	sleep(resultTime)
	Text.setText("")
	return
  else
	Text.setText("This command only available in Developer Mode")
	sleep(resultTime)
	Text.setText("")
	return
  end
end

So I'm looking at this code and I realize that the line
 var=tostring(words[1])
appears unnecessary considering the words table is comprised of strings to begin with; ie words[1] is already a string.

Now I've fired up my lua interpreter in computer craft and began testing the code on the line that returns nil. Explicitly I noticed these things happening
  1. No matter the name of your variable, _G[var] returns empty or blank
  2. applying tostring to that makes it return nil
  3. Apparently there is NO _G table
So I strongly suggest using that vars = {} table method that Bubba suggested.
CaptainAether #14
Posted 14 September 2013 - 10:03 PM
I am tostring'ing it just incase I ever have a number used. I like to cover my bases to play it safe. Its a bad habit of mine.

Yeah. I was thinking I may have to convert my variables to a table. I was just hoping I could avoid it, as It means rummaging through the code and I wanted to be a bit lazy. xD Oh well. guess it cant be helped. I'll try this out and see if that fixes it!
Engineer #15
Posted 15 September 2013 - 04:00 AM
Spoiler

local function getVar()
  if devMode then
	var = tostring(words[1])
	Text.setText("The variable ~"..var.."~ is currently: "..tostring(_G[var]))

	sleep(resultTime)
	Text.setText("")
	return
  else
	Text.setText("This command only available in Developer Mode")
	sleep(resultTime)
	Text.setText("")
	return
  end
end

So I'm looking at this code and I realize that the line
 var=tostring(words[1])
appears unnecessary considering the words table is comprised of strings to begin with; ie words[1] is already a string.

Now I've fired up my lua interpreter in computer craft and began testing the code on the line that returns nil. Explicitly I noticed these things happening
  1. No matter the name of your variable, _G[var] returns empty or blank
  2. applying tostring to that makes it return nil
  3. Apparently there is NO _G table
So I strongly suggest using that vars = {} table method that Bubba suggested.
The _G table exists no matter what. _G[ 'os' ] is for example the os API
kreezxil #16
Posted 15 September 2013 - 01:30 PM
I am tostring'ing it just incase I ever have a number used. I like to cover my bases to play it safe. Its a bad habit of mine. Yeah. I was thinking I may have to convert my variables to a table. I was just hoping I could avoid it, as It means rummaging through the code and I wanted to be a bit lazy. xD Oh well. guess it cant be helped. I'll try this out and see if that fixes it!

Can you pastebin your code so we can something to properly test against. Ie, something includes all of your data.
kreezxil #17
Posted 15 September 2013 - 02:47 PM
Spoiler

local function getVar()
  if devMode then
	var = tostring(words[1])
	Text.setText("The variable ~"..var.."~ is currently: "..tostring(_G[var]))

	sleep(resultTime)
	Text.setText("")
	return
  else
	Text.setText("This command only available in Developer Mode")
	sleep(resultTime)
	Text.setText("")
	return
  end
end

So I'm looking at this code and I realize that the line
 var=tostring(words[1])
appears unnecessary considering the words table is comprised of strings to begin with; ie words[1] is already a string.

Now I've fired up my lua interpreter in computer craft and began testing the code on the line that returns nil. Explicitly I noticed these things happening
  1. No matter the name of your variable, _G[var] returns empty or blank
  2. applying tostring to that makes it return nil
  3. Apparently there is NO _G table
So I strongly suggest using that vars = {} table method that Bubba suggested.
The _G table exists no matter what. _G[ 'os' ] is for example the os API
Ok, so I redact #3, however, I went and test _G and while does contain values in it, It does not contain variables that the cc programmer has set. I had to explicitly do
_G["devMode"]=true
to get it to behave properly in his getVar() routine.
Engineer #18
Posted 15 September 2013 - 03:01 PM
Because global variables come into the environment of the program, not into _G
kreezxil #19
Posted 15 September 2013 - 03:50 PM
-snip-

You could also use global variablesand access them using the_G table:

devMode=true

function getVar(var)
  return "the value of "..var.." is "..tostring(_G[var])
end
Because global variables come into the environment of the program, not into _G

How do you suggest solving CaptiainAether's problem using Bubba's _G example?
CaptainAether #20
Posted 15 September 2013 - 03:55 PM
the current version of this program can always be found at http://pastebin.com/7X4pG51K

I'm about to convert all my variables into a table so I can search them as suggested.
kreezxil #21
Posted 15 September 2013 - 04:03 PM
Sweet I'm going to check this out further. :)/>
CaptainAether #22
Posted 16 September 2013 - 01:53 AM
Got it working! Here are the snipits related to this feature in case this could ever help someone else


-- This is the master variable list
local vars = {
  ["currentVersion"] = 5,
  ["resultTime"] = 5,
  ["defaultTimeZone"] = "notSet",
  ["defaultTimeZoneCode"] = "notSet",
  ["bridgeName"] = "notSet",
  ["updateCheck"] = false,
  ["devMode"] = false,
  ["timeZone"] = "notSet",
  ["timeZoneCode"] = "notSet",
  ["pxFromTop"] = 25
}

local function getVar()
  if vars["devMode"] then
	var = tostring(words[1])
	Text.setText("The variable ~"..var.."~ is currently: "..vars[var])
	sleep(vars["resultTime"])
	Text.setText("")
	return
  else
	Text.setText("This command only available in Developer Mode")
	sleep(vars["resultTime"])
	Text.setText("")
	return
  end
end

local function command()
  while true do
	evt, command = os.pullEvent("chat_command")
	words = {}
	i = 0
	for word in string.gmatch(command, "%S+") do
	  words[i] = word
	  i = i + 1
	end
  
	if string.lower(words[0]) == "?" then
	  variables["searchString"] = string.lower(tostring(words[1]))
	  printSearch()
	elseif words[0] == "reset" then
	  resetScreen()
	elseif words[0] == "newZone" then
	  vars[timeZone] = tostring(words[1])
	  changeZone()
	elseif string.lower(words[0]) == "!" then
	  chat()
	elseif words[0] == "update" then
	  update()
	elseif words[0] == "newSettings" then
	  settings()
	elseif words[0] == "devToggle" then
	  devToggle()
	elseif words[0] == "getVar" then
	  getVar()
	else
	  badCommand()
	end
  end
end
kreezxil #23
Posted 16 September 2013 - 06:23 AM
Sweet, awesome job!