Merge remote-tracking branch 'origin/testing' into compatibility

This commit is contained in:
kay27 2022-02-01 06:45:10 +04:00
commit fda5aa1395
15 changed files with 692 additions and 688 deletions

View File

@ -1,101 +1,120 @@
# mcl_mapgen # mcl_mapgen
============ ------------
Helps to avoid problems caused by 'chunk-in-shell' feature of mapgen.cpp. Helps to avoid problems caused by 'chunk-in-shell' feature of mapgen.cpp.
It also queues your generators to run them in proper order: It also queues your generators to run them in proper order:
### mcl_mapgen.register_on_generated(lvm_callback_function, order_number) ### mcl_mapgen.register_on_generated(lvm_callback_function, order_number)
========================================================================= -------------------------------------------------------------------------
Replacement of engine API function `minetest.register_on_generated(function(vm_context))` 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. 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. 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. For Minetest 5.4 it doesn't recommended to place blocks within lvm callback function.
See https://git.minetest.land/MineClone2/MineClone2/issues/1395 See https://git.minetest.land/MineClone2/MineClone2/issues/1395
`lvm_callback_function`: chunk callback LVM function definition:
`function(vm_context)`: * `lvm_callback_function`: chunk callback LVM function definition:
`vm_context` will pass into next lvm callback function from the queue! * `function(vm_context)`:
`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_context` will pass into next lvm callback function from the queue!
`vm`: curent voxel manipulator object itself; * `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:
`chunkseed`: seed of this mapchunk; * `vm`: curent voxel manipulator object itself;
`minp` & `maxp`: minimum and maximum chunk position; * `chunkseed`: seed of this mapchunk;
`emin` & `emax`: minimum and maximum chunk position WITH SHELL AROUND IT; * `minp` & `maxp`: minimum and maximum chunk position;
`area`: voxel area, can be helpful to access data; * `emin` & `emax`: minimum and maximum chunk position WITH SHELL AROUND IT;
`data`: LVM buffer data array, data loads into it before the callbacks; * `area`: voxel area, can be helpful to access data;
`write`: set it to true in your lvm callback functionm, if you changed `data` and want to write it; * `data`: LVM buffer data array, data loads into it before the callbacks;
`param2_data`: LVM buffer data array of `param2`, !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - you load it yourself: * `write`: set it to true in your lvm callback functionm, if you changed `data` and want to write it;
`vm_context.param2_data = vm_context.param2_data or vm_context.vm:get_param2_data(vm_context.lvm_param2_buffer)` * `param2_data`: LVM buffer data array of `param2`, *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - you load it yourself:
`write_param2`: set it to true in your lvm callback function, if you used `param2_data` and want to write it; * `vm_context.param2_data = vm_context.param2_data or vm_context.vm:get_param2_data(vm_context.lvm_param2_buffer)`
`light`: LVM buffer data array of light, !NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - you load it yourself: * `write_param2`: set it to true in your lvm callback function, if you used `param2_data` and want to write it;
`vm_context.light = vm_context.light or vm_context.vm.get_light_data(vm_context.lvm_light_buffer)` * `light`: LVM buffer data array of light, *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - you load it yourself:
`write_light`: set it to true in your lvm callback function, if you used `light` and want to write it; * `vm_context.light = vm_context.light or vm_context.vm.get_light_data(vm_context.lvm_light_buffer)`
`lvm_param2_buffer`: static `param2` buffer pointer, used to load `param2_data` array; * `write_light`: set it to true in your lvm callback function, if you used `light` and want to write it;
`shadow`: set it to false to disable shadow propagation; * `lvm_param2_buffer`: static `param2` buffer pointer, used to load `param2_data` array;
`heightmap`: mapgen object contanting y coordinates of ground level, * `shadow`: set it to false to disable shadow propagation;
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself: * `heightmap`: mapgen object contanting y coordinates of ground level,
`vm_context.heightmap = vm_context.heightmap or minetest.get_mapgen_object('heightmap')` * *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
`biomemap`: mapgen object contanting biome IDs of nodes, * `vm_context.heightmap = vm_context.heightmap or minetest.get_mapgen_object('heightmap')`
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself: * `biomemap`: mapgen object contanting biome IDs of nodes,
`vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object('biomemap')` * *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
`heatmap`: mapgen object contanting temperature values of nodes, * `vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object('biomemap')`
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself: * `heatmap`: mapgen object contanting temperature values of nodes,
`vm_context.heatmap = vm_context.heatmap or minetest.get_mapgen_object('heatmap')` * *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
`humiditymap`: mapgen object contanting humidity values of nodes, * `vm_context.heatmap = vm_context.heatmap or minetest.get_mapgen_object('heatmap')`
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself: * `humiditymap`: mapgen object contanting humidity values of nodes,
`vm_context.humiditymap = vm_context.humiditymap or minetest.get_mapgen_object('humiditymap')` * *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
`gennotify`: mapgen object contanting mapping table of structures, see Minetest Lua API for explanation, * `vm_context.humiditymap = vm_context.humiditymap or minetest.get_mapgen_object('humiditymap')`
!NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS! - load it yourself: * `gennotify`: mapgen object contanting mapping table of structures, see Minetest Lua API for explanation,
`vm_context.gennotify = vm_context.gennotify or minetest.get_mapgen_object('gennotify')` * *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
`order_number` (optional): the less, the earlier, * `vm_context.gennotify = vm_context.gennotify or minetest.get_mapgen_object('gennotify')`
e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS` * `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) ### 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. 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. `vm_context` passes into lvm callback function.
`lvm_callback_function`: the block callback LVM function definition - same as for chunks - see definition example above; * `lvm_callback_function`: the block callback LVM function definition - same as for chunks - see definition example above;
`order_number` (optional): the less, the earlier, * `order_number` (optional): the less, the earlier,
e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS` * e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
### mcl_mapgen.register_mapgen_block(node_callback_function, order_number) ### 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. 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: * `node_callback_function`: node callback function definition:
`function(minp, maxp, seed)`: * `function(minp, maxp, seed)`:
`minp` & `maxp`: minimum and maximum block position; * `minp` & `maxp`: minimum and maximum block position;
`seed`: seed of this mapblock; * `seed`: seed of this mapblock;
`order_number` (optional): the less, the earlier, * `order_number` (optional): the less, the earlier,
e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS` * e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
### mcl_mapgen.register_mapgen(callback_function, order_number) ### mcl_mapgen.register_mapgen(callback_function, order_number)
==================================================================== ---------------------------------------------------------------
Registers callback function to be called when current chunk generation is REALLY 100% finished. 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. 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. It can't provide you access to mapgen objects. They are probably gone long ago.
Don't use it for accessing mapgen objects please. Don't use it for accessing mapgen objects please.
To use VM you have to run `vm_context.vm = mcl_mapgen.get_voxel_manip(vm_context.emin, vm_context.emax)`. To use VM you have to run `vm_context.vm = mcl_mapgen.get_voxel_manip(vm_context.emin, vm_context.emax)`.
Set * `callback_function`: callback function definition:
`callback_function`: callback function definition: * `function(minp, maxp, seed, vm_context)`:
`function(minp, maxp, seed, vm_context)`: * `minp` & `maxp`: minimum and maximum block position;
`minp` & `maxp`: minimum and maximum block position; * `seed`: seed of this mapblock;
`seed`: seed of this mapblock; * `vm_context`: a table - see description above.
`vm_context`: a table - see description above. * `order_number` (optional): the less, the earlier.
`order_number` (optional): the less, the earlier.
### mcl_mapgen.register_mapgen_lvm(lvm_callback_function, order_number) ### 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. 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. 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. Don't use it for accessing mapgen objects please.
`vm_context` passes into lvm callback function. `vm_context` passes into lvm callback function.
`lvm_callback_function`: the block callback LVM function definition - same as above; * `lvm_callback_function`: the block callback LVM function definition - same as above;
`order_number` (optional): the less, the earlier. * `order_number` (optional): the less, the earlier.
### mcl_mapgen.get_far_node(pos) ### mcl_mapgen.get_far_node(pos)
================================ --------------------------------
Returns node if it is generated, otherwise returns `{name = "ignore"}`. Returns node if it is generated, otherwise returns `{name = "ignore"}`.
## Constants: ### mcl_mapgen.clamp_to_chunk(x, size)
--------------------------------------
Returns new `x`, slighty tuned to make structure of size `size` be within single chunk side of 80 nodes.
* `mcl_mapgen.EDGE_MIN`, `mcl_mapgen.EDGE_MAX` - world edges, min & max. ### function mcl_mapgen.get_chunk_beginning(x)
* `mcl_mapgen.seed`, `mcl_mapgen.name` - mapgen seed & name. ----------------------------------------------
* `mcl_mapgen.v6`, `mcl_mapgen.superflat`, `mcl_mapgen.singlenode` - is mapgen v6, superflat, singlenode. Returns chunk beginning of `x`. It is the same as `minp.axis` for per-chunk callbacks, but we don't always have `minp`.
* `mcl_mapgen.normal` is mapgen normal (not superflat or singlenode).
## 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).

View File

@ -52,13 +52,14 @@ local seed = minetest.get_mapgen_setting("seed")
mcl_mapgen.seed = seed mcl_mapgen.seed = seed
mcl_mapgen.name = minetest.get_mapgen_setting("mg_name") mcl_mapgen.name = minetest.get_mapgen_setting("mg_name")
mcl_mapgen.v6 = mcl_mapgen.name == "v6" 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.flat = mcl_mapgen.name == "flat"
mcl_mapgen.superflat = mcl_mapgen.flat and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
mcl_mapgen.singlenode = mcl_mapgen.name == "singlenode" mcl_mapgen.singlenode = mcl_mapgen.name == "singlenode"
mcl_mapgen.normal = not mcl_mapgen.superflat and not mcl_mapgen.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 local flat, superflat, singlenode, normal = mcl_mapgen.flat, 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"))) minetest_log("action", "[mcl_mapgen] Mapgen mode: " .. (normal and "normal" or (superflat and "superflat" or (flat and "flat" or "singlenode"))))
---------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------
-- Generator queues -- Generator queues
local queue_unsafe_engine = {} local queue_unsafe_engine = {}
@ -263,6 +264,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
end end
if #queue_unsafe_engine > 0 then if #queue_unsafe_engine > 0 then
vm_context.minp, vm_context.maxp = minp, maxp
for _, v in pairs(queue_unsafe_engine) do for _, v in pairs(queue_unsafe_engine) do
v.f(vm_context) v.f(vm_context)
end end
@ -430,14 +432,12 @@ else
nether.bedrock_top_min = nether.bedrock_top_max nether.bedrock_top_min = nether.bedrock_top_max
nether.lava_max = nether.min + 2 nether.lava_max = nether.min + 2
end end
if mcl_mapgen.name == "flat" then if superflat then
if superflat then nether.flat_floor = nether.bedrock_bottom_max + 4
nether.flat_floor = nether.bedrock_bottom_max + 4 nether.flat_ceiling = nether.bedrock_bottom_max + 52
nether.flat_ceiling = nether.bedrock_bottom_max + 52 elseif flat then
else nether.flat_floor = nether.lava_max + 4
nether.flat_floor = nether.lava_max + 4 nether.flat_ceiling = nether.lava_max + 52
nether.flat_ceiling = nether.lava_max + 52
end
end end
-- The End (surface at ca. Y = -27000) -- The End (surface at ca. Y = -27000)

View File

@ -1,5 +1,5 @@
local PARTICLES_COUNT_RAIN = 30 local PARTICLES_COUNT_RAIN = 100
local PARTICLES_COUNT_THUNDER = 45 local PARTICLES_COUNT_THUNDER = 300
local get_connected_players = minetest.get_connected_players local get_connected_players = minetest.get_connected_players
@ -19,6 +19,45 @@ mcl_weather.rain = {
init_done = false, init_done = false,
} }
local update_sound={}
local vel=math.random(0,3)
local falling_speed=math.random(10,15)
local size = math.random(1,3)
local psdef= {
amount = mcl_weather.rain.particles_count,
time=0,
minpos = vector.new(-6,3,-6),
maxpos = vector.new(6,15,6),
minvel = vector.new(-vel,-falling_speed,-vel),
maxvel = vector.new(vel,-falling_speed+vel,vel),
minacc = vector.new(0,0,0),
maxacc = vector.new(0,-0.4,0),
minexptime = 0.5,
maxexptime = 2,
minsize = size,
maxsize= size*2,
collisiondetection = true,
collision_removal = true,
vertical = true,
}
local psdef_backsplash= {
amount = 10,
time=0,
minpos = vector.new(-3,-1,-3),
maxpos = vector.new(3,0,3),
minvel = vector.new(-vel,falling_speed*2,-vel),
maxvel = vector.new(vel,falling_speed*2+vel,vel),
minacc = vector.new(0,0,0),
maxacc = vector.new(0,0,0),
minexptime = 0.1,
maxexptime = 0.2,
minsize = size*0.1,
maxsize= size*0.5,
collisiondetection = true,
collision_removal = true,
vertical = true,
}
local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png", "weather_pack_rain_raindrop_1.png"}
function mcl_weather.rain.sound_handler(player) function mcl_weather.rain.sound_handler(player)
return minetest.sound_play("weather_rain", { return minetest.sound_play("weather_rain", {
@ -44,42 +83,18 @@ function mcl_weather.rain.set_sky_box()
end end
end end
-- creating manually parctiles instead of particles spawner because of easier to control -- no no no NO NO f*.. no. no manual particle creatin' PLS!! this sends EVERY particle over the net.
-- spawn position.
function mcl_weather.rain.add_rain_particles(player) function mcl_weather.rain.add_rain_particles(player)
mcl_weather.rain.last_rp_count = 0 mcl_weather.rain.last_rp_count = mcl_weather.rain.particles_count
for i=mcl_weather.rain.particles_count, 1,-1 do for k,v in pairs(textures) do
local random_pos_x, random_pos_y, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player) psdef.texture=v
if mcl_weather.is_outdoor({x=random_pos_x, y=random_pos_y, z=random_pos_z}) then mcl_weather.add_spawner_player(player,"rain"..k,psdef)
mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1
minetest.add_particle({
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
velocity = {x=0, y=-10, z=0},
acceleration = {x=0, y=-30, z=0},
expirationtime = 1.0,
size = math.random(0.5, 3),
collisiondetection = true,
collision_removal = true,
vertical = true,
texture = mcl_weather.rain.get_texture(),
playername = player:get_player_name()
})
end
end end
end psdef_backsplash.texture=textures[math.random(1,#textures)]
local l=mcl_weather.add_spawner_player(player,"rainbacksplash",psdef_backsplash)
-- Simple random texture getter if l then
function mcl_weather.rain.get_texture() update_sound[player:get_player_name()]=true
local texture_name
local random_number = math.random()
if random_number > 0.33 then
texture_name = "weather_pack_rain_raindrop_1.png"
elseif random_number > 0.66 then
texture_name = "weather_pack_rain_raindrop_2.png"
else
texture_name = "weather_pack_rain_raindrop_3.png"
end end
return texture_name;
end end
-- register player for rain weather. -- register player for rain weather.
@ -89,6 +104,7 @@ function mcl_weather.rain.add_player(player)
local player_meta = {} local player_meta = {}
player_meta.origin_sky = {player:get_sky()} player_meta.origin_sky = {player:get_sky()}
mcl_weather.players[player:get_player_name()] = player_meta mcl_weather.players[player:get_player_name()] = player_meta
update_sound[player:get_player_name()]=true
end end
end end
@ -99,26 +115,15 @@ function mcl_weather.rain.remove_player(player)
if player_meta and player_meta.origin_sky then if player_meta and player_meta.origin_sky then
player:set_clouds({color="#FFF0F0E5"}) player:set_clouds({color="#FFF0F0E5"})
mcl_weather.players[player:get_player_name()] = nil mcl_weather.players[player:get_player_name()] = nil
update_sound[player:get_player_name()]=true
end end
end end
mcl_worlds.register_on_dimension_change(function(player, dimension)
if dimension ~= "overworld" and dimension ~= "void" then
mcl_weather.rain.remove_sound(player)
mcl_weather.rain.remove_player(player)
elseif dimension == "overworld" then
mcl_weather.rain.update_sound(player)
if mcl_weather.rain.raining then
mcl_weather.rain.add_rain_particles(player)
mcl_weather.rain.add_player(player)
end
end
end)
-- adds and removes rain sound depending how much rain particles around player currently exist. -- adds and removes rain sound depending how much rain particles around player currently exist.
-- have few seconds delay before each check to avoid on/off sound too often -- have few seconds delay before each check to avoid on/off sound too often
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance. -- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
function mcl_weather.rain.update_sound(player) function mcl_weather.rain.update_sound(player)
if not update_sound[player:get_player_name()] then return end
local player_meta = mcl_weather.players[player:get_player_name()] local player_meta = mcl_weather.players[player:get_player_name()]
if player_meta then if player_meta then
if player_meta.sound_updated and player_meta.sound_updated + 5 > minetest.get_gametime() then if player_meta.sound_updated and player_meta.sound_updated + 5 > minetest.get_gametime() then
@ -136,6 +141,7 @@ function mcl_weather.rain.update_sound(player)
player_meta.sound_updated = minetest.get_gametime() player_meta.sound_updated = minetest.get_gametime()
end end
update_sound[player:get_player_name()]=false
end end
-- rain sound removed from player. -- rain sound removed from player.
@ -158,7 +164,8 @@ function mcl_weather.rain.clear()
for _, player in pairs(get_connected_players()) do for _, player in pairs(get_connected_players()) do
mcl_weather.rain.remove_sound(player) mcl_weather.rain.remove_sound(player)
mcl_weather.rain.remove_player(player) mcl_weather.rain.remove_player(player)
end mcl_weather.remove_spawners_player(player)
end
end end
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
@ -177,8 +184,10 @@ function mcl_weather.rain.make_weather()
end end
for _, player in pairs(get_connected_players()) do for _, player in pairs(get_connected_players()) do
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then local pos=player:get_pos()
if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(pos) or not mcl_weather.is_outdoor(pos) then
mcl_weather.rain.remove_sound(player) mcl_weather.rain.remove_sound(player)
mcl_weather.remove_spawners_player(player)
return false return false
end end
mcl_weather.rain.add_player(player) mcl_weather.rain.add_player(player)
@ -190,8 +199,12 @@ end
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops -- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
function mcl_weather.rain.set_particles_mode(mode) function mcl_weather.rain.set_particles_mode(mode)
if mode == "thunder" then if mode == "thunder" then
psdef.amount=PARTICLES_COUNT_THUNDER
psdef_backsplash.amount=PARTICLES_COUNT_THUNDER
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
else else
psdef.amount=PARTICLES_COUNT_RAIN
psdef_backsplash.amount=PARTICLES_COUNT_RAIN
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
end end
end end

View File

@ -5,30 +5,25 @@ mcl_weather.snow = {}
mcl_weather.snow.particles_count = 15 mcl_weather.snow.particles_count = 15
mcl_weather.snow.init_done = false mcl_weather.snow.init_done = false
-- calculates coordinates and draw particles for snow weather local psdef= {
function mcl_weather.snow.add_snow_particles(player) amount = 99,
mcl_weather.rain.last_rp_count = 0 time = 0, --stay on til we turn it off
for i=mcl_weather.snow.particles_count, 1,-1 do minpos = vector.new(-15,-5,-15),
local random_pos_x, _, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player) maxpos =vector.new(15,10,15),
local random_pos_y = math.random() + math.random(player:get_pos().y - 1, player:get_pos().y + 7) minvel = vector.new(0,-1,0),
if minetest.get_node_light({x=random_pos_x, y=random_pos_y, z=random_pos_z}, 0.5) == 15 then maxvel = vector.new(0,-4,0),
mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1 minacc = vector.new(0,-1,0),
minetest.add_particle({ maxacc = vector.new(0,-4,0),
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z}, minexptime = 1,
velocity = {x = math.random(-100,100)*0.001, y = math.random(-300,-100)*0.004, z = math.random(-100,100)*0.001}, maxexptime = 1,
acceleration = {x = 0, y=0, z = 0}, minsize = 0.5,
expirationtime = 8.0, maxsize = 5,
size = 1, collisiondetection = true,
collisiondetection = true, collision_removal = true,
collision_removal = true, object_collision = true,
object_collision = false, vertical = true,
vertical = false, glow = 1
texture = mcl_weather.snow.get_texture(), }
playername = player:get_player_name()
})
end
end
end
function mcl_weather.snow.set_sky_box() function mcl_weather.snow.set_sky_box()
mcl_weather.skycolor.add_layer( mcl_weather.skycolor.add_layer(
@ -48,6 +43,7 @@ end
function mcl_weather.snow.clear() function mcl_weather.snow.clear()
mcl_weather.skycolor.remove_layer("weather-pack-snow-sky") mcl_weather.skycolor.remove_layer("weather-pack-snow-sky")
mcl_weather.snow.init_done = false mcl_weather.snow.init_done = false
mcl_weather.remove_all_spawners()
end end
-- Simple random texture getter -- Simple random texture getter
@ -74,10 +70,14 @@ minetest.register_globalstep(function(dtime)
end end
for _, player in pairs(get_connected_players()) do for _, player in pairs(get_connected_players()) do
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos()) or not mcl_weather.is_outdoor(player:get_pos())) then
mcl_weather.remove_spawners_player(player)
return false return false
end end
mcl_weather.snow.add_snow_particles(player) for i=1,2 do
psdef.texture="weather_pack_snow_snowflake"..i..".png"
mcl_weather.add_spawner_player(player,"snow"..i,psdef)
end
end end
end) end)

View File

@ -47,6 +47,35 @@ local function save_weather()
end end
minetest.register_on_shutdown(save_weather) minetest.register_on_shutdown(save_weather)
local particlespawners={}
function mcl_weather.add_spawner_player(pl,id,ps)
local name=pl:get_player_name()
if not particlespawners[name] then
particlespawners[name] = {}
end
if not particlespawners[name][id] then
ps.playername =name
ps.attached = pl
particlespawners[name][id]=minetest.add_particlespawner(ps)
return particlespawners[name][id]
end
end
function mcl_weather.remove_spawners_player(pl)
local name=pl:get_player_name()
if not particlespawners[name] then return end
for k,v in pairs(particlespawners[name]) do
minetest.delete_particlespawner(v)
end
particlespawners[name] = nil
return true
end
function mcl_weather.remove_all_spawners()
for k,v in pairs(minetest.get_connected_players()) do
mcl_weather.remove_spawners_player(v)
end
end
function mcl_weather.get_rand_end_time(min_duration, max_duration) function mcl_weather.get_rand_end_time(min_duration, max_duration)
local r local r
if min_duration and max_duration then if min_duration and max_duration then
@ -92,36 +121,6 @@ function mcl_weather.is_underwater(player)
return false return false
end end
-- trying to locate position for particles by player look direction for performance reason.
-- it is costly to generate many particles around player so goal is focus mainly on front view.
function mcl_weather.get_random_pos_by_player_look_dir(player)
local look_dir = player:get_look_dir()
local player_pos = player:get_pos()
local random_pos_x, random_pos_y, random_pos_z
if look_dir.x > 0 then
if look_dir.z > 0 then
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
else
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
end
else
if look_dir.z > 0 then
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
else
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
end
end
random_pos_y = math.random() + math.random(player_pos.y + 10, player_pos.y + 15)
return random_pos_x, random_pos_y, random_pos_z
end
local t, wci = 0, mcl_weather.check_interval local t, wci = 0, mcl_weather.check_interval
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)

View File

@ -248,7 +248,7 @@ function mcl_beds.register_bed(name, def)
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false, is_ground_content = false,
-- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks! -- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks!
groups = {handy = 1, flammable = 3, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1}, groups = {handy = 1, flammable = -1, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
_mcl_hardness = 0.2, _mcl_hardness = 0.2,
_mcl_blast_resistance = 1, _mcl_blast_resistance = 1,
sounds = def.sounds or default_sounds, sounds = def.sounds or default_sounds,
@ -275,5 +275,3 @@ function mcl_beds.register_bed(name, def)
doc.add_entry_alias("nodes", name.."_bottom", "nodes", name.."_top") doc.add_entry_alias("nodes", name.."_bottom", "nodes", name.."_top")
end end

View File

@ -116,7 +116,7 @@ end
-- Bow item, uncharged state -- Bow item, uncharged state
minetest.register_tool("mcl_bows:crossbow", { minetest.register_tool("mcl_bows:crossbow", {
description = S("Corssbow"), description = S("Crossbow"),
_tt_help = S("Launches arrows"), _tt_help = S("Launches arrows"),
_doc_items_longdesc = S("Bows are ranged weapons to shoot arrows at your foes.").."\n".. _doc_items_longdesc = S("Bows are ranged weapons to shoot arrows at your foes.").."\n"..
S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."), S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."),
@ -151,11 +151,11 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
}) })
minetest.register_tool("mcl_bows:crossbow_loaded", { minetest.register_tool("mcl_bows:crossbow_loaded", {
description = S("Corssbow"), description = S("Crossbow"),
_tt_help = S("Launches arrows"), _tt_help = S("Launches arrows"),
_doc_items_longdesc = S("Corssbow are ranged weapons to shoot arrows at your foes.").."\n".. _doc_items_longdesc = S("Crossbow is a ranged weapon to shoot arrows at your foes.").."\n"..
S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."), S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."),
_doc_items_usagehelp = S("To use the corssbow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to load an arrow into the chamber, then to shoot press left mouse."), _doc_items_usagehelp = S("To use the crossbow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to load an arrow into the chamber, then to shoot press left mouse."),
_doc_items_durability = BOW_DURABILITY, _doc_items_durability = BOW_DURABILITY,
inventory_image = "mcl_bows_crossbow_3.png", inventory_image = "mcl_bows_crossbow_3.png",
wield_scale = mcl_vars.tool_wield_scale, wield_scale = mcl_vars.tool_wield_scale,

View File

@ -37,7 +37,7 @@ local lava_fire=
{ x = 1, y = 1, z = 0}, { x = 1, y = 1, z = 0},
{ x = 1, y = 1, z = 1} { x = 1, y = 1, z = 1}
} }
local alldirs= local adjacents =
{ {
{ x =-1, y = 0, z = 0}, { x =-1, y = 0, z = 0},
{ x = 1, y = 0, z = 0}, { x = 1, y = 0, z = 0},
@ -87,7 +87,7 @@ else
end end
local function fire_timer(pos) local function fire_timer(pos)
minetest.get_node_timer(pos):start(math.random(3, 7)) minetest.get_node_timer(pos):start(math.random(15, 45))
end end
local function spawn_fire(pos, age) local function spawn_fire(pos, age)
@ -95,6 +95,23 @@ local function spawn_fire(pos, age)
minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z}) minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z})
end end
local function shuffle_adjacents()
for i = #adjacents, 1, -1 do
local r = math.random(i)
adjacents[i], adjacents[r] = adjacents[r], adjacents[i]
end
end
local function has_flammable(pos)
for k,v in pairs(adjacents) do
local p=vector.add(pos,v)
local n=minetest.get_node_or_nil(p)
if n and minetest.get_item_group(n.name, "flammable") ~= 0 then
return p
end
end
end
minetest.register_node("mcl_fire:fire", { minetest.register_node("mcl_fire:fire", {
description = S("Fire"), description = S("Fire"),
_doc_items_longdesc = fire_help, _doc_items_longdesc = fire_help,
@ -125,80 +142,12 @@ minetest.register_node("mcl_fire:fire", {
end end
end, end,
on_timer = function(pos) on_timer = function(pos)
local node = get_node(pos) local p=has_flammable(pos)
-- Age is a number from 0 to 15 and is increased every timer step. if not p or minetest.get_item_group(minetest.get_node(p).name, "flammable") == -1 then
-- "old" fire is more likely to be extinguished minetest.remove_node(pos)
local age = node.param2
local flammables = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
local below = get_node({x=pos.x, y=pos.z-1, z=pos.z})
local below_is_flammable = get_item_group(below.name, "flammable") > 0
-- Extinguish fire
if (not fire_enabled) and (math.random(1,3) == 1) then
remove_node(pos)
return return
end end
if age == 15 and not below_is_flammable then return true --restart timer
remove_node(pos)
return
elseif age > 3 and #flammables == 0 and not below_is_flammable and math.random(1,4) == 1 then
remove_node(pos)
return
end
local age_add = 1
-- If fire spread is disabled, we have to skip the "destructive" code
if (not fire_enabled) then
if age + age_add <= 15 then
node.param2 = age + age_add
set_node(pos, node)
end
-- Restart timer
fire_timer(pos)
return
end
-- Spawn fire to nearby flammable nodes
local is_next_to_flammable = find_node_near(pos, 2, {"group:flammable"}) ~= nil
if is_next_to_flammable and math.random(1,2) == 1 then
-- The fire we spawn copies the age of this fire.
-- This prevents fire from spreading infinitely far as the fire fire dies off
-- quicker the further it has spreaded.
local age_next = math.min(15, age + math.random(0, 1))
-- Select random type of fire spread
local burntype = math.random(1,2)
if burntype == 1 then
-- Spawn fire in air
local nodes = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
while #nodes > 0 do
local r = math.random(1, #nodes)
if find_node_near(nodes[r], 1, {"group:flammable"}) then
spawn_fire(nodes[r], age_next)
break
else
table.remove(nodes, r)
end
end
else
-- Burn flammable block
local nodes = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
if #nodes > 0 then
local r = math.random(1, #nodes)
local nn = get_node(nodes[r]).name
local ndef = minetest.registered_nodes[nn]
local fgroup = get_item_group(nn, "flammable")
if ndef and ndef._on_burn then
ndef._on_burn(nodes[r])
elseif fgroup ~= -1 then
spawn_fire(nodes[r], age_next)
end
end
end
end
-- Regular age increase
if age + age_add <= 15 then
node.param2 = age + age_add
set_node(pos, node)
end
-- Restart timer
fire_timer(pos)
end, end,
drop = "", drop = "",
sounds = {}, sounds = {},
@ -254,29 +203,8 @@ minetest.register_node("mcl_fire:eternal_fire", {
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true) minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end end
end, end,
on_timer = function(pos) -- light Nether portal (if possible)
if fire_enabled then
local airs = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
while #airs > 0 do
local r = math.random(1, #airs)
if find_node_near(airs[r], 1, {"group:flammable"}) then
local node = get_node(airs[r])
local age = node.param2
local age_next = math.min(15, age + math.random(0, 1))
spawn_fire(airs[r], age_next)
break
else
table.remove(airs, r)
end
end
end
-- Restart timer
fire_timer(pos)
end,
-- Start burning timer and light Nether portal (if possible)
on_construct = function(pos) on_construct = function(pos)
fire_timer(pos)
if has_mcl_portals then --Calling directly minetest.get_modpath consumes 4x more compute time if has_mcl_portals then --Calling directly minetest.get_modpath consumes 4x more compute time
mcl_portals.light_nether_portal(pos) mcl_portals.light_nether_portal(pos)
end end
@ -421,21 +349,39 @@ minetest.register_abm({
end, end,
}) })
--- Fire spread logic
-- Enable the following ABMs according to 'enable fire' setting -- A fire that is not adjacent to any flammable block does not spread, even to another flammable block within the normal range.
-- A fire block can turn any air block that is adjacent to a flammable block into a fire block. This can happen at a distance of up to one block downward, one block sideways (including diagonals), and four blocks upward of the original fire block (not the block the fire is on/next to).
-- Fire spreads from a still lava block similarly: any air block one above and up to one block sideways (including diagonals) or two above and two blocks sideways (including diagonals) that is adjacent to a flammable block may be turned into a fire block.
-- https://minecraft.fandom.com/wiki/Fire#Spread
local function has_flammable(pos) local function check_aircube(p1,p2)
local npos, node local nds=minetest.find_nodes_in_area(p1,p2,{"air"})
for n, v in ipairs(alldirs) do for k,v in pairs(nds) do
npos = vector.add(pos, v) if has_flammable(v) then return v end
node = get_node_or_nil(npos)
if node and node.name and get_item_group(node.name, "flammable") ~= 0 then
return npos
end
end end
return false return false
end end
local function get_ignitable(pos)
return check_aircube(vector.add(pos,vector.new(-1,-1,-1)),vector.add(pos,vector.new(1,4,1)))
end
local function get_ignitable_by_lava(pos)
return check_aircube(vector.add(pos,vector.new(-1,1,-1)),vector.add(pos,vector.new(1,1,1))) or check_aircube(vector.add(pos,vector.new(-2,2,-2)),vector.add(pos,vector.new(2,2,2))) or nil
end
local function add_fire_particle(pos,f)
minetest.add_particle({
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.25), z=f.z-pos.z},
expirationtime=1, size=1, collisiondetection=false,
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
})
end
-- Enable the following ABMs according to 'enable fire' setting
if not fire_enabled then if not fire_enabled then
-- Occasionally remove fire if fire disabled -- Occasionally remove fire if fire disabled
@ -451,62 +397,70 @@ if not fire_enabled then
else -- Fire enabled else -- Fire enabled
minetest.register_abm({
label = "Ignite flame",
nodenames ={"mcl_fire:fire","mcl_fire:eternal_fire"},
interval = 7,
chance = 12,
catch_up = false,
action = function(pos)
local p = get_ignitable(pos)
if p then
add_fire_particle(p,pos)
spawn_fire(p)
shuffle_adjacents()
end
end
})
-- Set fire to air nodes -- Set fire to air nodes
minetest.register_abm({ minetest.register_abm({
label = "Ignite fire by lava", label = "Ignite fire by lava",
nodenames = {"group:lava"}, nodenames = {"group:lava"},
neighbors = {"air"}, nodenames = {"mcl_core:lava_source","mcl_nether:nether_lava_source"},
neighbors = {"air","group:flammable"},
interval = 7, interval = 7,
chance = 3, chance = 3,
catch_up = false, catch_up = false,
action = function(pos) action = function(pos)
local i, dir, target, node, i2, f local p=get_ignitable_by_lava(pos)
i = math.random(1,9) if p then
dir = lava_fire[i] add_fire_particle(p,pos)
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z} spawn_fire(p)
node = get_node(target)
if not node or node.name ~= "air" then
i = ((i + math.random(0,7)) % 9) + 1
dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
node = get_node(target)
if not node or node.name ~= "air" then
return
end
end
i2 = math.random(1,15)
if i2 < 10 then
local dir2, target2, node2
dir2 = lava_fire[i2]
target2 = {x=target.x+dir2.x, y=target.y+dir2.y, z=target.z+dir2.z}
node2 = get_node(target2)
if node2 and node2.name == "air" then
f = has_flammable(target2)
if f then
minetest.after(1, spawn_fire, {x=target2.x, y=target2.y, z=target2.z})
minetest.add_particle({
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.7), z=f.z-pos.z},
expirationtime=1, size=1.5, collisiondetection=false,
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
})
return
end
end
end
f = has_flammable(target)
if f then
minetest.after(1, spawn_fire, {x=target.x, y=target.y, z=target.z})
minetest.add_particle({
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.25), z=f.z-pos.z},
expirationtime=1, size=1, collisiondetection=false,
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
})
end end
end, end,
}) })
-- Remove flammable nodes around basic flame
minetest.register_abm({
label = "Remove flammable nodes",
nodenames = {"mcl_fire:fire","mcl_fire:eternal_fire"},
neighbors = {"group:flammable"},
interval = 5,
chance = 18,
catch_up = false,
action = function(pos)
local p = has_flammable(pos)
if not p then
return
end
local nn = minetest.get_node(p).name
local def = minetest.registered_nodes[nn]
local fgroup = minetest.get_item_group(nn, "flammable")
if def and def._on_burn then
def._on_burn(p)
elseif fgroup ~= -1 then
add_fire_particle(p,pos)
spawn_fire(p)
fire_timer(p)
minetest.check_for_falling(p)
end
end
})
end end
-- Set pointed_thing on (normal) fire. -- Set pointed_thing on (normal) fire.

View File

@ -173,16 +173,22 @@ local function set_shield(player, block, i)
end end
end end
local shield = mcl_shields.players[player].shields[i] local shield = mcl_shields.players[player].shields[i]
if shield then if not shield then return end
shield:get_luaentity()._blocking = block local luaentity = shield:get_luaentity()
end if not luaentity then return end
luaentity._blocking = block
end end
local function set_interact(player, interact) local function set_interact(player, interact)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local privs = minetest.get_player_privs(player_name) local privs = minetest.get_player_privs(player_name)
privs.interact = interact if privs.interact ~= interact then
minetest.set_player_privs(player_name, privs) local meta = player:get_meta()
if meta:get_int("ineract_revoked") ~= 1 then
privs.interact = interact
minetest.set_player_privs(player_name, privs)
end
end
end end
local shield_hud = {} local shield_hud = {}
@ -194,7 +200,12 @@ local function remove_shield_hud(player)
set_shield(player, false, 1) set_shield(player, false, 1)
set_shield(player, false, 2) set_shield(player, false, 2)
end end
player:hud_set_flags({wielditem = true})
local hf=player:hud_get_flags()
if not hf.wielditem then
player:hud_set_flags({wielditem = true})
end
playerphysics.remove_physics_factor(player, "speed", "shield_speed") playerphysics.remove_physics_factor(player, "speed", "shield_speed")
set_interact(player, true) set_interact(player, true)
end end
@ -456,6 +467,5 @@ minetest.register_on_joinplayer(function(player)
shields = {}, shields = {},
blocking = 0, blocking = 0,
} }
mcl_shields.players[player].blocking = 0
remove_shield_hud(player) remove_shield_hud(player)
end) end)

View File

@ -0,0 +1,50 @@
local c_dirt_with_grass_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow")
local c_top_snow = minetest.get_content_id("mcl_core:snow")
local c_snow_block = minetest.get_content_id("mcl_core:snowblock")
mcl_mapgen.register_on_generated(function(vm_context)
local minp, maxp = vm_context.minp, vm_context.maxp
local min_y, max_y = minp.y, maxp.y
if min_y > mcl_mapgen.overworld.max or max_y < mcl_mapgen.overworld.min then return end
vm_context.param2_data = vm_context.param2_data or vm:get_param2_data(vm_context.lvm_param2_buffer)
vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object("biomemap")
local param2_data = vm_context.param2_data
local biomemap = vm_context.biomemap
local vm, data, area = vm_context.vm, vm_context.data, vm_context.area
local min_x, min_z = minp.x, minp.z
local chunksize = max_y - min_y + 1
----- Interactive block fixing section -----
----- The section to perform basic block overrides of the core mapgen generated world. -----
-- Snow and sand fixes. This code implements snow consistency
-- and fixes floating sand and cut plants.
-- A snowy grass block must be below a top snow or snow block at all times.
-- Set param2 (=color) of grass blocks.
-- Clear snowy grass blocks without snow above to ensure consistency.
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:dirt_with_grass", "mcl_core:dirt_with_grass_snow"})
for n=1, #nodes do
local pos = nodes[n]
local x, y, z = pos.x, pos.y, pos.z
local p_pos = area:index(x, y, z)
local p_pos_above = area:index(x, y + 1, z)
local biomemap_offset = (z - min_z) * chunksize + x - min_x + 1
local biome_id = biomemap[biomemap_offset]
local biome_name = minetest.get_biome_name(biome_id)
if biome_name then
local biome = minetest.registered_biomes[biome_name]
if biome and biome._mcl_biome_type then
param2_data[p_pos] = biome._mcl_palette_index
vm_context.write_param2 = true
end
end
if data[p_pos] == c_dirt_with_grass_snow and p_pos_above and data[p_pos_above] ~= c_top_snow and data[p_pos_above] ~= c_snow_block then
data[p_pos] = c_dirt_with_grass
vm_context.write = true
end
end
end, 999999999)

View File

@ -56,19 +56,14 @@ local mg_name = mcl_mapgen.name
local superflat = mcl_mapgen.superflat local superflat = mcl_mapgen.superflat
local v6 = mcl_mapgen.v6 local v6 = mcl_mapgen.v6
local singlenode = mcl_mapgen.singlenode local singlenode = mcl_mapgen.singlenode
local flat = mcl_mapgen.flat
-- Content IDs -- Content IDs
local c_bedrock = minetest.get_content_id("mcl_core:bedrock") local c_bedrock = minetest.get_content_id("mcl_core:bedrock")
local c_obsidian = minetest.get_content_id("mcl_core:obsidian")
local c_stone = minetest.get_content_id("mcl_core:stone")
local c_dirt = minetest.get_content_id("mcl_core:dirt") local c_dirt = minetest.get_content_id("mcl_core:dirt")
local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass") local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass")
local c_dirt_with_grass_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow")
local c_sand = minetest.get_content_id("mcl_core:sand")
--local c_sandstone = minetest.get_content_id("mcl_core:sandstone")
local c_void = minetest.get_content_id("mcl_core:void") local c_void = minetest.get_content_id("mcl_core:void")
local c_lava = minetest.get_content_id("mcl_core:lava_source") local c_lava = minetest.get_content_id("mcl_core:lava_source")
local c_water = minetest.get_content_id("mcl_core:water_source")
local c_nether = nil local c_nether = nil
if minetest.get_modpath("mcl_nether") then if minetest.get_modpath("mcl_nether") then
@ -79,12 +74,7 @@ if minetest.get_modpath("mcl_nether") then
} }
end end
--local c_end_stone = minetest.get_content_id("mcl_end:end_stone")
local c_realm_barrier = minetest.get_content_id("mcl_core:realm_barrier") local c_realm_barrier = minetest.get_content_id("mcl_core:realm_barrier")
local c_top_snow = minetest.get_content_id("mcl_core:snow")
local c_snow_block = minetest.get_content_id("mcl_core:snowblock")
local c_clay = minetest.get_content_id("mcl_core:clay")
--local c_jungletree = minetest.get_content_id("mcl_core:jungletree")
local c_air = minetest.CONTENT_AIR local c_air = minetest.CONTENT_AIR
-- --
@ -1194,100 +1184,6 @@ function mcl_mapgen_core.generate_end_exit_portal(pos)
portal_generated = true portal_generated = true
end end
-- Generate mushrooms in caves manually.
-- Minetest's API does not support decorations in caves yet. :-(
local function generate_underground_mushrooms(minp, maxp, seed)
if not mcl_mushrooms then return end
local pr_shroom = PseudoRandom(seed-24359)
-- Generate rare underground mushrooms
-- TODO: Make them appear in groups, use Perlin noise
local min, max = mcl_mapgen.overworld.lava_max + 4, 0
if minp.y > max or maxp.y < min then
return
end
local bpos
local stone = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_core:stone", "mcl_core:dirt", "mcl_core:mycelium", "mcl_core:podzol", "mcl_core:andesite", "mcl_core:diorite", "mcl_core:granite", "mcl_core:stone_with_coal", "mcl_core:stone_with_iron", "mcl_core:stone_with_gold"})
for n = 1, #stone do
bpos = {x = stone[n].x, y = stone[n].y + 1, z = stone[n].z }
local l = minetest.get_node_light(bpos, 0.5)
if bpos.y >= min and bpos.y <= max and l and l <= 12 and pr_shroom:next(1,1000) < 4 then
if pr_shroom:next(1,2) == 1 then
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
else
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
end
end
end
end
-- Generate Nether decorations manually: Eternal fire, mushrooms
-- Minetest's API does not support decorations in caves yet. :-(
local function generate_nether_decorations(minp, maxp, seed)
if c_nether == nil then
return
end
local pr_nether = PseudoRandom(seed+667)
if minp.y > mcl_mapgen.nether.max or maxp.y < mcl_mapgen.nether.min then
return
end
minetest.log("action", "[mcl_mapgen_core] Nether decorations " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp))
-- TODO: Generate everything based on Perlin noise instead of PseudoRandom
local bpos
local rack = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:netherrack"})
local magma = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:magma"})
local ssand = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:soul_sand"})
-- Helper function to spawn “fake” decoration
local function special_deco(nodes, spawn_func)
for n = 1, #nodes do
bpos = {x = nodes[n].x, y = nodes[n].y + 1, z = nodes[n].z }
spawn_func(bpos)
end
end
-- Eternal fire on netherrack
special_deco(rack, function(bpos)
-- Eternal fire on netherrack
if pr_nether:next(1,100) <= 3 then
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
end
end)
-- Eternal fire on magma cubes
special_deco(magma, function(bpos)
if pr_nether:next(1,150) == 1 then
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
end
end)
-- Mushrooms on netherrack
-- Note: Spawned *after* the fire because of light level checks
if mcl_mushrooms then
special_deco(rack, function(bpos)
local l = minetest.get_node_light(bpos, 0.5)
if bpos.y > mcl_mapgen.nether.lava_max + 6 and l and l <= 12 and pr_nether:next(1,1000) <= 4 then
-- TODO: Make mushrooms appear in groups, use Perlin noise
if pr_nether:next(1,2) == 1 then
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
else
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
end
end
end)
end
end
-- Generate basic layer-based nodes: void, bedrock, realm barrier, lava seas, etc. -- Generate basic layer-based nodes: void, bedrock, realm barrier, lava seas, etc.
-- Also perform some basic node replacements. -- Also perform some basic node replacements.
@ -1338,268 +1234,96 @@ end
-- lvm_used: Set to true if any node in this on_generated has been set before. -- lvm_used: Set to true if any node in this on_generated has been set before.
-- --
-- returns true if any node was set and lvm_used otherwise -- returns true if any node was set and lvm_used otherwise
local function set_layers(data, area, content_id, check, min, max, minp, maxp, lvm_used, pr) local function set_layers(vm_context, pr, min, max, content_id, check)
local minp, maxp, data, area = vm_context.minp, vm_context.maxp, vm_context.data, vm_context.area
if (maxp.y >= min and minp.y <= max) then if (maxp.y >= min and minp.y <= max) then
for y = math.max(min, minp.y), math.min(max, maxp.y) do for y = math.max(min, minp.y), math.min(max, maxp.y) do
for x = minp.x, maxp.x do for x = minp.x, maxp.x do
for z = minp.z, maxp.z do for z = minp.z, maxp.z do
local p_pos = area:index(x, y, z) local p_pos = vm_context.area:index(x, y, z)
if check then if check then
if type(check) == "function" and check({x=x,y=y,z=z}, data[p_pos], pr) then if type(check) == "function" and check({x=x,y=y,z=z}, data[p_pos], pr) then
data[p_pos] = content_id data[p_pos] = content_id
lvm_used = true vm_context.write = true
elseif check == data[p_pos] then elseif check == data[p_pos] then
data[p_pos] = content_id data[p_pos] = content_id
lvm_used = true vm_context.write = true
end end
else else
data[p_pos] = content_id vm_context.data[p_pos] = content_id
lvm_used = true vm_context.write = true
end end
end end
end end
end end
end end
return lvm_used
end end
-- Below the bedrock, generate air/void ---- Generate layers of air, void, etc
local function basic_safe(vm_context) local air_layers = {
local vm, data, emin, emax, area, minp, maxp, chunkseed, blockseed = vm_context.vm, vm_context.data, vm_context.emin, vm_context.emax, vm_context.area, vm_context.minp, vm_context.maxp, vm_context.chunkseed, vm_context.blockseed {mcl_mapgen.nether.max + 1, mcl_mapgen.nether.max + 128} -- on Nether Roof
}
if flat then
air_layers[#air_layers + 1] = {mcl_mapgen.nether.flat_floor, mcl_mapgen.nether.flat_ceiling} -- Flat Nether
end
-- Realm barrier between the Overworld void and the End
local barrier_min = mcl_mapgen.realm_barrier_overworld_end_min
local barrier_max = mcl_mapgen.realm_barrier_overworld_end_max
local void_layers = {
{mcl_mapgen.EDGE_MIN , mcl_mapgen.nether.min - 1 }, -- below Nether
{mcl_mapgen.nether.max + 129, mcl_mapgen.end_.min - 1 }, -- below End (above Nether)
{mcl_mapgen.end_.max + 1 , barrier_min - 1 }, -- below Realm Barrier, above End
{barrier_max + 1 , mcl_mapgen.overworld.min - 1}, -- below Overworld, above Realm Barrier
}
local bedrock_layers = {}
if not singlelayer then
bedrock_layers = {
{mcl_mapgen.overworld.bedrock_min , mcl_mapgen.overworld.bedrock_max },
{mcl_mapgen.nether.bedrock_bottom_min, mcl_mapgen.nether.bedrock_bottom_max},
{mcl_mapgen.nether.bedrock_top_min , mcl_mapgen.nether.bedrock_top_max },
}
end
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
local vm, data, area, minp, maxp, chunkseed, blockseed = vm_context.vm, vm_context.data, vm_context.area, vm_context.minp, vm_context.maxp, vm_context.chunkseed, vm_context.blockseed
vm_context.param2_data = vm_context.param2_data or vm:get_param2_data(vm_context.lvm_param2_buffer) vm_context.param2_data = vm_context.param2_data or vm:get_param2_data(vm_context.lvm_param2_buffer)
local param2_data = vm_context.param2_data local param2_data = vm_context.param2_data
local lvm_used = false
local pr = PseudoRandom(blockseed) local pr = PseudoRandom(blockseed)
for _, layer in pairs(void_layers) do
-- The Void below the Nether: set_layers(vm_context, pr, layer[1], layer[2], c_void)
lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.EDGE_MIN , mcl_mapgen.nether.min -1, minp, maxp, lvm_used, pr) end
for _, layer in pairs(air_layers) do
-- [[ THE NETHER: mcl_mapgen.nether.min mcl_mapgen.nether.max ]] set_layers(vm_context, pr, layer[1], layer[2], c_air)
end
-- The Air on the Nether roof, https://git.minetest.land/MineClone2/MineClone2/issues/1186 set_layers(vm_context, pr, barrier_min, barrier_max, c_realm_barrier)
lvm_used = set_layers(data, area, c_air , nil, mcl_mapgen.nether.max +1, mcl_mapgen.nether.max + 128 , minp, maxp, lvm_used, pr) for _, layer in pairs(bedrock_layers) do
-- The Void above the Nether below the End: set_layers(vm_context, pr, layer[1], layer[2], c_bedrock, bedrock_check)
lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.nether.max + 128 +1, mcl_mapgen.end_.min -1, minp, maxp, lvm_used, pr) end
-- [[ THE END: mcl_mapgen.end_.min mcl_mapgen.end_.max ]]
-- The Void above the End below the Realm barrier:
lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.end_.max +1, mcl_mapgen.realm_barrier_overworld_end_min-1, minp, maxp, lvm_used, pr)
-- Realm barrier between the Overworld void and the End
lvm_used = set_layers(data, area, c_realm_barrier, nil, mcl_mapgen.realm_barrier_overworld_end_min , mcl_mapgen.realm_barrier_overworld_end_max , minp, maxp, lvm_used, pr)
-- The Void above Realm barrier below the Overworld:
lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.realm_barrier_overworld_end_max+1, mcl_mapgen.overworld.min -1, minp, maxp, lvm_used, pr)
if not singlenode then if not singlenode then
-- Bedrock
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_mapgen.overworld.bedrock_min, mcl_mapgen.overworld.bedrock_max, minp, maxp, lvm_used, pr)
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_mapgen.nether.bedrock_bottom_min, mcl_mapgen.nether.bedrock_bottom_max, minp, maxp, lvm_used, pr)
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_mapgen.nether.bedrock_top_min, mcl_mapgen.nether.bedrock_top_max, minp, maxp, lvm_used, pr)
-- Flat Nether
if mg_name == "flat" then
lvm_used = set_layers(data, area, c_air, nil, mcl_mapgen.nether.flat_floor, mcl_mapgen.nether.flat_ceiling, minp, maxp, lvm_used, pr)
end
-- Big lava seas by replacing air below a certain height -- Big lava seas by replacing air below a certain height
if mcl_mapgen.lava then if mcl_mapgen.lava then
lvm_used = set_layers(data, area, c_lava, c_air, mcl_mapgen.overworld.min, mcl_mapgen.overworld.lava_max, minp, maxp, lvm_used, pr) set_layers(vm_context, pr, mcl_mapgen.overworld.min, mcl_mapgen.overworld.lava_max, c_lava, c_air)
if c_nether then if c_nether then
lvm_used = set_layers(data, area, c_nether.lava, c_air, mcl_mapgen.nether.min, mcl_mapgen.nether.lava_max, minp, maxp, lvm_used, pr) set_layers(vm_context, pr, mcl_mapgen.nether.min, mcl_mapgen.nether.lava_max, c_nether.lava, c_air)
end
end
vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object("biomemap")
local biomemap = vm_context.biomemap
----- Interactive block fixing section -----
----- The section to perform basic block overrides of the core mapgen generated world. -----
-- Snow and sand fixes. This code implements snow consistency
-- and fixes floating sand and cut plants.
-- A snowy grass block must be below a top snow or snow block at all times.
if minp.y <= mcl_mapgen.overworld.max and maxp.y >= mcl_mapgen.overworld.min then
-- v6 mapgen:
if v6 then
--[[ Remove broken double plants caused by v6 weirdness.
v6 might break the bottom part of double plants because of how it works.
There are 3 possibilities:
1) Jungle: Top part is placed on top of a jungle tree or fern (=v6 jungle grass).
This is because the schematic might be placed even if some nodes of it
could not be placed because the destination was already occupied.
TODO: A better fix for this would be if schematics could abort placement
altogether if ANY of their nodes could not be placed.
2) Cavegen: Removes the bottom part, the upper part floats
3) Mudflow: Same as 2) ]]
local plants = minetest.find_nodes_in_area(minp, maxp, "group:double_plant")
for n = 1, #plants do
local node = vm:get_node_at(plants[n])
local is_top = minetest.get_item_group(node.name, "double_plant") == 2
if is_top then
local p_pos = area:index(plants[n].x, plants[n].y-1, plants[n].z)
if p_pos then
node = vm:get_node_at({x=plants[n].x, y=plants[n].y-1, z=plants[n].z})
local is_bottom = minetest.get_item_group(node.name, "double_plant") == 1
if not is_bottom then
p_pos = area:index(plants[n].x, plants[n].y, plants[n].z)
data[p_pos] = c_air
lvm_used = true
end
end
end
end
-- Non-v6 mapgens:
else
-- Set param2 (=color) of grass blocks.
-- Clear snowy grass blocks without snow above to ensure consistency.
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:dirt_with_grass", "mcl_core:dirt_with_grass_snow"})
-- Flat area at y=0 to read biome 3 times faster than 5.3.0.get_biome_data(pos).biome: 43us vs 125us per iteration:
local aream = VoxelArea:new({MinEdge={x=minp.x, y=0, z=minp.z}, MaxEdge={x=maxp.x, y=0, z=maxp.z}})
for n=1, #nodes do
local n = nodes[n]
local p_pos = area:index(n.x, n.y, n.z)
local p_pos_above = area:index(n.x, n.y+1, n.z)
--local p_pos_below = area:index(n.x, n.y-1, n.z)
local b_pos = aream:index(n.x, 0, n.z)
local bn = minetest.get_biome_name(biomemap[b_pos])
if bn then
local biome = minetest.registered_biomes[bn]
if biome and biome._mcl_biome_type then
param2_data[p_pos] = biome._mcl_palette_index
vm_context.write_param2 = true
end
end
if data[p_pos] == c_dirt_with_grass_snow and p_pos_above and data[p_pos_above] ~= c_top_snow and data[p_pos_above] ~= c_snow_block then
data[p_pos] = c_dirt_with_grass
lvm_used = true
end
end
end
-- Nether block fixes:
-- * Replace water with Nether lava.
-- * Replace stone, sand dirt in v6 so the Nether works in v6.
elseif minp.y <= mcl_mapgen.nether.max and maxp.y >= mcl_mapgen.nether.min then
-- elseif emin.y <= mcl_mapgen.nether.max and emax.y >= mcl_mapgen.nether.min then
if c_nether then
if v6 then
-- local nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
for n=1, #nodes do
local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z)
if data[p_pos] == c_water then
data[p_pos] = c_nether.lava
lvm_used = true
elseif data[p_pos] == c_stone then
data[p_pos] = c_netherrack
lvm_used = true
elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then
data[p_pos] = c_soul_sand
lvm_used = true
end
end
else
-- local nodes = minetest.find_nodes_in_area(emin, emax, {"group:water"})
local nodes = minetest.find_nodes_in_area(minp, maxp, {"group:water"})
for _, n in pairs(nodes) do
data[area:index(n.x, n.y, n.z)] = c_nether.lava
end
end
end
-- End block fixes:
-- * Replace water with end stone or air (depending on height).
-- * Remove stone, sand, dirt in v6 so our End map generator works in v6.
-- * Generate spawn platform (End portal destination)
elseif minp.y <= mcl_mapgen.end_.max and maxp.y >= mcl_mapgen.end_.min then
local nodes
if v6 then
nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
-- nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
else
nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source"})
-- nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source"})
end
if #nodes > 0 then
lvm_used = true
for _,n in pairs(nodes) do
data[area:index(n.x, n.y, n.z)] = c_air
end
end
-- Obsidian spawn platform
if minp.y <= mcl_mapgen.end_.platform_pos.y and maxp.y >= mcl_mapgen.end_.platform_pos.y and
minp.x <= mcl_mapgen.end_.platform_pos.x and maxp.x >= mcl_mapgen.end_.platform_pos.z and
minp.z <= mcl_mapgen.end_.platform_pos.z and maxp.z >= mcl_mapgen.end_.platform_pos.z then
--local pos1 = {x = math.max(minp.x, mcl_mapgen.end_.platform_pos.x-2), y = math.max(minp.y, mcl_mapgen.end_.platform_pos.y), z = math.max(minp.z, mcl_mapgen.end_.platform_pos.z-2)}
--local pos2 = {x = math.min(maxp.x, mcl_mapgen.end_.platform_pos.x+2), y = math.min(maxp.y, mcl_mapgen.end_.platform_pos.y+2), z = math.min(maxp.z, mcl_mapgen.end_.platform_pos.z+2)}
for x=math.max(minp.x, mcl_mapgen.end_.platform_pos.x-2), math.min(maxp.x, mcl_mapgen.end_.platform_pos.x+2) do
for z=math.max(minp.z, mcl_mapgen.end_.platform_pos.z-2), math.min(maxp.z, mcl_mapgen.end_.platform_pos.z+2) do
for y=math.max(minp.y, mcl_mapgen.end_.platform_pos.y), math.min(maxp.y, mcl_mapgen.end_.platform_pos.y+2) do
local p_pos = area:index(x, y, z)
if y == mcl_mapgen.end_.platform_pos.y then
data[p_pos] = c_obsidian
else
data[p_pos] = c_air
end
end
end
end
lvm_used = true
end end
end end
end end
end, 1)
if not singlenode then
-- Generate special decorations
generate_underground_mushrooms(minp, maxp, blockseed)
generate_nether_decorations(minp, maxp, blockseed)
end
vm_context.write = vm_context.write or lvm_used
end
mcl_mapgen.register_mapgen_block_lvm(basic_safe, 1)
local modpath = minetest.get_modpath(minetest.get_current_modname()) local modpath = minetest.get_modpath(minetest.get_current_modname())
dofile(modpath .. "/clay.lua") dofile(modpath .. "/clay.lua")
dofile(modpath .. "/tree_decoration.lua") dofile(modpath .. "/tree_decoration.lua")
dofile(modpath .. "/nether_wart.lua") dofile(modpath .. "/nether_wart.lua")
dofile(modpath .. "/light.lua")
-- Nether Roof Light: if v6 then
mcl_mapgen.register_mapgen_block_lvm(function(vm_context) dofile(modpath .. "/v6.lua")
local minp = vm_context.minp elseif not singlenode then
local miny = minp.y dofile(modpath .. "/biomes.lua")
if miny > mcl_mapgen.nether.max+127 then return end end
local maxp = vm_context.maxp if not singlenode and c_nether then
local maxy = maxp.y dofile(modpath .. "/nether.lua")
if maxy <= mcl_mapgen.nether.max then return end end
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.nether.max + 1), z = minp.z}
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.nether.max + 127), z = maxp.z}
vm_context.vm:set_lighting({day=15, night=15}, p1, p2)
vm_context.write = true
end, 999999999)
-- End Light:
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
local minp = vm_context.minp
local miny = minp.y
if miny > mcl_mapgen.end_.max then return end
local maxp = vm_context.maxp
local maxy = maxp.y
if maxy <= mcl_mapgen.end_.min then return end
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.end_.min), z = minp.z}
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.end_.max), z = maxp.z}
vm_context.vm:set_lighting({day=15, night=15}, p1, p2)
vm_context.write = true
end, 9999999999)

View File

@ -0,0 +1,41 @@
-- Nether Light:
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
local minp = vm_context.minp
local miny = minp.y
if miny > mcl_mapgen.nether.max then return end
local maxp = vm_context.maxp
local maxy = maxp.y
if maxy < mcl_mapgen.nether.min then return end
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.nether.min), z = minp.z}
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.nether.max), z = maxp.z}
vm_context.vm:set_lighting({day = 3, night = 4}, p1, p2)
vm_context.write = true
end, 999999999)
-- Nether Roof Light:
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
local minp = vm_context.minp
local miny = minp.y
if miny > mcl_mapgen.nether.max+127 then return end
local maxp = vm_context.maxp
local maxy = maxp.y
if maxy <= mcl_mapgen.nether.max then return end
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.nether.max + 1), z = minp.z}
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.nether.max + 127), z = maxp.z}
vm_context.vm:set_lighting({day = 15, night = 15}, p1, p2)
vm_context.write = true
end, 999999999)
-- End Light:
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
local minp = vm_context.minp
local miny = minp.y
if miny > mcl_mapgen.end_.max then return end
local maxp = vm_context.maxp
local maxy = maxp.y
if maxy <= mcl_mapgen.end_.min then return end
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.end_.min), z = minp.z}
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.end_.max), z = maxp.z}
vm_context.vm:set_lighting({day=15, night=15}, p1, p2)
vm_context.write = true
end, 9999999999)

View File

@ -0,0 +1,131 @@
local v6 = mcl_mapgen.v6
local mcl_mushrooms = minetest.get_modpath("mcl_mushrooms")
local c_water = minetest.get_content_id("mcl_core:water_source")
local c_stone = minetest.get_content_id("mcl_core:stone")
local c_sand = minetest.get_content_id("mcl_core:sand")
local c_soul_sand = minetest.get_content_id("mcl_nether:soul_sand")
local c_netherrack = minetest.get_content_id("mcl_nether:netherrack")
local c_nether_lava = minetest.get_content_id("mcl_nether:nether_lava_source")
-- Generate mushrooms in caves manually.
-- Minetest's API does not support decorations in caves yet. :-(
local function generate_underground_mushrooms(minp, maxp, seed)
if not mcl_mushrooms then return end
local pr_shroom = PseudoRandom(seed-24359)
-- Generate rare underground mushrooms
-- TODO: Make them appear in groups, use Perlin noise
local min, max = mcl_mapgen.overworld.lava_max + 4, 0
if minp.y > max or maxp.y < min then
return
end
local bpos
local stone = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_core:stone", "mcl_core:dirt", "mcl_core:mycelium", "mcl_core:podzol", "mcl_core:andesite", "mcl_core:diorite", "mcl_core:granite", "mcl_core:stone_with_coal", "mcl_core:stone_with_iron", "mcl_core:stone_with_gold"})
for n = 1, #stone do
bpos = {x = stone[n].x, y = stone[n].y + 1, z = stone[n].z }
local l = minetest.get_node_light(bpos, 0.5)
if bpos.y >= min and bpos.y <= max and l and l <= 12 and pr_shroom:next(1,1000) < 4 then
if pr_shroom:next(1,2) == 1 then
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
else
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
end
end
end
end
-- Generate Nether decorations manually: Eternal fire, mushrooms
-- Minetest's API does not support decorations in caves yet. :-(
local function generate_nether_decorations(minp, maxp, seed)
local pr_nether = PseudoRandom(seed+667)
if minp.y > mcl_mapgen.nether.max or maxp.y < mcl_mapgen.nether.min then
return
end
minetest.log("action", "[mcl_mapgen_core] Nether decorations " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp))
-- TODO: Generate everything based on Perlin noise instead of PseudoRandom
local bpos
local rack = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:netherrack"})
local magma = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:magma"})
local ssand = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:soul_sand"})
-- Helper function to spawn “fake” decoration
local function special_deco(nodes, spawn_func)
for n = 1, #nodes do
bpos = {x = nodes[n].x, y = nodes[n].y + 1, z = nodes[n].z }
spawn_func(bpos)
end
end
-- Eternal fire on netherrack
special_deco(rack, function(bpos)
-- Eternal fire on netherrack
if pr_nether:next(1,100) <= 3 then
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
end
end)
-- Eternal fire on magma cubes
special_deco(magma, function(bpos)
if pr_nether:next(1,150) == 1 then
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
end
end)
-- Mushrooms on netherrack
-- Note: Spawned *after* the fire because of light level checks
if mcl_mushrooms then
special_deco(rack, function(bpos)
local l = minetest.get_node_light(bpos, 0.5)
if bpos.y > mcl_mapgen.nether.lava_max + 6 and l and l <= 12 and pr_nether:next(1,1000) <= 4 then
-- TODO: Make mushrooms appear in groups, use Perlin noise
if pr_nether:next(1,2) == 1 then
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
else
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
end
end
end)
end
end
mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context)
local min_y, max_y = minp.y, maxp.y
-- Nether block fixes:
-- * Replace water with Nether lava.
-- * Replace stone, sand dirt in v6 so the Nether works in v6.
if min_y > mcl_mapgen.nether.max or max_y < mcl_mapgen.nether.min then return end
if v6 then
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
if #nodes < 1 then return end
vm_context.write = true
local data = vm_context.data
local area = vm_context.area
for n = 1, #nodes do
local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z)
if data[p_pos] == c_water then
data[p_pos] = c_nether_lava
elseif data[p_pos] == c_stone then
data[p_pos] = c_netherrack
elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then
data[p_pos] = c_soul_sand
end
end
else
end
generate_underground_mushrooms(minp, maxp, seed)
generate_nether_decorations(minp, maxp, seed)
end, 1)

View File

@ -0,0 +1,49 @@
local c_air = minetest.CONTENT_AIR
mcl_mapgen.register_on_generated(function(vm_context)
local minp, maxp = vm_context.minp, vm_context.maxp
if minp.y <= mcl_mapgen.end_.max and maxp.y >= mcl_mapgen.end_.min then
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
if #nodes > 0 then
for _, n in pairs(nodes) do
data[area:index(n.x, n.y, n.z)] = c_air
end
end
vm_context.write = true
return
end
if minp.y > mcl_mapgen.overworld.max or maxp.y < mcl_mapgen.overworld.min then return end
local vm, data, area = vm_context.vm, vm_context.data, vm_context.area
--[[ Remove broken double plants caused by v6 weirdness.
v6 might break the bottom part of double plants because of how it works.
There are 3 possibilities:
1) Jungle: Top part is placed on top of a jungle tree or fern (=v6 jungle grass).
This is because the schematic might be placed even if some nodes of it
could not be placed because the destination was already occupied.
TODO: A better fix for this would be if schematics could abort placement
altogether if ANY of their nodes could not be placed.
2) Cavegen: Removes the bottom part, the upper part floats
3) Mudflow: Same as 2) ]]
local plants = minetest.find_nodes_in_area(minp, maxp, "group:double_plant")
for n = 1, #plants do
local node = vm:get_node_at(plants[n])
local is_top = minetest.get_item_group(node.name, "double_plant") == 2
if is_top then
local p_pos = area:index(plants[n].x, plants[n].y-1, plants[n].z)
if p_pos then
node = vm:get_node_at({x=plants[n].x, y=plants[n].y-1, z=plants[n].z})
local is_bottom = minetest.get_item_group(node.name, "double_plant") == 1
if not is_bottom then
p_pos = area:index(plants[n].x, plants[n].y, plants[n].z)
data[p_pos] = c_air
vm_context.write = true
end
end
end
end
end, 999999999)

View File

@ -20,10 +20,26 @@ end)
for _, action in pairs({"grant", "revoke"}) do for _, action in pairs({"grant", "revoke"}) do
minetest["register_on_priv_" .. action](function(name, _, priv) minetest["register_on_priv_" .. action](function(name, _, priv)
if priv == "fly" then local player = minetest.get_player_by_name(name)
local player = minetest.get_player_by_name(name) if player then
local meta = player:get_meta() local meta = player:get_meta()
meta:set_int("fly_changed", 1)
if priv == "fly" then
meta:set_int("fly_changed", 1)
end
--[[
so e.g. hackers who have been revoked of the interact privilege
will not automatically get the interact privilege through the mcl shields code back
]]
if priv == "interact" then
if action == "revoke" then
meta:set_int("ineract_revoked", 1)
else
meta:set_int("ineract_revoked", 0)
end
end
end end
end) end)
end end