Page 1 of 1
How to identify ground level (or treetop level)

Posted:
Mon May 12, 2014 23:18
by dgm5555
EDIT: The following code seems to work correctly:-
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- 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.
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- 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)
Re: How to identify ground level (or treetop level)

Posted:
Tue May 13, 2014 12:28
by Calinou
I can't help much, but for consistency, variables should be like_this, not likeThis.
Re: How to identify ground level (or treetop level)

Posted:
Tue May 13, 2014 12:36
by Evergreen
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
Re: How to identify ground level (or treetop level)

Posted:
Tue May 13, 2014 13:00
by spillz
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)
Re: How to identify ground level (or treetop level)

Posted:
Tue May 13, 2014 13:39
by Calinou
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. :)
Re: How to identify ground level (or treetop level)

Posted:
Tue May 13, 2014 14:23
by dgm5555
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...
Re: How to identify ground level (or treetop level)

Posted:
Tue May 13, 2014 15:31
by Kodiologist
See this thread for a previous discussion. But, as you can see, I ended up using the light level, too.
Re: How to identify ground level (or treetop level)

Posted:
Tue May 13, 2014 20:40
by HeroOfTheWinds
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.
Re: How to identify ground level (or treetop level)

Posted:
Wed May 14, 2014 09:28
by Topywo
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:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- 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:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- 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,
})
Re: How to identify ground level (or treetop level)

Posted:
Wed May 14, 2014 22:07
by paramat
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.
Re: How to identify ground level (or treetop level)

Posted:
Wed May 14, 2014 22:50
by dgm5555
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?
Re: How to identify ground level (or treetop level)

Posted:
Sat May 17, 2014 08:46
by dgm5555
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
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- 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
Re: How to identify ground level (or treetop level)

Posted:
Sat May 17, 2014 14:30
by BrandonReese
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.
Re: How to identify ground level (or treetop level)

Posted:
Sat May 17, 2014 15:01
by Hybrid Dog
̣
Re: How to identify ground level (or treetop level)

Posted:
Sun May 18, 2014 09:31
by dgm5555
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.
Re: How to identify ground level (or treetop level)

Posted:
Sun May 18, 2014 13:35
by Hybrid Dog
̣
Re: How to identify ground level (or treetop level)

Posted:
Thu May 22, 2014 19:18
by dgm5555
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...
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
local manip = minetest.get_voxel_manip()
p = {x=targetX, y=i, z=targetZ}
manip:read_from_map(p, p)
Re: How to identify ground level (or treetop level)

Posted:
Mon Aug 18, 2014 18:45
by Smitje
It depeds if you are using mapgen v6 or v7.
This is what I just learned from paramat:
I checked and the following only works in v7 not in v6:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- 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
Re: How to identify ground level (or treetop level)

Posted:
Sat Sep 06, 2014 21:25
by Smitje
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=9940Cheers,
Smitje