mirror of
https://github.com/mt-mods/moretrees.git
synced 2024-11-15 23:10:20 +01:00
Merge branch 'master' into master
This commit is contained in:
commit
a9f49368bf
|
@ -94,7 +94,7 @@ moretrees.sequoia_biome = {
|
|||
temp_min = 1,
|
||||
temp_max = -0.4,
|
||||
rarity = 90,
|
||||
max_count = 5,
|
||||
max_count = 2,
|
||||
}
|
||||
|
||||
moretrees.birch_biome = {
|
||||
|
@ -107,7 +107,7 @@ moretrees.birch_biome = {
|
|||
temp_min = 0.9,
|
||||
temp_max = 0.3,
|
||||
rarity = 50,
|
||||
max_count = 10,
|
||||
max_count = 6,
|
||||
}
|
||||
|
||||
moretrees.willow_biome = {
|
||||
|
@ -169,7 +169,7 @@ moretrees.spruce_biome = {
|
|||
temp_min = 0.9,
|
||||
temp_max = 0.7,
|
||||
rarity = 50,
|
||||
max_count = 5,
|
||||
max_count = 3,
|
||||
}
|
||||
|
||||
moretrees.cedar_biome = {
|
||||
|
|
174
cocos_palm.lua
174
cocos_palm.lua
|
@ -45,34 +45,6 @@ gftrunk.description = gftrunk.description.." (gen)"
|
|||
minetest.register_node("moretrees:palm_fruit_trunk", ftrunk)
|
||||
minetest.register_node("moretrees:palm_fruit_trunk_gen", gftrunk)
|
||||
|
||||
local coconut_regrow_abm_spec = {
|
||||
nodenames = { "moretrees:palm_fruit_trunk" },
|
||||
interval = moretrees.coconut_flower_interval,
|
||||
chance = moretrees.coconut_flower_chance,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local coconuts = minetest.find_nodes_in_area(
|
||||
{x=pos.x-1, y=pos.y, z=pos.z-1},
|
||||
{x=pos.x+1, y=pos.y, z=pos.z+1},
|
||||
"group:moretrees_coconut"
|
||||
)
|
||||
-- Expected growth interval increases exponentially with number of coconuts already hanging.
|
||||
-- Also: if more coconuts are hanging, the chance of picking an empty spot decreases as well...
|
||||
if math.random(2^#coconuts) <= 2 then
|
||||
-- Grow in area of 3x3 round trunk
|
||||
local dx=math.floor(math.random(3)-2)
|
||||
local dz=math.floor(math.random(3)-2)
|
||||
local coconutpos = {x=pos.x+dx, y=pos.y, z=pos.z+dz}
|
||||
local coconutnode = minetest.get_node(coconutpos)
|
||||
if coconutnode.name == "air" then
|
||||
minetest.swap_node(coconutpos, {name="moretrees:coconut_0"})
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
if moretrees.coconuts_regrow then
|
||||
minetest.register_abm(coconut_regrow_abm_spec)
|
||||
end
|
||||
|
||||
-- Spawn initial coconuts
|
||||
|
||||
-- Spawn initial coconuts
|
||||
|
@ -84,7 +56,7 @@ minetest.register_abm({
|
|||
chance = 1,
|
||||
min_y = biome_lib.mapgen_elevation_limit.min,
|
||||
max_y = biome_lib.mapgen_elevation_limit.max,
|
||||
label = "converts palm trunk to a regular fruit trunk, and spawns some coconuts",
|
||||
label = "converts the trunk to a regular fruit trunk, and spawns some coconuts",
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.swap_node(pos, {name="moretrees:palm_fruit_trunk"})
|
||||
local poslist = minetest.find_nodes_in_area(
|
||||
|
@ -192,147 +164,3 @@ for _,suffix in ipairs({"_0", "_1", "_2", "_3", ""}) do
|
|||
}
|
||||
minetest.register_node("moretrees:coconut"..suffix, coconutdef)
|
||||
end
|
||||
|
||||
-- convert exisiting cocos palms. This is a bit tricky...
|
||||
-- Try to make sure that this is indeed a generated tree, and not manually-placed trunks and/or coconuts
|
||||
if moretrees.coconuts_convert_existing_palms then
|
||||
local spec = {
|
||||
name = "moretrees:convert_existing_cocos_palms_to_regrow_coconuts",
|
||||
nodenames = "moretrees:coconut",
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local trunks
|
||||
local cvtrunks
|
||||
local leaves
|
||||
local coconuts
|
||||
-- One regular trunk must be adjacent to the coconut
|
||||
trunks = minetest.find_nodes_in_area(
|
||||
{x=pos.x-1, y=pos.y, z=pos.z-1},
|
||||
{x=pos.x+1, y=pos.y, z=pos.z+1},
|
||||
"moretrees:palm_trunk"
|
||||
)
|
||||
if #trunks ~= 1 then
|
||||
return
|
||||
end
|
||||
local tpos = trunks[1]
|
||||
-- 1 or 2 other trunks must be one level below to the trunk being converted.
|
||||
trunks = minetest.find_nodes_in_area(
|
||||
{x=tpos.x-1, y=tpos.y-1, z=tpos.z-1},
|
||||
{x=tpos.x+1, y=tpos.y-1, z=tpos.z+1},
|
||||
"moretrees:palm_trunk"
|
||||
)
|
||||
if #trunks < 1 or #trunks > 2 then
|
||||
return
|
||||
end
|
||||
-- 1 or 2 other trunks must be two levels below to the trunk being converted.
|
||||
trunks = minetest.find_nodes_in_area(
|
||||
{x=tpos.x-1, y=tpos.y-2, z=tpos.z-1},
|
||||
{x=tpos.x+1, y=tpos.y-2, z=tpos.z+1},
|
||||
"moretrees:palm_trunk"
|
||||
)
|
||||
if #trunks < 1 or #trunks > 2 then
|
||||
return
|
||||
end
|
||||
-- 1 or 2 trunks must at the level of the trunk being converted.
|
||||
cvtrunks = minetest.find_nodes_in_area(
|
||||
{x=tpos.x-1, y=tpos.y, z=tpos.z-1},
|
||||
{x=tpos.x+1, y=tpos.y, z=tpos.z+1},
|
||||
"moretrees:palm_trunk"
|
||||
)
|
||||
if #cvtrunks < 1 or #cvtrunks > 2 then
|
||||
return
|
||||
end
|
||||
-- No trunks may be one level above the trunk being converted.
|
||||
trunks = minetest.find_nodes_in_area(
|
||||
{x=tpos.x-1, y=tpos.y+1, z=tpos.z-1},
|
||||
{x=tpos.x+1, y=tpos.y+1, z=tpos.z+1},
|
||||
"moretrees:palm_trunk"
|
||||
)
|
||||
if #trunks ~= 0 then
|
||||
return
|
||||
end
|
||||
-- Leaves must be one level above the trunk being converted.
|
||||
leaves = minetest.find_nodes_in_area(
|
||||
{x=tpos.x-1, y=tpos.y+1, z=tpos.z-1},
|
||||
{x=tpos.x+1, y=tpos.y+1, z=tpos.z+1},
|
||||
"moretrees:palm_leaves"
|
||||
)
|
||||
if #leaves == 0 then
|
||||
return
|
||||
end
|
||||
-- Leaves must be two levels above the trunk being converted.
|
||||
leaves = minetest.find_nodes_in_area(
|
||||
{x=tpos.x-1, y=tpos.y+2, z=tpos.z-1},
|
||||
{x=tpos.x+1, y=tpos.y+2, z=tpos.z+1},
|
||||
"moretrees:palm_leaves"
|
||||
)
|
||||
if #leaves == 0 then
|
||||
return
|
||||
end
|
||||
-- No cocos fruit trunk may already be adjacent to the coconut
|
||||
trunks = minetest.find_nodes_in_area(
|
||||
{x=pos.x-1, y=pos.y, z=pos.z-1},
|
||||
{x=pos.x+1, y=pos.y, z=pos.z+1},
|
||||
"moretrees:palm_fruit_trunk"
|
||||
)
|
||||
if #trunks ~= 0 then
|
||||
return
|
||||
end
|
||||
-- No cocos fruit trunk may be adjacent to or below the trunk being converted.
|
||||
trunks = minetest.find_nodes_in_area(
|
||||
{x=tpos.x-1, y=tpos.y-2, z=tpos.z-1},
|
||||
{x=tpos.x+1, y=tpos.y, z=tpos.z+1},
|
||||
"moretrees:palm_fruit_trunk"
|
||||
)
|
||||
if #trunks ~= 0 then
|
||||
return
|
||||
end
|
||||
-- Convert trunk and all coconuts nearby. Maybe convert 2 trunks, just in case...
|
||||
for _, tpos_1 in pairs(cvtrunks) do
|
||||
minetest.swap_node(tpos_1, {name = "moretrees:palm_fruit_trunk"})
|
||||
coconuts = minetest.find_nodes_in_area(
|
||||
{x=tpos_1.x-1, y=tpos_1.y, z=tpos_1.z-1},
|
||||
{x=tpos_1.x+1, y=tpos_1.y, z=tpos_1.z+1},
|
||||
"moretrees:coconut"
|
||||
)
|
||||
for _, coconutpos in pairs(coconuts) do
|
||||
minetest.swap_node(coconutpos, {name = "moretrees:coconut_3"})
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
if minetest.register_lbm then
|
||||
minetest.register_lbm(spec)
|
||||
else
|
||||
spec.interval = 3691
|
||||
spec.chance = 10
|
||||
minetest.register_abm(spec)
|
||||
end
|
||||
end
|
||||
|
||||
-- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing coconuts
|
||||
if moretrees.coconuts_regrow then
|
||||
local spec = {
|
||||
name = "moretrees:restart_coconut_regrow_timer",
|
||||
nodenames = "group:moretrees_coconut",
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if not timer:is_started() then
|
||||
coconut_starttimer(pos)
|
||||
else
|
||||
local timeout = timer:get_timeout()
|
||||
local elapsed = timer:get_elapsed()
|
||||
if timeout - elapsed > moretrees.coconut_grow_interval * 4/3 then
|
||||
coconut_starttimer(pos, math.random(moretrees.coconut_grow_interval * 4/3))
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
if minetest.register_lbm then
|
||||
minetest.register_lbm(spec)
|
||||
else
|
||||
spec.interval = 3659
|
||||
spec.chance = 10
|
||||
minetest.register_abm(spec)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ for i in ipairs(moretrees.cutting_tools) do
|
|||
}
|
||||
})
|
||||
end
|
||||
|
||||
--[[
|
||||
-- give tool back with wear preserved
|
||||
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
|
||||
if (itemstack:get_name() == "moretrees:coconut_milk") then
|
||||
|
@ -156,7 +156,7 @@ minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv
|
|||
end
|
||||
end
|
||||
end)
|
||||
|
||||
]]--
|
||||
-- coconut milk using food_cutting_board from farming redo
|
||||
if minetest.registered_items["farming:cutting_board"] then
|
||||
minetest.register_craft({
|
||||
|
|
620
date_palm.lua
620
date_palm.lua
|
@ -77,598 +77,6 @@ minetest.register_node("moretrees:date_palm_fruit_trunk", ftrunk)
|
|||
minetest.register_node("moretrees:date_palm_ffruit_trunk", fftrunk)
|
||||
minetest.register_node("moretrees:date_palm_mfruit_trunk", mftrunk)
|
||||
|
||||
-- ABM to grow new date blossoms
|
||||
local date_regrow_abm_spec = {
|
||||
nodenames = { "moretrees:date_palm_ffruit_trunk", "moretrees:date_palm_mfruit_trunk" },
|
||||
interval = moretrees.dates_flower_interval,
|
||||
chance = moretrees.dates_flower_chance,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local dates = minetest.find_nodes_in_area({x=pos.x-2, y=pos.y, z=pos.z-2}, {x=pos.x+2, y=pos.y, z=pos.z+2}, "group:moretrees_dates")
|
||||
|
||||
-- New blossom interval increases exponentially with number of dates already hanging
|
||||
-- In addition: if more dates are hanging, the chance of picking an empty spot decreases as well...
|
||||
if math.random(2^#dates) <= 2 then
|
||||
-- Grow in area of 5x5 round trunk; higher probability in 3x3 area close to trunk
|
||||
local dx=math.floor((math.random(50)-18)/16)
|
||||
local dz=math.floor((math.random(50)-18)/16)
|
||||
local datepos = {x=pos.x+dx, y=pos.y, z=pos.z+dz}
|
||||
local datenode = minetest.get_node(datepos)
|
||||
if datenode.name == "air" then
|
||||
if node.name == "moretrees:date_palm_ffruit_trunk" then
|
||||
minetest.swap_node(datepos, {name="moretrees:dates_f0"})
|
||||
else
|
||||
minetest.swap_node(datepos, {name="moretrees:dates_m0"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
if moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0 then
|
||||
minetest.register_abm(date_regrow_abm_spec)
|
||||
end
|
||||
|
||||
-- Choose male or female palm, and spawn initial dates
|
||||
-- (Instead of dates, a dates fruit trunk is generated with the tree. This
|
||||
-- ABM converts the trunk to a female or male fruit trunk, and spawns some
|
||||
-- hanging dates)
|
||||
minetest.register_abm({
|
||||
nodenames = { "moretrees:date_palm_fruit_trunk" },
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local type
|
||||
if math.random(100) <= moretrees.dates_female_percent then
|
||||
type = "f"
|
||||
minetest.swap_node(pos, {name="moretrees:date_palm_ffruit_trunk"})
|
||||
else
|
||||
type = "m"
|
||||
minetest.swap_node(pos, {name="moretrees:date_palm_mfruit_trunk"})
|
||||
end
|
||||
local dates1 = minetest.find_nodes_in_area(
|
||||
{x=pos.x-1, y=pos.y, z=pos.z-1},
|
||||
{x=pos.x+1, y=pos.y, z=pos.z+1},
|
||||
"air"
|
||||
)
|
||||
for _,genpos in pairs(dates1) do
|
||||
if math.random(100) <= 20 then
|
||||
if type == "m" then
|
||||
minetest.swap_node(genpos, {name = "moretrees:dates_n"})
|
||||
else
|
||||
minetest.swap_node(genpos, {name = "moretrees:dates_f4"})
|
||||
end
|
||||
end
|
||||
end
|
||||
local dates2 = minetest.find_nodes_in_area(
|
||||
{x=pos.x-2, y=pos.y, z=pos.z-2},
|
||||
{x=pos.x+2, y=pos.y, z=pos.z+2},
|
||||
"air"
|
||||
)
|
||||
for _,genpos in pairs(dates2) do
|
||||
if math.random(100) <= 5 then
|
||||
if type == "m" then
|
||||
minetest.swap_node(genpos, {name = "moretrees:dates_n"})
|
||||
else
|
||||
minetest.swap_node(genpos, {name = "moretrees:dates_f4"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Dates growing functions.
|
||||
|
||||
-- This is a bit complex, as the purpose is to find male flowers at horizontal distances of over
|
||||
-- 100 nodes. As searching such a large area is time consuming, this is optimized in four ways:
|
||||
-- - The search result (the locations of male trees) is cached, so that it can be used again
|
||||
-- - Only 1/9th of the desired area is searched at a time. A new search is only performed if no male
|
||||
-- flowers are found in the previously searched parts.
|
||||
-- - Search results are shared with other female palms nearby.
|
||||
-- - If previous searches for male palms have consumed too much CPU time, the search is skipped
|
||||
-- (This means no male palms will be found, and the pollination of the flowers affected will be
|
||||
-- delayed. If this happens repeatedly, eventually, the female flowers will wither...)
|
||||
-- A caching method was selected that is suited for the case where most date trees are long-lived,
|
||||
-- and where the number of trees nearby is limited:
|
||||
-- - Locations of male palms are stored as metadata for every female palm. This means that a player
|
||||
-- visiting a remote area with some date palms will not cause extensive searches for male palms as
|
||||
-- long overdue blossoming ABMs are triggered for every date palm.
|
||||
-- - Even when male palms *are* cut down, a cache refill will only be performed if the cached results do not
|
||||
-- contain a male palm with blossoms.
|
||||
-- The method will probably perform suboptimally:
|
||||
-- - If female palms are frequently chopped down and replanted.
|
||||
-- Freshly grown palms will need to search for male palms again
|
||||
-- (this is mitigated by the long blossoming interval, which increases the chance that search
|
||||
-- results have already been shared)
|
||||
-- - If an area contains a large number of male and female palms.
|
||||
-- In this area, every female palm will have an almost identical list of male palm locations
|
||||
-- as metadata.
|
||||
-- - If all male palms within range of a number of female palms have been chopped down (with possibly
|
||||
-- new ones planted). Although an attempt was made to share search results in this case as well,
|
||||
-- a number of similar searches will unavoidably be performed by the different female palms.
|
||||
-- - If no male palms are in range of a female palm. In that case, there will be frequent searches
|
||||
-- for newly-grown male palms.
|
||||
|
||||
-- Search statistics - used to limit the search load.
|
||||
local sect_search_stats = {} -- Search statistics - server-wide
|
||||
local function reset_sect_search_stats()
|
||||
sect_search_stats.count = 0 -- # of searches
|
||||
sect_search_stats.skip = 0 -- # of times skipped
|
||||
sect_search_stats.sum = 0 -- total time spent
|
||||
sect_search_stats.min = 999999999 -- min time spent
|
||||
sect_search_stats.max = 0 -- max time spent
|
||||
end
|
||||
reset_sect_search_stats()
|
||||
sect_search_stats.last_us = 0 -- last time a search was done (microseconds, max: 2^32)
|
||||
sect_search_stats.last_s = 0 -- last time a search was done (system time in seconds)
|
||||
|
||||
-- Find male trunks in one section (=1/9 th) of the searchable area.
|
||||
-- sect is -4 to 4, where 0 is the center section
|
||||
local function find_fruit_trunks_near(ftpos, sect)
|
||||
local r = moretrees.dates_pollination_distance + 2 * math.sqrt(2)
|
||||
local sect_hr = math.floor(r / 3 + 0.9999)
|
||||
local sect_vr = math.floor(r / 2 + 0.9999)
|
||||
local t0us = minetest.get_us_time()
|
||||
local t0s = os.time()
|
||||
|
||||
-- Compute elapsed time since last search.
|
||||
-- Unfortunately, the time value wraps after about 71 minutes (2^32 microseconds),
|
||||
-- so it must be corrected to obtain the actual elapsed time.
|
||||
if t0us < sect_search_stats.last_us then
|
||||
-- Correct a simple wraparound.
|
||||
-- This is not sufficient, as the time value may have wrapped more than once...
|
||||
sect_search_stats.last_us = sect_search_stats.last_us - 2^32
|
||||
end
|
||||
if t0s - sect_search_stats.last_s > 2^32/1000000 then
|
||||
-- One additional correction is enough for our purposes.
|
||||
-- For exact results, more corrections may be needed though...
|
||||
-- (and even not applying this correction at all would still only yield
|
||||
-- a minimal risk of a non-serious miscalculation...)
|
||||
sect_search_stats.last_us = sect_search_stats.last_us - 2^32
|
||||
end
|
||||
|
||||
-- Skip the search if it is consuming too much CPU time
|
||||
if sect_search_stats.count > 0 and moretrees.dates_blossom_search_iload > 0
|
||||
and sect_search_stats.sum / sect_search_stats.count > moretrees.dates_blossom_search_time_treshold
|
||||
and t0us - sect_search_stats.last_us < moretrees.dates_blossom_search_iload * (sect_search_stats.sum / sect_search_stats.count) then
|
||||
sect_search_stats.skip = sect_search_stats.skip + 1
|
||||
return nil
|
||||
end
|
||||
|
||||
local basevec = { x = ftpos.x + 2 * sect.x * sect_hr,
|
||||
y = ftpos.y,
|
||||
z = ftpos.z + 2 * sect.z * sect_hr}
|
||||
-- find_nodes_in_area is limited to 82^3, make sure to not overrun it
|
||||
local sizevec = { x = sect_hr, y = sect_vr, z = sect_hr }
|
||||
if sect_hr * sect_hr * sect_vr > 41^3 then
|
||||
sizevec = vector.apply(sizevec, function(a) return math.min(a, 41) end)
|
||||
end
|
||||
|
||||
local all_palms = minetest.find_nodes_in_area(
|
||||
vector.subtract(basevec, sizevec),
|
||||
vector.add(basevec, sizevec),
|
||||
{"moretrees:date_palm_mfruit_trunk", "moretrees:date_palm_ffruit_trunk"})
|
||||
|
||||
-- Collect different palms in separate lists.
|
||||
local female_palms = {}
|
||||
local male_palms = {}
|
||||
local all_male_palms = {}
|
||||
for _, pos in pairs(all_palms) do
|
||||
if pos.x ~= ftpos.x or pos.y ~= ftpos.y or pos.z ~= ftpos.z then
|
||||
local node = minetest.get_node(pos)
|
||||
if node and node.name == "moretrees:date_palm_ffruit_trunk" then
|
||||
table.insert(female_palms,pos)
|
||||
elseif node then
|
||||
table.insert(all_male_palms,pos)
|
||||
-- In sector 0, all palms are of interest.
|
||||
-- In other sectors, forget about palms that are too far away.
|
||||
if sect == 0 then
|
||||
table.insert(male_palms,pos)
|
||||
else
|
||||
local ssq = 0
|
||||
for _, c in pairs({"x", "z"}) do
|
||||
local dc = pos[c] - ftpos[c]
|
||||
ssq = ssq + dc * dc
|
||||
end
|
||||
if math.sqrt(ssq) <= r then
|
||||
table.insert(male_palms,pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Update search statistics
|
||||
local t1us = minetest.get_us_time()
|
||||
if t1us < t0us then
|
||||
-- Wraparound. Assume the search lasted less than 2^32 microseconds (~71 min)
|
||||
-- (so no need to apply another correction)
|
||||
t0us = t0us - 2^32
|
||||
end
|
||||
sect_search_stats.last_us = t0us
|
||||
sect_search_stats.last_s = t0s
|
||||
sect_search_stats.count = sect_search_stats.count + 1
|
||||
sect_search_stats.sum = sect_search_stats.sum + t1us-t0us
|
||||
if t1us - t0us < sect_search_stats.min then
|
||||
sect_search_stats.min = t1us - t0us
|
||||
end
|
||||
if t1us - t0us > sect_search_stats.max then
|
||||
sect_search_stats.max = t1us - t0us
|
||||
end
|
||||
|
||||
return male_palms, female_palms, all_male_palms
|
||||
end
|
||||
|
||||
local function dates_print_search_stats(log)
|
||||
local stats
|
||||
if sect_search_stats.count > 0 then
|
||||
stats = string.format("Male date tree searching stats: searches: %d/%d: average: %d µs (%d..%d)",
|
||||
sect_search_stats.count, sect_search_stats.count + sect_search_stats.skip,
|
||||
sect_search_stats.sum/sect_search_stats.count, sect_search_stats.min, sect_search_stats.max)
|
||||
else
|
||||
stats = string.format("Male date tree searching stats: searches: 0/0: average: (no searches yet)")
|
||||
end
|
||||
if log then
|
||||
minetest.log("action", "[moretrees] " .. stats)
|
||||
end
|
||||
return true, stats
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("dates_stats", {
|
||||
description = "Print male date palm search statistics",
|
||||
params = "|chat|log|reset",
|
||||
privs = { server = true },
|
||||
func = function(name, param)
|
||||
param = string.lower(param:gsub("%s+", ""))
|
||||
if param == "" or param == "chat" then
|
||||
return dates_print_search_stats(false)
|
||||
elseif param == "log" then
|
||||
return dates_print_search_stats(true)
|
||||
elseif param == "reset" then
|
||||
reset_sect_search_stats()
|
||||
return true
|
||||
else
|
||||
return false, "Invalid subcommand; expected: '' or 'chat' or 'log' or 'reset'"
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Find the female trunk near the female flowers to be pollinated
|
||||
local function find_female_trunk(fbpos)
|
||||
local trunks = minetest.find_nodes_in_area({x=fbpos.x-2, y=fbpos.y, z=fbpos.z-2},
|
||||
{x=fbpos.x+2, y=fbpos.y, z=fbpos.z+2},
|
||||
"moretrees:date_palm_ffruit_trunk")
|
||||
local ftpos
|
||||
local d = 99
|
||||
for x, pos in pairs(trunks) do
|
||||
local ssq = 0
|
||||
for _, c in pairs({"x", "z"}) do
|
||||
local dc = pos[c] - fbpos[c]
|
||||
ssq = ssq + dc * dc
|
||||
end
|
||||
if math.sqrt(ssq) < d then
|
||||
ftpos = pos
|
||||
d = math.sqrt(ssq)
|
||||
end
|
||||
end
|
||||
return ftpos
|
||||
end
|
||||
|
||||
-- Find male blossom near a male trunk,
|
||||
-- the male blossom must be in range of a specific female blossom as well
|
||||
local function find_male_blossom_near_trunk(fbpos, mtpos)
|
||||
local r = moretrees.dates_pollination_distance
|
||||
local blossoms = minetest.find_nodes_in_area({x=mtpos.x-2, y=mtpos.y, z=mtpos.z-2},
|
||||
{x=mtpos.x+2, y=mtpos.y, z=mtpos.z+2},
|
||||
"moretrees:dates_m0")
|
||||
for x, mbpos in pairs(blossoms) do
|
||||
local ssq = 0
|
||||
for _, c in pairs({"x", "z"}) do
|
||||
local dc = mbpos[c] - fbpos[c]
|
||||
ssq = ssq + dc * dc
|
||||
end
|
||||
if math.sqrt(ssq) <= r then
|
||||
return mbpos
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Find a male blossom in range of a specific female blossom,
|
||||
-- using a nested list of male blossom positions
|
||||
local function find_male_blossom_in_mpalms(ftpos, fbpos, mpalms)
|
||||
-- Process the elements of mpalms.sect (index -4 .. 4) in random order
|
||||
-- First, compute the order in which the sectors will be searched
|
||||
local sect_index = {}
|
||||
local sect_rnd = {}
|
||||
for i = -4,4 do
|
||||
local n = math.random(1023)
|
||||
sect_index[n] = i
|
||||
table.insert(sect_rnd, n)
|
||||
end
|
||||
table.sort(sect_rnd)
|
||||
|
||||
-- Search the sectors
|
||||
local sect_old = 0
|
||||
local sect_time = minetest.get_gametime()
|
||||
for _, n in pairs(sect_rnd) do
|
||||
-- Record the oldest sector, so that it can be searched if no male
|
||||
-- blossoms were found
|
||||
if not mpalms.sect_time[sect_index[n]] then
|
||||
sect_old = sect_index[n]
|
||||
sect_time = 0
|
||||
elseif mpalms.sect_time[sect_index[n]] < sect_time then
|
||||
sect_old = sect_index[n]
|
||||
sect_time = mpalms.sect_time[sect_index[n]]
|
||||
end
|
||||
if mpalms.sect[sect_index[n]] and #mpalms.sect[sect_index[n]] then
|
||||
for px, mtpos in pairs(mpalms.sect[sect_index[n]]) do
|
||||
local node = minetest.get_node(mtpos)
|
||||
if node and node.name == "moretrees:date_palm_mfruit_trunk" then
|
||||
local mbpos = find_male_blossom_near_trunk(fbpos, mtpos)
|
||||
if mbpos then
|
||||
return mbpos
|
||||
end
|
||||
elseif node and node.name ~= "ignore" then
|
||||
-- no more male trunk here.
|
||||
mpalms.sect[sect_index[n]][px] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil, sect_old
|
||||
end
|
||||
|
||||
-- Find a male blossom in range of a specific female blossom,
|
||||
-- using the cache associated with the given female trunk
|
||||
-- If necessary, recompute part of the cache
|
||||
local last_search_result = {}
|
||||
local function find_male_blossom_with_ftrunk(fbpos,ftpos)
|
||||
local meta = minetest.get_meta(ftpos)
|
||||
local mpalms
|
||||
local cache_changed = true
|
||||
|
||||
-- Load cache. If distance has changed, start with empty cache instead.
|
||||
local mpalms_dist = meta:get_int("male_palms_dist")
|
||||
if mpalms_dist and mpalms_dist == moretrees.dates_pollination_distance then
|
||||
mpalms = meta:get_string("male_palms")
|
||||
if mpalms and mpalms ~= "" then
|
||||
mpalms = minetest.deserialize(mpalms)
|
||||
cache_changed = false
|
||||
end
|
||||
end
|
||||
if not mpalms or not mpalms.sect then
|
||||
mpalms = {}
|
||||
mpalms.sect = {}
|
||||
mpalms.sect_time = {}
|
||||
meta:set_int("male_palms_dist", moretrees.dates_pollination_distance)
|
||||
cache_changed = true
|
||||
end
|
||||
local fpalms_list
|
||||
local all_mpalms_list
|
||||
local sector0_searched = false
|
||||
|
||||
-- Always make sure that sector 0 is cached
|
||||
if not mpalms.sect[0] then
|
||||
mpalms.sect[0], fpalms_list, all_mpalms_list = find_fruit_trunks_near(ftpos, {x = 0, z = 0})
|
||||
mpalms.sect_time[0] = minetest.get_gametime()
|
||||
sector0_searched = true
|
||||
cache_changed = true
|
||||
last_search_result.female = fpalms_list
|
||||
last_search_result.male = all_mpalms_list
|
||||
end
|
||||
|
||||
-- Find male palms
|
||||
local mbpos, sect_old = find_male_blossom_in_mpalms(ftpos, fbpos, mpalms)
|
||||
|
||||
-- If not found, (re)generate the cache for an additional sector. But don't search it yet (for performance reasons)
|
||||
-- (Use the globally cached results if possible)
|
||||
if not mbpos and not sector0_searched then
|
||||
if not mpalms.sect_time[0] or mpalms.sect_time[0] == 0 or math.random(3) == 1 then
|
||||
-- Higher probability of re-searching the center sector
|
||||
sect_old = 0
|
||||
end
|
||||
-- Use globally cached result if possible
|
||||
mpalms.sect[sect_old] = nil
|
||||
if sect_old == 0 and mpalms.sect_time[0] and mpalms.sect_time[0] > 0
|
||||
and last_search_result.male and #last_search_result.male then
|
||||
for _, pos in pairs(last_search_result.female) do
|
||||
if pos.x == ftpos.x and pos.y == ftpos.y and pos.z == ftpos.z then
|
||||
mpalms.sect[sect_old] = last_search_result.male
|
||||
-- Next time, don't use the cached result
|
||||
mpalms.sect_time[sect_old] = nil
|
||||
cache_changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Else do a new search
|
||||
if not mpalms.sect[sect_old] then
|
||||
mpalms.sect[sect_old], fpalms_list, all_mpalms_list = find_fruit_trunks_near(ftpos, {x = (sect_old + 4) % 3 - 1, z = (sect_old + 4) / 3 - 1})
|
||||
cache_changed = true
|
||||
if sect_old == 0 then
|
||||
-- Save the results if it is sector 0
|
||||
-- (chance of reusing results from another sector are smaller)
|
||||
last_search_result.female = fpalms_list
|
||||
last_search_result.male = all_mpalms_list
|
||||
end
|
||||
if mpalms.sect[sect_old] then
|
||||
mpalms.sect_time[sect_old] = minetest.get_gametime()
|
||||
else
|
||||
mpalms.sect_time[sect_old] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Share search results with other female trunks in the same area
|
||||
-- Note that the list of female trunks doesn't (shouldn't :-) contain the current female trunk.
|
||||
if fpalms_list and #fpalms_list and #all_mpalms_list then
|
||||
local all_mpalms = {}
|
||||
all_mpalms.sect = {}
|
||||
all_mpalms.sect_time = {}
|
||||
all_mpalms.sect[0] = all_mpalms_list
|
||||
-- Don't set sect_time[0], so that the cached sector will be re-searched soon (if necessary)
|
||||
local all_mpalms_serialized = minetest.serialize(all_mpalms)
|
||||
for _, pos in pairs(fpalms_list) do
|
||||
local fmeta = minetest.get_meta(pos)
|
||||
local fdist = fmeta:get_int("male_palms_dist")
|
||||
if not fdist or fdist ~= moretrees.dates_pollination_distance then
|
||||
fmeta:set_string("male_palms", all_mpalms_serialized)
|
||||
fmeta:set_int("male_palms_dist", moretrees.dates_pollination_distance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Save cache.
|
||||
if cache_changed then
|
||||
meta:set_string("male_palms", minetest.serialize(mpalms))
|
||||
end
|
||||
|
||||
return mbpos
|
||||
end
|
||||
|
||||
-- Find a male blossom in range of a specific female blossom
|
||||
local function find_male_blossom(fbpos)
|
||||
local ftpos = find_female_trunk(fbpos)
|
||||
if ftpos then
|
||||
return find_male_blossom_with_ftrunk(fbpos, ftpos)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Growing function for dates
|
||||
local dates_growfn = function(pos, elapsed)
|
||||
local node = minetest.get_node(pos)
|
||||
local delay = moretrees.dates_grow_interval
|
||||
local action
|
||||
if not node then
|
||||
return
|
||||
elseif not moretrees.dates_regrow_pollinated and dates_regrow_prob == 0 then
|
||||
-- Regrowing of dates is disabled.
|
||||
if string.find(node.name, "moretrees:dates_f") then
|
||||
minetest.swap_node(pos, {name="moretrees:dates_f4"})
|
||||
elseif string.find(node.name, "moretrees:dates_m") then
|
||||
minetest.swap_node(pos, {name="moretrees:dates_n"})
|
||||
else
|
||||
minetest.swap_node(pos, biome_lib.air)
|
||||
end
|
||||
return
|
||||
elseif node.name == "moretrees:dates_f0" and math.random(100) <= 100 * dates_regrow_prob then
|
||||
-- Dates grow unpollinated
|
||||
minetest.swap_node(pos, {name="moretrees:dates_f1"})
|
||||
action = "nopollinate"
|
||||
elseif node.name == "moretrees:dates_f0" and moretrees.dates_regrow_pollinated and find_male_blossom(pos) then
|
||||
-- Pollinate flowers
|
||||
minetest.swap_node(pos, {name="moretrees:dates_f1"})
|
||||
action = "pollinate"
|
||||
elseif string.match(node.name, "0$") then
|
||||
-- Make female unpollinated and male flowers last a bit longer
|
||||
if math.random(flowers_wither_ichance) == 1 then
|
||||
if node.name == "moretrees:dates_f0" then
|
||||
minetest.swap_node(pos, {name="moretrees:dates_fn"})
|
||||
else
|
||||
minetest.swap_node(pos, {name="moretrees:dates_n"})
|
||||
end
|
||||
action = "wither"
|
||||
else
|
||||
action = "nowither"
|
||||
end
|
||||
elseif node.name == "moretrees:dates_f4" then
|
||||
-- Remove dates, and optionally drop them as items
|
||||
if math.random(dates_drop_ichance) == 1 then
|
||||
if moretrees.dates_item_drop_ichance > 0 and math.random(moretrees.dates_item_drop_ichance) == 1 then
|
||||
local items = minetest.get_node_drops(minetest.get_node(pos).name)
|
||||
for _, itemname in pairs(items) do
|
||||
minetest.add_item(pos, itemname)
|
||||
end
|
||||
end
|
||||
minetest.swap_node(pos, {name="moretrees:dates_n"})
|
||||
action = "drop"
|
||||
else
|
||||
action = "nodrop"
|
||||
end
|
||||
elseif string.match(node.name, "n$") then
|
||||
-- Remove stems.
|
||||
if math.random(stems_drop_ichance) == 1 then
|
||||
minetest.swap_node(pos, biome_lib.air)
|
||||
return "stemdrop"
|
||||
end
|
||||
action = "nostemdrop"
|
||||
else
|
||||
-- Grow dates
|
||||
local offset = 18
|
||||
local n = string.sub(node.name, offset)
|
||||
minetest.swap_node(pos, {name=string.sub(node.name, 1, offset-1)..n+1})
|
||||
action = "grow"
|
||||
end
|
||||
-- Don't catch up when elapsed time is large. Regular visits are needed for growth...
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(delay + math.random(moretrees.dates_grow_interval))
|
||||
return action
|
||||
end
|
||||
|
||||
--[[
|
||||
-- Alternate growth function for dates.
|
||||
-- It calls the primary growth function, but also measures CPU time consumed.
|
||||
-- Use this function to analyze date growing performance.
|
||||
local stat = {}
|
||||
stat.count = 0
|
||||
local dates_growfn_profiling = function(pos, elapsed)
|
||||
local t0 = minetest.get_us_time()
|
||||
local action = dates_growfn(pos, elapsed)
|
||||
local t1 = minetest.get_us_time()
|
||||
if t1 < t0 then
|
||||
t1 = t1 + 2^32
|
||||
end
|
||||
stat.count = stat.count + 1
|
||||
if not stat[action] then
|
||||
stat[action] = {}
|
||||
stat[action].count = 0
|
||||
stat[action].sum = 0
|
||||
stat[action].min = 9999999999
|
||||
stat[action].max = 0
|
||||
end
|
||||
stat[action].count = stat[action].count + 1
|
||||
stat[action].sum = stat[action].sum + t1-t0
|
||||
if t1-t0 < stat[action].min then
|
||||
stat[action].min = t1-t0
|
||||
end
|
||||
if t1-t0 > stat[action].max then
|
||||
stat[action].max = t1-t0
|
||||
end
|
||||
|
||||
if stat.count % 10 == 0 then
|
||||
io.write(".")
|
||||
io.flush()
|
||||
end
|
||||
if stat.count % 100 == 0 then
|
||||
print(string.format("Date grow statistics %5d:", stat.count))
|
||||
local sum = 0
|
||||
local count = 0
|
||||
if sect_search_stats.count > 0 and stat.pollinate and stat.pollinate.count > 0 then
|
||||
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
|
||||
"search", sect_search_stats.count,
|
||||
100*sect_search_stats.count/stat.pollinate.count,
|
||||
sect_search_stats.sum/sect_search_stats.count,
|
||||
sect_search_stats.min, sect_search_stats.max))
|
||||
else
|
||||
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
|
||||
"search", sect_search_stats.count,
|
||||
0, 0, 0, 0))
|
||||
end
|
||||
for action,data in pairs(stat) do
|
||||
if action ~= "count" then
|
||||
count = count + data.count
|
||||
sum = sum + data.sum
|
||||
print(string.format("\t%-12s: %6d (%4.1f%%): %6dus (%d..%d)",
|
||||
action, data.count,
|
||||
100*data.count/stat.count, data.sum/data.count,
|
||||
data.min, data.max))
|
||||
end
|
||||
end
|
||||
print(string.format("\t%-12s: %6d ( 100%%): %6dus",
|
||||
"TOTAL", count, sum/count))
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
||||
-- Register dates
|
||||
|
||||
local dates_starttimer = function(pos, elapsed)
|
||||
|
@ -732,31 +140,3 @@ for _,suffix in ipairs({"f0", "f1", "f2", "f3", "f4", "m0", "fn", "n"}) do
|
|||
}
|
||||
minetest.register_node("moretrees:dates_"..suffix, datedef)
|
||||
end
|
||||
|
||||
-- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing dates
|
||||
if moretrees.dates_regrow_pollinated or moretrees.dates_regrow_unpollinated_percent > 0 then
|
||||
local spec = {
|
||||
name = "moretrees:restart_dates_regrow_timer",
|
||||
nodenames = "group:moretrees_dates",
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if not timer:is_started() then
|
||||
dates_starttimer(pos)
|
||||
else
|
||||
local timeout = timer:get_timeout()
|
||||
local elapsed = timer:get_elapsed()
|
||||
if timeout - elapsed > moretrees.dates_grow_interval * 4/3 then
|
||||
dates_starttimer(pos, math.random(moretrees.dates_grow_interval * 4/3))
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
if minetest.register_lbm then
|
||||
minetest.register_lbm(spec)
|
||||
else
|
||||
spec.interval = 3557
|
||||
spec.chance = 10
|
||||
minetest.register_abm(spec)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -508,7 +508,7 @@ for i in ipairs(moretrees.treelist) do
|
|||
radius = decay,
|
||||
})
|
||||
end
|
||||
|
||||
--[[
|
||||
minetest.register_abm({
|
||||
nodenames = { "moretrees:"..treename.."_trunk_sideways" },
|
||||
interval = 1,
|
||||
|
@ -519,7 +519,7 @@ for i in ipairs(moretrees.treelist) do
|
|||
minetest.add_node(pos, {name = "moretrees:"..treename.."_trunk", param2 = nfdir})
|
||||
end,
|
||||
})
|
||||
|
||||
]]--
|
||||
table.insert(moretrees.avoidnodes, "moretrees:"..treename.."_trunk")
|
||||
|
||||
if moretrees.spawn_saplings then
|
||||
|
@ -684,7 +684,7 @@ minetest.register_node("moretrees:rubber_tree_trunk_empty", {
|
|||
is_ground_content = false,
|
||||
on_place = minetest.rotate_node,
|
||||
})
|
||||
|
||||
--[[
|
||||
minetest.register_abm({
|
||||
nodenames = { "moretrees:rubber_tree_trunk_empty_sideways" },
|
||||
interval = 1,
|
||||
|
@ -695,7 +695,7 @@ minetest.register_abm({
|
|||
minetest.add_node(pos, {name = "moretrees:rubber_tree_trunk_empty", param2 = nfdir})
|
||||
end,
|
||||
})
|
||||
|
||||
]]--
|
||||
-- For compatibility with old nodes, recently-changed nodes, and default nodes
|
||||
|
||||
minetest.register_alias("technic:rubber_tree_full", "moretrees:rubber_tree_trunk")
|
||||
|
|
Loading…
Reference in New Issue
Block a user