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

Bad Reception(noGPS) - easy, out-of-the-box location tracking

Started by ChaosNicro, 27 February 2016 - 01:15 PM
ChaosNicro #1
Posted 27 February 2016 - 02:15 PM
Hello Everyone,

My API provides a way to return a turtle to a home position without the need of wireless modems or GPS-towers.

Additionally there is an auto-save/auto-load feature for persistence

How to use it (or any custom API):

- Download and save the API on the turtle.

- Load it via os.loadAPI() either in your program or in the Lua prompt.

- Use any of the functions below like you normally would.

Functions:

noGPS.save() - Manually saves the current relative position to file.

noGPS.load() - Manually reads position from the save file.

noGPS.reset() - Resets both the internal memory and the save-data, thus setting the current position as the new home.

noGPS.goHome() - Returns the turtle to its home position by aligning the relative length, width, height and facing coordinates in that order. if possible turtles will break blocks in their path, otherwise they will get stuck until the path is cleared.

noGPS.up()

noGPS.down()

noGPS.forward()

noGPS.back()

noGPS.turnLeft()

noGPS.turnRight()

These will behave just like the vanilla counterparts with the addition of reporting the respective movement to the tracker, this includes return values and responses to lack of fuel.

Compatibility:

In order to use an already made program with this API replace all the movement functions with their modded versions.
Or you could use the new automatic converter:
SpoilerThe converter is a separate program that will translate between noGPS and native movement functions, it will also add or remove an "os.loadAPI" at the top.
To use it follow this format:
converter <filename> <direction> <keep>

"filename" needs to be the name of the original file (and the path to it if necessary).
"direction" needs to be "true" when converting to the noGPS-format and "false" when converting a file back to the native format. (without quotes)
"keep" needs to be "true" when the original file should be kept and "false" when it should be overwritten. (without quotes)
Whenever "keep" is enabled, the output will be named "filename-converted" and will appear next to the original file.
A help-text will be displayed when any of the argument mismatch or none are given.

Download:
V1.0: http://pastebin.com/3q7c5zGw no guarantees yet, backup your stuff!

To return home automatically after a restart call goHome() at the top of your startup-script.

Settings:

isMiningTurtle: Defaults to true and determines whether blocks can/should be broken when trying to reach home.

Disclaimer:

All measures have been taken to protect the data from unloading chunks, servers crashing or games being closed suddenly. However, cases may still exist where the coordinates get offset sightly because of such events.

Dowload:

SpoilerV1.1:
http://pastebin.com/qiews8gx (with fuel enabled)
http://pastebin.com/y13d4Rge (with fuel disabled)

V1.0:
http://pastebin.com/nhbfuM3U

Changelog:

SpoilerV1.1
cleanup
now using fuellevels to validate movements (Thanks, Sangar.)
added Temp-files for in-movement-crashes

V1.0
initial release


Please enjoy and leave feedback below. ^_^/>
Edited on 18 April 2016 - 09:24 PM
DannySMc #2
Posted 28 February 2016 - 01:57 AM
It's a cool idea, but my question is why don't you overwrite the current functions?
So save the old function to another name, then add your code and then add in the older function to make it actually move? Then this API can just extend the functionality of the turtle API so turtle.goHome() if you need an example I can give you one? Just ask.

But I like it a lot don't get me wrong, it can be very useful!
HDeffo #3
Posted 28 February 2016 - 06:48 AM
for examples you can either look at kingofgamesyami's LAMA or my tortoise APIs. Both of ours have a built in override function. In case you need a working example of this.
ChaosNicro #4
Posted 28 February 2016 - 11:33 AM
@
It's a cool idea, but my question is why don't you overwrite the current functions?
So save the old function to another name, then add your code and then add in the older function to make it actually move? Then this API can just extend the functionality of the turtle API so turtle.goHome() if you need an example I can give you one? Just ask.

