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
1 changed files with 134 additions and 58 deletions

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" }, ["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 -- Add pattern/emblazoning crafting recipes
dofile(minetest.get_modpath("mcl_banners").."/patterncraft.lua") 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 standing_banner_entity_offset = { x=0, y=-0.499, z=0 }
local hanging_banner_entity_offset = { x=0, y=-1.7, 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 -- 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) local objects = minetest.get_objects_inside_radius(checkpos, 0.5)
for _, v in ipairs(objects) do for _, v in ipairs(objects) do
local ent = v:get_luaentity() local ent = v:get_luaentity()
if ent and ent.name == "mcl_banners:standing_banner" then if ent and ent.name == nodename then
v:get_luaentity():_drop() v:remove()
end end
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 end
local on_destruct_hanging_banner = function(pos) local on_destruct_hanging_banner = function(pos)
-- Find this node's banner entity and make it drop as an item return on_destruct_banner(pos, true)
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
end end
local make_banner_texture = function(base_color, layers) local make_banner_texture = function(base_color, layers)
@ -96,6 +113,59 @@ local make_banner_texture = function(base_color, layers)
end end
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 local on_rotate
if minetest.get_modpath("screwdriver") then if minetest.get_modpath("screwdriver") then
on_rotate = screwdriver.disallow on_rotate = screwdriver.disallow
@ -138,6 +208,9 @@ minetest.register_node("mcl_banners:standing_banner", {
drop = "", -- Item drops are handled in entity code drop = "", -- Item drops are handled in entity code
on_destruct = on_destruct_standing_banner, on_destruct = on_destruct_standing_banner,
on_punch = function(pos, node)
respawn_banner_entity(pos, node)
end,
_mcl_hardness = 1, _mcl_hardness = 1,
_mcl_blast_resistance = 5, _mcl_blast_resistance = 5,
}) })
@ -166,6 +239,9 @@ minetest.register_node("mcl_banners:hanging_banner", {
drop = "", -- Item drops are handled in entity code drop = "", -- Item drops are handled in entity code
on_destruct = on_destruct_hanging_banner, on_destruct = on_destruct_hanging_banner,
on_punch = function(pos, node)
respawn_banner_entity(pos, node)
end,
_mcl_hardness = 1, _mcl_hardness = 1,
_mcl_blast_resistance = 5, _mcl_blast_resistance = 5,
on_rotate = on_rotate, on_rotate = on_rotate,
@ -269,48 +345,61 @@ for colorid, colortab in pairs(mcl_banners.colors) do
end end
hanging = true hanging = true
end end
local place_pos local place_pos
if minetest.registered_nodes[node_under.name].buildable_to then if minetest.registered_nodes[node_under.name].buildable_to then
place_pos = under place_pos = under
else else
place_pos = above place_pos = above
end end
if hanging then local bnode = minetest.get_node(place_pos)
place_pos = vector.add(place_pos, hanging_banner_entity_offset) if bnode.name ~= "mcl_banners:standing_banner" and bnode.name ~= "mcl_banners:hanging_banner" then
else minetest.log("error", "[mcl_banners] The placed banner node is not what the mod expected!")
place_pos = vector.add(place_pos, standing_banner_entity_offset) return itemstack
end 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 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 else
banner = minetest.add_entity(place_pos, "mcl_banners:standing_banner") entity_place_pos = vector.add(place_pos, standing_banner_entity_offset)
end end
local imeta = itemstack:get_meta() local banner_entity = spawn_banner_entity(entity_place_pos, hanging, itemstack)
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
-- Set rotation -- Set rotation
local final_yaw local final_yaw, rotation_level
if hanging then if hanging then
local pdir = vector.direction(pointed_thing.under, pointed_thing.above) local pdir = vector.direction(pointed_thing.under, pointed_thing.above)
final_yaw = minetest.dir_to_yaw(pdir) 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 else
-- Determine the rotation based on player's yaw -- Determine the rotation based on player's yaw
local yaw = placer:get_look_horizontal() local yaw = placer:get_look_horizontal()
-- Select one of 16 possible rotations (0-15) -- 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 final_yaw = (rotation_level * (math.pi/8)) + math.pi
end 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 if not minetest.settings:get_bool("creative_mode") then
itemstack:take_item() itemstack:take_item()
@ -392,30 +481,6 @@ local entity_standing = {
self.object:set_armor_groups({immortal=1}) self.object:set_armor_groups({immortal=1})
end, 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. -- Set the banner textures. This function can be used by external mods.
-- Meaning of parameters: -- Meaning of parameters:
-- * self: Lua entity reference to entity. -- * self: Lua entity reference to entity.
@ -436,6 +501,17 @@ local entity_hanging = table.copy(entity_standing)
entity_hanging.mesh = "amc_banner_hanging.b3d" entity_hanging.mesh = "amc_banner_hanging.b3d"
minetest.register_entity("mcl_banners:hanging_banner", entity_hanging) 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({ minetest.register_craft({
type = "fuel", type = "fuel",
recipe = "group:banner", recipe = "group:banner",