Voxelmanip Forums
foodyummy foodyummy
Posted on 2023-10-20 05:13 Link | ID: 719
back again after months of having completely forgotten about this site... regardless, here's something new from me :)

this thread I declare to be designated for my random minetest ideas, experiments and tech demos. after a long time away from minetest I decided to try my hand at it again to dust off my programming skills. we'll see how long this lasts... :P

I will keep all of you updated on my developments. here we go. here is the first experiment.

octahedron world

I have not yet begun actual development of this idea, although I would like to get a simple prototype working sometime in the following week. I think some simple Perlin noise and interpolation will do.

this is a proposed solution to the question of "simulating" a spherical planet in a minecraft-like voxel grid. I am not sure if anyone has actually asked that question (besides from me), but here it is nonetheless :LOL:

anyway: this solution is based on the premise that a sphere, the approximate shape of any real planet, can be split into two equal hemispheres. the below stock-free image explains this, using the Earth as an example:



here are top-down views of both of these hemispheres, centered on the poles:



(maybe you can already see where I'm going with this...? :D )

instead of generating one square map, we generate two, and assign each map to a hemisphere. We let their data rest side by side in the greater overall Minetest "map."



(pardon the crappy maps, I literally ripped them from a youtube thumbnail :LOL: )

So the center of each square sub-map will be the pole. Here we will find the arctic climates and biomes. The edges of each sub-map, then, becomes the equator, and the location of the tropics.

So our world isn't necessarily going to be a "sphere" ... sorry to let you down :( but we can go for the next best thing: an octahedron, the shape of a d8 dice.

we can pretend that we can "project" each square sub-map to the two halves of this octahedron, like so:



But all of this alone won't work. we need some extra systems in order to flesh out the simulation.

so how do we complete the illusion? one minetest mod has already figured it out: https://content.minetest.net/packages/Don/worldedge/ it detects when a player (or any entity, really) has walked past an arbitrary boundary, and warps them to the same position at the opposing boundary.

However, in our octahedron model, we wouldn't warp the players to the opposing boundary of the same hemisphere: rather, we warp them to the corresponding position of the other hemisphere, completing the illusion of travel.

so, from the player's perspective: if they travel in only one direction, they will "wrap around" from one hemisphere to the next in an infinite loop.



so the player's transition from one hemisphere to the next will be more or less seamless. but what about the hemispheres themselves? the natural terrain should match up between hemispheres.

it's simple: we interpolate the perlin noise used to generate each hemisphere so that it will generate the same terrain at the corresponding locations of the equator at each hemisphere.

does that make any sense? :LOL:

Limitations and faults of the model itself

of course there will be limitations... ¯\_(ツ)_/¯

one in particular is that this model assumes that the players won't have access to a large part of the world depth-wise. in order for the illusion to work effectively, there must be a relatively restricted underground and airspace. About the depth of the average minecraft world will do :)

in addition, the world is not a true sphere. It is an octahedron... of course, going for a true sphere is impossible without introducing severe distortion in the map voxel data, to the point where it's arguably unsuitable for a video game...

Minetest's implications on this model

minetest, the engine I will be working with, also introduces some snags along the way.

the first I can think of is what the players will see when they reach the boundary of a hemisphere (the "equator" of our imaginary octahedron planet).

due to the way that the hemispheres are stored in minetest's map data, across only one quarter of the equator should these hemispheres reliably match up: across the other three quarters, there will be a sharp cliff which must be walked over to teleport the players.

The only solution I can think of is to use VoxelManip to create copies of the hemisphere mapblocks, place them outside of the normal gameplay boundaries at the correct locations (please refer to the last image I posted) and update them periodically.

however, this may be intensive on the server and won't be a real-time accurate reflection of what's actually happening on the alternating hemispheres. so I'm kinda stumped on this one... :(

anyway, what do you think about all this? it's getting late and I'm kind of tired but I wanted to get this out before I forget about it.

are you confused? I am too. If you need me to clarify anything, just ask :LOL:
Compa Compa
please just get off the internet already jamie
Posted on 2023-10-21 19:46 Link | ID: 721
No joke this looks seriously interesting. I'd really like to see how this progresses, it could be a massive game changer.
ROllerozxa ROllerozxa
Site Admin
Posted on 2023-10-21 22:08 Link | ID: 724
Yes, looks quite interesting, I'm interested to see what this will become. :D
Compa Compa
please just get off the internet already jamie
Posted on 2023-10-21 22:54 (edited 2023-10-21 22:55) Link | ID: 727
Think he'll implement the industrial revolution and global warming into it? And perhaps even the concept of colonisation, monarchy, totalitarian states, Boris Johnson's voxel-defying face and parties... you know, to make a true Earth Simulator in Minetest...
foodyummy foodyummy
Posted on 2023-10-22 02:33 (edited 2023-10-23 07:27) Link | ID: 732
No joke this looks seriously interesting. I'd really like to see how this progresses, it could be a massive game changer.
Yes, looks quite interesting, I'm interested to see what this will become. :D
Think he'll implement the industrial revolution and global warming into it? And perhaps even the concept of colonisation, monarchy, totalitarian states, Boris Johnson's voxel-defying face and parties... you know, to make a true Earth Simulator in Minetest...
just you wait... :)

