Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/lua_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -8255,6 +8255,13 @@ Can be obtained via `item:get_meta()`.
* Overrides the item's wear bar parameters (see "Wear Bar Color" section)
* A nil value will clear the override data and restore the original
behavior.
* `set_inventory_image(<Item image definition>)`
* `set_inventory_overlay(<Item image definition>)`
* `set_wield_image(<Item image definition>)`
* `set_wield_overlay(<Item image definition>)`
* Overrides the item image definitions
* Takes precedence over the overwritten image names from [Item Metadata](#item-metadata)
* A nil value will clear the override data and restore the original behavior.

`MetaDataRef`
-------------
Expand Down
82 changes: 82 additions & 0 deletions games/devtest/mods/testitems/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,85 @@ core.register_craftitem("testitems:wield_image_animation_overlay", {
wield_overlay = animated_overlay,
color = "#ff0000",
})

local function animated_image_accelerated(speed)
local image = table.copy(animated_image)
image.animation.length = image.animation.length * speed
return image
end

local function animated_overlay_accelerated(speed)
local image = table.copy(animated_overlay)
image.animation.frame_length = image.animation.frame_length * speed
return image
end

local function update_animation(meta, mode, speed, name)
local msg
local speed_factor = 1/(speed+1)
if mode == 0 then
meta:set_wield_overlay()
msg = S"Not animated"
elseif mode == 1 then
meta:set_inventory_image(animated_image_accelerated(speed_factor))
msg = S"Inventory image animated"
elseif mode == 2 then
meta:set_inventory_image()
meta:set_inventory_overlay(animated_overlay_accelerated(speed_factor))
msg = S"Inventory overlay animated"
elseif mode == 3 then
meta:set_inventory_overlay()
meta:set_wield_image(animated_image_accelerated(speed_factor))
msg = S"Wield image animated"
else
meta:set_wield_image()
meta:set_wield_overlay(animated_overlay_accelerated(speed_factor))
msg = S"Wield overlay animated"
end
core.chat_send_player(name, msg .. S", speed " .. speed)
end

local function toggle_red_string_meta_inventory_image(itemstack)
local meta = itemstack:get_meta()
local image = meta:get_string("inventory_image") == "" and
"testnodes_anim.png^[invert:rgb^[verticalframe:4:0^[multiply:#ff0000" or ""
local overlay = meta:get_string("inventory_overlay") == "" and
"testitems_animation_overlay.png^[verticalframe:4:0^[multiply:#ff0000" or ""
meta:set_string("inventory_image", image)
meta:set_string("inventory_overlay", overlay)
meta:set_string("wield_image", image)
meta:set_string("wield_overlay", overlay)
return itemstack
end

core.register_craftitem("testitems:inventory_image_animation_meta", {
description = S("Animated Meta Test Item").."\n"..
S("Left click to cycle through modes").."\n"..
S("Hold sneak and left click to change speed").."\n"..
S("Right click to toggle red string meta inventory image fields"),
inventory_image = "testnodes_anim.png^[invert:rgb^[verticalframe:4:0",
inventory_overlay = "testitems_animation_overlay.png^[verticalframe:4:0",
wield_image = "testnodes_anim.png^[invert:rgb^[verticalframe:4:0",
wield_overlay = "testitems_animation_overlay.png^[verticalframe:4:0",
on_use = function(itemstack, user, pointed_thing)
if not core.is_player(user) then
return
end
local name = user:get_player_name()
local meta = itemstack:get_meta()
local speed = meta:get_int("speed")
local mode = meta:get_int("mode")

if user:get_player_control().sneak then
speed = (speed + 1) % 4
meta:set_int("speed", speed)
else
mode = (mode + 1) % 5
meta:set_int("mode", mode)
end
update_animation(meta, mode, speed, name)
return itemstack
end,
on_place = toggle_red_string_meta_inventory_image,
on_secondary_use = toggle_red_string_meta_inventory_image,
})
15 changes: 9 additions & 6 deletions src/client/item_visuals_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,16 @@ ItemVisualsManager::ItemVisuals *ItemVisualsManager::createItemVisuals( const It
ItemImageDef inventory_image = item.getInventoryImage(idef);
ItemImageDef inventory_overlay = item.getInventoryOverlay(idef);

// Key only consists of item name + image name,
// because animation currently cannot be overridden by meta
std::ostringstream os(def.name);
if (!inventory_image.name.empty())
os << "/" << inventory_image.name;
if (!inventory_overlay.name.empty())
os << ":" << inventory_overlay.name;
if (!inventory_image.name.empty()) {
os << "/";
inventory_image.serializeJson(os);
}
if (!inventory_overlay.name.empty()) {
os << ":";
inventory_overlay.serializeJson(os);
}

std::string cache_key = os.str();


Expand Down
16 changes: 16 additions & 0 deletions src/inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ std::string ItemStack::getShortDescription(const IItemDefManager *itemdef) const

ItemImageDef ItemStack::getInventoryImage(const IItemDefManager *itemdef) const
{
const auto &override_image = metadata.getInventoryImageOverride();
if (override_image)
return override_image.value();

ItemImageDef image = getDefinition(itemdef).inventory_image;
std::string meta_image = metadata.getString("inventory_image");
if (!meta_image.empty())
Expand All @@ -268,6 +272,10 @@ ItemImageDef ItemStack::getInventoryImage(const IItemDefManager *itemdef) const

ItemImageDef ItemStack::getInventoryOverlay(const IItemDefManager *itemdef) const
{
const auto &override_image = metadata.getInventoryOverlayOverride();
if (override_image)
return override_image.value();

ItemImageDef image = getDefinition(itemdef).inventory_overlay;
std::string meta_image = metadata.getString("inventory_overlay");
if (!meta_image.empty())
Expand All @@ -278,6 +286,10 @@ ItemImageDef ItemStack::getInventoryOverlay(const IItemDefManager *itemdef) cons

ItemImageDef ItemStack::getWieldImage(const IItemDefManager *itemdef) const
{
const auto &override_image = metadata.getWieldImageOverride();
if (override_image)
return override_image.value();

ItemImageDef image = getDefinition(itemdef).wield_image;
std::string meta_image = metadata.getString("wield_image");
if (!meta_image.empty())
Expand All @@ -288,6 +300,10 @@ ItemImageDef ItemStack::getWieldImage(const IItemDefManager *itemdef) const

ItemImageDef ItemStack::getWieldOverlay(const IItemDefManager *itemdef) const
{
const auto &override_image = metadata.getWieldOverlayOverride();
if (override_image)
return override_image.value();

ItemImageDef image = getDefinition(itemdef).wield_overlay;
std::string meta_image = metadata.getString("wield_overlay");
if (!meta_image.empty())
Expand Down
4 changes: 4 additions & 0 deletions src/inventory.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ struct ItemStack
ItemImageDef getWieldImage(const IItemDefManager *itemdef) const;
ItemImageDef getWieldOverlay(const IItemDefManager *itemdef) const;
v3f getWieldScale(const IItemDefManager *itemdef) const;
const TileAnimationParams getInventoryImageAnimation(const IItemDefManager *itemdef) const;
const TileAnimationParams getInventoryOverlayAnimation(const IItemDefManager *itemdef) const;
const TileAnimationParams getWieldImageAnimation(const IItemDefManager *itemdef) const;
const TileAnimationParams getWieldOverlayAnimation(const IItemDefManager *itemdef) const;

/*
Quantity methods
Expand Down
25 changes: 25 additions & 0 deletions src/itemdef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "util/pointedthing.h"
#include <map>
#include <set>
#include "convert_json.h"
#include <json/json.h>

TouchInteraction::TouchInteraction()
{
Expand Down Expand Up @@ -103,6 +105,29 @@ void ItemImageDef::deSerialize(std::istream &is, u16 protocol_version)
animation.deSerialize(is, protocol_version);
}

void ItemImageDef::serializeJson(std::ostream &os) const
{
Json::Value root;
root["name"] = name;
root["animation"] = animation.serializeJson();

fastWriteJson(root, os);
}

std::optional<ItemImageDef> ItemImageDef::deserializeJson(std::istream &is)
{
Json::Value root;
is >> root;
if (!root.isObject() || !root["name"].isString()) {
return std::nullopt;
}

ItemImageDef def;
def.name = root["name"].asString();
def.animation.deserializeJson(root["animation"]);
return def;
}

/*
ItemDefinition
*/
Expand Down
3 changes: 3 additions & 0 deletions src/itemdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ struct ItemImageDef

void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is, u16 protocol_version);

void serializeJson(std::ostream &os) const;
static std::optional<ItemImageDef> deserializeJson(std::istream &is);
};

struct ItemDefinition
Expand Down
53 changes: 51 additions & 2 deletions src/itemstackmetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,25 @@

#define TOOLCAP_KEY "tool_capabilities"
#define WEAR_BAR_KEY "wear_color"
#define INVENTORY_IMAGE_KEY "inventory_image_def"
#define INVENTORY_OVERLAY_KEY "inventory_overlay_def"
#define WIELD_IMAGE_KEY "wield_image_def"
#define WIELD_OVERLAY_KEY "wield_overlay_def"

void ItemStackMetadata::clear()
{
SimpleMetadata::clear();
updateAll();
}

void ItemStackMetadata::updateAll()
{
updateToolCapabilities();
updateWearBarParams();
updateInventoryImage();
updateOverlayImage();
updateWieldImage();
updateWieldOverlay();
}

static void sanitize_string(std::string &str)
Expand All @@ -46,6 +59,14 @@ bool ItemStackMetadata::setString(const std::string &name, std::string_view var)
updateToolCapabilities();
else if (clean_name == WEAR_BAR_KEY)
updateWearBarParams();
else if (clean_name == INVENTORY_IMAGE_KEY)
updateInventoryImage();
else if (clean_name == INVENTORY_OVERLAY_KEY)
updateOverlayImage();
else if (clean_name == WIELD_IMAGE_KEY)
updateWieldImage();
else if (clean_name == WIELD_OVERLAY_KEY)
updateWieldOverlay();
return result;
}

Expand Down Expand Up @@ -81,8 +102,7 @@ void ItemStackMetadata::deSerialize(std::istream &is)
m_stringvars[""] = std::move(in);
}
}
updateToolCapabilities();
updateWearBarParams();
updateAll();
}

