EinsDreiDreiSieben/mods/abdecor/init.lua
2025-05-04 16:01:41 +02:00

227 lines
No EOL
6.5 KiB
Lua

local modpath = minetest.get_modpath("abdecor")
abdecor = {}
abdecor.registered_names = {}
abdecor.registered_advanced_decorations = {}
abdecor.register_advanced_decoration = function(name, def)
-- Ensure that all necessary arguments are defined
if not name or not def.target or not def.fn then
minetest.warn("[abdecor] Advanced decoration '" .. (name or "???") .. "' was not provided with all necessary values.")
return false
end
-- Ensure that the name isn't already in use
local mapgen = nil
if abdecor.registered_names[name] then
minetest.warn("[abdecor] Advanced decoration '" .. name .. "' was already registered.")
return false
else
mapgen = {}
abdecor.registered_names[name] = true
end
-- Check for all_floors + all_ceilings flags which is unsupported due to
-- undefined mapgen node erasure
local is_ceiling = false
local is_water_surface = false
def.target.flags = def.target.flags or ""
if def.target.flags and def.target.flags:find("all_floors") and def.target.flags:find("all_ceilings") then
minetest.warn("[abdecor] Advanced decoration '" .. name .. "' specifies all_floors and all_ceilings which the abdecor API does not support.")
return false
else
is_ceiling = def.target.flags:find("all_ceilings") and true or false
is_water_surface = def.target.flags:find("water_surface") and true or false
end
-- Register node for targeted mapgen node
local mapgen_node_name = "abdecor:" .. name .. "_marker"
minetest.register_node(":" .. mapgen_node_name,{
drawtype = "airlike",
sunlight_propagates = true,
walkable = false,
pointable = true,
diggable = false,
climbable = false,
buildable_to = true,
floodable = false,
groups = { not_in_creative_inventory = 1 },
})
-- Register injected decor for targeted mapgen node placement
def.target.deco_type = "simple"
def.target.name = "abdecor:" .. name .. "_decoration"
def.target.decoration = mapgen_node_name
minetest.register_decoration(def.target)
local decoration_id = minetest.get_decoration_id(def.target.name)
minetest.set_gen_notify({ decoration = true },{decoration_id})
mapgen.decoration_id = "decoration#" .. decoration_id
abdecor.registered_advanced_decorations[mapgen.decoration_id] = mapgen
-- Compute decoration placement offset for automatic erasure during mapgen
mapgen.offset = (is_water_surface and 0 or 1) * (is_ceiling and -1 or 1) + (def.target.place_offset_y or 0)
-- Capture placement function and voxelmanip flags for later use
mapgen.fn = def.fn
if not def.flags then
def.flags = {}
end
if def.flags.param2 == nil then
def.flags.param2 = false
end
if def.flags.liquid == nil then
def.flags.liquid = false
end
if def.flags.schematic == nil then
def.flags.schematic = false
end
mapgen.flags = def.flags
-- Success!
return true
end
-- Schematic placement helper functions
abdecor._place_schematic_check = function(args)
-- Fail or set defaults for missing arguments
if not args.pos or not args.schematic then
return nil -- fail
end
args.rotation = args.rotation or "random"
args.replacements = args.replacements or {}
args.force_placement = (args.force_placement == nil) and false or true
args.flags = args.flags or ""
-- Arguments are good
return true
end
-- Register targeted mapgen generation
local vdata = {}
local vparam2 = {}
minetest.register_on_generated(function(minp, maxp, seed)
-- Lazy initializers for mapgen
local mapgen = {}
local is_mapgen_init = false
local function mapgen_init()
if not is_mapgen_init then
mapgen.vm, mapgen.emin, mapgen.emax = minetest.get_mapgen_object("voxelmanip")
mapgen.va = VoxelArea:new({MinEdge = mapgen.emin, MaxEdge = mapgen.emax})
is_mapgen_init = true
end
end
local is_vm_data_init = false
local function vm_data_init()
mapgen_init()
if not is_vm_data_init then
mapgen.vm:get_data(vdata)
is_vm_data_init = true
end
end
local is_vm_param2_init = false
local function vm_param2_init()
mapgen_init()
if not is_vm_param2_init then
mapgen.vm:get_param2_data(vparam2)
is_vm_param2_init = true
end
end
local is_schematic_init = false
local function schematic_init()
if not is_schematic_init then
mapgen.place_schematic = function(args)
mapgen.vm:set_data(vdata)
local retval = abdecor._place_schematic_check(args) and minetest.place_schematic_on_vmanip(mapgen.vm,args.pos,args.schematic,args.rotation,args.replacements,args.force_placement,args.flags)
if retval then
mapgen.vm:get_data(vdata)
end
return retval
end
is_schematic_init = true
end
end
mapgen.calc_lighting = function(p1,p2,propagate_shadow)
return mapgen.vm:calc_lighting(p1,p2,propagate_shadow)
end
local is_liquid = false
-- Place any targeted decorations that were generated
local gennotify = minetest.get_mapgen_object("gennotify")
for decoration_id,decorations in pairs(gennotify) do
local decoration = abdecor.registered_advanced_decorations[decoration_id]
if decoration then
-- Initialize vm data
vm_data_init()
-- Initialize param2 data if needed
if decoration.flags.param2 then
vm_param2_init()
end
-- Initialize schematic placement function if needed
if decoration.flags.schematic then
schematic_init()
end
-- Note liquid status
if decoration.flags.liquid then
is_liquid = true
end
-- Erase dummy mapgen nodes and process decorations
for i = 1, #decorations do
local pos = decorations[i]
vdata[mapgen.va:index(pos.x,pos.y + decoration.offset,pos.z)] = minetest.CONTENT_AIR
decoration.fn({
pos = pos,
voxelarea = mapgen.va,
data = vdata,
param2 = vparam2,
minp = minp,
maxp = maxp,
seed = seed,
place_schematic = mapgen.place_schematic,
calc_lighting = mapgen.calc_lighting,
index2d = function(x,z) -- (portions of this function © FaceDeer 2018, licensed MIT, copied from https://github.com/minetest-mods/mapgen_helper/blob/2521562a42472271d9d761f2b1e84ead59250a14/noise_manager.lua)
if type(x) == "table" then -- accept x/y/z pos table
z = x.z
x = x.x
end
return x - minp.x +
(maxp.x - minp.x + 1)
*(z - minp.z)
+ 1
end,
})
end
end
end
-- Write data back to voxelmanip if necessary
if is_mapgen_init then
if is_vm_data_init then
mapgen.vm:set_data(vdata)
end
if is_vm_param2_init then
mapgen.vm:set_param2_data(vparam2)
end
if is_liquid then
mapgen.vm:update_liquids()
end
if is_vm_data_init or is_vm_param2_init then
mapgen.vm:write_to_map()
end
end
end)