From ef4b243a30075a925f1bc976a2e141a17a07a7ce Mon Sep 17 00:00:00 2001 From: cora Date: Mon, 10 Oct 2022 03:42:51 +0200 Subject: [PATCH] Add coord safe infinite particlespawners api for mobs --- mods/ENTITIES/mcl_mobs/api.lua | 63 +++++++++++++++++++++++++++++++++- mods/ENTITIES/mcl_mobs/api.txt | 2 ++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index e85cfc160..5cb7fcf85 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -68,6 +68,7 @@ local disable_blood = minetest.settings:get_bool("mobs_disable_blood") local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false +local player_transfer_distance = minetest.settings:get("player_transfer_distance") or 128 local remove_far = true local difficulty = tonumber(minetest.settings:get("mob_difficulty")) or 1.0 local show_health = false @@ -84,6 +85,8 @@ if minetest.settings:get_bool("only_peaceful_mobs", false) then end) end +local active_particlespawners = {} + local function dir_to_pitch(dir) --local dir2 = vector.normalize(dir) @@ -121,6 +124,60 @@ minetest.register_chatcommand("clearmobs",{ end end}) +local function remove_particlespawners(pn,self) + if not active_particlespawners[pn] then return end + if not active_particlespawners[pn][self.object] then return end + for k,v in pairs(active_particlespawners[pn][self.object]) do + minetest.delete_particlespawner(v) + end +end + +local function add_particlespawners(pn,self) + if not active_particlespawners[pn] then active_particlespawners[pn] = {} end + if not active_particlespawners[pn][object] then active_particlespawners[pn][self.object] = {} end + for _,ps in pairs(self.particlespawners) do + ps.attached = self.object + ps.playername = pn + table.insert(active_particlespawners[pn][self.object],minetest.add_particlespawner(ps)) + end +end + +local function particlespawner_check(self,dtime) + if not self.particlespawners then return end + --minetest.log(dump(active_particlespawners)) + if self._particle_timer and self._particle_timer >= 1 then + self._particle_timer = 0 + local players = {} + for _,player in pairs(minetest.get_connected_players()) do + local pn = player:get_player_name() + table.insert(players,pn) + if not active_particlespawners[pn] then + active_particlespawners[pn] = {} end + + local dst = vector.distance(player:get_pos(),self.object:get_pos()) + if dst < player_transfer_distance and not active_particlespawners[pn][self.object] then + add_particlespawners(pn,self) + elseif dst >= player_transfer_distance and active_particlespawners[pn][self.object] then + remove_particlespawners(pn,self) + end + end + elseif not self._particle_timer then + self._particle_timer = 0 + end + self._particle_timer = self._particle_timer + dtime +end + +minetest.register_on_leaveplayer(function(player) + local pn = player:get_player_name() + if not active_particlespawners[pn] then return end + for _,m in pairs(active_particlespawners[pn]) do + for k,v in pairs(m) do + minetest.delete_particlespawner(v) + end + end + active_particlespawners[pn] = nil +end) + ----For Water Flowing: local enable_physics = function(object, luaentity, ignore_check) if luaentity.physical_state == false or ignore_check == true then @@ -3477,7 +3534,9 @@ end -- get entity staticdata local mob_staticdata = function(self) - + for _,p in pairs(minetest.get_connected_players()) do + remove_particlespawners(p:get_player_name(),self) + end -- remove mob when out of range unless tamed if remove_far and self.can_despawn @@ -3711,6 +3770,7 @@ local mob_step = function(self, dtime) self.lifetimer = self.lifetimer - dtime check_item_pickup(self) check_aggro(self,dtime) + particlespawner_check(self,dtime) if not self.fire_resistant then mcl_burning.tick(self.object, dtime, self) -- mcl_burning.tick may remove object immediately @@ -4226,6 +4286,7 @@ minetest.register_entity(name, { spawn_in_group = def.spawn_in_group, spawn_in_group_min = def.spawn_in_group_min, noyaw = def.noyaw or false, + particlespawners = def.particlespawners, -- End of MCL2 extensions on_spawn = def.on_spawn, diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index a73cc2e3e..038c34a77 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -260,6 +260,8 @@ functions needed for the mob to work properly which contains the following: 'pick_up' table of itemstrings the mob will pick up (e.g. for breeding) 'on_pick_up' function that will be called on item pickup - return true to not pickup the item 'custom_visual_size' will not reset visual_size from the base class on reload + 'noyaw' If true this mob will not automatically change yaw + 'particlespawners' Table of particlespawners attached to the mob. This is implemented in a coord safe manner i.e. spawners are only sent to players within the player_transfer_distance (and automatically removed). This enables infinitely lived particlespawners. mobs:gopath(self,target,callback_arrived) pathfind a way to target and run callback on arrival