126 lines
5.0 KiB
Python
126 lines
5.0 KiB
Python
"""
|
|
Debugger for detecting when animations within an object get started or stopped
|
|
|
|
Useful for tracking down animation sequence-related bugs within your LSL scripts,
|
|
or debugging automatic animation stopping behavior in the viewer.
|
|
|
|
If an animation unexpectedly stops and nobody requested it be stopped, it's a potential viewer bug (or priority issue).
|
|
If an animation unexpectedly stops and the viewer requested it be stopped, it's also a potential viewer bug.
|
|
If an animation unexpectedly stops and only the server requested it be stopped, it's a potential script / server bug.
|
|
"""
|
|
|
|
from typing import *
|
|
|
|
from hippolyzer.lib.base.message.message import Message
|
|
from hippolyzer.lib.base.network.transport import Direction
|
|
from hippolyzer.lib.base.objects import Object
|
|
from hippolyzer.lib.base.templates import AssetType
|
|
from hippolyzer.lib.proxy.addon_utils import BaseAddon, SessionProperty
|
|
from hippolyzer.lib.proxy.region import ProxiedRegion
|
|
from hippolyzer.lib.proxy.sessions import Session
|
|
from hippolyzer.lib.base.datatypes import UUID
|
|
from hippolyzer.lib.proxy.commands import handle_command
|
|
from hippolyzer.lib.proxy.addon_utils import show_message
|
|
|
|
|
|
class AnimTrackerAddon(BaseAddon):
|
|
should_track_anims: bool = SessionProperty(False)
|
|
anims_lookup: Dict[UUID, str] = SessionProperty(dict)
|
|
last_tracker_anims: Set[UUID] = SessionProperty(set)
|
|
|
|
def _format_anim_diffs(self, started_anims: Set[UUID], stopped_anims: Set[UUID]):
|
|
added_strs = [f"+{self.anims_lookup[x]!r}" for x in started_anims]
|
|
removed_strs = [f"-{self.anims_lookup[x]!r}" for x in stopped_anims]
|
|
|
|
return ", ".join(removed_strs + added_strs)
|
|
|
|
@handle_command()
|
|
async def track_anims(self, session: Session, region: ProxiedRegion):
|
|
"""Track when animations within this object get started or stopped"""
|
|
if self.should_track_anims:
|
|
self.last_tracker_anims.clear()
|
|
self.anims_lookup.clear()
|
|
|
|
selected = region.objects.lookup_localid(session.selected.object_local)
|
|
if not selected:
|
|
return
|
|
|
|
self.should_track_anims = True
|
|
|
|
object_items = await region.objects.request_object_inv(selected)
|
|
|
|
anims: Dict[UUID, str] = {}
|
|
for item in object_items:
|
|
if item.type != AssetType.ANIMATION:
|
|
continue
|
|
anims[item.true_asset_id] = item.name
|
|
|
|
self.anims_lookup = anims
|
|
|
|
@handle_command()
|
|
async def stop_tracking_anims(self, _session: Session, _region: ProxiedRegion):
|
|
"""Stop reporting differences"""
|
|
if self.should_track_anims:
|
|
self.should_track_anims = False
|
|
self.last_tracker_anims.clear()
|
|
self.anims_lookup.clear()
|
|
|
|
def handle_lludp_message(self, session: Session, region: ProxiedRegion, message: Message):
|
|
if not self.should_track_anims:
|
|
return
|
|
|
|
if message.name != "AgentAnimation" or message.direction != Direction.OUT:
|
|
# AgentAnimation is the message the viewer uses to request manually starting or stopping animations.
|
|
# We don't care about other messages, we're just interested in distinguishing cases where the viewer
|
|
# specifically requested something vs something being done by the server on its own.
|
|
return
|
|
av = region.objects.lookup_avatar(session.agent_id)
|
|
if not av or not av.Object:
|
|
print("Somehow didn't know about our own av object?")
|
|
return
|
|
|
|
current_anims = set([x for x in av.Object.Animations if x in self.anims_lookup])
|
|
started_anims: Set[UUID] = set()
|
|
stopped_anims: Set[UUID] = set()
|
|
|
|
for block in message["AnimationList"]:
|
|
anim_id = block["AnimID"]
|
|
if anim_id not in self.anims_lookup:
|
|
continue
|
|
|
|
start_anim = block["StartAnim"]
|
|
already_started = anim_id in current_anims
|
|
if start_anim == already_started:
|
|
# No change
|
|
continue
|
|
|
|
if start_anim:
|
|
started_anims.add(anim_id)
|
|
else:
|
|
stopped_anims.add(anim_id)
|
|
|
|
if started_anims or stopped_anims:
|
|
show_message("Viewer Requested Anims: " + self._format_anim_diffs(started_anims, stopped_anims))
|
|
|
|
def handle_object_updated(self, session: Session, region: ProxiedRegion,
|
|
obj: Object, updated_props: Set[str], msg: Optional[Message]):
|
|
if not self.should_track_anims:
|
|
return
|
|
if obj.FullID != session.agent_id:
|
|
return
|
|
if "Animations" not in updated_props:
|
|
return
|
|
|
|
current_anims = set([x for x in obj.Animations if x in self.anims_lookup])
|
|
started_anims = current_anims - self.last_tracker_anims
|
|
stopped_anims = self.last_tracker_anims - current_anims
|
|
|
|
self.last_tracker_anims.clear()
|
|
self.last_tracker_anims.update(current_anims)
|
|
|
|
if started_anims or stopped_anims:
|
|
show_message("Anim Diffs: " + self._format_anim_diffs(started_anims, stopped_anims))
|
|
|
|
|
|
addons = [AnimTrackerAddon()]
|