Combine mapgen callbacks for efficiency (#7)

1. Two read/write pairs to the VM have been replaced with one.
2. If no changes are made to the data, it is not written back to the VM.
This commit is contained in:
Jude Melton-Houghton 2022-04-14 13:34:28 -04:00 committed by GitHub
parent 186d8743b4
commit cf67547455
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

142
init.lua
View File

@ -320,29 +320,7 @@ if not springs then
end
minetest.register_node("dynamic_liquid:clay", clay_def)
local data = {}
if springs then
local c_clay = minetest.get_content_id("default:clay")
local c_spring_clay = minetest.get_content_id("dynamic_liquid:clay")
-- Turn mapgen clay into spring clay
minetest.register_on_generated(function(minp, maxp, seed)
if minp.y >= water_level or maxp.y <= -15 then
return
end
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
for voxelpos, voxeldata in pairs(data) do
if voxeldata == c_clay then
data[voxelpos] = c_spring_clay
end
end
vm:set_data(data)
vm:write_to_map()
end)
minetest.register_abm({
label = "dynamic_liquid damp clay spring",
nodenames = {"dynamic_liquid:clay"},
@ -409,34 +387,38 @@ end
local mapgen_prefill = minetest.settings:get_bool("dynamic_liquid_mapgen_prefill", true)
local waternodes
if springs or mapgen_prefill then
local data = {}
if mapgen_prefill then
local c_clay = minetest.get_content_id("default:clay")
local c_spring_clay = minetest.get_content_id("dynamic_liquid:clay")
local c_water = minetest.get_content_id("default:water_source")
local c_air = minetest.get_content_id("air")
waternodes = {}
local waternodes = {}
local fill_to = function (vi, data, area)
if area:containsi(vi) and area:position(vi).y <= water_level then
if data[vi] == c_air then
data[vi] = c_water
table.insert(waternodes, vi)
return true
end
end
return false
end
-- local count = 0
local drop_liquid = function(vi, data, area, min_y)
if data[vi] ~= c_water then
-- we only care about water.
return
return false
end
local start = vi -- remember the water node we started from
local ystride = area.ystride
vi = vi - ystride
if data[vi] ~= c_air then
-- if there's no air below this water node, give up immediately.
return
return false
end
vi = vi - ystride -- There's air below the water, so move down one.
while data[vi] == c_air and area:position(vi).y > min_y do
@ -452,58 +434,80 @@ if mapgen_prefill then
-- if count % 100 == 0 then
-- minetest.chat_send_all("dropped water " .. (start-vi)/ystride .. " at " .. minetest.pos_to_string(area:position(vi)))
-- end
return true
end
minetest.register_on_generated(function(minp, maxp, seed)
if minp.y > water_level then
-- we're in the sky.
return
end
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
vm:get_data(data)
local maxp_y = maxp.y
local minp_y = minp.y
if maxp_y > -70 then
local top = vector.new(maxp.x, math.min(maxp_y, water_level), maxp.z) -- prevents flood fill from affecting any water above sea level
for vi in area:iterp(minp, top) do
if data[vi] == c_water then
table.insert(waternodes, vi)
local vm, emin, emax
local dirty = false
local update_liquids = false
if springs and minp_y < water_level and maxp_y > -15 then
vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
for voxelpos = 1, #data do
if data[voxelpos] == c_clay then
data[voxelpos] = c_spring_clay
dirty = true
end
end
while table.getn(waternodes) > 0 do
local vi = table.remove(waternodes)
local below = vi - area.ystride
local left = vi - area.zstride
local right = vi + area.zstride
local front = vi - 1
local back = vi + 1
fill_to(below, data, area)
fill_to(left, data, area)
fill_to(right, data, area)
fill_to(front, data, area)
fill_to(back, data, area)
end
if mapgen_prefill and minp_y <= water_level then
if not vm then
vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
end
else
-- Caves sometimes generate with liquid nodes hovering in mid air.
-- This immediately drops them straight down as far as they can go, reducing the ABM thrashing.
-- We only iterate down to minp.y+1 because anything at minp.y will never be dropped farther anyway.
for vi in area:iter(minp.x, minp_y+1, minp.z, maxp.x, maxp_y, maxp.z) do
-- fortunately, area:iter iterates through y columns going upward. Just what we need!
-- We could possibly be a bit more efficient by remembering how far we dropped then
-- last liquid node in a column and moving stuff down that far,
-- but for now let's keep it simple.
drop_liquid(vi, data, area, minp_y)
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
if maxp_y > -70 then
local top = vector.new(maxp.x, math.min(maxp_y, water_level), maxp.z) -- prevents flood fill from affecting any water above sea level
for vi in area:iterp(minp, top) do
if data[vi] == c_water then
table.insert(waternodes, vi)
end
end
while table.getn(waternodes) > 0 do
local vi = table.remove(waternodes)
local below = vi - area.ystride
local left = vi - area.zstride
local right = vi + area.zstride
local front = vi - 1
local back = vi + 1
dirty = fill_to(below, data, area) or dirty
dirty = fill_to(left, data, area) or dirty
dirty = fill_to(right, data, area) or dirty
dirty = fill_to(front, data, area) or dirty
dirty = fill_to(back, data, area) or dirty
end
else
-- Caves sometimes generate with liquid nodes hovering in mid air.
-- This immediately drops them straight down as far as they can go, reducing the ABM thrashing.
-- We only iterate down to minp.y+1 because anything at minp.y will never be dropped farther anyway.
for vi in area:iter(minp.x, minp_y+1, minp.z, maxp.x, maxp_y, maxp.z) do
-- fortunately, area:iter iterates through y columns going upward. Just what we need!
-- We could possibly be a bit more efficient by remembering how far we dropped then
-- last liquid node in a column and moving stuff down that far,
-- but for now let's keep it simple.
dirty = drop_liquid(vi, data, area, minp_y) or dirty
end
end
update_liquids = dirty
end
if dirty then
vm:set_data(data)
vm:write_to_map()
if update_liquids then
vm:update_liquids()
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_liquids()
end)
end