267 lines
11 KiB
Python
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)
|