How to identify ground level (or treetop level)

Post Reply
dgm5555
Member
Posts: 245
Joined: Tue Apr 08, 2014 19:45

How to identify ground level (or treetop level)

by dgm5555 » Post

EDIT: The following code seems to work correctly:-

Code: Select all

local function groundLevel(targetX,targetZ)
	local manip = minetest.get_voxel_manip()	-- the voxel_manip is require to force loading of the block

	local groundLevel = nil
	local i
	-- This will fail if ground level is 100 or above or below below -100 (but this doesn't happen very often)
	for i = 96, -100, -1 do	
		p = {x=targetX, y=i, z=targetZ}
		manip:read_from_map(p, p)
		if minetest.get_node(p).name ~= "air" and minetest.get_node(p).name ~= "ignore" then
			groundLevel = i
			break
		end
	end
	if groundLevel ~= nil then
		-- Search Successful
		return {x=targetX, y=groundLevel, z=targetZ}
	else
		-- Search Failed
		print("groundLevel Search Failed. Groundlevel could be deeper than -100")
		return -1

	end
end

The following is the original post which stimulated the discussion:-


Is there a better way than this to identify ground level in an area which hasn't been visited recently?
My code works but isn't very elegant, as nodes are all seem to be named "ignore" or have a light level of nil unless a player has recently been near them. Moving the player temporarily to the area seems to work as I presume it forces minetest to load the block, but it doesn't seem very elegant. It also forces minetest to generate the terrain even if the area has never been visited, which isn't necesarily desirable. The loop also needs to be repeated as it fails on the initial cycle (presumably loading is slower than looking for nodes). In the forums is mentioned a lua function get_ground_level, but I couldn't find it in the api. minetest.forceload_block(pos) also seems to be slow, but I read somewhere it forces minetest to load it at future startups too, which I don't want.

Code: Select all

local curPos = player:getpos()
local i
while groundLevel == nil do
	for i = 100, -100, -1 do	
		local p = {x=worldX, y=i, z=worldZ}
		player:setpos(p)
--		print (minetest.get_node_light(p, 0.5))
--		print (minetest.get_node(p).name)
		if minetest.get_node(p).name ~= "air" and minetest.get_node(p).name ~= "ignore" then
			groundLevel = i
			break
		end
	end
end
player:setpos(curPos)
Last edited by dgm5555 on Thu May 22, 2014 19:25, edited 1 time in total.

User avatar
Calinou
Moderator
Posts: 3169
Joined: Mon Aug 01, 2011 14:26
GitHub: Calinou
IRC: Calinou
In-game: Calinou
Location: Troyes, France
Contact:

Re: How to identify ground level (or treetop level)

by Calinou » Post

I can't help much, but for consistency, variables should be like_this, not likeThis.

User avatar
Evergreen
Member
Posts: 2135
Joined: Sun Jan 06, 2013 01:22
GitHub: 4Evergreen4
IRC: EvergreenTree
In-game: Evergreen
Location: A forest in the midwest
Contact:

Re: How to identify ground level (or treetop level)

by Evergreen » Post

Calinou wrote:I can't help much, but for consistency, variables should be like_this, not likeThis.
True, camelcase is not what we use around here. :P

spillz
Member
Posts: 138
Joined: Thu Feb 13, 2014 05:11

Re: How to identify ground level (or treetop level)

by spillz » Post

I don't think he asked for style pointers. Sheesh. (And the engine is littered with camelCase last I checked)

What are you trying to do dgm? From what I understand the engine wasn't designed to handle having arbitrary sections of the map loaded, but there was talk on IRC a month ago about improving this situation (and i think some code exists)

User avatar
Calinou
Moderator
Posts: 3169
Joined: Mon Aug 01, 2011 14:26
GitHub: Calinou
IRC: Calinou
In-game: Calinou
Location: Troyes, France
Contact:

Re: How to identify ground level (or treetop level)

by Calinou » Post

spillz wrote:I don't think he asked for style pointers. Sheesh. (And the engine is littered with camelCase last I checked)
Those are not supposed to be there (and are likely from external contributors). On the old wiki, celeron55 specifically wrote the variables should be like_this and not likeThis.

The default mods also use a similar variable styling.

If you want to continue the discussion, I suggest PMing me or creating a new topic. Let's stay on-topic here, thanks in advance. :)

dgm5555
Member
Posts: 245
Joined: Tue Apr 08, 2014 19:45

Re: How to identify ground level (or treetop level)

by dgm5555 » Post

sorry about the camel case, I picked it up many years ago as it was a little more concise, and found that trying to switch back and forth made my own code inconsistent, which was even worse than being different to the current flavour of the project, should it become critical I can easily change them all with a script.

The projects I'm working on which use ground level are mapping the world and placing random items and teleporting to locations without using pre-defined destinations. I'd also like to generate some buildings/features randomly, but don't want to do it in areas a player has already visited (like happen to me recently when something (paragenv7?) randomly decided to cover what was previously an empty patch of desert in jungle trees with a number of them floating above the ground). Ground level is my biggest frustration, but also I can't find any exposed functions which tell me if a block of nodes has been generated, or where the x and z boundaries of the currently generated world are, or force generation without a player trigger. Teleporting a player to an area either forces generation or loads the block (but I can't tell which, so don't know if I should put stuff there) and when this has completed enables me to find ground level. However as I mentioned moving the player around doesn't seem like a very elegant solution. Intuitively it feels like these basic functions would have been exposed, but I can't find them, so am trying to make what I can...
Last edited by dgm5555 on Tue May 13, 2014 18:50, edited 2 times in total.

Kodiologist
Member
Posts: 13
Joined: Fri Dec 27, 2013 18:06
Contact:

Re: How to identify ground level (or treetop level)

by Kodiologist » Post

See this thread for a previous discussion. But, as you can see, I ended up using the light level, too.

User avatar
HeroOfTheWinds
Member
Posts: 470
Joined: Wed Apr 23, 2014 23:16
GitHub: HeroOfTheWinds
IRC: WindHero
Location: Hawaii

Re: How to identify ground level (or treetop level)

by HeroOfTheWinds » Post

Unless you absolutely need to have this code occur in places before you get to them, I highly recommend using the minetest.register_on_generated() function. Then, whenever the player reaches a new chunk, it will call whatever code you have in that function. Now, as for finding ground level. One method is to use the voxelmanip to loop through xyz values from the top down, and upon finding a node ~= "air", call your ground level code. Take a look at paramat's highlandpools mod for an example of this.

I'd say this is the most balanced solution between elegance, speed, and control, but I could be wrong. There's no need to displace a player just to generate something ahead of time. That will only eat up hard drive space on servers where no one may ever even visit a chunk that was loaded for no good reason.
Nam ex spatio, omnes res venire possunt.
Why let the ground limit you when you can reach for the sky?
Back to college now, yay for sophomore year schedules. :P

User avatar
Topywo
Member
Posts: 1721
Joined: Fri May 18, 2012 20:27

Re: How to identify ground level (or treetop level)

by Topywo » Post

I don't know if this is of any use at all.

The ore generation in default/mapgen.lua gives the possibility to generate nodes you create at random positions, for which you can specifiy the height.

Example:

Code: Select all

minetest.register_ore({
	ore_type       = "scatter",
	ore            = "default:stone_with_coal",
	wherein        = "default:stone",
	clust_scarcity = 8*8*8,
	clust_num_ores = 8,
	clust_size     = 3,
	height_min     = -31000,
	height_max     = 64,
})
What you can do is something like this:

Code: Select all

minetest.register_ore({
	ore_type       = "scatter",
	ore            = "mymod:fakeairorwhatever",
	wherein        = "air",
	clust_scarcity = 8*8*8,
	clust_num_ores = 8,
	clust_size     = 3,
	height_min     = 0,
	height_max     = 1,
})

User avatar
paramat
Developer
Posts: 3700
Joined: Sun Oct 28, 2012 00:05
GitHub: paramat
IRC: paramat
Location: UK

Re: How to identify ground level (or treetop level)

by paramat » Post

It is possible to know ground level at any co-ordinate in advance of map generation, but i think the only way is to recreate the mapgen in lua. My 'spawn player' functions in watershed and fracture do this to spawn the player at the correct height to avoid burial or falling to death. But then it's easy for me to recreate my mapgen code within a function.
It would be good to recreate mgv6, useful for re-generating chunks too.

dgm5555
Member
Posts: 245
Joined: Tue Apr 08, 2014 19:45

Re: How to identify ground level (or treetop level)

by dgm5555 » Post

paramat wrote:It is possible to know ground level at any co-ordinate in advance of map generation, but i think the only way is to recreate the mapgen in lua.
This looks like a good method, actually if it's that simple it's even more surprising minetest doesn't expose the function, I guess I'd still have to check for trees etc, but at least I won't be starting far from ground. Does the mapgen version not have to be coded for?

dgm5555
Member
Posts: 245
Joined: Tue Apr 08, 2014 19:45

Re: How to identify ground level (or treetop level)

by dgm5555 » Post

I have tried lots of different methods, and it seems that there is no method to force the engine to load a block other than moving a player to the spot and leaving them there after the function exits.
I've tried light levels, loops, forceload, sleep commands, placing nodes, more loops, etc, etc...
This code seems to work best

Code: Select all

teleportTargetWuX = pngMinWuX + butX*worldStepWuX + 0.5*worldStepWuX
teleportTargetWuZ = pngMaxWuZ - butZ*worldStepWuZ - 0.5*worldStepWuZ
local groundLevel = nil
local i
for i = 96, 0, -1 do	
	p = {x=teleportTargetWuX, y=i, z=teleportTargetWuZ}
	player:setpos(p)

	if minetest.get_node(p).name ~= "air" and minetest.get_node(p).name ~= "ignore" then
		groundLevel = i
		break
	end
end
if groundLevel ~= nil then
	print("Mapit Teleport Successful")
	player:setpos({x=teleportTargetWuX, y=groundLevel, z=teleportTargetWuZ})
else
	-- minetest failed to load the block within the loop, and never seems to no matter how many loops are executed
	--   (even os.execute("sleep 10") doesn't give it time to do so)
	-- However completing the function and having the player re-activate it seems to trigger the engine to load properly
	-- Don't set player back to departure position, or the block will never be loaded
	minetest.chat_send_player(mapItPlayerName, "mapit: Aaarrrgh Teleport Mistargeted (Please Try Again)", false)
end

User avatar
BrandonReese
Member
Posts: 839
Joined: Wed Sep 12, 2012 00:44
GitHub: bremaweb
IRC: BrandonReese
In-game: BrandonReese
Location: USA

Re: How to identify ground level (or treetop level)

by BrandonReese » Post

I'm pretty sure you can force an area to load with voxelmanip. I've never used it before but I believe that's how the Technic quarries quarry down 100 nodes from the source without a player present. I think it will even force mapgen to run when you access an area of the map that hasn't been generated.

User avatar
Hybrid Dog
Member
Posts: 2836
Joined: Thu Nov 01, 2012 12:46
GitHub: HybridDog

Re: How to identify ground level (or treetop level)

by Hybrid Dog » Post

̣
Last edited by Hybrid Dog on Thu May 22, 2014 17:36, edited 1 time in total.

‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪

dgm5555
Member
Posts: 245
Joined: Tue Apr 08, 2014 19:45

Re: How to identify ground level (or treetop level)

by dgm5555 » Post

I tried forceload_block, it didn't seem to work while the call to the function was running even with long sleeps and/or loops to delay. might look at technic and try voxelmanip.

User avatar
Hybrid Dog
Member
Posts: 2836
Joined: Thu Nov 01, 2012 12:46
GitHub: HybridDog

Re: How to identify ground level (or treetop level)

by Hybrid Dog » Post

̣

‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪

dgm5555
Member
Posts: 245
Joined: Tue Apr 08, 2014 19:45

Re: How to identify ground level (or treetop level)

by dgm5555 » Post

voxel_manip seems to force the loading of the block, so a groundlevel search works. I've changed the code in the first post to provided the entire loop to find ground level...

Code: Select all

local manip = minetest.get_voxel_manip()
p = {x=targetX, y=i, z=targetZ}
manip:read_from_map(p, p)

Smitje
Member
Posts: 22
Joined: Wed Nov 14, 2012 20:42

Re: How to identify ground level (or treetop level)

by Smitje » Post

It depeds if you are using mapgen v6 or v7.

This is what I just learned from paramat:
by paramat » Mon Aug 18, 2014 6:49 am
https://github.com/minetest/minetest/bl ... .txt#L2126 line 2126
Not sure if all of these are available within mapgen v6, some may be v7 only.
I checked and the following only works in v7 not in v6:

Code: Select all

lastheightmap = minetest.get_mapgen_object("heightmap")
alternatively, mapgen.cpp uses a function that checks for the highest node that is walkable:
lines 921 to 937
perhaps this could be recreated in LUA

cheers,
Smitje

Smitje
Member
Posts: 22
Joined: Wed Nov 14, 2012 20:42

Re: How to identify ground level (or treetop level)

by Smitje » Post

Hi all,

I did a little hacking to make the groundlevel available in my own mod it may be usefull. see this thread:
viewtopic.php?f=7&t=9940

Cheers,
Smitje

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 31 guests