forked from MineClone5/MineClone5
Compare commits
47 Commits
master
...
mapgen_iss
Author | SHA1 | Date |
---|---|---|
kay27 | 16116df4c6 | |
kay27 | 667ebf1385 | |
kay27 | da8e92e071 | |
kay27 | 7868cf7dc5 | |
kay27 | 726159e796 | |
kay27 | 54adfe9e30 | |
kay27 | 806edcda19 | |
kay27 | 6c1d30a130 | |
kay27 | 4ce3102ab4 | |
kay27 | b703dbc288 | |
kay27 | 05f1614893 | |
kay27 | 91fd78f38f | |
kay27 | bcb93fb49c | |
kay27 | 72e88f1980 | |
kay27 | e226d6ce45 | |
kay27 | 67248afe58 | |
kay27 | 2f8e30b1bb | |
kay27 | 1d1378197b | |
kay27 | 9d383560be | |
kay27 | 5dfc0ac9b5 | |
kay27 | b70859e185 | |
kay27 | 279b1b09cd | |
kay27 | 3bd1a6f89e | |
kay27 | e529c4839a | |
kay27 | ce6f5b0ee1 | |
NO11 | 135c8ece41 | |
kay27 | 2272753652 | |
kay27 | 2fda0f2644 | |
kay27 | 9e3c2fe21e | |
kay27 | 66d1172852 | |
kay27 | 8a53d24fa7 | |
kay27 | 16700632af | |
kay27 | 238eb6cb68 | |
kay27 | fd56bb746c | |
kay27 | f4a28cfab0 | |
kay27 | f38c8daab7 | |
kay27 | b12367b500 | |
kay27 | d60e0d75b4 | |
kay27 | 3c5bf8c9b2 | |
kay27 | c23bb1d59d | |
kay27 | 29727136ac | |
kay27 | 3f20d8c1f0 | |
kay27 | 269e560db1 | |
kay27 | 3732097ed6 | |
kay27 | 942d70ee62 | |
kay27 | abc3a1f139 | |
kay27 | 49ac211f87 |
|
@ -27,11 +27,17 @@ movement_gravity = 10.4
|
|||
|
||||
# Mapgen stuff
|
||||
|
||||
max_block_generate_distance = 13
|
||||
|
||||
# altitude_chill and altitude_dry doesn't go well together with MCL2 biomes
|
||||
# which already include "snowed" variants as you go higher.
|
||||
# humid_rivers would cause the MushroomIsland biome to appear frequently around rivers.
|
||||
mgvalleys_spflags = noaltitude_chill,noaltitude_dry,nohumid_rivers,vary_river_depth
|
||||
|
||||
# From how far blocks are generated for clients, stated in mapblocks (16 nodes).
|
||||
# Probably values >10 won't work because of numerous overridings. Type: int.
|
||||
max_block_generate_distance = 13
|
||||
|
||||
# MCL2-specific stuff
|
||||
keepInventory = false
|
||||
|
||||
|
|
|
@ -24,240 +24,9 @@ mcl_vars.inventory_header = ""
|
|||
-- Tool wield size
|
||||
mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 }
|
||||
|
||||
-- Mapgen variables
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local minecraft_height_limit = 256
|
||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
local singlenode = mg_name == "singlenode"
|
||||
|
||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16)
|
||||
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000)
|
||||
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
||||
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
|
||||
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
||||
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
|
||||
|
||||
local function coordinate_to_block(x)
|
||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||
end
|
||||
|
||||
local function coordinate_to_chunk(x)
|
||||
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_vars.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
if not superflat and not singlenode then
|
||||
-- Normal mode
|
||||
--[[ Realm stacking (h is for height)
|
||||
- Overworld (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Realm Barrier (h=11), to allow escaping the End
|
||||
- End (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Nether (h=128)
|
||||
- Void (h>=1000)
|
||||
]]
|
||||
|
||||
-- Overworld
|
||||
mcl_vars.mg_overworld_min = -62
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min + 4
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min + 10
|
||||
mcl_vars.mg_lava = true
|
||||
mcl_vars.mg_bedrock_is_rough = true
|
||||
|
||||
elseif singlenode then
|
||||
mcl_vars.mg_overworld_min = -66
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||
mcl_vars.mg_lava = false
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_is_rough = false
|
||||
else
|
||||
-- Classic superflat
|
||||
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
||||
ground = tonumber(ground)
|
||||
if not ground then
|
||||
ground = 8
|
||||
end
|
||||
mcl_vars.mg_overworld_min = ground - 3
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||
mcl_vars.mg_lava = false
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_is_rough = false
|
||||
end
|
||||
|
||||
mcl_vars.mg_overworld_max = mcl_vars.mapgen_edge_max
|
||||
|
||||
-- The Nether (around Y = -29000)
|
||||
mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border
|
||||
mcl_vars.mg_nether_max = mcl_vars.mg_nether_min + 128
|
||||
mcl_vars.mg_bedrock_nether_bottom_min = mcl_vars.mg_nether_min
|
||||
mcl_vars.mg_bedrock_nether_top_max = mcl_vars.mg_nether_max
|
||||
if not superflat then
|
||||
mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + 4
|
||||
mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - 4
|
||||
mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 31
|
||||
else
|
||||
-- Thin bedrock in classic superflat mapgen
|
||||
mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min
|
||||
mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max
|
||||
mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 2
|
||||
end
|
||||
if mg_name == "flat" then
|
||||
if superflat then
|
||||
mcl_vars.mg_flat_nether_floor = mcl_vars.mg_bedrock_nether_bottom_max + 4
|
||||
mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_bedrock_nether_bottom_max + 52
|
||||
else
|
||||
mcl_vars.mg_flat_nether_floor = mcl_vars.mg_lava_nether_max + 4
|
||||
mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_lava_nether_max + 52
|
||||
end
|
||||
end
|
||||
|
||||
-- The End (surface at ca. Y = -27000)
|
||||
mcl_vars.mg_end_min = -27073 -- Carefully chosen to be at a mapchunk border
|
||||
mcl_vars.mg_end_max_official = mcl_vars.mg_end_min + minecraft_height_limit
|
||||
mcl_vars.mg_end_max = mcl_vars.mg_overworld_min - 2000
|
||||
mcl_vars.mg_end_platform_pos = { x = 100, y = mcl_vars.mg_end_min + 74, z = 0 }
|
||||
|
||||
-- Realm barrier used to safely separate the End from the void below the Overworld
|
||||
mcl_vars.mg_realm_barrier_overworld_end_max = mcl_vars.mg_end_max
|
||||
mcl_vars.mg_realm_barrier_overworld_end_min = mcl_vars.mg_end_max - 11
|
||||
|
||||
-- Use MineClone 5-style dungeons
|
||||
mcl_vars.mg_dungeons = true
|
||||
|
||||
-- Set default stack sizes
|
||||
minetest.nodedef_default.stack_max = 64
|
||||
minetest.craftitemdef_default.stack_max = 64
|
||||
|
||||
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||
math.randomseed(os.time())
|
||||
|
||||
local chunks = {} -- intervals of chunks generated
|
||||
function mcl_vars.add_chunk(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local prev
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then -- we've found it
|
||||
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
||||
if n == d[1]-1 then -- right before:
|
||||
if prev and (prev[2] == n-1) then
|
||||
prev[2] = d[2]
|
||||
table.remove(chunks, i)
|
||||
return
|
||||
end
|
||||
d[1] = n
|
||||
return
|
||||
end
|
||||
if prev and (prev[2] == n-1) then --join to previous
|
||||
prev[2] = n
|
||||
return
|
||||
end
|
||||
table.insert(chunks, i, {n, n}) -- insert new interval before i
|
||||
return
|
||||
end
|
||||
prev = d
|
||||
end
|
||||
chunks[#chunks+1] = {n, n}
|
||||
end
|
||||
function mcl_vars.is_generated(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then
|
||||
return (n >= d[1])
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||
-- p: Position, if it's wrong, {name="error"} node will return.
|
||||
-- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
|
||||
-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
|
||||
--
|
||||
-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
|
||||
function mcl_vars.get_node(p, force, us_timeout)
|
||||
-- check initial circumstances
|
||||
if not p or not p.x or not p.y or not p.z then return {name="error"} end
|
||||
|
||||
-- try common way
|
||||
local node = minetest.get_node(p)
|
||||
if node.name ~= "ignore" then
|
||||
return node
|
||||
end
|
||||
|
||||
-- copy table to get sure it won't changed by other threads
|
||||
local pos = {x=p.x,y=p.y,z=p.z}
|
||||
|
||||
-- try LVM
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" or not force then
|
||||
return node
|
||||
end
|
||||
|
||||
-- all ways failed - need to emerge (or forceload if generated)
|
||||
local us_timeout = us_timeout or 244
|
||||
if mcl_vars.is_generated(pos) then
|
||||
minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!")
|
||||
minetest.forceload_block(pos)
|
||||
else
|
||||
minetest.emerge_area(pos, pos)
|
||||
end
|
||||
|
||||
local t = minetest.get_us_time()
|
||||
|
||||
node = minetest.get_node(pos)
|
||||
|
||||
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
|
||||
return node
|
||||
-- it still can return "ignore", LOL, even if force = true, but only after time out
|
||||
end
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
# mcl_mapgen
|
||||
============
|
||||
Helps to avoid problems caused by 'chunk-in-shell' feature of mapgen.cpp.
|
||||
It also queues your generators to run them in proper order:
|
||||
|
||||
### mcl_mapgen.register_on_generated(lvm_callback_function, order_number)
|
||||
=========================================================================
|
||||
Replacement of engine API function `minetest.register_on_generated(function(vm_context))`
|
||||
It is still unsafe. Cavegen part can and will overwrite outer 1-block layer of the chunk which is expected to be generated.
|
||||
Nodes marked as `is_ground_content` could be overwritten. Air and water are usually 'ground content' too.
|
||||
For Minetest 5.4 it doesn't recommended to place blocks within lvm callback function.
|
||||
See https://git.minetest.land/MineClone2/MineClone2/issues/1395
|
||||
`lvm_callback_function`: chunk callback LVM function definition:
|
||||
`function(vm_context)`:
|
||||
`vm_context` will pass into next lvm callback function from the queue!
|
||||
`vm_context`: a table which already contains some LVM data as the fields, and some of them can be added in your lvm callback function:
|
||||
`vm`: curent voxel manipulator object itself;
|
||||
`blockseed`: seed of this mapchunk;
|
||||
`minp` & `maxp`: minimum and maximum chunk position;
|
||||
`emin` & `emax`: minimum and maximum chunk position WITH SHELL AROUND IT;
|
||||
`area`: voxel area, can be helpful to access data;
|
||||
`data`: LVM buffer data array, data loads into it before the callbacks;
|
||||
`write`: set it to true in your lvm callback functionm, if you changed `data` and want to write it;
|
||||
`data2`: LVM buffer data array of `param2`, !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - you load it yourself:
|
||||
`vm_context.data2 = vm_context.data2 or vm_context.vm.get_param2_data(vm_context.lvm_param2_buffer)`
|
||||
`write_param2`: set it to true in your lvm callback function, if you used `data2` and want to write it;
|
||||
`light`: LVM buffer data array of light, !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - you load it yourself:
|
||||
`vm_context.light = vm_context.light or vm_context.vm.get_light2_data(vm_context.lvm_light_buffer)`
|
||||
`write_light`: set it to true in your lvm callback function, if you used `light` and want to write it;
|
||||
`lvm_param2_buffer`: static `param2` buffer pointer, used to load `data2` array;
|
||||
`shadow`: set it to false to disable shadow propagation;
|
||||
`heightmap`: mapgen object contanting y coordinates of ground level,
|
||||
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself:
|
||||
`vm_context.heightmap = vm_context.heightmap or minetest.get_mapgen_object('heightmap')`
|
||||
`biomemap`: mapgen object contanting biome IDs of nodes,
|
||||
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself:
|
||||
`vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object('biomemap')`
|
||||
`heatmap`: mapgen object contanting temperature values of nodes,
|
||||
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself:
|
||||
`vm_context.heatmap = vm_context.heatmap or minetest.get_mapgen_object('heatmap')`
|
||||
`humiditymap`: mapgen object contanting humidity values of nodes,
|
||||
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself:
|
||||
`vm_context.humiditymap = vm_context.humiditymap or minetest.get_mapgen_object('humiditymap')`
|
||||
`gennotify`: mapgen object contanting mapping table of structures, see Minetest Lua API for explanation,
|
||||
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself:
|
||||
`vm_context.gennotify = vm_context.gennotify or minetest.get_mapgen_object('gennotify')`
|
||||
`order_number` (optional): the less, the earlier,
|
||||
e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen_block_lvm(lvm_callback_function, order_number)
|
||||
=============================================================================
|
||||
Registers lvm callback function to be called when current block (usually 16x16x16 nodes) generation is REALLY 100% finished.
|
||||
`vm_context` passes into lvm callback function.
|
||||
`lvm_callback_function`: the block callback LVM function definition - same as for chunks - see definition example above;
|
||||
`order_number` (optional): the less, the earlier,
|
||||
e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen_block(node_callback_function, order_number)
|
||||
==========================================================================
|
||||
Registers node_callback function to be called when current block (usually 16x16x16 nodes) generation is REALLY 100% finished.
|
||||
`node_callback_function`: node callback function definition:
|
||||
`function(minp, maxp, seed)`:
|
||||
`minp` & `maxp`: minimum and maximum block position;
|
||||
`seed`: seed of this mapblock;
|
||||
`order_number` (optional): the less, the earlier,
|
||||
e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen(callback_function, order_number)
|
||||
====================================================================
|
||||
Registers callback function to be called when current chunk generation is REALLY 100% finished.
|
||||
For LVM it's the most frustrating function from this mod.
|
||||
It can't provide you access to mapgen objects. They are probably gone long ago.
|
||||
Don't use it for accessing mapgen objects please.
|
||||
To use VM you have to run `vm_context.vm = minetest.get_voxel_manip(vm_context.emin, vm_context.emax)`.
|
||||
Set
|
||||
`callback_function`: callback function definition:
|
||||
`function(minp, maxp, seed, vm_context)`:
|
||||
`minp` & `maxp`: minimum and maximum block position;
|
||||
`seed`: seed of this mapblock;
|
||||
`vm_context`: a table - see description above.
|
||||
`order_number` (optional): the less, the earlier.
|
||||
|
||||
### mcl_mapgen.register_mapgen_lvm(lvm_callback_function, order_number)
|
||||
=======================================================================
|
||||
Registers lvm callback function to be called when current chunk generation is REALLY 100% finished.
|
||||
It's the most frustrating function from this mod. It can't provide you access to mapgen objects. They are probably gone long ago.
|
||||
Don't use it for accessing mapgen objects please.
|
||||
`vm_context` passes into lvm callback function.
|
||||
`lvm_callback_function`: the block callback LVM function definition - same as above;
|
||||
`order_number` (optional): the less, the earlier.
|
||||
|
||||
### mcl_mapgen.get_far_node(pos)
|
||||
================================
|
||||
Returns node if it is generated, otherwise returns `{name = "ignore"}`.
|
||||
|
||||
## Constants:
|
||||
|
||||
* `mcl_mapgen.EDGE_MIN`, `mcl_mapgen.EDGE_MAX` - world edges, min & max.
|
||||
* `mcl_mapgen.seed`, `mcl_mapgen.name` - mapgen seed & name.
|
||||
* `mcl_mapgen.v6`, `mcl_mapgen.superflat`, `mcl_mapgen.singlenode` - is mapgen v6, superflat, singlenode.
|
||||
* `mcl_mapgen.normal` is mapgen normal (not superflat or singlenode).
|
|
@ -0,0 +1,465 @@
|
|||
mcl_mapgen = {}
|
||||
|
||||
local order = { -- mcl_mapgen.order...
|
||||
DEFAULT = 5000,
|
||||
CHORUS = 100000,
|
||||
BUILDINGS = 200000,
|
||||
VILLAGES = 900000,
|
||||
DUNGEONS = 950000,
|
||||
STRONGHOLDS = 999999,
|
||||
OCEAN_MONUMENT = 1000000,
|
||||
LARGE_BUILDINGS = 2000000,
|
||||
}
|
||||
|
||||
local math_floor = math.floor
|
||||
local math_max = math.max
|
||||
local minetest_get_node = minetest.get_node
|
||||
local minetest_get_voxel_manip = minetest.get_voxel_manip
|
||||
local minetest_log = minetest.log
|
||||
local minetest_pos_to_string = minetest.pos_to_string
|
||||
|
||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||
mcl_mapgen.CS = math_max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
mcl_mapgen.BS = math_max(1, core.MAP_BLOCKSIZE or 16)
|
||||
mcl_mapgen.LIMIT = math_max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_mapgen.MAX_LIMIT = math_max(1, core.MAX_MAP_GENERATION_LIMIT or 31000) -- might be set to 31000 or removed, see https://github.com/minetest/minetest/issues/10428
|
||||
mcl_mapgen.OFFSET = - math_floor(mcl_mapgen.CS / 2)
|
||||
mcl_mapgen.OFFSET_NODES = mcl_mapgen.OFFSET * mcl_mapgen.BS
|
||||
mcl_mapgen.CS_NODES = mcl_mapgen.CS * mcl_mapgen.BS
|
||||
|
||||
local central_chunk_min_pos = mcl_mapgen.OFFSET * mcl_mapgen.BS
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_mapgen.CS_NODES - 1
|
||||
|
||||
local ccfmin = central_chunk_min_pos - mcl_mapgen.BS -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_mapgen.BS
|
||||
|
||||
local mapgen_limit_b = math_floor(math.min(mcl_mapgen.LIMIT, mcl_mapgen.MAX_LIMIT) / mcl_mapgen.BS)
|
||||
local mapgen_limit_min = - mapgen_limit_b * mcl_mapgen.BS
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_mapgen.BS - 1
|
||||
|
||||
local numcmin = math_max(math_floor((ccfmin - mapgen_limit_min) / mcl_mapgen.CS_NODES), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math_max(math_floor((mapgen_limit_max - ccfmax) / mcl_mapgen.CS_NODES), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
|
||||
mcl_mapgen.EDGE_MIN = central_chunk_min_pos - numcmin * mcl_mapgen.CS_NODES
|
||||
mcl_mapgen.EDGE_MAX = central_chunk_max_pos + numcmax * mcl_mapgen.CS_NODES
|
||||
|
||||
minetest_log("action", "[mcl_mapgen] World edges: mcl_mapgen.EDGE_MIN = " .. tostring(mcl_mapgen.EDGE_MIN) .. ", mcl_mapgen.EDGE_MAX = " .. tostring(mcl_mapgen.EDGE_MAX))
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Mapgen variables
|
||||
local overworld, end_, nether = {}, {}, {}
|
||||
local seed = minetest.get_mapgen_setting("seed")
|
||||
mcl_mapgen.seed = seed
|
||||
mcl_mapgen.name = minetest.get_mapgen_setting("mg_name")
|
||||
mcl_mapgen.v6 = mcl_mapgen.name == "v6"
|
||||
mcl_mapgen.superflat = mcl_mapgen.name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
mcl_mapgen.singlenode = mcl_mapgen.name == "singlenode"
|
||||
mcl_mapgen.normal = not mcl_mapgen.superflat and not mcl_mapgen.singlenode
|
||||
local superflat, singlenode, normal = mcl_mapgen.superflat, mcl_mapgen.singlenode, mcl_mapgen.normal
|
||||
|
||||
minetest_log("action", "[mcl_mapgen] Mapgen mode: " .. (normal and "normal" or (superflat and "superflat" or "singlenode")))
|
||||
----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Generator queues
|
||||
local queue_unsafe_engine = {}
|
||||
local queue_chunks_nodes = {}
|
||||
local queue_chunks_lvm = {}
|
||||
local queue_blocks_nodes = {}
|
||||
local queue_blocks_lvm = {}
|
||||
|
||||
-- Requirements. 0 means 'none', greater than 0 means 'required'
|
||||
local block = 0
|
||||
local queue_blocks_lvm_counter = 0
|
||||
local lvm_chunk = 0
|
||||
local param2 = 0
|
||||
local nodes_block = 0
|
||||
local nodes_chunk = 0
|
||||
local safe_functions = 0
|
||||
|
||||
local BS, CS = mcl_mapgen.BS, mcl_mapgen.CS -- Mapblock size (in nodes), Mapchunk size (in blocks)
|
||||
local LAST_BLOCK, LAST_NODE = CS - 1, BS - 1 -- First mapblock in chunk (node in mapblock) has number 0, last has THIS number. It's for runtime optimization
|
||||
local offset = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks)
|
||||
local CS_NODES = mcl_mapgen.CS_NODES -- 80
|
||||
|
||||
local CS_3D = CS * CS * CS
|
||||
|
||||
local DEFAULT_ORDER = order.DEFAULT
|
||||
|
||||
function mcl_mapgen.register_on_generated(callback_function, order)
|
||||
queue_unsafe_engine[#queue_unsafe_engine+1] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_unsafe_engine, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen(callback_function, order)
|
||||
nodes_chunk = nodes_chunk + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_chunks_nodes[nodes_chunk] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_chunks_nodes, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_lvm(callback_function, order)
|
||||
lvm_chunk = lvm_chunk + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_chunks_lvm[lvm_chunk] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_chunks_lvm, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_block(callback_function, order)
|
||||
block = block + 1
|
||||
nodes_block = nodes_block + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_blocks_nodes[nodes_block] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_blocks_nodes, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_block_lvm(callback_function, order)
|
||||
block = block + 1
|
||||
queue_blocks_lvm_counter = queue_blocks_lvm_counter + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_blocks_lvm[queue_blocks_lvm_counter] = {order = order or DEFAULT_ORDER, callback_function = callback_function}
|
||||
table.sort(queue_blocks_lvm, function(a, b) return (a.order <= b.order) end)
|
||||
end
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
local blocks = minetest.deserialize(storage:get_string("mapgen_blocks") or "return {}") or {}
|
||||
local chunks = minetest.deserialize(storage:get_string("mapgen_chunks") or "return {}") or {}
|
||||
minetest.register_on_shutdown(function()
|
||||
storage:set_string("mapgen_chunks", minetest.serialize(chunks))
|
||||
storage:set_string("mapgen_blocks", minetest.serialize(blocks))
|
||||
end)
|
||||
|
||||
local vm_context -- here will be many references and flags, like: param2, light_data, heightmap, biomemap, heatmap, humiditymap, gennotify, write_lvm, write_param2, shadow
|
||||
local data, data2, light, area
|
||||
local current_blocks = {}
|
||||
local current_chunks = {}
|
||||
local lvm_buffer, lvm_param2_buffer, lvm_light_buffer = {}, {}, {} -- Static buffer pointers
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, chunkseed)
|
||||
local minp, maxp, chunkseed = minp, maxp, chunkseed
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
minetest_log("warning", "[mcl_mapgen] New_chunk=" .. minetest_pos_to_string(minp) .. "..." .. minetest_pos_to_string(maxp) .. ", shell=" .. minetest_pos_to_string(emin) .. "..." .. minetest_pos_to_string(emax) .. ", chunkseed=" .. tostring(chunkseed))
|
||||
|
||||
data = vm:get_data(lvm_buffer)
|
||||
area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
|
||||
vm_context = {
|
||||
data = data,
|
||||
data2 = data2,
|
||||
light = light,
|
||||
area = area,
|
||||
lvm_buffer = lvm_buffer,
|
||||
lvm_param2_buffer = lvm_param2_buffer,
|
||||
lvm_light_buffer = lvm_light_buffer,
|
||||
vm = vm,
|
||||
emin = emin,
|
||||
emax = emax,
|
||||
minp = minp,
|
||||
maxp = maxp,
|
||||
chunkseed = chunkseed,
|
||||
}
|
||||
|
||||
if safe_functions > 0 then
|
||||
local x0, y0, z0 = minp.x, minp.y, minp.z
|
||||
local bx0, by0, bz0 = math_floor(x0/BS), math_floor(y0/BS), math_floor(z0/BS)
|
||||
local bx1, by1, bz1 = bx0 + LAST_BLOCK, by0 + LAST_BLOCK, bz0 + LAST_BLOCK -- only for entire chunk check
|
||||
|
||||
-- Keep `chunkseed` in `chunks[cx][cy][cz].seed` for further safe usage:
|
||||
local cx0, cy0, cz0 = math_floor((bx0-offset)/CS), math_floor((by0-offset)/CS), math_floor((bz0-offset)/CS)
|
||||
if not chunks[cx0] then chunks[cx0] = {} end
|
||||
if not chunks[cx0][cy0] then chunks[cx0][cy0] = {} end
|
||||
if not chunks[cx0][cy0][cz0] then
|
||||
chunks[cx0][cy0][cz0] = {seed = chunkseed, counter = 0}
|
||||
else
|
||||
chunks[cx0][cy0][cz0].seed = chunkseed
|
||||
end
|
||||
|
||||
local x1, y1, z1, x2, y2, z2 = emin.x, emin.y, emin.z, emax.x, emax.y, emax.z
|
||||
local x, y, z = x1, y1, z1 -- iterate 7x7x7 mapchunk, {x,y,z} - first node pos. of mapblock
|
||||
local bx, by, bz -- block coords (in blocs)
|
||||
local box, boy, boz -- block offsets in chunks (in blocks)
|
||||
while x < x2 do
|
||||
bx = math_floor(x/BS)
|
||||
local block_pos_offset_removed = bx - offset
|
||||
local cx = math_floor(block_pos_offset_removed / CS)
|
||||
box = block_pos_offset_removed % CS
|
||||
if not blocks[bx] then blocks[bx]={} end
|
||||
|
||||
-- We don't know how many calls, including this one, will overwrite this block content!
|
||||
-- Start calculating it with `total_mapgen_block_writes_through_x` variable.
|
||||
-- It can be `8 or less`, if we (speaking of `x` axis) are on chunk edge now,
|
||||
-- or it can be `4 or less` - if we are in the middle of the chunk by `x` axis:
|
||||
|
||||
local total_mapgen_block_writes_through_x = (box > 0 and box < LAST_BLOCK) and 4 or 8
|
||||
while y < y2 do
|
||||
by = math_floor(y/BS)
|
||||
block_pos_offset_removed = by - offset
|
||||
local cy = math_floor(block_pos_offset_removed / CS)
|
||||
boy = block_pos_offset_removed % CS
|
||||
if not blocks[bx][by] then blocks[bx][by]={} end
|
||||
|
||||
-- Here we just divide `total_mapgen_block_writes_through_x` by 2,
|
||||
-- if we are (speaking of `y` axis now) in the middle of the chunk now.
|
||||
-- Or we don't divide it, if not.
|
||||
-- So, basing on `total_mapgen_block_writes_through_x`,
|
||||
--- we calculate `total_mapgen_block_writes_through_y` this way:
|
||||
|
||||
local total_mapgen_block_writes_through_y = (boy > 0 and boy < LAST_BLOCK) and math_floor(total_mapgen_block_writes_through_x / 2) or total_mapgen_block_writes_through_x
|
||||
while z < z2 do
|
||||
bz = math_floor(z/BS)
|
||||
block_pos_offset_removed = bz - offset
|
||||
local cz = math_floor(block_pos_offset_removed / CS)
|
||||
boz = block_pos_offset_removed % CS
|
||||
|
||||
-- Now we do absolutely the same for `z` axis, basing on our previous result
|
||||
-- from `total_mapgen_block_writes_through_y` variable.
|
||||
-- And our final result is in `total_mapgen_block_writes`.
|
||||
-- It can be still 8, derived from `x` calculation, but it can be less!
|
||||
-- It can be even 1, if we are in safe 3x3x3 area of mapchunk:
|
||||
|
||||
local total_mapgen_block_writes = (boz > 0 and boz < LAST_BLOCK) and math_floor(total_mapgen_block_writes_through_y / 2) or total_mapgen_block_writes_through_y
|
||||
|
||||
-- Get current number of writes from the table, or just set it to 1, if accessing first time:
|
||||
|
||||
local current_mapgen_block_writes = blocks[bx][by][bz] and (blocks[bx][by][bz] + 1) or 1
|
||||
|
||||
-- And compare:
|
||||
|
||||
if current_mapgen_block_writes == total_mapgen_block_writes then
|
||||
-- this block shouldn't be overwritten anymore, no need to keep it in memory
|
||||
blocks[bx][by][bz] = nil
|
||||
if not chunks[cx] then chunks[cx] = {} end
|
||||
if not chunks[cx][cy] then chunks[cx][cy] = {} end
|
||||
if not chunks[cx][cy][cz] then
|
||||
if not chunks[cx][cy][cz] then chunks[cx][cy][cz] = {counter = 1} end
|
||||
else
|
||||
chunks[cx][cy][cz].counter = chunks[cx][cy][cz].counter + 1
|
||||
if chunks[cx][cy][cz].counter >= CS_3D then
|
||||
current_chunks[#current_chunks+1] = { x = cx, y = cy, z = cz, s = chunks[cx][cy][cz].seed }
|
||||
-- this chunk shouldn't be overwritten anymore, no need to keep it in memory
|
||||
chunks[cx][cy][cz] = nil
|
||||
if next(chunks[cx][cy]) == nil then chunks[cx][cy] = nil end
|
||||
if next(chunks[cx]) == nil then chunks[cx] = nil end
|
||||
end
|
||||
end
|
||||
local blockseed = seed + bx * 7 + by * 243 + bz * 11931
|
||||
if queue_blocks_lvm_counter > 0 then
|
||||
vm_context.blockseed = blockseed
|
||||
vm_context.minp, vm_context.maxp = {x=x, y=y, z=z}, {x=x+LAST_NODE, y=y+LAST_NODE, z=z+LAST_NODE}
|
||||
for _, v in pairs(queue_blocks_lvm) do
|
||||
v.callback_function(vm_context)
|
||||
end
|
||||
end
|
||||
if nodes_block > 0 then
|
||||
current_blocks[#current_blocks+1] = { minp = {x=x, y=y, z=z}, maxp = {x=x+LAST_NODE, y=y+LAST_NODE, z=z+LAST_NODE}, seed = blockseed }
|
||||
end
|
||||
else
|
||||
blocks[bx][by][bz] = current_mapgen_block_writes
|
||||
end
|
||||
z = z + BS
|
||||
end
|
||||
if next(blocks[bx][by]) == nil then blocks[bx][by] = nil end
|
||||
z = z1
|
||||
y = y + BS
|
||||
end
|
||||
if next(blocks[bx]) == nil then blocks[bx] = nil end
|
||||
y = y1
|
||||
x = x + BS
|
||||
end
|
||||
end
|
||||
|
||||
if #queue_unsafe_engine > 0 then
|
||||
for _, v in pairs(queue_unsafe_engine) do
|
||||
v.f(vm_context)
|
||||
end
|
||||
if vm_context.write then
|
||||
vm:set_data(data)
|
||||
end
|
||||
if vm_context.write_param2 then
|
||||
vm:set_param2_data(data2)
|
||||
end
|
||||
if vm_context.write_light then
|
||||
vm:set_light_data(light)
|
||||
end
|
||||
if vm_context.write or vm_context.write_param2 or vm_context.write_light then
|
||||
vm:calc_lighting(minp, maxp, vm_context.shadow or true) -- TODO: check boundaries
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
end
|
||||
end
|
||||
|
||||
for i, b in pairs(current_chunks) do
|
||||
local cx, cy, cz, seed = b.x, b.y, b.z, b.s
|
||||
local bx, by, bz = cx * CS + offset, cy * CS + offset, cz * CS + offset
|
||||
local x, y, z = bx * BS, by * BS, bz * BS
|
||||
local minp = {x = x, y = y, z = z}
|
||||
local maxp = {x = x + CS_NODES - 1, y = y + CS_NODES - 1, z = z + CS_NODES - 1}
|
||||
area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp})
|
||||
vm_context = {
|
||||
data = data,
|
||||
data2 = data2,
|
||||
light = light,
|
||||
area = area,
|
||||
lvm_buffer = lvm_buffer,
|
||||
lvm_param2_buffer = lvm_param2_buffer,
|
||||
lvm_light_buffer = lvm_light_buffer,
|
||||
emin = minp,
|
||||
emax = maxp,
|
||||
minp = minp,
|
||||
maxp = maxp,
|
||||
chunkseed = seed,
|
||||
}
|
||||
for _, v in pairs(queue_chunks_lvm) do
|
||||
vm_context = v.f(vm_context)
|
||||
end
|
||||
for _, v in pairs(queue_chunks_nodes) do
|
||||
v.f(minp, maxp, seed, vm_context)
|
||||
end
|
||||
if vm_context.write or vm_context.write_param2 or vm_context.write_light then
|
||||
if vm_context.write then
|
||||
vm:set_data(data)
|
||||
end
|
||||
if vm_context.write_param2 then
|
||||
vm:set_param2_data(data2)
|
||||
end
|
||||
if vm_context.write_light then
|
||||
vm:set_light_data(light)
|
||||
end
|
||||
-- caused error from torches (?)
|
||||
-- vm:calc_lighting(minp, maxp, vm_context.shadow or true)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
end
|
||||
current_chunks[i] = nil
|
||||
end
|
||||
|
||||
for i, b in pairs(current_blocks) do
|
||||
for _, v in pairs(queue_blocks_nodes) do
|
||||
v.f(b.minp, b.maxp, b.seed)
|
||||
end
|
||||
current_blocks[i] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_generated = mcl_mapgen.register_chunk_generator
|
||||
|
||||
function mcl_mapgen.get_far_node(p)
|
||||
local p = p
|
||||
local node = minetest_get_node(p)
|
||||
if node.name ~= "ignore" then return node end
|
||||
minetest_get_voxel_manip():read_from_map(p, p)
|
||||
return minetest_get_node(p)
|
||||
end
|
||||
|
||||
local function coordinate_to_block(x)
|
||||
return math_floor(x / BS)
|
||||
end
|
||||
|
||||
local function coordinate_to_chunk(x)
|
||||
return math_floor((coordinate_to_block(x) - offset) / CS)
|
||||
end
|
||||
|
||||
function mcl_mapgen.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_mapgen.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_mapgen.MAX_LIMIT / mcl_mapgen.CS_NODES)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
function mcl_mapgen.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_mapgen.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
mcl_mapgen.minecraft_height_limit = 256
|
||||
|
||||
mcl_mapgen.bedrock_is_rough = normal
|
||||
|
||||
--[[ Realm stacking (h is for height)
|
||||
- Overworld (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Realm Barrier (h=11), to allow escaping the End
|
||||
- End (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Nether (h=128)
|
||||
- Void (h>=1000)
|
||||
]]
|
||||
|
||||
-- Overworld
|
||||
overworld.min = -62
|
||||
if superflat then
|
||||
mcl_mapgen.ground = tonumber(minetest.get_mapgen_setting("mgflat_ground_level")) or 8
|
||||
overworld.min = ground - 3
|
||||
end
|
||||
-- if singlenode then mcl_mapgen.overworld.min = -66 end -- DONT KNOW WHY
|
||||
overworld.max = mcl_mapgen.EDGE_MAX
|
||||
|
||||
overworld.bedrock_min = overworld.min
|
||||
overworld.bedrock_max = overworld.bedrock_min + (mcl_mapgen.bedrock_is_rough and 4 or 0)
|
||||
|
||||
mcl_mapgen.lava = normal
|
||||
overworld.lava_max = overworld.min + (normal and 10 or 0)
|
||||
|
||||
|
||||
-- The Nether (around Y = -29000)
|
||||
nether.min = -29067 -- Carefully chosen to be at a mapchunk border
|
||||
nether.max = nether.min + 128
|
||||
nether.bedrock_bottom_min = nether.min
|
||||
nether.bedrock_top_max = nether.max
|
||||
if not superflat then
|
||||
nether.bedrock_bottom_max = nether.bedrock_bottom_min + 4
|
||||
nether.bedrock_top_min = nether.bedrock_top_max - 4
|
||||
nether.lava_max = nether.min + 31
|
||||
else
|
||||
-- Thin bedrock in classic superflat mapgen
|
||||
nether.bedrock_bottom_max = nether.bedrock_bottom_min
|
||||
nether.bedrock_top_min = nether.bedrock_top_max
|
||||
nether.lava_max = nether.min + 2
|
||||
end
|
||||
if mcl_mapgen.name == "flat" then
|
||||
if superflat then
|
||||
nether.flat_floor = nether.bedrock_bottom_max + 4
|
||||
nether.flat_ceiling = nether.bedrock_bottom_max + 52
|
||||
else
|
||||
nether.flat_floor = nether.lava_max + 4
|
||||
nether.flat_ceiling = nether.lava_max + 52
|
||||
end
|
||||
end
|
||||
|
||||
-- The End (surface at ca. Y = -27000)
|
||||
end_.min = -27073 -- Carefully chosen to be at a mapchunk border
|
||||
end_.max = overworld.min - 2000
|
||||
end_.platform_pos = { x = 100, y = end_.min + 74, z = 0 }
|
||||
|
||||
-- Realm barrier used to safely separate the End from the void below the Overworld
|
||||
mcl_mapgen.realm_barrier_overworld_end_max = end_.max
|
||||
mcl_mapgen.realm_barrier_overworld_end_min = end_.max - 11
|
||||
|
||||
-- Use MineClone 2-style dungeons for normal mapgen
|
||||
mcl_mapgen.dungeons = normal
|
||||
|
||||
mcl_mapgen.overworld = overworld
|
||||
mcl_mapgen.end_ = end_
|
||||
mcl_mapgen.nether = nether
|
||||
|
||||
mcl_mapgen.order = order
|
||||
|
||||
function mcl_mapgen.get_voxel_manip(vm_context)
|
||||
if vm_context.vm then
|
||||
return vm
|
||||
end
|
||||
vm_context.vm = minetest.get_voxel_manip(vm_context.emin, vm_context.emax)
|
||||
vm_context.emin, vm_context.emax = vm_context.vm:read_from_map(vm_context.emin, vm_context.emax)
|
||||
vm_context.area = VoxelArea:new({MinEdge=vm_context.emin, MaxEdge=vm_context.emax})
|
||||
return vm_context.vm
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_mapgen
|
||||
author = kay27
|
||||
description = MineClone 2/5 MapGen Basic Stuff
|
||||
depends = mcl_init
|
|
@ -5,25 +5,25 @@ local get_connected_players = minetest.get_connected_players
|
|||
-- For a given position, returns a 2-tuple:
|
||||
-- 1st return value: true if pos is in void
|
||||
-- 2nd return value: true if it is in the deadly part of the void
|
||||
local min1, min2, min3 = mcl_mapgen.overworld.min, mcl_mapgen.end_.min, mcl_mapgen.nether.min
|
||||
local max1, max2, max3 = mcl_mapgen.overworld.max, mcl_mapgen.end_.max, mcl_mapgen.nether.max+128
|
||||
function mcl_worlds.is_in_void(pos)
|
||||
local void =
|
||||
not ((pos.y < mcl_vars.mg_overworld_max and pos.y > mcl_vars.mg_overworld_min) or
|
||||
(pos.y < mcl_vars.mg_nether_max+128 and pos.y > mcl_vars.mg_nether_min) or
|
||||
(pos.y < mcl_vars.mg_end_max and pos.y > mcl_vars.mg_end_min))
|
||||
local y = pos.y
|
||||
local void = not ((y < max1 and y > min1) or (y < max2 and y > min2) or (y < max3 and y > min3))
|
||||
|
||||
local void_deadly = false
|
||||
local deadly_tolerance = 64 -- the player must be this many nodes “deep” into the void to be damaged
|
||||
if void then
|
||||
-- Overworld → Void → End → Void → Nether → Void
|
||||
if pos.y < mcl_vars.mg_overworld_min and pos.y > mcl_vars.mg_end_max then
|
||||
void_deadly = pos.y < mcl_vars.mg_overworld_min - deadly_tolerance
|
||||
elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max+128 then
|
||||
if y < min1 and y > max2 then
|
||||
void_deadly = y < min1 - deadly_tolerance
|
||||
elseif y < min2 and y > max3 then
|
||||
-- The void between End and Nether. Like usual, but here, the void
|
||||
-- *above* the Nether also has a small tolerance area, so player
|
||||
-- can fly above the Nether without getting hurt instantly.
|
||||
void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max+128 + deadly_tolerance)
|
||||
elseif pos.y < mcl_vars.mg_nether_min then
|
||||
void_deadly = pos.y < mcl_vars.mg_nether_min - deadly_tolerance
|
||||
void_deadly = (y < min2 - deadly_tolerance) and (y > max3 + deadly_tolerance)
|
||||
elseif y < min3 then
|
||||
void_deadly = y < min3 - deadly_tolerance
|
||||
end
|
||||
end
|
||||
return void, void_deadly
|
||||
|
@ -35,15 +35,15 @@ end
|
|||
-- If the Y coordinate is not located in any dimension, it will return:
|
||||
-- nil, "void"
|
||||
function mcl_worlds.y_to_layer(y)
|
||||
if y >= mcl_vars.mg_overworld_min then
|
||||
return y - mcl_vars.mg_overworld_min, "overworld"
|
||||
elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max+128 then
|
||||
return y - mcl_vars.mg_nether_min, "nether"
|
||||
elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then
|
||||
return y - mcl_vars.mg_end_min, "end"
|
||||
else
|
||||
return nil, "void"
|
||||
end
|
||||
if y >= min1 then
|
||||
return y - min1, "overworld"
|
||||
elseif y >= min3 and y <= max3 then
|
||||
return y - min3, "nether"
|
||||
elseif y >= min2 and y <= max2 then
|
||||
return y - min2, "end"
|
||||
else
|
||||
return nil, "void"
|
||||
end
|
||||
end
|
||||
|
||||
local y_to_layer = mcl_worlds.y_to_layer
|
||||
|
@ -61,38 +61,38 @@ local pos_to_dimension = mcl_worlds.pos_to_dimension
|
|||
-- MineClone 2.
|
||||
-- mc_dimension is one of "overworld", "nether", "end" (default: "overworld").
|
||||
function mcl_worlds.layer_to_y(layer, mc_dimension)
|
||||
if mc_dimension == "overworld" or mc_dimension == nil then
|
||||
return layer + mcl_vars.mg_overworld_min
|
||||
elseif mc_dimension == "nether" then
|
||||
return layer + mcl_vars.mg_nether_min
|
||||
elseif mc_dimension == "end" then
|
||||
return layer + mcl_vars.mg_end_min
|
||||
end
|
||||
if mc_dimension == "overworld" or mc_dimension == nil then
|
||||
return layer + min1
|
||||
elseif mc_dimension == "nether" then
|
||||
return layer + min3
|
||||
elseif mc_dimension == "end" then
|
||||
return layer + min2
|
||||
end
|
||||
end
|
||||
|
||||
-- Takes a position and returns true if this position can have weather
|
||||
function mcl_worlds.has_weather(pos)
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= max1 and pos.y >= min1 - 64
|
||||
end
|
||||
|
||||
-- Takes a position and returns true if this position can have Nether dust
|
||||
function mcl_worlds.has_dust(pos)
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= max3 + 138 and pos.y >= min3 - 10
|
||||
end
|
||||
|
||||
-- Takes a position (pos) and returns true if compasses are working here
|
||||
function mcl_worlds.compass_works(pos)
|
||||
-- It doesn't work in Nether and the End, but it works in the Overworld and in the high part of the void below
|
||||
local _, dim = mcl_worlds.y_to_layer(pos.y)
|
||||
if dim == "nether" or dim == "end" then
|
||||
return false
|
||||
elseif dim == "void" then
|
||||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||
else
|
||||
return true
|
||||
end
|
||||
-- It doesn't work in Nether and the End, but it works in the Overworld and in the high part of the void below
|
||||
local _, dim = mcl_worlds.y_to_layer(pos.y)
|
||||
if dim == "nether" or dim == "end" then
|
||||
return false
|
||||
elseif dim == "void" then
|
||||
return pos.y <= max1 and pos.y >= min1 - 64
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Takes a position (pos) and returns true if clocks are working here
|
||||
|
@ -152,4 +152,3 @@ minetest.register_globalstep(function(dtime)
|
|||
dimtimer = 0
|
||||
end
|
||||
end)
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
name = mcl_worlds
|
||||
author = Wuzzy
|
||||
description = Utility functions for worlds and the “dimensions”.
|
||||
depends = mcl_init
|
||||
|
||||
depends = mcl_mapgen
|
||||
|
|
|
@ -175,16 +175,16 @@ end
|
|||
-- check if within physical map limits (-30911 to 30927)
|
||||
-- within_limits, wmin, wmax = nil, -30913, 30928
|
||||
mobs.within_limits = function(pos, radius)
|
||||
local wmin, wmax
|
||||
if mcl_vars then
|
||||
if mcl_vars.mapgen_edge_min and mcl_vars.mapgen_edge_max then
|
||||
wmin, wmax = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max
|
||||
local wmin, wmax
|
||||
if mcl_mapgen then
|
||||
if mcl_mapgen.EDGE_MIN and mcl_mapgen.EDGE_MAX then
|
||||
wmin, wmax = mcl_mapgen.EDGE_MIN, mcl_mapgen.EDGE_MAX
|
||||
return pos
|
||||
and (pos.x - radius) > wmin and (pos.x + radius) < wmax
|
||||
and (pos.y - radius) > wmin and (pos.y + radius) < wmax
|
||||
and (pos.z - radius) > wmin and (pos.z + radius) < wmax
|
||||
end
|
||||
end
|
||||
return pos
|
||||
and (pos.x - radius) > wmin and (pos.x + radius) < wmax
|
||||
and (pos.y - radius) > wmin and (pos.y + radius) < wmax
|
||||
and (pos.z - radius) > wmin and (pos.z + radius) < wmax
|
||||
end
|
||||
|
||||
-- get node but use fallback for nil or unknown
|
||||
|
@ -214,6 +214,7 @@ end
|
|||
--a function used for despawning mobs
|
||||
mobs.check_for_player_within_area = function(self, radius)
|
||||
local pos1 = self.object:get_pos()
|
||||
if not pos1 then return end
|
||||
--get players in radius
|
||||
for _,player in pairs(minetest_get_connected_players()) do
|
||||
if player and player:get_hp() > 0 then
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name = mcl_mobs
|
||||
author = PilzAdam
|
||||
description = Adds a mob API for mods to add animals or monsters, etc.
|
||||
depends = mcl_particles
|
||||
depends = mcl_mapgen, mcl_particles
|
||||
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience
|
||||
|
|
|
@ -233,15 +233,15 @@ mobs_mc.override.spawn_height = {
|
|||
water = tonumber(minetest.settings:get("water_level")) or 0, -- Water level in the Overworld
|
||||
|
||||
-- Overworld boundaries (inclusive)
|
||||
overworld_min = mcl_vars.mg_overworld_min,
|
||||
overworld_max = mcl_vars.mg_overworld_max,
|
||||
overworld_min = mcl_mapgen.overworld.min,
|
||||
overworld_max = mcl_mapgen.overworld.max,
|
||||
|
||||
-- Nether boundaries (inclusive)
|
||||
nether_min = mcl_vars.mg_nether_min,
|
||||
nether_max = mcl_vars.mg_nether_max,
|
||||
nether_min = mcl_mapgen.nether.min,
|
||||
nether_max = mcl_mapgen.nether.max,
|
||||
|
||||
-- End boundaries (inclusive)
|
||||
end_min = mcl_vars.mg_end_min,
|
||||
end_max = mcl_vars.mg_end_max,
|
||||
end_min = mcl_mapgen.end_.min,
|
||||
end_max = mcl_mapgen.end_.max,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_portals
|
||||
description = Adds buildable portals to the Nether and End dimensions.
|
||||
depends = mcl_nether, mcl_end, mcl_particles, mcl_spawn, mcl_credits
|
||||
depends = mcl_mapgen, mcl_nether, mcl_end, mcl_particles, mcl_spawn, mcl_credits
|
||||
optional_depends = awards, doc
|
||||
|
|
|
@ -6,12 +6,6 @@ local math = math
|
|||
|
||||
local has_doc = minetest.get_modpath("doc")
|
||||
|
||||
-- Parameters
|
||||
--local SPAWN_MIN = mcl_vars.mg_end_min+70
|
||||
--local SPAWN_MAX = mcl_vars.mg_end_min+98
|
||||
|
||||
--local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
|
||||
local function destroy_portal(pos)
|
||||
local neighbors = {
|
||||
{ x=1, y=0, z=0 },
|
||||
|
@ -184,7 +178,7 @@ function mcl_portals.end_teleport(obj, pos)
|
|||
-- Teleport to the End at a fixed position and generate a
|
||||
-- 5×5 obsidian platform below.
|
||||
|
||||
local platform_pos = mcl_vars.mg_end_platform_pos
|
||||
local platform_pos = mcl_mapgen.end_.platform_pos
|
||||
-- force emerge of target1 area
|
||||
minetest.get_voxel_manip():read_from_map(platform_pos, platform_pos)
|
||||
if not minetest.get_node_or_nil(platform_pos) then
|
||||
|
|
|
@ -19,7 +19,7 @@ local W_MIN, W_MAX = 4, 23
|
|||
local H_MIN, H_MAX = 5, 23
|
||||
local N_MIN, N_MAX = 6, (W_MAX-2) * (H_MAX-2)
|
||||
local TRAVEL_X, TRAVEL_Y, TRAVEL_Z = 8, 1, 8
|
||||
local LIM_MIN, LIM_MAX = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max
|
||||
local LIM_MIN, LIM_MAX = mcl_mapgen.EDGE_MIN, mcl_mapgen.EDGE_MAX
|
||||
local PLAYER_COOLOFF, MOB_COOLOFF = 3, 14 -- for this many seconds they won't teleported again
|
||||
local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds
|
||||
local CHATTER_US = TOUCH_CHATTER_TIME * 1000000
|
||||
|
@ -27,8 +27,8 @@ local DELAY = 3 -- seconds before teleporting in Nether portal in Survival mo
|
|||
local DISTANCE_MAX = 128
|
||||
local PORTAL = "mcl_portals:portal"
|
||||
local OBSIDIAN = "mcl_core:obsidian"
|
||||
local O_Y_MIN, O_Y_MAX = max(mcl_vars.mg_overworld_min, -31), min(mcl_vars.mg_overworld_max, 2048)
|
||||
local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_top_min - H_MIN
|
||||
local O_Y_MIN, O_Y_MAX = max(mcl_mapgen.overworld.min, -31), min(mcl_mapgen.overworld.max, 2048)
|
||||
local N_Y_MIN, N_Y_MAX = mcl_mapgen.nether.bedrock_bottom_min, mcl_mapgen.nether.bedrock_top_min - H_MIN
|
||||
|
||||
-- Alpha and particles
|
||||
local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none"
|
||||
|
@ -66,7 +66,7 @@ minetest.register_on_shutdown(function()
|
|||
storage:set_string("nether_exits_keys", minetest.serialize(keys))
|
||||
end)
|
||||
|
||||
local get_node = mcl_vars.get_node
|
||||
local get_node = mcl_mapgen.get_far_node
|
||||
local set_node = minetest.set_node
|
||||
local registered_nodes = minetest.registered_nodes
|
||||
local is_protected = minetest.is_protected
|
||||
|
@ -437,7 +437,7 @@ local function create_portal_2(pos1, name, obj)
|
|||
end
|
||||
local exit = build_nether_portal(pos1, W_MIN-2, H_MIN-2, orientation, name)
|
||||
finalize_teleport(obj, exit)
|
||||
local cn = mcl_vars.get_chunk_number(pos1)
|
||||
local cn = mcl_mapgen.get_chunk_number(pos1)
|
||||
chunks[cn] = nil
|
||||
if queue[cn] then
|
||||
for next_obj, _ in pairs(queue[cn]) do
|
||||
|
@ -451,9 +451,9 @@ end
|
|||
|
||||
local function get_lava_level(pos, pos1, pos2)
|
||||
if pos.y > -1000 then
|
||||
return max(min(mcl_vars.mg_lava_overworld_max, pos2.y-1), pos1.y+1)
|
||||
return max(min(mcl_mapgen.overworld.lava_max, pos2.y-1), pos1.y+1)
|
||||
end
|
||||
return max(min(mcl_vars.mg_lava_nether_max, pos2.y-1), pos1.y+1)
|
||||
return max(min(mcl_mapgen.nether.lava_max, pos2.y-1), pos1.y+1)
|
||||
end
|
||||
|
||||
local function ecb_scan_area_2(blockpos, action, calls_remaining, param)
|
||||
|
@ -532,7 +532,7 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param)
|
|||
end
|
||||
|
||||
local function create_portal(pos, limit1, limit2, name, obj)
|
||||
local cn = mcl_vars.get_chunk_number(pos)
|
||||
local cn = mcl_mapgen.get_chunk_number(pos)
|
||||
if chunks[cn] then
|
||||
local q = queue[cn] or {}
|
||||
q[obj] = true
|
||||
|
@ -545,8 +545,8 @@ local function create_portal(pos, limit1, limit2, name, obj)
|
|||
-- so we'll emerge single chunk only: 5x5x5 blocks, 80x80x80 nodes maximum
|
||||
-- and maybe one more chunk from below if (SCAN_2_MAP_CHUNKS = true)
|
||||
|
||||
local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes)
|
||||
local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1)
|
||||
local pos1 = add(mul(mcl_mapgen.pos_to_chunk(pos), mcl_mapgen.CS_NODES), mcl_mapgen.OFFSET_NODES)
|
||||
local pos2 = add(pos1, mcl_mapgen.CS_NODES - 1)
|
||||
|
||||
if not SCAN_2_MAP_CHUNKS then
|
||||
if limit1 and limit1.x and limit1.y and limit1.z then
|
||||
|
@ -560,8 +560,8 @@ local function create_portal(pos, limit1, limit2, name, obj)
|
|||
end
|
||||
|
||||
-- Basically the copy of code above, with minor additions to continue the search in single additional chunk below:
|
||||
local next_chunk_1 = {x = pos1.x, y = pos1.y - mcl_vars.chunk_size_in_nodes, z = pos1.z}
|
||||
local next_chunk_2 = add(next_chunk_1, mcl_vars.chunk_size_in_nodes - 1)
|
||||
local next_chunk_1 = {x = pos1.x, y = pos1.y - mcl_mapgen.CS_NODES, z = pos1.z}
|
||||
local next_chunk_2 = add(next_chunk_1, mcl_mapgen.CS_NODES - 1)
|
||||
local next_pos = {x = pos.x, y=max(next_chunk_2.y, limit1.y), z = pos.z}
|
||||
if limit1 and limit1.x and limit1.y and limit1.z then
|
||||
pos1 = {x = max(min(limit1.x, pos.x), pos1.x), y = max(min(limit1.y, pos.y), pos1.y), z = max(min(limit1.z, pos.z), pos1.z)}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
name = mcl_biomes
|
||||
author = maikerumine
|
||||
description = Adds the various biomes and biome-related things for non-v6 map generators.
|
||||
depends = mcl_init, mcl_mapgen_core, mcl_core, mcl_worlds, mcl_farming, mcl_flowers, mcl_end, mcl_ocean
|
||||
depends = mcl_mapgen, mcl_mapgen_core, mcl_core, mcl_worlds, mcl_farming, mcl_flowers, mcl_end, mcl_ocean
|
||||
|
|
|
@ -1,44 +1,33 @@
|
|||
local c_debris = minetest.get_content_id("mcl_nether:ancient_debris")
|
||||
local c_netherrack = minetest.get_content_id("mcl_nether:netherrack")
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local minetest_get_node = minetest.get_node
|
||||
local minetest_set_node = minetest.set_node
|
||||
local debris_name = "mcl_nether:ancient_debris"
|
||||
local netherrack_name = "mcl_nether:netherrack"
|
||||
local air_name = "air"
|
||||
|
||||
local facedir = {
|
||||
vector.new(0, 0, 1),
|
||||
vector.new(0, 1, 0),
|
||||
vector.new(1, 0, 0),
|
||||
vector.new(0, 0, -1),
|
||||
vector.new(0, -1, 0),
|
||||
vector.new(-1, 0, 0),
|
||||
}
|
||||
local min, max = mcl_mapgen.nether.min, mcl_mapgen.nether.max
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp)
|
||||
if maxp.y < mcl_vars.mg_nether_min or minp.y > mcl_vars.mg_nether_max then
|
||||
return
|
||||
end
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
|
||||
for idx in area:iter(minp.x, math.max(minp.y, mcl_vars.mg_nether_min), minp.z, maxp.x, math.min(maxp.y, mcl_vars.mg_nether_max), maxp.z) do
|
||||
if data[idx] == c_debris then
|
||||
local pos = area:position(idx)
|
||||
local exposed = false
|
||||
for _, dir in pairs(facedir) do
|
||||
if data[area:indexp(vector.add(pos, dir))] == c_air then
|
||||
exposed = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if exposed then
|
||||
data[idx] = c_netherrack
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vm:set_data(data)
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
mcl_mapgen.register_mapgen_block(function(minp, maxp)
|
||||
local minp = minp
|
||||
local minp_y = minp.y
|
||||
if minp_y > max then return end
|
||||
local maxp = maxp
|
||||
local maxp_y = maxp.y
|
||||
if maxp_y < min then return end
|
||||
local nodes = minetest_find_nodes_in_area(minp, maxp, debris_name)
|
||||
if nodes then
|
||||
for _, pos in pairs(nodes) do
|
||||
minetest.log("warning","debris found at "..minetest.pos_to_string(pos))
|
||||
local x, y, z = pos.x, pos.y, pos.z
|
||||
if minetest_get_node({x = x-1, y = y, z = z}) == air_name
|
||||
or minetest_get_node({x = x+1, y = y, z = z}) == air_name
|
||||
or minetest_get_node({x = x, y = y-1, z = z}) == air_name
|
||||
or minetest_get_node({x = x, y = y+1, z = z}) == air_name
|
||||
or minetest_get_node({x = x, y = y, z = z-1}) == air_name
|
||||
or minetest_get_node({x = x, y = y, z = z+1}) == air_name then
|
||||
minetest_set_node(pos, netherrack_name)
|
||||
minetest.log("warning","debris at "..minetest.pos_to_string(pos) .. " replaced to netherrack")
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_debrisgen
|
||||
author = Fleckenstein
|
||||
description = Make sure ancient debris is not generated exposed to air
|
||||
depends = mcl_mapgen_core, mcl_nether
|
||||
depends = mcl_mapgen, mcl_nether
|
||||
|
|
|
@ -2,21 +2,19 @@
|
|||
|
||||
mcl_dungeons = {}
|
||||
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
|
||||
-- Are dungeons disabled?
|
||||
if mcl_vars.mg_dungeons == false or mg_name == "singlenode" then
|
||||
if mcl_mapgen.dungeons == false or mcl_mapgen.singlenode == true then
|
||||
return
|
||||
end
|
||||
|
||||
--lua locals
|
||||
--minetest
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local registered_nodes = minetest.registered_nodes
|
||||
local swap_node = minetest.swap_node
|
||||
local set_node = minetest.set_node
|
||||
local dir_to_facedir = minetest.dir_to_facedir
|
||||
local get_meta = minetest.get_meta
|
||||
local emerge_area = minetest.emerge_area
|
||||
|
||||
--vector
|
||||
local vector_add = vector.add
|
||||
|
@ -32,15 +30,15 @@ local math_max = math.max
|
|||
local math_ceil = math.ceil
|
||||
|
||||
--custom mcl_vars
|
||||
local get_node = mcl_vars.get_node
|
||||
local get_node = mcl_mapgen.get_far_node
|
||||
|
||||
|
||||
local min_y = math_max(mcl_vars.mg_overworld_min, mcl_vars.mg_bedrock_overworld_max) + 1
|
||||
local max_y = mcl_vars.mg_overworld_max - 1
|
||||
local min_y = math_max(mcl_mapgen.overworld.min, mcl_mapgen.overworld.bedrock_max) + 1
|
||||
local max_y = mcl_mapgen.overworld.max - 1
|
||||
-- Calculate the number of dungeon spawn attempts
|
||||
-- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks).
|
||||
-- Minetest chunks don't have this size, so scale the number accordingly.
|
||||
local attempts = math_ceil(((mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE) ^ 3) / 8192) -- 63 = 80*80*80/8192
|
||||
local attempts = math_ceil((mcl_mapgen.CS_NODES ^ 3) / 8192) -- 63 = 80*80*80/8192
|
||||
|
||||
local dungeonsizes = {
|
||||
{ x=5, y=4, z=5},
|
||||
|
@ -112,7 +110,7 @@ local loottable =
|
|||
}
|
||||
|
||||
-- Bonus loot for v6 mapgen: Otherwise unobtainable saplings.
|
||||
if mg_name == "v6" then
|
||||
if mcl_mapgen.v6 then
|
||||
table.insert(loottable, {
|
||||
stacks_min = 1,
|
||||
stacks_max = 3,
|
||||
|
@ -124,20 +122,28 @@ if mg_name == "v6" then
|
|||
})
|
||||
end
|
||||
|
||||
local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
--local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
|
||||
-- if calls_remaining >= 1 then return end
|
||||
-- local p1, _, dim, pr = param.p1, param.p2, param.dim, param.pr
|
||||
-- local check = not (param.dontcheck or false)
|
||||
local m1, m2 = 0, 0
|
||||
local function spawn_dungeon(p1, p2, dim, pr, dontcheck)
|
||||
|
||||
local p1, _, dim, pr = param.p1, param.p2, param.dim, param.pr
|
||||
local x, y, z = p1.x, p1.y, p1.z
|
||||
local check = not (param.dontcheck or false)
|
||||
local check = not (dontcheck or false)
|
||||
|
||||
-- Check floor and ceiling: Must be *completely* solid
|
||||
local y_floor = y
|
||||
local y_ceiling = y + dim.y + 1
|
||||
if check then for tx = x+1, x+dim.x do for tz = z+1, z+dim.z do
|
||||
if not registered_nodes[get_node({x = tx, y = y_floor , z = tz}).name].walkable
|
||||
or not registered_nodes[get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end
|
||||
end end end
|
||||
|
||||
if check then
|
||||
local dim_x, dim_z = dim.x, dim.z
|
||||
local size = dim_z*dim_x
|
||||
if #minetest_find_nodes_in_area({x=x+1,y=y_floor,z=z+1}, {x=x+dim_z,y=y_floor,z=z+dim_z}, "group:walkabke") < size
|
||||
or #minetest_find_nodes_in_area({x=x+1,y=y_floor,z=z+1}, {x=x+dim_z,y=y_floor,z=z+dim_z}, "group:walkabke") < size then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Check for air openings (2 stacked air at ground level) in wall positions
|
||||
local openings_counter = 0
|
||||
|
@ -404,8 +410,7 @@ local function dungeons_nodes(minp, maxp, blockseed)
|
|||
local z = pr:next(minp.z, maxp.z-dim.z-1)
|
||||
local p1 = {x=x,y=y,z=z}
|
||||
local p2 = {x = x+dim.x+1, y = y+dim.y+1, z = z+dim.z+1}
|
||||
minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
emerge_area(p1, p2, ecb_spawn_dungeon, {p1=p1, p2=p2, dim=dim, pr=pr})
|
||||
spawn_dungeon(p1, p2, dim, pr)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -413,8 +418,7 @@ function mcl_dungeons.spawn_dungeon(p1, _, pr)
|
|||
if not p1 or not pr or not p1.x or not p1.y or not p1.z then return end
|
||||
local dim = dungeonsizes[pr:next(1, #dungeonsizes)]
|
||||
local p2 = {x = p1.x+dim.x+1, y = p1.y+dim.y+1, z = p1.z+dim.z+1}
|
||||
minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
emerge_area(p1, p2, ecb_spawn_dungeon, {p1=p1, p2=p2, dim=dim, pr=pr, dontcheck=true})
|
||||
spawn_dungeon(p1, p2, dim, pr, true)
|
||||
end
|
||||
|
||||
mcl_mapgen_core.register_generator("dungeons", nil, dungeons_nodes, 999999)
|
||||
mcl_mapgen.register_mapgen(dungeons_nodes, mcl_mapgen.order.DUNGEONS)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_dungeons
|
||||
author = Wuzzy
|
||||
description = Generates random dungeons in the world
|
||||
depends = mcl_init, mcl_core, mcl_chests, mcl_mobs, mcl_mobspawners, mcl_mapgen_core, mobs_mc
|
||||
depends = mcl_mapgen, mcl_core, mcl_chests, mcl_mobs, mcl_mobspawners, mcl_mapgen_core, mobs_mc
|
||||
|
|
|
@ -10,7 +10,7 @@ local noisemap = PerlinNoiseMap({
|
|||
local c_end_stone = minetest.get_content_id("mcl_end:end_stone")
|
||||
local y_offset = -2
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp)
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp)
|
||||
if maxp.y < (-27025 + y_offset) or minp.y > (-27000 + y_offset + 4) or maxp.x < -75 or minp.x > 75 or maxp.z < -75 or minp.z > 75 then
|
||||
return
|
||||
end
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
local c_water = minetest.get_content_id("mcl_core:water_source")
|
||||
local c_dirt = minetest.get_content_id("mcl_core:dirt")
|
||||
local c_clay = minetest.get_content_id("mcl_core:clay")
|
||||
|
||||
local perlin_clay
|
||||
|
||||
mcl_mapgen.register_mapgen_lvm(function(c)
|
||||
local minp, maxp, blockseed, voxelmanip_data, voxelmanip_area, lvm_used = c.minp, c.maxp, c.chunkseed, c.data, c.area, c.write or false
|
||||
-- TODO: Make clay generation reproducible for same seed.
|
||||
if maxp.y < -5 or minp.y > 0 then
|
||||
return c
|
||||
end
|
||||
c.vm = c.vm or mcl_mapgen.get_voxel_manip(c)
|
||||
|
||||
minetest.log("warning", "CLAY!")
|
||||
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
perlin_clay = perlin_clay or minetest.get_perlin({
|
||||
offset = 0.5,
|
||||
scale = 0.2,
|
||||
spread = {x = 5, y = 5, z = 5},
|
||||
seed = -316,
|
||||
octaves = 1,
|
||||
persist = 0.0
|
||||
})
|
||||
|
||||
for y=math.max(minp.y, 0), math.min(maxp.y, -8), -1 do
|
||||
-- Assume X and Z lengths are equal
|
||||
local divlen = 4
|
||||
local divs = (maxp.x-minp.x)/divlen+1;
|
||||
for divx=0+1,divs-2 do
|
||||
for divz=0+1,divs-2 do
|
||||
-- Get position and shift it a bit randomly so the clay do not obviously appear in a grid
|
||||
local cx = minp.x + math.floor((divx+0.5)*divlen) + pr:next(-1,1)
|
||||
local cz = minp.z + math.floor((divz+0.5)*divlen) + pr:next(-1,1)
|
||||
|
||||
local water_pos = voxelmanip_area:index(cx, y+1, cz)
|
||||
local waternode = voxelmanip_data[water_pos]
|
||||
local surface_pos = voxelmanip_area:index(cx, y, cz)
|
||||
local surfacenode = voxelmanip_data[surface_pos]
|
||||
|
||||
local genrnd = pr:next(1, 20)
|
||||
if genrnd == 1 and perlin_clay:get_3d({x=cx,y=y,z=cz}) > 0 and waternode == c_water and
|
||||
(surfacenode == c_dirt or minetest.get_item_group(minetest.get_name_from_content_id(surfacenode), "sand") == 1) then
|
||||
local diamondsize = pr:next(1, 3)
|
||||
for x1 = -diamondsize, diamondsize do
|
||||
for z1 = -(diamondsize - math.abs(x1)), diamondsize - math.abs(x1) do
|
||||
local ccpos = voxelmanip_area:index(cx+x1, y, cz+z1)
|
||||
local claycandidate = voxelmanip_data[ccpos]
|
||||
if voxelmanip_data[ccpos] == c_dirt or minetest.get_item_group(minetest.get_name_from_content_id(claycandidate), "sand") == 1 then
|
||||
voxelmanip_data[ccpos] = c_clay
|
||||
minetest.log("warning", "CLAY! "..minetest.pos_to_string({x=cx+x1,y=y,z=cz+z1}))
|
||||
lvm_used = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
c.write = lvm_used
|
||||
return c
|
||||
end)
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
name = mcl_mapgen_core
|
||||
author = Wuzzy
|
||||
description = The core of the MCL2 mapgen
|
||||
depends = mcl_init, mcl_core, biomeinfo, mcl_worlds
|
||||
depends = mcl_mapgen, mcl_init, mcl_core, biomeinfo, mcl_worlds
|
||||
optional_depends = mclx_core, mcl_cocoas, mcl_sponges, mcl_ocean, mcl_stairs, mcl_monster_eggs, mcl_structures, mcl_flowers, mcl_farming, mcl_mushrooms, mcl_nether
|
||||
|
|
|
@ -0,0 +1,459 @@
|
|||
|
||||
local END_EXIT_PORTAL_POS = vector.new(-3, -27003, -3) -- End exit portal position
|
||||
local WITCH_HUT_HEIGHT = 3 -- Exact Y level to spawn witch huts at. This height refers to the height of the floor
|
||||
local OVERWORLD_STRUCT_MIN, OVERWORLD_STRUCT_MAX = mcl_mapgen.overworld.min, mcl_mapgen.overworld.max
|
||||
local END_STRUCT_MIN, END_STRUCT_MAX = mcl_mapgen.end_.min, mcl_mapgen.end_.max
|
||||
local DIVLEN = 5
|
||||
local V6 = mcl_mapgen.v6
|
||||
|
||||
local math_min, math_max = math.min, math.max
|
||||
local math_floor, math_ceil = math.floor, math.ceil
|
||||
local minetest_get_node = minetest.get_node
|
||||
local minetest_get_mapgen_object = minetest.get_mapgen_object
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local minetest_get_item_group = minetest.get_item_group
|
||||
|
||||
local perlin_structures
|
||||
|
||||
local function determine_ground_level(p, vm_context)
|
||||
local maxp = vm_context.maxp
|
||||
local maxp_y = maxp.y
|
||||
local y = math_min(OVERWORLD_STRUCT_MAX, maxp_y)
|
||||
if y < maxp_y then
|
||||
y = y + 1
|
||||
end
|
||||
p.y = y
|
||||
|
||||
local checknode = minetest_get_node(p)
|
||||
local nn = checknode.name
|
||||
if nn ~= "air" and minetest_get_item_group(nn, "attached_node") == 0 and minetest_get_item_group(nn, "deco_block") == 0 then return end
|
||||
|
||||
for y = y - 1, math_max(OVERWORLD_STRUCT_MIN, vm_context.minp.y), -1 do
|
||||
p.y = y
|
||||
local checknode = minetest_get_node(p)
|
||||
if checknode then
|
||||
local nn = checknode.name
|
||||
local def = minetest.registered_nodes[nn]
|
||||
if def and def.walkable then
|
||||
return p, y, nn
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Helper function for converting a MC probability to MT, with
|
||||
-- regards to MapBlocks.
|
||||
-- Some MC generated structures are generated on per-chunk
|
||||
-- probability.
|
||||
-- The MC probability is 1/x per Minecraft chunk (16×16).
|
||||
|
||||
-- x: The MC probability is 1/x.
|
||||
-- minp, maxp: MapBlock limits
|
||||
-- returns: Probability (1/return_value) for a single MT mapblock
|
||||
local function minecraft_chunk_probability(x, minp, maxp)
|
||||
-- 256 is the MC chunk height
|
||||
return x * (((maxp.x-minp.x+1)*(maxp.z-minp.z+1)) / 256)
|
||||
end
|
||||
|
||||
-- Takes x and z coordinates and minp and maxp of a generated chunk
|
||||
-- (in on_generated callback) and returns a biomemap index)
|
||||
-- Inverse function of biomemap_to_xz
|
||||
local function xz_to_biomemap_index(x, z, minp, maxp)
|
||||
local zstride = maxp.z - minp.z + 1
|
||||
return (z - minp.z) * zstride + (x - minp.x) + 1
|
||||
end
|
||||
|
||||
--local chunk_has_desert_struct
|
||||
--local chunk_has_desert_temple
|
||||
--local chunk_has_igloo
|
||||
|
||||
|
||||
|
||||
|
||||
minetest.register_node("mcl_mapgen_core:desert_temple", {
|
||||
-- drawtype="airlike",
|
||||
tiles = {"mcl_core_stonebrick_carved.png"},
|
||||
groups = {
|
||||
struct = 1,
|
||||
not_in_creative_inventory = 1,
|
||||
},
|
||||
})
|
||||
|
||||
local octaves = 3
|
||||
local persistence = 0.6
|
||||
local offset = 0
|
||||
local scale = 1
|
||||
local max_noise = 0
|
||||
for i = 1, octaves do
|
||||
local noise = 1 * (persistence ^ (i - 1))
|
||||
max_noise = max_noise + noise
|
||||
end
|
||||
|
||||
max_noise = max_noise * octaves
|
||||
|
||||
max_noise = offset + scale * max_noise
|
||||
|
||||
--[[function structures.register_structure(
|
||||
name, -- "desert_temple"
|
||||
place_on, -- {"mcl_core:sand", "mcl_core:sandstone"}
|
||||
flags, -- "all_floors"
|
||||
]]
|
||||
|
||||
|
||||
minetest.register_decoration({
|
||||
decoration = "mcl_mapgen_core:desert_temple",
|
||||
deco_type = "simple",
|
||||
place_on = {"mcl_core:sand", "mcl_core:sandstone"},
|
||||
flags = "all_floors",
|
||||
--[[ noise_params = {
|
||||
offset = offset,
|
||||
scale = scale,
|
||||
spread = {
|
||||
x = 1,
|
||||
y = 1,
|
||||
z = 1,
|
||||
},
|
||||
seed = 329,
|
||||
octaves = octaves,
|
||||
persistence = persistence,
|
||||
lacunarity = 2.0,
|
||||
flags = "eased",
|
||||
},
|
||||
noise_threshold = 1000,-- * 0.9,
|
||||
]]
|
||||
fill_ratio = 0.001,
|
||||
y_min = 5,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
biomes = {
|
||||
"ColdTaiga_beach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Desert",
|
||||
"Desert_ocean",
|
||||
"ExtremeHills_beach",
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"MesaBryce_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
"StoneBeach",
|
||||
"StoneBeach_ocean",
|
||||
"Taiga_beach",
|
||||
},
|
||||
})
|
||||
|
||||
--minetest.register_lbm(
|
||||
-- name = "mcl_mapgen_core:process_struct_seed",
|
||||
-- nodenames = {
|
||||
-- "group:struct",
|
||||
-- }
|
||||
-- run_at_everly_load = true,
|
||||
-- action = function(pos, node)
|
||||
-- end,
|
||||
--)
|
||||
|
||||
|
||||
local function spawn_desert_temple(p, nn, pr, vm_context)
|
||||
if p.y < 5 then return end
|
||||
if nn ~= "mcl_core:sand" and nn ~= "mcl_core:sandstone" then return end
|
||||
-- if pr:next(1,12000) ~= 1 then return end
|
||||
mcl_structures.call_struct(p, "desert_temple", nil, pr)
|
||||
return true
|
||||
end
|
||||
|
||||
local function spawn_desert_well(p, nn, pr, vm_context)
|
||||
if p.y < 5 then return end
|
||||
if nn ~= "mcl_core:sand" and nn ~= "mcl_core:sandstone" then return end
|
||||
local desert_well_prob = minecraft_chunk_probability(1000, vm_context.minp, vm_context.maxp)
|
||||
-- if pr:next(1, desert_well_prob) ~= 1 then return end
|
||||
local surface = minetest_find_nodes_in_area({x=p.x,y=p.y-1,z=p.z}, {x=p.x+5, y=p.y-1, z=p.z+5}, "mcl_core:sand")
|
||||
if #surface < 25 then return end
|
||||
mcl_structures.call_struct(p, "desert_well", nil, pr)
|
||||
return true
|
||||
end
|
||||
|
||||
local function spawn_igloo(p, nn, pr, vm_context)
|
||||
if nn ~= "mcl_core:snowblock" and nn ~= "mcl_core:snow" and minetest_get_item_group(nn, "grass_block_snow") ~= 1 then return end
|
||||
-- if pr:next(1, 4400) ~= 1 then return end
|
||||
-- Check surface
|
||||
local floor = {x=p.x+9, y=p.y-1, z=p.z+9}
|
||||
local surface = minetest_find_nodes_in_area({x=p.x,y=p.y-1,z=p.z}, floor, {"mcl_core:snowblock", "mcl_core:dirt_with_grass_snow"})
|
||||
if #surface < 63 then return end
|
||||
mcl_structures.call_struct(p, "igloo", nil, pr)
|
||||
-- chunk_has_igloo = true
|
||||
return true
|
||||
end
|
||||
|
||||
local function spawn_fossil(p, nn, pr, vm_context)
|
||||
-- if chunk_has_desert_temple or p.y < 4 then return end
|
||||
if p.y < 4 then return end
|
||||
if nn ~= "mcl_core:sandstone" and nn ~= "mcl_core:sand" then return end
|
||||
local fossil_prob = minecraft_chunk_probability(64, vm_context.minp, vm_context.maxp)
|
||||
if pr:next(1, fossil_prob) ~= 1 then return end
|
||||
-- Spawn fossil below desert surface between layers 40 and 49
|
||||
local p1 = {x=p.x, y=pr:next(mcl_worlds.layer_to_y(40), mcl_worlds.layer_to_y(49)), z=p.z}
|
||||
-- Very rough check of the environment (we expect to have enough stonelike nodes).
|
||||
-- Fossils may still appear partially exposed in caves, but this is O.K.
|
||||
local p2 = vector.add(p1, 4)
|
||||
local nodes = minetest_find_nodes_in_area(p1, p2, {"mcl_core:sandstone", "mcl_core:stone", "mcl_core:diorite", "mcl_core:andesite", "mcl_core:granite", "mcl_core:stone_with_coal", "mcl_core:dirt", "mcl_core:gravel"})
|
||||
if #nodes < 100 then return end
|
||||
-- >= 80%
|
||||
mcl_structures.call_struct(p1, "fossil", nil, pr)
|
||||
end
|
||||
|
||||
local witch_hut_offsets = {
|
||||
["0"] = {
|
||||
{x=1, y=0, z=1}, {x=1, y=0, z=5}, {x=6, y=0, z=1}, {x=6, y=0, z=5},
|
||||
},
|
||||
["180"] = {
|
||||
{x=2, y=0, z=1}, {x=2, y=0, z=5}, {x=7, y=0, z=1}, {x=7, y=0, z=5},
|
||||
},
|
||||
["270"] = {
|
||||
{x=1, y=0, z=1}, {x=5, y=0, z=1}, {x=1, y=0, z=6}, {x=5, y=0, z=6},
|
||||
},
|
||||
["90"] = {
|
||||
{x=1, y=0, z=2}, {x=5, y=0, z=2}, {x=1, y=0, z=7}, {x=5, y=0, z=7},
|
||||
},
|
||||
}
|
||||
|
||||
local function spawn_witch_hut(p, nn, pr, vm_context)
|
||||
minetest.log("warning", "p="..minetest.pos_to_string(p)..", nn="..nn)
|
||||
-- if p.y > 1 or minetest_get_item_group(nn, "dirt") == 0 then return end
|
||||
local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
local prob = minecraft_chunk_probability(48, minp, maxp)
|
||||
minetest.log("warning", "prob="..tostring(prob))
|
||||
-- if pr:next(1, prob) ~= 1 then return end
|
||||
|
||||
-- Where do witches live?
|
||||
if V6 then
|
||||
-- v6: In Normal biome
|
||||
if biomeinfo.get_v6_biome(p) ~= "Normal" then return end
|
||||
else
|
||||
-- Other mapgens: In swampland biome
|
||||
local biomemap = vm_context.biomemap
|
||||
if not biomemap then
|
||||
vm_context.biomemap = minetest_get_mapgen_object('biomemap')
|
||||
biomemap = vm_context.biomemap
|
||||
end
|
||||
-- minetest.chat_send_all(minetest.serialize(biomemap))
|
||||
local swampland = minetest.get_biome_id("Swampland")
|
||||
local swampland_shore = minetest.get_biome_id("Swampland_shore")
|
||||
local bi = xz_to_biomemap_index(p.x, p.z, vm_context.minp, vm_context.maxp)
|
||||
if (biomemap[bi] == swampland) then
|
||||
minetest.chat_send_all('swampland')
|
||||
end
|
||||
if (biomemap[bi] == swampland_shore) then
|
||||
minetest.chat_send_all('swampland_shore')
|
||||
end
|
||||
-- if biomemap[bi] ~= swampland and biomemap[bi] ~= swampland_shore then return end
|
||||
end
|
||||
|
||||
local r = tostring(pr:next(0, 3) * 90) -- "0", "90", "180" or 270"
|
||||
local p1 = {x=p.x-1, y=WITCH_HUT_HEIGHT+2, z=p.z-1}
|
||||
local size
|
||||
if r == "0" or r == "180" then
|
||||
size = {x=10, y=4, z=8}
|
||||
else
|
||||
size = {x=8, y=4, z=10}
|
||||
end
|
||||
local p2 = vector.add(p1, size)
|
||||
|
||||
-- This checks free space at the “body” of the hut and a bit around.
|
||||
-- ALL nodes must be free for the placement to succeed.
|
||||
local free_nodes = minetest_find_nodes_in_area(p1, p2, {"air", "mcl_core:water_source", "mcl_flowers:waterlily"})
|
||||
if #free_nodes < ((size.x+1)*(size.y+1)*(size.z+1)) then return end
|
||||
|
||||
local place = {x=p.x, y=WITCH_HUT_HEIGHT-1, z=p.z}
|
||||
|
||||
-- FIXME: For some mysterious reason (black magic?) this
|
||||
-- function does sometimes NOT spawn the witch hut. One can only see the
|
||||
-- oak wood nodes in the water, but no hut. :-/
|
||||
mcl_structures.call_struct(place, "witch_hut", r, pr)
|
||||
|
||||
-- TODO: Spawn witch in or around hut when the mob sucks less.
|
||||
|
||||
local function place_tree_if_free(pos, prev_result)
|
||||
local nn = minetest.get_node(pos).name
|
||||
if nn == "mcl_flowers:waterlily" or nn == "mcl_core:water_source" or nn == "mcl_core:water_flowing" or nn == "air" then
|
||||
minetest.set_node(pos, {name="mcl_core:tree", param2=0})
|
||||
return prev_result
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local offsets = witch_hut_offsets[r]
|
||||
for o=1, #offsets do
|
||||
local ok = true
|
||||
for y=place.y-1, place.y-64, -1 do
|
||||
local tpos = vector.add(place, offsets[o])
|
||||
tpos.y = y
|
||||
ok = place_tree_if_free(tpos, ok)
|
||||
if not ok then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: Check spikes sizes, it looks like we have to swap them:
|
||||
|
||||
local function spawn_ice_spike_large(p, pr)
|
||||
-- Check surface
|
||||
local floor = {x=p.x+4, y=p.y-1, z=p.z+4}
|
||||
local surface = minetest_find_nodes_in_area({x=p.x+1,y=p.y-1,z=p.z+1}, floor, {"mcl_core:snowblock"})
|
||||
if #surface < 9 then return end
|
||||
|
||||
-- Check for collision with spruce
|
||||
local spruce_collisions = minetest_find_nodes_in_area({x=p.x+1,y=p.y+2,z=p.z+1}, {x=p.x+4, y=p.y+6, z=p.z+4}, {"mcl_core:sprucetree", "mcl_core:spruceleaves"})
|
||||
if #spruce_collisions > 0 then return end
|
||||
|
||||
mcl_structures.call_struct(p, "ice_spike_large", nil, pr)
|
||||
return true
|
||||
end
|
||||
|
||||
local function spawn_ice_spike_small(p, pr)
|
||||
-- Check surface
|
||||
local floor = {x=p.x+6, y=p.y-1, z=p.z+6}
|
||||
local surface = minetest_find_nodes_in_area({x=p.x+1,y=p.y-1,z=p.z+1}, floor, {"mcl_core:snowblock", "mcl_core:dirt_with_grass_snow"})
|
||||
if #surface < 25 then return end
|
||||
|
||||
-- Check for collision with spruce
|
||||
local spruce_collisions = minetest_find_nodes_in_area({x=p.x+1,y=p.y+1,z=p.z+1}, {x=p.x+6, y=p.y+6, z=p.z+6}, {"mcl_core:sprucetree", "mcl_core:spruceleaves"})
|
||||
|
||||
if #spruce_collisions > 0 then return end
|
||||
|
||||
mcl_structures.call_struct(p, "ice_spike_small", nil, pr)
|
||||
return true
|
||||
end
|
||||
|
||||
local function spawn_spikes_in_v6(p, nn, pr)
|
||||
-- In other mapgens, ice spikes are generated as decorations.
|
||||
-- if chunk_has_igloo or nn ~= "mcl_core:snowblock" then return end
|
||||
if nn ~= "mcl_core:snowblock" then return end
|
||||
local spike = pr:next(1,58000)
|
||||
if spike < 3 then
|
||||
return spawn_ice_spike_large(p, pr)
|
||||
elseif spike < 100 then
|
||||
return spawn_ice_spike_small(p, pr)
|
||||
end
|
||||
end
|
||||
|
||||
local function generate_structures(vm_context)
|
||||
|
||||
local levels = {
|
||||
[-9] = "black",
|
||||
[-8] = "brown",
|
||||
[-7] = "brown",
|
||||
[-6] = "gray",
|
||||
[-5] = "gray",
|
||||
[-4] = "red",
|
||||
[-3] = "orange",
|
||||
[-2] = "purple",
|
||||
[-1] = "magenta",
|
||||
[0] = "pink",
|
||||
[1] = "yellow",
|
||||
[2] = "green",
|
||||
[3] = "lime",
|
||||
[4] = "blue",
|
||||
[5] = "cyan",
|
||||
[6] = "light_blue",
|
||||
[7] = "silver",
|
||||
[8] = "silver",
|
||||
[9] = "white",
|
||||
}
|
||||
|
||||
-- local pr = PcgRandom(vm_context.blockseed)
|
||||
local pr = PcgRandom(vm_context.chunkseed)
|
||||
-- chunk_has_desert_struct = false
|
||||
-- chunk_has_desert_temple = false
|
||||
-- chunk_has_igloo = false
|
||||
local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
|
||||
perlin_structures = perlin_structures or minetest.get_perlin(329, 3, 0.6, 100)
|
||||
|
||||
-- Assume X and Z lengths are equal
|
||||
local DIVLEN = 5
|
||||
for x0 = minp.x, maxp.x, DIVLEN do for z0 = minp.z, maxp.z, DIVLEN do
|
||||
-- Determine amount from perlin noise
|
||||
local noise = perlin_structures:get_2d({x=x0, y=z0})
|
||||
local amount
|
||||
if noise < 0 then
|
||||
amount = math_ceil(noise * 9)
|
||||
else
|
||||
amount = math_floor(noise * 9)
|
||||
end
|
||||
-- local amount = math_floor(perlin_structures:get_2d({x=x0, y=z0}) * 9)
|
||||
|
||||
local y1 = maxp.y - 9 + amount
|
||||
for x1 = x0, x0 + DIVLEN - 1, 1 do for z1 = z0, z0 + DIVLEN - 1, 1 do
|
||||
if not levels[amount] then
|
||||
minetest.log("ERROR",tostring(amount))
|
||||
else
|
||||
minetest.set_node({x=x1, y=y1, z=z1}, {name = "mcl_core:glass_"..levels[amount]})
|
||||
end
|
||||
end end
|
||||
|
||||
-- Find random positions based on this random
|
||||
local p, ground_y, nn
|
||||
for i = 0, 24 do
|
||||
--for i=0, amount do
|
||||
-- p = {x = pr:next(x0, x0 + DIVLEN - 1), y = 0, z = pr:next(z0, z0 + DIVLEN - 1)}
|
||||
p = {x = x0 + i % 5, z = z0 + math_floor(i/5)}
|
||||
p, ground_y, nn = determine_ground_level(p, vm_context)
|
||||
if ground_y then
|
||||
p.y = ground_y + 1
|
||||
local nn0 = minetest.get_node(p).name
|
||||
-- Check if the node can be replaced
|
||||
if minetest.registered_nodes[nn0] and minetest.registered_nodes[nn0].buildable_to then
|
||||
--spawn_desert_temple(p, nn, pr, vm_context)
|
||||
--spawn_desert_well(p, nn, pr, vm_context)
|
||||
--spawn_igloo(p, nn, pr, vm_context)
|
||||
--spawn_fossil(p, nn, pr, vm_context)
|
||||
--spawn_witch_hut(p, nn, pr, vm_context)
|
||||
if V6 then
|
||||
spawn_spikes_in_v6(p, nn, pr, vm_context)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end end
|
||||
return vm_context
|
||||
end
|
||||
|
||||
local function generate_end_structures(vm_context)
|
||||
local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
if minp.y <= END_EXIT_PORTAL_POS.y and maxp.y >= END_EXIT_PORTAL_POS.y
|
||||
and minp.x <= END_EXIT_PORTAL_POS.x and maxp.x >= END_EXIT_PORTAL_POS.x
|
||||
and minp.z <= END_EXIT_PORTAL_POS.z and maxp.z >= END_EXIT_PORTAL_POS.z
|
||||
then
|
||||
local p = {x=END_EXIT_PORTAL_POS.x, z=END_EXIT_PORTAL_POS.z}
|
||||
for y = maxp.y, minp.y, -1 do
|
||||
p.y = y
|
||||
if minetest.get_node(p).name == "mcl_end:end_stone" then
|
||||
mcl_mapgen_core.generate_end_exit_portal(p)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return vm_context
|
||||
end
|
||||
|
||||
if not mcl_mapgen.singlenode then
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context)
|
||||
-- mcl_mapgen.register_on_generated(function(vm_context)
|
||||
-- local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
local minp, maxp = minp, maxp
|
||||
local minp_y, maxp_y = minp.y, maxp.y
|
||||
generate_structures(vm_context)
|
||||
-- if maxp_y >= OVERWORLD_STRUCT_MIN and minp_y <= OVERWORLD_STRUCT_MAX then
|
||||
-- return generate_structures(vm_context)
|
||||
-- End exit portal
|
||||
-- elseif maxp_y >= END_STRUCT_MIN and minp_y <= END_STRUCT_MAX then
|
||||
-- return generate_end_structures(vm_context)
|
||||
-- end
|
||||
-- return vm_context
|
||||
end)
|
||||
end
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
-- Check it:
|
||||
-- seed 1, v7 mapgen
|
||||
-- /teleport 14958,8,11370
|
||||
|
||||
local mcl_mapgen_get_far_node = mcl_mapgen.get_far_node
|
||||
local minetest_log = minetest.log
|
||||
local minetest_place_schematic = minetest.place_schematic
|
||||
local minetest_pos_to_string = minetest.pos_to_string
|
||||
local minetest_swap_node = minetest.swap_node
|
||||
|
||||
local path = minetest.get_modpath("mcl_ocean_monument") .. "/schematics/ocean_monument.mts"
|
||||
|
||||
local water = "mcl_core:water_source"
|
||||
local air = "air"
|
||||
local ice = "mcl_core:ice"
|
||||
|
||||
local leg_materials = {
|
||||
"mcl_ocean:prismarine_brick",
|
||||
"mcl_ocean:prismarine",
|
||||
}
|
||||
local what_we_can_replace_by_legs = {
|
||||
water,
|
||||
air,
|
||||
"mcl_core:water_flowing",
|
||||
"mcl_core:stone",
|
||||
}
|
||||
|
||||
local leg_search_quick_index = {}
|
||||
for _, v in pairs(leg_materials) do
|
||||
leg_search_quick_index[v] = true
|
||||
end
|
||||
|
||||
local leg_replace_quick_index = {}
|
||||
for _, v in pairs(what_we_can_replace_by_legs) do
|
||||
leg_replace_quick_index[v] = true
|
||||
end
|
||||
|
||||
local y_wanted = mcl_mapgen.OFFSET_NODES -- supposed to be -32
|
||||
local y_bottom = mcl_mapgen.overworld.min -- -62
|
||||
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, seed)
|
||||
local minp = minp
|
||||
local y = minp.y
|
||||
if y ~= y_wanted then return end
|
||||
|
||||
local x, z = minp.x, minp.z
|
||||
local pr = PseudoRandom(seed)
|
||||
|
||||
-- scan the ocean - it should be the ocean:
|
||||
for i = 1, pr:next(10, 100) do
|
||||
local pos = {x = pr:next(15, 64) + x, y = pr:next(0, 25) - 25, z = pr:next(15, 64) + z}
|
||||
local node_name = mcl_mapgen_get_far_node(pos).name
|
||||
if node_name ~= water then return end
|
||||
end
|
||||
|
||||
-- scan nodes above water level - there should be the air:
|
||||
for i = 1, pr:next(10, 100) do
|
||||
local pos = {x = pr:next(0, 79) + x, y = 2, z = pr:next(0,79) + z}
|
||||
local node_name = mcl_mapgen_get_far_node(pos).name
|
||||
if node_name ~= air then return end
|
||||
end
|
||||
|
||||
-- scan ocean surface - allow only water and ice:
|
||||
for i = 1, pr:next(10,100) do
|
||||
local pos = {x=pr:next(0, 79)+x, y=1, z=pr:next(0,79)+z}
|
||||
local node_name = mcl_mapgen_get_far_node(pos).name
|
||||
if node_name ~= water and node_name ~= ice then return end
|
||||
end
|
||||
|
||||
-- random rotation:
|
||||
local rotation = pr:next(0, 3)
|
||||
local rotation_str = tostring(rotation * 90)
|
||||
minetest_place_schematic(minp, path, rotation_str, nil, true)
|
||||
|
||||
-- search prismarine legs at base level and continue them up to the bottom:
|
||||
for x = x, maxp.x do
|
||||
for z = z, maxp.z do
|
||||
local pos = {x = x, y = y, z = z}
|
||||
local node_name = mcl_mapgen_get_far_node(pos).name
|
||||
if leg_search_quick_index[node_name] then
|
||||
local node_leg = {name = node_name}
|
||||
for y = y - 1, y_bottom, -1 do
|
||||
pos.y = y
|
||||
local next_name = mcl_mapgen_get_far_node(pos).name
|
||||
if not leg_replace_quick_index[next_name] then
|
||||
break
|
||||
end
|
||||
minetest_swap_node(pos, node_leg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest_log("action", "[mcl_ocean_monument] Placed at " .. minetest_pos_to_string(minp) .. ", " .. rotation_str .. " deg.")
|
||||
|
||||
end, mcl_mapgen.order.OCEAN_MONUMENT)
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_ocean_monument
|
||||
author = TrashPanda
|
||||
description = Adds Ocean Monument, https://git.minetest.land/MineClone2/MineClone2/issues/958#issuecomment-14102
|
||||
depends = mcl_mapgen, mcl_structures
|
Binary file not shown.
|
@ -18,8 +18,7 @@ local stronghold_rings = {
|
|||
local strongholds = {}
|
||||
local strongholds_inited = false
|
||||
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
local superflat = mcl_mapgen.superflat
|
||||
|
||||
-- Determine the stronghold positions and store them into the strongholds table.
|
||||
-- The stronghold positions are based on the world seed.
|
||||
|
@ -30,7 +29,7 @@ local function init_strongholds()
|
|||
return
|
||||
end
|
||||
-- Don't generate strongholds in singlenode
|
||||
if mg_name == "singlenode" then
|
||||
if mcl_mapgen.singlenode then
|
||||
strongholds_inited = true
|
||||
return
|
||||
end
|
||||
|
@ -47,9 +46,9 @@ local function init_strongholds()
|
|||
local dist = pr:next(ring.min, ring.max)
|
||||
local y
|
||||
if superflat then
|
||||
y = mcl_vars.mg_bedrock_overworld_max + 3
|
||||
y = mcl_mapgen.overworld.bedrock_max + 3
|
||||
else
|
||||
y = pr:next(mcl_vars.mg_bedrock_overworld_max+1, mcl_vars.mg_overworld_min+48)
|
||||
y = pr:next(mcl_mapgen.overworld.bedrock_max+1, mcl_mapgen.overworld.bedrock_min+48)
|
||||
end
|
||||
local pos = { x = math.cos(angle) * dist, y = y, z = math.sin(angle) * dist }
|
||||
pos = vector.round(pos)
|
||||
|
@ -66,8 +65,10 @@ local function init_strongholds()
|
|||
strongholds_inited = true
|
||||
end
|
||||
|
||||
init_strongholds()
|
||||
|
||||
-- Stronghold generation for register_on_generated.
|
||||
local function generate_strongholds(minp, maxp, blockseed)
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, blockseed)
|
||||
local pr = PseudoRandom(blockseed)
|
||||
for s=1, #strongholds do
|
||||
if not strongholds[s].generated then
|
||||
|
@ -99,8 +100,4 @@ local function generate_strongholds(minp, maxp, blockseed)
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
init_strongholds()
|
||||
|
||||
mcl_mapgen_core.register_generator("strongholds", nil, generate_strongholds, 999999)
|
||||
end, mcl_mapgen.order.STRONGHOLDS)
|
||||
|
|
|
@ -38,7 +38,9 @@ function mcl_structures.place_schematic(pos, schematic, rotation, replacements,
|
|||
local p2 = {x=pos.x+x-1, y=pos.y+s.size.y-1, z=pos.z+z-1}
|
||||
minetest.log("verbose", "[mcl_structures] size=" ..minetest.pos_to_string(s.size) .. ", rotation=" .. tostring(rotation) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
local param = {pos=vector.new(pos), schematic=s, rotation=rotation, replacements=replacements, force_placement=force_placement, flags=flags, p1=p1, p2=p2, after_placement_callback = after_placement_callback, size=vector.new(s.size), pr=pr, callback_param=callback_param}
|
||||
minetest.emerge_area(p1, p2, ecb_place, param)
|
||||
-- minetest.emerge_area(p1, p2, ecb_place, param)
|
||||
-- TODO: Make it better
|
||||
ecb_place(0, 0, 0, param)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -69,7 +71,7 @@ local function init_node_construct(pos)
|
|||
end
|
||||
|
||||
-- The call of Struct
|
||||
function mcl_structures.call_struct(pos, struct_style, rotation, pr)
|
||||
function mcl_structures.call_struct(pos, struct_style, rotation, pr, callback)
|
||||
minetest.log("action","[mcl_structures] call_struct " .. struct_style.." at "..minetest.pos_to_string(pos))
|
||||
if not rotation then
|
||||
rotation = "random"
|
||||
|
@ -91,13 +93,31 @@ function mcl_structures.call_struct(pos, struct_style, rotation, pr)
|
|||
elseif struct_style == "fossil" then
|
||||
return mcl_structures.generate_fossil(pos, rotation, pr)
|
||||
elseif struct_style == "end_exit_portal" then
|
||||
return mcl_structures.generate_end_exit_portal(pos, rotation)
|
||||
return mcl_structures.generate_end_exit_portal(pos, rotation, pr, callback)
|
||||
elseif struct_style == "end_exit_portal_open" then
|
||||
return mcl_structures.generate_end_exit_portal_open(pos, rotation)
|
||||
elseif struct_style == "end_gateway_portal" then
|
||||
return mcl_structures.generate_end_gateway_portal(pos, rotation)
|
||||
elseif struct_style == "end_portal_shrine" then
|
||||
return mcl_structures.generate_end_portal_shrine(pos, rotation, pr)
|
||||
elseif struct_style == "end_portal" then
|
||||
return mcl_structures.generate_end_portal(pos, rotation, pr)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_structures.generate_end_portal(pos, rotation, pr)
|
||||
-- todo: proper facedir
|
||||
local x0, y0, z0 = pos.x - 2, pos.y, pos.z - 2
|
||||
for x = 0, 4 do
|
||||
for z = 0, 4 do
|
||||
if x % 4 == 0 or z % 4 == 0 then
|
||||
if x % 4 ~= 0 or z % 4 ~= 0 then
|
||||
minetest.swap_node({x = x0 + x, y = y0, z = z0 + z}, {name = "mcl_portals:end_portal_frame_eye"})
|
||||
end
|
||||
else
|
||||
minetest.swap_node({x = x0 + x, y = y0, z = z0 + z}, {name = "mcl_portals:portal_end"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -115,14 +135,14 @@ function mcl_structures.generate_igloo(pos, rotation, pr)
|
|||
if r == 1 then
|
||||
-- Select basement depth
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
--local buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10)
|
||||
--local buffer = pos.y - (mcl_mapgen.overworld.lava_max + 10)
|
||||
local buffer
|
||||
if dim == "nether" then
|
||||
buffer = pos.y - (mcl_vars.mg_lava_nether_max + 10)
|
||||
elseif dim == "end" then
|
||||
buffer = pos.y - (mcl_vars.mg_end_min + 1)
|
||||
elseif dim == "overworld" then
|
||||
buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10)
|
||||
buffer = pos.y - (mcl_mapgen.overworld.lava_max + 10)
|
||||
else
|
||||
return success
|
||||
end
|
||||
|
@ -284,7 +304,7 @@ local function hut_placement_callback(p1, p2, size, orientation, pr)
|
|||
if not p1 or not p2 then return end
|
||||
local legs = minetest.find_nodes_in_area(p1, p2, "mcl_core:tree")
|
||||
for i = 1, #legs do
|
||||
while minetest.get_item_group(mcl_vars.get_node({x=legs[i].x, y=legs[i].y-1, z=legs[i].z}, true, 333333).name, "water") ~= 0 do
|
||||
while minetest.get_item_group(mcl_mapgen.get_far_node({x=legs[i].x, y=legs[i].y-1, z=legs[i].z}, true, 333333).name, "water") ~= 0 do
|
||||
legs[i].y = legs[i].y - 1
|
||||
minetest.swap_node(legs[i], {name = "mcl_core:tree", param2 = 2})
|
||||
end
|
||||
|
@ -324,9 +344,9 @@ function mcl_structures.generate_fossil(pos, rotation, pr)
|
|||
return mcl_structures.place_schematic(newpos, path, rotation or "random", nil, true)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_end_exit_portal(pos, rot)
|
||||
function mcl_structures.generate_end_exit_portal(pos, rot, pr, callback)
|
||||
local path = modpath.."/schematics/mcl_structures_end_exit_portal.mts"
|
||||
return mcl_structures.place_schematic(pos, path, rot or "0", {["mcl_portals:portal_end"] = "air"}, true)
|
||||
return mcl_structures.place_schematic(pos, path, rot or "0", {["mcl_portals:portal_end"] = "air"}, true, nil, callback)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_end_exit_portal_open(pos, rot)
|
||||
|
@ -556,7 +576,7 @@ end
|
|||
|
||||
-- Debug command
|
||||
minetest.register_chatcommand("spawnstruct", {
|
||||
params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_exit_portal_open | end_gateway_portal | end_portal_shrine | nether_portal | dungeon",
|
||||
params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_exit_portal_open | end_gateway_portal | end_portal_shrine | end_portal | nether_portal | dungeon",
|
||||
description = S("Generate a pre-defined structure near your position."),
|
||||
privs = {debug = true},
|
||||
func = function(name, param)
|
||||
|
@ -596,6 +616,8 @@ minetest.register_chatcommand("spawnstruct", {
|
|||
mcl_structures.generate_end_portal_shrine(pos, rot, pr)
|
||||
elseif param == "dungeon" and mcl_dungeons and mcl_dungeons.spawn_dungeon then
|
||||
mcl_dungeons.spawn_dungeon(pos, rot, pr)
|
||||
elseif param == "end_portal" then
|
||||
mcl_structures.generate_end_portal(pos, rot, pr)
|
||||
elseif param == "nether_portal" and mcl_portals and mcl_portals.spawn_nether_portal then
|
||||
mcl_portals.spawn_nether_portal(pos, rot, pr, name)
|
||||
elseif param == "" then
|
||||
|
|
|
@ -88,7 +88,7 @@ function settlements.create_site_plan(maxp, minp, pr)
|
|||
-- find center_surface of chunk
|
||||
local center_surface , surface_material = settlements.find_surface(center, true)
|
||||
local chunks = {}
|
||||
chunks[mcl_vars.get_chunk_number(center)] = true
|
||||
chunks[mcl_mapgen.get_chunk_number(center)] = true
|
||||
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
|
@ -124,7 +124,7 @@ function settlements.create_site_plan(maxp, minp, pr)
|
|||
ptx = settlements.round(ptx, 0)
|
||||
ptz = settlements.round(ptz, 0)
|
||||
local pos1 = { x=ptx, y=center_surface.y+50, z=ptz}
|
||||
local chunk_number = mcl_vars.get_chunk_number(pos1)
|
||||
local chunk_number = mcl_mapgen.get_chunk_number(pos1)
|
||||
local pos_surface, surface_material
|
||||
if chunks[chunk_number] then
|
||||
pos_surface, surface_material = settlements.find_surface(pos1)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
settlements = {}
|
||||
settlements.modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
local minetest_get_spawn_level = minetest.get_spawn_level
|
||||
|
||||
dofile(settlements.modpath.."/const.lua")
|
||||
dofile(settlements.modpath.."/utils.lua")
|
||||
dofile(settlements.modpath.."/foundation.lua")
|
||||
|
@ -53,6 +55,7 @@ end
|
|||
-- on map generation, try to build a settlement
|
||||
--
|
||||
local function build_a_settlement(minp, maxp, blockseed)
|
||||
minetest.log("action","[mcl_villages] Building village at mapchunk " .. minetest.pos_to_string(minp) .. "..." .. minetest.pos_to_string(maxp) .. ", blockseed = " .. tostring(blockseed))
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
-- fill settlement_info with buildings and their data
|
||||
|
@ -69,29 +72,38 @@ local function build_a_settlement(minp, maxp, blockseed)
|
|||
settlements.place_schematics(settlement_info, pr)
|
||||
end
|
||||
|
||||
local function ecb_village(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
local minp, maxp, blockseed = param.minp, param.maxp, param.blockseed
|
||||
build_a_settlement(minp, maxp, blockseed)
|
||||
end
|
||||
|
||||
-- Disable natural generation in singlenode.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if mg_name ~= "singlenode" then
|
||||
mcl_mapgen_core.register_generator("villages", nil, function(minp, maxp, blockseed)
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, blockseed)
|
||||
-- local str1 = (maxp.y >= 0 and blockseed % 77 == 17) and "YES" or "no"
|
||||
-- minetest.log("action","[mcl_villages] " .. str1 .. ": minp=" .. minetest.pos_to_string(minp) .. ", maxp=" .. minetest.pos_to_string(maxp) .. ", blockseed=" .. tostring(blockseed))
|
||||
-- don't build settlement underground
|
||||
if maxp.y < 0 then return end
|
||||
-- randomly try to build settlements
|
||||
if blockseed % 77 ~= 17 then return end
|
||||
-- needed for manual and automated settlement building
|
||||
|
||||
-- don't build settlements on (too) uneven terrain
|
||||
--local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
local height_difference = settlements.evaluate_heightmap()
|
||||
|
||||
-- lame and quick replacement of `heightmap` by kay27 - we maybe need to restore `heightmap` analysis if there will be a way for the engine to avoid cavegen conflicts:
|
||||
--------------------------------------------------------------------------
|
||||
local height_difference, min, max
|
||||
local pr1=PseudoRandom(blockseed)
|
||||
for i=1,pr1:next(5,10) do
|
||||
local x = pr1:next(0, 40) + minp.x + 19
|
||||
local z = pr1:next(0, 40) + minp.z + 19
|
||||
local y = minetest_get_spawn_level(x, z)
|
||||
if not y then return end
|
||||
if y < (min or y+1) then min = y end
|
||||
if y > (max or y-1) then max = y end
|
||||
end
|
||||
height_difference = max - min + 1
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
if height_difference > max_height_difference then return end
|
||||
|
||||
local param={minp=vector.new(minp), maxp=vector.new(maxp), blockseed=blockseed}
|
||||
minetest.emerge_area(minp, maxp, ecb_village, param)
|
||||
end)
|
||||
build_a_settlement(minp, maxp, blockseed)
|
||||
end, mcl_mapgen.order.VILLAGES)
|
||||
end
|
||||
-- manually place villages
|
||||
if minetest.is_creative_enabled("") then
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
local get_node = mcl_vars.get_node
|
||||
local get_node = mcl_mapgen.get_far_node
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to copy tables
|
||||
|
@ -207,44 +207,6 @@ function shuffle(tbl, pr)
|
|||
return table
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate heightmap
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.evaluate_heightmap()
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
-- max height and min height, initialize with impossible values for easier first time setting
|
||||
local max_y = -50000
|
||||
local min_y = 50000
|
||||
-- only evaluate the center square of heightmap 40 x 40
|
||||
local square_start = 1621
|
||||
local square_end = 1661
|
||||
for j = 1 , 40, 1 do
|
||||
for i = square_start, square_end, 1 do
|
||||
-- skip buggy heightmaps, return high value
|
||||
if heightmap[i] == -31000 or heightmap[i] == 31000 then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
if heightmap[i] < min_y then
|
||||
min_y = heightmap[i]
|
||||
end
|
||||
if heightmap[i] > max_y then
|
||||
max_y = heightmap[i]
|
||||
end
|
||||
end
|
||||
-- set next line
|
||||
square_start = square_start + 80
|
||||
square_end = square_end + 80
|
||||
end
|
||||
-- return the difference between highest and lowest pos in chunk
|
||||
local height_diff = max_y - min_y
|
||||
-- filter buggy heightmaps
|
||||
if height_diff <= 1 then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
-- debug info
|
||||
settlements.debug("heightdiff ".. height_diff)
|
||||
return height_diff
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
|
|
|
@ -19,8 +19,7 @@ end
|
|||
local probability_railcaves_in_mapchunk = P(0.33333)
|
||||
setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_railcaves_in_mapchunk"))
|
||||
-- Extra check to prevent mod griefing in singlenode, mcimported worlds.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if mg_name == "singlenode" then
|
||||
if mcl_mapgen.singlenode then
|
||||
probability_railcaves_in_mapchunk = P(0)
|
||||
elseif setting then
|
||||
probability_railcaves_in_mapchunk = P(setting)
|
||||
|
@ -96,10 +95,10 @@ end
|
|||
|
||||
-- Max. and min. heights between rail corridors are generated
|
||||
local height_min
|
||||
if mcl_vars.mg_lava then
|
||||
height_min = mcl_vars.mg_lava_overworld_max + 2
|
||||
if mcl_mapgen.lava then
|
||||
height_min = mcl_mapgen.overworld.lava_max + 2
|
||||
else
|
||||
height_min = mcl_vars.mg_bedrock_overworld_max + 2
|
||||
height_min = mcl_mapgen.overworld.bedrock_max + 2
|
||||
end
|
||||
local height_max = mcl_worlds.layer_to_y(60)
|
||||
|
||||
|
@ -1093,7 +1092,7 @@ local function create_corridor_system(main_cave_coords)
|
|||
end
|
||||
|
||||
-- The rail corridor algorithm starts here
|
||||
mcl_mapgen_core.register_generator("railcorridors", nil, function(minp, maxp, blockseed, _pr)
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, blockseed)
|
||||
-- We re-init the randomizer for every mapchunk as we start generating in the middle of each mapchunk.
|
||||
-- We can't use the mapgen seed as this would make the algorithm depending on the order the mapchunk generate.
|
||||
InitRandomizer(blockseed)
|
||||
|
|
|
@ -81,7 +81,7 @@ local dir_step = storage:get_int("mcl_spawn_dir_step") or 0
|
|||
local dir_ind = storage:get_int("mcl_spawn_dir_ind") or 1
|
||||
local emerge_pos1, emerge_pos2
|
||||
|
||||
local spawn_limit = mcl_vars.mapgen_edge_max
|
||||
local spawn_limit = mcl_mapgen.EDGE_MAX
|
||||
|
||||
|
||||
--Functions
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_spawn
|
||||
author = Wuzzy
|
||||
description = Set and get the player's respawn position
|
||||
depends = mcl_init
|
||||
depends = mcl_mapgen
|
||||
|
|
Loading…
Reference in New Issue