| 1 |
# standard python libs |
|---|
| 2 |
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG |
|---|
| 3 |
import uuid |
|---|
| 4 |
import re |
|---|
| 5 |
from binascii import hexlify |
|---|
| 6 |
import struct |
|---|
| 7 |
import math |
|---|
| 8 |
|
|---|
| 9 |
# related |
|---|
| 10 |
|
|---|
| 11 |
# pyogp |
|---|
| 12 |
from pyogp.lib.base import * |
|---|
| 13 |
from pyogp.lib.base.datamanager import DataManager |
|---|
| 14 |
from pyogp.lib.base.permissions import * |
|---|
| 15 |
|
|---|
| 16 |
# pyogp message |
|---|
| 17 |
from pyogp.lib.base.message.message_handler import MessageHandler |
|---|
| 18 |
from pyogp.lib.base.message.packets import * |
|---|
| 19 |
from pyogp.lib.base.datatypes import * |
|---|
| 20 |
|
|---|
| 21 |
# pyogp utilities |
|---|
| 22 |
from pyogp.lib.base.utilities.helpers import Helpers |
|---|
| 23 |
from pyogp.lib.base.utilities.enums import * |
|---|
| 24 |
|
|---|
| 25 |
# initialize logging |
|---|
| 26 |
logger = getLogger('pyogp.lib.base.objects') |
|---|
| 27 |
log = logger.log |
|---|
| 28 |
|
|---|
| 29 |
class ObjectManager(DataManager): |
|---|
| 30 |
""" is an Object Manager |
|---|
| 31 |
|
|---|
| 32 |
Initialize the event queue client class |
|---|
| 33 |
>>> objects = ObjectManager() |
|---|
| 34 |
|
|---|
| 35 |
Sample implementations: region.py |
|---|
| 36 |
Tests: tests/test_objects.py |
|---|
| 37 |
""" |
|---|
| 38 |
|
|---|
| 39 |
def __init__(self, agent = None, region = None, settings = None, message_handler = None, events_handler = None): |
|---|
| 40 |
""" set up the object manager """ |
|---|
| 41 |
super(ObjectManager, self).__init__(settings, agent) |
|---|
| 42 |
self.region = region |
|---|
| 43 |
|
|---|
| 44 |
# the object store consists of a list |
|---|
| 45 |
# of Object() instances |
|---|
| 46 |
self.object_store = [] |
|---|
| 47 |
|
|---|
| 48 |
# the avatar store consists of a list |
|---|
| 49 |
# of Avatar() instances |
|---|
| 50 |
self.avatar_store = [] |
|---|
| 51 |
|
|---|
| 52 |
# other useful things |
|---|
| 53 |
self.helpers = Helpers() |
|---|
| 54 |
|
|---|
| 55 |
self.message_handler = message_handler |
|---|
| 56 |
|
|---|
| 57 |
if self.settings.LOG_VERBOSE: log(INFO, "Initializing object storage") |
|---|
| 58 |
|
|---|
| 59 |
def enable_callbacks(self): |
|---|
| 60 |
"""enables the callback handlers for this ObjectManager""" |
|---|
| 61 |
if self.settings.HANDLE_PACKETS: |
|---|
| 62 |
# supply a MessageHandler if not given one |
|---|
| 63 |
if self.message_handler == None: |
|---|
| 64 |
self.message_handler = MessageHandler() |
|---|
| 65 |
|
|---|
| 66 |
onObjectUpdate_received = self.message_handler.register('ObjectUpdate') |
|---|
| 67 |
onObjectUpdate_received.subscribe(self.onObjectUpdate) |
|---|
| 68 |
|
|---|
| 69 |
onObjectUpdateCached_received = self.message_handler.register('ObjectUpdateCached') |
|---|
| 70 |
onObjectUpdateCached_received.subscribe(self.onObjectUpdateCached) |
|---|
| 71 |
|
|---|
| 72 |
onObjectUpdateCompressed_received= self.message_handler.register('ObjectUpdateCompressed') |
|---|
| 73 |
onObjectUpdateCompressed_received.subscribe(self.onObjectUpdateCompressed) |
|---|
| 74 |
|
|---|
| 75 |
onObjectProperties_received = self.message_handler.register('ObjectProperties') |
|---|
| 76 |
onObjectProperties_received.subscribe(self.onObjectProperties) |
|---|
| 77 |
|
|---|
| 78 |
onKillObject_received= self.message_handler.register('KillObject') |
|---|
| 79 |
onKillObject_received.subscribe(self.onKillObject) |
|---|
| 80 |
|
|---|
| 81 |
# uncomment these to view packets sent back to simulator |
|---|
| 82 |
# onObjectName_sent = self.message_handler.register('ObjectName') |
|---|
| 83 |
# onObjectName_sent.subscribe(self.helpers.log_packet, self) |
|---|
| 84 |
|
|---|
| 85 |
# onDeRezObject_sent = self.message_handler.register('DeRezObject') |
|---|
| 86 |
# onDeRezObject_sent.subscribe(self.helpers.log_packet, self) |
|---|
| 87 |
|
|---|
| 88 |
|
|---|
| 89 |
def process_multiple_object_updates(self, objects): |
|---|
| 90 |
""" process a list of object updates """ |
|---|
| 91 |
|
|---|
| 92 |
[self.process_object_update(_object) for _object in objects] |
|---|
| 93 |
|
|---|
| 94 |
def process_object_update(self, _object): |
|---|
| 95 |
""" append to or replace an object in self.objects """ |
|---|
| 96 |
|
|---|
| 97 |
# this is an avatar |
|---|
| 98 |
if _object.PCode == 47: |
|---|
| 99 |
|
|---|
| 100 |
self.store_avatar(_object) |
|---|
| 101 |
|
|---|
| 102 |
# this is a Primitive |
|---|
| 103 |
elif _object.PCode == 9: |
|---|
| 104 |
|
|---|
| 105 |
self.store_object(_object) |
|---|
| 106 |
|
|---|
| 107 |
else: |
|---|
| 108 |
|
|---|
| 109 |
if self.settings.LOG_VERBOSE: log(DEBUG, "Not processing object update of type %s" % (PCode(PCode))) |
|---|
| 110 |
|
|---|
| 111 |
def store_object(self, _object): |
|---|
| 112 |
|
|---|
| 113 |
# replace an existing list member, else, append |
|---|
| 114 |
|
|---|
| 115 |
index = [self.object_store.index(_object_) for _object_ in self.object_store if _object_.LocalID == _object.LocalID] |
|---|
| 116 |
|
|---|
| 117 |
if index != []: |
|---|
| 118 |
|
|---|
| 119 |
self.object_store[index[0]] = _object |
|---|
| 120 |
|
|---|
| 121 |
#if self.settings.LOG_VERBOSE: log(DEBUG, 'Updating a stored object: %s in region \'%s\'' % (_object.FullID, self.region.SimName)) |
|---|
| 122 |
|
|---|
| 123 |
else: |
|---|
| 124 |
|
|---|
| 125 |
self.object_store.append(_object) |
|---|
| 126 |
|
|---|
| 127 |
#if self.settings.LOG_VERBOSE: log(DEBUG, 'Stored a new object: %s in region \'%s\'' % (_object.LocalID, self.region.SimName)) |
|---|
| 128 |
|
|---|
| 129 |
def store_avatar(self, _objectdata): |
|---|
| 130 |
|
|---|
| 131 |
# if the object data pertains to us, update our data! |
|---|
| 132 |
if str(_objectdata.FullID) == str(self.agent.agent_id): |
|---|
| 133 |
#self.agent.Position = _objectdata.Position # currently sets to None |
|---|
| 134 |
if self.agent.Position == None: |
|---|
| 135 |
log(WARNING, "agent.position is None objects.py") |
|---|
| 136 |
self.agent.FootCollisionPlane = _objectdata.FootCollisionPlane |
|---|
| 137 |
self.agent.Velocity = _objectdata.Velocity |
|---|
| 138 |
self.agent.Acceleration = _objectdata.Acceleration |
|---|
| 139 |
self.agent.Rotation = _objectdata.Rotation |
|---|
| 140 |
self.agent.AngularVelocity = _objectdata.AngularVelocity |
|---|
| 141 |
if self.settings.ENABLE_APPEARANCE_MANAGEMENT and not self.settings.ENABLE_LOOK_LIKE_NEARBY_AVATAR: |
|---|
| 142 |
self.agent.appearance.TextureEntry = _objectdata.TextureEntry |
|---|
| 143 |
self.agent.appearance.send_AgentSetAppearance() |
|---|
| 144 |
|
|---|
| 145 |
index = [self.avatar_store.index(_avatar_) for _avatar_ in self.avatar_store if _avatar_.LocalID == _objectdata.LocalID] |
|---|
| 146 |
|
|---|
| 147 |
if index != []: |
|---|
| 148 |
|
|---|
| 149 |
self.avatar_store[index[0]] = _objectdata |
|---|
| 150 |
|
|---|
| 151 |
#if self.settings.LOG_VERBOSE: log(DEBUG, 'Replacing a stored avatar: %s in region \'%s\'' % (_objectdata.LocalID, self.region.SimName)) |
|---|
| 152 |
|
|---|
| 153 |
else: |
|---|
| 154 |
|
|---|
| 155 |
self.avatar_store.append(_objectdata) |
|---|
| 156 |
|
|---|
| 157 |
#if self.settings.LOG_VERBOSE: log(DEBUG, 'Stored a new avatar: %s in region \'%s\'' % (_objectdata.LocalID, self.region.SimName)) |
|---|
| 158 |
|
|---|
| 159 |
def get_object_from_store(self, LocalID = None, FullID = None): |
|---|
| 160 |
""" searches the store and returns object if stored, None otherwise """ |
|---|
| 161 |
|
|---|
| 162 |
_object = [] |
|---|
| 163 |
|
|---|
| 164 |
if LocalID != None: |
|---|
| 165 |
_object = [_object for _object in self.object_store if _object.LocalID == LocalID] |
|---|
| 166 |
elif FullID != None: |
|---|
| 167 |
_object = [_object for _object in self.object_store if str(_object.FullID) == str(FullID)] |
|---|
| 168 |
|
|---|
| 169 |
if _object == []: |
|---|
| 170 |
return None |
|---|
| 171 |
else: |
|---|
| 172 |
return _object[0] |
|---|
| 173 |
|
|---|
| 174 |
def get_avatar_from_store(self, LocalID = None, FullID = None): |
|---|
| 175 |
""" searches the store and returns object if stored, None otherwise """ |
|---|
| 176 |
|
|---|
| 177 |
if LocalID != None: |
|---|
| 178 |
_avatar = [_avatar for _avatar in self.avatar_store if _avatar.LocalID == LocalID] |
|---|
| 179 |
elif FullID != None: |
|---|
| 180 |
_avatar = [_avatar for _avatar in self.avatar_store if _avatar.FullID == FullID] |
|---|
| 181 |
|
|---|
| 182 |
if _avatar == []: |
|---|
| 183 |
return None |
|---|
| 184 |
else: |
|---|
| 185 |
return _avatar[0] |
|---|
| 186 |
|
|---|
| 187 |
def my_objects(self): |
|---|
| 188 |
""" returns a list of known objects where the calling client is the owner """ |
|---|
| 189 |
|
|---|
| 190 |
matches = [_object for _object in self.object_store if str(_object.OwnerID) == str(self.agent.agent_id)] |
|---|
| 191 |
|
|---|
| 192 |
return matches |
|---|
| 193 |
|
|---|
| 194 |
def find_objects_by_name(self, Name): |
|---|
| 195 |
""" searches the store for known objects by name |
|---|
| 196 |
|
|---|
| 197 |
returns a list of all such known objects |
|---|
| 198 |
""" |
|---|
| 199 |
|
|---|
| 200 |
pattern = re.compile(Name) |
|---|
| 201 |
|
|---|
| 202 |
matches = [_object for _object in self.object_store if pattern.match(_object.Name)] |
|---|
| 203 |
|
|---|
| 204 |
return matches |
|---|
| 205 |
|
|---|
| 206 |
def find_objects_within_radius(self, radius): |
|---|
| 207 |
""" returns objects nearby. returns a list of objects """ |
|---|
| 208 |
|
|---|
| 209 |
if type(radius) != float: |
|---|
| 210 |
radius = float(radius) |
|---|
| 211 |
|
|---|
| 212 |
objects_nearby = [] |
|---|
| 213 |
|
|---|
| 214 |
for item in self.object_store: |
|---|
| 215 |
|
|---|
| 216 |
if item.Position == None: continue |
|---|
| 217 |
|
|---|
| 218 |
if math.sqrt(math.pow((item.Position.X - self.agent.Position.X),2) + math.pow((item.Position.Y - self.agent.Position.Y),2) + math.pow((item.Position.Z - self.agent.Position.Z),2)) <= radius: |
|---|
| 219 |
objects_nearby.append(item) |
|---|
| 220 |
|
|---|
| 221 |
return objects_nearby |
|---|
| 222 |
|
|---|
| 223 |
def remove_object_from_store(self, ID = None): |
|---|
| 224 |
|
|---|
| 225 |
victim = self.get_object_from_store(LocalID = ID) |
|---|
| 226 |
if victim == None: |
|---|
| 227 |
victim = self.get_avatar_from_store(LocalID = ID) |
|---|
| 228 |
|
|---|
| 229 |
# if we do not know about this object, pass |
|---|
| 230 |
if victim == None or victim == []: |
|---|
| 231 |
return |
|---|
| 232 |
|
|---|
| 233 |
# this is an avatar |
|---|
| 234 |
if victim.PCode == 47: |
|---|
| 235 |
|
|---|
| 236 |
self.kill_stored_avatar(ID) |
|---|
| 237 |
|
|---|
| 238 |
# this is a Primitive |
|---|
| 239 |
elif victim.PCode == 9: |
|---|
| 240 |
|
|---|
| 241 |
self.kill_stored_object(ID) |
|---|
| 242 |
|
|---|
| 243 |
else: |
|---|
| 244 |
|
|---|
| 245 |
if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Not processing kill of unstored object type %s" % (PCode(PCode))) |
|---|
| 246 |
|
|---|
| 247 |
def kill_stored_avatar(self, ID): |
|---|
| 248 |
|
|---|
| 249 |
index = [self.avatar_store.index(_avatar_) for _avatar_ in self.avatar_store if _avatar_.LocalID == ID] |
|---|
| 250 |
|
|---|
| 251 |
if index != []: |
|---|
| 252 |
del self.avatar_store[index[0]] |
|---|
| 253 |
if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Kill on object data for avatar tracked as local id %s" % (ID)) |
|---|
| 254 |
|
|---|
| 255 |
def kill_stored_object(self, ID): |
|---|
| 256 |
|
|---|
| 257 |
index = [self.object_store.index(_object_) for _object_ in self.object_store if _object_.LocalID == ID] |
|---|
| 258 |
|
|---|
| 259 |
if index != []: |
|---|
| 260 |
del self.object_store[index[0]] |
|---|
| 261 |
if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Kill on object data for object tracked as local id %s" % (ID)) |
|---|
| 262 |
|
|---|
| 263 |
def update_multiple_objects_properties(self, object_list): |
|---|
| 264 |
""" update the attributes of objects """ |
|---|
| 265 |
|
|---|
| 266 |
#if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Processing multiple object properties updates: %s" % (len(object_list))) |
|---|
| 267 |
|
|---|
| 268 |
for object_properties in object_list: |
|---|
| 269 |
|
|---|
| 270 |
self.update_object_properties(object_properties) |
|---|
| 271 |
|
|---|
| 272 |
def update_object_properties(self, object_properties): |
|---|
| 273 |
""" update the attributes of an object |
|---|
| 274 |
|
|---|
| 275 |
If the object is known, we update the properties. |
|---|
| 276 |
If not, we create a new object |
|---|
| 277 |
""" |
|---|
| 278 |
|
|---|
| 279 |
#if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Processing object properties update for FullID: %s" % (object_properties['FullID'])) |
|---|
| 280 |
|
|---|
| 281 |
if object_properties.has_key('PCode'): |
|---|
| 282 |
# this is an avatar |
|---|
| 283 |
if object_properties['PCode'] == 47: |
|---|
| 284 |
|
|---|
| 285 |
#if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Creating a new avatar and storing their attributes. LocalID = %s" % (object_properties['LocalID'])) |
|---|
| 286 |
|
|---|
| 287 |
_object = Object() |
|---|
| 288 |
_object._update_properties(object_properties) |
|---|
| 289 |
|
|---|
| 290 |
self.store_avatar(_object) |
|---|
| 291 |
|
|---|
| 292 |
else: |
|---|
| 293 |
|
|---|
| 294 |
self.update_prim_properties(object_properties) |
|---|
| 295 |
|
|---|
| 296 |
else: |
|---|
| 297 |
|
|---|
| 298 |
self.update_prim_properties(object_properties) |
|---|
| 299 |
|
|---|
| 300 |
def update_prim_properties(self, prim_properties): |
|---|
| 301 |
|
|---|
| 302 |
_object = self.get_object_from_store(FullID = prim_properties['FullID']) |
|---|
| 303 |
|
|---|
| 304 |
if _object == None: |
|---|
| 305 |
#if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Creating a new object and storing it's attributes. LocalID = %s" % (object_properties['LocalID'])) |
|---|
| 306 |
_object = Object() |
|---|
| 307 |
_object._update_properties(prim_properties) |
|---|
| 308 |
self.store_object(_object) |
|---|
| 309 |
else: |
|---|
| 310 |
#if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Updating an object's attributes. LocalID = %s" % (object_properties['LocalID'])) |
|---|
| 311 |
_object._update_properties(prim_properties) |
|---|
| 312 |
|
|---|
| 313 |
def request_object_update(self, ID = None, ID_list = None): |
|---|
| 314 |
""" requests object updates from the simulator |
|---|
| 315 |
|
|---|
| 316 |
accepts a tuple of (ID, CacheMissType), or a list of such tuples |
|---|
| 317 |
""" |
|---|
| 318 |
|
|---|
| 319 |
packet = RequestMultipleObjectsPacket() |
|---|
| 320 |
packet.AgentData['AgentID'] = self.agent.agent_id |
|---|
| 321 |
packet.AgentData['SessionID'] = self.agent.session_id |
|---|
| 322 |
|
|---|
| 323 |
if ID != None: |
|---|
| 324 |
|
|---|
| 325 |
ObjectData = {} |
|---|
| 326 |
ObjectData['CacheMissType'] = ID[1] |
|---|
| 327 |
ObjectData['ID'] = ID[0] |
|---|
| 328 |
|
|---|
| 329 |
packet.ObjectDataBlocks.append(ObjectData) |
|---|
| 330 |
|
|---|
| 331 |
else: |
|---|
| 332 |
|
|---|
| 333 |
for ID in ID_list: |
|---|
| 334 |
|
|---|
| 335 |
ObjectData = {} |
|---|
| 336 |
ObjectData['CacheMissType'] = ID[1] |
|---|
| 337 |
ObjectData['ID'] = ID[0] |
|---|
| 338 |
|
|---|
| 339 |
packet.ObjectDataBlocks.append(ObjectData) |
|---|
| 340 |
|
|---|
| 341 |
# enqueue the message, send as reliable |
|---|
| 342 |
self.region.enqueue_message(packet(), True) |
|---|
| 343 |
|
|---|
| 344 |
def create_default_box(self, GroupID = UUID(), relative_position = (1, 0, 0)): |
|---|
| 345 |
""" creates the default box, defaulting as 1m to the east, with an option GroupID to set the prim to""" |
|---|
| 346 |
|
|---|
| 347 |
# self.agent.Position holds where we are. we need to add this tuple to the incoming tuple (vector to a vector) |
|---|
| 348 |
location_to_rez_x = self.agent.Position.X + relative_position[0] |
|---|
| 349 |
location_to_rez_y = self.agent.Position.Y + relative_position[1] |
|---|
| 350 |
location_to_rez_z = self.agent.Position.Z + relative_position[2] |
|---|
| 351 |
|
|---|
| 352 |
location_to_rez = (location_to_rez_x, location_to_rez_y, location_to_rez_z) |
|---|
| 353 |
|
|---|
| 354 |
# not sure what RayTargetID is, send as uuid of zeros |
|---|
| 355 |
RayTargetID = UUID() |
|---|
| 356 |
|
|---|
| 357 |
self.object_add(GroupID = GroupID, PCode = 9, Material = 3, AddFlags = 2, PathCurve = 16, ProfileCurve = 1, PathBegin = 0, PathEnd = 0, PathScaleX = 100, PathScaleY = 100, PathShearX = 0, PathShearY = 0, PathTwist = 0, PathTwistBegin = 0, PathRadiusOffset = 0, PathTaperX = 0, PathTaperY = 0, PathRevolutions = 0, PathSkew = 0, ProfileBegin = 0, ProfileEnd = 0, ProfileHollow = 0, BypassRaycast = 1, RayStart = location_to_rez, RayEnd = location_to_rez, RayTargetID = RayTargetID, RayEndIsIntersection = 0, Scale = (0.5, 0.5, 0.5), Rotation = (0, 0, 0, 1), State = 0) |
|---|
| 358 |
|
|---|
| 359 |
def object_add(self, PCode, Material, AddFlags, PathCurve, ProfileCurve, PathBegin, PathEnd, PathScaleX, PathScaleY, PathShearX, PathShearY, PathTwist, PathTwistBegin, PathRadiusOffset, PathTaperX, PathTaperY, PathRevolutions, PathSkew, ProfileBegin, ProfileEnd, ProfileHollow, BypassRaycast, RayStart, RayEnd, RayTargetID, RayEndIsIntersection, Scale, Rotation, State, GroupID = UUID()): |
|---|
| 360 |
''' |
|---|
| 361 |
ObjectAdd - create new object in the world |
|---|
| 362 |
Simulator will assign ID and send message back to signal |
|---|
| 363 |
object actually created. |
|---|
| 364 |
|
|---|
| 365 |
AddFlags (see also ObjectUpdate) |
|---|
| 366 |
0x01 - use physics |
|---|
| 367 |
0x02 - create selected |
|---|
| 368 |
|
|---|
| 369 |
GroupID defaults to (No group active) |
|---|
| 370 |
''' |
|---|
| 371 |
|
|---|
| 372 |
packet = ObjectAddPacket() |
|---|
| 373 |
|
|---|
| 374 |
# build the AgentData block |
|---|
| 375 |
packet.AgentData['AgentID'] = self.agent.agent_id |
|---|
| 376 |
packet.AgentData['SessionID'] = self.agent.session_id |
|---|
| 377 |
packet.AgentData['GroupID'] = GroupID |
|---|
| 378 |
|
|---|
| 379 |
# build the ObjectData block (it's a Single) |
|---|
| 380 |
packet.ObjectData['PCode'] = PCode |
|---|
| 381 |
packet.ObjectData['Material'] = Material |
|---|
| 382 |
packet.ObjectData['AddFlags'] = AddFlags |
|---|
| 383 |
packet.ObjectData['PathCurve'] = PathCurve |
|---|
| 384 |
packet.ObjectData['ProfileCurve'] = ProfileCurve |
|---|
| 385 |
packet.ObjectData['PathBegin'] = PathBegin |
|---|
| 386 |
packet.ObjectData['PathEnd'] = PathEnd |
|---|
| 387 |
packet.ObjectData['PathScaleX'] = PathScaleX |
|---|
| 388 |
packet.ObjectData['PathScaleY'] = PathScaleY |
|---|
| 389 |
packet.ObjectData['PathShearX'] = PathShearX |
|---|
| 390 |
packet.ObjectData['PathShearY'] = PathShearY |
|---|
| 391 |
packet.ObjectData['PathTwist'] = PathTwist |
|---|
| 392 |
packet.ObjectData['PathTwistBegin'] = PathTwistBegin |
|---|
| 393 |
packet.ObjectData['PathRadiusOffset'] = PathRadiusOffset |
|---|
| 394 |
packet.ObjectData['PathTaperX'] = PathTaperX |
|---|
| 395 |
packet.ObjectData['PathTaperY'] = PathTaperY |
|---|
| 396 |
packet.ObjectData['PathRevolutions'] = PathRevolutions |
|---|
| 397 |
packet.ObjectData['PathSkew'] = PathSkew |
|---|
| 398 |
packet.ObjectData['ProfileBegin'] = ProfileBegin |
|---|
| 399 |
packet.ObjectData['ProfileEnd'] = ProfileEnd |
|---|
| 400 |
packet.ObjectData['ProfileHollow'] = ProfileHollow |
|---|
| 401 |
packet.ObjectData['BypassRaycast'] = BypassRaycast |
|---|
| 402 |
packet.ObjectData['RayStart'] = RayStart |
|---|
| 403 |
packet.ObjectData['RayEnd'] = RayEnd |
|---|
| 404 |
packet.ObjectData['RayTargetID'] = RayTargetID |
|---|
| 405 |
packet.ObjectData['RayEndIsIntersection'] = RayEndIsIntersection |
|---|
| 406 |
packet.ObjectData['Scale'] = Scale |
|---|
| 407 |
packet.ObjectData['Rotation'] = Rotation |
|---|
| 408 |
packet.ObjectData['State'] = State |
|---|
| 409 |
|
|---|
| 410 |
self.region.enqueue_message(packet(), True) |
|---|
| 411 |
|
|---|
| 412 |
def onObjectUpdate(self, packet): |
|---|
| 413 |
""" populates an Object instance and adds it to the ObjectManager() store """ |
|---|
| 414 |
|
|---|
| 415 |
object_list = [] |
|---|
| 416 |
|
|---|
| 417 |
# ToDo: handle these 2 variables properly |
|---|
| 418 |
_RegionHandle = packet.blocks['RegionData'][0].get_variable('RegionHandle').data |
|---|
| 419 |
_TimeDilation = packet.blocks['RegionData'][0].get_variable('TimeDilation').data |
|---|
| 420 |
|
|---|
| 421 |
for ObjectData_block in packet.blocks['ObjectData']: |
|---|
| 422 |
|
|---|
| 423 |
object_properties = {} |
|---|
| 424 |
|
|---|
| 425 |
object_properties['LocalID'] = ObjectData_block.get_variable('ID').data |
|---|
| 426 |
object_properties['State'] = ObjectData_block.get_variable('State').data |
|---|
| 427 |
object_properties['FullID'] = ObjectData_block.get_variable('FullID').data |
|---|
| 428 |
object_properties['CRC'] = ObjectData_block.get_variable('CRC').data |
|---|
| 429 |
object_properties['PCode'] = ObjectData_block.get_variable('PCode').data |
|---|
| 430 |
object_properties['Material'] = ObjectData_block.get_variable('Material').data |
|---|
| 431 |
object_properties['ClickAction'] = ObjectData_block.get_variable('ClickAction').data |
|---|
| 432 |
object_properties['Scale'] = ObjectData_block.get_variable('Scale').data |
|---|
| 433 |
object_properties['ObjectData'] = ObjectData_block.get_variable('ObjectData').data |
|---|
| 434 |
object_properties['ParentID'] = ObjectData_block.get_variable('ParentID').data |
|---|
| 435 |
object_properties['UpdateFlags'] = ObjectData_block.get_variable('UpdateFlags').data |
|---|
| 436 |
object_properties['PathCurve'] = ObjectData_block.get_variable('PathCurve').data |
|---|
| 437 |
object_properties['ProfileCurve'] = ObjectData_block.get_variable('ProfileCurve').data |
|---|
| 438 |
object_properties['PathBegin'] = ObjectData_block.get_variable('PathBegin').data |
|---|
| 439 |
object_properties['PathEnd'] = ObjectData_block.get_variable('PathEnd').data |
|---|
| 440 |
object_properties['PathScaleX'] = ObjectData_block.get_variable('PathScaleX').data |
|---|
| 441 |
object_properties['PathScaleY'] = ObjectData_block.get_variable('PathScaleY').data |
|---|
| 442 |
object_properties['PathShearX'] = ObjectData_block.get_variable('PathShearX').data |
|---|
| 443 |
object_properties['PathShearY'] = ObjectData_block.get_variable('PathShearY').data |
|---|
| 444 |
object_properties['PathTwist'] = ObjectData_block.get_variable('PathTwist').data |
|---|
| 445 |
object_properties['PathTwistBegin'] = ObjectData_block.get_variable('PathTwistBegin').data |
|---|
| 446 |
object_properties['PathRadiusOffset'] = ObjectData_block.get_variable('PathRadiusOffset').data |
|---|
| 447 |
object_properties['PathTaperX'] = ObjectData_block.get_variable('PathTaperX').data |
|---|
| 448 |
object_properties['PathTaperY'] = ObjectData_block.get_variable('PathTaperY').data |
|---|
| 449 |
object_properties['PathRevolutions'] = ObjectData_block.get_variable('PathRevolutions').data |
|---|
| 450 |
object_properties['PathSkew'] = ObjectData_block.get_variable('PathSkew').data |
|---|
| 451 |
object_properties['ProfileBegin'] = ObjectData_block.get_variable('ProfileBegin').data |
|---|
| 452 |
object_properties['ProfileEnd'] = ObjectData_block.get_variable('ProfileEnd').data |
|---|
| 453 |
object_properties['ProfileHollow'] = ObjectData_block.get_variable('ProfileHollow').data |
|---|
| 454 |
object_properties['TextureEntry'] = ObjectData_block.get_variable('TextureEntry').data |
|---|
| 455 |
object_properties['TextureAnim'] = ObjectData_block.get_variable('TextureAnim').data |
|---|
| 456 |
object_properties['NameValue'] = ObjectData_block.get_variable('NameValue').data |
|---|
| 457 |
object_properties['Data'] = ObjectData_block.get_variable('Data').data |
|---|
| 458 |
object_properties['Text'] = ObjectData_block.get_variable('Text').data |
|---|
| 459 |
object_properties['TextColor'] = ObjectData_block.get_variable('TextColor').data |
|---|
| 460 |
object_properties['MediaURL'] = ObjectData_block.get_variable('MediaURL').data |
|---|
| 461 |
object_properties['PSBlock'] = ObjectData_block.get_variable('PSBlock').data |
|---|
| 462 |
object_properties['ExtraParams'] = ObjectData_block.get_variable('ExtraParams').data |
|---|
| 463 |
object_properties['Sound'] = ObjectData_block.get_variable('Sound').data |
|---|
| 464 |
object_properties['OwnerID'] = ObjectData_block.get_variable('OwnerID').data |
|---|
| 465 |
object_properties['Gain'] = ObjectData_block.get_variable('Gain').data |
|---|
| 466 |
object_properties['Flags'] = ObjectData_block.get_variable('Flags').data |
|---|
| 467 |
object_properties['Radius'] = ObjectData_block.get_variable('Radius').data |
|---|
| 468 |
object_properties['JointType'] = ObjectData_block.get_variable('JointType').data |
|---|
| 469 |
object_properties['JointPivot'] = ObjectData_block.get_variable('JointPivot').data |
|---|
| 470 |
object_properties['JointAxisOrAnchor'] = ObjectData_block.get_variable('JointAxisOrAnchor').data |
|---|
| 471 |
|
|---|
| 472 |
# deal with the data stored in _ObjectData |
|---|
| 473 |
# see http://wiki.secondlife.com/wiki/ObjectUpdate#ObjectData_Format for details |
|---|
| 474 |
|
|---|
| 475 |
object_properties['FootCollisionPlane'] = None |
|---|
| 476 |
object_properties['Position'] = None |
|---|
| 477 |
object_properties['Velocity'] = None |
|---|
| 478 |
object_properties['Acceleration'] = None |
|---|
| 479 |
object_properties['Rotation'] = None |
|---|
| 480 |
object_properties['AngularVelocity'] = None |
|---|
| 481 |
|
|---|
| 482 |
if len(object_properties['ObjectData']) == 76: |
|---|
| 483 |
|
|---|
| 484 |
# Foot collision plane. LLVector4. |
|---|
| 485 |
# Angular velocity is ignored and set to 0. Falls through to 60 bytes parser. |
|---|
| 486 |
|
|---|
| 487 |
object_properties['FootCollisionPlane'] = Quaternion(object_properties['ObjectData'], 0) |
|---|
| 488 |
object_properties['Position'] = Vector3(object_properties['ObjectData'], 16) |
|---|
| 489 |
object_properties['Velocity'] = Vector3(object_properties['ObjectData'], 28) |
|---|
| 490 |
object_properties['Acceleration'] = Vector3(object_properties['ObjectData'], 40) |
|---|
| 491 |
object_properties['Rotation'] = Vector3(object_properties['ObjectData'], 52) |
|---|
| 492 |
object_properties['AngularVelocity'] = Vector3(object_properties['ObjectData'], 60) |
|---|
| 493 |
|
|---|
| 494 |
elif len(object_properties['ObjectData']) == 60: |
|---|
| 495 |
|
|---|
| 496 |
# 32 bit precision update. |
|---|
| 497 |
|
|---|
| 498 |
object_properties['Position'] = Vector3(object_properties['ObjectData'], 0) |
|---|
| 499 |
object_properties['Velocity'] = Vector3(object_properties['ObjectData'], 12) |
|---|
| 500 |
object_properties['Acceleration'] = Vector3(object_properties['ObjectData'], 24) |
|---|
| 501 |
object_properties['Rotation'] = Vector3(object_properties['ObjectData'], 36) |
|---|
| 502 |
object_properties['AngularVelocity'] = Vector3(object_properties['ObjectData'], 48) |
|---|
| 503 |
|
|---|
| 504 |
elif len(object_properties['ObjectData']) == 48: |
|---|
| 505 |
|
|---|
| 506 |
# Foot collision plane. LLVector4 |
|---|
| 507 |
# Falls through to 32 bytes parser. |
|---|
| 508 |
|
|---|
| 509 |
log(WARNING, "48 bit ObjectData precision not implemented") |
|---|
| 510 |
|
|---|
| 511 |
elif len(object_properties['ObjectData']) == 32: |
|---|
| 512 |
|
|---|
| 513 |
# 32 bit precision update. |
|---|
| 514 |
|
|---|
| 515 |
# Position. U16Vec3. |
|---|
| 516 |
# Velocity. U16Vec3. |
|---|
| 517 |
# Acceleration. U16Vec3. |
|---|
| 518 |
# Rotation. U16Rot(4xU16). |
|---|
| 519 |
# Angular velocity. LLVector3. |
|---|
| 520 |
log(WARNING, "32 bit ObjectData precision not implemented") |
|---|
| 521 |
|
|---|
| 522 |
elif len(object_properties['ObjectData']) == 16: |
|---|
| 523 |
|
|---|
| 524 |
# 8 bit precision update. |
|---|
| 525 |
|
|---|
| 526 |
# Position. U8Vec3. |
|---|
| 527 |
# Velocity. U8Vec3. |
|---|
| 528 |
# Acceleration. U8Vec3. |
|---|
| 529 |
# Rotation. U8Rot(4xU8). |
|---|
| 530 |
# Angular velocity. U8Vec3 |
|---|
| 531 |
log(WARNING, "16 bit ObjectData precision not implemented") |
|---|
| 532 |
|
|---|
| 533 |
object_list.append(object_properties) |
|---|
| 534 |
|
|---|
| 535 |
self.update_multiple_objects_properties(object_list) |
|---|
| 536 |
|
|---|
| 537 |
def onObjectUpdateCached(self, packet): |
|---|
| 538 |
""" borrowing from libomv, we'll request object data for all data coming in via ObjectUpdateCached""" |
|---|
| 539 |
|
|---|
| 540 |
# ToDo: handle these 2 variables properly |
|---|
| 541 |
_RegionHandle = packet.blocks['RegionData'][0].get_variable('RegionHandle').data |
|---|
| 542 |
_TimeDilation = packet.blocks['RegionData'][0].get_variable('TimeDilation').data |
|---|
| 543 |
|
|---|
| 544 |
_request_list = [] |
|---|
| 545 |
|
|---|
| 546 |
for ObjectData_block in packet.blocks['ObjectData']: |
|---|
| 547 |
|
|---|
| 548 |
LocalID = ObjectData_block.get_variable('ID').data |
|---|
| 549 |
_CRC = ObjectData_block.get_variable('CRC').data |
|---|
| 550 |
_UpdateFlags = ObjectData_block.get_variable('UpdateFlags').data |
|---|
| 551 |
|
|---|
| 552 |
# Objects.request_object_update() expects a tuple of (_ID, CacheMissType) |
|---|
| 553 |
|
|---|
| 554 |
# see if we have the object stored already |
|---|
| 555 |
_object = self.get_object_from_store(LocalID = LocalID) |
|---|
| 556 |
|
|---|
| 557 |
if _object == None or _object == []: |
|---|
| 558 |
CacheMissType = 1 |
|---|
| 559 |
else: |
|---|
| 560 |
CacheMissType = 0 |
|---|
| 561 |
|
|---|
| 562 |
_request_list.append((LocalID, CacheMissType)) |
|---|
| 563 |
|
|---|
| 564 |
# ask the simulator for updates |
|---|
| 565 |
self.request_object_update(ID_list = _request_list) |
|---|
| 566 |
|
|---|
| 567 |
def onObjectUpdateCompressed(self, packet): |
|---|
| 568 |
|
|---|
| 569 |
object_list = [] |
|---|
| 570 |
|
|---|
| 571 |
# ToDo: handle these 2 variables properly |
|---|
| 572 |
_RegionHandle = packet.blocks['RegionData'][0].get_variable('RegionHandle').data |
|---|
| 573 |
_TimeDilation = packet.blocks['RegionData'][0].get_variable('TimeDilation').data |
|---|
| 574 |
|
|---|
| 575 |
for ObjectData_block in packet.blocks['ObjectData']: |
|---|
| 576 |
|
|---|
| 577 |
object_properties = {} |
|---|
| 578 |
|
|---|
| 579 |
object_properties['UpdateFlags'] = ObjectData_block.get_variable('UpdateFlags').data |
|---|
| 580 |
object_properties['Data'] = ObjectData_block.get_variable('Data').data |
|---|
| 581 |
_Data = object_properties['Data'] |
|---|
| 582 |
|
|---|
| 583 |
pos = 0 # position in the binary string |
|---|
| 584 |
object_properties['FullID'] = UUID(bytes = _Data, offset = 0) # LLUUID |
|---|
| 585 |
pos += 16 |
|---|
| 586 |
object_properties['LocalID'] = struct.unpack("<I", _Data[pos:pos+4])[0] |
|---|
| 587 |
pos += 4 |
|---|
| 588 |
object_properties['PCode'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 589 |
pos += 1 |
|---|
| 590 |
|
|---|
| 591 |
if object_properties['PCode'] != 9: # if it is not a prim, stop. |
|---|
| 592 |
log(WARNING, 'Fix Me!! Skipping parsing of ObjectUpdateCompressed packet when it is not a prim.') |
|---|
| 593 |
# we ought to parse it and make sense of the data... |
|---|
| 594 |
continue |
|---|
| 595 |
|
|---|
| 596 |
object_properties['State'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 597 |
pos += 1 |
|---|
| 598 |
object_properties['CRC'] = struct.unpack("<I", _Data[pos:pos+4])[0] |
|---|
| 599 |
pos += 4 |
|---|
| 600 |
object_properties['Material'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 601 |
pos += 1 |
|---|
| 602 |
object_properties['ClickAction'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 603 |
pos += 1 |
|---|
| 604 |
object_properties['Scale'] = Vector3(_Data, pos) |
|---|
| 605 |
pos += 12 |
|---|
| 606 |
object_properties['Position'] = Vector3(_Data, pos) |
|---|
| 607 |
pos += 12 |
|---|
| 608 |
object_properties['Rotation'] = Vector3(_Data, pos) |
|---|
| 609 |
pos += 12 |
|---|
| 610 |
object_properties['Flags'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 611 |
pos += 1 |
|---|
| 612 |
object_properties['OwnerID'] = UUID(bytes = _Data, offset = pos) |
|---|
| 613 |
pos += 16 |
|---|
| 614 |
|
|---|
| 615 |
# Placeholder vars, to be populated via flags if present |
|---|
| 616 |
object_properties['AngularVelocity'] = Vector3() |
|---|
| 617 |
object_properties['ParentID'] = UUID() |
|---|
| 618 |
object_properties['Text'] = '' |
|---|
| 619 |
object_properties['TextColor'] = None |
|---|
| 620 |
object_properties['MediaURL'] = '' |
|---|
| 621 |
object_properties['Sound'] = UUID() |
|---|
| 622 |
object_properties['Gain'] = 0 |
|---|
| 623 |
object_properties['Flags'] = 0 |
|---|
| 624 |
object_properties['Radius'] = 0 |
|---|
| 625 |
object_properties['NameValue'] = '' |
|---|
| 626 |
object_properties['ExtraParams'] = None |
|---|
| 627 |
|
|---|
| 628 |
if object_properties['Flags'] != 0: |
|---|
| 629 |
|
|---|
| 630 |
log(WARNING, "FixMe! Quiting parsing an ObjectUpdateCompressed packet with flags due to incomplete implemention. Storing a partial representation of an object with uuid of %s" % (_FullID)) |
|---|
| 631 |
|
|---|
| 632 |
# the commented code is not working right, we need to figure out why! |
|---|
| 633 |
# ExtraParams in particular seemed troublesome |
|---|
| 634 |
|
|---|
| 635 |
''' |
|---|
| 636 |
print 'Flags: ', Flags |
|---|
| 637 |
|
|---|
| 638 |
if (Flags & CompressedUpdateFlags.contains_AngularVelocity) != 0: |
|---|
| 639 |
_AngularVelocity = Vector3(_Data, pos) |
|---|
| 640 |
pos += 12 |
|---|
| 641 |
print 'AngularVelocity: ', _AngularVelocity |
|---|
| 642 |
else: |
|---|
| 643 |
_AngularVelocity = None |
|---|
| 644 |
|
|---|
| 645 |
if (Flags & CompressedUpdateFlags.contains_Parent) != 0: |
|---|
| 646 |
_ParentID = UUID(_Data, pos) |
|---|
| 647 |
pos += 16 |
|---|
| 648 |
print 'ParentID: ', _ParentID |
|---|
| 649 |
else: |
|---|
| 650 |
_ParentID = None |
|---|
| 651 |
|
|---|
| 652 |
if (Flags & CompressedUpdateFlags.Tree) != 0: |
|---|
| 653 |
# skip it, only iterate the position |
|---|
| 654 |
pos += 1 |
|---|
| 655 |
print 'Tree' |
|---|
| 656 |
|
|---|
| 657 |
if (Flags & CompressedUpdateFlags.ScratchPad) != 0: |
|---|
| 658 |
# skip it, only iterate the position |
|---|
| 659 |
size = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 660 |
pos += 1 |
|---|
| 661 |
pos += size |
|---|
| 662 |
print 'Scratchpad size' |
|---|
| 663 |
|
|---|
| 664 |
if (Flags & CompressedUpdateFlags.contains_Text) != 0: |
|---|
| 665 |
# skip it, only iterate the position |
|---|
| 666 |
_Text = '' |
|---|
| 667 |
while struct.unpack(">B", _Data[pos:pos+1])[0] != 0: |
|---|
| 668 |
pos += 1 |
|---|
| 669 |
pos += 1 |
|---|
| 670 |
_TextColor = struct.unpack("<I", _Data[pos:pos+4])[0] |
|---|
| 671 |
pos += 4 |
|---|
| 672 |
print '_TextColor: ', _TextColor |
|---|
| 673 |
|
|---|
| 674 |
if (Flags & CompressedUpdateFlags.MediaURL) != 0: |
|---|
| 675 |
# skip it, only iterate the position |
|---|
| 676 |
_MediaURL = '' |
|---|
| 677 |
while struct.unpack(">B", _Data[pos:pos+1])[0] != 0: |
|---|
| 678 |
pos += 1 |
|---|
| 679 |
pos += 1 |
|---|
| 680 |
print '_MediaURL: ', _MediaURL |
|---|
| 681 |
|
|---|
| 682 |
if (Flags & CompressedUpdateFlags.contains_Particles) != 0: |
|---|
| 683 |
# skip it, only iterate the position |
|---|
| 684 |
ParticleData = _Data[pos:pos+86] |
|---|
| 685 |
pos += 86 |
|---|
| 686 |
print 'Particles' |
|---|
| 687 |
|
|---|
| 688 |
# parse ExtraParams |
|---|
| 689 |
# ToDo: finish this up, for now we are just incrementing the position and not dealing with the data |
|---|
| 690 |
|
|---|
| 691 |
_Flexible = None |
|---|
| 692 |
_Light = None |
|---|
| 693 |
_Sculpt = None |
|---|
| 694 |
|
|---|
| 695 |
num_extra_params = struct.unpack(">b", _Data[pos:pos+1])[0] |
|---|
| 696 |
print 'Number of extra params: ', num_extra_params |
|---|
| 697 |
pos += 1 |
|---|
| 698 |
|
|---|
| 699 |
for i in range(num_extra_params): |
|---|
| 700 |
|
|---|
| 701 |
# ExtraParam type |
|---|
| 702 |
extraparam_type = struct.unpack("<H", _Data[pos:pos+2])[0] |
|---|
| 703 |
pos += 2 |
|---|
| 704 |
|
|---|
| 705 |
datalength = struct.unpack("<I", _Data[pos:pos+4])[0] |
|---|
| 706 |
print 'ExtraParams type: %s length: %s' % (extraparam_type, datalength) |
|---|
| 707 |
pos += 4 |
|---|
| 708 |
|
|---|
| 709 |
pos += int(datalength) |
|---|
| 710 |
|
|---|
| 711 |
# ToDo: Deal with extra parameters |
|---|
| 712 |
#log(WARNING, "Incomplete implementation in onObjectUpdateCompressed when flags are present. Skipping parsing this object...") |
|---|
| 713 |
#continue |
|---|
| 714 |
|
|---|
| 715 |
if (Flags & CompressedUpdateFlags.contains_Sound) != 0: |
|---|
| 716 |
# skip it, only iterate the position |
|---|
| 717 |
#_Sound = UUID(bytes = _Data[pos:pos+16]) |
|---|
| 718 |
pos += 16 |
|---|
| 719 |
print 'Sound' |
|---|
| 720 |
|
|---|
| 721 |
#_Gain = struct.unpack(">f", _Data[pos:pos+4])[0] |
|---|
| 722 |
pos += 4 |
|---|
| 723 |
|
|---|
| 724 |
#_Flags = stuct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 725 |
pos += 1 |
|---|
| 726 |
|
|---|
| 727 |
#_Radius = struct.unpack(">f", _Data[pos:pos+4])[0] |
|---|
| 728 |
pos += 4 |
|---|
| 729 |
|
|---|
| 730 |
if (Flags & CompressedUpdateFlags.contains_NameValues) != 0: |
|---|
| 731 |
# skip it, only iterate the position |
|---|
| 732 |
_NameValue = '' |
|---|
| 733 |
|
|---|
| 734 |
while _Data[pos:pos+1] != 0: |
|---|
| 735 |
#_NameValue += struct.unpack(">c", _Data[pos:pos+1])[0] |
|---|
| 736 |
pos += 1 |
|---|
| 737 |
pos += 1 |
|---|
| 738 |
''' |
|---|
| 739 |
|
|---|
| 740 |
object_properties['PathCurve'] = None |
|---|
| 741 |
object_properties['PathBegin'] = None |
|---|
| 742 |
object_properties['PathEnd'] = None |
|---|
| 743 |
object_properties['PathScaleX'] = None |
|---|
| 744 |
object_properties['PathScaleY'] = None |
|---|
| 745 |
object_properties['PathShearX'] = None |
|---|
| 746 |
object_properties['PathShearY'] = None |
|---|
| 747 |
object_properties['PathTwist'] = None |
|---|
| 748 |
object_properties['PathTwistBegin'] = None |
|---|
| 749 |
object_properties['PathRadiusOffset'] = None |
|---|
| 750 |
object_properties['PathTaperX'] = None |
|---|
| 751 |
object_properties['PathTaperY'] = None |
|---|
| 752 |
object_properties['PathRevolutions'] = None |
|---|
| 753 |
object_properties['PathSkew'] = None |
|---|
| 754 |
object_properties['ProfileCurve'] = None |
|---|
| 755 |
object_properties['ProfileBegin'] = None |
|---|
| 756 |
object_properties['ProfileEnd'] = None |
|---|
| 757 |
object_properties['ProfileHollow'] = None |
|---|
| 758 |
object_properties['TextureEntry'] = None |
|---|
| 759 |
object_properties['TextureAnim'] = None |
|---|
| 760 |
object_properties['TextureAnim'] = None |
|---|
| 761 |
|
|---|
| 762 |
else: |
|---|
| 763 |
|
|---|
| 764 |
object_properties['PathCurve'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 765 |
pos += 1 |
|---|
| 766 |
object_properties['PathBegin'] = struct.unpack("<H", _Data[pos:pos+2])[0] |
|---|
| 767 |
pos += 2 |
|---|
| 768 |
object_properties['PathEnd'] = struct.unpack("<H", _Data[pos:pos+2])[0] |
|---|
| 769 |
pos += 2 |
|---|
| 770 |
object_properties['PathScaleX'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 771 |
pos += 1 |
|---|
| 772 |
object_properties['PathScaleY'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 773 |
pos += 1 |
|---|
| 774 |
object_properties['PathShearX'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 775 |
pos += 1 |
|---|
| 776 |
object_properties['PathShearY'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 777 |
pos += 1 |
|---|
| 778 |
object_properties['PathTwist'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 779 |
pos += 1 |
|---|
| 780 |
object_properties['PathTwistBegin'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 781 |
pos += 1 |
|---|
| 782 |
object_properties['PathRadiusOffset'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 783 |
pos += 1 |
|---|
| 784 |
object_properties['PathTaperX'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 785 |
pos += 1 |
|---|
| 786 |
object_properties['PathTaperY'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 787 |
pos += 1 |
|---|
| 788 |
object_properties['PathRevolutions'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 789 |
pos += 1 |
|---|
| 790 |
object_properties['PathSkew'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 791 |
pos += 1 |
|---|
| 792 |
object_properties['ProfileCurve'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 793 |
pos += 1 |
|---|
| 794 |
object_properties['ProfileBegin'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 795 |
pos += 1 |
|---|
| 796 |
object_properties['ProfileEnd'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 797 |
pos += 1 |
|---|
| 798 |
object_properties['ProfileHollow'] = struct.unpack(">B", _Data[pos:pos+1])[0] |
|---|
| 799 |
pos += 1 |
|---|
| 800 |
|
|---|
| 801 |
# Texture handling |
|---|
| 802 |
size = struct.unpack("<H", _Data[pos:pos+2])[0] |
|---|
| 803 |
pos += 2 |
|---|
| 804 |
object_properties['TextureEntry'] = _Data[pos:pos+size] |
|---|
| 805 |
pos += size |
|---|
| 806 |
|
|---|
| 807 |
if (object_properties['Flags'] & CompressedUpdateFlags.TextureAnim) != 0: |
|---|
| 808 |
object_properties['TextureAnim'] = struct.unpack("<H", _Data[pos:pos+2])[0] |
|---|
| 809 |
pos += 2 |
|---|
| 810 |
else: |
|---|
| 811 |
object_properties['TextureAnim'] = None |
|---|
| 812 |
|
|---|
| 813 |
object_list.append(object_properties) |
|---|
| 814 |
|
|---|
| 815 |
self.update_multiple_objects_properties(object_list) |
|---|
| 816 |
|
|---|
| 817 |
def onKillObject(self, packet): |
|---|
| 818 |
|
|---|
| 819 |
_KillID = packet.blocks['ObjectData'][0].get_variable('ID').data |
|---|
| 820 |
|
|---|
| 821 |
self.remove_object_from_store(_KillID) |
|---|
| 822 |
|
|---|
| 823 |
def onObjectProperties(self, packet): |
|---|
| 824 |
|
|---|
| 825 |
object_list = [] |
|---|
| 826 |
|
|---|
| 827 |
for ObjectData_block in packet.blocks['ObjectData']: |
|---|
| 828 |
|
|---|
| 829 |
object_properties = {} |
|---|
| 830 |
|
|---|
| 831 |
object_properties['FullID'] = ObjectData_block.get_variable('ObjectID').data |
|---|
| 832 |
object_properties['CreatorID'] = ObjectData_block.get_variable('CreatorID').data |
|---|
| 833 |
object_properties['OwnerID'] = ObjectData_block.get_variable('OwnerID').data |
|---|
| 834 |
object_properties['GroupID'] = ObjectData_block.get_variable('GroupID').data |
|---|
| 835 |
object_properties['CreationDate'] = ObjectData_block.get_variable('CreationDate').data |
|---|
| 836 |
object_properties['BaseMask'] = ObjectData_block.get_variable('BaseMask').data |
|---|
| 837 |
object_properties['OwnerMask'] = ObjectData_block.get_variable('OwnerMask').data |
|---|
| 838 |
object_properties['GroupMask'] = ObjectData_block.get_variable('GroupMask').data |
|---|
| 839 |
object_properties['EveryoneMask'] = ObjectData_block.get_variable('EveryoneMask').data |
|---|
| 840 |
object_properties['NextOwnerMask'] = ObjectData_block.get_variable('NextOwnerMask').data |
|---|
| 841 |
object_properties['OwnershipCost'] = ObjectData_block.get_variable('OwnershipCost').data |
|---|
| 842 |
#object_properties['TaxRate'] = ObjectData_block.get_variable('TaxRate').data |
|---|
| 843 |
object_properties['SaleType'] = ObjectData_block.get_variable('SaleType').data |
|---|
| 844 |
object_properties['SalePrice'] = ObjectData_block.get_variable('SalePrice').data |
|---|
| 845 |
object_properties['AggregatePerms'] = ObjectData_block.get_variable('AggregatePerms').data |
|---|
| 846 |
object_properties['AggregatePermTextures'] = ObjectData_block.get_variable('AggregatePermTextures').data |
|---|
| 847 |
object_properties['AggregatePermTexturesOwner'] = ObjectData_block.get_variable('AggregatePermTexturesOwner').data |
|---|
| 848 |
object_properties['Category'] = ObjectData_block.get_variable('Category').data |
|---|
| 849 |
object_properties['InventorySerial'] = ObjectData_block.get_variable('InventorySerial').data |
|---|
| 850 |
object_properties['ItemID'] = ObjectData_block.get_variable('ItemID').data |
|---|
| 851 |
object_properties['FolderID'] = ObjectData_block.get_variable('FolderID').data |
|---|
| 852 |
object_properties['FromTaskID'] = ObjectData_block.get_variable('FromTaskID').data |
|---|
| 853 |
object_properties['LastOwnerID'] = ObjectData_block.get_variable('LastOwnerID').data |
|---|
| 854 |
object_properties['Name'] = ObjectData_block.get_variable('Name').data |
|---|
| 855 |
object_properties['Description'] = ObjectData_block.get_variable('Description').data |
|---|
| 856 |
object_properties['TouchName'] = ObjectData_block.get_variable('TouchName').data |
|---|
| 857 |
object_properties['SitName'] = ObjectData_block.get_variable('SitName').data |
|---|
| 858 |
object_properties['TextureID'] = ObjectData_block.get_variable('TextureID').data |
|---|
| 859 |
|
|---|
| 860 |
object_list.append(object_properties) |
|---|
| 861 |
|
|---|
| 862 |
self.update_multiple_objects_properties(object_list) |
|---|
| 863 |
|
|---|
| 864 |
class Object(object): |
|---|
| 865 |
""" represents an Object |
|---|
| 866 |
|
|---|
| 867 |
Initialize the Object class instance |
|---|
| 868 |
>>> object = Object() |
|---|
| 869 |
|
|---|
| 870 |
Sample implementations: objects.py |
|---|
| 871 |
Tests: tests/test_objects.py |
|---|
| 872 |
""" |
|---|
| 873 |
|
|---|
| 874 |
def __init__(self, LocalID = None, State = None, FullID = None, CRC = None, PCode = None, Material = None, ClickAction = None, Scale = None, ObjectData = 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, Gain = None, Flags = None, Radius = None, JointType = None, JointPivot = None, JointAxisOrAnchor = None, FootCollisionPlane = None, Position = None, Velocity = None, Acceleration = None, Rotation = None, AngularVelocity = None): |
|---|
| 875 |
""" set up the object attributes """ |
|---|
| 876 |
|
|---|
| 877 |
self.LocalID = LocalID # U32 |
|---|
| 878 |
self.State = State # U8 |
|---|
| 879 |
self.FullID = FullID # LLUUID |
|---|
| 880 |
self.CRC = CRC # U32 // TEMPORARY HACK FOR JAMES |
|---|
| 881 |
self.PCode = PCode # U8 |
|---|
| 882 |
self.Material = Material # U8 |
|---|
| 883 |
self.ClickAction = ClickAction # U8 |
|---|
| 884 |
self.Scale = Scale # LLVector3 |
|---|
| 885 |
self.ObjectData = ObjectData # Variable 1 |
|---|
| 886 |
self.ParentID = ParentID # U32 |
|---|
| 887 |
self.UpdateFlags = UpdateFlags # U32 // U32, see object_flags.h |
|---|
| 888 |
self.PathCurve = PathCurve # U8 |
|---|
| 889 |
self.ProfileCurve = ProfileCurve # U8 |
|---|
| 890 |
self.PathBegin = PathBegin # U16 // 0 to 1, quanta = 0.01 |
|---|
| 891 |
self.PathEnd = PathEnd # U16 // 0 to 1, quanta = 0.01 |
|---|
| 892 |
self.PathScaleX = PathScaleX # U8 // 0 to 1, quanta = 0.01 |
|---|
| 893 |
self.PathScaleY = PathScaleY # U8 // 0 to 1, quanta = 0.01 |
|---|
| 894 |
self.PathShearX = PathShearX # U8 // -.5 to .5, quanta = 0.01 |
|---|
| 895 |
self.PathShearY = PathShearY # U8 // -.5 to .5, quanta = 0.01 |
|---|
| 896 |
self.PathTwist = PathTwist # S8 // -1 to 1, quanta = 0.01 |
|---|
| 897 |
self.PathTwistBegin = PathTwistBegin # S8 // -1 to 1, quanta = 0.01 |
|---|
| 898 |
self.PathRadiusOffset = PathRadiusOffset # S8 // -1 to 1, quanta = 0.01 |
|---|
| 899 |
self.PathTaperX = PathTaperX # S8 // -1 to 1, quanta = 0.01 |
|---|
| 900 |
self.PathTaperY = PathTaperY # S8 // -1 to 1, quanta = 0.01 |
|---|
| 901 |
self.PathRevolutions = PathRevolutions # U8 // 0 to 3, quanta = 0.015 |
|---|
| 902 |
self.PathSkew = PathSkew # S8 // -1 to 1, quanta = 0.01 |
|---|
| 903 |
self.ProfileBegin = ProfileBegin # U16 // 0 to 1, quanta = 0.01 |
|---|
| 904 |
self.ProfileEnd = ProfileEnd # U16 // 0 to 1, quanta = 0.01 |
|---|
| 905 |
self.ProfileHollow = ProfileHollow # U16 // 0 to 1, quanta = 0.01 |
|---|
| 906 |
self.TextureEntry = TextureEntry # Variable 2 |
|---|
| 907 |
self.TextureAnim = TextureAnim # Variable 1 |
|---|
| 908 |
self.NameValue = NameValue # Variable 2 |
|---|
| 909 |
self.Data = Data # Variable 2 |
|---|
| 910 |
self.Text = Text # Variable 1 // llSetText() hovering text |
|---|
| 911 |
self.TextColor = TextColor # Fixed 4 // actually, a LLColor4U |
|---|
| 912 |
self.MediaURL = MediaURL # Variable 1 // URL for web page, movie, etc. |
|---|
| 913 |
self.PSBlock = PSBlock # Variable 1 |
|---|
| 914 |
self.ExtraParams = ExtraParams # Variable 1 |
|---|
| 915 |
self.Sound = Sound # LLUUID |
|---|
| 916 |
self.OwnerID = OwnerID # LLUUID // HACK object's owner id, only set if non-null sound, for muting |
|---|
| 917 |
self.Gain = Gain # F32 |
|---|
| 918 |
self.Flags = Flags # U8 |
|---|
| 919 |
self.Radius = Radius # F32 // cutoff radius |
|---|
| 920 |
self.JointType = JointType # U8 |
|---|
| 921 |
self.JointPivot = JointPivot # LLVector3 |
|---|
| 922 |
self.JointAxisOrAnchor = JointAxisOrAnchor # LLVector3 |
|---|
| 923 |
|
|---|
| 924 |
# from ObjectUpdateCompressed |
|---|
| 925 |
self.FootCollisionPlane = FootCollisionPlane |
|---|
| 926 |
self.Position = Position |
|---|
| 927 |
self.Velocity = Velocity |
|---|
| 928 |
self.Acceleration = Acceleration |
|---|
| 929 |
self.Rotation = Rotation |
|---|
| 930 |
self.AngularVelocity = AngularVelocity |
|---|
| 931 |
|
|---|
| 932 |
# from ObjectProperties |
|---|
| 933 |
self.CreatorID = None |
|---|
| 934 |
self.GroupID = None |
|---|
| 935 |
self.CreationDate = None |
|---|
| 936 |
self.BaseMask = None |
|---|
| 937 |
self.OwnerMask = None |
|---|
| 938 |
self.GroupMask = None |
|---|
| 939 |
self.EveryoneMask = None |
|---|
| 940 |
self.NextOwnerMask = None |
|---|
| 941 |
self.OwnershipCost = None |
|---|
| 942 |
# TaxRate |
|---|
| 943 |
self.SaleType = None |
|---|
| 944 |
self.SalePrice = None |
|---|
| 945 |
self.AggregatePerms = None |
|---|
| 946 |
self.AggregatePermTextures = None |
|---|
| 947 |
self.AggregatePermTexturesOwner = None |
|---|
| 948 |
self.Category = None |
|---|
| 949 |
self.InventorySerial = None |
|---|
| 950 |
self.ItemID = None |
|---|
| 951 |
self.FolderID = None |
|---|
| 952 |
self.FromTaskID = None |
|---|
| 953 |
self.LastOwnerID = None |
|---|
| 954 |
self.Name = None |
|---|
| 955 |
self.Description = None |
|---|
| 956 |
self.TouchName = None |
|---|
| 957 |
self.SitName = None |
|---|
| 958 |
self.TextureID = None |
|---|
| 959 |
|
|---|
| 960 |
def update_object_permissions(self, agent, Field, Set, Mask, Override = False): |
|---|
| 961 |
""" update permissions for a list of objects |
|---|
| 962 |
|
|---|
| 963 |
This will update a specific bit to a specific value. |
|---|
| 964 |
""" |
|---|
| 965 |
|
|---|
| 966 |
packet = ObjectPermissionsPacket() |
|---|
| 967 |
|
|---|
| 968 |
# build the AgentData block |
|---|
| 969 |
packet.AgentData['AgentID'] = agent.agent_id |
|---|
| 970 |
packet.AgentData['SessionID'] = agent.session_id |
|---|
| 971 |
|
|---|
| 972 |
packet.HeaderData['Override'] = Override # BOOL, God-bit. |
|---|
| 973 |
|
|---|
| 974 |
ObjectData = {} |
|---|
| 975 |
ObjectData['ObjectLocalID'] = self.LocalID |
|---|
| 976 |
ObjectData['Field'] = Field # U32 |
|---|
| 977 |
ObjectData['Set'] = Set # U8 |
|---|
| 978 |
ObjectData['Mask'] = Mask # S32 |
|---|
| 979 |
|
|---|
| 980 |
packet.ObjectDataBlocks.append(ObjectData) |
|---|
| 981 |
|
|---|
| 982 |
agent.region.enqueue_message(packet()) |
|---|
| 983 |
|
|---|
| 984 |
def set_object_full_permissions(self, agent): |
|---|
| 985 |
""" |
|---|
| 986 |
Set Next Owner Permissions Copy, Modify, Transfer |
|---|
| 987 |
This is also called 'full permissions'. |
|---|
| 988 |
""" |
|---|
| 989 |
|
|---|
| 990 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Copy) |
|---|
| 991 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Modify) |
|---|
| 992 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Transfer) |
|---|
| 993 |
|
|---|
| 994 |
def set_object_copy_mod_permissions(self, agent): |
|---|
| 995 |
""" |
|---|
| 996 |
Set Next Owner Permissions to Copy/Mod |
|---|
| 997 |
This is a common permission set for attachements. |
|---|
| 998 |
""" |
|---|
| 999 |
|
|---|
| 1000 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Copy) |
|---|
| 1001 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Modify) |
|---|
| 1002 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 0, PermissionsMask.Transfer) |
|---|
| 1003 |
|
|---|
| 1004 |
def set_object_mod_transfer_permissions(self, agent): |
|---|
| 1005 |
""" |
|---|
| 1006 |
Set Next Owner Permissions to Mod/Transfer |
|---|
| 1007 |
This is a common permission set for clothing. |
|---|
| 1008 |
""" |
|---|
| 1009 |
|
|---|
| 1010 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 0, PermissionsMask.Copy) |
|---|
| 1011 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Modify) |
|---|
| 1012 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Transfer) |
|---|
| 1013 |
|
|---|
| 1014 |
def set_object_transfer_only_permissions(self, agent): |
|---|
| 1015 |
""" |
|---|
| 1016 |
Set Next Owner Permissions to Transfer Only |
|---|
| 1017 |
This is the most restrictive set of permissions allowed. |
|---|
| 1018 |
""" |
|---|
| 1019 |
|
|---|
| 1020 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 0, PermissionsMask.Copy) |
|---|
| 1021 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 0, PermissionsMask.Modify) |
|---|
| 1022 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Transfer) |
|---|
| 1023 |
|
|---|
| 1024 |
def set_object_copy_transfer_permissions(self, agent): |
|---|
| 1025 |
""" |
|---|
| 1026 |
Set Next Owner Permissions to Copy/Transfer |
|---|
| 1027 |
""" |
|---|
| 1028 |
|
|---|
| 1029 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Copy) |
|---|
| 1030 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 0, PermissionsMask.Modify) |
|---|
| 1031 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Transfer) |
|---|
| 1032 |
|
|---|
| 1033 |
def set_object_copy_only_permissions(self, agent): |
|---|
| 1034 |
""" |
|---|
| 1035 |
Set Next Owner Permissions to Copy Only |
|---|
| 1036 |
""" |
|---|
| 1037 |
|
|---|
| 1038 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 1, PermissionsMask.Copy) |
|---|
| 1039 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 0, PermissionsMask.Modify) |
|---|
| 1040 |
self.update_object_permissions(agent, PermissionsTarget.NextOwner, 0, PermissionsMask.Transfer) |
|---|
| 1041 |
|
|---|
| 1042 |
def set_object_name(self, agent, Name): |
|---|
| 1043 |
""" update the name of an object |
|---|
| 1044 |
|
|---|
| 1045 |
""" |
|---|
| 1046 |
|
|---|
| 1047 |
packet = ObjectNamePacket() |
|---|
| 1048 |
|
|---|
| 1049 |
# build the AgentData block |
|---|
| 1050 |
packet.AgentData['AgentID'] = agent.agent_id |
|---|
| 1051 |
packet.AgentData['SessionID'] = agent.session_id |
|---|
| 1052 |
|
|---|
| 1053 |
ObjectData = {} |
|---|
| 1054 |
ObjectData['LocalID'] = self.LocalID |
|---|
| 1055 |
ObjectData['Name'] = Name |
|---|
| 1056 |
|
|---|
| 1057 |
packet.ObjectDataBlocks.append(ObjectData) |
|---|
| 1058 |
|
|---|
| 1059 |
agent.region.enqueue_message(packet()) |
|---|
| 1060 |
|
|---|
| 1061 |
def set_object_description(self, agent, Description): |
|---|
| 1062 |
""" update the description of an objects |
|---|
| 1063 |
|
|---|
| 1064 |
""" |
|---|
| 1065 |
|
|---|
| 1066 |
packet = ObjectDescriptionPacket() |
|---|
| 1067 |
|
|---|
| 1068 |
# build the AgentData block |
|---|
| 1069 |
packet.AgentData['AgentID'] = agent.agent_id |
|---|
| 1070 |
packet.AgentData['SessionID'] = agent.session_id |
|---|
| 1071 |
|
|---|
| 1072 |
ObjectData = {} |
|---|
| 1073 |
ObjectData['LocalID'] = self.LocalID |
|---|
| 1074 |
ObjectData['Description'] = Description |
|---|
| 1075 |
|
|---|
| 1076 |
packet.ObjectDataBlocks.append(ObjectData) |
|---|
| 1077 |
|
|---|
| 1078 |
agent.region.enqueue_message(packet()) |
|---|
| 1079 |
|
|---|
| 1080 |
def derez(self, agent, destination, destinationID, transactionID, GroupID): |
|---|
| 1081 |
""" derez an object, specifying the destination """ |
|---|
| 1082 |
|
|---|
| 1083 |
packet = DeRezObjectPacket() |
|---|
| 1084 |
|
|---|
| 1085 |
# build the AgentData block |
|---|
| 1086 |
packet.AgentData['AgentID'] = agent.agent_id |
|---|
| 1087 |
packet.AgentData['SessionID'] = agent.session_id |
|---|
| 1088 |
|
|---|
| 1089 |
packet.AgentBlock['GroupID'] = GroupID |
|---|
| 1090 |
packet.AgentBlock['Destination'] = destination |
|---|
| 1091 |
packet.AgentBlock['DestinationID'] = destinationID |
|---|
| 1092 |
packet.AgentBlock['TransactionID'] = transactionID |
|---|
| 1093 |
|
|---|
| 1094 |
# fix me: faking these values |
|---|
| 1095 |
packet.AgentBlock['PacketCount'] = 1 |
|---|
| 1096 |
packet.AgentBlock['PacketNumber'] = 0 |
|---|
| 1097 |
|
|---|
| 1098 |
ObjectData = {} |
|---|
| 1099 |
ObjectData['ObjectLocalID'] = self.LocalID |
|---|
| 1100 |
|
|---|
| 1101 |
packet.ObjectDataBlocks.append(ObjectData) |
|---|
| 1102 |
|
|---|
| 1103 |
agent.region.enqueue_message(packet()) |
|---|
| 1104 |
|
|---|
| 1105 |
def take(self, agent): |
|---|
| 1106 |
""" take object into inventory """ |
|---|
| 1107 |
|
|---|
| 1108 |
parent_folder = self.FolderID |
|---|
| 1109 |
|
|---|
| 1110 |
# Check if we have inventory turned on |
|---|
| 1111 |
if not(parent_folder and agent.settings.ENABLE_INVENTORY_MANAGEMENT): |
|---|
| 1112 |
log(WARNING,"Inventory not available, please enable settings.ENABLE_INVENTORY_MANAGEMENT") |
|---|
| 1113 |
return |
|---|
| 1114 |
|
|---|
| 1115 |
if not(parent_folder): |
|---|
| 1116 |
# locate Object folder |
|---|
| 1117 |
objects_folder = [ folder for folder in agent.inventory.folders if folder.Name == 'Objects' ] |
|---|
| 1118 |
if objects_folder: |
|---|
| 1119 |
parent_folder = objects_folder[0].FolderID |
|---|
| 1120 |
else: |
|---|
| 1121 |
log(ERROR,"Unable to locate top-level Objects folder to take item into inventory.") |
|---|
| 1122 |
return |
|---|
| 1123 |
|
|---|
| 1124 |
self.derez(agent, 4, parent_folder, uuid.uuid4(), agent.ActiveGroupID) |
|---|
| 1125 |
|
|---|
| 1126 |
def select(self, agent): |
|---|
| 1127 |
""" select an object |
|---|
| 1128 |
|
|---|
| 1129 |
""" |
|---|
| 1130 |
|
|---|
| 1131 |
packet = ObjectSelectPacket() |
|---|
| 1132 |
|
|---|
| 1133 |
# build the AgentData block |
|---|
| 1134 |
packet.AgentData['AgentID'] = agent.agent_id |
|---|
| 1135 |
packet.AgentData['SessionID'] = agent.session_id |
|---|
| 1136 |
|
|---|
| 1137 |
ObjectData = {} |
|---|
| 1138 |
ObjectData['ObjectLocalID'] = self.LocalID |
|---|
| 1139 |
|
|---|
| 1140 |
packet.ObjectDataBlocks.append(ObjectData) |
|---|
| 1141 |
|
|---|
| 1142 |
agent.region.enqueue_message(packet()) |
|---|
| 1143 |
|
|---|
| 1144 |
def deselect(self, agent): |
|---|
| 1145 |
""" deselect an object |
|---|
| 1146 |
|
|---|
| 1147 |
""" |
|---|
| 1148 |
|
|---|
| 1149 |
packet = ObjectDeselectPacket() |
|---|
| 1150 |
|
|---|
| 1151 |
# build the AgentData block |
|---|
| 1152 |
packet.AgentData['AgentID'] = agent.agent_id |
|---|
| 1153 |
packet.AgentData['SessionID'] = agent.session_id |
|---|
| 1154 |
|
|---|
| 1155 |
ObjectData = {} |
|---|
| 1156 |
ObjectData['ObjectLocalID'] = self.LocalID |
|---|
| 1157 |
|
|---|
| 1158 |
packet.ObjectDataBlocks.append(ObjectData) |
|---|
| 1159 |
|
|---|
| 1160 |
agent.region.enqueue_message(packet()) |
|---|
| 1161 |
|
|---|
| 1162 |
def _update_properties(self, properties): |
|---|
| 1163 |
""" takes a dictionary of attribute:value and makes it so """ |
|---|
| 1164 |
|
|---|
| 1165 |
for attribute in properties: |
|---|
| 1166 |
|
|---|
| 1167 |
setattr(self, attribute, properties[attribute]) |
|---|
| 1168 |
|
|---|
| 1169 |
""" |
|---|
| 1170 |
Contributors can be viewed at: |
|---|
| 1171 |
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt |
|---|
| 1172 |
|
|---|
| 1173 |
$LicenseInfo:firstyear=2008&license=apachev2$ |
|---|
| 1174 |
|
|---|
| 1175 |
Copyright 2009, Linden Research, Inc. |
|---|
| 1176 |
|
|---|
| 1177 |
Licensed under the Apache License, Version 2.0 (the "License"). |
|---|
| 1178 |
You may obtain a copy of the License at: |
|---|
| 1179 |
http://www.apache.org/licenses/LICENSE-2.0 |
|---|
| 1180 |
or in |
|---|
| 1181 |
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/LICENSE.txt |
|---|
| 1182 |
|
|---|
| 1183 |
$/LicenseInfo$ |
|---|
| 1184 |
""" |
|---|
| 1185 |
|
|---|