266 lines
9.7 KiB
Python
266 lines
9.7 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 typing import *
|
|
|
|
import lazy_object_proxy
|
|
|
|
from hippolyzer.lib.base.datatypes import Vector3, Quaternion, Vector4
|
|
|
|
|
|
class Object:
|
|
""" represents an Object
|
|
|
|
Initialize the Object class instance
|
|
>>> obj = Object()
|
|
"""
|
|
|
|
__slots__ = (
|
|
"LocalID",
|
|
"State",
|
|
"FullID",
|
|
"CRC",
|
|
"PCode",
|
|
"Material",
|
|
"ClickAction",
|
|
"Scale",
|
|
"ParentID",
|
|
"UpdateFlags",
|
|
"PathCurve",
|
|
"ProfileCurve",
|
|
"PathBegin",
|
|
"PathEnd",
|
|
"PathScaleX",
|
|
"PathScaleY",
|
|
"PathShearX",
|
|
"PathShearY",
|
|
"PathTwist",
|
|
"PathTwistBegin",
|
|
"PathRadiusOffset",
|
|
"PathTaperX",
|
|
"PathTaperY",
|
|
"PathRevolutions",
|
|
"PathSkew",
|
|
"ProfileBegin",
|
|
"ProfileEnd",
|
|
"ProfileHollow",
|
|
"TextureEntry",
|
|
"TextureAnim",
|
|
"NameValue",
|
|
"Data",
|
|
"Text",
|
|
"TextColor",
|
|
"MediaURL",
|
|
"PSBlock",
|
|
"ExtraParams",
|
|
"Sound",
|
|
"OwnerID",
|
|
"SoundGain",
|
|
"SoundFlags",
|
|
"SoundRadius",
|
|
"JointType",
|
|
"JointPivot",
|
|
"JointAxisOrAnchor",
|
|
"TreeSpecies",
|
|
"ObjectCosts",
|
|
"FootCollisionPlane",
|
|
"Position",
|
|
"Velocity",
|
|
"Acceleration",
|
|
"Rotation",
|
|
"AngularVelocity",
|
|
"CreatorID",
|
|
"GroupID",
|
|
"CreationDate",
|
|
"BaseMask",
|
|
"OwnerMask",
|
|
"GroupMask",
|
|
"EveryoneMask",
|
|
"NextOwnerMask",
|
|
"OwnershipCost",
|
|
"SaleType",
|
|
"SalePrice",
|
|
"AggregatePerms",
|
|
"AggregatePermTextures",
|
|
"AggregatePermTexturesOwner",
|
|
"Category",
|
|
"InventorySerial",
|
|
"ItemID",
|
|
"FolderID",
|
|
"FromTaskID",
|
|
"LastOwnerID",
|
|
"Name",
|
|
"Description",
|
|
"TouchName",
|
|
"SitName",
|
|
"TextureID",
|
|
"ChildIDs",
|
|
"Children",
|
|
"Parent",
|
|
"ScratchPad",
|
|
"__weakref__",
|
|
)
|
|
|
|
def __init__(self, *, ID=None, 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 or ID # 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 {
|
|
x: getattr(self, x) for x in dir(self)
|
|
if not isinstance(getattr(self.__class__, x, None), property) and
|
|
not callable(getattr(self, x)) and not x.startswith("_")
|
|
}
|