Merge from asset_upload 2550:2592
This commit is contained in:
committed by
Salad Dais
parent
953f4ef900
commit
b3db3a8f47
@@ -14,7 +14,7 @@ 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.visualparams import VisualParams
|
||||
from pyogp.lib.base.datatypes import UUID, Vector3
|
||||
from pyogp.lib.base.utilities.enums import BakedIndex, TextureIndex, \
|
||||
WearableMap, AssetType, WearablesIndex
|
||||
|
||||
@@ -14,9 +14,10 @@ from pyogp.lib.base.utilities.enums import TransferChannelType, TransferSourceTy
|
||||
from pyogp.lib.base.message.message_handler import MessageHandler
|
||||
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.exc import NotImplemented, ResourceError, ResourceNotFound
|
||||
from pyogp.lib.base.objects import Object
|
||||
from pyogp.lib.base.datatypes import Vector3, UUID
|
||||
from pyogp.lib.base.caps import Capability
|
||||
|
||||
|
||||
# initialize logging
|
||||
@@ -35,12 +36,12 @@ class AssetManager(DataManager):
|
||||
super(AssetManager, self).__init__(agent, settings)
|
||||
#indexed by assetID
|
||||
self.assets = {}
|
||||
|
||||
|
||||
def enable_callbacks(self):
|
||||
pass
|
||||
|
||||
|
||||
def request_asset(self, assetID, assetType, isPriority, callback):
|
||||
def request_asset(self, assetID, assetType, isPriority, callback=None, itemID=None):
|
||||
"""
|
||||
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
|
||||
@@ -55,26 +56,31 @@ class AssetManager(DataManager):
|
||||
def onTransferPacket(packet):
|
||||
"""
|
||||
TransferPacket of a successful TransferRequest
|
||||
TODO wait for all all packets to arrive and assemble the data
|
||||
"""
|
||||
# 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)
|
||||
if callback != None:
|
||||
callback(assetID, True)
|
||||
transferPacketHandler.unsubscribe(onTransferPacket)
|
||||
|
||||
def onTransferInfo(packet):
|
||||
"""
|
||||
Status of TransferRequest
|
||||
Account for size and multiple packets
|
||||
TODO set packet count
|
||||
"""
|
||||
|
||||
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)
|
||||
if callback != None:
|
||||
callback(assetID, False)
|
||||
transferPacketHandler.unsubscribe(onTransferPacket)
|
||||
transferInfoHandler.unsubscribe(onTransferInfo)
|
||||
|
||||
@@ -85,8 +91,17 @@ class AssetManager(DataManager):
|
||||
priority = 1.0
|
||||
else:
|
||||
priortity = 0.0
|
||||
params = assetID.get_bytes() \
|
||||
+ Helpers().int_to_bytes(assetType)
|
||||
|
||||
params = ''
|
||||
if itemID != None:
|
||||
params += self.agent.agent_id.get_bytes() + \
|
||||
self.agent.session_id.get_bytes() + \
|
||||
self.agent.agent_id.get_bytes() + \
|
||||
UUID().get_bytes() + \
|
||||
itemID.get_bytes()
|
||||
|
||||
params += assetID.get_bytes() + \
|
||||
Helpers().int_to_bytes(assetType)
|
||||
|
||||
self.send_TransferRequest(transferID,
|
||||
TransferChannelType.Asset,
|
||||
@@ -94,11 +109,71 @@ class AssetManager(DataManager):
|
||||
priority,
|
||||
params)
|
||||
|
||||
|
||||
"""
|
||||
def upload_asset(self, transaction_id, type_, tempfile, store_local,
|
||||
asset_data=None):
|
||||
|
||||
assetUploadCompleteHandler = self.agent.region.message_handler.register('AssetUploadComplete')
|
||||
def onAssetUploadComplete(packet):
|
||||
log(INFO, "AssetUploadComplete: %s" % packet)
|
||||
|
||||
assetUploadCompleteHandler.subscribe(onAssetUploadComplete)
|
||||
|
||||
self.send_AssetUploadRequest(transaction_id, type_, tempfile,
|
||||
store_local)
|
||||
"""
|
||||
def upload_script_via_caps(self, item_id, script):
|
||||
|
||||
def upload_script_via_caps_responder(response):
|
||||
|
||||
if response['state'] == 'upload':
|
||||
cap = Capability('UpdateScriptAgentResponse', response['uploader'])
|
||||
response = cap.POST_FILE(script)
|
||||
upload_script_via_caps_responder(response)
|
||||
elif response['state'] == 'complete':
|
||||
log(DEBUG, "Upload of script Successful")
|
||||
else:
|
||||
log(WARNING, "Upload failed")
|
||||
|
||||
cap = self.agent.region.capabilities['UpdateScriptAgent']
|
||||
post_body = {'item_id' : str(item_id), 'target': 'lsl2'}
|
||||
custom_headers = {'Accept' : 'application/llsd+xml'}
|
||||
|
||||
try:
|
||||
response = cap.POST(post_body, custom_headers)
|
||||
except ResourceError, error:
|
||||
log(ERROR, error)
|
||||
return
|
||||
except ResourceNotFound, error:
|
||||
log(ERROR, "404 calling: %s" % (error))
|
||||
return
|
||||
upload_script_via_caps_responder(response)
|
||||
|
||||
|
||||
|
||||
|
||||
def upload_via_udp(self):
|
||||
pass
|
||||
|
||||
def get_asset(self, assetID):
|
||||
|
||||
return self.assets[str(assetID)]
|
||||
|
||||
def send_AssetUploadRequest(self, TransactionID, Type, Tempfile, \
|
||||
StoreLocal, AssetData=None):
|
||||
"""
|
||||
Sends an AssetUploadRequest packet to request that an asset be
|
||||
uploaded to the to the sim
|
||||
"""
|
||||
packet = Message('AssetUploadRequest',
|
||||
Block('AssetBlock',
|
||||
TransactionID = TransactionID,
|
||||
Type = Type,
|
||||
Tempfile = Tempfile,
|
||||
StoreLocal = StoreLocal,
|
||||
AssetData = AssetData))
|
||||
self.agent.region.enqueue_message(packet)
|
||||
|
||||
|
||||
def send_TransferRequest(self, TransferID, ChannelType, SourceType,
|
||||
Priority, Params):
|
||||
@@ -118,8 +193,6 @@ class AssetManager(DataManager):
|
||||
|
||||
self.agent.region.enqueue_message(packet)
|
||||
|
||||
|
||||
|
||||
class Asset(object):
|
||||
def __init__(self, assetID, assetType, data):
|
||||
self.assetID = assetID
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import urllib2
|
||||
from types import *
|
||||
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
|
||||
|
||||
import re
|
||||
# related
|
||||
|
||||
# pyogp
|
||||
@@ -107,15 +107,42 @@ class Capability(object):
|
||||
else:
|
||||
raise ResourceError(self.public_url, e.code, e.msg, e.fp.read(), method="POST")
|
||||
|
||||
return self._response_handler(response)
|
||||
|
||||
def POST_FILE(self, file_name, custom_headers={}):
|
||||
""" Opens file at file_name and posts contents to this cap. """
|
||||
headers = {"Content-type" : "application/octet-stream"}
|
||||
fd = open(file_name)
|
||||
payload = fd.read()
|
||||
fd.close
|
||||
|
||||
try:
|
||||
response = self.restclient.POST(self.public_url,
|
||||
payload, headers=headers)
|
||||
except HTTPError, e:
|
||||
if e.code==404:
|
||||
raise ResourceNotFound(self.public_url)
|
||||
else:
|
||||
raise ResourceError(self.public_url, e.code, e.msg,
|
||||
e.fp.read(), method="POST")
|
||||
|
||||
return self._response_handler(response)
|
||||
|
||||
def _response_handler(self, response):
|
||||
# now deserialize the data again, we ask for a utility with the content type
|
||||
# as the name
|
||||
content_type_charset = response.headers['Content-Type']
|
||||
content_type = content_type_charset.split(";")[0] # remove the charset part
|
||||
|
||||
pattern = re.compile('<\?xml\sversion="1.0"\s\?><llsd>.*?</llsd>')
|
||||
# ToDo: write a generic serializer/deserializer
|
||||
if (content_type == 'application/llsd+xml') or (content_type == 'application/xml'):
|
||||
if (content_type == 'application/llsd+xml') or \
|
||||
(content_type == 'application/xml') or \
|
||||
(content_type == 'text/html' and \
|
||||
pattern.match(response.body) != None):
|
||||
deserializer = LLSDDeserializer()
|
||||
else:
|
||||
print response
|
||||
raise DeserializerNotFound(content_type)
|
||||
|
||||
data = deserializer.deserialize(response.body)
|
||||
@@ -125,6 +152,7 @@ class Capability(object):
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "<Capability '%s' for %s>" %(self.name, self.public_url)
|
||||
|
||||
|
||||
@@ -182,16 +182,17 @@ class InventoryManager(DataManager):
|
||||
container[index[0]].inventory[inventory_index[0]] = inventory_item
|
||||
|
||||
if self.settings.LOG_VERBOSE:
|
||||
log(DEBUG, 'Replacing a stored inventory item: %s for agent \'%s\'' % (inventory_item.ItemID, self.agent.agent_id))
|
||||
log(DEBUG, 'Replacing a stored inventory item: %s' % (inventory_item.ItemID))
|
||||
|
||||
except:
|
||||
|
||||
container[index[0]].inventory.append(inventory_item)
|
||||
|
||||
if self.settings.LOG_VERBOSE:
|
||||
log(DEBUG, 'Storing a new inventory item: %s in agent \'%s\'' % (inventory_item.ItemID, self.agent.agent_id))
|
||||
log(DEBUG, 'Storing a new inventory item: %s ' % (inventory_item.ItemID))
|
||||
|
||||
def search_inventory(self, folder_list = [], item_id = None, name = None, match_list = []):
|
||||
def search_inventory(self, folder_list = [], item_id = None, name = None,
|
||||
match_list = []):
|
||||
""" search through all inventory folders for an id(uuid) or Name, and
|
||||
return a list of matching InventoryItems or InventoryFolders
|
||||
|
||||
@@ -200,60 +201,52 @@ class InventoryManager(DataManager):
|
||||
|
||||
This does not request inventory from the grid. It could, were we to go about enabling this...
|
||||
"""
|
||||
|
||||
def match():
|
||||
_match = lambda arg : False
|
||||
if item_id != None:
|
||||
def _match(arg):
|
||||
if isinstance(arg, InventoryItem):
|
||||
return str(arg.ItemID) == str(item_id)
|
||||
else:
|
||||
return str(arg.FolderID) == str(item_id)
|
||||
elif name != None:
|
||||
pattern = re.compile(name)
|
||||
def _match(arg):
|
||||
if pattern.match(arg.Name):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return _match
|
||||
|
||||
is_match = match()
|
||||
|
||||
# search our inventory storage if we aren't told what to look in
|
||||
if folder_list == []:
|
||||
if folder_list == []:
|
||||
search_folders = self.folders
|
||||
else:
|
||||
search_folders = folder_list
|
||||
|
||||
if item_id != None:
|
||||
|
||||
item_id = UUID(str(item_id))
|
||||
|
||||
for item in search_folders:
|
||||
|
||||
if isinstance(item, InventoryItem):
|
||||
if str(item.ItemID) == str(item_id):
|
||||
match_list.append(item)
|
||||
|
||||
elif isinstance(item, InventoryFolder):
|
||||
matches = self.search_inventory_folder(item.FolderID, _id = item_id)
|
||||
match_list.extend(matches)
|
||||
|
||||
return match_list
|
||||
|
||||
elif name != None:
|
||||
|
||||
for item in search_folders:
|
||||
|
||||
pattern = re.compile(name)
|
||||
|
||||
if isinstance(item, InventoryItem):
|
||||
if pattern.match(item.Name):
|
||||
match_list.append(item)
|
||||
|
||||
elif isinstance(item, InventoryFolder):
|
||||
matches = self.search_inventory_folder(item.FolderID, name = name.strip())
|
||||
match_list.extend(matches)
|
||||
|
||||
return match_list
|
||||
|
||||
else:
|
||||
|
||||
# return an empty list
|
||||
return []
|
||||
|
||||
for item in search_folders:
|
||||
if is_match(item):
|
||||
match_list.append(item)
|
||||
if isinstance(item, InventoryFolder):
|
||||
matches = self.search_inventory_folder(item.FolderID,
|
||||
_id=item_id,
|
||||
name=name)
|
||||
match_list.extend(matches)
|
||||
return match_list
|
||||
|
||||
def search_inventory_folder(self, folder_id, _id = None, name = None):
|
||||
""" search an inventory folder for _id or name
|
||||
|
||||
return a list of matches
|
||||
"""
|
||||
|
||||
|
||||
match_list = []
|
||||
|
||||
|
||||
search_folder = [folder for folder in self.folders if str(folder.FolderID) == str(folder_id)][0]
|
||||
|
||||
|
||||
for item in search_folder.inventory:
|
||||
|
||||
if _id != None:
|
||||
@@ -261,9 +254,8 @@ class InventoryManager(DataManager):
|
||||
if isinstance(item, InventoryItem):
|
||||
if str(item.ItemID) == str(_id):
|
||||
match_list.append(item)
|
||||
|
||||
elif isinstance(item, InventoryFolder):
|
||||
if item.FolderID == _id:
|
||||
if str(item.FolderID) == str(_id):
|
||||
match_list.append(item)
|
||||
|
||||
elif name != None:
|
||||
@@ -469,6 +461,81 @@ class InventoryManager(DataManager):
|
||||
|
||||
self.agent.send_ImprovedInstantMessage(self.agent.agent_id, self.agent.session_id, 0, FromAgentID, 0, UUID(), self.agent.Position, 0, accept_key, ID, 0, self.agent.Name(), '', '')
|
||||
|
||||
def create_new_item(self, folder, name, desc, asset_type, inv_type,
|
||||
wearable_type, next_owner_permission, callback=None):
|
||||
"""
|
||||
Creates a new item in folder.
|
||||
"""
|
||||
transaction_id = UUID()
|
||||
transaction_id.random()
|
||||
|
||||
updateCreateInventoryHandler = self.agent.region.message_handler.register('UpdateCreateInventoryItem')
|
||||
|
||||
def onUpdateCreateInventoryItem(packet):
|
||||
if str(transaction_id) != \
|
||||
str(packet.blocks['AgentData'][0]\
|
||||
.get_variable('TransactionID').data):
|
||||
inv_data = packet.blocks['InventoryData'][0]
|
||||
item = InventoryItem(inv_data.get_variable('ItemID').data,
|
||||
inv_data.get_variable('FolderID').data,
|
||||
inv_data.get_variable('CreatorID').data,
|
||||
inv_data.get_variable('OwnerID').data,
|
||||
inv_data.get_variable('GroupID').data,
|
||||
inv_data.get_variable('BaseMask').data,
|
||||
inv_data.get_variable('OwnerMask').data,
|
||||
inv_data.get_variable('GroupMask').data,
|
||||
inv_data.get_variable('EveryoneMask').data,
|
||||
inv_data.get_variable('NextOwnerMask').data,
|
||||
inv_data.get_variable('GroupOwned').data,
|
||||
inv_data.get_variable('AssetID').data,
|
||||
inv_data.get_variable('Type').data,
|
||||
inv_data.get_variable('InvType').data,
|
||||
inv_data.get_variable('Flags').data,
|
||||
inv_data.get_variable('SaleType').data,
|
||||
inv_data.get_variable('SalePrice').data,
|
||||
inv_data.get_variable('Name').data,
|
||||
inv_data.get_variable('Description').data,
|
||||
inv_data.get_variable('CreationDate').data,
|
||||
inv_data.get_variable('CRC').data)
|
||||
|
||||
self._store_inventory_item(item)
|
||||
updateCreateInventoryHandler.unsubscribe(onUpdateCreateInventoryItem)
|
||||
if callback != None:
|
||||
callback(item)
|
||||
|
||||
updateCreateInventoryHandler.subscribe(onUpdateCreateInventoryItem)
|
||||
|
||||
self.send_CreateInventoryItem(self.agent.agent_id,
|
||||
self.agent.session_id,
|
||||
0,
|
||||
folder.FolderID,
|
||||
transaction_id,
|
||||
next_owner_permission,
|
||||
asset_type,
|
||||
inv_type,
|
||||
wearable_type,
|
||||
name,
|
||||
desc)
|
||||
|
||||
def send_CreateInventoryItem(self, agent_id, session_id, callback_id,
|
||||
folder_id, transaction_id, next_owner_mask,
|
||||
type_, inv_type, wearable_type, name, desc):
|
||||
""" sends a CreateInventoryItem message """
|
||||
args = [Block('AgentData',
|
||||
AgentID = agent_id,
|
||||
SessionID = session_id)]
|
||||
args += [Block('InventoryBlock',
|
||||
CallbackID = callback_id,
|
||||
FolderID = folder_id,
|
||||
TransactionID = transaction_id,
|
||||
NextOwnerMask = next_owner_mask,
|
||||
Type = type_,
|
||||
InvType = inv_type,
|
||||
WearableType = wearable_type,
|
||||
Name = name,
|
||||
Description = desc)]
|
||||
self.agent.region.enqueue_message(Message("CreateInventoryItem", *args))
|
||||
|
||||
def sendFetchInventoryDescendentsRequest(self, folder_id = None):
|
||||
""" send a request to the grid for folder contents """
|
||||
|
||||
@@ -863,7 +930,29 @@ class InventoryItem(object):
|
||||
Tests: tests/test_inventory.py
|
||||
"""
|
||||
|
||||
def __init__(self, ItemID = None, FolderID = None, CreatorID = None, OwnerID = None, GroupID = None, BaseMask = None, OwnerMask = None, GroupMask = None, EveryoneMask = None, NextOwnerMask = 0, GroupOwned = None, AssetID = None, Type = None, InvType = None, Flags = None, SaleType = None, SalePrice = None, Name = None, Description = None, CreationDate = None, CRC = None, LastOwnerID = UUID()):
|
||||
def __init__(self,
|
||||
ItemID = None,
|
||||
FolderID = None,
|
||||
CreatorID = None,
|
||||
OwnerID = None,
|
||||
GroupID = None,
|
||||
BaseMask = None,
|
||||
OwnerMask = None,
|
||||
GroupMask = None,
|
||||
EveryoneMask = None,
|
||||
NextOwnerMask = 0,
|
||||
GroupOwned = None,
|
||||
AssetID = None,
|
||||
Type = None,
|
||||
InvType = None,
|
||||
Flags = None,
|
||||
SaleType = None,
|
||||
SalePrice = None,
|
||||
Name = None,
|
||||
Description = None,
|
||||
CreationDate = None,
|
||||
CRC = None,
|
||||
LastOwnerID = UUID()):
|
||||
""" initialize the inventory item """
|
||||
|
||||
self.type = 'InventoryItem'
|
||||
@@ -984,47 +1073,49 @@ def sendRezObject(agent, inventory_item, RayStart, RayEnd, FromTaskID = UUID(),
|
||||
|
||||
packet = Message('RezObject',
|
||||
Block('AgentData',
|
||||
AgentID = agent.agent_id,
|
||||
SessionID = agent.session_id,
|
||||
GroupID = agent.ActiveGroupID),
|
||||
AgentID = agent.agent_id,
|
||||
SessionID = agent.session_id,
|
||||
GroupID = agent.ActiveGroupID),
|
||||
Block('RezData',
|
||||
FromTaskID = UUID(str(FromTaskID)),
|
||||
BypassRaycast = BypassRaycast,
|
||||
RayStart = RayStart,
|
||||
RayEnd = RayEnd,
|
||||
RayTargetID = UUID(str(RayTargetID)),
|
||||
RayEndIsIntersection = RayEndIsIntersection,
|
||||
RezSelected = RezSelected,
|
||||
RemoveItem = RemoveItem,
|
||||
ItemFlags = ItemFlags,
|
||||
GroupMask = GroupMask,
|
||||
EveryoneMask = EveryoneMask,
|
||||
NextOwnerMask = NextOwnerMask),
|
||||
FromTaskID = UUID(str(FromTaskID)),
|
||||
BypassRaycast = BypassRaycast,
|
||||
RayStart = RayStart,
|
||||
RayEnd = RayEnd,
|
||||
RayTargetID = UUID(str(RayTargetID)),
|
||||
RayEndIsIntersection = RayEndIsIntersection,
|
||||
RezSelected = RezSelected,
|
||||
RemoveItem = RemoveItem,
|
||||
ItemFlags = ItemFlags,
|
||||
GroupMask = GroupMask,
|
||||
EveryoneMask = EveryoneMask,
|
||||
NextOwnerMask = NextOwnerMask),
|
||||
Block('InventoryData',
|
||||
ItemID = inventory_item.ItemID,
|
||||
FolderID = inventory_item.FolderID,
|
||||
CreatorID = inventory_item.CreatorID,
|
||||
OwnerID = inventory_item.OwnerID,
|
||||
GroupID = inventory_item.GroupID,
|
||||
BaseMask = inventory_item.BaseMask,
|
||||
OwnerMask = inventory_item.OwnerMask,
|
||||
GroupMask = inventory_item.GroupMask,
|
||||
EveryoneMask = inventory_item.EveryoneMask,
|
||||
GroupOwned = inventory_item.GroupOwned,
|
||||
TransactionID = UUID(),
|
||||
Type = inventory_item.Type,
|
||||
InvType = inventory_item.InvType,
|
||||
Flags = inventory_item.Flags,
|
||||
SaleType = inventory_item.SaleType,
|
||||
SalePrice = inventory_item.SalePrice,
|
||||
Name = inventory_item.Name,
|
||||
Description = inventory_item.Description,
|
||||
CreationDate = inventory_item.CreationDate,
|
||||
CRC = inventory_item.CRC,
|
||||
NextOwnerMask = inventory_item.NextOwnerMask))
|
||||
ItemID = inventory_item.ItemID,
|
||||
FolderID = inventory_item.FolderID,
|
||||
CreatorID = inventory_item.CreatorID,
|
||||
OwnerID = inventory_item.OwnerID,
|
||||
GroupID = inventory_item.GroupID,
|
||||
BaseMask = inventory_item.BaseMask,
|
||||
OwnerMask = inventory_item.OwnerMask,
|
||||
GroupMask = inventory_item.GroupMask,
|
||||
EveryoneMask = inventory_item.EveryoneMask,
|
||||
GroupOwned = inventory_item.GroupOwned,
|
||||
TransactionID = UUID(),
|
||||
Type = inventory_item.Type,
|
||||
InvType = inventory_item.InvType,
|
||||
Flags = inventory_item.Flags,
|
||||
SaleType = inventory_item.SaleType,
|
||||
SalePrice = inventory_item.SalePrice,
|
||||
Name = inventory_item.Name,
|
||||
Description = inventory_item.Description,
|
||||
CreationDate = inventory_item.CreationDate,
|
||||
CRC = inventory_item.CRC,
|
||||
NextOwnerMask = inventory_item.NextOwnerMask))
|
||||
|
||||
agent.region.enqueue_message(packet)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Contributors can be viewed at:
|
||||
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt
|
||||
|
||||
@@ -7,11 +7,13 @@ import math
|
||||
|
||||
# related
|
||||
|
||||
|
||||
# pyogp
|
||||
from pyogp.lib.base import *
|
||||
from pyogp.lib.base.datamanager import DataManager
|
||||
from pyogp.lib.base.permissions import PermissionsTarget, PermissionsMask
|
||||
from pyogp.lib.base.datatypes import UUID, Vector3, Quaternion
|
||||
from pyogp.lib.base.event_system import AppEvent
|
||||
|
||||
# pyogp message
|
||||
from pyogp.lib.base.message.message_handler import MessageHandler
|
||||
@@ -20,7 +22,8 @@ from pyogp.lib.base.message.message import Message, Block
|
||||
|
||||
# pyogp utilities
|
||||
from pyogp.lib.base.utilities.helpers import Helpers
|
||||
from pyogp.lib.base.utilities.enums import PCodeEnum, CompressedUpdateFlags
|
||||
from pyogp.lib.base.utilities.enums import PCodeEnum, CompressedUpdateFlags, \
|
||||
Permissions, AssetType
|
||||
|
||||
# initialize logging
|
||||
logger = getLogger('pyogp.lib.base.objects')
|
||||
@@ -329,6 +332,11 @@ class ObjectManager(DataManager):
|
||||
else:
|
||||
#if self.settings.LOG_VERBOSE and self.settings.ENABLE_OBJECT_LOGGING: log(DEBUG, "Updating an object's attributes. LocalID = %s" % (object_properties['LocalID']))
|
||||
_object._update_properties(prim_properties)
|
||||
if _object.UpdateFlags & 2 != 0 and self.agent != None:
|
||||
|
||||
self.agent.events_handler.handle(AppEvent("ObjectSelected",
|
||||
payload = {'object':_object}))
|
||||
|
||||
|
||||
def request_object_update(self, AgentID, SessionID, ID_CacheMissType_list = None):
|
||||
""" requests object updates from the simulator
|
||||
@@ -360,9 +368,28 @@ class ObjectManager(DataManager):
|
||||
# not sure what RayTargetID is, send as uuid of zeros
|
||||
RayTargetID = UUID()
|
||||
|
||||
self.object_add(self.agent.agent_id, self.agent.session_id, GroupID = GroupID, PCode = PCodeEnum.Primitive, 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)
|
||||
self.object_add(self.agent.agent_id, self.agent.session_id,
|
||||
GroupID = GroupID, PCode = PCodeEnum.Primitive,
|
||||
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)
|
||||
|
||||
def object_add(self, AgentID, SessionID, 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()):
|
||||
def object_add(self, AgentID, SessionID, 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()):
|
||||
'''
|
||||
ObjectAdd - create new object in the world
|
||||
Simulator will assign ID and send message back to signal
|
||||
@@ -580,7 +607,7 @@ class ObjectManager(DataManager):
|
||||
X=Helpers.packed_u8_to_float(objdata, 13, -REGION_SIZE, REGION_SIZE),
|
||||
Y=Helpers.packed_u8_to_float(objdata, 14, -REGION_SIZE, REGION_SIZE),
|
||||
Z=Helpers.packed_u8_to_float(objdata, 15, -REGION_SIZE, REGION_SIZE))
|
||||
|
||||
|
||||
object_list.append(object_properties)
|
||||
|
||||
self.update_multiple_objects_properties(object_list)
|
||||
@@ -913,6 +940,61 @@ class ObjectManager(DataManager):
|
||||
|
||||
self.update_multiple_objects_properties(object_list)
|
||||
|
||||
def send_RezScript(self, agent, prim, item_id=UUID(),
|
||||
Enabled=True,
|
||||
GroupID=UUID(),
|
||||
BaseMask=Permissions.All,
|
||||
OwnerMask=Permissions.All,
|
||||
GroupMask=Permissions.None_,
|
||||
EveryoneMask=Permissions.None_,
|
||||
NextOwnerMask=Permissions.Transfer&Permissions.Move,
|
||||
GroupOwned=False,
|
||||
Type=AssetType.LSLText,
|
||||
InvType=AssetType.LSLText,
|
||||
Flags=0,
|
||||
SaleType=0,
|
||||
SalePrice=0,
|
||||
Name="New Script",
|
||||
Description="Created by PyOGP",
|
||||
CreationDate=0,
|
||||
CRC=0):
|
||||
""" sends a RezScript message to the sim, not providing a item_id will
|
||||
rez the default script otherwise the script with ItemID item_id will be rezzed
|
||||
to prim"""
|
||||
packet = Message('RezScript',
|
||||
Block('AgentData',
|
||||
AgentID = agent.agent_id,
|
||||
SessionID = agent.session_id,
|
||||
GroupID = agent.ActiveGroupID),
|
||||
Block('UpdateBlock',
|
||||
ObjectLocalID = prim.LocalID,
|
||||
Enabled = Enabled),
|
||||
Block('InventoryBlock',
|
||||
ItemID = item_id,
|
||||
FolderID = prim.FullID,
|
||||
CreatorID = agent.agent_id,
|
||||
OwnerID = agent.agent_id,
|
||||
GroupID = GroupID,
|
||||
BaseMask = BaseMask,
|
||||
OwnerMask = OwnerMask,
|
||||
GroupMask = GroupMask,
|
||||
EveryoneMask = EveryoneMask,
|
||||
NextOwnerMask = NextOwnerMask,
|
||||
GroupOwned = GroupOwned,
|
||||
TransactionID = UUID(),
|
||||
Type = Type,
|
||||
InvType = InvType,
|
||||
Flags = Flags,
|
||||
SaleType = SaleType,
|
||||
SalePrice = SalePrice,
|
||||
Name = Name,
|
||||
Description = Description,
|
||||
CreationDate = CreationDate,
|
||||
CRC = CRC))
|
||||
agent.region.enqueue_message(packet)
|
||||
|
||||
|
||||
|
||||
class Object(object):
|
||||
""" represents an Object
|
||||
|
||||
@@ -1214,7 +1296,7 @@ class Object(object):
|
||||
|
||||
"""
|
||||
|
||||
self.send_ObjectSelect(agent, agent.agent_id, agent.session_id, [self.LocalID])
|
||||
self.send_ObjectDeselect(agent, agent.agent_id, agent.session_id, [self.LocalID])
|
||||
|
||||
def send_ObjectDeselect(self, agent, AgentID, SessionID, ObjectLocalIDs):
|
||||
""" send an ObjectDeselect message to the agent's host simulator
|
||||
@@ -1230,13 +1312,15 @@ class Object(object):
|
||||
|
||||
agent.region.enqueue_message(packet)
|
||||
|
||||
|
||||
def _update_properties(self, properties):
|
||||
""" takes a dictionary of attribute:value and makes it so """
|
||||
|
||||
for attribute in properties:
|
||||
for attribute in properties.keys():
|
||||
|
||||
setattr(self, attribute, properties[attribute])
|
||||
|
||||
|
||||
"""
|
||||
Contributors can be viewed at:
|
||||
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt
|
||||
|
||||
@@ -22,8 +22,6 @@ class TestAppearance(unittest.TestCase):
|
||||
self.settings = Settings()
|
||||
self.agent = Agent()
|
||||
self.appearance = AppearanceManager(self.agent, settings = self.settings)
|
||||
|
||||
|
||||
self.agent.agent_id = UUID("01234567-89ab-cdef-0123-456789abcdef")
|
||||
self.agent.session_id = UUID("fedcba98-7654-3210-fedc-ba9876543210")
|
||||
self.agent.region = DummyRegion()
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,9 +8,12 @@ from binascii import unhexlify
|
||||
from pyogp.lib.base.objects import *
|
||||
from pyogp.lib.base.settings import Settings
|
||||
from pyogp.lib.base.region import Region
|
||||
from pyogp.lib.base.agent import Agent
|
||||
from pyogp.lib.base.datatypes import UUID, Vector3
|
||||
|
||||
# pyogp messaging
|
||||
from pyogp.lib.base.message.udpdeserializer import UDPMessageDeserializer
|
||||
from pyogp.lib.base.message.message import Message, Block
|
||||
|
||||
# pyogp tests
|
||||
import pyogp.lib.base.tests.config
|
||||
@@ -29,6 +32,7 @@ class TestObjects(unittest.TestCase):
|
||||
|
||||
self.object_store = ObjectManager(region = self.region, settings = self.settings)
|
||||
self.object_store.enable_callbacks()
|
||||
self.data = []
|
||||
def tearDown(self):
|
||||
|
||||
pass
|
||||
@@ -67,7 +71,59 @@ class TestObjects(unittest.TestCase):
|
||||
|
||||
self.assertEquals(known_objects, [(str(uuid.UUID('e2ba7ac7-db28-24e3-484d-f418b045e62d')), 159536), (str(uuid.UUID('6cbafc4a-9758-9481-cd74-c7ccc89e7440')), 171059), (str(uuid.UUID('d2b300c3-71f1-6887-2750-6d48da05e2f5')), 171036), (str(uuid.UUID('dbb7d110-3f65-0859-d494-3dc40ffb2b61')), 171037), (str(uuid.UUID('1f389eb9-8639-28ff-c37b-a3e4f39a7fed')), 171038)])
|
||||
|
||||
def test_onObjectUpdate_selected(self):
|
||||
|
||||
self.object_store.agent = Agent()
|
||||
fake_uuid = UUID()
|
||||
fake_uuid.random()
|
||||
packet = Message('ObjectUpdate',
|
||||
Block('RegionData',
|
||||
RegionHandle=0,
|
||||
TimeDilation=0),
|
||||
Block('ObjectData',
|
||||
ID=1,
|
||||
State=1,
|
||||
FullID=fake_uuid,
|
||||
CRC=0,
|
||||
PCode=0,
|
||||
Material=0,
|
||||
ClickAction=0,
|
||||
Scale=Vector3(X=0.0, Y=0.0, Z=0.0),
|
||||
ObjectData='',
|
||||
ParentID=fake_uuid,
|
||||
UpdateFlags=0,
|
||||
ProfileCurve=0,
|
||||
PathBegin=0.0,
|
||||
PathEnd=0.0,
|
||||
PathScaleX=0.0,
|
||||
PathScaleY=0.0,
|
||||
PathShearX=0.0,
|
||||
PathShearY=0.0,
|
||||
PathTwist=-1,
|
||||
PathTwistBegin=-1,
|
||||
PathRadiusOffset=-1,
|
||||
PathTaperX=-1,
|
||||
PathTaperY=-1,
|
||||
PathRevolutions=0,
|
||||
PathSkew=-1,
|
||||
ProfileBegin=0,
|
||||
ProfileEnd=0,
|
||||
ProfileHollow=0,
|
||||
TextureEntry='',
|
||||
TextureAnim='',
|
||||
NameValue='Test',
|
||||
Data='',
|
||||
Text='',
|
||||
TextColor=0x0,
|
||||
MedialURL=''))
|
||||
|
||||
def callback(payload):
|
||||
self.data.append("foo")
|
||||
object_handler = self.object_store.agent.events_handler.register("ObjectSelected")
|
||||
object_handler.subscribe(callback)
|
||||
self.object_store.region.message_handler.handle(packet)
|
||||
self.assertTrue(self.data.pop, "foo")
|
||||
|
||||
def test_suite():
|
||||
from unittest import TestSuite, makeSuite
|
||||
suite = TestSuite()
|
||||
|
||||
@@ -439,7 +439,17 @@ class TransferStatus(object):
|
||||
Error = -1
|
||||
UnknownSource = -2
|
||||
InsufficientPermissions = -3
|
||||
|
||||
|
||||
|
||||
|
||||
class Permissions(object):
|
||||
Transfer = 1 << 13
|
||||
Modify = 1 << 14
|
||||
Copy = 1 << 15
|
||||
Move = 1 << 19
|
||||
None_ = 0
|
||||
All = 0x7FFFFFFF
|
||||
Unrestricted = Transfer | Modify | Copy
|
||||
"""
|
||||
Contributors can be viewed at:
|
||||
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt
|
||||
|
||||
Reference in New Issue
Block a user