after a morning's worth of suffering I have managed this. the first build of MapLoopTest :D



just one hemisphere's worth of stone. I had to use an ugly hack to force minetest to generate only a limited section of terrain with user-set boundaries.

I know it's not much, but... I haven't done any proper programming in months... 8-) but everyone's gotta start somewhere... at least I'm doing something, though. hey, it's a start! :D

planned features that I'm mostly sure I can implement:
- creation of multiple planets on the fly, specifying the size and depth of their hemispheres, where in minetest's map they're stored, and planet-unique metadata
- keeping track of which players are on which planets, simple enough
- teleporting players across hemispheres when they cross the equator
- teleporting players between different planets
- choice of 1, 2 or 6 hemispheres for each planet (to support octahedron and cube planets and to appease the flat earthers 8-)
- simple map generation for each hemisphere using perlin noise
- seamless interpolation of that perlin noise across hemispheres to make the terrain match up, the more difficult part
- biome generation? colder biomes near the poles, warmer biomes near the equator? I have no idea how to do this, but it's here for completeness

and that'll be all for MapLoopTest, I think :)

anyway, I will keep you all updated on my progress. once I finish a prototype and get the license worked out, I'll post my code on github for roller to criticize 8-)
foodyummy foodyummy
Posted on 2023-10-23 08:44 (edited 2023-10-23 08:53) Link | ID: 733
here's another devlog, mostly just to complain about stuff ¯\_(ツ)_/¯

I'm deciding to hold off on hemispheres until I get some bugs under control. right now I'm focusing on just having Lua generate and handle multiple "subworlds" in a single minetest map. hemispheres will come when I'm ready for that :)

