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

Delayed Reactions

Started by gixbit, 26 August 2016 - 11:05 PM
gixbit #1
Posted 27 August 2016 - 01:05 AM
This should be fun to explain!

So, I believe this is my first time posting on this forum and I'm not entirely sure if there's some etiquette besides not asking obvious questions like "How do I lua?". So in advance, I'm sorry if I broke etiquette.

I have a program that uses a Scanner wrapped to the turtle to scan tiles around it. I've been testing the mechanics and found that the scans around the turtle are not relative to the turtle, rather, relative to the world centered on the turtle. So, that means the turtle's direction has no impact on the scan, just what coordinates it has in the world. So, I made a huge key table, like you would if you want to have faster access times, converted all the default scan indexes into coordinates. And now I can scan under the turtle without using turtle.detectDown(). So, here's the issue.

I wanted to test it's reliability on a loop basis. And here's where i'm totally stumped. I have highly modified turtle code so, me pasting code, would REALLY break etiquette, and unless there's enough interest I wont post any code. But, here's the code that is being weird.


while bot.scan[vector.new(0,-1,0)] do bot.move() end


function Scanner.new(Peripheral, Cardinal)
local Meta = Scanner
local self = setmetatable({ device = Peripheral, scanData = nil, type = nil, tracking = {} },Scanner)
function Scanner:__index(key)
  if key.type == "vector" then
   if not self.scanData then
	self.scanData = self.device.sonicScan()
   end
   if self.type then
	return self.scanData[map[key.x][key.y][key.z]].type == self.type
   end
   return self.scanData[map[key.x][key.y][key.z]]
  else
   return Meta[key]
  end
end
return self
end


this.move = function (y,x)
...
	if this.scan.scanData then
		  this.scan.scanData = nil
	end
...
end

That is a test line I wrote. So the setup is, the turtle moves forward until it finds a hole in the floor. But, what actually happens is it stops after it passes the hole, adjacent to it, right next to it, [F][F][H][T]. Floor, Hole, Turtle. Any ideas?

Edit
If I use os.sleep(0.25), after the bot.move(), not before, this whole problem goes away, so clearly there's a particular speed element to this. Oddly enough, I think the code is executing too fast after bot.move().
Edited on 26 August 2016 - 11:35 PM
Lupus590 #2
Posted 27 August 2016 - 02:01 AM
if there is a lot of code you can use something like pastebin to post the whole program
gixbit #3
Posted 27 August 2016 - 02:43 AM
if there is a lot of code you can use something like pastebin to post the whole program

I don't believe that will be necessary, There is a lot of code, but, most of it would be unrelated. I was referring to the main files where the main code for all the functions of the modified turtle code is about 700 lines, and the only ones that really matter i pasted. Unless theres a lack of necessary code to trace enough to understand what is going on, then I will. But, I believe it would distract more than help. I am a novice lua programmer, and most of my experience is in C#, Java, C++. I'm sure it would cause more cringe than it would be worth. I believe this should be enough, I didn't really state the question though.. My question is, is there a way to write code so that it only waits as long as necessary before executing the code safely? I believe it's executing the code that comes next before the turtle has traveled far enough to provide an accurate scan of it's surroundings. Kind of like the scan is ghosting, if you know what i mean.
Bomb Bloke #4
Posted 29 August 2016 - 06:20 AM
Given the symptom you're describing, the issue falls outside of the code you've displayed here.

I would guess that you're managing coroutines (either directly or via the parallel API) in order to allow, I dunno, fielding of incoming modem messages during turtle movements. If you allow your scans to perform asynchronously to your movements as well (bearing in mind that movements trigger a yield, and odds are very high that your chosen scanner peripheral does too), then chances are that therein lies your problem.

There's a possibility that the fault lies in the scanning peripheral itself, though I imagine you've already built a simplified code snippet to test that out?
gixbit #5
Posted 29 August 2016 - 06:31 PM
Well, after further analysis, it seems like, the problem is after the scan is called, the table is not returned immediately, and it looks like it's called asynchronously and doesnt get returned to the turtle for quite some time. Long enough that to circumvent it for now, i've put in code
while not self.scan.Data do end
To halt the whole thing to wait, my code is VERY dependent on that being done before proceeding. I use the scan to check for holes in the tunnel.

https://www.youtube.com/watch?v=TAOyOVcaQ9g

There is the program in question in it's current state. All things considered, it runs quite well. I know that it's not 100% ideal all the time but, for the most part. it does what it is meant to do.
Bomb Bloke #6
Posted 30 August 2016 - 06:45 AM
for now, i've put in code
while not self.scan.Data do end
To halt the whole thing to wait

I assume you're paraphrasing your code again; that particular snippet would lead to a crash on its own, assuming it did anything at all - because it never yields, if self.scan.Data was ever nil at the time it was reached, it'd become impossible for the assignment to complete at all…

(All multitasking in CC is co-operative, see. This is actually true server-wide - if any one script refuses to yield, every CC system in the world will freeze. For this reason, the mod automatically kills scripts which fail to yield within about ten seconds of being resumed.)

Well, if you've got things running, good job in any case. :)/>
gixbit #7
Posted 30 August 2016 - 10:09 PM
I'm not going to paste all of my code to pastebin. I dont like the idea of sharing code without anyone crediting me for my hand in their ideas/work. Hundreds of hours of my work mean a lot to me, I don't mind passing this to friends, I just have some simple questions.


function Scanner:__index(key)
  if key.type == "vector" then
   if not self.Data then
	self.Data = self.Sensor.sonicScan()
	while not self.Data do end
   end
   local S = self.Data[map[key.x][key.y][key.z]]
   if self.type then
	return S.type == self.type
   end
   return S
  end
  return rawget(Scanner, key) or rawget(self, key)
end

There's the scanner index, it's ran just after the turtle moves forward in the video. As you can see, that loop will quit. Unless the self.Sensor key does not exist, in which case, that loop will probably not even run, so I'm covered. Theres also no way that the Sensor key cannot be a Sensor, I've got a Wrapper object that returns SENSORS only. And the Scanner.new has a copy of the this.wrap key from the main turtle object. So, as long as nothing happens to that, which it wont, this code is stable, or should be..

EDIT: Also, the whole self.type thing, when a new Scanner object is instantiated type is nil by default, there's a table of supported filters, So the wrong filter cannot be applied. The only 4 supported are the only results that the sonicScan can return. The point of that should be fairly obvious, it's to return whether or not a block exists in the empty spot. Also, the map[x][y][z], is exactly how it looks.


local map = {
[-3] = {
  [0] = {
   [0] = 1
  }
},
[-2] = {
  [-2] = {
   [-1] = 2,
   [0] = 3,
   [1] = 4
  },
		....
}

There you go, now one of my ideas is public for how to handle scans. Enjoy anyone who cares ;o. It's relative to the world, I think that much is obvious to anyone using scanners. EDIT: And yes, I did sit down and copy each x,y,z value from scans into that map to relate to the default scan range data. It never changes, so why shouldn't you map it.
Edited on 30 August 2016 - 08:21 PM