Files
Hippolyzer/hippolyzer/lib/base/objects.py
Salad Dais dda3759028 Speed up Object tracking
Fixes #4
2021-05-03 02:59:50 +00:00

267 lines
11 KiB
Python

"""
Copyright 2009, Linden Research, Inc.
See NOTICE.md for previous contributors
Copyright 2021, Salad Dais
All Rights Reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
from __future__ import annotations
from typing import *
import lazy_object_proxy
import recordclass
from hippolyzer.lib.base.datatypes import Vector3, Quaternion, Vector4, UUID
class Object(recordclass.datatuple): # type: ignore
__options__ = {
"fast_new": False,
"use_weakref": True,
}
__weakref__: Any
LocalID: Optional[int] = None
State: Optional[int] = None
FullID: Optional[UUID] = None
CRC: Optional[int] = None
PCode: Optional[int] = None
Material: Optional[int] = None
ClickAction: Optional[int] = None
Scale: Optional[Vector3] = None
ParentID: Optional[int] = None
# Actually contains a weakref proxy
Parent: Optional[Object] = None
UpdateFlags: Optional[int] = None
PathCurve: Optional[int] = None
ProfileCurve: Optional[int] = None
PathBegin: Optional[int] = None
PathEnd: Optional[int] = None
PathScaleX: Optional[int] = None
PathScaleY: Optional[int] = None
PathShearX: Optional[int] = None
PathShearY: Optional[int] = None
PathTwist: Optional[int] = None
PathTwistBegin: Optional[int] = None
PathRadiusOffset: Optional[int] = None
PathTaperX: Optional[int] = None
PathTaperY: Optional[int] = None
PathRevolutions: Optional[int] = None
PathSkew: Optional[int] = None
ProfileBegin: Optional[int] = None
ProfileEnd: Optional[int] = None
ProfileHollow: Optional[int] = None
TextureEntry: Optional[Any] = None
TextureAnim: Optional[Any] = None
NameValue: Optional[Any] = None
Data: Optional[Any] = None
Text: Optional[str] = None
TextColor: Optional[bytes] = None
MediaURL: Optional[Any] = None
PSBlock: Optional[Any] = None
ExtraParams: Optional[Any] = None
Sound: Optional[UUID] = None
OwnerID: Optional[UUID] = None
SoundGain: Optional[float] = None
SoundFlags: Optional[int] = None
SoundRadius: Optional[float] = None
JointType: Optional[int] = None
JointPivot: Optional[int] = None
JointAxisOrAnchor: Optional[int] = None
TreeSpecies: Optional[int] = None
ScratchPad: Optional[bytes] = None
ObjectCosts: Optional[Dict] = None
ChildIDs: Optional[List[int]] = None
# Same as parent, contains weakref proxies.
Children: Optional[List[Object]] = None
FootCollisionPlane: Optional[Vector4] = None
Position: Optional[Vector3] = None
Velocity: Optional[Vector3] = None
Acceleration: Optional[Vector3] = None
Rotation: Optional[Quaternion] = None
AngularVelocity: Optional[Vector3] = None
# from ObjectProperties
CreatorID: Optional[UUID] = None
GroupID: Optional[UUID] = None
CreationDate: Optional[int] = None
BaseMask: Optional[int] = None
OwnerMask: Optional[int] = None
GroupMask: Optional[int] = None
EveryoneMask: Optional[int] = None
NextOwnerMask: Optional[int] = None
OwnershipCost: Optional[int] = None
# TaxRate
SaleType: Optional[int] = None
SalePrice: Optional[int] = None
AggregatePerms: Optional[int] = None
AggregatePermTextures: Optional[int] = None
AggregatePermTexturesOwner: Optional[int] = None
Category: Optional[int] = None
InventorySerial: Optional[int] = None
ItemID: Optional[UUID] = None
FolderID: Optional[UUID] = None
FromTaskID: Optional[UUID] = None
LastOwnerID: Optional[UUID] = None
Name: Optional[str] = None
Description: Optional[str] = None
TouchName: Optional[str] = None
SitName: Optional[str] = None
TextureID: Optional[Any] = None
def __init__(self, *, LocalID=None, State=None, FullID=None, CRC=None, PCode=None, Material=None,
ClickAction=None, Scale=None, ParentID=None, UpdateFlags=None, PathCurve=None, ProfileCurve=None,
PathBegin=None, PathEnd=None, PathScaleX=None, PathScaleY=None, PathShearX=None, PathShearY=None,
PathTwist=None, PathTwistBegin=None, PathRadiusOffset=None, PathTaperX=None, PathTaperY=None,
PathRevolutions=None, PathSkew=None, ProfileBegin=None, ProfileEnd=None, ProfileHollow=None,
TextureEntry=None, TextureAnim=None, NameValue=None, Data=None, Text=None, TextColor=None,
MediaURL=None, PSBlock=None, ExtraParams=None, Sound=None, OwnerID=None, SoundGain=None,
SoundFlags=None, SoundRadius=None, JointType=None, JointPivot=None, JointAxisOrAnchor=None,
FootCollisionPlane=None, Position=None, Velocity=None, Acceleration=None, Rotation=None,
AngularVelocity=None, TreeSpecies=None, ObjectCosts=None, ScratchPad=None):
""" set up the object attributes """
self.LocalID = LocalID # U32
self.State = State # U8
self.FullID = FullID # LLUUID
self.CRC = CRC # U32 // TEMPORARY HACK FOR JAMES
self.PCode = PCode # U8
self.Material = Material # U8
self.ClickAction = ClickAction # U8
self.Scale = Scale # LLVector3
self.ParentID = ParentID # U32
# Actually contains a weakref proxy
self.Parent: Optional[Object] = None
self.UpdateFlags = UpdateFlags # U32 // U32, see object_flags.h
self.PathCurve = PathCurve # U8
self.ProfileCurve = ProfileCurve # U8
self.PathBegin = PathBegin # U16 // 0 to 1, quanta = 0.01
self.PathEnd = PathEnd # U16 // 0 to 1, quanta = 0.01
self.PathScaleX = PathScaleX # U8 // 0 to 1, quanta = 0.01
self.PathScaleY = PathScaleY # U8 // 0 to 1, quanta = 0.01
self.PathShearX = PathShearX # U8 // -.5 to .5, quanta = 0.01
self.PathShearY = PathShearY # U8 // -.5 to .5, quanta = 0.01
self.PathTwist = PathTwist # S8 // -1 to 1, quanta = 0.01
self.PathTwistBegin = PathTwistBegin # S8 // -1 to 1, quanta = 0.01
self.PathRadiusOffset = PathRadiusOffset # S8 // -1 to 1, quanta = 0.01
self.PathTaperX = PathTaperX # S8 // -1 to 1, quanta = 0.01
self.PathTaperY = PathTaperY # S8 // -1 to 1, quanta = 0.01
self.PathRevolutions = PathRevolutions # U8 // 0 to 3, quanta = 0.015
self.PathSkew = PathSkew # S8 // -1 to 1, quanta = 0.01
self.ProfileBegin = ProfileBegin # U16 // 0 to 1, quanta = 0.01
self.ProfileEnd = ProfileEnd # U16 // 0 to 1, quanta = 0.01
self.ProfileHollow = ProfileHollow # U16 // 0 to 1, quanta = 0.01
self.TextureEntry = TextureEntry # Variable 2
self.TextureAnim = TextureAnim # Variable 1
self.NameValue = NameValue # Variable 2
self.Data = Data # Variable 2
self.Text = Text # Variable 1 // llSetText() hovering text
self.TextColor = TextColor # Fixed 4 // actually, a LLColor4U
self.MediaURL = MediaURL # Variable 1 // URL for web page, movie, etc.
self.PSBlock = PSBlock # Variable 1
self.ExtraParams = ExtraParams or {} # Variable 1
self.Sound = Sound # LLUUID
self.OwnerID = OwnerID # LLUUID // HACK object's owner id, only set if non-null sound, for muting
self.SoundGain = SoundGain # F32
self.SoundFlags = SoundFlags # U8
self.SoundRadius = SoundRadius # F32 // cutoff radius
self.JointType = JointType # U8
self.JointPivot = JointPivot # LLVector3
self.JointAxisOrAnchor = JointAxisOrAnchor # LLVector3
self.TreeSpecies = TreeSpecies
self.ScratchPad = ScratchPad
self.ObjectCosts = ObjectCosts or {}
self.ChildIDs = []
# Same as parent, contains weakref proxies.
self.Children: List[Object] = []
# from ObjectUpdateCompressed
self.FootCollisionPlane: Optional[Vector4] = FootCollisionPlane
self.Position: Optional[Vector3] = Position
self.Velocity: Optional[Vector3] = Velocity
self.Acceleration: Optional[Vector3] = Acceleration
self.Rotation: Optional[Quaternion] = Rotation
self.AngularVelocity: Optional[Vector3] = AngularVelocity
# from ObjectProperties
self.CreatorID = None
self.GroupID = None
self.CreationDate = None
self.BaseMask = None
self.OwnerMask = None
self.GroupMask = None
self.EveryoneMask = None
self.NextOwnerMask = None
self.OwnershipCost = None
# TaxRate
self.SaleType = None
self.SalePrice = None
self.AggregatePerms = None
self.AggregatePermTextures = None
self.AggregatePermTexturesOwner = None
self.Category = None
self.InventorySerial = None
self.ItemID = None
self.FolderID = None
self.FromTaskID = None
self.LastOwnerID = None
self.Name = None
self.Description = None
self.TouchName = None
self.SitName = None
self.TextureID = None
@property
def RegionPosition(self) -> Vector3:
if not self.ParentID:
return self.Position
if not self.Parent:
raise ValueError("Can't calculate an orphan's RegionPosition")
# TODO: Cache this and dirty cache if ancestor updates pos?
return self.Parent.RegionPosition + (self.Position.rotated(self.Parent.RegionRotation))
@property
def RegionRotation(self) -> Quaternion:
if not self.ParentID:
return self.Rotation
if not self.Parent:
raise ValueError("Can't calculate an orphan's RegionRotation")
# TODO: Cache this and dirty cache if ancestor updates rot?
return self.Rotation * self.Parent.RegionRotation
def update_properties(self, properties: Dict[str, Any]) -> Set[str]:
""" takes a dictionary of attribute:value and makes it so """
updated_properties = set()
for key, val in properties.items():
if hasattr(self, key):
old_val = getattr(self, key, val)
# Don't check equality if we're using a lazy proxy,
# parsing is deferred until we actually use it.
is_proxy = isinstance(val, lazy_object_proxy.Proxy)
if is_proxy or old_val != val:
updated_properties.add(key)
setattr(self, key, val)
return updated_properties
def to_dict(self):
return recordclass.asdict(self)