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

OpenCCSensors sensor.getTargets() won't return table?

Started by MoscowModder, 06 October 2013 - 11:33 AM
MoscowModder #1
Posted 06 October 2013 - 01:33 PM
I'm familiar with programming in general but new to LUA and ComputerCraft. I decided (perhaps rashly) to try making an elevator for my first project. I'm directly copying everything, including the PasteBin code, from this video. I'm pretty sure I set up everything exactly like it was in the video (except with only 2 floors, not 6), but every time I select a floor, I get the error on line 38 that sensor.getTargets() returns a number when the program expects a table (with pairs).

Here is the code I'm using (not written by me).

I've tried placing both of the two sensor cards (inventory and proximity) in the Turtle's slot 16, but both return an error. I've verified with sensorView that there is sensor data on the left sensor, which shows my player stats for the proximity sensor and the two dispensors in the inventory card's display.

If it makes a difference, I'm using the latest version of FTB Ultimate on Minecraft 1.5.2, plus I downloaded the latest vesion of OpenCCSensors for 1.5.2 to use this code.

Edit: I made a test program to try to output the table from each sensor - tried it with each of the two sensors (again, inventory and proximity) and got numbers from both.

Edit 2: The program interacts with another computer (per floor) running this code (also not by me) to handle cart dispensing.
Edited on 06 October 2013 - 04:37 PM
Lyqyd #2
Posted 06 October 2013 - 06:37 PM
Split into new topic.

