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

Player Detector Door Trigger Failing[Solved]

Started by kauqilla, 08 June 2013 - 04:57 PM
kauqilla #1
Posted 08 June 2013 - 06:57 PM
m is my monitor system
detector is the player detector
What is happening is it opens the door once and displays on the monitor but fails to work again. I think I made a loop somewhere that is causing the program to fail. Can anyone help with this?
I have posted the code below.
*edit* I have yet to impliment the other half of the code for Tarsk69 which is why countt is as of yet unused


detector = peripheral.wrap("front")
m = peripheral.wrap("left")
mx, my = m.getSize()
while true do
event, player = os.pullEvent(player)
local p = player
local countk = 0
local countt = 0
if player == "kauqilla" then
print("Kauqilla has entered")
countk = countk + 1
redstone.setOutput ("right", true )
sleep(1)
rs.setOutput("right",false)
m.setCursorPos( mx/2 -7 , 4)
m.write("Welcome "..p )
m.setCursorPos( mx/2 -7, 5)
m.write("You have been here ")
m.setCursorPos(mx/2 -7 ,6)
m.write(countk)
m.setCursorPos(mx/2 -7, 7)
m.write("time(s)")
sleep(10)
m.clear()
elseif player == "Tarsk69" then
rs.setOutput ("right", true)
sleep(1)
rs.setOutput ("right", false)
elseif player ~= "kauqilla" or player ~= "Tarsk69" then
print("Invalid Player")
rs.setOutput("left",true)
else
print("Error has occured")
end
end
Bomb Bloke #2
Posted 08 June 2013 - 10:57 PM
event, player = os.pullEvent(player)

You want to use: os.pullEvent("player")

Without the quotes, it's waiting for an event type that matches the string stored in the 'player' variable. When the program first runs there's nothing in there so it waits for any event. After the first loop there's a player name in there, and since you won't ever occur as an event, it never works again. ;)/>

Also, unless you want to handle certain users in different ways, tables and loops are the way to go.

Spoiler
local detector = peripheral.wrap("front")
local m = peripheral.wrap("left")
local mx, my = m.getSize()

-- All you need to do to have the program handle more players is add them to this list:
local players = {"kauqilla","Tarsk69"}  

-- Expands the table out a bit so's we can put our counters in it too:
for i=1,#players do
  players[i] = {name = players[i], count = 0}
end 
-- "#players" returns the number of items in the "players" table (sorta).

while true do
  event, player = os.pullEvent("player")

  for i=1,#players do
    if player == players[i].name then
      print(players[i].name.." has entered")
      players[i].count = players[i].count + 1
      redstone.setOutput ("right", true )
      sleep(1)
      rs.setOutput("right",false)
      m.setCursorPos( mx/2 -7 , 4)
      m.write("Welcome "..players[i].name)
      m.setCursorPos( mx/2 -7, 5)
      m.write("You have been here ")
      m.setCursorPos(mx/2 -7 ,6)
      m.write(players[i].count)
      m.setCursorPos(mx/2 -7, 7)
      m.write("time(s)")
      sleep(10)
      m.clear()
      break  -- Stop the for loop, 'cause if player[i] was a match, we won't find another match.
    else
      print("Invalid Player")
      rs.setOutput("left",true)
    end
  end
end
kauqilla #3
Posted 08 June 2013 - 11:07 PM
last question.. will it store the count even if the pc reboots or will i have to us the FS api system for that?

*edit* yeah just rebooted the pc and it lost the count. guess I'll have to dig into the FS api side of things unless you could shed some light on it. your update to my code worked perfectly
Bomb Bloke #4
Posted 08 June 2013 - 11:08 PM
You'll need to use the FS API for that. textutils.serialize() is your friend there, as it lets you save (or load, with textutils.unserialize()) the whole table in one go.
kauqilla #5
Posted 08 June 2013 - 11:19 PM
ok so if i had it do

