root/projects/2008/pyogp/pyogp.lib.base/branches/kotler_tests/pyogp/lib/base/objects.py

Revision 2487, 52.1 kB (checked in by kotler.linden, 5 months ago)

asset manager updates

Line 
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:
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
Note: See TracBrowser for help on using the browser.