Specifically for the case of sponge squeezers, not only do we need
enough map around the artificial water to be loaded, we need it to
actually be active, to be certain that the squeezer has an
opportunity to run and keep the water fresh. This change should
prevent specific water nodes from disappearing from sponge
squeezers when they're right on the edge of the active mapblock
range.
This genericizes the API for checking the state of a mapblock, and
adds a function to check if a mapblock is active, not merely loaded.
Any gameplay mechanic that could be done before only in full
direct sunlight now works anywhere using the light from an
immediately adjacent shining lens.
The only things that still require full true sunlight are purely
cosmetic things like ambient sound effects.
Instead of doing 16 pseudo-raycasts per second, lower it to a max
of 4, and don't do "catch up" raycasts if we are stepping at a
slower rate than that, just increase the weight of the current
cast to account for the entire time frame.
This will reduce the precision of radiation detection in the short
run, but is probably still good enough, especially with radiation
simulation already being very probabilistic.
This will hopefully mitigate per-player performance load on more
heavily loaded servers with many players.
Testing did not reveal this to have a meaningful impact; most of
the lag I was hoping to prevent with it is still there. Even though
this is a big operation and runs tens of thousands of iterations
per second in some cases, it's still efficient enough overall that
it doesn't impact lag significantly.
Leaving it disabled would cause there to be bugs/exploits with
tall columns of stuff remaining suspended in mid air if the upper
parts are unloaded when the bottom is dug out. While there is no
way to avoid that entirely, as long as the middle area where
some falling node is floating above air gets loaded eventually,
it will at least self-resolve with the feature intact as
originally.
This reverts commit 580fcc462292f495b531735ca098faae9060b9c7.
Previously, this was triggering "on every load" to ensure that
there is the lowest possible chance that any falling nodes are left
suspended in air, to potentially fall on players and crush or jump
scare them.
However, it seems that LBMs trigger not when a mapblock is loaded
into memory (to be kept there until unloaded after the timeout) but
when they are activated (which can happen repeatedly for the same
mapblock if a player is walking back and forth so that it enters
and leaves their active radius). This was causing a storm of LBM
events to fire, which, while the actions are very small (just
adding a position to a queue) the number of times the engine calls
the method (and the repeated construction and garbage collection
of tens of thousands of vectors) is suspected of causing
significant performance issues.
For now, replace this LBM with a once-ever-per-mapblock LBM which
fires only after a block is initially generated. We will need to
catch anything we miss later with the cleanup ABM, which should be
a lot gentler on performance.
What we were calling "data.n" basically means "an entity already
has this position covered so another is not needed." We check it
below in the "creation" phase to skip creating where an ent already
exists, but we ALSO check it in the "validation" phase, above where
it's set, to catch duplicate entities during the loop pass.
This was a guard against the filtered entity collection being
modified during the pass, which can cause pairs iterators to go
off in some weird direction and miss or double count some entries.
However, we never add/remove luaentities during this iteration,
so it's safe, and we can avoid creating and GCing a separate array
each pass.
In theory this was supposed to be more efficient than walking over
every luaentity, but in practice, eventually the majority of
luaentities end up being visinvs anyway, and the filtration is
cheap enough to perform on the fly.
The bigger issue is that the visinv index was getting out of date
due to not accounting for entities that were being unloaded
passively by the engine rather than actively removed. This would
eventually bog down a server after enough uptime and certain areas
containing lots of visinvs had been unloaded and reloaded a few
times.
Nodes that are stuck in a deferred check state can get unloaded,
and we don't want to keep trying to re-check them again, even if
we are only doing it every few seconds now. Allow them to fall
out of the queue entirely, and we can pick them up again next time
they get loaded.
If a node couldn't be checked for falling due to it having an
unloaded area below it, we were kicking it back into the queue
for immediate recheck on the next step, which caused us to often
process a batch every step when those nodes were in a stable
unloaded state. Instead, kick them to a time deferred queue that
gets merged back into the main queue only every 2 seconds. This
should cut down on how many times we have to keep reshuffling the
batch and garbage-collecting old batch tables.
Some time ago, we were "labeling" callbacks so that we could use
a specially modified profiler to identify time spent per specific
callback. This became largely unnecessary thanks to the
jitprofiler mod, which shows specific line numbers anyway. Now,
the labeling has actually even broken because it interferes with
MT's newest built-in instrumentation, which expects functions, not
callable tables. Since the indirection wasn't helping, and could
only have caused some small performance costs anyway, we might as
well just remove it instead of trying to make it work.
Unfortunately "labeled" callbacks were all over the game, so now
these all have to be removed...
Each of these showed up as ~2% on a flame graph:
- Skip the sanity check for nodecore.func vs nodecore:func
typos, which don't seem to happen in the wild lately.
- Directly construct a vector in unsuspend instead of using the
more expensive abstract vector functions.
- Debounce YCTIWY database saving to cut down on serialization
calls, especially since writes are IIRC debounced by MTE
anyway.
Instead of updating entity age every tick for every envsound
entity, record their "birth" time, compute age ad-hoc, and run
a slower interval to cull expired ones. This should cut down
a lot on the per-step costs of these entities.
The old API simply registered functions, which listened for all
events and received all parameters. This was inefficient because:
- Not all calls actually used the "node" parameter, so if we don't
need it, and the event that triggers the notification doesn't
provide one, we used to have to do a get_node for it.
- A lot of things that can change a node in the world can't
actually cause certain things to change. For example,
remove_node can never cause a cookable node to be in a position
for a recipe check (and making plain air cookable would not
be sane).
Allowing us to selectively ignore certain events, and to indicate
that we aren't using the "node" param so the API doesn't need to go
out of its way to provide it, should make a lot of things more
efficient.
The biggest problems we were seeing were when a lot of liquids were
transforming due to "pumhell" deep underground, where pumice
freezing and melting causes constant reflows of pumwater. This is
an intentional game mechanic to make those areas dangerous to
explore or try to develop without taming them, but the only notify
callback we really need to trigger is the optic revalidation one,
which should just be checking for indexed beams to reevaluate and
finding none in most cases. We were seeing a ton of lag when in
these areas, leading to the hypothesis that it's all the other
unnecessary checks that causes this slowdown.
Instead of using limited-lifetime particles that need to be
refreshed, use sprite entities, which never need to be replaced
as long as they stay loaded.
There was a short "glitch" when replacing the particles where
they could appear twice, or be absent, for a frame or two. If
we're taking the screenshot at insanely high resolution/AA, which
the automation in this mod enables, we may have fractional FPS,
and the time window when the particles are in an invalid state
may expand to the point where it's impossible to capture a
screenshot with the correct smoke particles.
Making the smoke particles stable this way makes it possible to
reliably capture a screenshot with correct smoke particles at
insanely high quality / low framerate.
The documentation says that position is absolute unless you pass
in absolute = false. This is not correct, as passing in
absolute = true seems to be necessary to fix it. That's what was
necessary to get the behavior back in line with what the old
set_bone_position was.
Moving the head up 1/2 unit was apparently some workaround for an
issue that existed in some previous version, but no longer
applies to 5.9.0 at least.
This is apparently due to some lack of RTL support in MT itself
which is not easily resolved or worked around, so the affected
languages currently just can't be supported.
- Don't produce translated output for languages that are blocked.
- This also works around a package validation error in CDB due to
some unrecognized unicode in the current nc_api.ar.tr file.
- Also don't advertise translation completion for unsupported
languages, since users will not experience the translation.
For a high-resolution texture pack to properly support these, it
MUST use overrides, either to replace the texture with a pre-baked
one, or to correct the combine layer offsets. If a texture pack
does not do this, rescale the images down to 16x16 so that the
resultant image is at least properly aligned at some resolution.
There were severe performance issues when players place objects
like tools or amalgam to soak under a wide enough spread out flow
of flux, as it was recursively backtracing to the source for each
soaking object, which could involve inspecting a ton of nodes each
time.
Instead, try background scanning all flowing flux nodes, and
propagate distance information slowly forward from the source out
to each node. Checking each soaking object is now only a fixed
length validation and cache check. Propagation itself is a fixed
amount of work per node, and the ABM limiter limits the work
involved.
Propagation is a bit slower (possibly a lot slower on a
sufficiently loaded server) so there may be more delays in
soaking response, but it should limit the maximum lag caused by
this mechanic.
The actual distance calculation has changed, so charging rates
may have changed.
According to Rollerozxa, player:set_inventory_formspec has
updated an already-visible form since at least 5.6, so the extra
explicit show_formspec shouldn't have been necessary for a while.
This also resimplifies the form name hack back out, and further
simplifies the player guide code.
This allows us to remove a compatibility hack that risked creating
memory leaks on the server side. There may be other
simplifications possible that aren't known yet (e.g. with
formspec handling)
We are apparently no longer allowed to use show_formspec to replace
an already-open inventory form with another version of the same
form, we have to rename it, and then support 2 different names for
the same form.
This fixes tool infusion/boosting not working after engine
commit e7dd9737.
Before, minetest.after(0, func) was running in FIFO order, but
after it's in LIFO order. Unexpectedly, we were actually relying
on the old behavior unknowingly, as the after(0) to build the AISM
index was racing against the after(0) to register the AISMs for
infusion/boosting. When they were in FIFO order, the AISM index
was rebuilt last, so it included the infusion/boosting AISMs.
We never really intended AISMs to be registered "long" after load
time, but they were never intended not to work "immediately" after
load time. Using after(0) rather than on_mods_loaded callbacks
ensures that all engine item registration MUST be completed
already. However, we don't want to get into an arms race of
registering minetest.after(0.00001) to ensure the AISM index gets
rebuilt after all after(0) registrations. So it's actually cleaner
just to allow AISM registration at any time.
Whenever an AISM is registered, rebuild the index on the next tick
(it's deferred to debounce, since a bunch of AISMs could get
registered in a batch but we only want to rebuild the index once
if possible). This ensures that the AISM index is never out of
date for a non-trivial amount of time, and thus AISMs should
generally work reliably over time now, regardless of when they're
registered.
This may or may not actually work on servers. If it does, then
it may help cut down on log/chat noise from players trying to join
using outdated protocols.
If the player somehow gets beyond map_limit, allow push-out to
work, but continue to treat ignores inside map_limit as non-solid
until they can finish being loaded.
Items can be changed into other items by dropping. This can
replace just the item name, or it can run arbitrary logic and
replace the entire stack.
This is used now to drop shining lenses as normal inactive ones
instantly instead of relying on the AISM to deactivate them
after dropping. It smooths out gameplay logic and may prevent
things like accidentally activating lenses for a moment.
Holding lenses in hand while facing an optic beam causes the
lenses in your hand to shine, but shining lenses didn't stack with
non-shining lenses, so picking up lenses from the ground when in
this state would fail to stack. This fixes that.
builtin:item entities and nc_player_yctiwy apparently already use
the standard unified stack end property system.
This fixes wield items not displaying the correct metadata-driven
overrides (e.g. color or inventory/wield image) when held in
player hands. These features are not used in vanilla but are
probably used in mods.
For at least since cf4bd2d7 (26 months ago) it looks like the
recipe for quenching lode ore back into cobble has required zero
coolant instead of 1+, causing the quench recipe to happen
instantly in situations where the lode cobble should slowly
anneal over time, effectively preventing vanilla game access to
relocating lode ore per intended mechanics.
This fix should make the lode cobble quenching and annealing
recipes function as originally designed again.
Note that some old mods had relied on the inability to reform lode
ore once it's been dug (likely due to not knowing about the
advanced mechanic rather than explicitly relying on the bug) and
these have only been balanced by accident (assuming other mods
hadn't made lode ore diggable, e.g. by adding higher-tier tools).
This fix will fully cement breakage of those mods, though the
process of annealing lode cobble back into ore again will still
limit the rate that free resources can be duplicated.
Some mods (e.g. catrealm_core) set the sky with some values that
don't match the way minetest's get_sky now returns the sky table,
e.g. colors in "#xxxxxx" string vs {r,g,b,a} table format. When
we were comparing the new sky against the old one according to the
engine, this caused a mismatch on every step when this condition
was true, causing a sky change packet every step.
Instead of comparing against the engine's internal copy, just
do that for the first run, and then use the last sky definition we
requested after that, under the assumption that the engine did
correctly set it when we called set_sky last. This should prevent
mismatches when mods disagree with the engine about preferred
format, though only if the mods are themselves consistent.