Performance Improvements

This commit is contained in:
ElCeejo 2022-08-09 15:18:47 -07:00
parent a71cf18e84
commit b8de610493
5 changed files with 144 additions and 101 deletions

22
api.lua
View file

@ -355,8 +355,13 @@ function creatura.sensor_ceil(self, range, water)
return dist, node return dist, node
end end
local get_objects = minetest.get_objects_inside_radius
function creatura.get_nearby_player(self, range) function creatura.get_nearby_player(self, range)
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), range or self.tracking_range) local pos = self.object:get_pos()
if not pos then return end
local stored_objs = self._nearby_objs or {}
local objects = (#stored_objs > 0 and stored_objs) or get_objects(pos, range or self.tracking_range)
for _, object in ipairs(objects) do for _, object in ipairs(objects) do
if object:is_player() if object:is_player()
and creatura.is_alive(object) then and creatura.is_alive(object) then
@ -366,7 +371,10 @@ function creatura.get_nearby_player(self, range)
end end
function creatura.get_nearby_players(self, range) function creatura.get_nearby_players(self, range)
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), range or self.tracking_range) local pos = self.object:get_pos()
if not pos then return end
local stored_objs = self._nearby_objs or {}
local objects = (#stored_objs > 0 and stored_objs) or get_objects(pos, range or self.tracking_range)
local nearby = {} local nearby = {}
for _, object in ipairs(objects) do for _, object in ipairs(objects) do
if object:is_player() if object:is_player()
@ -378,7 +386,10 @@ function creatura.get_nearby_players(self, range)
end end
function creatura.get_nearby_object(self, name, range) function creatura.get_nearby_object(self, name, range)
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), range or self.tracking_range) local pos = self.object:get_pos()
if not pos then return end
local stored_objs = self._nearby_objs or {}
local objects = (#stored_objs > 0 and stored_objs) or get_objects(pos, range or self.tracking_range)
for _, object in ipairs(objects) do for _, object in ipairs(objects) do
local ent = creatura.is_alive(object) and object:get_luaentity() local ent = creatura.is_alive(object) and object:get_luaentity()
if ent if ent
@ -392,7 +403,10 @@ function creatura.get_nearby_object(self, name, range)
end end
function creatura.get_nearby_objects(self, name, range) function creatura.get_nearby_objects(self, name, range)
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), range or self.tracking_range) local pos = self.object:get_pos()
if not pos then return end
local stored_objs = self._nearby_objs or {}
local objects = (#stored_objs > 0 and stored_objs) or get_objects(pos, range or self.tracking_range)
local nearby = {} local nearby = {}
for _, object in ipairs(objects) do for _, object in ipairs(objects) do
local ent = creatura.is_alive(object) and object:get_luaentity() local ent = creatura.is_alive(object) and object:get_luaentity()

View file

@ -74,6 +74,14 @@ function creatura.get_boid_members(pos, radius, name)
table.insert(members, object) table.insert(members, object)
end end
end end
if #members > 1 then
for _, object in ipairs(members) do
local ent = object and object:get_luaentity()
if ent then
ent._movement_data.boids = members
end
end
end
return members return members
end end

View file

@ -32,15 +32,15 @@ local vec_add = vector.add
local yaw2dir = minetest.yaw_to_dir local yaw2dir = minetest.yaw_to_dir
local dir2yaw = minetest.dir_to_yaw local dir2yaw = minetest.dir_to_yaw
--[[local function debugpart(pos, time, tex) local function debugpart(pos, time, tex)
minetest.add_particle({ minetest.add_particle({
pos = pos, pos = pos,
texture = tex or "creatura_particle_red.png", texture = tex or "creatura_particle_red.png",
expirationtime = time or 3, expirationtime = time or 0.55,
glow = 6, glow = 6,
size = 1 size = 8
}) })
end]] end
--------------------- ---------------------
-- Local Utilities -- -- Local Utilities --
@ -101,7 +101,7 @@ end
return false return false
end]] end]]
local function get_collision(self) function creatura.get_collision(self)
local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local pos = self.object:get_pos() local pos = self.object:get_pos()
if not pos then return end if not pos then return end
@ -113,41 +113,36 @@ local function get_collision(self)
-- Loop -- Loop
local pos_x, pos_z = ahead.x, ahead.z local pos_x, pos_z = ahead.x, ahead.z
for x = -width, width, width / ceil(width) do for x = -width, width, width / ceil(width) do
local vec1 = { for y = 0, height, height / ceil(height) do
x = cos(yaw) * ((pos_x + x) - pos_x) + pos_x, local pos2 = {
y = pos.y + height, x = cos(yaw) * ((pos_x + x) - pos_x) + pos_x,
z = sin(yaw) * ((pos_x + x) - pos_x) + pos_z y = pos.y + y,
} z = sin(yaw) * ((pos_x + x) - pos_x) + pos_z
local vec2 = { }
x = cos(yaw) * ((pos_x + x) - pos_x) + pos_x, if pos2.y - pos.y > (self.stepheight or 1.1)
y = pos.y, and creatura.get_node_def(pos2).walkable then
z = sin(yaw) * ((pos_x + x) - pos_x) + pos_z return true, pos2
}
local ray = raycast(vec1, vec2, false)
if ray then
local collision = ray.intersection_point
if collision.y - pos.y <= (self.stepheight or 1.1) then
local step = creatura.get_node_def({x = vec1.x, y = vec1.y + 0.5, z = vec1.z})
if step.walkable then
return true, collision
end
end end
end end
end end
return false return false
end end
local get_collision = creatura.get_collision
local function get_avoidance_dir(self) local function get_avoidance_dir(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
if not pos then return end if not pos then return end
local _, col_pos = get_collision(self) local _, col_pos = get_collision(self)
if col_pos then if col_pos then
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
local ahead = vec_add(pos, vec_normal(self.object:get_velocity())) vel.y = 0
local vel_len = vec_len(vel) * (1 + (self.step_delay or 0))
local ahead = vec_add(pos, vec_normal(vel))
local avoidance_force = vector.subtract(ahead, col_pos) local avoidance_force = vector.subtract(ahead, col_pos)
avoidance_force.y = 0 avoidance_force.y = 0
local vel_len = vec_len(vel)
avoidance_force = vec_multi(vec_normal(avoidance_force), (vel_len > 1 and vel_len) or 1) avoidance_force = vec_multi(vec_normal(avoidance_force), (vel_len > 1 and vel_len) or 1)
debugpart(vec_add(ahead, avoidance_force))
return vec_dir(pos, vec_add(ahead, avoidance_force)) return vec_dir(pos, vec_add(ahead, avoidance_force))
end end
end end

View file

@ -215,12 +215,12 @@ function mob:do_velocity()
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
if not yaw then return end if not yaw then return end
local dir = minetest.yaw_to_dir(yaw)
local horz_vel = data.horz_vel local horz_vel = data.horz_vel
local vert_vel = data.vert_vel local vert_vel = data.vert_vel
vel.x = (horz_vel and horz_vel * dir.x) or vel.x if horz_vel and horz_vel < 1 then horz_vel = 1 end
vel.x = (horz_vel and (sin(yaw) * -horz_vel)) or vel.x
vel.y = vert_vel or vel.y vel.y = vert_vel or vel.y
vel.z = (horz_vel and horz_vel * dir.z) or vel.z vel.z = (horz_vel and (cos(yaw) * horz_vel)) or vel.z
self.object:set_velocity(vel) self.object:set_velocity(vel)
end end
@ -629,6 +629,27 @@ function mob:get_target(target)
return true, line_of_sight, tpos return true, line_of_sight, tpos
end end
function mob:store_nearby_objects()
local pos = self.object:get_pos()
if not pos then return end
local objects = minetest.get_objects_inside_radius(pos, self.tracking_range or 8)
if #objects < 1 then return end
local objs = {}
for _, object in ipairs(objects) do
if creatura.is_alive(object)
and object ~= self.object then
local ent = object:get_luaentity()
local player = object:is_player()
if (ent
and not ent._ignore)
or player then
table.insert(objs, object)
end
end
end
self._nearby_objs = objs
end
-- Actions -- Actions
function mob:set_action(func) function mob:set_action(func)
@ -784,6 +805,8 @@ function mob:activate(staticdata, dtime)
end end
end end
self:store_nearby_objects()
if self.activate_func then if self.activate_func then
self:activate_func(self, staticdata, dtime) self:activate_func(self, staticdata, dtime)
end end
@ -806,20 +829,27 @@ function mob:on_step(dtime, moveresult)
if moveresult then if moveresult then
self.touching_ground = moveresult.touching_ground self.touching_ground = moveresult.touching_ground
end end
local stand_pos
local stand_node
if step_tick <= 0 then if step_tick <= 0 then
-- Physics stand_pos = self.object:get_pos()
if self._physics then if not stand_pos then return end
self:_physics(moveresult) stand_node = minetest.get_node(stand_pos)
end
-- Vitals
if self._vitals then
self:_vitals()
end
-- Cached Geometry -- Cached Geometry
self.properties = self.object:get_properties() self.properties = self.object:get_properties()
self.width = self:get_hitbox()[4] or 0.5 self.width = self:get_hitbox()[4] or 0.5
self.height = self:get_height() or 1 self.height = self:get_height() or 1
end end
if stand_pos
and stand_node then
if self._vitals then
self:_vitals(stand_pos, stand_node)
end
if self._physics then
self:_physics(moveresult, stand_pos, stand_node)
end
end
if self:timer(10) then self:store_nearby_objects() end -- Reduce expensive calls
self:do_velocity() self:do_velocity()
self:do_turn() self:do_turn()
if self.utility_stack if self.utility_stack
@ -931,16 +961,14 @@ local function collision_detection(self)
end end
end end
local function water_physics(self) local function water_physics(self, pos, node)
-- Props -- Props
local gravity = self._movement_data.gravity local gravity = self._movement_data.gravity
local height = self.height local height = self.height
-- Vectors -- Vectors
local floor_pos = self.object:get_pos() pos.y = pos.y + 0.01
floor_pos.y = floor_pos.y + 0.01 local surface_pos = pos
local surface_pos = floor_pos if minetest.get_item_group(node.name, "liquid") < 1 then
local floor_node = minetest.get_node(floor_pos)
if minetest.get_item_group(floor_node.name, "liquid") < 1 then
self.object:set_acceleration({ self.object:set_acceleration({
x = 0, x = 0,
y = gravity, y = gravity,
@ -951,13 +979,13 @@ local function water_physics(self)
end end
return return
end end
self.in_liquid = floor_node.name self.in_liquid = node.name
-- Get submergence (Not the most accurate, but reduces lag) -- Get submergence (Not the most accurate, but reduces lag)
for i = 1, math.ceil(height * 3) do for i = 1, math.ceil(height * 3) do
local step_pos = { local step_pos = {
x = floor_pos.x, x = pos.x,
y = floor_pos.y + 0.5 * i, y = pos.y + 0.5 * i,
z = floor_pos.z z = pos.z
} }
if minetest.get_item_group(minetest.get_node(step_pos).name, "liquid") > 0 then if minetest.get_item_group(minetest.get_node(step_pos).name, "liquid") > 0 then
surface_pos = step_pos surface_pos = step_pos
@ -966,7 +994,7 @@ local function water_physics(self)
end end
end end
-- Apply Physics -- Apply Physics
local submergence = surface_pos.y - floor_pos.y local submergence = surface_pos.y - pos.y
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
local bouyancy = self.bouyancy_multiplier or 1 local bouyancy = self.bouyancy_multiplier or 1
local accel = (submergence - vel.y * abs(vel.y) * 0.4) * bouyancy local accel = (submergence - vel.y * abs(vel.y) * 0.4) * bouyancy
@ -988,23 +1016,27 @@ local function water_physics(self)
}) })
end end
function mob:_physics(moveresult) function mob:_physics(moveresult, pos, node)
if not self.object then return end if not pos then return end
water_physics(self) water_physics(self, pos, node)
-- Step up nodes -- Step up nodes
do_step(self, moveresult) do_step(self, moveresult)
-- Object collision -- Object collision
collision_detection(self) collision_detection(self)
if not self.in_liquid local in_liquid = self.in_liquid
and not self.touching_ground then local on_ground = self.touching_ground
if not in_liquid
and not on_ground then
self.is_falling = true self.is_falling = true
else else
self.is_falling = false self.is_falling = false
end end
if not self.in_liquid local move_data = self._movement_data
and self._movement_data.gravity ~= 0 then if not in_liquid
and not move_data.func
and move_data.gravity ~= 0 then
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
if self.touching_ground then if on_ground then
local nvel = vector.multiply(vel, 0.2) local nvel = vector.multiply(vel, 0.2)
if nvel.x < 0.2 if nvel.x < 0.2
and nvel.z < 0.2 then and nvel.z < 0.2 then
@ -1166,67 +1198,55 @@ end
-- Vitals -- Vitals
function mob:_vitals() function mob:_vitals(pos, node)
local stand_pos = self.object:get_pos() if not pos or not node then return end
if not stand_pos then return end local stand_def = creatura.get_node_def(node.name)
local max_fall = self.max_fall or 0 local max_fall = self.max_fall or 0
if max_fall > 0 then local in_liquid = self.in_liquid
local fall_start = self._fall_start local on_ground = self.touching_ground
if self.is_falling local damage
and not fall_start then if max_fall > 0
self._fall_start = stand_pos.y and not in_liquid then
elseif fall_start then local fall_start = self._fall_start or (not on_ground and pos.y)
if self.touching_ground if fall_start then
and not self.in_liquid then if on_ground then
local damage = fall_start - stand_pos.y damage = fall_start - pos.y
if damage < max_fall then if damage < max_fall then
self._fall_start = nil damage = nil
return
end end
local resist = self.fall_resistance or 0 local resist = self.fall_resistance or 0
self:hurt(damage - (damage * resist)) damage = damage - damage * resist
self:indicate_damage()
if random(4) < 2 then
self:play_sound("hurt")
end
self._fall_start = nil
elseif self.in_liquid then
self._fall_start = nil self._fall_start = nil
end end
end end
end end
if self:timer(1) then if self:timer(1) then
local head_pos = vec_raise(stand_pos, self.height) local head_pos = vec_raise(pos, self.height)
local head_node = minetest.get_node(head_pos) local head_node = minetest.get_node(head_pos)
local head_def = creatura.get_node_def(head_node.name) if minetest.get_item_group(head_node.name, "liquid") > 0 then
if head_def.drawtype == "liquid"
and minetest.get_item_group(head_node.name, "water") > 0 then
if self._breath <= 0 then if self._breath <= 0 then
self:hurt(1) damage = (damage or 0) + 1
self:indicate_damage()
if random(4) < 2 then
self:play_sound("hurt")
end
else else
self._breath = self._breath - 1 self._breath = self._breath - 1
self:memorize("_breath", self._breath) self:memorize("_breath", self._breath)
end end
end end
local stand_node = minetest.get_node(stand_pos) if minetest.get_item_group(stand_def.name, "fire") > 0
local stand_def = creatura.get_node_def(stand_node.name)
if minetest.get_item_group(stand_node.name, "fire") > 0
and stand_def.damage_per_second then and stand_def.damage_per_second then
local damage = stand_def.damage_per_second
local resist = self.fire_resistance or 0.5 local resist = self.fire_resistance or 0.5
self:hurt(damage - damage * resist) damage = (damage or 0) + stand_def.damage_per_second * resist
self:indicate_damage()
if random(4) < 2 then
self:play_sound("hurt")
end
end end
end end
if damage then
self:hurt(damage)
self:indicate_damage()
if random(4) < 2 then
self:play_sound("hurt")
end
end
-- Entity Cramming
if self:timer(5) then if self:timer(5) then
local objects = minetest.get_objects_inside_radius(stand_pos, 0.2) local objects = minetest.get_objects_inside_radius(pos, 0.2)
if #objects > 10 then if #objects > 10 then
self:indicate_damage() self:indicate_damage()
self.hp = self:memorize("hp", -1) self.hp = self:memorize("hp", -1)

View file

@ -134,9 +134,9 @@ function creatura.find_lvm_path(self, start, goal, obj_width, obj_height, max_op
fly = fly or false fly = fly or false
swim = swim or false swim = swim or false
start = start if vec_dist(start, goal) > (self.tracking_range or 128) then return {} end
--self._path_data.start = start self._path_data.start = start
local path_neighbors = { local path_neighbors = {
{x = 1, y = 0, z = 0}, {x = 1, y = 0, z = 0},
@ -276,6 +276,12 @@ function creatura.find_lvm_path(self, start, goal, obj_width, obj_height, max_op
self._path_data.open = openSet self._path_data.open = openSet
self._path_data.closedSet = closedSet self._path_data.closedSet = closedSet
local current_start = vec_round(self._path_data.start)
if closedSet[minetest.hash_node_position(current_start)] then
start_index = minetest.hash_node_position(current_start)
end
-- Reconstruct path if end is reached -- Reconstruct path if end is reached
if ((is_on_ground(_goal) if ((is_on_ground(_goal)
or fly) or fly)