254 lines
7.1 KiB
Lua
254 lines
7.1 KiB
Lua
|
--
|
||
|
-- Minetest blueprints mod: Core functions
|
||
|
--
|
||
|
|
||
|
blueprints = {}
|
||
|
|
||
|
-- Default rules
|
||
|
-- These may be overriden on a per-node basis using '_blueprints' in the node's
|
||
|
-- definition.
|
||
|
blueprints.default_rules = {
|
||
|
-- allowed - Allows the node to be blueprint-ified. If this is 'default',
|
||
|
-- it will only allow nodes that are in the creative inventory, and will
|
||
|
-- be set to either true or false when blueprints.get_rules() is called.
|
||
|
allowed = 'default',
|
||
|
|
||
|
-- param2 - Allows param2 to be saved in the blueprint.
|
||
|
param2 = true,
|
||
|
|
||
|
-- meta - Specifies which meta strings to save. This can be 'true' to save
|
||
|
-- everything.
|
||
|
-- meta = {'formspec', 'infotext'},
|
||
|
meta = true,
|
||
|
|
||
|
-- pvmeta - Specifies which meta strings to mark as private.
|
||
|
pvmeta = {},
|
||
|
|
||
|
-- inv_lists - A list of inventory lists to be copied.
|
||
|
inv_lists = {},
|
||
|
|
||
|
-- item - The blueprint item to use.
|
||
|
item = 'blueprints:print'
|
||
|
}
|
||
|
|
||
|
-- Aliases - Allow multiple nodes to be treated internally as one.
|
||
|
local aliases = {}
|
||
|
blueprints.register_alias = function(old_node, new_node)
|
||
|
aliases[old_node] = new_node
|
||
|
end
|
||
|
|
||
|
blueprints.check_alias = function(node)
|
||
|
if aliases[node] then return aliases[node] end
|
||
|
local def = minetest.registered_nodes[node]
|
||
|
-- Mesecons integration
|
||
|
if def and def.__mesecon_state and def.__mesecon_basename then
|
||
|
node = def.__mesecon_basename .. '_off'
|
||
|
end
|
||
|
return node
|
||
|
end
|
||
|
|
||
|
blueprints.check_reverse_alias = function(new_node, old_node)
|
||
|
return blueprints.check_alias(old_node) == new_node
|
||
|
end
|
||
|
|
||
|
-- Get a list of rules for a node.
|
||
|
blueprints.get_rules = function(node)
|
||
|
if node and type(node) ~= 'string' then node = node.name end
|
||
|
|
||
|
-- Check aliases
|
||
|
node = blueprints.check_alias(node)
|
||
|
|
||
|
-- Unknown nodes cannot be blueprinted.
|
||
|
local def = false
|
||
|
if node and node ~= 'ignore' then
|
||
|
def = minetest.registered_nodes[node]
|
||
|
end
|
||
|
if not def then
|
||
|
return {
|
||
|
allowed = false,
|
||
|
param2 = false,
|
||
|
meta = {},
|
||
|
pvmeta = {},
|
||
|
inv_lists = {},
|
||
|
item = 'blueprints:blank'
|
||
|
}
|
||
|
end
|
||
|
|
||
|
-- Use the default rules
|
||
|
local node_rules = def._blueprints
|
||
|
if not node_rules then
|
||
|
if def.groups and def.groups.not_in_creative_inventory then
|
||
|
node_rules = {}
|
||
|
else
|
||
|
return blueprints.default_rules
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Replace any omitted values with the defaults.
|
||
|
local rules = {}
|
||
|
for k, v in pairs(blueprints.default_rules) do
|
||
|
if node_rules[k] ~= nil then
|
||
|
rules[k] = node_rules[k]
|
||
|
else
|
||
|
rules[k] = v
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Check for 'You hacker you!'
|
||
|
if rules.allowed == 'default' then
|
||
|
if def.groups and def.groups.not_in_creative_inventory then
|
||
|
rules.allowed = false
|
||
|
else
|
||
|
rules.allowed = true
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return rules
|
||
|
end
|
||
|
|
||
|
-- Get a nicer inv_lists
|
||
|
local function get_inv_lists(rules)
|
||
|
local inv_lists = {}
|
||
|
if rules.inv_lists then
|
||
|
for _, list in ipairs(rules.inv_lists) do
|
||
|
inv_lists[list] = true
|
||
|
end
|
||
|
end
|
||
|
return inv_lists
|
||
|
end
|
||
|
|
||
|
-- Get a blueprint string for a node.
|
||
|
blueprints.get_blueprint = function(pos, raw)
|
||
|
-- Check aliases
|
||
|
local node = minetest.get_node(pos)
|
||
|
node.name = blueprints.check_alias(node.name)
|
||
|
|
||
|
-- Get the rules list
|
||
|
local rules = blueprints.get_rules(node)
|
||
|
if not rules.allowed then return end
|
||
|
|
||
|
-- Using a meta table allows ints/floats/etc to be copied nicely.
|
||
|
local blueprint = {name = node.name, pattern = rules.pattern}
|
||
|
local metatable = minetest.get_meta(pos):to_table()
|
||
|
|
||
|
-- Copy across allowed metadata fields
|
||
|
if (rules.meta == true or #rules.meta > 0) and metatable.fields then
|
||
|
if rules.meta == true then
|
||
|
blueprint.meta = metatable.fields
|
||
|
else
|
||
|
blueprint.meta = {}
|
||
|
for _, name in ipairs(rules.meta) do
|
||
|
blueprint.meta[name] = metatable.fields[name]
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Get a nicer inv_lists
|
||
|
local inv_lists = get_inv_lists(rules)
|
||
|
|
||
|
-- Copy allowed inventories
|
||
|
if metatable.inventory then
|
||
|
blueprint.inv = {}
|
||
|
for listname, list in pairs(metatable.inventory) do
|
||
|
blueprint.inv[listname] = {}
|
||
|
for id, itemstack in ipairs(list) do
|
||
|
if inv_lists[listname] then
|
||
|
blueprint.inv[listname][id] = itemstack:to_table() or ''
|
||
|
else
|
||
|
blueprint.inv[listname][id] = ''
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Copy across param2
|
||
|
if rules.param2 then
|
||
|
blueprint.param2 = node.param2
|
||
|
end
|
||
|
|
||
|
-- Return the blueprint
|
||
|
if not raw then
|
||
|
blueprint = minetest.serialize(blueprint)
|
||
|
end
|
||
|
return blueprint
|
||
|
end
|
||
|
|
||
|
-- Apply blueprints (and double-check the allowed fields)
|
||
|
blueprints.apply_blueprint = function(pos, blueprint, only_if_exists)
|
||
|
-- Deserialize if required and get the rules
|
||
|
if type(blueprint) == 'string' then
|
||
|
blueprint = minetest.deserialize(blueprint)
|
||
|
end
|
||
|
if not blueprint then return end
|
||
|
|
||
|
-- Make sure the node exists
|
||
|
if only_if_exists then
|
||
|
local node = minetest.get_node(pos)
|
||
|
if node.name ~= blueprint.name then
|
||
|
-- "Un-alias" the blueprint.
|
||
|
if blueprints.check_reverse_alias(blueprint.name, node.name) then
|
||
|
blueprint.name = node.name
|
||
|
else
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Get the rules
|
||
|
local rules = blueprints.get_rules(blueprint)
|
||
|
if not rules or not rules.allowed then return end
|
||
|
|
||
|
-- Set the node (and param2)
|
||
|
local node = {name = blueprint.name}
|
||
|
if rules.param2 and blueprint.param2 then
|
||
|
node.param2 = blueprint.param2
|
||
|
end
|
||
|
minetest.set_node(pos, node)
|
||
|
local metatable = {fields = {}, inventory = {}}
|
||
|
|
||
|
-- Copy across allowed metadata fields
|
||
|
if blueprint.meta and rules.meta then
|
||
|
if rules.meta == true then
|
||
|
metatable.fields = blueprint.meta
|
||
|
else
|
||
|
for _, name in ipairs(rules.meta) do
|
||
|
metatable.fields[name] = blueprint.meta[name]
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Copy allowed inventories
|
||
|
if blueprint.inv then
|
||
|
local inv_lists = get_inv_lists(rules)
|
||
|
|
||
|
for name, inv in pairs(blueprint.inv) do
|
||
|
metatable.inventory[name] = {}
|
||
|
for id, item in ipairs(inv) do
|
||
|
if not inv_lists[name] then item = '' end
|
||
|
metatable.inventory[name][id] = ItemStack(item)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Update the node meta
|
||
|
local meta = minetest.get_meta(pos)
|
||
|
meta:from_table(metatable)
|
||
|
meta:mark_as_private(rules.pvmeta)
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
-- Protection check function
|
||
|
blueprints.check_protection = function(pos, name)
|
||
|
if type(name) ~= 'string' then
|
||
|
name = name:get_player_name()
|
||
|
end
|
||
|
|
||
|
if minetest.is_protected(pos, name) and
|
||
|
not minetest.check_player_privs(name, {protection_bypass=true}) then
|
||
|
minetest.record_protection_violation(pos, name)
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
return false
|
||
|
end
|