fs.open("attendance" , r)
attendance = fs.readAll(textutils.unserialize("attendance"))
---then in the code i would add the count and then
fs.open("attendance" , w)
fs.write(textutils.serialize())
or am I missing parts?
Bomb Bloke #6
Posted 08 June 2013 - 11:37 PM
Have a read through this thread, it should explain all you need to know about that. :)/>
kauqilla #7
Posted 08 June 2013 - 11:57 PM
Have a read through this thread, it should explain all you need to know about that. :)/>
my brain is bashing against my skull right now as i try to wrap my head around inserting the players into the table. is there a way i can do it so the count is unique per person?
Bomb Bloke #8
Posted 09 June 2013 - 12:16 AM
That's what the code I first gave you does, yes. I complicated that process of adding counters in order to simplify the process of adding names, so it may be a bit tricky to understand if you haven't used tables before. Sorry.

The idea is this line:

local players = {"kauqilla","Tarsk69"}

… creates a table with two elements: players[1] (which is a string with the value of "kauqilla"), and players[2] (which is "Tarsk69"). Let's say you added an extra player in there (so eg "kauqilla","Tarsk69","BombBloke") - you'd then have a players[3] (which is "BombBloke").

Then I turn that simple table into a table made of tables.

for i=1,#players do
  players[i] = {name = players[i], count = 0}
end

The "for" block creates a loop. The first time it runs, it sets the variable "i" to 1. When the code block is complete, "i" goes up by one, and the loop runs again. It keeps going until "i" would exceed the value of "#players" (which represents how many items are in the "players" table), so effectively it's running the code block once for each name in the table.

The "players = {name = players, count = 0}" line is a little more complex. It creates a new table, with two elements: One is called "name", and is set to whatever name was in "players". The other is called "count", and it sets that to 0. These tables overwrite the names that were in the original table, so the "simple" list you put your names into gets entirely re-written before the player detector code starts using it.

So, at the end of the code block, this table:

local players = {"kauqilla","Tarsk69","BombBloke","herobrine"}

Has become this table:

local players = {
{name="kauqilla",count=0},
{name="Tarsk69",count=0},
{name="BombBloke",count=0},
{name="herobrine",count=0}}

Now players[1] is a table, not a string. You can refer to the string in that table by checking "players[1].name", which returns "kauqilla". If you call for "players[2].count", you get Tarsk's counter, which starts at 0… and so on.

The idea with the serialise command is that you can turn that whole table filled with tables into a single string and write it to your file as a single line.
kauqilla #9
Posted 09 June 2013 - 12:18 AM
*facedesk* table within a table my brain wasn't wrapping around it as it was presented. I used to program in QuickBasic back in high school and some minor python…. as you can see I've been out of the coding loop for too long. Thanks for the help I should be able to smash something together and work
kauqilla #10
Posted 09 June 2013 - 12:32 AM
Ok so here is what I have now. The Program works but the counter is broken lol. do i need to pass the players.count into the updateTable() ?


local detector = peripheral.wrap("front")
local m = peripheral.wrap("left")
local mx, my = m.getSize()
local myFile = "attendance"
local players = {}
local function loadTable()
  if fs.exists(myFile) then
    local handle = fs.open(myFile,r)
    players = textutils.unserialize(handle.readLine())
    handle.close()
  else
    -- The file doesn't exist, so reset all the variables in
    -- the table to whatever default values you want to use.
    players = {{name="kauqilla",count=0},
			  {name="Tarsk69",count=0}}
  end
end
local function updateFile()
  local handle = fs.open(myFile,w)
  handle.write(textutils.serialize(players))
  handle.close()
end
while true do
  event, player = os.pullEvent("player")
  loadTable()
  for i=1,#players do
    if player == players[i].name then
	  print(players[i].name.." has entered")
	  players[i].count = players[i].count + 1
	  redstone.setOutput ("right", true )
	  sleep(1)
	  rs.setOutput("right",false)
	  m.setCursorPos( mx/2 -7 , 4)
	  m.write("Welcome "..players[i].name)
	  m.setCursorPos( mx/2 -7, 5)
	  m.write("You have been here ")
	  m.setCursorPos(mx/2 -7 ,6)
	  m.write(players[i].count)
	  m.setCursorPos(mx/2 -7, 7)
	  m.write("time(s)")
	  sleep(10)
	  m.clear()
	  break  -- Stop the for loop, 'cause if player[i] was a match, we won't find another match.
    else
	  print("Invalid Player")
	  rs.setOutput("left",true)
    end
