44 posts
Posted 22 August 2016 - 02:59 AM
CodeAs I demonstrated earlier today on Lurcraft Relived, gps.locate only verifies that the gps hosts it receives messages from are sending tables with 3 coords (the location of the GPS host), but doesn't test to see if the coords are numbers. Sending three tables is enough to trip up an attempt to display the coords using tostring, or to trip up the latter attempt to do subtraction on a malformed vector.
Edited on 29 August 2016 - 12:09 AM
2427 posts
Location
UK
Posted 22 August 2016 - 01:03 PM
the vector API should probably check that what it's getting is numbers too:
https://github.com/a...rom/apis/vectorUntested code fixes, mainly for Dan200
Vector API
Make sure args are numbersfunction new( x, y, z )
local v = {
x = tonumber(x) or 0,
y = tonumber(y) or 0,
z = tonumber(z) or 0
}
setmetatable( v, vmetatable )
return v
end
GPS API
Make sure GPS host positions are not nilfunction locate( _nTimeout, _bDebug )
-- Let command computers use their magic fourth-wall-breaking special abilities
if commands then
return commands.getBlockPosition()
end
-- Find a modem
local sModemSide = nil
for n,sSide in ipairs( rs.getSides() ) do
if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then
sModemSide = sSide
break
end
end
if sModemSide == nil then
if _bDebug then
print( "No wireless modem attached" )
end
return nil
end
if _bDebug then
print( "Finding position..." )
end
-- Open a channel
local modem = peripheral.wrap( sModemSide )
local bCloseChannel = false
if not modem.isOpen( os.getComputerID() ) then
modem.open( os.getComputerID() )
bCloseChannel = true
end
-- Send a ping to listening GPS hosts
modem.transmit( CHANNEL_GPS, os.getComputerID(), "PING" )
-- Wait for the responses
local tFixes = {}
local pos1, pos2 = nil, nil
sBadPositionError = "GPS replied with bad position, check your GPS hosts."
local timeout = os.startTimer( _nTimeout or 2 )
while true do
local e, p1, p2, p3, p4, p5 = os.pullEvent()
if e == "modem_message" then
-- We received a reply from a modem
local sSide, sChannel, sReplyChannel, tMessage, nDistance = p1, p2, p3, p4, p5
if sSide == sModemSide and sChannel == os.getComputerID() and sReplyChannel == CHANNEL_GPS and nDistance then
-- Received the correct message from the correct modem: use it to determine position
if type(tMessage) == "table" and #tMessage == 3 then
local tFix = { vPosition = vector.new( assert(tMessage[1], sBadPositionError), assert(tMessage[2], sBadPositionError),assert(tMessage[3], sBadPositionError) ), nDistance = nDistance }
if _bDebug then
print( tFix.nDistance.." metres from "..tostring( tFix.vPosition ) )
end
if tFix.nDistance == 0 then
pos1, pos2 = tFix.vPosition, nil
else
table.insert( tFixes, tFix )
if #tFixes >= 3 then
if not pos1 then
pos1, pos2 = trilaterate( tFixes[1], tFixes[2], tFixes[#tFixes] )
else
pos1, pos2 = narrow( pos1, pos2, tFixes[#tFixes] )
end
end
end
if pos1 and not pos2 then
break
end
end
end
elseif e == "timer" then
-- We received a timeout
local timer = p1
if timer == timeout then
break
end
end
end
-- Close the channel, if we opened one
if bCloseChannel then
modem.close( os.getComputerID() )
end
-- Return the response
if pos1 and pos2 then
if _bDebug then
print( "Ambiguous position" )
print( "Could be "..pos1.x..","..pos1.y..","..pos1.z.." or "..pos2.x..","..pos2.y..","..pos2.z )
end
return nil
elseif pos1 then
if _bDebug then
print( "Position is "..pos1.x..","..pos1.y..","..pos1.z )
end
return pos1.x, pos1.y, pos1.z
else
if _bDebug then
print( "Could not determine position" )
end
return nil
end
end
Also, I've posted this to GitHub:
https://github.com/dan200/ComputerCraft/issues/138
Edited on 22 August 2016 - 11:32 AM
44 posts
Posted 22 August 2016 - 07:20 PM
I made a
resource pack to fix the bugs.
Edited on 29 August 2016 - 04:41 PM