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

User login program problem

Started by Barlender, 04 August 2015 - 11:00 PM
Barlender #1
Posted 05 August 2015 - 01:00 AM
Ok, so I am creating an OS in which there can be multiple users created at a time. I want it to be so that the first time you select a user it asks for your name and for you to create a profile picture (now that's not the part I need help with). The issue I'm having is getting the user to go through this process only the first time the user is selected, and not have to do it every time, but rather go to the login. So how do I get the computer to only do the setup the first time, but not again, even if the computer has been shutdown or rebooted? I've attempted using this:

function user1()
  i = 1

  if i == 1 then
	--this is the part where it creates the user's information
	i = i + 1
  end

  if i == 2 then
	--this takes the user to their login
  end
end

Now obviously this has problems in that every time the function is run, "i" will be reset to 1 instead of 1 or 2. If you have experience with such issues and have a solution, it would be much appreciated.
Edited on 05 August 2015 - 03:28 AM
safetyscissors #2
Posted 05 August 2015 - 03:15 AM
Hello. fs is a fairly persistent option. doesnt survive an unnetworked computer being broken though.
below is just pseudo code. didnt test it.

function login(username)
 
  -- if theres a data file named username in the users dir, do login.
  if fs.exists("users/"..username) then
    data = fs.open("users/"..username, "r")
    -- do login stuff
  -- if data file doesnt exist, user hasnt logged in before.
  else
    -- create new user information and add the data file.
    file = fs.open("users/"..uesrname,"w")
    file.write(userInformation)
  end
end
Barlender #3
Posted 05 August 2015 - 05:28 AM
I've used fs.exists in the past, and don't know why I haven't thought to use it here. Thanks for the suggestion, I haven't tested it, but it should work.
Barlender #4
Posted 05 August 2015 - 06:35 AM
So I am having an issue with my OS. I have gotten to the point in my program where the user can create his/her own, well, user (profile, account, whatever). Anyways, the part in my program that I am having issues with is this:

function user1()
  if not fs.exists(".users/user1") then -- Do not worry, the directory "users" was created in a previous part of the program
   local username = user1
   userCreator()
  else
  -- this would be where the usual login screen would occur, not relevent to this problem
end

function user2()
  if not fs.exists(".users/user2") then
   local username = user2
   userCreator()
  else
end

function userCreator()
   term.setTextColor(colors.green)
   term.setCursorPos(1,1)
   textutils.slowPrint("Hello, and welcome to the user creator!")
   sleep(1)
   term.setCursorPos(1,2)
   textutils.slowPrint("You are creating a user under the save "..username) -- it is at this line that I get the error message
   -- the code continues from here to create the file, but I have not included it because it is beyond the problem
end
Edited on 05 August 2015 - 04:36 AM
Lyqyd #5
Posted 05 August 2015 - 06:59 AM
Threads merged. Please stick to one topic for all questions about a given piece of code.
safetyscissors #6
Posted 05 August 2015 - 08:03 AM
Hey Barlender,
Your issue deals with the scope for the username variable. In short, function user1 knows whats in the variable username is but not userCreator.
a good option is to have a function pass it to the other as a parameter.

--// we write userCheck to take the username string and then hand it off to userCreator after
function userCheck(username)
  if not fs.exists(".users/"..username) then
	userCreator(username)
  end
end
--// we write userCreator to take the username string
function userCreator(username)
  textutils.slowPrint("blah blah "..username)
end
--// when we call userCheck, we give it the string username.
userCheck("user1")

If you truly need the variable username, the less happy option is to put username in a bigger scope where both functions always have access to it.

--// we define username outside of either function. and set it to a stringish value
local username = ""
function user1()
  --// we dont create a new local var, we stick the user into the existing one defined outside.
  username = "user1"
  userCreator()
end
function userCreator()
  textutils.slowPrint("blah blah" .. username)
end
Barlender #7
Posted 05 August 2015 - 07:10 PM
Hey Barlender,
Your issue deals with the scope for the username variable. In short, function user1 knows whats in the variable username is but not userCreator.
a good option is to have a function pass it to the other as a parameter.

And what do you know, it worked! Thank you for the help.
Barlender #8
Posted 05 August 2015 - 09:35 PM
Ok, I have yet another problem now. So I want to have a screen in which the user must type in a password. This password part will be handled by a conditional if statement (if read() == " " then), yet I also want another conditional statement active at the same time, one where the user can click on a button to go back to the main menu (if x == # and y == # then). When I tried to have both of these conditional statements active unanimously, whichever statement was coded first would be active, but the other wouldn't. This is the first code I used:

event,side,x,y = os.pullEvent("mouse_click")

if x == 1 and y == 1 then
  print("You clicked the button")

elseif read() == " " then
  print("You typed something")
end

I've also tried:

event,side,x,y = os.pullEvent("mouse_click")

if x == 1 and y == 1 then
  print("You clicked the button")
end

if read() == " " then
  print("You typed something")
end

The only difference is the "elseif" was changed to another "if". I want to know if it's even possible to have multiple conditional statements active at the same time.
KingofGamesYami #9
Posted 05 August 2015 - 09:38 PM
You're looking for parallel.



local function click()
  while true do
    local event, side, x, y = os.pullEvent( "mouse_click" )
    --#check coordinates
  end
end

local function input()
  local text = read()
  --#check text
end

parallel.waitForAny( input, click )
Barlender #10
Posted 05 August 2015 - 09:51 PM
I see. This really helps, thanks
Barlender #11
Posted 06 August 2015 - 11:57 PM
New problem now. So whenever I enable the ability to click on the screen with:
event,side,x,y = os.pullEvent("mouse_click")
if x == # and y == # then
end
The problem is that whenever I set a pixel to be clickable, the user can click elsewhere, and by default clicking somewhere else will simply end. So is there an easy way to (without having to set a complicated "else" command that makes it look like nothing happened) make it so that if any other pixel is clicked on, nothing happened?
KingofGamesYami #12
Posted 07 August 2015 - 02:41 AM
You'll notice I wrapped it in a loop in my example.


local function click()
  while true do
    local event, side, x, y = os.pullEvent( "mouse_click" )
    if x == # and y == # then
      break
    end
  end
end

parallel.waitForAny waits until either function is completed, so only pulling a "mouse_click" event once will, in effect, ignore whatever checks you do on it. Which is why I added an infinite loop, that ends when the correct spot is clicked.
Barlender #13
Posted 11 August 2015 - 11:51 PM
Thanks for the "while loop" suggestion, it helped me quite a bit. I'm having another issue now, however. So this is part of the code that I am using in my program:

local function type()

   term.setCursorPos(22,14)
  
   local passwordGuess = read("*")

   if passwordGuess == password then
   --// This runs the login program, not relevant
   else
   --// This makes the user re-enter the password until it is guessed correctly
   end
  end

  local function click()

   while true do

    event,side,x,y = os.pullEvent("mouse_click")
  
    if x >= 24 and x <= 27 and y == 15 then
	 startupScreen() --// So there is a "Back" button on the password screen, and when it is pressed it returns to the startup screen, which is divided into these two functions
	 startup()
  
    elseif x == 4 and y == 16 then
	 shutdown() --// A function which shuts the computer down
  
    elseif x == 6 and y == 16 then
	 reboot() --// A function which reboots the computer
    end
   end
  end

  parallel.waitForAny(click,type)

My problem is that if the user clicks the "back" button, as previously mentioned, it does return the user to the startup screen, however the computer is still waiting for the user to input the "passwordGuess" command, even though the "passwordGuess" variable is defined locally within the larger function of the login screen, which isn't shown here. I tried using the "break" command to stop it from waiting for an input, placing the command in multiple places, but none of them worked successfully. So my question is is it possible for the computer to stop waiting for the "passwordGuess" variable to be entered, without an input actually being entered?
H4X0RZ #14
Posted 12 August 2015 - 12:00 AM
You should break the loop in your click function. If your don't do it, the loop waiting for the user input will never stop (you could break this one too, though). Maybe make a variable (possibly) called state. When you click a button you set state to e.g. "Back" and then break the loop. Afterwards the code after the parallel call will continue to run, and then you add another if clause checking for the content of state and acting accordingly.
Barlender #15
Posted 12 August 2015 - 12:14 AM
And, of course, it worked. I ended up using your latter suggestion to use the "state" variable. I did have to set the cursor blink to false though, because even though it wasn't waiting for the input, it still had the cursor blinking, for some reason. Anyways, thanks.
Barlender #16
Posted 12 August 2015 - 02:14 AM
Quick question, so I'm trying to put text on the bottom-most layer of the terminal, which is x = 19. However, whenever I do so, the entire screen is brought down 1 pixel to make x be equal to 18 instead. Is it possible to actually put text on the very bottom layer? I'm sure I've seen it done before…

If you need an example of what I mean, use this simple code:

term.clear()
term.setCursorPos(1,19)
print("Hi")
term.setCursorPos(1,1) --// I did this to bring the screen back up to the top of the terminal
Edited on 12 August 2015 - 12:16 AM
Bomb Bloke #17
Posted 12 August 2015 - 04:47 AM
print() performs a line break after writing. Try term.write() instead, or - if you still want word-wrap - just write().
Barlender #18
Posted 15 August 2015 - 10:16 PM
Another problem, and this one's a bit more complicated. This is the segment of my program I'm having issues with:

function clock() --// This function displays the time in the bottom right corner of the screen

 while true do

   time = os.time()
   term.setCursorPos(44,19)
   term.setBackgroundColor(colors.blue)
   term.write(textutils.formatTime(os.time(),false))
   sleep(.75)
 end
end


 
function console() --// This function enters the console, and makes it look like it would when you first boot up.

 term.setBackgroundColor(colors.black)
 term.clear()
 term.setTextColor(colors.yellow)
 term.setCursorPos(1,1)
 print("CraftOS 1.7")
 term.setCursorPos(1,2)

end



function menu(userslot) --// "Userslot" simply tells the program what save the user is currently signed into.

local state = 0

local function click()

  while true do

  event,side,x,y = os.pullEvent("mouse_click")

   if x >= 1 and x <= 7 and y == 19 then
    state = 1
    break
  
--// ...
  
   elseif x >= 11 and x <= 20 and y >= 8 and y <= 9 then
    state = 8
    break
  
--// ...

   end
  end
end

parallel.waitForAny(clock,click)


if state == 1 then
  desktopScreen(userslot)
  desktop(userslot)

--// ...

elseif state == 8 then
  console()
  return

--// ...

end
end

My problem is near the end, with entering the console when the state == 8. It does execute the console() function, however the cursor isn't blinking, or even present, and if you attempt typing anything, nothing happens (in the console, that is). I think that the issue is to do with the "parallel.waitForAny(clock,click)" line, because if you re-click on the button that launched the console it takes you back to the menu screen. I tried using the return function (the break function didn't work becuase it couldn't find anything to break), but it didn't seem to do anything at all. Am I missing something obvious here?

Here is a pretty pictures to help you:

https://www.dropbox.com/home?preview=Problem+Picture.png

PS: If you want to know why I used the "state" variable instead of simply executing the function, see [member='H4X0RZ']'s post earlier
Bomb Bloke #19
Posted 16 August 2015 - 01:48 AM
Is "menu()" getting called over and over, or what's the deal? I don't see anything here that attempts to get text input from the user.