void ItemStackMetadata::updateToolCapabilities()
Expand Down Expand Up @@ -129,3 +149,32 @@ void ItemStackMetadata::clearWearBarParams()
{
setString(WEAR_BAR_KEY, "");
}

// Item image overrides

#define ITEM_IMAGE_FUNCTIONS(NAME, FIELD, KEY) \
void ItemStackMetadata::set##NAME(const ItemImageDef &def) \
{ \
std::ostringstream os; \
def.serializeJson(os); \
setString(KEY, os.str()); \
} \
void ItemStackMetadata::clear##NAME() \
{ \
setString(KEY, ""); \
} \
void ItemStackMetadata::update##NAME() \
{ \
if (contains(KEY)) { \
std::istringstream is(getString(KEY)); \
FIELD = ItemImageDef::deserializeJson(is); \
} else { \
FIELD.reset(); \
} \
}

ITEM_IMAGE_FUNCTIONS(InventoryImage, inventory_image_override, INVENTORY_IMAGE_KEY)
ITEM_IMAGE_FUNCTIONS(OverlayImage, inventory_overlay_override, INVENTORY_OVERLAY_KEY)
ITEM_IMAGE_FUNCTIONS(WieldImage, wield_image_override, WIELD_IMAGE_KEY)
ITEM_IMAGE_FUNCTIONS(WieldOverlay, wield_overlay_override, WIELD_OVERLAY_KEY)
#undef ITEM_IMAGE_FUNCTIONS
41 changes: 41 additions & 0 deletions src/itemstackmetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "metadata.h"
#include "tool.h"
#include "itemdef.h"