But I like it a lot don't get me wrong, it can be very useful!

for examples you can either look at kingofgamesyami's LAMA or my tortoise APIs. Both of ours have a built in override function. In case you need a working example of this.

I thought of that as well but I was hesitant to touch the vanilla functions for compatibility's sake.
Seeing as my versions are used the very same way it would be something to look into though.
Would the override only apply in the program using the API and nowhere beyond that?
biggest yikes #5
Posted 28 February 2016 - 02:02 PM
Would the override only apply in the program using the API and nowhere beyond that?
No, unless the API has not been loaded since the last reboot, in which case it's not overridden at all
HDeffo #6
Posted 28 February 2016 - 04:45 PM
here you can feel free to use the override function from my Tortoise API :3


function becomeTurtle()
   turtle = {}
   for k, v in next, _G.turtle do --#first we need to fix our local turtle table so we dont start any loops
	 turtle[k] = v
   end
   for k, v in next, getfenv() do --#then we put ourselves in the global turtle table
	 _G.turtle[k] = v
   end
end

please note in order for this to work turtle had to have been localized in the script just call

local turtle = turtle
at the top of your script and it will work fine




If you want it to only appear in the program that started it that's a bit more complicated but you could do something like this

function becomeTurtle(programName)
   turtle = {}
   for k, v in next, _G.turtle do --#first we need to fix our local turtle table so we dont start any loops
	 turtle[k] = v
   end
   for k, v in next, getfenv() do --#then we put ourselves in the global turtle table
	 _G.turtle[k] = function(...) --#we are creating a new function
		 if shell.getRunningProgram()==programName then--#if what is running is what was passed as a parameter
			return v(...) --#we return our function
		 else
			return turtle[k](...)--#if not we return the native turtle function
		 end
	  end
   end
end


I wrote that up off the top of my head so it isn't very "fool" proof but it should give you a general idea on how to make that work
Edited on 28 February 2016 - 03:52 PM
ChaosNicro #7
Posted 04 March 2016 - 05:34 PM
snip and such

Thanks, finally got around to looking at it.
I changed the code to read this:
function changeMode(mode)
   turtle = {}
   for k, v in next, _G.turtle do --#first we need to fix our local turtle table so we dont start any loops
		 turtle[k] = v
   end
   for k, v in next, getfenv() do --#then we put ourselves in the global turtle table
		 _G.turtle[k] = function(...) --#we are creating a new function
				 if mode == "noGPS" then --#if the mode is noGPS...
					    return v(...) --#we return our function
				 elseif mode == "native" then
					    return turtle[k](...)--#if it is native we return the native turtle function
				 end
		  end
   end
end

It works great ecxept for the piece where it should restore the native function.
From what I can see this is because the table gets reset on the first line and your version goes through each function one-by-one, dropping the native function completely when not used.
Can I actually keep a table of the native functions and restore it as needed?

I would personally like to keep one table with my functions and one with the native ones, then I would apply the specified one to "turtle", keeping the tables stored separately.

This should not be too difficult but the two for-loops still look like sorcery to me.

On another note would you mind your name next to the entry regarding this in the topic's change log (that I am going to add once I have an actual update)?
Edited on 04 March 2016 - 04:36 PM
HDeffo #8
Posted 04 March 2016 - 08:48 PM
to change it back it should be as simple as

function backToNormal()
   for k, v in next, turtle do
	  _G.turtle[k] = v
   end
end


and actually what you want it already does. If you placed at the top of the program
 local turtle = turtle 
that makes a local table only accessible by the program which just directs to the global turtle table. When your overriding function runs however it instead copies out each individual function. So now instead of pointing to the global table it only points to itself. Then the second loop puts out functions into the global turtle table replacing functions as needed. This works because we have the variable turtle stored as a local which contains the old global functions now. When calling a variable a local will be used before a global. So in our program turtle refers to the normal turtle functions and in every other program turtle refers to our functions. I hope that makes sense…

