From 5a48c2b23276e75fe5c7c5ee7308745d011437ad Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Sun, 23 Jan 2022 14:53:19 +0100 Subject: [PATCH] Initial commit --- .luacheckrc | 7 +++ Readme.md | 46 +++++++++++++++ init.lua | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mod.conf | 4 ++ 4 files changed, 218 insertions(+) create mode 100644 .luacheckrc create mode 100644 Readme.md create mode 100644 init.lua create mode 100644 mod.conf diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 0000000..772c898 --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,7 @@ +globals = {"visible_wielditem"} +read_globals = { + "minetest", + "modlib", + "ItemStack", + "vector", +} \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..8afe25c --- /dev/null +++ b/Readme.md @@ -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. diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..1602c2d --- /dev/null +++ b/init.lua @@ -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) \ No newline at end of file diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..2214c49 --- /dev/null +++ b/mod.conf @@ -0,0 +1,4 @@ +name = visible_wielditem +description = Shows your wielditem +depends = modlib +min_minetest_version = 5.1 \ No newline at end of file