2021-04-30 17:30:24 +00:00
|
|
|
"""
|
|
|
|
|
ObjectUpdate blame tracker, to figure out what objects are spamming updates
|
|
|
|
|
|
|
|
|
|
Assumes that you've received a full ObjectUpdate for everything (meaning the proxy
|
|
|
|
|
object tracker knows about it) and that you have received an ObjectProperties for
|
|
|
|
|
everything you want the name of. You can force a full ObjectUpdate for everything
|
|
|
|
|
by relogging with an empty object cache. Doing the "precache_objects" command
|
|
|
|
|
before you start tracking can help too.
|
|
|
|
|
"""
|
|
|
|
|
from typing import *
|
|
|
|
|
|
|
|
|
|
from hippolyzer.lib.base.datatypes import UUID
|
2023-06-18 18:29:51 +00:00
|
|
|
from hippolyzer.lib.base.message.message import Message
|
2021-04-30 17:30:24 +00:00
|
|
|
from hippolyzer.lib.base.objects import Object
|
2021-06-01 08:23:33 +00:00
|
|
|
from hippolyzer.lib.base.templates import PCode
|
2021-04-30 17:30:24 +00:00
|
|
|
from hippolyzer.lib.proxy.addon_utils import BaseAddon, show_message, SessionProperty
|
|
|
|
|
from hippolyzer.lib.proxy.commands import handle_command
|
|
|
|
|
from hippolyzer.lib.proxy.region import ProxiedRegion
|
|
|
|
|
from hippolyzer.lib.proxy.sessions import Session
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ObjectUpdateBlameAddon(BaseAddon):
|
|
|
|
|
update_blame_counter: Counter[UUID] = SessionProperty(Counter)
|
2022-11-01 23:06:17 +00:00
|
|
|
should_track_update_blame: bool = SessionProperty(False)
|
2021-04-30 17:30:24 +00:00
|
|
|
|
|
|
|
|
@handle_command()
|
|
|
|
|
async def precache_objects(self, _session: Session, region: ProxiedRegion):
|
|
|
|
|
"""
|
|
|
|
|
Make the proxy's object tracker request any missing objects
|
|
|
|
|
|
|
|
|
|
Should be done before tracking update blame to make sure the proxy
|
|
|
|
|
knows about any objects that are cached in the client but not by the proxy
|
|
|
|
|
"""
|
|
|
|
|
region.objects.request_missing_objects()
|
|
|
|
|
|
|
|
|
|
@handle_command()
|
|
|
|
|
async def object_cache_miss_stats(self, _session: Session, region: ProxiedRegion):
|
|
|
|
|
show_message(len(region.objects.missing_locals))
|
|
|
|
|
|
|
|
|
|
@handle_command()
|
|
|
|
|
async def track_update_blame(self, _session: Session, _region: ProxiedRegion):
|
2022-11-01 23:06:17 +00:00
|
|
|
self.should_track_update_blame = True
|
2021-04-30 17:30:24 +00:00
|
|
|
|
|
|
|
|
@handle_command()
|
|
|
|
|
async def untrack_update_blame(self, _session: Session, _region: ProxiedRegion):
|
2022-11-01 23:06:17 +00:00
|
|
|
self.should_track_update_blame = False
|
2021-04-30 17:30:24 +00:00
|
|
|
|
|
|
|
|
@handle_command()
|
|
|
|
|
async def clear_update_blame(self, _session: Session, _region: ProxiedRegion):
|
|
|
|
|
self.update_blame_counter.clear()
|
|
|
|
|
|
|
|
|
|
@handle_command()
|
|
|
|
|
async def dump_update_blame(self, _session: Session, region: ProxiedRegion):
|
|
|
|
|
print("ObjectUpdate blame:")
|
|
|
|
|
for obj_id, count in self.update_blame_counter.most_common(50):
|
|
|
|
|
obj = region.objects.lookup_fullid(obj_id)
|
|
|
|
|
name = obj.Name if obj and obj.Name else "<Unknown>"
|
|
|
|
|
print(f"{obj_id} ({name!r}): {count}")
|
|
|
|
|
|
|
|
|
|
def handle_object_updated(self, session: Session, region: ProxiedRegion,
|
2023-06-18 18:29:51 +00:00
|
|
|
obj: Object, updated_props: Set[str], msg: Optional[Message]):
|
2022-11-01 23:06:17 +00:00
|
|
|
if not self.should_track_update_blame:
|
2021-04-30 17:30:24 +00:00
|
|
|
return
|
|
|
|
|
if region != session.main_region:
|
|
|
|
|
return
|
|
|
|
|
# Log this as related to the parent object unless the parent is an avatar
|
|
|
|
|
if obj.Parent and obj.Parent.PCode != PCode.AVATAR:
|
|
|
|
|
obj = obj.Parent
|
|
|
|
|
|
|
|
|
|
if obj.PCode != PCode.PRIMITIVE:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.update_blame_counter[obj.FullID] += 1
|
|
|
|
|
# Ask the region for the object name if we don't know it
|
|
|
|
|
if obj.Name is None:
|
|
|
|
|
region.objects.request_object_properties(obj)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addons = [ObjectUpdateBlameAddon()]
|