removing dependencies to packets.py from assets and appearance

This commit is contained in:
enus.linden
2009-07-20 23:34:00 +00:00
committed by Salad Dais
parent d8a0ac44cd
commit 55cf7be2ba
3 changed files with 363 additions and 153 deletions

View File

@@ -9,13 +9,15 @@ from eventlet import api
from pyogp.lib.base.datamanager import DataManager
# pyogp messaging
from pyogp.lib.base.message.message_handler import MessageHandler
from pyogp.lib.base.message.packets import *
from pyogp.lib.base.message.message import Message, Block
from pyogp.lib.base.utilities.helpers import Helpers
from pyogp.lib.base.exc import NotImplemented
from pyogp.lib.base.objects import Object
from pyogp.lib.base.params import VisualParams
from pyogp.lib.base.datatypes import *
from pyogp.lib.base.utilities.enums import BakedIndex, TextureIndex, WearableMap
from pyogp.lib.base.datatypes import UUID, Vector3
from pyogp.lib.base.utilities.enums import BakedIndex, TextureIndex, \
WearableMap, AssetType, WearablesIndex
# initialize logging
logger = getLogger('pyogp.lib.base.appearance')
@@ -40,13 +42,15 @@ class AppearanceManager(DataManager):
for i in range(TextureIndex.TEX_COUNT):
self.wearables.append(Wearable(i))
self.helpers = Helpers()
self.bakedTextures = [] #indexed by TextureIndex
self.bakedTextures = {} #indexed by TextureIndex
for i in range(BakedIndex.BAKED_COUNT):
self.bakedTextures.append(BakedTexture(i))
self.params = VisualParams().params
self.bakedTextures[i] = BakedTexture(i)
self.visualParams = VisualParams().params
self.visualParams[32].value = 1.0
self.TextureEntry = ""
self.Size = Vector3(X = 0.45, Y = 0.60, Z = 1.14 ) # Z which is Height needs to be calculated using params
self.requests = []
def enable_callbacks(self):
"""
enables the calback handlers for this AppearanceManager
@@ -62,25 +66,48 @@ class AppearanceManager(DataManager):
onAgentDataUpdate_received = self.agent.region.message_handler.register('AgentDataUpdate')
onAgentDataUpdate_received.subscribe(self.helpers.log_packet, self)
'''
def request_agent_wearables(self):
"""
Asks the simulator what the avatar is wearing
#TODO create a one--shot callback
"""
if self.agent.agent_id == None or self.agent.session_id == None or \
str(self.agent.agent_id) == str(UUID()) or \
str(self.agent.session_id) == str(UUID()):
log(WARNING, "Agent has either no agent_id or session_id, message not sent")
return
packet = AgentWearablesRequestPacket()
self.send_AgentWearablesRequest(self.agent.agent_id,
self.agent.session_id)
def wearableArrived(self, assetID, isSuccess):
"""
callback for wearables request
"""
packet.AgentData['AgentID'] = self.agent.agent_id
packet.AgentData['SessionID'] = self.agent.session_id
self.agent.region.enqueue_message(packet())
self.requests.remove(str(assetID))
if isSuccess:
asset = self.agent.asset_manager.get_asset(assetID)
#log(INFO, "wearable data\n, %s" % asset.data )
for paramID in asset.params.keys():
#log (INFO, 'Changing param %d from %f to %f' %(paramID,
# self.visualParams[paramID].value,
# asset.params[paramID]))
self.visualParams[paramID].value = asset.params[paramID]
if len(self.requests) == 0:
#log(INFO, "YAY!! Got all requested assets")
self.send_AgentCachedTexture(self.agent.agent_id,
self.agent.session_id,
self.bakedTextures,
self.wearables)
self.send_AgentIsNowWearing(self.agent.agent_id,
self.agent.session_id,
self.wearables)
def onAgentWearablesUpdate(self, packet):
"""
Automatically tells simulator avatar is wearing the wearables from
@@ -90,68 +117,22 @@ class AppearanceManager(DataManager):
Error Checking: make sure agent and session id are correct
make sure this method is only called once.
#TODO download wearables using assetIDs, upload wearables if wearing none
"""
self.verifyAgentData(packet)
#log(INFO, "Got AgentWearablesUpdate: %s" % packet)
for wearable in packet.blocks['WearableData']:
wearableType = wearable.get_variable('WearableType').data
itemID = wearable.get_variable('ItemID').data
assetID = wearable.get_variable('AssetID').data
self.wearables[wearableType].ItemID = itemID
self.wearables[wearableType].AssetID = assetID
self.send_AgentIsNowWearing()
self.send_AgentCachedTexture()
def send_AgentIsNowWearing(self):
"""
Tell the simulator that avatar is wearing initial items
"""
packet = AgentIsNowWearingPacket()
packet.AgentData['AgentID'] = self.agent.agent_id
packet.AgentData['SessionID'] = self.agent.session_id
for wearable in self.wearables:
WearableData = {}
WearableData['ItemID'] = wearable.ItemID
WearableData['WearableType'] = wearable.WearableType
packet.WearableDataBlocks.append(WearableData)
self.agent.region.enqueue_message(packet(), True)
def send_AgentSetAppearance(self):
"""
Informs simulator how avatar looks
"""
packet = AgentSetAppearancePacket()
#AgentData
packet.AgentData['AgentID'] = self.agent.agent_id
packet.AgentData['SessionID'] = self.agent.session_id
packet.AgentData['SerialNum'] = self.AgentSetSerialNum
packet.AgentData['Size'] = Vector3(X = 0.45, Y = 0.60, Z = 1.14) #Hard code? From Height in avatar_lad.xml
#WearableData
for bakedTexture in self.bakedTextures:
WearableData = {}
WearableData['CacheID'] = bakedTexture.TextureID
WearableData['TextureIndex'] = bakedTexture.bakedIndex
packet.WearableDataBlocks.append(WearableData)
#self.verifyAgentData(packet)
log(INFO, "Got AgentWearablesUpdate: %s" % packet)
for wearableData in packet.blocks['WearableData']:
wearableType = wearableData.get_variable('WearableType').data
itemID = wearableData.get_variable('ItemID').data
assetID = wearableData.get_variable('AssetID').data
wearable = self.wearables[wearableType]
wearable.ItemID = itemID
wearable.AssetID = assetID
if str(assetID) != '00000000-0000-0000-0000-000000000000':
self.agent.asset_manager.request_asset(assetID, wearable.getAssetType(),
True, self.wearableArrived)
self.requests.append(str(assetID))
#ObjectData
packet.ObjectData['TextureEntry'] = self.TextureEntry
#VisualParam
paramkeys = self.params.keys()
paramkeys.sort() #since param id is not sent the parameters should be in sorted order
for paramkey in paramkeys:
if self.params[paramkey].group == 0:
paramBlock = {}
paramBlock['ParamValue'] = self.params[paramkey].floatToByte()
packet.VisualParamBlocks.append(paramBlock)
self.agent.region.enqueue_message(packet())
self.AgentSetSerialNum += 1
def onAvatarTextureUpdate(self, packet):
raise NotImplemented("onAvatarTextureUpdate")
@@ -160,39 +141,7 @@ class AppearanceManager(DataManager):
Informs viewer how other avatars look
"""
raise NotImplemented("onAvatarAppearance")
def send_AgentCachedTexture(self):
"""
Ask the simulator what baked textures it has cached.
TODO Create a one-shot callback?
"""
#AgentData
packet = AgentCachedTexturePacket()
packet.AgentData['AgentID'] = self.agent.agent_id
packet.AgentData['SessionID'] = self.agent.session_id
packet.AgentData['SerialNum'] = self.AgentCachedSerialNum
#WearableData
for i in range(BakedIndex.BAKED_COUNT):
wearableData = {}
wearableData['ID'] = self.get_hash(i)
wearableData['TextureIndex'] = i
packet.WearableDataBlocks.append(wearableData)
self.agent.region.enqueue_message(packet(), True)
self.AgentCachedSerialNum += 1
def get_hash(self, bakedIndex):
"""
Creates a hash using the assetIDs for each wearable in a baked layer
"""
wearable_map = WearableMap().map
hash = UUID()
for wearable_index in wearable_map[bakedIndex]:
hash ^= self.wearables[wearable_index].AssetID
if str(hash) != '00000000-0000-0000-0000-000000000000':
hash ^= self.bakedTextures[bakedIndex].Hash
return hash
def onAgentCachedTextureResponse(self, packet):
"""
Update the bakedTextures with their TextureIDs and HostNames and call
@@ -203,7 +152,12 @@ class AppearanceManager(DataManager):
bakedIndex = bakedTexture.get_variable('TextureIndex').data
self.bakedTextures[bakedIndex].TextureID = bakedTexture.get_variable('TextureID').data
self.bakedTextures[bakedIndex].HostName = bakedTexture.get_variable('HostName').data
self.send_AgentSetAppearance()
self.send_AgentSetAppearance(self.agent.agent_id,
self.agent.session_id,
self.Size,
self.bakedTextures,
self.TextureEntry,
self.visualParams)
def verifyAgentData(self, packet):
"""
@@ -213,8 +167,92 @@ class AppearanceManager(DataManager):
pSessionID = packet.blocks['AgentData'][0].get_variable("SessionID").data
if str(pAgentID) != str(self.agent.agent_id):
log(WARNING, "%s packet does not have an AgentID", packet.name)
if str(pSessionID) != str(self.agent.session_id):
log(WARNING, "%s packet does not have a SessionID" % packet.name)
def send_AgentWearablesRequest(self, AgentID, SessionID):
"""
sends and AgentWearablesRequest message.
"""
packet = Message('AgentWearablesRequest',
Block('AgentData',
AgentID = AgentID,
SessionID = SessionID))
self.agent.region.enqueue_message(packet)
def send_AgentIsNowWearing(self, AgentID, SessionID, wearables):
"""
Tell the simulator that avatar is wearing initial items
"""
args = [Block('AgentData',
AgentID = AgentID,
SessionID = SessionID)]
args += [Block('WearableData',
ItemID = wearable.ItemID,
WearableType = wearable.WearableType) \
for wearable in wearables]
packet = Message('AgentIsNowWearing', *args)
self.agent.region.enqueue_message(packet, True)
def send_AgentCachedTexture(self, AgentID, SessionID, bakedTextures,
wearables):
"""
Ask the simulator what baked textures it has cached.
TODO Create a one-shot callback?
"""
args = [Block('AgentData',
AgentID = AgentID,
SessionID = SessionID,
SerialNum = self.AgentCachedSerialNum)]
args += [Block('WearableData',
ID = bakedTextures[i].get_hash(wearables),
TextureIndex = i) \
for i in range(BakedIndex.BAKED_COUNT)]
packet = Message('AgentCachedTexture', *args)
self.AgentCachedSerialNum += 1
self.agent.region.enqueue_message(packet, True)
def send_AgentSetAppearance(self, AgentID, SessionID, Size, bakedTextures,
TextureEntry, visualParams):
"""
Informs simulator how avatar looks
"""
args = [Block('AgentData',
AgentID = AgentID,
SessionID = SessionID,
SerialNum = self.AgentSetSerialNum,
Size = Size)]
args += [Block('WearableData',
CacheID = bakedTextures[i].TextureID,
TextureIndex = bakedTextures[i].bakedIndex) \
for i in range(BakedIndex.BAKED_COUNT)]
args += [Block('ObjectData',
TextureEntry = TextureEntry)]
paramkeys = visualParams.keys()
paramkeys.sort()
args += [Block('VisualParam',
ParamValue = visualParams[key].floatToByte()) \
for key in paramkeys]
packet = Message('AgentSetAppearance', *args)
self.AgentSetSerialNum += 1
self.agent.region.enqueue_message(packet)
class Wearable(object):
"""
Represents 1 of the 13 wearables an avatar can wear
@@ -224,6 +262,25 @@ class Wearable(object):
self.ItemID = ItemID
self.AssetID = AssetID
def getAssetType(self):
if self.WearableType == WearablesIndex.WT_SHAPE or \
self.WearableType == WearablesIndex.WT_SKIN or \
self.WearableType == WearablesIndex.WT_HAIR or \
self.WearableType == WearablesIndex.WT_EYES:
return AssetType.BodyPart
elif self.WearableType == WearablesIndex.WT_SHIRT or \
self.WearableType == WearablesIndex.WT_PANTS or \
self.WearableType == WearablesIndex.WT_SHOES or \
self.WearableType == WearablesIndex.WT_SOCKS or \
self.WearableType == WearablesIndex.WT_JACKET or \
self.WearableType == WearablesIndex.WT_GLOVES or \
self.WearableType == WearablesIndex.WT_UNDERSHIRT or \
self.WearableType == WearablesIndex.WT_UNDERPANTS or \
self.WearableType == WearablesIndex.WT_SKIRT:
return AssetType.Clothing
else:
return AssetType.NONE
class BakedTexture(object):
"""
@@ -235,19 +292,31 @@ class BakedTexture(object):
self.HostName = None
if bakedIndex == BakedIndex.BAKED_HEAD:
self.Hash = UUID("18ded8d6-bcfc-e415-8539-944c0f5ea7a6")
self.secret_hash = UUID("18ded8d6-bcfc-e415-8539-944c0f5ea7a6")
elif bakedIndex == BakedIndex.BAKED_UPPER:
self.Hash = UUID("338c29e3-3024-4dbb-998d-7c04cf4fa88f")
self.secret_hash = UUID("338c29e3-3024-4dbb-998d-7c04cf4fa88f")
elif bakedIndex == BakedIndex.BAKED_LOWER:
self.Hash = UUID("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f")
self.secret_hash = UUID("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f")
elif bakedIndex == BakedIndex.BAKED_EYES:
self.Hash = UUID("b2cf28af-b840-1071-3c6a-78085d8128b5")
self.secret_hash = UUID("b2cf28af-b840-1071-3c6a-78085d8128b5")
elif bakedIndex == BakedIndex.BAKED_SKIRT:
self.Hash = UUID("ea800387-ea1a-14e0-56cb-24f2022f969a")
self.secret_hash = UUID("ea800387-ea1a-14e0-56cb-24f2022f969a")
elif bakedIndex == BakedIndex.BAKED_HAIR:
self.Hash = UUID("0af1ef7c-ad24-11dd-8790-001f5bf833e8")
self.secret_hash = UUID("0af1ef7c-ad24-11dd-8790-001f5bf833e8")
else:
self.Hash = UUID()
self.secret_hash = UUID()
def get_hash(self, wearables):
"""
Creates a hash using the assetIDs for each wearable in a baked layer
"""
wearable_map = WearableMap().map
hash = UUID()
for wearable_index in wearable_map[self.bakedIndex]:
hash ^= wearables[wearable_index].AssetID
if str(hash) != '00000000-0000-0000-0000-000000000000':
hash ^= self.secret_hash
return hash
class AvatarTexture(object):
"""

View File

@@ -7,13 +7,16 @@ from eventlet import api
# pyogp
from pyogp.lib.base.datamanager import DataManager
from pyogp.lib.base.utilities.enums import TransferChannelType, TransferSourceType, \
TransferTargetType, TransferStatus
# pyogp messaging
from pyogp.lib.base.message.message_handler import MessageHandler
from pyogp.lib.base.message.packets import *
from pyogp.lib.base.message.message import Message, Block
from pyogp.lib.base.utilities.helpers import Helpers
from pyogp.lib.base.exc import NotImplemented
from pyogp.lib.base.objects import Object
from pyogp.lib.base.datatypes import *
from pyogp.lib.base.datatypes import Vector3
# initialize logging
@@ -25,59 +28,142 @@ class AssetManager(DataManager):
The AssetManager class handles the assets of an Agent() instance
Sample implementations:
Tests:
Tests: test_assets.py
"""
def __init__(self, agent, settings = None):
super(AssetManager, self).__init__(agent, settings)
self.requests = [] # queue of requests?
self.assets = {} # indexed by assetID?
#indexed by assetID
self.assets = {}
def enable_callbacks(self):
self.agent.region.message_handler.register('TransferInfo').subscribe(self.onTransferInfo)
self.agent.region.message_handler.register('TransferPacket').subscribe(self.onTransferPacket)
pass
def request_asset(self, assetID, assetType, isPriority):
self.requests.append(Asset(assetID, assetType, isPriority))
packet = TransferRequestPacket()
#TransferInfo
def request_asset(self, assetID, assetType, isPriority, callback):
"""
Sends a TransferRequest to the sim for asset assetID with type assetType,
will call back with the assetID and True with asset received or False
if request failed. On successful request the asset is store in
self.assets
"""
transferID = UUID() #associate the assetID with the transferID
transferID.random()
packet.TransferInfo['TransferID'] = transferID
packet.TransferInfo['ChannelType'] = 2
packet.TransferInfo['SourceType'] = 2
transferInfoHandler = self.agent.region.message_handler.register('TransferInfo')
transferPacketHandler = self.agent.region.message_handler.register('TransferPacket')
def onTransferPacket(packet):
"""
TransferPacket of a successful TransferRequest
"""
# fill in data for Asset in the requests queue and pop it off and story in assets dict
if str(transferID) == str(packet.blocks['TransferData'][0].get_variable('TransferID').data):
self.assets[str(assetID)] = AssetWearable(assetID, assetType,
packet.blocks['TransferData'][0].get_variable('Data').data)
callback(assetID, True)
transferPacketHandler.unsubscribe(onTransferPacket)
def onTransferInfo(packet):
"""
Status of TransferRequest
Account for size and multiple packets
"""
if str(transferID) == str(packet.blocks['TransferInfo'][0].get_variable('TransferID')):
status = packet.blocks['TransferInfo'][0].get_variable("Status").data
if status != TransferStatus.OK:
log(WARNING, "Request for asset %s failed with status %s" \
% (assetID, status))
callback(assetID, False)
transferPacketHandler.unsubscribe(onTransferPacket)
transferInfoHandler.unsubscribe(onTransferInfo)
transferInfoHandler.subscribe(onTransferInfo)
transferPacketHandler.subscribe(onTransferPacket)
if isPriority:
packet.TransferInfo['Priority'] = 1.0
priority = 1.0
else:
packet.TransferInfo['Priority'] = 0.0
packet.TransferInfo['Params'] = assetID.get_bytes() \
+ Helpers().int_to_bytes(5) #FIXME <-assetID & type endianness of type may not be correct
self.agent.region.enqueue_message(packet())
return transferID
priortity = 0.0
params = assetID.get_bytes() \
+ Helpers().int_to_bytes(assetType)
self.send_TransferRequest(transferID,
TransferChannelType.Asset,
TransferSourceType.Asset,
priority,
params)
def onTransferInfo(self, packet):
log(INFO, "TransferInfo received %s" % packet)
#raise NotImplemented("onTranferInfo")
def onTransferPacket(self, packet):
# fill in data for Asset in the requests queue and pop it off and story in assets dict
log(INFO, "TransferPacket received %s" % packet)
#raise NotImplemented("onTransferPacket")
def get_asset(self, xxxID):
raise NotImplemented("get_asset")
def pending_downloads(self):
if len(self.requests) > 0:
return True
return False
def get_asset(self, assetID):
return self.assets[str(assetID)]
def send_TransferRequest(self, TransferID, ChannelType, SourceType,
Priority, Params):
"""
sends a TransferRequest packet to request an asset to download, the
assetID and assetType of the request are stored in the Params variable
see assets.request_asset for example.
"""
packet = Message('TransferRequest',
Block('TransferInfo',
TransferID = TransferID,
ChannelType = ChannelType,
SourceType = SourceType,
Priority = Priority,
Params = Params))
self.agent.region.enqueue_message(packet)
class Asset(object):
def __init__(self, assetID, assetType, isPriority):
def __init__(self, assetID, assetType, data):
self.assetID = assetID
self.assetType = assetID
self.isPriority = isPriority
self.data = None
self.assetType = assetType
self.data = data
class AssetWearable(Asset):
def __init__(self, assetID, assetType, data):
super(AssetWearable, self).__init__(assetID, assetType, data)
self.Version = -1
self.Name = ''
self.Description = ''
self.Type = -1
self.Permissions = ''
self.SaleInfo = ''
self.params = {}
self.textures = {}
self.parse_data()
def parse_data(self):
tokens = self.data.split()
i = iter(tokens)
while True:
try:
token = i.next()
if token.lower() == 'version':
self.Version = int(i.next())
if token.lower() == 'type':
self.Type = int(i.next())
if token.lower() == 'parameters':
count = int(i.next())
while count > 0:
paramID = int(i.next())
self.params[paramID] = float(i.next())
count -= 1
if token.lower() == 'textures':
count = int(i.next())
while count > 0:
textureID = int(i.next())
self.textures[textureID] = UUID(i.next())
count -= 1
except StopIteration:
break
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt

