Initial commit

master
Lars Mueller 2022-01-23 14:53:19 +01:00
commit 5a48c2b232
4 changed files with 218 additions and 0 deletions

7
.luacheckrc Normal file
View File

@ -0,0 +1,7 @@
globals = {"visible_wielditem"}
read_globals = {
"minetest",
"modlib",
"ItemStack",
"vector",
}

46
Readme.md Normal file
View File

@ -0,0 +1,46 @@
# Visible Wielditem
Shows wielded items in-world.
## Features
Modern alternative to [`wield3d`](https://github.com/stujones11/wield3d):
* Relies less on deprecated engine APIs, doesn't aim to support older MT versions
* Supports colored items. Works well with [`epidermis`](https://github.com/epidermis).
* Supports glow (for environmental lighting use a wielded light mod)
* Indicates size of stacks
* Provides a proper API for mods to use
* Rotates the model instead of the texture
## License
Written by [appgurueu](https://github.com/appgurueu) and licensed under the MIT license.
## API
All within the `visible_wielditem` global variable.
### `get_attachment(modelname, itemname)`
Returns a table with fields `bonename`, `position` (unit: metric/nodes), `rotation` (unit: degrees) and `scale` (number, unit: metric/nodes) based on model attachments and item tweaks.
### `model_attachments`
Table. Keys are model media (file) names, values are tables with field `bonename`, `position`, `rotation` and `scale`. The special field `default` is used for default attachment settings based on `character.b3d` if no model attachments are specified for a player model or if the specified attachment settings are incomplete.
### `item_tweaks`
Table of tweaks applied based on the item. Subtable entries have strings as keys and tweak tables with fields `position`, `rotation` and `scale` as values. `position`s are added up, `rotation`s are properly composed, `scale` is multiplied.
#### `types`
Applies tweaks based on item type. Possible keys are `unknown`, `node`, `tool` and `craftitem`.
#### `groups`
Tweaks for a key are applied if the item has an item group with that name.
#### `names`
Tweaks for a single item, by full item name.

161
init.lua Normal file
View File

@ -0,0 +1,161 @@
visible_wielditem = {}
local entities = {}
local function create_entity(player)
local entity = minetest.add_entity(player:get_pos(), "visible_wielditem:visible_wielditem"):get_luaentity()
entity:_set_player(player)
entities[player:get_player_name()] = entity
end
minetest.register_on_joinplayer(create_entity)
minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
entities[player_name]:remove()
entities[player_name] = nil
end)
visible_wielditem.model_attachments = {
default = {
bonename = "Arm_Right",
position = vector.new(0, 0.375, 0),
rotation = vector.new(180, 90, 0),
scale = 0.25
}
}
visible_wielditem.item_tweaks = {
types = {
unknown = {},
node = {
position = vector.new(0, 0.2, 0),
rotation = vector.new(0, 0, 180)
},
tool = {
position = vector.new(0, 0, 0.3),
rotation = vector.new(0, 0, 135)
},
craft = {
position = vector.new(0, 0, 0.3),
rotation = vector.new(0, 0, 45),
}
},
groups = {},
names = {}
}
local quaternion_from_euler_rot_deg = modlib.quaternion.from_euler_rotation_deg
local quaternion_to_euler_rot_deg = modlib.quaternion.to_euler_rotation_irrlicht
-- HACK quaternion multiplication should be fixed in modlib eventually
local function quaternion_compose(other, self)
local X, Y, Z, W = unpack(self)
return modlib.quaternion.normalize{
(other[4] * X) + (other[1] * W) + (other[2] * Z) - (other[3] * Y);
(other[4] * Y) + (other[2] * W) + (other[3] * X) - (other[1] * Z);
(other[4] * Z) + (other[3] * W) + (other[1] * Y) - (other[2] * X);
(other[4] * W) - (other[1] * X) - (other[2] * Y) - (other[3] * Z);
}
end
function visible_wielditem.get_attachment(modelname, itemname)
local model_attachments = visible_wielditem.model_attachments
local attachment = modlib.table.copy(model_attachments[modelname] or model_attachments.default)
local rotation = quaternion_from_euler_rot_deg(attachment.rotation)
local function apply_tweaks(tweaks)
tweaks = tweaks or {}
if tweaks.position then attachment.position = vector.add(attachment.position, tweaks.position) end
if tweaks.rotation then
rotation = quaternion_compose(rotation, quaternion_from_euler_rot_deg(tweaks.rotation))
end
if tweaks.scale then attachment.scale = attachment.scale * tweaks.scale end
end
local def = minetest.registered_items[itemname]
local item_tweaks = visible_wielditem.item_tweaks
apply_tweaks(item_tweaks.types[def and def.type or "unknown"])
for groupname, rating in pairs(def.groups or {}) do
if rating ~= 0 then
apply_tweaks(item_tweaks.groups[groupname])
end
end
apply_tweaks(item_tweaks.names[itemname])
attachment.rotation = quaternion_to_euler_rot_deg(rotation)
return attachment
end
minetest.register_entity("visible_wielditem:visible_wielditem", {
initial_properties = {
physical = false,
collide_with_objects = false,
pointable = false,
visual = "wielditem" ,
wield_item = "",
is_visible = false,
backface_culling = false,
use_texture_alpha = true,
glow = 0,
static_save = false,
shaded = true
},
on_activate = function(self)
local object = self.object
object:set_armor_groups{immortal = 1}
end,
_force_resend = function(self) -- HACK
self.object:set_pos(self.object:get_pos())
end,
_update_attachment = function(self)
if not self._item then return end
local object = self.object
local attachment = visible_wielditem.get_attachment(self._player:get_properties().mesh, self._item:get_name() or "")
-- TODO softcode
local stack_scale = 1
if self._item:get_definition().type ~= "tool" then
stack_scale = 0.75 + 0.5 * math.min(1, self._item:get_count() / self._item:get_stack_max())
end
local vsize = attachment.scale * stack_scale
object:set_properties{visual_size = vector.new(vsize, vsize, vsize)}
object:set_attach(self._player,
attachment.bonename,
vector.multiply(vector.offset(attachment.position, 0, vsize / 2, 0), 10),
attachment.rotation)
self:_force_resend()
end,
_set_player = function(self, player)
self._player = player -- HACK this assumes that PlayerRefs don't change
self:_set_item(player:get_wielded_item())
self:_update_attachment()
end,
on_deactivate = function(self)
create_entity(self._player)
end,
_set_item = function(self, item)
self._item = item
local object = self.object
if item:is_empty() then
object:set_properties{
is_visible = false,
wield_item = ""
}
return
end
object:set_properties{
is_visible = true,
wield_item = item:to_string(),
glow = item:get_definition().light_source or 0
}
self:_update_attachment()
end,
-- TODO on_step: reattach regularly to work around engine bugs?
})
modlib.minetest.register_on_wielditem_change(function(player, _, _, item)
local entity = entities[player:get_player_name()]
if entity.object:get_pos() then
entity:_set_item(item)
else -- recreate entity if necessary
create_entity(player)
end
end)

4
mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = visible_wielditem
description = Shows your wielditem
depends = modlib
min_minetest_version = 5.1