Xpanes: Convert to connected nodeboxes

I've rewritten this to use connected nodeboxes, but with a caveat. In
order to make flat nodes look better, I'm keeping one non-connected
pane that is flat around to convert flat sections to the flat nodes
instead of connected, as these look better and are easier to work
with. Once more sides are needed we convert the panes on the fly to
connected nodes and recalculate the shape.

We don't paint any of the half-panes that the previous generation of
xpanes did. There's no need and it's harder to work with. Updating the
nodes also seems more natural and placement and removal works straight
forward.

The conversion of old panes relies on an LBM, and does a reasonable
conversion job, but it's not exact, since the panes behave slightly
different now.

The game API documentation was wrong to begin with. We discard param
nr. 2 of the API entirely, and correct the tile usage text.
This commit is contained in:
Auke Kok 2016-03-17 00:40:30 -07:00 committed by paramat
parent 992f295880
commit 54235f3276
4 changed files with 137 additions and 134 deletions

@ -421,7 +421,7 @@ Creates panes that automatically connect to each other
### Pane definition
{
textures = {"texture_Bottom_top", "texture_left_right", "texture_front_back"}, -- More tiles aren't supported
textures = {"texture for sides", (unused), "texture for top and bottom"}, -- More tiles aren't supported
groups = {group = rating}, -- Uses the known node groups, see [Known damage and digging time defining groups]
sounds = SoundSpec, -- See [#Default sounds]
recipe = {{"","","","","","","","",""}}, -- Recipe field only

@ -6,6 +6,7 @@ Authors of source code
----------------------
Originally by xyz (MIT)
BlockMen (MIT)
sofar (MIT)
Various Minetest developers and contributors (MIT)
Authors of media (textures)

@ -1,156 +1,146 @@
xpanes = {}
local function rshift(x, by)
return math.floor(x / 2 ^ by)
local function is_pane(pos)
return minetest.get_item_group(minetest.get_node(pos).name, "pane") > 0
end
local directions = {
{x = 1, y = 0, z = 0},
{x = 0, y = 0, z = 1},
{x = -1, y = 0, z = 0},
{x = 0, y = 0, z = -1},
}
local function connects_dir(pos, name, dir)
local aside = vector.add(pos, minetest.facedir_to_dir(dir))
if is_pane(aside) then
return true
end
local function update_pane(pos, name)
if not minetest.get_node(pos).name:find("^xpanes:"..name) then
local connects_to = minetest.registered_nodes[name].connects_to
if not connects_to then
return false
end
local list = minetest.find_nodes_in_area(aside, aside, connects_to)
if #list > 0 then
return true
end
return false
end
local function swap(pos, node, name, param2)
if node.name == name and node.param2 == param2 then
return
end
local sum = 0
for i, dir in pairs(directions) do
local node = minetest.get_node(vector.add(pos, dir))
local def = minetest.registered_nodes[node.name]
local pane_num = def and def.groups.pane or 0
if pane_num > 0 or not def or (def.walkable ~= false and
def.drawtype ~= "nodebox") then
sum = sum + 2 ^ (i - 1)
minetest.set_node(pos, {name = name, param2 = param2})
end
local function update_pane(pos)
if not is_pane(pos) then
return
end
local node = minetest.get_node(pos)
local name = node.name
if name:sub(-5) == "_flat" then
name = name:sub(1, -6)
end
local any = node.param2
local c = {}
local count = 0
for dir = 0, 3 do
c[dir] = connects_dir(pos, name, dir)
if c[dir] then
any = dir
count = count + 1
end
end
if sum == 0 then
sum = 15
end
minetest.set_node(pos, {name = "xpanes:"..name.."_"..sum})
end
local function update_nearby(pos, node)
node = node or minetest.get_node(pos)
local name = node.name
if not name or node.name:sub(1, 7) ~= "xpanes:" then
return
end
local underscore_pos = string.find(name, "_[^_]*$") or 0
local len = name:len()
local num = tonumber(name:sub(underscore_pos+1, len))
if not num or num < 1 or num > 15 then
name = name:sub(8)
if count == 0 then
swap(pos, node, name .. "_flat", any)
elseif count == 1 then
swap(pos, node, name .. "_flat", (any + 1) % 4)
elseif count == 2 then
if (c[0] and c[2]) or (c[1] and c[3]) then
swap(pos, node, name .. "_flat", (any + 1) % 4)
else
swap(pos, node, name, 0)
end
else
name = name:sub(8, underscore_pos - 1)
end
for i, dir in pairs(directions) do
update_pane(vector.add(pos, dir), name)
swap(pos, node, name, 0)
end
end
minetest.register_on_placenode(update_nearby)
minetest.register_on_dignode(update_nearby)
minetest.register_on_placenode(function(pos, node)
if minetest.get_item_group(node, "pane") then
update_pane(pos)
end
for i = 0, 3 do
local dir = minetest.facedir_to_dir(i)
update_pane(vector.add(pos, dir))
end
end)
local half_boxes = {
{0, -0.5, -1/32, 0.5, 0.5, 1/32},
{-1/32, -0.5, 0, 1/32, 0.5, 0.5},
{-0.5, -0.5, -1/32, 0, 0.5, 1/32},
{-1/32, -0.5, -0.5, 1/32, 0.5, 0}
}
local full_boxes = {
{-0.5, -0.5, -1/32, 0.5, 0.5, 1/32},
{-1/32, -0.5, -0.5, 1/32, 0.5, 0.5}
}
local sb_half_boxes = {
{0, -0.5, -0.06, 0.5, 0.5, 0.06},
{-0.06, -0.5, 0, 0.06, 0.5, 0.5},
{-0.5, -0.5, -0.06, 0, 0.5, 0.06},
{-0.06, -0.5, -0.5, 0.06, 0.5, 0}
}
local sb_full_boxes = {
{-0.5, -0.5, -0.06, 0.5, 0.5, 0.06},
{-0.06, -0.5, -0.5, 0.06, 0.5, 0.5}
}
local pane_def_fields = {
drawtype = "airlike",
paramtype = "light",
is_ground_content = false,
sunlight_propagates = true,
walkable = false,
pointable = false,
diggable = false,
buildable_to = true,
air_equivalent = true,
}
minetest.register_on_dignode(function(pos)
for i = 0, 3 do
local dir = minetest.facedir_to_dir(i)
update_pane(vector.add(pos, dir))
end
end)
xpanes = {}
function xpanes.register_pane(name, def)
for i = 1, 15 do
local need = {}
local cnt = 0
for j = 1, 4 do
if rshift(i, j - 1) % 2 == 1 then
need[j] = true
cnt = cnt + 1
end
end
local take = {}
local take2 = {}
if need[1] == true and need[3] == true then
need[1] = nil
need[3] = nil
table.insert(take, full_boxes[1])
table.insert(take2, sb_full_boxes[1])
end
if need[2] == true and need[4] == true then
need[2] = nil
need[4] = nil
table.insert(take, full_boxes[2])
table.insert(take2, sb_full_boxes[2])
end
for k in pairs(need) do
table.insert(take, half_boxes[k])
table.insert(take2, sb_half_boxes[k])
end
local texture = def.textures[1]
if cnt == 1 then
texture = def.textures[1].."^"..def.textures[2]
end
minetest.register_node(":xpanes:"..name.."_"..i, {
drawtype = "nodebox",
tiles = {def.textures[3], def.textures[3], texture},
paramtype = "light",
groups = def.groups,
drop = "xpanes:"..name,
sounds = def.sounds,
node_box = {
type = "fixed",
fixed = take
},
selection_box = {
type = "fixed",
fixed = take2
}
})
minetest.register_alias("xpanes:" .. name .. "_" .. i, "xpanes:" .. name .. "_flat")
end
for k, v in pairs(pane_def_fields) do
def[k] = def[k] or v
end
local flatgroups = table.copy(def.groups)
flatgroups.pane = 1
minetest.register_node(":xpanes:" .. name .. "_flat", {
description = def.description,
drawtype = "nodebox",
paramtype = "light",
is_ground_content = false,
sunlight_propagates = true,
inventory_image = def.inventory_image,
wield_image = def.wield_image,
paramtype2 = "facedir",
tiles = {def.textures[3], def.textures[3], def.textures[1]},
groups = flatgroups,
drop = "xpanes:" .. name .. "_flat",
sounds = def.sounds,
node_box = {
type = "fixed",
fixed = {{-1/2, -1/2, -1/32, 1/2, 1/2, 1/32}},
},
selection_box = {
type = "fixed",
fixed = {{-1/2, -1/2, -1/32, 1/2, 1/2, 1/32}},
},
connect_sides = { "left", "right" },
})
def.on_construct = function(pos)
update_pane(pos, name)
end
minetest.register_node(":xpanes:"..name, def)
local groups = table.copy(def.groups)
groups.pane = 1
groups.not_in_creative_inventory = 1
minetest.register_node(":xpanes:" .. name, {
drawtype = "nodebox",
paramtype = "light",
is_ground_content = false,
sunlight_propagates = true,
description = def.description,
tiles = {def.textures[3], def.textures[3], def.textures[1]},
groups = groups,
drop = "xpanes:" .. name .. "_flat",
sounds = def.sounds,
node_box = {
type = "connected",
fixed = {{-1/32, -1/2, -1/32, 1/32, 1/2, 1/32}},
connect_front = {{-1/32, -1/2, -1/2, 1/32, 1/2, -1/32}},
connect_left = {{-1/2, -1/2, -1/32, -1/32, 1/2, 1/32}},
connect_back = {{-1/32, -1/2, 1/32, 1/32, 1/2, 1/2}},
connect_right = {{1/32, -1/2, -1/32, 1/2, 1/2, 1/32}},
},
connects_to = {"group:pane", "group:stone", "group:glass", "group:wood", "group:tree"},
})
minetest.register_craft({
output = "xpanes:"..name.." 16",
output = "xpanes:" .. name .. "_flat 16",
recipe = def.recipe
})
end
@ -161,7 +151,7 @@ xpanes.register_pane("pane", {
inventory_image = "default_glass.png",
wield_image = "default_glass.png",
sounds = default.node_sound_glass_defaults(),
groups = {snappy=2, cracky=3, oddly_breakable_by_hand=3, pane=1},
groups = {snappy=2, cracky=3, oddly_breakable_by_hand=3},
recipe = {
{"default:glass", "default:glass", "default:glass"},
{"default:glass", "default:glass", "default:glass"}
@ -173,7 +163,7 @@ xpanes.register_pane("bar", {
textures = {"xpanes_bar.png","xpanes_bar.png","xpanes_space.png"},
inventory_image = "xpanes_bar.png",
wield_image = "xpanes_bar.png",
groups = {cracky=2, pane=1},
groups = {cracky=2},
sounds = default.node_sound_stone_defaults(),
recipe = {
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
@ -181,3 +171,14 @@ xpanes.register_pane("bar", {
}
})
minetest.register_lbm({
name = "xpanes:gen2",
nodenames = {"group:pane"},
action = function(pos, node)
update_pane(pos)
for i = 0, 3 do
local dir = minetest.facedir_to_dir(i)
update_pane(vector.add(pos, dir))
end
end
})

@ -4,6 +4,7 @@ License of source code
The MIT License (MIT)
Copyright (C) 2014-2016 xyz
Copyright (C) 2014-2016 BlockMen
Copyright (C) 2016 Auke Kok <sofar@foo-projects.org>
Copyright (C) 2014-2016 Various Minetest developers and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this