so, about those bugs: they cropped up in the middle of development, courtesy of minetest... :(

the biggest one in particular is that minetest's builtin perlin noise functions, as well as the entirety of VoxelManip, only work in a mapgen thread. considering that my demo revolves around being able to register and delete subworlds on the fly, this is going to be a problem...

the first issue was perlin noise, so let's start with that... I created a quick testing environment, ExtremeSimpleTest, and threw together some code in a single mod: https://pastebin.com/BsZzHhRL try it yourself! :D

now the official API documentation states that there are two methods to get a perlin noise generator: PerlinNoise() or minetest.get_perlin(). The sole difference is that minetest.get_perlin() adds the world's seed to its own provided seed.

I can only deduce it's the world seed feature of minetest.get_perlin() that causes it to crash... I mean, as far as I know, there's no other difference!

The solution was simple: replace minetest.get_perlin() with PerlinNoise(). it does mean I have to implement world seeds manually... although I'd probably have to do that with subworld mapgen anyway, so no loss :)

so by exploiting a small technicality, I was able to get perlin noise outside of a mapgen thread. however the next problem, voxelmanip, is still stumping me as of tonight: it seems that every time I call minetest.get_voxel_manip() or VoxelManip() outside of a mapgen thread, it returns nil.

so I looked through minetest's github repo. In particular I looked through minetest/src/script/lua_api/l_vmanip.cpp and I think I have found the culprit, starting at line 367:

LuaVoxelManip::~LuaVoxelManip()
{
if (!is_mapgen_vm)
delete vm;
}

check it out for yourself... https://github.com/minetest/minetest/blob/master/src/script/lua_api/l_vmanip.cpp#L367-L371

I don't fully understand c++ yet, but it seems here this function detects if the voxelmanip is in a mapgen thread or not and deletes the voxelmanip if it isn't. given that it was explicitly written like this, it has to be intentional, for reasons I don't know...

but maybe you can see how this is gonna be a huge problem for me? perlin noise works fine outside of a mapgen thread, but it's completely useless without voxelmanip... and what alternatives are there? minetest.set_node is way too slow for mapgen...

in addition to all of this, I was thinking about system a bit more last night, and some questions arose...

Some other questions I have about this tech demo
- how will fluid nodes be able to flow across the boundaries between hemispheres?
- how will any type of node be able to pass data from one hemisphere to the other?
- perlin noise can be interpolated across hemispheres, but what about the rest of mapgen? decorations, structures? how will things like trees and mineshafts be handled across boundaries?
- gravity. I'm so dumb. I just realized that my entire octahedron model doesn't account for physically correct gravity. In my current model, gravity can only work in two directions (along the planetoid's poles) but that's not how actual gravity works. Real gravity works in spheres, right? I mean, I know it's all just a simulation and an illusion and all, but still...

the only solution I can think of is, well... to manually make my own systems for all these. and while I'm sure it's all technically possible, I'm just concerned about how computationally expensive it'll be.

scientifically correct gravity, in particular, will require implementing my own realtime physics system and I don't know what kind of toll that'll take on a minetest server...

anyway, that's all for tonight. what do you think? :)
ROllerozxa ROllerozxa
Site Admin
Posted on 2023-10-23 17:30 Link | ID: 734
Nice that you've got something up and working now, that's something at least. :)

so by exploiting a small technicality, I was able to get perlin noise outside of a mapgen thread. however the next problem, voxelmanip, is still stumping me as of tonight: it seems that every time I call minetest.get_voxel_manip() or VoxelManip() outside of a mapgen thread, it returns nil.
Huh? It should be possible to create a VoxelManip object outside of minetest.on_generated by using minetest.get_voxel_manip. Make sure you pass two arguments to the function, two corner positions which define the cuboid it will load from the map to allow for bulk manipulation. It will then return a VoxelManip object along with the minimum and the maximum emerge position, just like the VoxelManip mapgen object.

so I looked through minetest's github repo. In particular I looked through minetest/src/script/lua_api/l_vmanip.cpp and I think I have found the culprit, starting at line 367:

LuaVoxelManip::~LuaVoxelManip()
{
if (!is_mapgen_vm)
delete vm;
}

check it out for yourself... https://github.com/minetest/minetest/blob/master/src/script/lua_api/l_vmanip.cpp#L367-L371

I don't fully understand c++ yet, but it seems here this function detects if the voxelmanip is in a mapgen thread or not and deletes the voxelmanip if it isn't. given that it was explicitly written like this, it has to be intentional, for reasons I don't know...
That's a destructor method for LuaVoxelManip (notice the tilde in the method name), which is called when a LuaVoxelManip object is deleted in C++.

I assume the mapgen LuaVoxelManip object's vm variable is not deleted because the engine's C++ mapgen code wants to keep that MMVManip object (the underlying C++ implementation for voxel manipulation) around for its own use. Meanwhile if you're creating your own VoxelManip object from Lua and it gets garbage collected, it can be safely destroyed so as to not leak memory. But I don't think that's related to the issues you had trying to obtain a VoxelManip object.
foodyummy foodyummy
Posted on 2023-10-23 21:45 Link | ID: 735
That's a destructor method for LuaVoxelManip (notice the tilde in the method name), which is called when a LuaVoxelManip object is deleted in C++.
whoops... well, I did say I'm not too familiar with c++... :LOL:
Huh? It should be possible to create a VoxelManip object outside of minetest.on_generated by using minetest.get_voxel_manip. Make sure you pass two arguments to the function, two corner positions which define the cuboid it will load from the map to allow for bulk manipulation. It will then return a VoxelManip object along with the minimum and the maximum emerge position, just like the VoxelManip mapgen object.
so I tried following your exact advice... I backed up the code and stripped it down to just the following:

local minp = {x = -8, y = -8, z = -8}
local maxp = {x = 8, y = 8, z = 8}

local vm1, emin1, emax1 = minetest.get_voxel_manip(minp, maxp)
minetest.log(tostring(vm1))

local vm2, emin2, emax2 = VoxelManip(minp, maxp)
minetest.log(tostring(vm2))

this is literally the only Lua code that's being run in the game... I tried calling both methods, outside of a mapgen thread, as plainly as possible.

here's the output from ~/.minetest/debug.txt:

2023-10-23 13:39:49: [Main]: Automatically selecting world at [~/.minetest/worlds/world1]
2023-10-23 13:39:59: [Main]: nil
2023-10-23 13:39:59: [Main]: nil
2023-10-23 13:39:59: ACTION[Main]: World at [~/.minetest/worlds/world1]
2023-10-23 13:39:59: ACTION[Main]: Server for gameid="extremesimpletest" listening on 0.0.0.0:52717.
2023-10-23 13:40:00: ACTION[Server]: singleplayer [127.0.0.1] joins game. List of players: singleplayer
2023-10-23 13:40:01: ACTION[Main]: Server: Shutting down

minetest.log simply prints nil, and any attempt to call the VM's methods results in a crash: attempt to index local 'vm1' (a nil value)

I don't really know what else to do... this is as plain and simple as it gets. both methods return nil :( I'm not sure if this is a bug or if it's intentional. The API documentation doesn't mention anywhere that voxelmanips can only be used in a mapgen thread, so it seems like a bug to me? I'm not a coredev so I can't be sure...

it seems my only alternative is to think inside the box :LOL: and try to hijack minetest's on_generated function... write my own function for managing the generation of each subworld... use emerge_area and delete_area to generate subworlds at will...

I mean, it all seems like a big hack to me, but if it's the only way to do it then I'll try it ¯\_(ツ)_/¯