Banners: Respawn entity if it got lost

Entity is respawned on load (in an LBM) or when the banner node is punched.
Also, the banner drop is now handled in the node instead of the entity.
This commit is contained in:
Wuzzy 2019-02-18 23:32:18 +01:00
parent eb7c8371ac
commit 267a697fab

View file

@ -32,6 +32,11 @@ mcl_banners.colors = {
["unicolor_light_blue"] = {"light_blue", "Light Blue Banner", "mcl_wool:light_blue", "#4040CF", "mcl_dye:lightblue", "Light Blue" },
}
local colors_reverse = {}
for k,v in pairs(mcl_banners.colors) do
colors_reverse["mcl_banners:banner_item_"..v[1]] = k
end
-- Add pattern/emblazoning crafting recipes
dofile(minetest.get_modpath("mcl_banners").."/patterncraft.lua")
@ -42,28 +47,40 @@ local layer_ratio = 255
local standing_banner_entity_offset = { x=0, y=-0.499, z=0 }
local hanging_banner_entity_offset = { x=0, y=-1.7, z=0 }
local on_destruct_standing_banner = function(pos)
local on_destruct_banner = function(pos, hanging)
local offset, nodename
if hanging then
offset = hanging_banner_entity_offset
nodename = "mcl_banners:hanging_banner"
else
offset = standing_banner_entity_offset
nodename = "mcl_banners:standing_banner"
end
-- Find this node's banner entity and make it drop as an item
local checkpos = vector.add(pos, standing_banner_entity_offset)
local checkpos = vector.add(pos, offset)
local objects = minetest.get_objects_inside_radius(checkpos, 0.5)
for _, v in ipairs(objects) do
local ent = v:get_luaentity()
if ent and ent.name == "mcl_banners:standing_banner" then
v:get_luaentity():_drop()
if ent and ent.name == nodename then
v:remove()
end
end
-- Drop item
local meta = minetest.get_meta(pos)
local item = meta:get_inventory():get_stack("banner", 1)
if not item:is_empty() then
minetest.add_item(pos, item)
else
minetest.add_item(pos, "mcl_banners:banner_item_white")
end
end
local on_destruct_standing_banner = function(pos)
return on_destruct_banner(pos, false)
end
local on_destruct_hanging_banner = function(pos)
-- Find this node's banner entity and make it drop as an item
local checkpos = vector.add(pos, hanging_banner_entity_offset)
local objects = minetest.get_objects_inside_radius(checkpos, 0.5)
for _, v in ipairs(objects) do
local ent = v:get_luaentity()
if ent and ent.name == "mcl_banners:hanging_banner" then
v:get_luaentity():_drop()
end
end
return on_destruct_banner(pos, true)
end
local make_banner_texture = function(base_color, layers)
@ -96,6 +113,59 @@ local make_banner_texture = function(base_color, layers)
end
end
local spawn_banner_entity = function(pos, hanging, itemstack)
local banner
if hanging then
banner = minetest.add_entity(pos, "mcl_banners:hanging_banner")
else
banner = minetest.add_entity(pos, "mcl_banners:standing_banner")
end
if banner == nil then
return banner
end
local imeta = itemstack:get_meta()
local layers_raw = imeta:get_string("layers")
local layers = minetest.deserialize(layers_raw)
local colorid = colors_reverse[itemstack:get_name()]
banner:get_luaentity():_set_textures(colorid, layers)
local mname = imeta:get_string("name")
if mname ~= nil and mname ~= "" then
banner:get_luaentity()._item_name = mname
banner:get_luaentity()._item_description = imeta:get_string("description")
end
return banner
end
local respawn_banner_entity = function(pos, node)
local hanging = node.name == "mcl_banners:hanging_banner"
local offset
if hanging then
offset = hanging_banner_entity_offset
else
offset = standing_banner_entity_offset
end
-- Check if a banner entity already exists
local bpos = vector.add(pos, offset)
local objects = minetest.get_objects_inside_radius(bpos, 0.5)
for _, v in ipairs(objects) do
local ent = v:get_luaentity()
if ent and (ent.name == "mcl_banners:standing_banner" or ent.name == "mcl_banners:hanging_banner") then
return
end
end
-- Spawn new entity
local meta = minetest.get_meta(pos)
local banner_item = meta:get_inventory():get_stack("banner", 1)
local banner_entity = spawn_banner_entity(bpos, hanging, banner_item)
-- Set rotation
local final_yaw
local rotation_level = meta:get_int("rotation_level")
final_yaw = (rotation_level * (math.pi/8)) + math.pi
banner_entity:set_yaw(final_yaw)
end
local on_rotate
if minetest.get_modpath("screwdriver") then
on_rotate = screwdriver.disallow
@ -138,6 +208,9 @@ minetest.register_node("mcl_banners:standing_banner", {
drop = "", -- Item drops are handled in entity code
on_destruct = on_destruct_standing_banner,
on_punch = function(pos, node)
respawn_banner_entity(pos, node)
end,
_mcl_hardness = 1,
_mcl_blast_resistance = 5,
})
@ -166,6 +239,9 @@ minetest.register_node("mcl_banners:hanging_banner", {
drop = "", -- Item drops are handled in entity code
on_destruct = on_destruct_hanging_banner,
on_punch = function(pos, node)
respawn_banner_entity(pos, node)
end,
_mcl_hardness = 1,
_mcl_blast_resistance = 5,
on_rotate = on_rotate,
@ -269,48 +345,61 @@ for colorid, colortab in pairs(mcl_banners.colors) do
end
hanging = true
end
local place_pos
if minetest.registered_nodes[node_under.name].buildable_to then
place_pos = under
else
place_pos = above
end
if hanging then
place_pos = vector.add(place_pos, hanging_banner_entity_offset)
else
place_pos = vector.add(place_pos, standing_banner_entity_offset)
local bnode = minetest.get_node(place_pos)
if bnode.name ~= "mcl_banners:standing_banner" and bnode.name ~= "mcl_banners:hanging_banner" then
minetest.log("error", "[mcl_banners] The placed banner node is not what the mod expected!")
return itemstack
end
local meta = minetest.get_meta(place_pos)
local inv = meta:get_inventory()
inv:set_size("banner", 1)
local store_stack = ItemStack(itemstack)
store_stack:set_count(1)
inv:set_stack("banner", 1, store_stack)
local banner
-- Spawn entity
local entity_place_pos
if hanging then
banner = minetest.add_entity(place_pos, "mcl_banners:hanging_banner")
entity_place_pos = vector.add(place_pos, hanging_banner_entity_offset)
else
banner = minetest.add_entity(place_pos, "mcl_banners:standing_banner")
entity_place_pos = vector.add(place_pos, standing_banner_entity_offset)
end
local imeta = itemstack:get_meta()
local layers_raw = imeta:get_string("layers")
local layers = minetest.deserialize(layers_raw)
banner:get_luaentity():_set_textures(colorid, layers)
local mname = imeta:get_string("name")
if mname ~= nil and mname ~= "" then
banner:get_luaentity()._item_name = mname
banner:get_luaentity()._item_description = imeta:get_string("description")
end
local banner_entity = spawn_banner_entity(entity_place_pos, hanging, itemstack)
-- Set rotation
local final_yaw
local final_yaw, rotation_level
if hanging then
local pdir = vector.direction(pointed_thing.under, pointed_thing.above)
final_yaw = minetest.dir_to_yaw(pdir)
if pdir.x > 0 then
rotation_level = 4
elseif pdir.z > 0 then
rotation_level = 8
elseif pdir.x < 0 then
rotation_level = 12
else
rotation_level = 0
end
else
-- Determine the rotation based on player's yaw
local yaw = placer:get_look_horizontal()
-- Select one of 16 possible rotations (0-15)
local rotation_level = round((yaw / (math.pi*2)) * 16)
rotation_level = round((yaw / (math.pi*2)) * 16)
if rotation_level >= 16 then
rotation_level = 0
end
final_yaw = (rotation_level * (math.pi/8)) + math.pi
end
banner:set_yaw(final_yaw)
meta:set_int("rotation_level", rotation_level)
if banner_entity ~= nil then
banner_entity:set_yaw(final_yaw)
end
if not minetest.settings:get_bool("creative_mode") then
itemstack:take_item()
@ -392,30 +481,6 @@ local entity_standing = {
self.object:set_armor_groups({immortal=1})
end,
-- This is a custom function which causes the banner to be dropped as item and destroys the entity.
_drop = function(self)
local pos = self.object:get_pos()
pos.y = pos.y + 1
if not minetest.settings:get_bool("creative_mode") and self._base_color then
-- Spawn item
local banner = ItemStack("mcl_banners:banner_item_"..mcl_banners.colors[self._base_color][1])
local meta = banner:get_meta()
meta:set_string("layers", minetest.serialize(self._layers))
if self._item_name ~= nil and self._item_name ~= "" then
meta:set_string("description", self._item_description)
meta:set_string("name", self._item_name)
else
meta:set_string("description", mcl_banners.make_advanced_banner_description(banner:get_definition().description, self._layers))
end
minetest.add_item(pos, banner)
end
-- Destroy entity
self.object:remove()
end,
-- Set the banner textures. This function can be used by external mods.
-- Meaning of parameters:
-- * self: Lua entity reference to entity.
@ -436,6 +501,17 @@ local entity_hanging = table.copy(entity_standing)
entity_hanging.mesh = "amc_banner_hanging.b3d"
minetest.register_entity("mcl_banners:hanging_banner", entity_hanging)
-- FIXME: Prevent entity destruction by /clearobjects
minetest.register_lbm({
label = "Respawn banner entities",
name = "mcl_banners:respawn_entities",
run_at_every_load = true,
nodenames = {"mcl_banners:standing_banner", "mcl_banners:hanging_banner"},
action = function(pos, node)
respawn_banner_entity(pos, node)
end,
})
minetest.register_craft({
type = "fuel",
recipe = "group:banner",