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:
parent
186d8743b4
commit
cf67547455
142
init.lua
142
init.lua
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user