updateFile()
end
end
kauqilla #11
Posted 09 June 2013 - 12:45 AM
Upon further investigation it's not creating the file for it to save the table. Is there something else I need to call for it to work? I tried making the file via ftp server and when i did that it gave me an error saying expecting (string,string)
Bomb Bloke #12
Posted 09 June 2013 - 01:25 AM
My bad - ironically, I forgot to put the quotes around the "w" and "r" symbols in the fs.open statements. I've edited them into my old post now.

Another mistake I made was in how I put the "invalid player" output inside the "for" loop. That implementation will spam the console regardless as to who comes near.

Anyway, you should only be calling loadTable() once - the program doesn't need to do so again until it restarts (say 'cause the server rebooted). updateFile() only needs to be called if a matching player moved near the detector.

Something like:

loadTable()

while true do
  event, player = os.pullEvent("player")

  for i=1,#players do
    if player == players[i].name then
          -- Open door and stuff...

          updateFile()  -- This is the only time we ever need to save anything.
          break  -- Stop the for loop, 'cause if player[i] was a match, we won't find another match.
    elseif i == #players then  -- We've checked the last player and still found no match...
          print("Invalid Player")
          rs.setOutput("left",true)
    end
  end
end

Otherwise it all seems ok.
kauqilla #13
Posted 09 June 2013 - 01:37 AM
that was the trick! fantastic. It works! the one very very very minor glitch with it i've found is that when i rebooted after testing it a few time the number didn't incriment on the first detector hit after reboot. So it's only 1 value behind which is very minor in my books considering how often the pc / server restart is minimal
kauqilla #14
Posted 09 June 2013 - 01:48 AM

local detector = peripheral.wrap("front")
local m = peripheral.wrap("left")
local mx, my = m.getSize()
local myFile = "attendance"
local players = {}
local function loadTable()
  if fs.exists(myFile) then
    local handle = fs.open(myFile,"r")
    players = textutils.unserialize(handle.readLine())
    handle.close()
  else
    -- The file doesn't exist, so reset all the variables in
    -- the table to whatever default values you want to use.
    players = {{name="kauqilla",count=0},
			  {name="Tarsk69",count=0}}
  end
end
local function updateFile()
  local handle = fs.open(myFile,"w")
  handle.write(textutils.serialize(players))
  handle.close()
end
loadTable()
while true do
  event, player = os.pullEvent("player")
  for i=1,#players do
    if player == players[i].name then
	    print(players[i].name.." has entered")
	  players[i].count = players[i].count + 1
	  redstone.setOutput ("right", true )
	  sleep(1)
	  rs.setOutput("right",false)
	  m.setCursorPos( mx/2 -7 , 4)
	  m.write("Welcome "..players[i].name)
	  m.setCursorPos( mx/2 -7, 5)
	  m.write("You have been here ")
	  m.setCursorPos(mx/2 -7 ,6)
	  m.write(players[i].count)
	  m.setCursorPos(mx/2 -7, 7)
	  m.write("time(s)")
	  sleep(10)
	  m.clear()
	  updateFile()  -- This is the only time we ever need to save anything.
	  break  -- Stop the for loop, 'cause if player[i] was a match, we won't find another match.
    elseif i == #players then  -- We've checked the last player and still found no match...
		  print("Invalid Player")
		  rs.setOutput("left",true)
    end
  end
end

This is the final product after much work sweat and assistance from Bomb Bloke. You have eased my mental anguish and have my thanks
Bomb Bloke #15
Posted 09 June 2013 - 01:48 AM
Hmph. Beats me as to why it'd ever miss a count. :huh:/> (Edit: Ah, it's probably because you rebooted the computer after having it open the door, but before it cleared the terminal! Repositioning the save statement would make it more reliable…) Well done in any case. :)/>

Note that because of the save file, adding names becomes a bit trickier: whenever the program restarts, it's pulling the list of names from that save file (if it exists) along with their counters, so if you only add new names to the program then you'd have to delete the attendance file or they won't be used.

Another option is to add the names to the attendance file and program manually, though this would be quite a nuisance if you found yourself updating it often.

The "best" (but somewhat more complex) solution is to have a separate "names list" file which only has names in it - have the program check that on startup, and update the attendance file with new counters as need be.
kauqilla #16
Posted 09 June 2013 - 02:12 AM
This is a door access system for my secure base. Right now the only people I trust inside is myself and Tarsk69 so that won't be an issue. Plus if I decide to give "tours" i would be there to let them in so to speak.