local ns = rgt_cosmetics ns.wearables = {} --[[ { name = "", -- Name of the wearable attachments = { -- List of individual attachments managed by this wearable (in case one wearable involves multiple bones) mesh = "", -- The wearable's mesh textures = {"", ...}, -- The wearable's textures bone = ", -- Name of the player bone to attach to pos = , -- Attachment offset rot = , -- Attachment rotation } } --]] function ns.register_wearable(def) ns.wearables[def.name] = def end minetest.register_entity("rgt_cosmetics:wearable", { initial_properties = { visual = "mesh", pointable = false, static_save = false }, on_activate = function(e) e.object:set_armor_groups{immortal = 1} end, represent = function(e, form) e.form = form e.object:set_properties { mesh = form.mesh, textures = form.textures } e.object:set_attach(e.owner.object, form.bone, form.pos, form.rot) if form.animation then e.object:set_animation(form.animation, form.animation.frame_speed or 1, nil, form.animation.loop) end end, on_deactivate = function(e, removed) -- Reactivate immediately if we were not explicitly marked for removal. -- This is to prevent wearables from being lost to unloading, and to -- minimize interference from mods that might try to remove objects -- they shouldn't try to remove. Note that we must check get_pos() here -- because, since on_leaveplayer is called _after_ mapblock unloading, -- the entity may otherwise attempt to reactivate itself when its -- owner has left the game (causing a crash). if not e._remove and e.owner.object:get_pos() then e.owner.wearing[e.form.name][e.index] = ns.apply_wearable_part(e.owner, e.form, e.index) end end }) function ns.apply_wearable_part(m, w, i) local obj = minetest.add_entity(m.pos, "rgt_cosmetics:wearable") local e = obj:get_luaentity() e.owner = m e.index = i e:represent(w) return obj end function ns.apply_wearable(m, wearable) local w = ns.wearables[wearable] -- Do nothing if we're already wearing this. if not w or m.wearing[w.name] then return end local item = {} for i, x in ipairs(w.attachments) do x.name = w.name item[i] = ns.apply_wearable_part(m, x, i) end m.wearing[w.name] = item if w.logical_height_offset then m:set_logical_height_offset(m.logical_height_offset +w.logical_height_offset) end end function ns.remove_wearable(m, wearable) if m.wearing[wearable] then for _, x in pairs(m.wearing[wearable]) do -- Explicitly mark the object for removal. x:get_luaentity()._remove = true x:remove() end m.wearing[wearable] = nil if ns.wearables[wearable].logical_height_offset then m:set_logical_height_offset(m.logical_height_offset -ns.wearables[wearable].logical_height_offset) end end end minetest.register_on_leaveplayer(function(p) local m = rgt.players[p:get_player_name()] for k in pairs(m.wearing) do ns.remove_wearable(m, k) end end) ns.register_wearable { name = "top_hat", logical_height_offset = 4.5, attachments = { { mesh = "rgt_top_hat.gltf", textures = {"rgt_top_hat.png"}, bone = "Head", pos = vector.new(0, 3.5, 0), rot = vector.new(0, 0, 0) } } } minetest.register_chatcommand("wear", { func = function(name, args) ns.apply_wearable(rgt.players[name], args) end }) minetest.register_chatcommand("unwear", { func = function(name, args) ns.remove_wearable(rgt.players[name], args) end })