#include <optional>

Expand Down Expand Up @@ -39,10 +40,50 @@ class ItemStackMetadata : public SimpleMetadata
void setWearBarParams(const WearBarParams &params);
void clearWearBarParams();

// Item image overrides

const std::optional<ItemImageDef> &getInventoryImageOverride() const
{
return inventory_image_override;
}
void setInventoryImage(const ItemImageDef &params);
void clearInventoryImage();

const std::optional<ItemImageDef> &getInventoryOverlayOverride() const
{
return inventory_overlay_override;
}
void setOverlayImage(const ItemImageDef &params);
void clearOverlayImage();

const std::optional<ItemImageDef> &getWieldImageOverride() const
{
return wield_image_override;
}
void setWieldImage(const ItemImageDef &params);
void clearWieldImage();

const std::optional<ItemImageDef> &getWieldOverlayOverride() const
{
return wield_overlay_override;
}
void setWieldOverlay(const ItemImageDef &params);
void clearWieldOverlay();

private:
void updateToolCapabilities();
void updateWearBarParams();
void updateInventoryImage();
void updateOverlayImage();
void updateWieldImage();
void updateWieldOverlay();

void updateAll();

std::optional<ToolCapabilities> toolcaps_override;
std::optional<WearBarParams> wear_bar_override;
std::optional<ItemImageDef> inventory_image_override;
std::optional<ItemImageDef> inventory_overlay_override;
std::optional<ItemImageDef> wield_image_override;
std::optional<ItemImageDef> wield_overlay_override;
};
Loading
Loading