The code you're using is from an old version. You'll need to load the sensor API (ocs/apis/sensor) and use sensor.wrap to wrap your sensor peripheral (don't put it in a variable named sensor!). With those two changes, it should start working, if the rest of the code is correct.
MoscowModder #3
Posted 06 October 2013 - 11:28 PM
Thanks! Now it doesn't give me the error… but it doesn't call the cart or tell me one is coming. It shifts around the sensor cards but doesn't make the elevator work.

Here's my update to elevator.main:
Spoiler
os.loadAPI("ocs/apis/sensor")
local theSensor = sensor.wrap("left")
rednet.open("right")
local config = dofile("elevator.config")
local floors = {}
local selectedFloor = 1
local cartDispenserId = nil
local lastError = nil
local expectingCart = false
local expectingArrival = false
local needCart = true
local gotCartResponse = false
local inUse = false
local inventorySlot = 1
local proximitySlot = 2

local function switchToInventorySensor()
    if turtle.getItemCount(inventorySlot) > 0 then
        turtle.select(16)
        turtle.transferTo(proximitySlot)
        turtle.select(inventorySlot)
        turtle.transferTo(16)
    end
end

local function switchToProximitySensor()
    if turtle.getItemCount(proximitySlot) > 0 then
        turtle.select(16)
        turtle.transferTo(inventorySlot)
        turtle.select(proximitySlot)
        turtle.transferTo(16)
    end
end

local function checkIfCart()
    local rtn = false
    local targetName = nil
    switchToInventorySensor()
    for name,target in pairs(theSensor.getTargets()) do
        if target.type == "railcraft.common.blocks.machine.gamma.TileDispenserCart" then
            targetName = name
            break
        end
    end
    if targetName then
        local inventoryData = theSensor.getTargetDetails(targetName)
        for slot, item in pairs(inventoryData) do
            if item.Size > 0 then
                rtn = true
                break
            end
        end
    end
    return rtn
end
local function dispenseCart(floor)
    if checkIfCart() then
        expectingCart = true
        rednet.send(cartDispenserId, textutils.serialize{type="elevator", sender="main", id=config.id, command="dispense"})
    else
        rednet.broadcast(textutils.serialize{type="elevator", sender="main", id=config.id, command="needCart"})
        needCart = true
    end
end

local function handleCancel()
    inUse = false
    needCart = false
    gotCartResponse = false
    expectingCart = false
    expectingArrival = false
    rs.setOutput("front", false)
    lastError = nil
end

local function chooseFloor()
    lastError = nil
    if cartDispenserId then
        if not expectingCart then
            local floor = floors[selectedFloor]
            dispenseCart(floor)
        end
    else
        lastError = "Cannot find the cart dispenser!"
    end
end

local function addFloor(message)
    local found = false
    for index, floor in ipairs(floors) do
        if floor.id == message.id then
            floors[index] = { id=message.id, shortcut = message.shortcut, description = message.description }
            found = true
            break
        end
    end
    if not found then        
        table.insert(floors, { id=message.id, shortcut = message.shortcut, description = message.description })
    end
    table.sort(floors, function(a,B)/>/> return tonumber(a.id) < tonumber(b.id) end)    
end

local function handleMain(senderId, message)
    if message.command == "announce" then
        rednet.send(senderId, textutils.serialize{type="elevator", sender = "main", id=config.id, command="ack", shortcut=config.shortcut, description=config.description})
        addFloor(message)
    elseif message.command == "ack" then
        addFloor(message)
    elseif message.command == "floorSelect" then
        inUse = true
        if message.floorId == config.id then
            rs.setOutput("front", true)
            expectingArrival = true
        end
    elseif message.command == "cancel" then
        handleCancel()
    elseif message.command == "gotCart" then
        if needCart and not gotCartResponse then
            gotCartResponse = true
            expectingCart = true
            rs.setOutput("front", true)
            rednet.send(senderId, textutils.serialize{type="elevator", sender="main", id = config.id, command="sendCart"})
        end            
    elseif message.command == "sendCart" then
        rednet.send(cartDispenserId, textutils.serialize{type="elevator", sender="main", id=config.id, command="sendCart"})
    elseif message.command == "needCart" then
        if checkIfCart() then
            rednet.send(senderId, textutils.serialize{type="elevator", sender="main", id=config.id, command="gotCart"})
        end
    end
end

local function handleDispenser(senderId, message)
    if message.command == "announce" then
        if message.id == config.id then
            rednet.send(senderId, textutils.serialize{type="elevator", sender = "main", id=config.id, command="ack", shortcut=config.shortcut, description=config.description})
            cartDispenserId = senderId
        end
    elseif message.command == "ack" then
        cartDispenserId = senderId
    end
end

local function doScan()
    while true do
        if expectingCart or expectingArrival then
            switchToProximitySensor()
            local targets = theSensor.getTargets()
            for name, target in pairs(targets) do
                if (target.Position.X == config.embarkedCoords.x) and (target.Position.Y == config.embarkedCoords.y) and (target.Position.Z == config.embarkedCoords.z) then
                    rs.setOutput("front", false)
                    if expectingCart then
                        inUse = true
                        rednet.broadcast(textutils.serialize{type="elevator", sender="main", id=config.id, command="floorSelect", floorId=floors[selectedFloor].id})
                        sleep(.5)
                        rednet.send(cartDispenserId, textutils.serialize{type="elevator", sender="main", id=config.id, command="launch"})
                    elseif expectingArrival then
                        inUse = false
                        rednet.broadcast(textutils.serialize{type="elevator", sender="main", id=config.id, command="cancel"})
                        rednet.send(cartDispenserId, textutils.serialize{type="elevator", sender="main", id=config.id, command="dispense"})                        
                        handleCancel()
                    end
                    expectingArrival = false                    
                    expectingCart = false
                end
            end
        end        
        sleep(.1)
    end
end

local function doNetwork()
    print("Starting network...")
    rednet.broadcast(textutils.serialize{type="elevator", sender = "main", id=config.id, command="announce", shortcut = config.shortcut, description=config.description })
    while true do
        local event, senderId, data, distance = os.pullEvent("rednet_message")
        local message = textutils.unserialize(data)
        if message and message.type == "elevator" then
            if message.sender == "main" then
                handleMain(senderId, message)            
            elseif message.sender == "dispenser" then
                handleDispenser(senderId, message)
            end
        end
    end
end

local function displayFloorSelection()
    print("Floors available: ")
    for index, floor in ipairs(floors) do
        if index == selectedFloor then
            print(string.format("[ %s: %s ]", floor.shortcut, floor.description))
        else
            print(string.format("  %s: %s  ", floor.shortcut, floor.description))
        end
    end
end

local function displayCart()
    if not needCart then
        print("Your cart is ready!")
    else
        print("Use cart when arrives.")
    end
end

local function displayInUse()
    print("Cart system in use!")
end

local function displayNeedCart()
    print("Waiting for cart...")
end

local function displayMenu()
    term.clear()
    term.setCursorPos(1,1)
    if expectingCart then
        displayCart()
    elseif inUse then
        displayInUse()
    else
        displayFloorSelection()
    end
    if lastError then print(lastError) end
    print("Press Q to exit C to Cancel Request")
end

local function doMenu()
    print("Displaying menu...")
    while true do
        sleep(1)
        displayMenu()
    end
end

local function doKeyboard()
    print("Starting keyboard handler...")
    while true do
        local event, key = os.pullEvent()
        if event == "char" then
            if string.lower(key) == "q" then
                break
            elseif string.lower(key) == "c" then
                rednet.broadcast(textutils.serialize{type="elevator", sender="main", id=config.id, command="cancel"})
                handleCancel()
            else
                local keyToCompare = string.lower(key)
                for index, floor in ipairs(floors) do
                    if keyToCompare == floor.shortcut then
                        selectedFloor = index
                        displayMenu()
                        chooseFloor()
                        break
                    end
                end
            end
        elseif event == "key" then
            if key == 200 then
                if selectedFloor > 1 then -- up arrow
                    selectedFloor = selectedFloor - 1
                    displayMenu()
                end
            elseif key == 208 then
                if selectedFloor < #floors then -- down arrow
                    selectedFloor = selectedFloor + 1
                    displayMenu()
                end
            elseif key == 28 then -- enter
                chooseFloor()
            end
        end
    end
end


local function startup()
    term.clear()
    term.setCursorPos(1,1)
    return parallel.waitForAny(doNetwork, doKeyboard, doMenu, doScan)
end


local rtn, error = pcall(startup)
if not rtn then
    print("Elevator failed: " .. error)
end
print("Exiting.")

MoscowModder #4
Posted 08 October 2013 - 09:38 PM
Update: I edited checkIfCart() to always return true, and the program now spawns Minecarts as it should. The problem is, neither the boarding track nor the elevator rails get powered to launch the cart. Can anyone figure this out? Or else point me to a more recent, better-working elevator program?
Bubba #5
Posted 09 October 2013 - 10:22 AM
There are only two instances of setting the redstone output to true in this program, and they are both in the handleMain function. The conditions to turn the redstone on are:

    elseif message.command == "floorSelect" then
        if message.floorId == config.id then
            rs.setOutput("front", true)


elseif message.command == "gotCart" then
  if needCart and not gotCartResponse then
      rs.setOutput("front", true)

I've deleted any extraneous code in there. If neither of these conditions evaluate to true, you're not going to be powering the rail. See if you can't check these conditions and fix the problem. I don't have time to sift through all of the code right now, but I'll check back later and see what I can do.