Skip to content

Commit

Permalink
Add node texture variants
Browse files Browse the repository at this point in the history
  • Loading branch information
TurkeyMcMac authored and sfence committed Sep 15, 2023
1 parent 2479d51 commit f5353e0
Show file tree
Hide file tree
Showing 28 changed files with 874 additions and 203 deletions.
19 changes: 19 additions & 0 deletions builtin/common/item_s.lua
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,25 @@ function core.strip_param2_color(param2, paramtype2)
return param2
end

function core.strip_param2_variant(param2, def)
if not def or def.variant_count <= 1 or not def.param2_variant then
return 0
end
local bf = def.param2_variant
local right_mask = bit.lshift(1, bf.width) - 1
return bit.band(bit.rshift(param2, bf.offset), right_mask) % def.variant_count
end

function core.set_param2_variant(param2, variant, def)
if not def or not def.param2_variant then
return param2
end
local bf = def.param2_variant
local mask = bit.lshift(bit.lshift(1, bf.width) - 1, bf.offset)
local new_bits = bit.band(bit.lshift(variant, bf.offset), mask)
return bit.bor(bit.band(param2, bit.bnot(mask)), new_bits)
end

-- Content ID caching

local old_get_content_id = core.get_content_id
Expand Down
9 changes: 7 additions & 2 deletions builtin/game/falling.lua
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ core.register_entity(":__builtin:falling_node", {
self.floats = core.get_item_group(node.name, "float") ~= 0

-- Set entity visuals
local variant = core.strip_param2_variant(node.param2, def)
if def.drawtype == "torchlike" or def.drawtype == "signlike" then
local textures
if def.tiles and def.tiles[1] then
local tile = def.tiles[1]
local tiles = def.variants and def.variants[variant] and def.variants[variant].tiles or def.tiles
if tiles and tiles[1] then
local tile = tiles[1]
if type(tile) == "table" then
tile = tile.name
end
Expand All @@ -110,6 +112,9 @@ core.register_entity(":__builtin:falling_node", {
if core.is_colored_paramtype(def.paramtype2) then
itemstring = core.itemstring_with_palette(itemstring, node.param2)
end
if variant > 0 then
itemstring = core.itemstring_with_variant(itemstring, variant)
end
-- FIXME: solution needed for paramtype2 == "leveled"
-- Calculate size of falling node
local s = {}
Expand Down
37 changes: 30 additions & 7 deletions builtin/game/item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,18 @@ function core.get_node_drops(node, toolname)
local ptype = def and def.paramtype2
-- get color, if there is color (otherwise nil)
local palette_index = core.strip_param2_color(param2, ptype)
-- get variant (always a number)
local variant = core.strip_param2_variant(param2, def)
if drop == nil then
-- default drop
local itemstring = nodename
if palette_index then
local stack = ItemStack(nodename)
stack:get_meta():set_int("palette_index", palette_index)
return {stack:to_string()}
itemstring = core.itemstring_with_palette(itemstring, palette_index)
end
return {nodename}
if variant > 0 then
itemstring = core.itemstring_with_variant(itemstring, variant)
end
return {itemstring}
elseif type(drop) == "string" then
-- itemstring drop
return drop ~= "" and {drop} or {}
Expand Down Expand Up @@ -120,9 +124,10 @@ function core.get_node_drops(node, toolname)
for _, add_item in ipairs(item.items) do
-- add color, if necessary
if item.inherit_color and palette_index then
local stack = ItemStack(add_item)
stack:get_meta():set_int("palette_index", palette_index)
add_item = stack:to_string()
add_item = core.itemstring_with_palette(add_item, palette_index)
end
if item.inherit_variant then
add_item = core.itemstring_with_variant(add_item, variant)
end
got_items[#got_items+1] = add_item
end
Expand Down Expand Up @@ -239,6 +244,13 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
end
end

-- Transfer variant
if not def.place_param2 and def.variant_count > 1 then
local variant = math.min(math.max(math.floor(metatable.variant or 0), 0),
def.variant_count - 1)
newnode.param2 = core.set_param2_variant(newnode.param2, variant, def)
end

-- Check if the node is attached and if it can be placed there
local an = core.get_item_group(def.name, "attached_node")
if an ~= 0 and
Expand Down Expand Up @@ -573,6 +585,12 @@ function core.itemstring_with_color(item, colorstring)
return stack:to_string()
end

function core.itemstring_with_variant(item, variant)
local stack = ItemStack(item) -- convert to ItemStack
stack:get_meta():set_string("variant", variant > 0 and variant or "")
return stack:to_string()
end

-- This is used to allow mods to redefine core.item_place and so on
-- NOTE: This is not the preferred way. Preferred way is to provide enough
-- callbacks to not require redefining global functions. -celeron55
Expand All @@ -594,6 +612,7 @@ core.nodedef_default = {
-- name intentionally not defined here
description = "",
groups = {},
variant_count = 1,
inventory_image = "",
wield_image = "",
wield_scale = vector.new(1, 1, 1),
Expand Down Expand Up @@ -624,6 +643,7 @@ core.nodedef_default = {
post_effect_color = {a=0, r=0, g=0, b=0},
paramtype = "none",
paramtype2 = "none",
param2_variant = {width = 0, offset = 0},
is_ground_content = true,
sunlight_propagates = false,
walkable = true,
Expand All @@ -649,6 +669,7 @@ core.craftitemdef_default = {
-- name intentionally not defined here
description = "",
groups = {},
variant_count = 1,
inventory_image = "",
wield_image = "",
wield_scale = vector.new(1, 1, 1),
Expand All @@ -669,6 +690,7 @@ core.tooldef_default = {
-- name intentionally not defined here
description = "",
groups = {},
variant_count = 1,
inventory_image = "",
wield_image = "",
wield_scale = vector.new(1, 1, 1),
Expand All @@ -689,6 +711,7 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items
-- name intentionally not defined here
description = "",
groups = {},
variant_count = 1,
inventory_image = "",
wield_image = "",
wield_scale = vector.new(1, 1, 1),
Expand Down
95 changes: 95 additions & 0 deletions doc/lua_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,60 @@ minetest.register_node("default:dirt_with_grass", {
})
```

Variants
--------

Items can have "variants", which are numbered states that can determine certain
properties. The number of variants is specified with the item definition field
`variant_count`. Each variant is numbered from 0 to `variant_count` - 1. Every
item has at least one variant (numbered 0). Nodes can specify a part of param2
to read as the variant number by setting the `param2_variant` field to a
`BitField`.

The currently supported variant properties are `tiles`, `overlay_tiles`, and
`special_tiles`. The `variants` table in the item definition is a mapping from
variant numbers to variant tables. These tables can include the aforementioned
fields to set the properties for particular variants. Variants not present in
the mapping default to the values of the aforementioned fields specified in the
item definition table. Old clients will receive only the variant 0 tiles.

Items with multiple variants can specify a variant number with the "variant" key
in their metadata. The absence of the key indicates a variant number of 0, and
this is the canonical representation of the 0 variant. The helper function
`minetest.itemstring_with_variant` is a shortcut for creating such itemstrings.
The variant is preserved when a node is placed or dug. Custom drops will inherit
the variant only if `inherit_variant` is set to `true` in their specification.

Example node with variants:

minetest.register_node("mod:grass", {
description = "Grass",
drawtype = "plantlike",
paramtype = "light",
sunlight_propagates = true,
walkable = false,
groups = {dig_immediate = 3},
-- There are 4 variants numbered 0 to 3.
variant_count = 4,
-- The lowest 2 bits store the variant number.
param2_variant = {width = 2, offset = 0},
-- These tiles will be used for variants not otherwise specified,
-- in this case variant 0.
tiles = {"mod_grass1.png"},
-- Tiles for variants 1, 2, and 3 are specified here.
variants = {
{tiles = {"mod_grass2.png"}},
{tiles = {"mod_grass3.png"}},
{tiles = {"mod_grass4.png"}},
},
drop = {
items = {
-- The seeds will inherit the variant of the grass.
{items = {"mod:seeds"}, inherit_variant = true},
}
}
})



Sounds
Expand Down Expand Up @@ -1818,6 +1872,13 @@ Exact pointing location (currently only `Raycast` supports these fields):
For entities with rotated selection boxes, this will be rotated properly
by the entity's rotation - it will always be in absolute world space.

`BitField`
----------

A `BitField` specifies a part of an unsigned integer whose bits represent
another unsigned integer. A `BitField` is represented as follows:

{width = <integer bit width>, offset = <offset from least significant bit>}



Expand Down Expand Up @@ -2520,6 +2581,8 @@ Some of the values in the key-value store are handled specially:
* `color`: A `ColorString`, which sets the stack's color.
* `palette_index`: If the item has a palette, this is used to get the
current color from the palette.
* `variant`: If the item has more than one variant, this is the variant number.
The canonical form of variant 0 is the absence of this key.
* `count_meta`: Replace the displayed count with any string.
* `count_alignment`: Set the alignment of the displayed count value. This is an
int value. The lowest 2 bits specify the alignment in x-direction, the 3rd and
Expand Down Expand Up @@ -6263,6 +6326,12 @@ Item handling
given `param2` value.
* Returns `nil` if the given `paramtype2` does not contain color
information.
* `minetest.strip_param2_variant(param2, def)`
* Returns the variant from `param2` with the given node definition `def`.
* Always returns a non-negative integer less than `def.variant_count`.
* `minetest.set_param2_variant(param2, variant, def)`
* Returns a modified `param2` with the variant bitfield set to `variant`
with the given node definition `def`.
* `minetest.get_node_drops(node, toolname)`
* Returns list of itemstrings that are dropped by `node` when dug
with the item `toolname` (not limited to tools).
Expand Down Expand Up @@ -6331,6 +6400,11 @@ Item handling
* `item`: the item stack which becomes colored. Can be in string,
table and native form.
* `colorstring`: the new color of the item stack
* `minetest.itemstring_with_variant(item, variant)`: returns an item string
* Creates an item string with an associated item variant.
* `item`: the item stack which is given the variant. Can be in string,
table or native form.
* `variant`: the new variant of the item stack

Rollback
--------
Expand Down Expand Up @@ -8568,6 +8642,9 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
-- {bendy = 2, snappy = 1},
-- {hard = 1, metal = 1, spikes = 1}

variant_count = 1,
-- The number item variants, a positive integer.

inventory_image = "",
-- Texture shown in the inventory GUI
-- Defaults to a 3D rendering of the node if left empty.
Expand Down Expand Up @@ -8734,6 +8811,9 @@ Used by `minetest.register_node`.
{
-- <all fields allowed in item definitions>

param2_variant = BitField,
-- The part of param2 from which to read the variant number.

drawtype = "normal", -- See "Node drawtypes"

visual_scale = 1.0,
Expand All @@ -8759,6 +8839,18 @@ Used by `minetest.register_node`.
-- Special textures of node; used rarely.
-- List can be shortened to needed length.

-- See "Variants"
variants = {
[variant number] = {
tiles = {tile definition 1, def2, def3, def4, def5, def6},

overlay_tiles = {def1, def2, def3, def4, def5, def6},

special_tiles = {def1, def2},
},
...
},

color = ColorSpec,
-- The node's original color will be multiplied with this color.
-- If the node has a palette, then this setting only has an effect in
Expand Down Expand Up @@ -9015,6 +9107,9 @@ Used by `minetest.register_node`.
-- hardware coloring palette color from the dug node.
-- Default is 'false'.
inherit_color = true,
-- variant of the dug node.
-- Default is 'false'.
inherit_variant = true,
},
{
-- Only drop if using an item whose name contains
Expand Down
1 change: 1 addition & 0 deletions games/devtest/mods/testnodes/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ dofile(path.."/liquids.lua")
dofile(path.."/light.lua")
dofile(path.."/textures.lua")
dofile(path.."/overlays.lua")
dofile(path.."/variants.lua")
dofile(path.."/commands.lua")
Loading

0 comments on commit f5353e0

Please sign in to comment.