Aaron Suen 034ecef2a9 Reuse envsound fx ents from a pool
This seems to reduce steady-state bandwidth
usage when standing still significantly, at least
according to rudimentary tests.

Try to reuse the entity that is already physically
closest to the target position, so to maximize
the chance that nearby player(s) already have
the entity transferred and only need the new
pos data, in case MT is intelligent enough to send
only the needed changes.
2022-01-22 21:49:11 -05:00

135 lines
3.3 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local math, minetest, nodecore, pairs, string, vector
= math, minetest, nodecore, pairs, string, vector
local math_exp, math_random, string_format
= math.exp, math.random, string.format
-- LUALOCALS > ---------------------------------------------------------
nodecore.amcoremod()
local modname = minetest.get_current_modname()
local entname = modname .. ":fx"
minetest.register_entity(entname, {
initial_properties = {
visual_size = {x = 0, y = 0},
pointable = false,
physical = true,
is_visible = false,
collide_with_objects = false,
static_save = false
},
age = 0,
on_step = function(self, dtime)
self.age = self.age + dtime
if self.age > 60 then return self.object:remove() end
end
})
local function dsqr(a, b)
local v = vector.subtract(a, b)
return vector.dot(v, v)
end
local poolent
do
local reused = 0
local created = 0
function poolent(pos)
local bestent
local bestd
for _, ent in pairs(minetest.luaentities) do
if ent.name == entname and ent.age >= 5.5 then
local op = ent.object:get_pos()
if op then
local d = dsqr(pos, op)
if (not bestd) or d < bestd then
bestd = d
bestent = ent
end
end
end
end
if bestent then
reused = reused + 1
bestent.object:set_pos(pos)
bestent.age = 0
return bestent.object
end
created = created + 1
return minetest.add_entity(pos, entname)
end
nodecore.interval(300, function()
nodecore.log("info", string_format("%s reused %d created %d",
modname, reused, created))
reused = 0
created = 0
end)
end
local function check(pos, done, srcs)
local sp = {
x = pos.x + math_random() * 64 - 32,
y = pos.y + math_random() * 64 - 32,
z = pos.z + math_random() * 64 - 32,
}
if dsqr(sp, pos) > (32 * 32) then return end
for p in pairs(done) do
if dsqr(sp, p) < (32 * 32) then return end
end
for p in pairs(srcs) do
if dsqr(sp, p) < (4 * 4) then return end
end
if minetest.get_node(sp).name ~= "air" then return end
if nodecore.is_full_sun(sp) then
if sp.y <= 0 then return end
if math_random(1, 2) ~= 1 then return end
local np = {
x = pos.x + math_random() * 64 - 32,
y = pos.y + math_random() * 64 - 32,
z = pos.z + math_random() * 64 - 32,
}
local ent = poolent(sp)
ent:set_velocity(vector.multiply(vector.normalize(
vector.subtract(np, sp)), 4 * math_random()))
nodecore.sound_play("nc_envsound_air", {
pos = sp,
object = ent,
gain = nodecore.windiness(sp.y) / 100,
max_hear_distance = 64
})
elseif nodecore.get_node_light(sp) < 4 then
nodecore.sound_play("nc_envsound_drip", {
pos = sp,
pitchvary = 0.4,
gain = math_exp(math_random()) / 5,
max_hear_distance = 64
})
end
done[pos] = true
end
local oldpos = {}
nodecore.interval(math_random, function()
local srcs = {}
for _, pl in pairs(minetest.get_connected_players()) do
if nodecore.player_visible(pl) then
local pname = pl:get_player_name()
local pos = pl:get_pos()
local op = oldpos[pname] or pos
oldpos[pname] = pos
pos = vector.add(pos, vector.multiply(vector.subtract(pos, op), 3))
srcs[#srcs + 1] = pos
end
end
local done = {}
for _, pos in pairs(srcs) do
check(pos, done, srcs)
end
end)