* Removed the `OrderedDict`s
* Changed some stuff from the code review
* Fixed a typo
* Added these imports: `from __future__ import annotations`
and `from typing import *`
* Moved `from __future__ import annotations` to the top.
* Changed type annotation `any`s to `Any`
Both the facing target conditional and object in volume and facing
detector store the cosine of the angle. We were only doing the cosine
for one case but not the other.
The Python File Nodes were always picking up the group owner's
`plAGMasterMod` key instead of the group's `plMsgForwarder` key. This is
fixed by using the appropriate generic method for fetching an
animation's key.
In an attempt to address #359, I separated 3D stereo sounds into
separate emitter scene objects and allow the engine to position them
around the listener such that the left channel is actually on the left
of the listener (and the same for the right channel). Unfortunately,
this did not fix the bug in question. However, the code that interfaces
with sounds from the outside is now much simpler, and the improved
behavior is a win, IMO, so let's keep this.
When a responder node is linked to a Python file node's
ptAttribNamedResponder socket, it will now export with the same name as
the node itself. In that way, the responder can be addressed in the
attribute's value mapping in the Python script itself.
Previously, the indentation level was hardcoded everywhere. This was
tedious before in that changing the log structure would require changing
many manual indentation values. Now that objects can be trivially
generated at export time, the export code might be much more nested that
before. So, it's better to let indentation be more implicit. This,
therefore, adds a context manager to increase the indentation using
`with` blocks. Manual indentation specification remains for
compatibility with Python 2.2 where required.
If a sound message was being sent to a random sound modifier, the
responder tree might crash on export. This fixes that particular problem
and adds a mitigation to the responder code itself. Remember kids that,
in Python `None and True` is `None`...
This allows Region Sensor nodes to export
`plObjectInVolumeAndFacingDetector`, which only triggers the region
sensor when an avatar is in the region, facing a certain direction
(within a tolerance amount), and (optionally) moving forward.
BREAKING CHANGE: The Facing Target node can now only link to a single
condition node.
`find_input_socket()`.
It's possible that we may want to address input sockets before the
Node's `update()` method is called. In that case, we need to initialize
the socket ourselves. This is most likely to happen if you're doing
something gnawty in a Node's `init()` method.
I don't really want to talk about it. *Gulp*. Anyway, you define
multiple animations on either the animation modifier or the textures
panel. The UIs have all been unified. By default, you have an "(Entire
Animation)" that represents the old single animation. You may create
additional sub-animations over an arbitrary range of keyframes. Once
other animations are defined, the "(Entire Animation)" may be deleted.
However, if all subanimations are deleted, the "(Entire Animation)" will
resurect itself with its last known settings.
Behavior change: object animations (except for fixed cameras) now
REQUIRE an animation modifier be attached to export. It is now an error
to attach an animation modifier to any camera except for a fixed camera.
It looks like simply attaching a lamp to a group already has fairly
major implications for how it's exported. If you're adding a lamp into
a group, then you are basically saying, "I only want to affect these
specific objects.", so marking them as movable (meaning, "apply me
to all objects") doesn't really make sense in that context.
The dumb string lookup probably worked most of the time, but with recent
changes that can cause layers and materials to be renamed to things not
matching the pattern exactly, it's better to explicitly lookup the keys.
This will prevent Dynamic Text Maps from seemingly "breaking" for no
reason just because the lighting strategy changes.
When an emitter is a random sound emitter, then it is no longer possible
to address the individual sounds on that emitter. Instead, you can now
only stop or resume the randomization OR set the volume of the active
sound.
We were only comparing connections in one direction in order to make the
list of suggestions. This ensures that suggested connections are
validated in both directions.
This allows directing the message to *all* modifiers -- this is
primarily only useful for ladders, but some other types may respect the
message. Also exposed the ability to send the message to child objects.
Translation of the rules posted by Sirius @ https://forum.guildofwriters.org/viewtopic.php?p=73757#p73757
PotS is in worldspace when the mass is non-zero. Plasma likely detects
nonzero mass as "this object can move" and expects localspace. MOUL on
the other hand uses localspace if the object has a CI, otherwise
worldspace.
It appears that in Havok-physics enabled versions of Plasma, plEnableMsg
does not affect physics. Therefore, we have to send the PotS-era
plSimSuppressMsg to do this job.
This fixes the issue in which python nodes reused in multiple pages
won't get properly exported. The exporter doesn't store which page a
node was exported to, and the "optimization" to prevent dupe python
parameters was over-optimizing in the case of multiple pages. Trivial
attempts to track the pages we exported to failed, so we'll fall back to
checking the PFM's filename. If it's None, then obviously the PFM has
not been exported...