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

Revision 2487, 10.7 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
5 #related
6 from eventlet import api
7
8 # pyogp
9 from pyogp.lib.base.datamanager import DataManager
10 # pyogp messaging
11 from pyogp.lib.base.message.message_handler import MessageHandler
12 from pyogp.lib.base.message.packets import *
13 from pyogp.lib.base.utilities.helpers import Helpers
14 from pyogp.lib.base.exc import NotImplemented
15 from pyogp.lib.base.objects import Object
16 from pyogp.lib.base.params import VisualParams
17 from pyogp.lib.base.datatypes import *
18 from pyogp.lib.base.utilities.enums import BakedIndex, TextureIndex, WearableMap
19
20 # initialize logging
21 logger = getLogger('pyogp.lib.base.appearance')
22 log = logger.log
23
24 class AppearanceManager(DataManager):
25     """The AppearanceManager class handles appearance of an Agent() instance
26
27     Sample implementations:
28     Tests:
29     """
30
31     def __init__(self, settings = None, agent = None):
32         """
33         initialize the appearance manager
34         TODO Fix the Z by generating actual height
35         """
36         super(AppearanceManager, self).__init__(settings, agent)
37         self.AgentSetSerialNum = 1
38         self.AgentCachedSerialNum = 1
39         self.wearables = [] #indexed by WearableType
40         for i in range(TextureIndex.TEX_COUNT):
41             self.wearables.append(Wearable(i))
42         self.helpers = Helpers()
43         self.bakedTextures = [] #indexed by TextureIndex
44         for i in range(BakedIndex.BAKED_COUNT):
45             self.bakedTextures.append(BakedTexture(i))
46         self.params = VisualParams().params
47         self.TextureEntry = ""
48         self.Size = Vector3(X = 0.45, Y = 0.60, Z = 1.14 ) # Z which is Height needs to be calculated using params
49        
50     def enable_callbacks(self):
51         """
52         enables the calback handlers for this AppearanceManager
53         """
54         onAgentWearablesUpdate_received = self.agent.region.message_handler.register('AgentWearablesUpdate')
55         onAgentWearablesUpdate_received.subscribe(self.onAgentWearablesUpdate)
56         onAgentCachedTextureResponse_received = self.agent.region.message_handler.register('AgentCachedTextureResponse')
57         onAgentCachedTextureResponse_received.subscribe(self.onAgentCachedTextureResponse)
58         #onAvatarAppearance_received = self.agent.region.message_handler.register('AvatarAppearance')
59         #onAvatarAppearance_received.subscribe(self.onAvatarAppearance)
60         self.request_agent_wearables()
61         '''
62         onAgentDataUpdate_received = self.agent.region.message_handler.register('AgentDataUpdate')
63         onAgentDataUpdate_received.subscribe(self.helpers.log_packet, self)
64         '''
65    
66
67     def request_agent_wearables(self):
68         """
69         Asks the simulator what the avatar is wearing
70         """
71         if self.agent.agent_id == None or self.agent.session_id == None or \
72               str(self.agent.agent_id) == str(UUID()) or \
73               str(self.agent.session_id) == str(UUID()):
74            log(WARNING, "Agent has either no agent_id or session_id, message not sent")
75            return
76        
77         packet = AgentWearablesRequestPacket()
78        
79         packet.AgentData['AgentID'] = self.agent.agent_id
80         packet.AgentData['SessionID'] = self.agent.session_id
81
82         self.agent.region.enqueue_message(packet())
83
84     def onAgentWearablesUpdate(self, packet):
85         """
86         Automatically tells simulator avatar is wearing the wearables from
87         the AgentWearables update packet.
88         This message should only be received once.
89        
90         Error Checking: make sure agent and session id are correct
91         make sure this method is only called once.
92
93         #TODO download wearables using assetIDs, upload wearables if wearing none
94         """
95        
96         self.verifyAgentData(packet)
97         #log(INFO, "Got AgentWearablesUpdate: %s" % packet)
98         for wearable in packet.blocks['WearableData']:
99             wearableType = wearable.get_variable('WearableType').data
100             itemID = wearable.get_variable('ItemID').data
101             assetID = wearable.get_variable('AssetID').data
102             self.wearables[wearableType].ItemID = itemID
103             self.wearables[wearableType].AssetID = assetID
104         self.send_AgentIsNowWearing()
105         self.send_AgentCachedTexture()
106                
107                
108     def send_AgentIsNowWearing(self):
109         """
110         Tell the simulator that avatar is wearing initial items
111         """
112         packet = AgentIsNowWearingPacket()
113
114         packet.AgentData['AgentID'] = self.agent.agent_id
115         packet.AgentData['SessionID'] = self.agent.session_id
116         for wearable in self.wearables:
117             WearableData = {}
118             WearableData['ItemID'] = wearable.ItemID
119             WearableData['WearableType'] = wearable.WearableType
120             packet.WearableDataBlocks.append(WearableData)
121         self.agent.region.enqueue_message(packet(), True)
122    
123     def send_AgentSetAppearance(self):
124         """
125         Informs simulator how avatar looks
126         """
127         packet = AgentSetAppearancePacket()
128         #AgentData
129         packet.AgentData['AgentID'] = self.agent.agent_id
130         packet.AgentData['SessionID'] = self.agent.session_id
131         packet.AgentData['SerialNum'] = self.AgentSetSerialNum
132         packet.AgentData['Size'] = Vector3(X = 0.45, Y = 0.60, Z = 1.14) #Hard code? From Height in avatar_lad.xml
133
134         #WearableData
135         for bakedTexture in self.bakedTextures:
136             WearableData = {}
137             WearableData['CacheID'] = bakedTexture.TextureID
138             WearableData['TextureIndex'] = bakedTexture.bakedIndex
139             packet.WearableDataBlocks.append(WearableData)
140        
141         #ObjectData
142         packet.ObjectData['TextureEntry'] = self.TextureEntry
143
144         #VisualParam
145         paramkeys = self.params.keys()
146         paramkeys.sort() #since param id is not sent the parameters should be in sorted order
147         for paramkey in paramkeys:
148             if self.params[paramkey].group == 0:
149                 paramBlock = {}
150                 paramBlock['ParamValue'] = self.params[paramkey].floatToByte()
151                 packet.VisualParamBlocks.append(paramBlock)
152         self.agent.region.enqueue_message(packet())
153         self.AgentSetSerialNum += 1
154    
155     def onAvatarTextureUpdate(self, packet):
156         raise NotImplemented("onAvatarTextureUpdate")
157
158     def onAvatarAppearance(self, packet):
159         """
160         Informs viewer how other avatars look
161         """
162         raise NotImplemented("onAvatarAppearance")
163    
164     def send_AgentCachedTexture(self):
165         """
166         Ask the simulator what baked textures it has cached.
167         TODO Create a one-shot callback?
168         """
169         #AgentData
170         packet = AgentCachedTexturePacket()
171         packet.AgentData['AgentID'] = self.agent.agent_id
172         packet.AgentData['SessionID'] = self.agent.session_id
173         packet.AgentData['SerialNum'] = self.AgentCachedSerialNum
174
175         #WearableData
176         for i in range(BakedIndex.BAKED_COUNT):
177             wearableData = {}
178             wearableData['ID'] = self.get_hash(i)
179             wearableData['TextureIndex'] = i
180             packet.WearableDataBlocks.append(wearableData)
181         self.agent.region.enqueue_message(packet(), True)
182         self.AgentCachedSerialNum += 1
183
184     def get_hash(self, bakedIndex):
185         """
186         Creates a hash using the assetIDs for each wearable in a baked layer
187         """
188         wearable_map = WearableMap().map
189         hash = UUID()
190         for wearable_index in wearable_map[bakedIndex]:
191             hash ^= self.wearables[wearable_index].AssetID
192         if str(hash) != '00000000-0000-0000-0000-000000000000':
193             hash ^= self.bakedTextures[bakedIndex].Hash
194         return hash
195        
196     def onAgentCachedTextureResponse(self, packet):
197         """
198         Update the bakedTextures with their TextureIDs and HostNames and call
199         send_AgentSetAppearance
200         """
201         #log(INFO, "AgentCachedTextureRespose received: %s" % packet)
202         for bakedTexture in packet.blocks['WearableData']:
203             bakedIndex = bakedTexture.get_variable('TextureIndex').data
204             self.bakedTextures[bakedIndex].TextureID = bakedTexture.get_variable('TextureID').data
205             self.bakedTextures[bakedIndex].HostName = bakedTexture.get_variable('HostName').data
206         self.send_AgentSetAppearance()
207
208     def verifyAgentData(self, packet):
209         """
210         verifies that packet refers to this agent
211         """
212         pAgentID = packet.blocks['AgentData'][0].get_variable("AgentID").data
213         pSessionID = packet.blocks['AgentData'][0].get_variable("SessionID").data
214         if  str(pAgentID) != str(self.agent.agent_id):
215             log(WARNING, "%s packet does not have an AgentID", packet.name)
216         if str(pSessionID) != str(self.agent.session_id):
217             log(WARNING, "%s packet does not have a SessionID" % packet.name)
218        
219 class Wearable(object):
220     """
221     Represents 1 of the 13 wearables an avatar can wear
222     """
223     def __init__(self, WearableType = None, ItemID = UUID(), AssetID = UUID()):
224         self.WearableType = WearableType
225         self.ItemID = ItemID
226         self.AssetID = AssetID
227
228
229 class BakedTexture(object):
230     """
231     Represents 1 of the 6 baked textures of an avatar
232     """
233     def __init__(self, bakedIndex, TextureID = UUID()):
234         self.bakedIndex = bakedIndex
235         self.TextureID = TextureID
236         self.HostName = None
237            
238         if bakedIndex == BakedIndex.BAKED_HEAD:
239             self.Hash = UUID("18ded8d6-bcfc-e415-8539-944c0f5ea7a6")
240         elif bakedIndex == BakedIndex.BAKED_UPPER:
241             self.Hash = UUID("338c29e3-3024-4dbb-998d-7c04cf4fa88f")
242         elif bakedIndex == BakedIndex.BAKED_LOWER:
243             self.Hash = UUID("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f")
244         elif bakedIndex == BakedIndex.BAKED_EYES:
245             self.Hash = UUID("b2cf28af-b840-1071-3c6a-78085d8128b5")
246         elif bakedIndex == BakedIndex.BAKED_SKIRT:
247             self.Hash = UUID("ea800387-ea1a-14e0-56cb-24f2022f969a")
248         elif bakedIndex == BakedIndex.BAKED_HAIR:
249             self.Hash = UUID("0af1ef7c-ad24-11dd-8790-001f5bf833e8")
250         else:
251             self.Hash = UUID()
252    
253 class AvatarTexture(object):
254     """
255     Represents 1 of the 21 baked and not baked textures of an avatar.
256     """
257     def __init__(self, TextureIndex, TextureID = None):
258         self.TextureIndex = TextureIndex
259         self.TextureID = TextureID
260
261
262
263 """
264 Contributors can be viewed at:
265 http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt
266
267 $LicenseInfo:firstyear=2008&license=apachev2$
268
269 Copyright 2009, Linden Research, Inc.
270
271 Licensed under the Apache License, Version 2.0 (the "License").
272 You may obtain a copy of the License at:
273     http://www.apache.org/licenses/LICENSE-2.0
274 or in
275     http://svn.secondlife.com/svn/linden/projects/2008/pyogp/LICENSE.txt
276
277 $/LicenseInfo$
278 """
279
Note: See TracBrowser for help on using the browser.