View File

@@ -384,6 +384,61 @@ class WearableMap(object):
self.map[BakedIndex.BAKED_SKIRT] = [WearablesIndex.WT_SKIRT]
self.map[BakedIndex.BAKED_HAIR] = [WearablesIndex.WT_HAIR]
class AssetType(object):
Texture = 0
Sound = 1
CallingCard = 2
Landmark = 3
Script = 4
Clothing = 5
Object = 6
NoteCard = 7
Category = 8
RootCategory = 9
LSLText = 10
LSLByteCode = 11
TextureTGA = 12
BodyPart = 13
Trash = 14
SnapshotCategory = 15
LostAndFound = 16
SoundWav = 17
ImageTGA = 18
ImageJPEG = 19
Animation = 20
Gesture = 21
Simstate = 22
Count = 23
NONE = -1
class TransferChannelType(object):
Unknown = 0
Misc = 1
Asset = 2
NumTypes = 3
class TransferSourceType(object):
Unknown = 0
File = 1
Asset = 2
SimInvItem = 3
SimEstate = 4
NumTypes = 5
class TransferTargetType(object):
Unknown = 0
File = 1
VFile = 2
class TransferStatus(object):
OK = 0
Done = 1
Skip = 2
Abort = 3
Error = -1
UnknownSource = -2
InsufficientPermissions = -3
"""
Contributors can be viewed at: