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

vm error: java.lang.NullPointerException occasionally in server program

Started by Dog, 18 May 2014 - 09:23 PM
Dog #1
Posted 18 May 2014 - 11:23 PM
I'm working on a system that provides centralized redstone door/wall/bridge/light control for a base or home. Every so often the server 'dies' with the error "vm error: java.langNullPointerException". Minecraft doesn't crash (so no crash log) and the Forge logs don't show anything except occasional world leaks (but no entries at the times this happens).

Does anyone have an idea if this is happening due to my program or is this beyond my control? If it's beyond my control is this a bug that should be brought to the bug thread?

Server
SpoilerPastebin

--[[    WiRe Server    ]]--
--[[      by Dog       ]]--
--[[ aka HydrantHunter ]]--
--[[  Wi = Wireless    ]]--
--[[  Re = Redstone    ]]--
--[[ pastebin hqpRw4Jy ]]--
--[[      GPL v3       ]]--
local WiReSver = "1.0.00"
--[[
Tested with/requires:
  - Mincraft 1.6.4
  - ComputerCraft ver. 1.6+ for MC 1.6.4
    - A Computer (standard or advanced) with a wireless modem and at least one (1) advanced monitor
]]--
local tArgs = { ... }
-- CONFIGURATION
-- Default Settings
local termX,termY = term.getSize()
local monX,monY
local me = os.getComputerID()
local config = "/data/WiReServerCfg"
local ccSettings = {
                     name = "WiReServer",
                     note = "short note",
                     color = "lgray",
                   }
local newCmdData = { }
local allClients = { }
local loc = { }
local pageNum, numPages = 1, 1
local quit = "NO"
local help = false
local ccSuccess = false
local kernelState = false
local mon, bio, wifiSide
local lockState = "Unlocked"
local client, thisCommand, pollTimer, sortDeviceList
 -- Terminal Colors
local white = colors.white
local black = colors.black
local lgray = colors.lightGray
local gray = colors.gray
local brown = colors.brown
local yellow = colors.yellow
local orange = colors.orange
local red = colors.red
local magenta = colors.magenta
local purple = colors.purple
local blue = colors.blue
local lblue = colors.lightBlue
local cyan = colors.cyan
local lime = colors.lime
local green = colors.green
if not term.isColor() then
  lgray = colors.white
  gray = colors.black
  brown = colors.white
  yellow = colors.white
  orange = colors.white
  red = colors.white
  magenta = colors.white
  purple = colors.white
  green = colors.white
  blue = colors.black
  lblue = colors.white
  cyan = colors.white
  lime = colors.white
  green = colors.white
end
-- Monitor colors
local mwhite = colors.white
local mblack = colors.black
local mlgray = colors.lightGray
local mgray = colors.gray
local mbrown = colors.brown
local myellow = colors.yellow
local morange = colors.orange
local mred = colors.red
local mmagenta = colors.magenta
local mpurple = colors.purple
local mblue = colors.blue
local mlblue = colors.lightBlue
local mcyan = colors.cyan
local mlime = colors.lime
local mgreen = colors.green
-- END CONFIGURATION

local function saveData()
  if not fs.exists("/data") then fs.makeDir("/data") end
  local srvConfig = fs.open(config,"w") or error("saveData(): Cannot open " .. config .. " for writing", 2)
  srvConfig.write(textutils.serialize(ccSettings))
  srvConfig.close()
end

local function netSend(qry)
  local tempSettings = { }
  if qry then
    tempSettings = { program = "WiRe", cc = me, color = ccSettings.color, cmd = "WiReQRY", }
  else
    tempSettings = { program = "WiRe", cc = me, color = ccSettings.color, cmd = thisCommand, }
  end
  if client then
    if not rednet.isOpen(wifiSide) then
      rednet.open(wifiSide)
    end
    rednet.send(client,tempSettings)
    return true
  end
  return false
end

local function netReceive()
  local netEvent = { rednet.receive() }
  local sender = netEvent[1]
  newCmdData = netEvent[2]
  if type(newCmdData) == "table" then
    if newCmdData.program == "WiRe" and newCmdData.cc == sender and newCmdData.color == ccSettings.color then
      client = sender
      sortDeviceList()
      thisCommand = newCmdData.deviceState
      ccSuccess = true
      return
    end
  end
  client = nil
  thisCommand = "net noise"
  ccSuccess = false
  return
end

