forked from VoxeLibre/VoxeLibre
Merge pull request 'When mob out of range, avoid processing expensive or unneccessary things' (#3517) from improve_mob_step_performance into master
Reviewed-on: MineClone2/MineClone2#3517
This commit is contained in:
commit
987760749f
|
@ -9,6 +9,8 @@ local CRASH_WARN_FREQUENCY = 60
|
||||||
-- Localize
|
-- Localize
|
||||||
local S = minetest.get_translator("mcl_mobs")
|
local S = minetest.get_translator("mcl_mobs")
|
||||||
|
|
||||||
|
local DEVELOPMENT = minetest.settings:get_bool("mcl_development",false)
|
||||||
|
|
||||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
|
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
|
||||||
local function mcl_log (message)
|
local function mcl_log (message)
|
||||||
if LOGGING_ON then
|
if LOGGING_ON then
|
||||||
|
@ -38,15 +40,6 @@ if minetest.settings:get_bool("only_peaceful_mobs", false) then
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
local node_ok = function(pos, fallback)
|
|
||||||
fallback = fallback or mcl_mobs.fallback_node
|
|
||||||
local node = minetest.get_node_or_nil(pos)
|
|
||||||
if node and minetest.registered_nodes[node.name] then
|
|
||||||
return node
|
|
||||||
end
|
|
||||||
return minetest.registered_nodes[fallback]
|
|
||||||
end
|
|
||||||
|
|
||||||
function mob_class:update_tag() --update nametag and/or the debug box
|
function mob_class:update_tag() --update nametag and/or the debug box
|
||||||
local tag
|
local tag
|
||||||
if mobs_debug then
|
if mobs_debug then
|
||||||
|
@ -392,7 +385,10 @@ local function on_step_work (self, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
if self:falling(pos) then return end
|
if self:falling(pos) then return end
|
||||||
self:check_suspend()
|
|
||||||
|
local player_in_active_range = self:player_in_active_range()
|
||||||
|
|
||||||
|
self:check_suspend(player_in_active_range)
|
||||||
|
|
||||||
if not self.fire_resistant then
|
if not self.fire_resistant then
|
||||||
mcl_burning.tick(self.object, dtime, self)
|
mcl_burning.tick(self.object, dtime, self)
|
||||||
|
@ -411,53 +407,58 @@ local function on_step_work (self, dtime)
|
||||||
self:check_water_flow()
|
self:check_water_flow()
|
||||||
self:env_danger_movement_checks (dtime)
|
self:env_danger_movement_checks (dtime)
|
||||||
|
|
||||||
self:follow_flop() -- Mob following code.
|
-- Follow code is heavy and probably shouldn't run when not in range, but we need to extract the cancel follow stuff
|
||||||
|
self:check_follow()
|
||||||
self:set_animation_speed() -- set animation speed relative to velocity
|
self:flop()
|
||||||
|
|
||||||
self:check_smooth_rotation(dtime)
|
self:check_smooth_rotation(dtime)
|
||||||
self:check_head_swivel(dtime)
|
|
||||||
|
|
||||||
if self.jump_sound_cooloff > 0 then self.jump_sound_cooloff = self.jump_sound_cooloff - dtime end
|
if player_in_active_range then
|
||||||
self:do_jump()
|
self:set_animation_speed() -- set animation speed relative to velocity
|
||||||
|
|
||||||
|
self:check_head_swivel(dtime)
|
||||||
|
|
||||||
|
if self.jump_sound_cooloff > 0 then self.jump_sound_cooloff = self.jump_sound_cooloff - dtime end
|
||||||
|
self:do_jump()
|
||||||
|
|
||||||
|
self:check_runaway_from()
|
||||||
|
self:monster_attack()
|
||||||
|
self:npc_attack()
|
||||||
|
|
||||||
|
self:check_herd(dtime)
|
||||||
|
end
|
||||||
|
|
||||||
self:check_runaway_from()
|
|
||||||
self:monster_attack()
|
|
||||||
self:npc_attack()
|
|
||||||
self:check_aggro(dtime)
|
self:check_aggro(dtime)
|
||||||
|
|
||||||
if self.do_custom and self.do_custom(self, dtime) == false then return end
|
if self.do_custom and self.do_custom(self, dtime) == false then return end
|
||||||
|
|
||||||
|
|
||||||
-- In certain circumstances, we abandon processing of certain functionality
|
-- In certain circumstances, we abandon processing of certain functionality
|
||||||
local skip_processing = false
|
local skip_processing = false
|
||||||
if update_timers(self, dtime) then
|
if update_timers(self, dtime) then
|
||||||
skip_processing = true
|
skip_processing = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if not skip_processing then
|
if not skip_processing then
|
||||||
self:check_breeding()
|
self:check_breeding()
|
||||||
|
|
||||||
self:check_item_pickup()
|
if player_in_active_range then
|
||||||
self:set_armor_texture()
|
self:check_item_pickup()
|
||||||
|
self:set_armor_texture()
|
||||||
|
|
||||||
|
if self.opinion_sound_cooloff > 0 then
|
||||||
|
self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime
|
||||||
|
end
|
||||||
|
-- mob plays random sound at times. Should be 120. Zombie and mob farms are ridiculous
|
||||||
|
if math.random(1, 70) == 1 then
|
||||||
|
self:mob_sound("random", true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
self:check_particlespawners(dtime)
|
self:check_particlespawners(dtime)
|
||||||
|
|
||||||
if self.opinion_sound_cooloff > 0 then
|
|
||||||
self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime
|
|
||||||
end
|
|
||||||
-- mob plays random sound at times. Should be 120. Zombie and mob farms are ridiculous
|
|
||||||
if math.random(1, 70) == 1 then
|
|
||||||
self:mob_sound("random", true)
|
|
||||||
end
|
|
||||||
|
|
||||||
if self:do_states(dtime) then return end
|
if self:do_states(dtime) then return end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if mobs_debug then self:update_tag() end
|
if mobs_debug then self:update_tag() end
|
||||||
|
|
||||||
if not self.object:get_luaentity() then
|
if not self.object:get_luaentity() then
|
||||||
|
@ -487,12 +488,19 @@ local on_step_error_handler = function ()
|
||||||
minetest.log("action", "--- Bug report end ---")
|
minetest.log("action", "--- Bug report end ---")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- main mob function
|
-- main mob function
|
||||||
function mob_class:on_step(dtime)
|
function mob_class:on_step(dtime)
|
||||||
local status, retVal = xpcall(on_step_work, on_step_error_handler, self, dtime)
|
if not DEVELOPMENT then
|
||||||
if status then
|
local status, retVal = xpcall(on_step_work, on_step_error_handler, self, dtime)
|
||||||
return retVal
|
if status then
|
||||||
|
return retVal
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return on_step_work (self, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local timer = 0
|
local timer = 0
|
||||||
|
|
|
@ -3,10 +3,7 @@ local mob_class = mcl_mobs.mob_class
|
||||||
local DEFAULT_FALL_SPEED = -9.81*1.5
|
local DEFAULT_FALL_SPEED = -9.81*1.5
|
||||||
local FLOP_HEIGHT = 6
|
local FLOP_HEIGHT = 6
|
||||||
local FLOP_HOR_SPEED = 1.5
|
local FLOP_HOR_SPEED = 1.5
|
||||||
local PATHFINDING = "gowp"
|
|
||||||
|
|
||||||
local node_ice = "mcl_core:ice"
|
|
||||||
local node_snowblock = "mcl_core:snowblock"
|
|
||||||
local node_snow = "mcl_core:snow"
|
local node_snow = "mcl_core:snow"
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,14 +18,19 @@ local function atan(x)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local registered_fallback_node = minetest.registered_nodes[mcl_mobs.fallback_node]
|
||||||
|
|
||||||
-- get node but use fallback for nil or unknown
|
-- get node but use fallback for nil or unknown
|
||||||
local node_ok = function(pos, fallback)
|
local node_ok = function(pos, fallback)
|
||||||
fallback = fallback or mcl_mobs.fallback_node
|
|
||||||
local node = minetest.get_node_or_nil(pos)
|
local node = minetest.get_node_or_nil(pos)
|
||||||
if node and minetest.registered_nodes[node.name] then
|
if node and minetest.registered_nodes[node.name] then
|
||||||
return node
|
return node
|
||||||
end
|
end
|
||||||
return minetest.registered_nodes[fallback]
|
if fallback then
|
||||||
|
return minetest.registered_nodes[fallback]
|
||||||
|
else
|
||||||
|
return registered_fallback_node
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns true is node can deal damage to self
|
-- Returns true is node can deal damage to self
|
||||||
|
@ -200,14 +202,19 @@ function mob_class:can_jump_cliff()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- is mob facing a cliff or danger
|
-- is mob facing a cliff or danger
|
||||||
function mob_class:is_at_cliff_or_danger()
|
function mob_class:is_at_cliff_or_danger(can_jump_cliff)
|
||||||
if self.fear_height == 0 or self:can_jump_cliff() or self._jumping_cliff or not self.object:get_luaentity() then -- 0 for no falling protection!
|
if can_jump_cliff == nil then
|
||||||
|
can_jump_cliff = self:can_jump_cliff()
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.fear_height == 0 or can_jump_cliff or self._jumping_cliff or not self.object:get_luaentity() then -- 0 for no falling protection!
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local yaw = self.object:get_yaw()
|
local yaw = self.object:get_yaw()
|
||||||
local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
|
local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
|
||||||
local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
|
local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
|
||||||
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local ypos = pos.y + self.collisionbox[2] -- just above floor
|
local ypos = pos.y + self.collisionbox[2] -- just above floor
|
||||||
|
|
||||||
|
@ -234,8 +241,12 @@ end
|
||||||
|
|
||||||
|
|
||||||
-- copy the 'mob facing cliff_or_danger check' from above, and rework to avoid water
|
-- copy the 'mob facing cliff_or_danger check' from above, and rework to avoid water
|
||||||
function mob_class:is_at_water_danger()
|
function mob_class:is_at_water_danger(can_jump_cliff)
|
||||||
if not self.object:get_luaentity() or self:can_jump_cliff() or self._jumping_cliff then
|
if can_jump_cliff == nil then
|
||||||
|
can_jump_cliff = self:can_jump_cliff()
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self.object:get_luaentity() or can_jump_cliff or self._jumping_cliff then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local yaw = self.object:get_yaw()
|
local yaw = self.object:get_yaw()
|
||||||
|
@ -276,7 +287,9 @@ end
|
||||||
|
|
||||||
function mob_class:env_danger_movement_checks(dtime)
|
function mob_class:env_danger_movement_checks(dtime)
|
||||||
local yaw = 0
|
local yaw = 0
|
||||||
if self:is_at_water_danger() and self.state ~= "attack" then
|
|
||||||
|
local can_jump_cliff = self:can_jump_cliff()
|
||||||
|
if self.state ~= "attack" and self:is_at_water_danger(can_jump_cliff) then
|
||||||
if math.random(1, 10) <= 6 then
|
if math.random(1, 10) <= 6 then
|
||||||
self:set_velocity(0)
|
self:set_velocity(0)
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
|
@ -284,14 +297,9 @@ function mob_class:env_danger_movement_checks(dtime)
|
||||||
yaw = yaw + math.random(-0.5, 0.5)
|
yaw = yaw + math.random(-0.5, 0.5)
|
||||||
yaw = self:set_yaw( yaw, 8)
|
yaw = self:set_yaw( yaw, 8)
|
||||||
end
|
end
|
||||||
else
|
|
||||||
-- This code should probably be moved to movement code
|
|
||||||
if self.move_in_group ~= false then
|
|
||||||
self:check_herd(dtime)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if self:is_at_cliff_or_danger() then
|
if self:is_at_cliff_or_danger(can_jump_cliff) then
|
||||||
self:set_velocity(0)
|
self:set_velocity(0)
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
self:set_animation( "stand")
|
self:set_animation( "stand")
|
||||||
|
@ -614,75 +622,51 @@ end
|
||||||
|
|
||||||
|
|
||||||
-- follow player if owner or holding item, if fish outta water then flop
|
-- follow player if owner or holding item, if fish outta water then flop
|
||||||
function mob_class:follow_flop()
|
function mob_class:check_follow()
|
||||||
|
|
||||||
-- find player to follow
|
-- find player to follow
|
||||||
if (self.follow ~= ""
|
if (self.follow ~= "" or self.order == "follow") and not self.following
|
||||||
or self.order == "follow")
|
|
||||||
and not self.following
|
|
||||||
and self.state ~= "attack"
|
and self.state ~= "attack"
|
||||||
and self.order ~= "sit"
|
and self.order ~= "sit"
|
||||||
and self.state ~= "runaway" then
|
and self.state ~= "runaway" then
|
||||||
|
|
||||||
local s = self.object:get_pos()
|
local s = self.object:get_pos()
|
||||||
local players = minetest.get_connected_players()
|
local players = minetest.get_connected_players()
|
||||||
|
|
||||||
for n = 1, #players do
|
for n = 1, #players do
|
||||||
|
if (self:object_in_range(players[n])) and not mcl_mobs.invis[ players[n]:get_player_name() ] then
|
||||||
if (self:object_in_range(players[n]))
|
|
||||||
and not mcl_mobs.invis[ players[n]:get_player_name() ] then
|
|
||||||
|
|
||||||
self.following = players[n]
|
self.following = players[n]
|
||||||
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.type == "npc"
|
if self.type == "npc" and self.order == "follow"
|
||||||
and self.order == "follow"
|
and self.state ~= "attack" and self.order ~= "sit" and self.owner ~= "" then
|
||||||
and self.state ~= "attack"
|
|
||||||
and self.order ~= "sit"
|
|
||||||
and self.owner ~= "" then
|
|
||||||
|
|
||||||
-- npc stop following player if not owner
|
if self.following and self.owner and self.owner ~= self.following:get_player_name() then
|
||||||
if self.following
|
|
||||||
and self.owner
|
|
||||||
and self.owner ~= self.following:get_player_name() then
|
|
||||||
self.following = nil
|
self.following = nil
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- stop following player if not holding specific item,
|
-- stop following player if not holding specific item,
|
||||||
-- mob is horny, fleeing or attacking
|
-- mob is horny, fleeing or attacking
|
||||||
if self.following
|
if self.following and self.following:is_player()
|
||||||
and self.following:is_player()
|
and (self:follow_holding(self.following) == false or self.horny or self.state == "runaway") then
|
||||||
and (self:follow_holding(self.following) == false or
|
|
||||||
self.horny or self.state == "runaway") then
|
|
||||||
self.following = nil
|
self.following = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- follow that thing
|
-- follow that thing
|
||||||
if self.following then
|
if self.following then
|
||||||
|
|
||||||
local s = self.object:get_pos()
|
local s = self.object:get_pos()
|
||||||
|
|
||||||
local p
|
local p
|
||||||
|
|
||||||
if self.following:is_player() then
|
if self.following:is_player() then
|
||||||
|
|
||||||
p = self.following:get_pos()
|
p = self.following:get_pos()
|
||||||
|
|
||||||
elseif self.following.object then
|
elseif self.following.object then
|
||||||
|
|
||||||
p = self.following.object:get_pos()
|
p = self.following.object:get_pos()
|
||||||
end
|
end
|
||||||
|
|
||||||
if p then
|
if p then
|
||||||
|
|
||||||
local dist = vector.distance(p, s)
|
local dist = vector.distance(p, s)
|
||||||
|
|
||||||
-- dont follow if out of range
|
|
||||||
if (not self:object_in_range(self.following)) then
|
if (not self:object_in_range(self.following)) then
|
||||||
self.following = nil
|
self.following = nil
|
||||||
else
|
else
|
||||||
|
@ -692,17 +676,12 @@ function mob_class:follow_flop()
|
||||||
}
|
}
|
||||||
|
|
||||||
local yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
local yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||||
|
|
||||||
if p.x > s.x then yaw = yaw +math.pi end
|
if p.x > s.x then yaw = yaw +math.pi end
|
||||||
|
|
||||||
self:set_yaw( yaw, 2.35)
|
self:set_yaw( yaw, 2.35)
|
||||||
|
|
||||||
-- anyone but standing npc's can move along
|
-- anyone but standing npc's can move along
|
||||||
if dist > 3
|
if dist > 3 and self.order ~= "stand" then
|
||||||
and self.order ~= "stand" then
|
|
||||||
|
|
||||||
self:set_velocity(self.follow_velocity)
|
self:set_velocity(self.follow_velocity)
|
||||||
|
|
||||||
if self.walk_chance ~= 0 then
|
if self.walk_chance ~= 0 then
|
||||||
self:set_animation( "run")
|
self:set_animation( "run")
|
||||||
end
|
end
|
||||||
|
@ -710,17 +689,18 @@ function mob_class:follow_flop()
|
||||||
self:set_velocity(0)
|
self:set_velocity(0)
|
||||||
self:set_animation( "stand")
|
self:set_animation( "stand")
|
||||||
end
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mob_class:flop()
|
||||||
-- swimmers flop when out of their element, and swim again when back in
|
-- swimmers flop when out of their element, and swim again when back in
|
||||||
if self.fly then
|
if self.fly then
|
||||||
local s = self.object:get_pos()
|
local s = self.object:get_pos()
|
||||||
if self:flight_check( s) == false then
|
|
||||||
|
|
||||||
|
if self:flight_check(s) == false then
|
||||||
self.state = "flop"
|
self.state = "flop"
|
||||||
self.object:set_acceleration({x = 0, y = DEFAULT_FALL_SPEED, z = 0})
|
self.object:set_acceleration({x = 0, y = DEFAULT_FALL_SPEED, z = 0})
|
||||||
|
|
||||||
|
@ -739,7 +719,6 @@ function mob_class:follow_flop()
|
||||||
end
|
end
|
||||||
|
|
||||||
self:set_animation( "stand", true)
|
self:set_animation( "stand", true)
|
||||||
|
|
||||||
return
|
return
|
||||||
elseif self.state == "flop" then
|
elseif self.state == "flop" then
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
|
@ -770,7 +749,10 @@ end
|
||||||
local check_herd_timer = 0
|
local check_herd_timer = 0
|
||||||
function mob_class:check_herd(dtime)
|
function mob_class:check_herd(dtime)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
if not pos then return end
|
if not pos or self.state == "attack" then return end
|
||||||
|
-- Does any mob not move in group. Weird check for something not set?
|
||||||
|
if self.move_in_group == false then return end
|
||||||
|
|
||||||
check_herd_timer = check_herd_timer + dtime
|
check_herd_timer = check_herd_timer + dtime
|
||||||
if check_herd_timer < 4 then return end
|
if check_herd_timer < 4 then return end
|
||||||
check_herd_timer = 0
|
check_herd_timer = 0
|
||||||
|
|
|
@ -995,10 +995,10 @@ function mob_class:check_dying()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mob_class:check_suspend()
|
function mob_class:check_suspend(player_in_active_range)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
if pos and not self:player_in_active_range() then
|
if pos and not player_in_active_range then
|
||||||
local node_under = node_ok(vector.offset(pos,0,-1,0)).name
|
local node_under = node_ok(vector.offset(pos,0,-1,0)).name
|
||||||
|
|
||||||
self:set_animation( "stand", true)
|
self:set_animation( "stand", true)
|
||||||
|
@ -1006,8 +1006,8 @@ function mob_class:check_suspend()
|
||||||
local acc = self.object:get_acceleration()
|
local acc = self.object:get_acceleration()
|
||||||
if acc then
|
if acc then
|
||||||
if acc.y > 0 or node_under ~= "air" then
|
if acc.y > 0 or node_under ~= "air" then
|
||||||
self.object:set_acceleration(vector.new(0,0,0))
|
self.object:set_acceleration(vector.zero())
|
||||||
self.object:set_velocity(vector.new(0,0,0))
|
self.object:set_velocity(vector.zero())
|
||||||
end
|
end
|
||||||
if acc.y == 0 and node_under == "air" then
|
if acc.y == 0 and node_under == "air" then
|
||||||
self:falling(pos)
|
self:falling(pos)
|
||||||
|
|
Loading…
Reference in New Issue