local player_positions = {} minetest.register_globalstep(function(dt) for i, v in pairs(player_positions) do player_positions[i] = nil end for i, player_handler in pairs(Guns4d.players) do table.insert(player_positions, player_handler.player:get_pos()) end local count = 0 for i = #Guns4d.bullet_hole.instances+1, 1, -1 do --start at the last so the bullet_holes added sooner are expired. local obj = Guns4d.bullet_hole.instances[i] if obj then --obj can be a false value. if (count > Guns4d.config.maximum_bullet_holes) and (obj.exp_time > 2.5) then obj.exp_time = 2.5 end count = count + 1 local closest_dist for _, pos in pairs(player_positions) do local dist = vector.distance(obj.pos, pos) if (not closest_dist) or (dist < closest_dist) then closest_dist = dist end end if closest_dist > obj.deletion_distance then obj:delete() return end if (closest_dist > obj.render_distance) and obj.rendered then obj:unrender() elseif (closest_dist < obj.render_distance*.85) and not obj.rendered then obj:render() end obj:update(dt) end end end) Guns4d.bullet_hole = leef.class.new_class:inherit({ texture = 'bullet_hole.png', exp_time = 30, --how much time a rendered bullet hole takes to expire unrendered_exptime = 10, --how much time an unrendered bullet hole takes to expire deletion_distance = 100, --heat_effect = false, instances = {}, size = .15, render_distance = 25, particle_spawner_id = nil, hole_entity = "guns4d:bullet_hole", rendered = true, }) local Bullet_hole = Guns4d.bullet_hole ---@diagnostic disable-next-line: duplicate-set-field function Bullet_hole.construct(def) if def.instance then assert(def.pos) assert(def.rotation) --[[for i, v in pairs(def.pos) do if math.abs(v-Guns4d.math.round(v)) > (.5-(def.size/2)) then def.pos[i] = Guns4d.math.round(v)+((math.abs(v-Guns4d.math.round(v))/(v-Guns4d.math.round(v)))*(.5-(def.size/2))) end end]] Bullet_hole.instances[(#Bullet_hole.instances)+1]=def def.id = #Bullet_hole.instances def.unrendered_expire_speed = def.exp_time/def.unrendered_exptime def:render() end end function Bullet_hole:render() assert(self.instance) self.rendered = true local normal = vector.rotate(vector.new(0,0,1), self.rotation) local ent = minetest.add_entity(self.pos+(normal*(.001+math.random()/1000)), self.hole_entity) ent:set_rotation(vector.dir_to_rotation(normal)) ent:set_properties({visual_size={x=self.size, y=self.size, z=0}}) self.entity = ent local lua_ent = ent:get_luaentity() lua_ent.lua_instance = self if self.particle_spawner_id then minetest.delete_particlespawner(self.particle_spawner_id) end end function Bullet_hole:unrender() assert(self.instance) self.rendered = false local normal = vector.rotate(vector.new(0,0,1), self.rotation) local time_left = self.exp_time/self.unrendered_expire_speed local number_of_particles = 2 minetest.add_particle({ size = self.size*10, texture = self.texture, expiration_time = 2*time_left/math.ceil(number_of_particles*time_left), pos = self.pos+(normal*.05) }) self.particle_spawner_id = minetest.add_particlespawner({ pos = self.pos+(normal*.05), amount = math.ceil(number_of_particles*time_left)*5, --multiply so it doesn't flash in and out of existence... time=time_left, exptime = time_left/math.ceil(number_of_particles*time_left), texture = { name = self.texture, scale = self.size*10 } }) if self.entity:get_pos() then self.entity:remove() end end function Bullet_hole:delete() assert(self.instance) Bullet_hole.instances[self.id] = false if self.entity:get_pos() then self.entity:remove() end if self.particle_spawner_id then minetest.delete_particlespawner(self.particle_spawner_id) end end function Bullet_hole:update(dt) assert(self.instance) if self.rendered then self.exp_time = self.exp_time-dt else self.exp_time = self.exp_time-(dt*self.unrendered_expire_speed) end if self.exp_time <= 0 then self:delete() end end minetest.register_entity("guns4d:bullet_hole", { initial_properties = { visual = "cube", visual_size = {x=.1, y=.1, z=0}, pointable = false, static_save = false, use_texture_alpha = true, textures = {"blank.png", "blank.png", "blank.png", "blank.png", "bullet_hole.png", "blank.png"} }, on_step = function(self, dt) if TICK % 50 then local lua_instance = self.lua_instance if lua_instance.exp_time <= 0 then self.object:remove() return end if lua_instance.exp_time < 2.5 then local properties = self.object:get_properties() properties.textures[5] = lua_instance.texture..'^[opacity:'..(math.floor((12.75*tostring(lua_instance.exp_time/2.5)))*20) self.object:set_properties(properties) end end end })