sortDeviceList = function()
  for i = 1,#allClients,1 do
    if client == allClients[i].cc then        -- we're already on the list
      allClients[i].name = newCmdData.name
      allClients[i].deviceType = newCmdData.deviceType
      allClients[i].deviceState = newCmdData.deviceState
      allClients[i].quietCount = newCmdData.quietCount
      allClients[i].loc.x = newCmdData.loc.x
      allClients[i].loc.y = newCmdData.loc.y
      allClients[i].loc.z = newCmdData.loc.z
      return
    end
  end
  -- Sort by name
  if #allClients == 0 then                    -- the list is empty
    table.insert(allClients,newCmdData)       -- add it
    numPages = math.ceil(#allClients/7)
    if numPages < pageNum then pageNum = numPages end
  else 
    for i = 1,#allClients,1 do
      if newCmdData.name < allClients[i].name then -- alphabetize
        table.insert(allClients,i,newCmdData) -- insert
        numPages = math.ceil(#allClients/7)
        if numPages < pageNum then pageNum = numPages end
        break
      end
      if i >= #allClients then                -- we've reached the end of the list
        table.insert(allClients,newCmdData)   -- tack it on
        numPages = math.ceil(#allClients/7)
        if numPages < pageNum then pageNum = numPages end
        break
      end
    end
  end
end

local function getColor(assignment)
  local colorBurst = { Purple = purple, Blue = blue, ["Light Blue"] = lblue, Green = green, Red = red, Orange = orange, Brown = brown, ["Light Gray"] = lgray, }
  for name,color in pairs(colorBurst) do
    if assignment == tostring(name) then
      return color
    end
  end
end

local function helpScreen()
  local hText = "WiRe Server Help"
  term.setBackgroundColor(black)
  term.setTextColor(white)
  term.clear()
  term.setBackgroundColor(blue)
  term.setCursorPos(1,1)
  term.write(string.rep(" ",math.floor(termX/2)-(#hText/2)) .. hText .. string.rep(" ",math.ceil(termX/2)+(#hText/2)))
  term.setBackgroundColor(black)
  term.setCursorPos(termX/2-5,3)
  term.write("Client list")
  term.setCursorPos(termX/2-15,5)
  term.write(", < [ { PGUP    Go back one page")
  term.setCursorPos(termX/2-15,7)
  term.write(". > ] } PDDN    Go forward one page")
end

local function termScreen()
  local hText = "WiRe Server " .. WiReSver
  term.setBackgroundColor(black)
  term.setCursorPos(1,1)
  term.setTextColor(white)
  term.setBackgroundColor(blue)
  term.write(string.rep(" ",math.floor(termX/2)-(#hText/2)) .. hText .. string.rep(" ",math.ceil(termX/2)+(#hText/2)))
  term.setCursorPos(1,3)
  term.setTextColor(lgray)
  term.setBackgroundColor(black)
  term.write("Name: ")
  term.setTextColor(white)
  term.write(ccSettings.name)
  term.setCursorPos(1,4)
  term.setTextColor(lgray)
  term.write("Note: ")
  term.setTextColor(white)
  term.write(ccSettings.note)
  term.setCursorPos(1,6)
  term.setTextColor(lgray)
  term.write("Group: ")
  term.setTextColor(getColor(ccSettings.color))
  term.write(ccSettings.color)
  term.setCursorPos(1,8)
  term.setTextColor(lgray)
  term.write("cc# ")
  term.setTextColor(white)
  term.write(tostring(me))
  term.setCursorPos(1,10)
  term.setTextColor(lgray)
  term.write("WiFi: ")
  term.setTextColor(white)
  term.write(wifiSide)
  term.setCursorPos(1,12)
  term.setTextColor(lgray)
  term.write("Last Client: ")
  term.setTextColor(white)
  local lastClient = client or "System"
  term.write("          ")
  term.setCursorPos(14,12)
  term.write(tostring(lastClient))
  term.setCursorPos(1,13)
  term.setTextColor(lgray)
  term.write("Last State:  ")
  if thisCommand == "CLOSED" or thisCommand == "ON" then
    term.setTextColor(green)
  elseif thisCommand == "OPEN" or thisCommand == "OFF" then
    term.setTextColor(orange)
  elseif thisCommand == "LOCKED" then
    term.setTextColor(red)
  else
    term.setTextColor(yellow)
  end
  term.write("          ")
  term.setCursorPos(14,13)
  term.write(thisCommand)
  term.setCursorPos(1,14)
  term.setTextColor(lgray)
  term.write("Success:     ")
  if ccSuccess then
    term.setTextColor(green)
  else
    term.setTextColor(red)
  end
  term.write(tostring(ccSuccess) .. " ")
  term.setCursorPos(1,16)
  term.setTextColor(lgray)
  term.write("Location: ")
  term.setTextColor(white)
  term.write("x: " .. loc.x)
  term.setCursorPos(11,17)
  term.write("y: " .. loc.y)
  term.setCursorPos(11,18)
  term.write("z: " .. loc.z)
  term.setCursorPos(26,3)
  term.setTextColor(lgray)
  term.write("Clients (page " .. tostring(pageNum) .. " of " .. tostring(numPages) .. ")")
  local yPos = 0
  for i = (pageNum * 7) - 6,#allClients,1 do
    yPos = yPos + 1
    term.setCursorPos(26,(yPos*2)+3)
    term.setTextColor(white)
    term.write(allClients[i].name .. " (" .. tostring(allClients[i].cc) .. ")" .. string.rep(" ",termX))
    if allClients[i].deviceState == "CLOSED" or allClients[i].deviceState == "ON" then
      term.setTextColor(green)
    elseif allClients[i].deviceState == "OPEN" or allClients[i].deviceState == "OFF" then
      term.setTextColor(orange)
    elseif allClients[i].deviceState == "LOCKED" then
      term.setTextColor(red)
    end
    term.setCursorPos(termX-6,(yPos*2)+3)
    term.write("      ")
    term.setCursorPos(termX-#allClients[i].deviceState,(yPos*2)+3)
    term.write(allClients[i].deviceState)
    term.setCursorPos(27,(yPos*2)+4)
    term.setTextColor(lgray)
    if allClients[i].loc.x == "No GPS Fix" then
      term.write(allClients[i].loc.x)
    else
      term.write("x: " .. allClients[i].loc.x .. " y: " .. allClients[i].loc.y .. " z: " .. allClients[i].loc.z)
    end
    if i >= #allClients or i >= pageNum * 7 then break end
  end
end

local function powerSwitch(x,y,state)
  mon.setCursorPos(x,y)
  if state == "OPEN" or state == "OFF" then
    mon.setBackgroundColor(gray)      --
    mon.write("      ")               --
    mon.setCursorPos(x,y+1)           -- Switch (ON/CLOSED)
    mon.setBackgroundColor(orange)    --
    mon.write("      ")               --
  elseif state == "CLOSED" or state == "ON" then
    mon.setBackgroundColor(green)     --
    mon.write("      ")               --
    mon.setCursorPos(x,y+1)           -- Switch (OFF/OPEN)
    mon.setBackgroundColor(gray)      --
    mon.write("      ")               --
  elseif state == "LOCKED" then
    mon.setBackgroundColor(red)       --
    mon.write("      ")               -- Switch (LOCKED)
    mon.setCursorPos(x,y+1)           --
    mon.write("      ")               --
  end
end

local function monControls()
  local labelText = ccSettings.name .. " (" .. ccSettings.color .. ")"
  local monLabel = string.rep(" ",math.floor((monX/2)-(#labelText/2))) .. labelText .. string.rep(" ",math.ceil((monX/2)-(#labelText/2)))
  mon.setBackgroundColor(gray)
  mon.setTextColor(cyan)
  mon.setCursorPos(1,1)
  mon.write(monLabel)
  mon.setCursorPos(1,monY)
  mon.setBackgroundColor(mgray)
  mon.write(string.rep(" ",monX))
  mon.setTextColor(mred)
  mon.setCursorPos((monX/4)-2,monY)
  mon.write("Lock")
  mon.setTextColor(mgreen)
  mon.setCursorPos((monX-(monX/4))-3,monY)
  mon.write("Unlock")
  for i = 1,#allClients,1 do
    mon.setCursorPos((i*8)-6,3)
    mon.setBackgroundColor(mblack)
    mon.setTextColor(mlblue)
    mon.write(allClients[i].name:sub(1,6) .. string.rep(" ",6-#allClients[i].name:sub(1,6)))
    mon.setCursorPos((i*8)-6,4)
    mon.write(allClients[i].name:sub(7,12) .. string.rep(" ",6-#allClients[i].name:sub(7,12)))
    powerSwitch((i*8)-6,5,allClients[i].deviceState)
    mon.setCursorPos((i*8)-6,8)
    mon.setBackgroundColor(mblack)
    if allClients[i].deviceState == "CLOSED" or allClients[i].deviceState == "ON" then
      mon.setTextColor(mgreen)
    elseif allClients[i].deviceState == "OPEN" or allClients[i].deviceState == "OFF" then
      mon.setTextColor(morange)
    elseif allClients[i].deviceState == "LOCKED" then
      mon.setTextColor(mred)
    end
    mon.write("        ")
    mon.setCursorPos((i*8)-6,8)
    mon.write(allClients[i].deviceState)
  end
end

local function monTouch()
  local touchEvent = { os.pullEvent("monitor_touch") }
  local posX = touchEvent[3]
  local posY = touchEvent[4]
  if posY == monY then
    if posX < monX/2 then
      thisCommand = "LOCKED"
      lockState = "Locked"
      for i = 1,#allClients,1 do
        client = allClients[i].cc
        allClients[i].deviceState = thisCommand
        ccSuccess = netSend()
      end
      return
    elseif posX > monX/2 then
      for i = 1,#allClients,1 do
        if allClients[i].deviceType == "Door" then 
          allClients[i].deviceState = "CLOSED"
          thisCommand = "CLOSED"
        elseif allClients[i].deviceType == "Energy" then
          allClients[i].deviceState = "ON"
          thisCommand = "ON"
        elseif allClients[i].deviceType == "Bridge" then
          allClients[i].deviceState = "OFF"
          thisCommand = "OFF"
        end
        client = allClients[i].cc
        ccSuccess = netSend()
      end
      lockState = "Unlocked"
      return
    end
  end
  for i = 1,#allClients,1 do
    if posX > (i*8)-8 and posX < (i*8) then
      client = allClients[i].cc
      if posY == 8 then
        thisCommand = "LOCKED"
        allClients[i].deviceState = thisCommand
        ccSuccess = netSend()
        return
      elseif posY > 4 and posY < 7 then
        if allClients[i].deviceState == "OPEN" or allClients[i].deviceState == "OFF" then
          if allClients[i].deviceType == "Door" then
            thisCommand = "CLOSED"
          else
            thisCommand = "ON"
          end
          allClients[i].deviceState = thisCommand
          ccSuccess = netSend()
          return
        elseif allClients[i].deviceState == "CLOSED" or allClients[i].deviceState == "ON" then
          if allClients[i].deviceType == "Door" then 
            thisCommand = "OPEN"
          else
            thisCommand = "OFF"
          end
          allClients[i].deviceState = thisCommand
          ccSuccess = netSend()
          return
        elseif allClients[i].deviceState == "LOCKED" then
          if allClients[i].deviceType == "Door" then 
            thisCommand = "CLOSED"
          elseif allClients[i].deviceType == "Energy" then
            thisCommand = "ON"
          elseif allClients[i].deviceType == "Bridge" then
            thisCommand = "OFF"
          end
          allClients[i].deviceState = thisCommand
          ccSuccess = netSend()
          return
        end
      end
    end
  end
  client = nil
  thisCommand = "touch"
  ccSuccess = false
end

local function keyInput()
  local keyEvent = { os.pullEvent("key") }
  if keyEvent[2] == 201 then -- keys.pageUp
    if pageNum > 1 then
      pageNum = pageNum - 1
      return
    end
  elseif keyEvent[2] == 209 then -- keys.pageDown
    if pageNum < numPages then
      for i = 5,termY,1 do
        term.setCursorPos(26,i)
        term.write(string.rep(" ",termX))
      end
      pageNum = pageNum + 1
      return
    end
  elseif keyEvent[2] == 59 then -- keys.F1
    help = not help
    if help then
      helpScreen()
    else
      term.clear()
      return
    end
  end
  return
end

local function charInput()
  local charEvent = { os.pullEvent("char") }
  if charEvent[2] == "," or charEvent[2] == "<" or charEvent[2] == "[" or charEvent[2] == "{" then
    if pageNum > 1 then
      pageNum = pageNum - 1
      return
    end
  elseif charEvent[2] == "." or charEvent[2] == ">" or charEvent[2] == "]" or charEvent[2] == "}" then
    if pageNum < numPages then
      for i = 5,termY,1 do
        term.setCursorPos(26,i)
        term.write(string.rep(" ",termX))
      end
      pageNum = pageNum + 1
      return
    end
  elseif charEvent[2] == "q" then
    kernelState = false
    rednet.close(wifiSide)
    mon.setBackgroundColor(mblack)
    mon.clear()
    term.clear()
    term.setCursorPos(1,1)
    term.setTextColor(white)
    term.write("WiRe Server is OFFLINE")
    term.setCursorPos(1,3)
    return
  end
  return
end

local function foregroundShell()
  term.setBackgroundColor(black)
  term.setTextColor(white)
  term.clear()
  term.setCursorPos(1,1)
  if tArgs[1] then
    if fs.exists(tArgs[1]) then
      shell.run(tArgs[1])
    end
  end
  mon.setBackgroundColor(mblack)
  mon.clear()
  term.setBackgroundColor(black)
  term.clear()
  term.setCursorPos(1,1)
  shell.run("shell")
  term.clear()
  term.setCursorPos(1,1)
  term.write("WiRe Server is OFFLINE")
  term.setCursorPos(1,3)
end

local function dataPoller()
  local timerEvent = { os.pullEvent("timer") }
  if timerEvent[2] == pollTimer then
    if kernelState then
      local clCount = 0
      for i = 1,#allClients,1 do
        clCount = clCount + 1
        if allClients[i].quietCount > 1 then
          table.remove(allClients,i)
          i = i - 1
          if i == 0 then i = 1 end
          if not help then
            term.setBackgroundColor(black)
            term.setCursorPos(26,4+clCount)
            term.write(string.rep(" ",termX))
            mon.setBackgroundColor(mblack)
            mon.clear()
          end
        end
        if clCount >= #allClients then break end
      end
      numPages = math.ceil(#allClients/7)
      for i = 1,#allClients,1 do
        client = allClients[i].cc
        allClients[i].quietCount = allClients[i].quietCount + 1
        ccSuccess = netSend("QRY")
      end
      client = nil
      thisCommand = "WiReQRY"
      pollTimer = os.startTimer(3)
      return
    end
  end
end      

local function ccKernel()
  while kernelState do
    if not tArgs[1] and not help then
      termScreen()
    end
    monControls()
    parallel.waitForAny(monTouch,keyInput,charInput,netReceive,dataPoller)
  end
end

local function firstRun()
  if not fs.exists("/data") then fs.makeDir("/data") end
  -- Set server name
  term.setCursorPos(2,2)
  term.write("Please name this server")
  while true do
    term.setCursorPos(2,4)
    local newName = tostring(read())
    if newName ~= "" and newName ~= "nil" then
      ccSettings.name = newName
      break
    end
  end
  -- Set server description
  term.clear()
  term.setCursorPos(2,2)
  term.write("Please type in a short")
  term.setCursorPos(2,3)
  term.write("server description")
  while true do
    term.setCursorPos(2,5)
    local newDesc = tostring(read())
    if newDesc ~= "" and newDesc ~= "nil" then
      ccSettings.note = newDesc
      break
    end
  end
  -- Set computer label
  local ccLabel = os.getComputerLabel()
  if ccLabel == nil or ccLabel == "" then
    os.setComputerLabel(ccSettings.name)
  end
   -- Select color
  local colorList = { P = "Purple", B = "Blue", L = "Light Blue", G = "Green", R = "Red", O = "Orange", N = "Brown", Y = "Light Gray", }
  local colorPick = { P = purple, B = blue, L = lblue, G = green, R = red, O = orange, N = brown, Y = lgray, }
  term.clear()
  term.setCursorPos(2,2)
  term.write("Select a group color")
  local ttY = 4
  for c,n in pairs(colorList) do
    term.setCursorPos(2,ttY)
    term.write(tostring(c) .. " = " .. n)
    ttY = ttY + 1
  end  
  term.setCursorPos(2,13)
  while true do
    local done = false
    local newColor = string.upper(tostring(read()))
    if newColor ~= "" and newColor ~= "nil" then
      for k,v in pairs(colorList) do
        if newColor == tostring(k) then
          ccSettings.color = v
          done = true
          break
        end
      end
      if done then break end
    end
  end
  saveData()
end

local function initMe()
  term.setBackgroundColor(black)
  term.clear()
  if not fs.exists(config) then firstRun() end
  term.setCursorPos(2,2)
  term.setTextColor(white)
  term.write("Ingesting configuration data . . .")
  local srvConfig = fs.open(config,"r") or error("41: Cannot open " .. config .. " for reading", 2)
  local srvData = srvConfig.readAll()
  ccSettings = textutils.unserialize(srvData)
  srvConfig.close()
  term.setCursorPos(2,4)
  term.write("Configuring hardware . . .")
  for _,side in ipairs(rs.getSides()) do
    if peripheral.isPresent(side) then
      if peripheral.getType(side) == "monitor" then
        mon = peripheral.wrap(side)
      elseif peripheral.getType(side) == "modem" then
        if peripheral.call(side,"isWireless") then
          wifiSide = side
          if not rednet.isOpen(side) then
            rednet.open(side)
          end
        else
          for _,perp in ipairs(peripheral.call(side,"getNamesRemote")) do
            if perp:sub(1,7) == "biolock" then
              bio = perhiperal.wrap(perp)
            elseif perp:sub(1,7) == "monitor" then
              mon = peripheral.wrap(perp)
            end
          end
        end
      end
    end
  end
  if not wifiSide then
    term.clear()
    term.setTextColor(red)
    term.setCursorPos(1,2)
    print("No modem detected!")
    print("WiRe Server REQUIRES")
    print("a wireless modem.")
    term.setCursorPos(1,6)
    quit = "YES"
    return
  end
  if not mon then
    term.clear()
    term.setTextColor(red)
    term.setCursorPos(1,2)
    print("No monitor detected!")
    print("WiRe Server REQUIRES")
    print("an Advanced Monitor.")
    term.setCursorPos(1,6)
    quit = "YES"
    return
  end
  if not mon.isColor() then
    term.clear()
    term.setTextColor(red)
    term.setCursorPos(1,2)
    print("Standard Monitor detected!")
    print("WiRe Server REQUIRES an")
    print("Advanced Monitor.")
    term.setCursorPos(1,6)
    quit = "YES"
    return
  end
  mon.setTextScale(0.5)
  monX,monY = mon.getSize()
  mon.setBackgroundColor(mblack)
  mon.clear()
  term.setCursorPos(2,6)
  term.write("Acquiring GPS fix . . .")
  loc.x, loc.y, loc.z = gps.locate(2)
  if not loc.x then
    loc.x,loc.y,loc.z = "No GPS Fix","No GPS Fix","No GPS Fix"
  end
  local lookupName = "WiRe-" .. ccSettings.color
  rednet.host(lookupName,ccSettings.name)
  ccSuccess = true
  thisCommand = "init"
  kernelState = true
  term.clear()
end

if os.clock() < 5 then sleep(math.random(0,1)) end
initMe()
pollTimer = os.startTimer(3)

if quit == "YES" then return end
if tArgs[1] then
parallel.waitForAny(ccKernel, foregroundShell)
else
  ccKernel()
end

Client
SpoilerPastebin

--[[    WiRe Client    ]]--
--[[      by Dog       ]]--
--[[ aka HydrantHunter ]]--
--[[  Wi = Wireless    ]]--
--[[  Re = Redstone    ]]--
--[[ pastebin jtFa7V1n ]]--
--[[      GPL v3       ]]--
local WiReCver = "1.0.00"
--[[
Tested with/requires:
  - Mincraft 1.6.4
  - ComputerCraft ver. 1.6+ for MC 1.6.4
    - A Computer (standard or advanced) with a wireless modem and an optional Advanced Monitor, or a Wireless Turtle (standard or advanced)
]]--
local tArgs = { ... }
-- CONFIGURATION
-- Default Settings
local mon = { }
--local bio = { }
local termX,termY = term.getSize()
local me = os.getComputerID()
local config = "/data/WiReClientCfg"
local ccSettings = {
                     name = "WiReClient",
                     note = "short note",
                     color = "lgray",
                     side = "top",
                     deviceType = "Door",
                   }
local loc = { }
local deviceState, deviceType = "QRY", "QRY"
local quit = "NO"
local ccSuccess = false
local kernelState = false
local server, wifiSide, thisCommand, pollTimer, GPS
 -- Terminal Colors
local white = colors.white
local black = colors.black
local lgray = colors.lightGray
local gray = colors.gray
local brown = colors.brown
local yellow = colors.yellow
local orange = colors.orange
local red = colors.red
local magenta = colors.magenta
local purple = colors.purple
local blue = colors.blue
local lblue = colors.lightBlue
local cyan = colors.cyan
local lime = colors.lime
local green = colors.green
if not term.isColor() then
  lgray = colors.white
  gray = colors.black
  brown = colors.white
  yellow = colors.white
  orange = colors.white
  red = colors.white
  magenta = colors.white
  purple = colors.white
  green = colors.white
  blue = colors.black
  lblue = colors.white
  cyan = colors.white
  lime = colors.white
  green = colors.white
end
-- Monitor colors
local mwhite = colors.white
local mblack = colors.black
local mlgray = colors.lightGray
local mgray = colors.gray
local mbrown = colors.brown
local myellow = colors.yellow
local morange = colors.orange
local mred = colors.red
local mmagenta = colors.magenta
local mpurple = colors.purple
local mblue = colors.blue
local mlblue = colors.lightBlue
local mcyan = colors.cyan
local mlime = colors.lime
local mgreen = colors.green
-- END CONFIGURATION

local function saveData()
  if not fs.exists("/data") then fs.makeDir("/data") end
  local clientConfig = fs.open(config,"w") or error("saveData(): Cannot open " .. config .. " for writing", 2)
  clientConfig.write(textutils.serialize(ccSettings))
  clientConfig.close()
end

local function netSend()
  local tempSettings = {
                         program = "WiRe",
                         cc = me,
                         name = ccSettings.name,
                         color = ccSettings.color,
                         deviceType = deviceType,
                         deviceState = deviceState,
                         quietCount = 0,
                         loc = loc
                       }
  if not rednet.isOpen(wifiSide) then
    rednet.open(wifiSide)
  end
  rednet.send(server,tempSettings)
  return true
end

local function netReceive()
  local netEvent = { rednet.receive() }
  local sender = netEvent[1]
  local newCmdData = netEvent[2]
  if type(newCmdData) == "table" then
    if newCmdData.program == "WiRe" and newCmdData.cc == sender and newCmdData.color == ccSettings.color then
      server = sender
      local validActions = { ON = true, OFF = true, OPEN = true, CLOSED = true, LOCKED = true, WiReQRY = true, }
      if validActions[newCmdData.cmd] then
        thisCommand = newCmdData.cmd
        return true
      else
        return false
      end
    end
  end
  return false
end

local function getColor(assignment)
  local colorBurst = { Purple = purple, Blue = blue, ["Light Blue"] = lblue, Green = green, Red = red, Orange = orange, Brown = brown, ["Light Gray"] = lgray, }
  for name,color in pairs(colorBurst) do
    if assignment == tostring(name) then
      return color
    end
  end
end

local function termScreen()
  local hText = "WiRe Client " .. WiReCver
  term.setBackgroundColor(black)
  term.setCursorPos(1,1)
  term.setTextColor(white)
  term.setBackgroundColor(blue)
  term.write(string.rep(" ",math.floor(termX/2)-(#hText/2)) .. hText .. string.rep(" ",math.ceil(termX/2)+(#hText/2)))
  term.setCursorPos(1,3)
  term.setTextColor(lgray)
  term.setBackgroundColor(black)
  term.write("Name: ")
  term.setTextColor(white)
  term.write(ccSettings.name)
  term.setCursorPos(1,4)
  term.setTextColor(lgray)
  term.write("Note: ")
  term.setTextColor(white)
  term.write(ccSettings.note)
  term.setCursorPos(1,6)
  term.setTextColor(lgray)
  term.write("Group: ")
  term.setTextColor(getColor(ccSettings.color))
  term.write(ccSettings.color)
  term.setCursorPos(1,8)
  term.setTextColor(lgray)
  term.write("cc# ")
  term.setTextColor(white)
  term.write(tostring(me))
  term.setCursorPos(1,9)
  term.setTextColor(lgray)
  term.write("Server cc# ")
  term.setTextColor(white)
  term.write(tostring(server))
  term.setCursorPos(1,11)
  term.setTextColor(lgray)
  term.write("WiFi: ")
  term.setTextColor(white)
  term.write(wifiSide)
  term.setCursorPos(1,12)
  term.setTextColor(lgray)
  term.write("Redstone: ")
  term.setTextColor(white)
  term.write(ccSettings.side)
  term.setCursorPos(1,14)
  term.setTextColor(lgray)
  term.write("Device Type: ")
  term.setTextColor(white)
  term.write(ccSettings.deviceType)
  term.setCursorPos(1,15)
  term.setTextColor(lgray)
  term.write("Current State: ")
  if deviceState == "LOCKED" then
    term.setTextColor(red)
  elseif deviceState == "OPEN" or deviceState == "OFF" then
    term.setTextColor(orange)
  elseif deviceState == "CLOSED" or deviceState == "ON" then
    term.setTextColor(green)
  end
  term.write(deviceState .. "  ")
  term.setCursorPos(1,17)
  term.setTextColor(lgray)
  term.write("Last Command: ")
  term.setTextColor(white)
  term.write(thisCommand .. string.rep(" ",8))
  term.setCursorPos(1,18)
  term.setTextColor(lgray)
  term.write("Success: ")
  if ccSuccess then
    term.setTextColor(green)
  else
    term.setTextColor(red)
  end
  term.write(tostring(ccSuccess) .. " ")
  term.setCursorPos(30,3)
  term.setTextColor(lgray)
  term.write("Peripherals")
  term.setCursorPos(30,5)
  term.setTextColor(white)
  if bio then term.write("Biolock") setCursorPos(30,7) end
  if mon then term.write("Monitor") end
end

local function doAction() -- to switch to net activation, change 'deviceState =' to 'thisCommand =' ???
  local actions = {
                    ON = function() rs.setOutput(ccSettings.side,true) deviceState = "ON" return true end,         -- redstone - side + true/false
                    OFF = function() rs.setOutput(ccSettings.side,false) deviceState = "OFF" return true end,      -- redstone - side + true/false
                    OPEN = function() rs.setOutput(ccSettings.side,false) deviceState = "OPEN" return true end,    -- redstone - side + true/false
                    CLOSED = function() rs.setOutput(ccSettings.side,true) deviceState = "CLOSED" return true end, -- redstone - side + true/false
                    LOCKED = function() if deviceType == "Door" or deviceType == "Energy" then rs.setOutput(ccSettings.side,true) else rs.setOutput(ccSettings.side,false) end deviceState = "LOCKED" return true end,   -- redstone - side + true/false
                    WiReQRY = function()
                                 local rsState = rs.getOutput(ccSettings.side)
                                 if rsState then
                                   if deviceState ~= "LOCKED" then
                                     if deviceType == "Door" then
                                       deviceState = "CLOSED"
                                       return true
                                     elseif deviceType == "Energy" then
                                       deviceState = "ON"
                                       return true
                                     elseif deviceType == "Bridge" then
                                       deviceState = "ON"
                                       return true
                                     end
                                   end
                                 else
                                   if deviceState ~= "LOCKED" then
                                     if deviceType == "Door" then
                                       deviceState = "OPEN"
                                       return true
                                     elseif deviceType == "Energy" then
                                       deviceState = "OFF"
                                       return true
                                     elseif deviceType == "Bridge" then
                                       deviceState = "OFF"
                                       return true
                                     end
                                   end
                                 end
                               end,
                  }
  for cmd,func in pairs(actions) do
    if tostring(cmd) == thisCommand then
      return func()
    end
  end
  return false
end

local function foregroundShell()
  term.setBackgroundColor(black)
  term.setTextColor(white)
  term.clear()
  term.setCursorPos(1,1)
  if fs.exists(tArgs[1]) then
 shell.run(tArgs[1])
  end
  term.setBackgroundColor(black)
  term.clear()
  term.setCursorPos(1,1)
  shell.run("shell")
  term.clear()
  term.setCursorPos(1,1)
  term.write("WiRe Client is OFFLINE")
  term.setCursorPos(1,3)
end

local function dataPoller()
  while true do
    local timerEvent = { os.pullEvent("timer") }
    if timerEvent[2] == pollTimer then
      if kernelState then
        thisCommand = "WiReQRY"
        pollTimer = os.startTimer(10)
        return
      end
    end
  end
end

local function charInput()
  local charEvent = { os.pullEvent("char") }
  if charEvent[2] == "q" then
    kernelState = false
    rednet.close(wifiSide)
    if mon[1] then
      for i = 1,#mon,1 do
        mon[i].setBackgroundColor(mblack)
        mon[i].clear()
      end
    end
    term.clear()
    term.setCursorPos(1,1)
    term.setTextColor(white)
    term.write("WiRe Client is OFFLINE")
    term.setCursorPos(1,3)
    return
  end
  return
end

local function monTouch()
  if not mon[1] then return end
  for i = 1,#mon,1 do
    if deviceState == "LOCKED" then
      mon[i].setBackgroundColor(mred)
    elseif deviceState == "OPEN" or deviceState == "OFF" then
      mon[i].setBackgroundColor(morange)
    elseif deviceState == "CLOSED" or deviceState == "ON" then
      mon[i].setBackgroundColor(mgreen)
    end
    for j = 2,6,1 do
      for k = 2,4,1 do
        mon[i].setCursorPos(j,k)
        mon[i].write(" ")
      end
    end
    mon[i].setCursorPos(3,3)
    mon[i].setTextColor(mwhite)
    mon[i].write("<*>")
  end
  local touchEvent = { os.pullEvent("monitor_touch") }
  if deviceState == "OPEN" or deviceState == "OFF" then
    if deviceType == "Door" then
      thisCommand = "CLOSED"
    else
      thisCommand = "ON"
    end
    return
  elseif deviceState == "CLOSED" or deviceState == "ON" then
    if deviceType == "Door" then
      thisCommand = "OPEN"
    else
      thisCommand = "OFF"
    end
    return
  end
end

local function bioTouch() --"biolock", userPrint, attachSide, learnedName, accessLevel
  if not bio then return end
  local touchEvent = { os.pullEvent("biolock") }
  if deviceState == "OPEN" then
    return "CLOSED",touchEvent[5]
  else
    return "OPEN",touchEvent[5]
  end
end

local function ccKernel()
  while kernelState do
    if not tArgs[1] then
      termScreen()
    end
    --local actionTrigger
    if mon[1] then
      parallel.waitForAny(netReceive,dataPoller,charInput,monTouch)
    else
      parallel.waitForAny(netReceive,dataPoller,charInput)
    end
    ccSuccess = doAction()
    ccSuccess = netSend()
  end
end

local function firstRun()
  term.clear()
  if not fs.exists("/data") then fs.makeDir("/data") end
  -- Set computer name
  term.setCursorPos(2,2)
  term.write("Please name this device")
  term.setCursorPos(3,3)
  term.write("(12 characters or less)")
  while true do
    term.setCursorPos(2,4)
    local newName = tostring(read())
    if newName ~= "" and newName ~= "nil" then
      if #newName > 12 then newName = newName:sub(1,12) end
      ccSettings.name = newName
      break
    end
  end
  -- Set computer description
  term.clear()
  term.setCursorPos(2,2)
  term.write("Please type in a short")
  term.setCursorPos(2,3)
  term.write("client description")
  while true do
    term.setCursorPos(2,5)
    local newDesc = tostring(read())
    if newDesc ~= "" and newDesc ~= "nil" then
      ccSettings.note = newDesc
      break
    end
  end
  -- Set computer label
  local ccLabel = os.getComputerLabel()
  if ccLabel == nil or ccLabel == "" then
    os.setComputerLabel(ccSettings.name)
  end
  term.clear()
  term.setCursorPos(2,2)
  term.write("Is this a door (d), an energy barrier (e),")
  term.setCursorPos(2,3)
  term.write("or a bridge (B)/>?")
  while true do
    term.setCursorPos(2,5)
    local newType = tostring(read())
    if string.lower(newType) == "d" or string.lower(newType) == "e" or string.lower(newType) == "b" then
      if string.lower(newType) == "d" then
        deviceType = "Door"
      elseif string.lower(newType) == "e" then
        deviceType = "Energy"
      elseif string.lower(newType) == "b" then
        deviceType = "Bridge"
      end
      ccSettings.deviceType = deviceType
      break
    end
  end
   -- Select color
  local colorList = { P = "Purple", B = "Blue", L = "Light Blue", G = "Green", R = "Red", O = "Orange", N = "Brown", Y = "Light Gray", }
  local colorPick = { P = purple, B = blue, L = lblue, G = green, R = red, O = orange, N = brown, Y = lgray, }
  term.clear()
  term.setCursorPos(2,2)
  term.write("Select a group color")
  local ttY = 4
  for c,n in pairs(colorList) do
    term.setCursorPos(2,ttY)
    term.write(tostring(c) .. " = " .. n)
    ttY = ttY + 1
  end  
  term.setCursorPos(2,13)
  while true do
    local newColor = string.upper(tostring(read()))
    if newColor ~= "" and newColor ~= "nil" then
      for k,v in pairs(colorList) do
        if newColor == tostring(k) then
          ccSettings.color = v
          break
        end
      end
      break
    end
  end
  -- Select redstone output side
  term.clear()
  term.setCursorPos(2,2)
  term.write("Select a redstone output side")
  local yPos = 3
  for num,side in ipairs(rs.getSides()) do
    yPos = yPos + 1
    term.setCursorPos(2,yPos)
    term.write(num .. ": " .. side)
  end
  repeat
    local finished = false
    term.setCursorPos(2,11)
    local rsSide = read()
    for num,side in ipairs(rs.getSides()) do
      if rsSide == side or tonumber(rsSide) == num then
        ccSettings.side = side
        finished = true
        break
      end
    end
  until finished
  saveData()
end

local function initMe()
  term.setBackgroundColor(black)
  if not fs.exists(config) then firstRun() end
  term.clear()
  term.setCursorPos(2,2)
  term.setTextColor(white)
  term.write("Ingesting configuration data . . .")
  local clientConfig = fs.open(config,"r") or error("41: Cannot open " .. config .. " for reading", 2)
  local clientData = clientConfig.readAll()
  ccSettings = textutils.unserialize(clientData)
  clientConfig.close()
  term.setCursorPos(2,4)
  term.write("Configuring hardware . . .")
  for _,side in ipairs(rs.getSides()) do
    if peripheral.isPresent(side) then
      if peripheral.getType(side) == "biolock" then
        bio = perhiperal.wrap(side)
      elseif peripheral.getType(side) == "monitor" then
        mon[#mon+1] = peripheral.wrap(side)
      elseif peripheral.getType(side) == "modem" then
        if peripheral.call(side,"isWireless") then
          wifiSide = side
          if not rednet.isOpen(side) then
            rednet.open(side)
          end
        else  -- need to figure out if rednet works over wired modems (to eliminate wireless if desired)
          for _,perp in ipairs(peripheral.call(side,"getNamesRemote")) do
            if perp:sub(1,7) == "biolock" then
              bio = perhiperal.wrap(perp)
            elseif perp:sub(1,7) == "monitor" then
              mon[#mon+1] = peripheral.wrap(perp)
            end
          end
        end
      end
    end
  end
  if not wifiSide then
    term.clear()
    term.setTextColor(red)
    term.setCursorPos(1,2)
    print("No modem detected!")
    print("WiRe Client REQUIRES")
    print("a wireless modem.")
    term.setCursorPos(1,6)
    quit = "YES"
    return
  end
  if mon[1] then
    for i = 1,#mon,1 do
      mon[i].setTextScale(1)
      mon[i].setBackgroundColor(mblack)
      mon[i].clear()
      if not mon[i].isColor() then
        term.clear()
        term.setTextColor(red)
        term.setCursorPos(1,2)
        print("Standard Monitor detected!")
        print("WiRe Client REQUIRES an")
        print("Advanced Monitor.")
        term.setCursorPos(1,6)
        quit = "YES"
        return
      end
    end
  end
  term.setCursorPos(2,6)
  term.write("Acquiring GPS fix . . .")
  loc.x, loc.y, loc.z = gps.locate(2)
  if not loc.x then
    loc.x,loc.y,loc.z = "No GPS Fix","No GPS Fix","No GPS Fix"
  end
  term.setCursorPos(2,8)
  term.write("Looking for WiRe Server . . .")
  for i = 1,3,1 do
    local lookupName = "WiRe-" .. ccSettings.color
    local tmpServers = { rednet.lookup(lookupName) }
    server = tmpServers[1] or nil
    if not server then
      sleep(2)
    else
      break
    end
  end
  if not server then
    term.clear()
    term.setTextColor(red)
    term.setCursorPos(1,2)
    print("No server detected!")
    print("WiRe Client REQUIRES")
    print("a WiRe Server.")
    term.setCursorPos(1,6)
    quit = "YES"
    return
  end
  deviceType = ccSettings.deviceType
  if deviceType == "Door" then
    rs.setOutput(ccSettings.side,true)
    deviceState = "CLOSED"
  elseif deviceType == "Energy" then
    rs.setOutput(ccSettings.side,true)
    deviceState = "ON"
  elseif deviceType == "Bridge" then
    rs.setOutput(ccSettings.side,false)
    deviceState = "OFF"
  end
  ccSuccess = netSend()
  thisCommand = "init"
  kernelState = true
  term.clear()
end

if os.clock() < 5 then sleep(math.random(1,2)) end
initMe()
pollTimer = os.startTimer(10)

if quit == "YES" then return end
if tArgs[1] then
parallel.waitForAny(foregroundShell, ccKernel)
else
  ccKernel()
end
CCGrimHaxor #2
Posted 19 May 2014 - 02:37 PM
This is a bug. You usually get it when you overflow the bios and it posts invalid code and crashes the system. I thought it was fixed in 1.6