local wea_c = worldeditadditions_core local EventEmitter = worldeditadditions_core.EventEmitter local Vector3 = wea_c.Vector3 local anchor local entity_wall_size = 10 local collision_thickness = 0.2 local WEAPositionMarkerWall = { initial_properties = { visual = "cube", visual_size = { x = 1, y = 1, z = 1 }, collisionbox = { -0.55, -0.55, -0.55, 0.55, 0.55, 0.55 }, -- ^^ { xmin, ymin, zmin, xmax, ymax, zmax } relative to obj pos physical = false, collide_with_objects = false, static_save = false, textures = { "worldeditadditions_core_marker_wall.png", "worldeditadditions_core_marker_wall.png", "worldeditadditions_core_marker_wall.png", "worldeditadditions_core_marker_wall.png", "worldeditadditions_core_marker_wall.png", "worldeditadditions_core_marker_wall.png", } }, on_activate = function(self, staticdata) -- noop end, on_punch = function(self, _) anchor.delete(self) end, on_blast = function(self, damage) return false, false, {} -- Do not damage or knockback the player end } minetest.register_entity( ":worldeditadditions:marker_wall", WEAPositionMarkerWall ) --- Updates the properties of a single wall to match it's side and size local function single_setup(entity, size, side) local new_props = { visual_size = Vector3.min( Vector3.new(10, 10, 10), size:abs() ) -- x = math.min(10, math.abs(size.x)), -- y = math.min(10, math.abs(size.y)), -- z = math.min(10, math.abs(size.z)) } local cthick = Vector3.new( collision_thickness, collision_thickness, collision_thickness ) local cpos1 = Vector3.clone(new_props.visual_size):multiply(-1):divide(2):add(cthick) local cpos2 = Vector3.clone(new_props.visual_size):divide(2):subtract(cthick) if side == "x" or side == "-x" then new_props.visual_size = new_props.visual_size + Vector3.new( collision_thickness - 0.1 ) cpos1.x = -collision_thickness cpos2.x = collision_thickness end if side == "y" or side == "-y" then new_props.visual_size.y = collision_thickness - 0.1 cpos1.y = -collision_thickness cpos2.y = collision_thickness end if side == "z" or side == "-z" then new_props.visual_size.z = collision_thickness - 0.1 cpos1.z = -collision_thickness cpos2.z = collision_thickness end new_props.collisionbox = { cpos1.x, cpos1.y, cpos1.z, cpos2.x, cpos2.y, cpos2.z } print("DEBUG:setup_single size", size, "side", side, "new_props", wea_c.inspect(new_props)) entity:set_properties(new_props) end --- Creates a single marker wall entity. -- @param player_name string The name of the player it should belong to. -- @param pos1 Vector3 The pos1 corner of the area the SINGLE marker should cover. -- @param pos2 Vector3 The pos2 corner of the area the SINGLE marker should cover. -- @param side string The side that this wall is on. Valid values: x, -x, y, -y, z, -z. -- @returns Entity local function create_single(player_name, pos1, pos2, side) local offset = Vector3.new() if side == "x" then offset.x = 0.5 elseif side == "-x" then offset.x = -0.5 elseif side == "y" then offset.y = 0.5 elseif side == "-y" then offset.y = -0.5 elseif side == "z" then offset.z = 0.5 elseif side == "-z" then offset.z = -0.5 end local pos_centre = ((pos2 - pos1) / 2) + pos1 + offset local entity = minetest.add_entity(pos_centre, "worldeditadditions:marker_wall") print("DEBUG:marker_wall create_single --> START player_name", player_name, "pos1", pos1, "pos2", pos2, "side", side, "SPAWN", pos_centre) entity:get_luaentity().player_name = player_name single_setup(entity, pos2 - pos1, side) return entity end --- Creates a marker wall around the defined region. -- @param player_name string The name of the player that the wall belongs to. -- @param pos1 Vector3 pos1 of the defined region. -- @param pos2 Vector3 pos2 of the defined region. -- @returns table A list of all created entities. local function create_wall(player_name, pos1, pos2) print("DEBUG:marker_wall create_wall --> START player_name", player_name, "pos1", pos1, "pos2", pos2) local pos1s, pos2s = Vector3.sort(pos1, pos2) local entities = {} -- local dim1, dim2 -- if side == "x" or side == "-x" then dim1, dim2 = size.z, size.y -- elseif side == "z" or size == "-z" then dim1, dim2 = size.x, size.y -- elseif side == "y" or size == "-y" then dim1, dim2 = size.x, size.z -- end -- x → z, y -- z → x, y -- y → x, z -- ██ ██ -- ██ ██ ██ -- ██████ ███ -- ██ ██ ██ -- ██ ██ -- First, do positive x local posx_pos1 = Vector3.new( math.max(pos1s.x, pos2s.x), math.min(pos1s.y, pos2s.y) - 0.5, math.min(pos1s.z, pos2s.z) - 0.5 ) local posx_pos2 = Vector3.new( math.max(pos1s.x, pos2s.x), math.max(pos1s.y, pos2s.y) + 0.5, math.max(pos1s.z, pos2s.z) + 0.5 ) print("DEBUG ************ +X pos1", posx_pos1, "pos2", posx_pos2) for z = posx_pos2.z, posx_pos1.z, -entity_wall_size do for y = posx_pos2.y, posx_pos1.y, -entity_wall_size do local single_pos1 = Vector3.new( posx_pos1.x, y, z ) local single_pos2 = Vector3.new( posx_pos1.x, math.max(y - entity_wall_size, posx_pos1.y), math.max(z - entity_wall_size, posx_pos1.z) ) local entity = create_single(player_name, single_pos1, single_pos2, "x" ) table.insert(entities, entity) end end -- ██ ██ -- ██ ██ -- ██████ ███ -- ██ ██ -- ██ ██ -- Now, do negative x local negx_pos1 = Vector3.new( math.min(pos1s.x, pos2s.x), math.min(pos1s.y, pos2s.y) - 0.5, math.min(pos1s.z, pos2s.z) - 0.5 ) local negx_pos2 = Vector3.new( math.min(pos1s.x, pos2s.x), math.max(pos1s.y, pos2s.y) + 0.5, math.max(pos1s.z, pos2s.z) + 0.5 ) print("DEBUG ************ -X pos1", negx_pos1, "pos2", negx_pos2) for z = negx_pos2.z, negx_pos1.z, -entity_wall_size do for y = negx_pos2.y, negx_pos1.y, -entity_wall_size do local single_pos1 = Vector3.new( negx_pos1.x, y, z ) local single_pos2 = Vector3.new( negx_pos1.x, math.max(y - entity_wall_size, negx_pos1.y), math.max(z - entity_wall_size, negx_pos1.z) ) local entity = create_single(player_name, single_pos1, single_pos2, "-x" ) table.insert(entities, entity) end end -- TODO: All the other sides. For testing we're doing 1 side for now, so we can vaoid having to do everything all over again if we make a mistake. -- for z = pos2.z, pos1.z, -entity_wall_size do -- for y = pos2.y, pos1.y, -entity_wall_size do -- for x = pos2.x, pos1.x, -entity_wall_size do -- end -- end -- end return entities end --- Deletes all entities in the given entity list -- @param entitylist table A list of wall entities that make up the wall to delete. local function delete(entitylist) print("DEBUG:marker_wall delete --> START with "..#entitylist.." entities") local player_name for _, entity in ipairs(entitylist) do if not entity.get_luaentity or not entity:get_luaentity() then return end -- Ensure the entity is still valid if not player_name then player_name = entity:get_luaentity().player_name end entity:remove() end anchor:emit("delete", { player_name = player_name }) end anchor = EventEmitter.new({ create = create_wall, delete = delete }) return anchor