before the loop

_G.turtle = native functions
turtle = native functions

after the loop

_G.turtle = our functions
turtle = native functions
Edited on 04 March 2016 - 07:55 PM
ChaosNicro #9
Posted 04 March 2016 - 10:37 PM
to change it back it should be as simple as

function backToNormal()
   for k, v in next, turtle do
	  _G.turtle[k] = v
   end
end


and actually what you want it already does. If you placed at the top of the program
 local turtle = turtle 
that makes a local table only accessible by the program which just directs to the global turtle table. When your overriding function runs however it instead copies out each individual function. So now instead of pointing to the global table it only points to itself. Then the second loop puts out functions into the global turtle table replacing functions as needed. This works because we have the variable turtle stored as a local which contains the old global functions now. When calling a variable a local will be used before a global. So in our program turtle refers to the normal turtle functions and in every other program turtle refers to our functions. I hope that makes sense…

before the loop

_G.turtle = native functions
turtle = native functions

after the loop

_G.turtle = our functions
turtle = native functions

Alright thanks for the quick answer. Based on your posts my function now looks like this (with turtle being localized beforehand):

function changeMode(mode)
   if mode == "noGPS" then
	  turtle = {}
   for k, v in next, _G.turtle do --#first we need to fix our local turtle table so we dont start any loops
		 turtle[k] = v
   end
   for k, v in next, getfenv() do --#then we put ourselves in the global turtle table
		 _G.turtle[k] = v
   end
elseif mode == "native" then
  for k, v in next, turtle do
		  _G.turtle[k] = v
  end
else
  print("Accepted modes are: noGPS and native.")
  end
end

calling with mode as "noGPS" does what it should, using "native" does not seem to change a thing though.
What I noticed as well is that after the override turtle includes something called "turtle._ENV" which more or less links to every API and function present in CC.
Is that intended?
Edited on 19 April 2016 - 08:52 AM
HDeffo #10
Posted 04 March 2016 - 11:08 PM
Adding _ENV is just an unintended side effect of the simplification of adding the functions. It doesn't really have any negative consequences so I just ignore it.
ChaosNicro #11
Posted 18 April 2016 - 11:30 PM
New Version!

Should now be a lot more robust thanks to the temp-files.
in-movement-restarts are still likely to break things on the noFuel variant though.
I decided to go with a converter instead of hijacking native functions, it just feels cleaner to me personally.
Meit #12
Posted 24 July 2016 - 11:49 AM
This saves movement per each function of movement when it is called and when we execute the command it tries to find the way back?, What if the turtle is closed and stuck on a 3x3 trap place and if we move it, the location will change(the x, y and z which is recorded) isn't it while the turtle cannot move..
Or you have added some checks if it is able to pass through.
ChaosNicro #13
Posted 04 August 2016 - 05:57 PM
This saves movement per each function of movement when it is called and when we execute the command it tries to find the way back?, What if the turtle is closed and stuck on a 3x3 trap place and if we move it, the location will change(the x, y and z which is recorded) isn't it while the turtle cannot move..
Or you have added some checks if it is able to pass through.

Not sure what the question is but if the turtle cannot successfully move it returns false (like the native function) and does not register the movement. I just looked at my code again, here is how it works:

When a movement function is called the turtle first figures out where it would theoretically be after moving. This is important for a potential server crash (etc.) at just this in-move second, so that it can pick up again after a restart.
It then tries to move using the native function and…
- saves the new theoretical position to memory and returns true if it could move successfully.
- discards the new theoretical position while returning false (thus reverting to the unchanged position still in memory.)
The last line then clears the temporary file which confirms that the command was fully executed regardless of success.

If you feel like this did not answer your question or like I made a mistake in my code (I am not perfect.) please feel free to respond again.

Also I am sorry that it took me a while, my notifications do not seem to process properly.

– Nicro