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)