removing components from base that will llive in client

This commit is contained in:
enus.linden
2009-08-28 16:48:12 +00:00
committed by Salad Dais
parent b629f37fda
commit 41fee8a893
14 changed files with 0 additions and 8264 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,174 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# std lib
import urllib2
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
# related
from indra.base import llsd
# pyogp
from pyogp.lib.base.network.stdlib_client import StdLibClient, HTTPError
from pyogp.lib.base.caps import SeedCapability
import pyogp.lib.base.exc
from pyogp.lib.base.settings import Settings
# initialize logging
logger = getLogger('pyogp.lib.base.agentdomain')
log = logger.log
class AgentDomain(object):
"""an agent domain endpoint"""
def __init__(self, uri, restclient = None):
""" initialize the agent domain endpoint """
if restclient == None:
self.restclient = StdLibClient()
else:
self.restclient = restclient
self.settings = Settings()
self.login_uri = uri
self.credentials = None
self.connectedStatus = False
self.capabilities = {}
self.agentdomain_caps_list = ['rez_avatar/place']
self._isEventQueueRunning = False
self.seed_cap = None
log(DEBUG, 'initializing agent domain: %s' %self)
def login(self, credentials):
""" login to the agent domain """
response = self.post_to_loginuri(credentials)
self.eval_login_response(response)
def post_to_loginuri(self, credentials):
""" post to login_uri and return response """
self.credentials = credentials
log(INFO, 'Logging in to %s as %s %s' % (self.login_uri, self.credentials.firstname, self.credentials.lastname))
payload = credentials.serialize()
content_type = credentials.content_type
headers = {'Content-Type': content_type}
# now create the request. We assume for now that self.uri is the login uri
# TODO: make this pluggable so we can use other transports like eventlet in the future
# TODO: add logging and error handling
try:
response = self.restclient.POST(self.login_uri, payload, headers=headers)
except HTTPError, error:
if error.code==404:
raise ResourceNotFound(self.login_uri)
else:
raise ResourceError(self.login_uri, error.code, error.msg, error.fp.read(), method="POST")
return response
def eval_login_response(self, response):
""" parse the login uri response """
seed_cap_url_data = self.parse_login_response(response)
try:
seed_cap_url = seed_cap_url_data['agent_seed_capability']
self.seed_cap = SeedCapability('seed_cap', seed_cap_url, self.restclient)
self.connectedStatus = True
log(INFO, 'logged in to %s' % (self.login_uri))
except KeyError:
raise UserNotAuthorized(self.credentials)
def parse_login_response(self, response):
""" parse the login uri response and returns deserialized data """
data = llsd.parse(response.body)
log(DEBUG, 'deserialized login response body = %s' % (data))
return data
def place_avatar(self, region_uri, position=[117,73,21]):
""" handles the rez_avatar/place cap on the agent domain, populates some initial region attributes """
# wow, this needs some thought... place avatar should really move to the region domain...
if not self.capabilities.has_key('rez_avatar/place'):
self.capabilities['rez_avatar/place'] = self.seed_cap.get(['rez_avatar/place'])['rez_avatar/place']
payload = {'public_region_seed_capability' : region_uri, 'position':position}
result = self.capabilities['rez_avatar/place'].POST(payload)
if result['region_seed_capability'] is None:
raise UserRezFailed(region)
else:
log(INFO, 'Region_uri %s returned a seed_cap of %s' % (region_uri, result['region_seed_capability']))
log(DEBUG, 'Full rez_avatar/place response is: %s' % (result))
return result
def get_agentdomain_capabilities(self):
""" queries the region seed cap for capabilities """
if (self.seed_cap == None):
raise RegionSeedCapNotAvailable("querying for agents's agent domain capabilities")
# well then get it
# return something?
else:
log(INFO, 'Getting caps from agent domain seed cap %s' % (self.seed_cap))
# use self.region_caps.keys() to pass a list to be parsed into LLSD
self.capabilities = self.seed_cap.get(self.agentdomain_caps_list)
def _processEventQueue(self):
self._isEventQueueRunning = True
if self.capabilities['event_queue'] == None:
raise RegionCapNotAvailable('event_queue')
# change the exception here (add a new one)
else:
while self._isEventQueueRunning:
# need to be able to pull data from a queue somewhere
data = {}
api.sleep(self.settings.agentdomain_event_queue_interval)
#if self.last_id != -1:
#data = {'ack':self.last_id, 'done':False}
result = self.capabilities['event_queue'].POST(data)
self.last_id = result['id']
#log(DEBUG, 'region event queue cap called, returned id: %s' % (self.last_id))
log(DEBUG, 'AgentDomain EventQueueGet result: %s' % (result))

View File

@@ -1,177 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# standard python libraries
from logging import getLogger, ERROR, WARNING, INFO, DEBUG
import signal
import sys
# related
from eventlet import api
# pyogp
from pyogp.lib.base.datatypes import UUID
from pyogp.lib.base.exc import LoginError
from pyogp.lib.base.utilities.helpers import Wait
# initialize logging
logger = getLogger('pyogp.lib.base.agentmanager')
log = logger.log
class AgentManager(object):
""" a simple class to track multiple agents
This class can perhaps begin to manage sessions in time.
"""
def __init__(self, settings = None):
""" initialize the agent manager """
# allow the settings to be passed in
# otherwise, grab the defaults
if settings != None:
self.settings = settings
else:
from pyogp.lib.base.settings import Settings
self.settings = Settings()
# store the agents in a dictionary keyed by a uuid
# this could be agent_id, if we know it ahead of time
# or, create a new one
self.agents = {}
# signal handler to capture erm signals
self.signal_handler = signal.signal(signal.SIGINT, self.sigint_handler)
if self.settings.LOG_VERBOSE:
log(DEBUG, 'Initializing agent manager for %s agents' % (len(self.agents)))
def initialize(self, agents):
""" accept a list of Agent() instances, and store them in the agents attribute """
if type(agents) != list:
log(WARNING, "The AgentManager requires a list of Agent instances to initialize. Stopping.")
return False
for agent in agents:
self.store_agent(agent)
def store_agent(self, agent):
""" adds an agent to the store """
if str(type(agent)) != '<class \'pyogp.lib.base.agent.Agent\'>':
log(WARNING, "The AgentManager stores only Agent instances to initialize. Stopping.")
return False
# check if the agent is on the store
if self._is_stored(agent) == False:
if agent.agent_id == None:
key = UUID().random()
else:
key = agent.agent_id
self.agents[key] = agent
log(INFO, "Stored agent %s with a key of %s" % (agent.name, key))
else:
if agent.firstname != None and agent.lastname != None:
uniq = ' named ' + agent.Name()
log(WARNING, "The AgentManager is already storing an agent%s. Stopping." % (uniq))
def _is_stored(self, agent):
""" returns True if an agent is already stored, False if not """
if agent.Name() in self._stored_names():
return True
elif agent.agent_id in self._stored_agent_ids():
return True
else:
return False
def _stored_names(self):
""" returns the stored agent's names in a list """
names = []
for key in self.agents:
names.append(self.agents[key].Name())
return names
def _stored_agent_ids(self):
""" returns the stored agent's names in a list """
ids = []
for key in self.agents:
if self.agents[key].agent_id != None:
ids.append(self.agents[key].agent_id)
return ids
def login(self, key, loginuri, start_location):
""" spawns a new agent via an eventlet coroutine """
if self.settings.LOG_COROUTINE_SPAWNS:
log(INFO, "Spawning a coroutine for agent login for %s." % (self.agents[key].Name()))
try:
api.spawn(self.agents[key].login, loginuri = loginuri, start_location = start_location)
except LoginError, error:
log(ERROR, "Skipping agent with failed login: %s due to %s." % (self.agents[key].Name(), error))
def has_agents_running(self):
""" returns true if there is a client who's running value = True """
for key in self.agents:
if self.agents[key].running:
return True
return False
def get_active_agents(self):
""" returns a list of agents that are connected to a grid """
active = []
for key in self.agents:
active.append(self.agents[key])
return active
def sigint_handler(self, sigint, frame):
""" handles signals from the command line (and others) and logs out all agents """
log(INFO, "Caught signal... %d. Stopping" % sigint)
for agent in self.get_active_agents():
agent.logout()
Wait(10)
if self.has_agents_running():
log(WARNING, "These agents have not yet shut down. Killing the process hard.\n\t\t%s" % (self.get_active_agents()))
sys.exit(1)

View File

@@ -1,350 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# standard python libs
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
import uuid
#related
from eventlet import api
# pyogp
from pyogp.lib.base.datamanager import DataManager
# pyogp messaging
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.objects import Object
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
# initialize logging
logger = getLogger('pyogp.lib.base.appearance')
log = logger.log
class AppearanceManager(DataManager):
"""The AppearanceManager class handles appearance of an Agent() instance
Sample implementations:
Tests:
"""
def __init__(self, agent, settings = None):
"""
initialize the appearance manager
TODO Fix the Z by generating actual height
"""
super(AppearanceManager, self).__init__(agent, settings)
self.AgentSetSerialNum = 1
self.AgentCachedSerialNum = 1
self.wearables = [] #indexed by WearableType
for i in range(TextureIndex.TEX_COUNT):
self.wearables.append(Wearable(i))
self.helpers = Helpers()
self.bakedTextures = {} #indexed by TextureIndex
for i in range(BakedIndex.BAKED_COUNT):
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
"""
onAgentWearablesUpdate_received = self.agent.region.message_handler.register('AgentWearablesUpdate')
onAgentWearablesUpdate_received.subscribe(self.onAgentWearablesUpdate)
onAgentCachedTextureResponse_received = self.agent.region.message_handler.register('AgentCachedTextureResponse')
onAgentCachedTextureResponse_received.subscribe(self.onAgentCachedTextureResponse)
#onAvatarAppearance_received = self.agent.region.message_handler.register('AvatarAppearance')
#onAvatarAppearance_received.subscribe(self.onAvatarAppearance)
self.request_agent_wearables()
'''
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
self.send_AgentWearablesRequest(self.agent.agent_id,
self.agent.session_id)
def wearableArrived(self, assetID, isSuccess):
"""
callback for wearables request
"""
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
the AgentWearables update packet.
This message should only be received once.
Error Checking: make sure agent and session id are correct
make sure this method is only called once.
"""
#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))
def onAvatarTextureUpdate(self, packet):
raise NotImplemented("onAvatarTextureUpdate")
def onAvatarAppearance(self, packet):
"""
Informs viewer how other avatars look
"""
raise NotImplemented("onAvatarAppearance")
def onAgentCachedTextureResponse(self, packet):
"""
Update the bakedTextures with their TextureIDs and HostNames and call
send_AgentSetAppearance
"""
#log(INFO, "AgentCachedTextureRespose received: %s" % packet)
for bakedTexture in packet.blocks['WearableData']:
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.agent.agent_id,
self.agent.session_id,
self.Size,
self.bakedTextures,
self.TextureEntry,
self.visualParams)
def verifyAgentData(self, packet):
"""
verifies that packet refers to this agent
"""
pAgentID = packet.blocks['AgentData'][0].get_variable("AgentID").data
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
"""
def __init__(self, WearableType = None, ItemID = UUID(), AssetID = UUID()):
self.WearableType = WearableType
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):
"""
Represents 1 of the 6 baked textures of an avatar
"""
def __init__(self, bakedIndex, TextureID = UUID()):
self.bakedIndex = bakedIndex
self.TextureID = TextureID
self.HostName = None
if bakedIndex == BakedIndex.BAKED_HEAD:
self.secret_hash = UUID("18ded8d6-bcfc-e415-8539-944c0f5ea7a6")
elif bakedIndex == BakedIndex.BAKED_UPPER:
self.secret_hash = UUID("338c29e3-3024-4dbb-998d-7c04cf4fa88f")
elif bakedIndex == BakedIndex.BAKED_LOWER:
self.secret_hash = UUID("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f")
elif bakedIndex == BakedIndex.BAKED_EYES:
self.secret_hash = UUID("b2cf28af-b840-1071-3c6a-78085d8128b5")
elif bakedIndex == BakedIndex.BAKED_SKIRT:
self.secret_hash = UUID("ea800387-ea1a-14e0-56cb-24f2022f969a")
elif bakedIndex == BakedIndex.BAKED_HAIR:
self.secret_hash = UUID("0af1ef7c-ad24-11dd-8790-001f5bf833e8")
else:
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):
"""
Represents 1 of the 21 baked and not baked textures of an avatar.
"""
def __init__(self, TextureIndex, TextureID = None):
self.TextureIndex = TextureIndex
self.TextureID = TextureID

View File

@@ -1,264 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# standard python libs
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
import uuid
#related
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.message import Message, Block
from pyogp.lib.base.utilities.helpers import Helpers
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
logger = getLogger('pyogp.lib.base.assets')
log = logger.log
class AssetManager(DataManager):
"""
The AssetManager class handles the assets of an Agent() instance
Sample implementations:
Tests: test_assets.py
"""
def __init__(self, agent, settings = None):
super(AssetManager, self).__init__(agent, settings)
#indexed by assetID
self.assets = {}
def enable_callbacks(self):
pass
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
if request failed. On successful request the asset is store in
self.assets
"""
transferID = UUID() #associate the assetID with the transferID
transferID.random()
transferInfoHandler = self.agent.region.message_handler.register('TransferInfo')
transferPacketHandler = self.agent.region.message_handler.register('TransferPacket')
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)
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))
if callback != None:
callback(assetID, False)
transferPacketHandler.unsubscribe(onTransferPacket)
transferInfoHandler.unsubscribe(onTransferInfo)
transferInfoHandler.subscribe(onTransferInfo)
transferPacketHandler.subscribe(onTransferPacket)
if isPriority:
priority = 1.0
else:
priortity = 0.0
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,
TransferSourceType.Asset,
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):
"""
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, data):
self.assetID = assetID
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())
paramVal = i.next()
#TODO Verify this is correct behavior this fix may be a hack
if paramVal == '.':
self.params[paramID] = 0.0
else:
self.params[paramID] = float(paramVal)
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

View File

@@ -1,220 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# standard python libs
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
import time
# related
from eventlet import api
# pyogp
from pyogp.lib.base.utilities.events import Event
from pyogp.lib.base.settings import Settings
from pyogp.lib.base.exc import DataParsingError
# initialize logging
logger = getLogger('event_system')
log = logger.log
class AppEventsHandler(object):
""" general class handling individual events """
def __init__(self, settings = None):
""" initialize the AppEventsHandler """
# allow the settings to be passed in
# otherwise, grab the defaults
if settings != None:
self.settings = settings
else:
from pyogp.lib.base.settings import Settings
self.settings = Settings()
self.handlers = {}
def register(self, event_name, timeout = 0):
""" create a watcher for a specific event in this event system. the timeout is optional, and defaults to no timeout """
if self.settings.LOG_VERBOSE: log(DEBUG, 'Creating a monitor for %s' % (event_name))
return self.handlers.setdefault(event_name, AppEventNotifier(event_name, self.settings, timeout))
def is_event_handled(self, event_name):
""" if the event is being monitored, return True, otherwise, return False """
try:
handler = self.handlers[event_name]
return True
except KeyError:
return False
def handle(self, event):
""" essentially a case statement to pass event data to notifiers """
try:
handler = self.handlers[event.name]
# Handle the packet if we have subscribers
if len(handler) > 0:
if self.settings.LOG_VERBOSE: log(DEBUG, 'Handling event: %s' % (event.name))
handler(event)
except KeyError:
#log(INFO, "Received an unhandled packet: %s" % (packet.name))
pass
class AppEventNotifier(object):
""" access points for subscribing to application wide events. timeout = 0 for no timeout """
def __init__(self, event_name, settings, timeout = 0):
""" initialize an event notifier by name, with an optional timeout """
self.event = Event()
self.event_name = event_name
self.settings = settings
if type(timeout) == int:
self.timeout = timeout
else:
raise DataParsingError("Timeout must be an integer creating an event watcher for %s" % (event_name))
def subscribe(self, *args, **kwdargs):
""" register a callback handler for a specific event, starting the timer if != 0, otherwise it will watch until forced to unsubscribe by the caller """
self.args = args
self.kwdargs = kwdargs
self.event.subscribe(*args, **kwdargs)
if self.timeout != 0:
self._start_timer()
def received(self, event):
""" notifies subscribers about an event firing and passes along the data """
self.event(event)
def unsubscribe(self, *args, **kwdargs):
""" stop watching this event """
self.event.unsubscribe(*args, **kwdargs)
if self.settings.LOG_VERBOSE: log(DEBUG, "Removed the monitor for %s by %s" % (args, kwdargs))
def _start_timer(self):
""" begins the timer when a timeout value is specified. returns None when the timer expires, then unsubscribes """
now = time.time()
start = now
# spawn an empty coroutine for the duration of the timeout
while now - start < self.timeout:
api.sleep()
now = time.time()
# once the timeout has expired...
if self.settings.LOG_VERBOSE: log(DEBUG, "Timing out the monitor for %s by %s" % (self.args, self.kwdargs))
# return None to the callback handler
self.received(None)
# unsubscribe the watcher due to the timeout
self.unsubscribe(*self.args, **self.kwdargs)
def __len__(self):
return len(self.event)
__call__ = received
##########################
# Application Level Events
##########################
class AppEvent(object):
""" container for an event payload.
name = name of the event, to which applications will subscribe.
payload = dict of the contents of the event (key:value)
**kwdargs = key:value pairs
either payload or **kwdargs should be used, not both
"""
def __init__(self, name, payload = None, llsd = None, **kwargs):
""" initialize the AppEvent contents """
self.name = name
self.payload = {}
if payload != None and len(kwargs) > 0 and llsd != None:
raise DataParsingError("AppEvent cannot parse both an explicit payload and a kwdargs representation of a payload")
return
if payload != None:
if type(payload) == dict:
self.payload = payload
else:
raise DataParsingError("AppEvent payload must be a dict. A %s was passed in." % (type(payload)))
return
elif len(kwargs) > 0:
for key in kwargs.keys():
self.payload[key] = kwargs[key]
elif llsd != None:
self.from_llsd(llsd)
else:
raise DataParsingError("AppEvent needs a payload or kwdargs, none were provided for %s." % (self.name))
return
def to_llsd(self):
""" transform the event payload into llsd """
raise NotImplemented("AppEvent().to_llsd() has not yet been written")
def from_llsd(self):
""" transform llsd into an event payload """
raise NotImplemented("AppEvent().from_llsd() has not yet been written")
class AppEventEnum(object):
""" enumeration of application level events and their keys"""
InstantMessageReceived = ['FromAgentID', 'RegionID', 'Position', 'ID', 'FromAgentName', 'Message']
ChatReceived = ['FromName', 'SourceID', 'OwnerID', 'SourceType', 'ChatType', 'Audible', 'Position', 'Message']

View File

@@ -1,634 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# standard python libs
from logging import getLogger, WARNING, INFO, DEBUG
import re
# related
from eventlet import api
# for MockChatInterface
import sys
import select
import tty
import termios
# pyogp
from pyogp.lib.base.datatypes import UUID, Vector3
from pyogp.lib.base.exc import DataParsingError
from pyogp.lib.base.utilities.helpers import Wait
from pyogp.lib.base.datamanager import DataManager
# pyogp messaging
from pyogp.lib.base.message.message import Message, Block
# pyogp utilities
from pyogp.lib.base.utilities.enums import ImprovedIMDialogue
# initialize logging
logger = getLogger('pyogp.lib.base.groups')
log = logger.log
class GroupManager(DataManager):
""" a storage bin for groups
also, a functional area for group creation operations
"""
def __init__(self, agent, settings = None):
""" initialize the group manager """
super(GroupManager, self).__init__(agent, settings)
# the group store consists of a list
# of Group() instances
self.group_store = []
if self.settings.LOG_VERBOSE:
log(DEBUG, "Initialized the Group Manager")
def enable_callbacks(self):
"""enables the callback handlers for this GroupManager"""
if self.settings.HANDLE_PACKETS:
onAgentGroupDataUpdate_received = self.agent.region.message_handler.register("AgentGroupDataUpdate")
onAgentGroupDataUpdate_received.subscribe(self.onAgentGroupDataUpdate)
onChatterBoxInvitation_received = self.agent.region.message_handler.register('ChatterBoxInvitation')
onChatterBoxInvitation_received.subscribe(self.onChatterBoxInvitation_Message)
onChatterBoxSessionEventReply_received = self.agent.region.message_handler.register('ChatterBoxSessionEventReply')
onChatterBoxSessionEventReply_received.subscribe(self.onChatterBoxSessionEventReply)
onChatterBoxSessionAgentListUpdates_received = self.agent.region.message_handler.register('ChatterBoxSessionAgentListUpdates')
onChatterBoxSessionAgentListUpdates_received.subscribe(self.onChatterBoxSessionAgentListUpdates)
onChatterBoxSessionStartReply_received = self.agent.region.message_handler.register('ChatterBoxSessionStartReply')
onChatterBoxSessionStartReply_received.subscribe(self.onChatterBoxSessionStartReply)
def handle_group_chat(self, message):
""" process a ChatterBoxInvitation_Message instance"""
group = [group for group in self.group_store if str(message.blocks['Message_Data'][0].get_variable('instantmessage').data['message_params']['id']) == str(group.GroupID)]
if group != []:
group[0].handle_inbound_chat(message)
else:
log(WARNING, "Received group chat message from unknown group. Group: %s. Agent: %s. Message: %s" % (message.blocks['Message_Data'][0].get_variable('session_name').data, message.blocks['Message_Data'][0].get_variable('from_name').data, message.blocks['Message_Data'][0].get_variable('message').data))
def store_group(self, _group):
""" append to or replace a group in self.group_store """
# replace an existing list member, else, append
try:
index = [self.group_store.index(_group_) for _group_ in self.group_store if _group_.ID == _group.GroupID]
self.group_store[index[0]] = _group
if self.settings.LOG_VERBOSE:
log(DEBUG, 'Replacing a stored group: \'%s\'' % (_group.GroupID))
except:
self.group_store.append(_group)
if self.settings.LOG_VERBOSE:
log(DEBUG, 'Stored a new group: \'%s\'' % (_group.GroupID))
def update_group(self, group_data):
""" accepts a dictionary of group data and creates/updates a group """
group = [group for group in self.group_store if str(group_data['GroupID']) == str(group.GroupID)]
if group != []:
group[0].update_properties(group_data)
if self.settings.LOG_VERBOSE:
log(DEBUG, 'Updating a stored group: \'%s\'' % (group[0].GroupID))
else:
group = Group(GroupID = group_data['GroupID'],
GroupPowers = group_data['GroupPowers'],
AcceptNotices = group_data['AcceptNotices'],
GroupInsigniaID = group_data['GroupInsigniaID'],
Contribution = group_data['Contribution'],
GroupName = group_data['GroupName'])
self.store_group(group)
def update_group_by_name(self, group_data, name):
""" accepts a dictionary of group data and creates/updates a group """
pattern = re.compile(name)
group = [group for group in self.group_store if pattern.match(group.GroupName)]
if group != []:
group[0].update_properties(group_data)
if self.settings.LOG_VERBOSE:
log(DEBUG, 'Updating a stored group: \'%s\'' % (group[0].GroupName))
else:
log(INFO, "Received an update for an unknown group for name: %s" % (name))
def update_group_by_session_id(self, group_data):
""" accepts a dictionary of group data and creates/updates a group """
group = [group for group in self.group_store if str(group.session_id) == str(group_data['session_id'])]
if group != []:
group[0].update_properties(group_data)
if self.settings.LOG_VERBOSE:
log(DEBUG, 'Updating a stored group: \'%s\'' % (group[0].GroupName))
else:
log(INFO, "Received an update for an unknown group with a session id of: %s" % (str(group_data['session_id'])))
def create_group(self,
AgentID = None,
SessionID = None,
Name = None,
Charter = '',
ShowInList = True,
InsigniaID = UUID(),
MembershipFee = 0,
OpenEnrollment = False,
AllowPublish = False,
MaturePublish = False):
""" sends a message to the agent's current region requesting to create a group
enables a callback (which should be unsubscribed from once we get a response)
"""
if Name != None:
log(INFO, "Sending a request to create group with a name of \'%s\'" % (Name))
if AgentID == None:
AgentID = self.agent.agent_id
if SessionID == None:
SessionID = self.agent.session_id
packet = Message('CreateGroupRequest',
Block('AgentData',
AgentID = AgentID,
SessionID = SessionID),
Block('GroupData',
Name = Name,
Charter = Charter,
ShowInList = ShowInList,
InsigniaID = InsigniaID,
MembershipFee = MembershipFee,
OpenEnrollment = OpenEnrollment,
AllowPublish = AllowPublish,
MaturePublish = MaturePublish))
self.agent.region.enqueue_message(packet, True)
if self.settings.HANDLE_PACKETS:
# enable the callback to watch for the CreateGroupReply packet
self.onCreateGroupReply_received = self.agent.region.message_handler.register('CreateGroupReply')
self.onCreateGroupReply_received.subscribe(self.onCreateGroupReply)
else:
raise DataParsingError('Failed to create a group, please specify a name')
def get_group(self, GroupID = None):
""" searches the store and returns group if stored, None otherwise """
group = [group for group in self.group_store if str(group.GroupID) == str(GroupID)]
if group == []:
return None
else:
return group[0]
def join_group(self, group_id):
""" sends a JoinGroupRequest packet for the specified uuid """
# set up the callback
self.onJoinGroupReply_received = self.agent.message_handler.register('JoinGroupReply')
self.onJoinGroupReply_received.subscribe(self.onJoinGroupReply)
self.send_JoinGroupRequest(self.agent.agent_id, self.agent.session_id, group_id)
def send_JoinGroupRequest(self, agent_id, session_id, group_id):
""" sends a JoinGroupRequest message to the hsot simulator """
packet = Message('JoinGroupRequest',
Block('AgentData',
AgentID = AgentID,
SessionID = SessionID),
Block('GroupData',
GroupID = group_id))
self.agent.region.enqueue_message(packet, True)
def activate_group(self, group_id):
""" set a particular group as active """
self.send_ActivateGroup(self.agent.agent_id, self.agent.session_id, group_id)
def send_ActivateGroup(self, agent_id, session_id, group_id):
""" sends an ActivateGroup message to the host simulator """
packet = Message('ActivateGroup',
Block('AgentData',
AgentID = agent_id,
SessionID = session_id,
GroupID = group_id))
self.agent.region.enqueue_message(packet)
# ~~~~~~~~~~~~~~~~~~
# Callback functions
# ~~~~~~~~~~~~~~~~~~
def onCreateGroupReply(self, packet):
""" when we get a CreateGroupReply packet, log Success, and if True, request the group details. remove the callback in any case """
# remove the monitor
self.onCreateGroupReply_received.unsubscribe(self.onCreateGroupReply)
AgentID = packet.blocks['AgentData'][0].get_variable('AgentID').data
GroupID = packet.blocks['ReplyData'][0].get_variable('GroupID').data
Success = packet.blocks['ReplyData'][0].get_variable('Success').data
_Message = packet.blocks['ReplyData'][0].get_variable('Message').data
if Success:
log(INFO, "Created group %s. Message data is: %s" % (GroupID, _Message))
log(WARNING, "We now need to request the group data...")
else:
log(WARNING, "Failed to create group due to: %s" % (_Message))
def onJoinGroupReply(self, packet):
""" the simulator tells us if joining a group was a success. """
self.onJoinGroupReply_received.unsubscribe(self.onJoinGroupReply)
AgentID = packet.blocks['AgentData'][0].get_variable('AgentID').data
GroupID = packet.blocks['GroupData'][0].get_variable('GroupID').data
Success = packet.blocks['GroupData'][0].get_variable('Success').data
if Success:
log(INFO, "Joined group %s" % (GroupID))
else:
log(WARNING, "Failed to join group %s" % (GroupID))
def onAgentGroupDataUpdate(self, packet):
""" deal with the data that comes in over the event queue """
group_data = {}
AgentID = packet.blocks['AgentData'][0].get_variable('AgentID').data
# GroupData block
for GroupData_block in packet.blocks['GroupData']:
group_data['GroupID'] = GroupData_block.get_variable('GroupID').data
group_data['GroupPowers'] = GroupData_block.get_variable('GroupPowers').data
group_data['AcceptNotices'] = GroupData_block.get_variable('AcceptNotices').data
group_data['GroupInsigniaID'] = GroupData_block.get_variable('GroupInsigniaID').data
group_data['Contribution'] = GroupData_block.get_variable('Contribution').data
group_data['GroupName'] = GroupData_block.get_variable('GroupName').data
# make sense of group powers
group_data['GroupPowers'] = [ord(x) for x in group_data['GroupPowers']]
group_data['GroupPowers'] = ''.join([str(x) for x in group_data['GroupPowers']])
self.update_group(group_data)
def onChatterBoxInvitation_Message(self, message):
""" handle a group chat message from the event queue """
self.handle_group_chat(message)
def onChatterBoxSessionEventReply(self, message):
""" handle a response from the simulator re: a message we sent to a group chat """
self.agent.helpers.log_event_queue_data(message, self)
def onChatterBoxSessionAgentListUpdates(self, message):
""" parse teh response to a request to join a group chat and propagate data out """
data = {}
data['session_id'] = message.blocks['Message_Data'][0].get_variable('session_id').data
data['agent_updates'] = message.blocks['Message_Data'][0].get_variable('agent_updates').data
self.update_group_by_session_id(data)
def onChatterBoxSessionStartReply(self, message):
data = {}
data['temp_session_id'] = message.blocks['Message_Data'][0].get_variable('temp_session_id').data
data['success'] = message.blocks['Message_Data'][0].get_variable('success').data
data['session_id'] = message.blocks['Message_Data'][0].get_variable('session_id').data
data['session_info'] = message.blocks['Message_Data'][0].get_variable('session_info').data
self.update_group_by_name(data, data['session_info']['session_name'])
class Group(object):
""" representation of a group """
def __init__(self, AcceptNotices = None, GroupPowers = None, GroupID = None, GroupName = None, ListInProfile = None, Contribution = None, GroupInsigniaID = None, agent = None):
self.AcceptNotices = AcceptNotices
self.GroupPowers = GroupPowers
self.GroupID = UUID(str(GroupID))
self.GroupName = GroupName
self.ListInProfile = ListInProfile
self.Contribution = Contribution
self.GroupInsigniaID = UUID(str(GroupInsigniaID))
self.agent = agent
# store a history of ChatterBoxInvitation messages, and outgoing packets
self.chat_history = []
self.session_id = None
def activate_group(self):
""" set this group as active """
self.send_ActivateGroup(self.agent.agent_id, self.agent.session_id, self.GroupID)
def send_ActivateGroup(self, agent_id, session_id, group_id):
""" send an ActivateGroup message to the host simulator """
packet = Message('ActivateGroup',
Block('AgentData',
AgentID = agent_id,
SessionID = session_id,
GroupID = group_id))
self.agent.region.enqueue_message(packet)
def update_properties(self, properties):
""" takes a dictionary of attribute:value and makes it so """
for attribute in properties:
setattr(self, attribute, properties[attribute])
def request_join_group_chat(self):
""" sends an ImprovedInstantMessage packet with the atributes necessary to join a group chat """
log(INFO, "Requesting to join group chat session for \'%s\'" % (self.GroupName))
_AgentID = self.agent.agent_id
_SessionID = self.agent.session_id
_FromGroup = False
_ToAgentID = self.GroupID
_ParentEstateID = 0
_RegionID = UUID()
_Position = Vector3()
_Offline = 0
_Dialog = ImprovedIMDialogue.SessionGroupStart
_ID = self.GroupID
_Timestamp = 0
_FromAgentName = self.agent.Name()
_Message = 'Message'''
_BinaryBucket = ''
self.agent.send_ImprovedInstantMessage(_AgentID,
_SessionID,
_FromGroup,
_ToAgentID,
_ParentEstateID,
_RegionID,
_Position,
_Offline,
_Dialog,
_ID,
_Timestamp,
_FromAgentName,
_Message,
_BinaryBucket)
def chat(self, Message = None):
""" sends an instant message to another avatar
wraps send_ImprovedInstantMessage with some handy defaults """
if self.session_id == None:
self.request_join_group_chat()
Wait(5)
if self.session_id == None:
log(WARNING, "Failed to start chat session with group %s. Please try again later." % (self.GroupName))
return
if Message != None:
_ID = self.GroupID
_AgentID = self.agent.agent_id
_SessionID = self.agent.session_id
_FromGroup = False
_ToAgentID = self.GroupID
_ParentEstateID = 0
_RegionID = UUID()
_Position = Vector3() # don't send position, send uuid zero
_Offline = 0
_Dialog = ImprovedIMDialogue.SessionSend
_ID = self.GroupID
_Timestamp = 0
_FromAgentName = self.agent.Name() + "\x00" #struct.pack(">" + str(len(self.agent.Name)) + "c", *(self.agent.Name()))
_Message = Message + "\x00" #struct.pack(">" + str(len(Message)) + "c", *(Message))
_BinaryBucket = "\x00" # self.GroupName #struct.pack(">" + str(len(self.GroupName)) + "c", *(self.GroupName))
self.agent.send_ImprovedInstantMessage(_AgentID,
_SessionID,
_FromGroup,
_ToAgentID,
_ParentEstateID,
_RegionID,
_Position,
_Offline,
_Dialog,
_ID,
_Timestamp,
_FromAgentName,
_Message,
_BinaryBucket)
def handle_inbound_chat(self, message):
""" parses an incoming chat message from a group """
session_id = message.blocks['Message_Data'][0].get_variable('session_id').data
session_name = message.blocks['Message_Data'][0].get_variable('session_name').data
from_name = message.blocks['Message_Data'][0].get_variable('from_name').data
_message = message.blocks['Message_Data'][0].get_variable('instantmessage').data['message_params']['message']
self.chat_history.append(message)
# Todo: raise an app level event
log(INFO, "Group chat received. Group: %s From: %s Message: %s" % (session_name, from_name, _message))
class MockChatInterface(object):
""" a super simple chat interface for testing group chat in a console """
def __init__(self, agent, chat_handler):
self.agent = agent
self.chat_handler = chat_handler
self.old_settings = termios.tcgetattr(sys.stdin)
self.message = ''
def data_watcher(self):
return select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], [])
def start(self):
self.message = ''
try:
tty.setcbreak(sys.stdin.fileno())
while self.agent.running:
if self.data_watcher():
c = sys.stdin.read(1)
#print c
if c == '\x1b':
self.message = self.get_and_send_input()
#if c == '\x1b': # x1b is ESC
#self.chat_handler(c)
#break
#else:
#self.message += c
api.sleep()
except:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.old_settings)
#finally:
# termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.old_settings)
if self.agent.running:
self.start()
def get_and_send_input(self):
print "This is blocking in this implementation. Go fast, else get disconnected..."
self.message = raw_input("Enter Message to group")
self.chat_handler(self.message)
'''
class ChatterBoxInvitation_Message(object):
""" a group chat message sent over the event queue """
def __init__(self, session_name = None, from_name = None, session_id = None, _type = None, region_id = None, offline = None, timestamp = None, ttl = None, to_id = None, source = None, from_group = None, position = None, parent_estate_id = None, message = None, binary_bucket = None, _id = None, god_level = None, limited_to_estate = None, check_estate = None, agent_id = None, from_id = None, ChatterBoxInvitation_Data = None):
if ChatterBoxInvitation_Data != None:
self.session_name = ChatterBoxInvitation_Data['session_name']
self.from_name = ChatterBoxInvitation_Data['from_name']
self.session_id = UUID(string = str(ChatterBoxInvitation_Data['session_id']))
#self.from_name = ChatterBoxInvitation_Data['session_name']
self._type = ChatterBoxInvitation_Data['instantmessage']['message_params']['type']
self.region_id = UUID(string = str(ChatterBoxInvitation_Data['instantmessage']['message_params']['region_id']))
self.offline = ChatterBoxInvitation_Data['instantmessage']['message_params']['offline']
self.timestamp = ChatterBoxInvitation_Data['instantmessage']['message_params']['timestamp']
self.ttl = ChatterBoxInvitation_Data['instantmessage']['message_params']['ttl']
self.to_id = UUID(string = str(ChatterBoxInvitation_Data['instantmessage']['message_params']['to_id']))
self.source = ChatterBoxInvitation_Data['instantmessage']['message_params']['source']
self.from_group = ChatterBoxInvitation_Data['instantmessage']['message_params']['from_group']
self.position = ChatterBoxInvitation_Data['instantmessage']['message_params']['position']
self.parent_estate_id = ChatterBoxInvitation_Data['instantmessage']['message_params']['parent_estate_id']
self.message = ChatterBoxInvitation_Data['instantmessage']['message_params']['message']
self.binary_bucket = ChatterBoxInvitation_Data['instantmessage']['message_params']['data']['binary_bucket']
self._id = UUID(string = str(ChatterBoxInvitation_Data['instantmessage']['message_params']['id']))
#self.from_id = ChatterBoxInvitation_Data['instantmessage']['message_params']['from_id']
self.god_level = ChatterBoxInvitation_Data['instantmessage']['agent_params']['god_level']
self.limited_to_estate = ChatterBoxInvitation_Data['instantmessage']['agent_params']['limited_to_estate']
self.check_estate = ChatterBoxInvitation_Data['instantmessage']['agent_params']['check_estate']
self.agent_id = UUID(string = str(ChatterBoxInvitation_Data['instantmessage']['agent_params']['agent_id']))
self.from_id = UUID(string = str(ChatterBoxInvitation_Data['from_id']))
#self.message = ChatterBoxInvitation_Data['message']
self.name = 'ChatterBoxInvitation'
else:
self.session_name = session_name
self.from_name = from_name
self.session_id = session_id
#self.from_name = from_name
self._type = _type
self.region_id = region_id
self.offline = offline
self.timestamp = timestamp
self.ttl = ttl
self.to_id = to_id
self.source = source
self.from_group = from_group
self.position = position
self.parent_estate_id = parent_estate_id
self.message = message
self.binary_bucket = binary_bucket
self._id = _id
#self.from_id = from_id
self.god_level = god_level
self.limited_to_estate = limited_to_estate
self.check_estate = check_estate
self.agent_id = agent_id
self.from_id = from_id
#self.message = message
self.name = 'ChatterBoxInvitation'
class ChatterBoxSessionEventReply_Message(object):
def __init__(self, message_data):
self.success = message_data['success']
self.event = message_data['event']
self.session_id = UUID(string = str(message_data['session_id']))
self.error = message_data['error']
self.name = 'ChatterBoxSessionEventReply'
class ChatterBoxSessionAgentListUpdates_Message(object):
""" incomplete implementation"""
def __init__(self, message_data):
self.agent_updates = message_data['agent_updates']
self.session_id = UUID(string = str(message_data['session_id']))
self.name = 'ChatterBoxSessionAgentListUpdates'
#{'body': {'agent_updates': {'a517168d-1af5-4854-ba6d-672c8a59e439': {'info': {'can_voice_chat': True, 'is_moderator': False}}}, 'session_id': '4dd70b7f-8b3a-eef9-fc2f-909151d521f6', 'updates': {}}, 'message': 'ChatterBoxSessionAgentListUpdates'}]
class ChatterBoxSessionStartReply_Message(object):
""" incomplete implementation"""
def __init__(self, message_data):
self.temp_session_id = UUID(string = str(message_data['temp_session_id']))
self.success = message_data['success']
self.session_id = UUID(string = str(message_data['session_id']))
self.session_info = message_data['session_info']
self.name = "ChatterBoxSessionStartReply"
#{'body': {'temp_session_id': 4dd70b7f-8b3a-eef9-fc2f-909151d521f6, 'success': True, 'session_id': 4dd70b7f-8b3a-eef9-fc2f-909151d521f6, 'session_info': {'voice_enabled': True, 'session_name': "Enus' Construction Crew", 'type': 0, 'moderated_mode': {'voice': False}}}, 'message': 'ChatterBoxSessionStartReply'}],
'''

File diff suppressed because it is too large Load Diff

View File

@@ -1,448 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# standard python libs
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
import xmlrpclib
import re
import sys
# related
from indra.base import llsd
# pyogp
from pyogp.lib.base.exc import LoginError, ParseStartLocError, HTTPError, ResourceError, ResourceNotFound
from pyogp.lib.base.tests.mock_xmlrpc import MockXMLRPC
from pyogp.lib.base.tests.base import MockXMLRPCLogin
from pyogp.lib.base.network.stdlib_client import StdLibClient
# initialize globals
logger = getLogger('login')
log = logger.log
class Login(object):
""" logs into a login endpoint
There are 2 cases here: 'legacy' login and 'OGP' login.
Legacy = standard Second Life/OpenSim login
OGP = Open Grid Protocol enabled grid, where one logs into an agent domain
Example (legacy oriented):
The login type is determined by parsing the login uri
'legacy' = login.cgi
'ogp' = auth.cgi
Initialize the login class
>>> login = Login()
Setup some login parameters.
>>> login_params = LegacyLoginParams('firstname', 'lastname', 'password')
>>> login_params = login_params.serialize()
login stores & returns the response from the loginuri (in our example a mock response)
>>> login.login('http://localhost:12345/login.cgi', login_params, 'region')
{'login': 'true', 'seed_capability': 'http://127.0.0.1:12345/seed_cap'}
>>> login.response['login']
true
Sample implementations: examples/sample_login.py
Tests: tests/login.txt, tests/test_legacy_login.py, tests/test_ogp_login.py
"""
def __init__(self, settings = None, handler = None):
""" initialize the login object """
# allow the settings to be passed in
# otherwise, grab the defaults
if settings != None:
self.settings = settings
else:
from pyogp.lib.base.settings import Settings
self.settings = Settings()
# this can be either 'legacy' or 'ogp'
self.type = None
# storage containers for login attributes
self.loginuri = None
self.login_params = {}
self.input_params = {}
self.start_location = None
# this will hold the reponse from the loginuri
self.response = None
# holds the transform response if there is one
self.transform_response = None
# if we are testing, we can initialize a mock handler
self.handler = None
if self.settings.LOG_VERBOSE: log(INFO, 'Initializing login')
def login(self, loginuri = None, login_params = None, start_location = None, handler = None):
""" high level login initiator, returns the login response as a dict"""
if (re.search('auth.cgi$', loginuri)):
self.type = 'ogp'
# prep the login parameters object
self._init_ogp_login_params(loginuri, login_params, start_location)
if handler == None and self.handler == None:
self.handler = StdLibClient()
else:
self.handler = handler
self._post_to_ogp_loginuri()
elif (re.search('login.cgi$', loginuri)):
self.type = 'legacy'
# prep the login parameters object
self._init_legacy_login_params(loginuri, login_params, start_location)
# handler can be a mock endpoint for testing, otherwise it's xmlrpc
if handler == None and self.handler == None:
# If we are running normally, we need xmlrpc for legacy login
self._init_legacy_login_handler(self.loginuri)
else:
self.handler = handler
self._post_to_legacy_loginuri()
else:
log(WARNING, 'Unknown loginuri type: %s' % (self.loginuri))
raise LoginError('Unknown loginuri type: %s' % (self.loginuri))
return self.response
def _init_legacy_login_handler(self, loginuri):
""" sets up the xmlrpc handler """
# MockXMLRPC is the test handler, retain it
if type(self.handler) == type(MockXMLRPC(MockXMLRPCLogin(), self.loginuri)):
pass
else:
self.handler = xmlrpclib.ServerProxy(self.loginuri)
def _init_legacy_login_params(self, loginuri = None, login_params = None, start_location = None):
""" prepares the login attributes for submission """
if (loginuri != None):
self.loginuri = loginuri
if (login_params != None):
# now store the account data
self.login_params = login_params.serialize()
# store the input params
self.input_params['firstname'] = self.login_params['first']
self.input_params['lastname'] = self.login_params['last']
self.input_params['password'] = self.login_params['passwd']
if (start_location != None):
self.start_location = self._parse_legacy_start_location(start_location)
else:
self.start_location = self.settings.DEFAULT_START_LOCATION
self.login_params['start'] = self.start_location
# add some additonal details to the login_params based on what is specified in settings
# do not overwrite specified settings
self._get_extended_legacy_params()
def _init_ogp_login_params(self, loginuri = None, login_params = None, start_location = None):
""" prepares the login attributes for submission """
if (loginuri != None):
self.loginuri = loginuri
if (login_params != None):
# we use content_type for http calls here
self.content_type = login_params.content_type
# now store the account data
self.login_params = login_params.serialize()
# store the input params
self.input_params['firstname'] = login_params.firstname
self.input_params['lastname'] = login_params.lastname
self.input_params['password'] = login_params.password
if (start_location != None):
self.start_location = start_location
else:
self.start_location = self.settings.DEFAULT_START_LOCATION
def _post_to_legacy_loginuri(self, loginuri = None, login_params = None, login_method = 'login_to_simulator'):
""" post to a login uri and return the results """
if loginuri != None:
self.loginuri = loginuri
if login_params != None:
self.login_params = login_params.serialize()
self._init_legacy_login_handler(loginuri)
log(INFO, 'Logging \'%s %s\' into %s with method: %s' % (self.login_params['first'], self.login_params['last'], self.loginuri, login_method))
if self.settings.LOG_VERBOSE: log(DEBUG, '\'%s %s\' has the following login parameters: %s' % (self.login_params['first'], self.login_params['last'], self.login_params))
# This handles the standard 'login_to_simulator' case
# plus, all the transforms that may need to be followed
login_handler = self.handler.__getattr__(login_method)
try:
self.response = login_handler(self.login_params)
except Exception, error:
raise LoginError('Failed to login agent due to: %s' % (error))
if self.response['login'] in ('true', 'false'):
self._parse_response()
else:
# handle transformation
self._handle_transform(self.response)
def _handle_transform(self, transform):
""" follows a transform """
if self.settings.LOG_VERBOSE: log(DEBUG, 'Login response for \'%s %s\' is: %s' % (self.input_params['firstname'], self.input_params['lastname'], transform))
# store the response in the transform response attribute
self.transform_response = transform
log(INFO, 'Following a login redirect to %s with method: %s. Message: %s' % (transform['next_url'], transform['next_method'], transform['message']))
self._post_to_legacy_loginuri(loginuri = transform['next_url'], login_method = transform['next_method'])
def _get_extended_legacy_params(self):
""" get the extra bits needed for login """
# do not overwrite existing settings
default_login_params = self.settings.get_default_xmlrpc_login_parameters()
if not self.login_params.has_key('channel'): self.login_params['channel'] = default_login_params['channel']
if not self.login_params.has_key('version'): self.login_params['version'] = default_login_params['version']
if not self.login_params.has_key('mac'): self.login_params['mac'] = default_login_params['mac']
if not self.login_params.has_key('agree_to_tos'): self.login_params['agree_to_tos'] = default_login_params['agree_to_tos']
if not self.login_params.has_key('read_critical'): self.login_params['read_critical'] = default_login_params['read_critical']
if not self.login_params.has_key('id0'): self.login_params['id0'] = default_login_params['id0']
if not self.login_params.has_key('options'): self.login_params['options'] = default_login_params['options']
log(DEBUG, 'Initializing login parameters for \'%s %s\'' % (self.login_params['first'], self.login_params['last']))
def _parse_response(self):
""" evaluates the data contained in the login response
This is just a lot of logging for the most part...
"""
if self.type == 'legacy':
if self.settings.LOG_VERBOSE: log(DEBUG, 'Login response for \'%s %s\' is: %s' % (self.input_params['firstname'], self.input_params['lastname'], self.response))
if self.response['login'] == 'true':
log(INFO, 'Logged in \'%s %s\'' % (self.input_params['firstname'], self.input_params['lastname']))
if self.response.has_key('message'): log(INFO, 'Login message: %s' % (self.response['message']))
elif self.response == None:
log(WARNING, 'Failed to login \'%s %s\' due to %s' % (self.input_params['firstname'], self.input_params['lastname'], 'empty response from loginuri'))
raise LoginError('Failed login due to empty response from loginuri')
elif self.response['login'] == 'false':
log(WARNING, 'Failed login for \'%s %s\', Reason: %s' % (self.input_params['firstname'], self.input_params['lastname'], self.response['message']))
raise LoginError('Failed login due to: %s' % (self.response['message']))
else:
raise LoginError('Unknown error during login')
elif self.type == 'ogp':
if self.settings.LOG_VERBOSE: log(DEBUG, 'Login response for \'%s %s\' is: %s' % (self.input_params['firstname'], self.input_params['lastname'], self.response.body))
if self.response == None:
log(WARNING, 'Failed to login \'%s %s\' due to %s' % (self.input_params['firstname'], self.input_params['lastname'], 'empty response from loginuri'))
raise LoginError('Failed login due to empty response from loginuri')
elif self.response._status == '200 OK':
self.response = llsd.parse(self.response.body)
if self.response['authenticated']:
log(INFO, 'Logged in \'%s %s\'' % (self.input_params['firstname'], self.input_params['lastname']))
elif not self.response['authenticated']:
log(WARNING, 'Failed login for \'%s %s\', Reason: %s' % (self.input_params['firstname'], self.input_params['lastname'], self.response['message']))
raise LoginError('Failed login due to: %s' % (self.response['message']))
else:
raise LoginError('Unknown error during login')
else:
return
def _parse_legacy_start_location(self, start_location):
""" make sure a user specified start location is in the correct form """
# for now, we accept a region name, or a tuple containing region name, x, y, z
# x, y, and z must be integers
if type(start_location) == tuple:
try:
return 'uri:%s&%i&%i&%i' % (start_location[0], start_location[1], start_location[2], start_location[3])
except IndexError, error:
log(WARNING, 'Invalid start_location specified (%s), using default of \'%s\'' % (start_location, self.settings.DEFAULT_START_LOCATION))
return self.settings.DEFAULT_START_LOCATION
except TypeError, error:
log(WARNING, 'Invalid start_location specified (%s), using default of \'%s\'' % (start_location, self.settings.DEFAULT_START_LOCATION))
return self.settings.DEFAULT_START_LOCATION
elif type(start_location) == str and re.match("uri:", start_location[0:4].lower()):
location = start_location.split(":")[1]
mg = location.split('&',3)
# try forcing to ints
if len(mg) == 4:
return 'uri:%s&%i&%i&%i' % (mg[0],int(mg[1]),int(mg[2]),int(mg[3]))
elif len(mg) == 3:
return 'uri:%s&%i&%i&30' % (mg[0],int(mg[1]),int(mg[2]))
elif len(mg) == 2:
return 'uri:%s&%i&128&30' % (mg[0],int(mg[1]))
elif len(mg) == 1:
return 'uri:%s&128&128&30' % mg[0]
else:
return self.settings.DEFAULT_START_LOCATION
elif type(start_location) == str:
mg = start_location.split('/',3)
# try forcing to ints
if len(mg) == 4:
return 'uri:%s&%i&%i&%i' % (mg[0],int(mg[1]),int(mg[2]),int(mg[3]))
elif len(mg) == 3:
return 'uri:%s&%i&%i&30' % (mg[0],int(mg[1]),int(mg[2]))
elif len(mg) == 2:
return 'uri:%s&%i&128&30' % (mg[0],int(mg[1]))
elif len(mg) == 1:
return 'uri:%s&128&128&30' % mg[0]
else:
return self.settings.DEFAULT_START_LOCATION
else:
# if we cannot make sense of what is passed in, use the settings default
return self.settings.DEFAULT_START_LOCATION
def _post_to_ogp_loginuri(self, loginuri = None, login_params = None, start_location = None):
""" logs in to an agent domain's loginuri """
if loginuri != None:
self.loginuri = loginuri
# we expect an OGPLoginParams object here
if login_params != None:
self.login_params = login_params.serialize()
# store the input params
for k in self.login_params:
self.input_params[k] = login_params[k]
headers = {'Content-Type': self.content_type}
log(INFO, 'Logging in to %s as %s %s' % (self.loginuri, self.input_params['firstname'], self.input_params['lastname']))
if self.settings.LOG_VERBOSE: log(DEBUG, '\'%s %s\' has the following login parameters: %s with headers of: %s' % (self.input_params['firstname'], self.input_params['lastname'], self.login_params, headers))
try:
self.response = self.handler.POST(self.loginuri, self.login_params, headers=headers)
self._parse_response()
except HTTPError, error:
if error.code==404:
raise ResourceNotFound(self.login_uri)
else:
raise ResourceError(self.loginuri, error.code, error.msg, error.fp.read(), method="POST")
class LegacyLoginParams(object):
""" a legacy plain password credential """
def __init__(self, firstname, lastname, password):
""" initialize this credential """
self.firstname = firstname
self.lastname = lastname
self.password = password
def __repr__(self):
""" return a string representation """
return 'Legacy login instance for \'%s %s\'' %(self.firstname, self.lastname)
def serialize(self):
""" return a dictionary of login params """
login_params = {
'first': self.firstname,
'last': self.lastname,
'passwd': self.password
}
return login_params
class OGPLoginParams(object):
""" an OGP plain password credential """
def __init__(self, firstname, lastname, password):
""" initialize this credential """
self.firstname = firstname
self.lastname = lastname
self.password = password
self.content_type = 'application/llsd+xml'
def __repr__(self):
""" return a string representation """
return 'OGP login parameters for \'%s %s\'' % (self.firstname, self.lastname)
def serialize(self):
""" return a dictionary of login params """
login_params = {
'firstname': self.firstname,
'lastname': self.lastname,
'password': self.password
}
llsd_params = llsd.format_xml(login_params)
return llsd_params

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,65 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# standard python libs
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
# pyogp
# pyogp messaging
# initialize logging
logger = getLogger('pyogp.lib.base.permissions')
log = logger.log
class PermissionsMask(object):
""" permissions flags mappings """
# the types of permissions
Transfer = 1 << 13 # 0x00002000
Modify = 1 << 14 # 0x00004000
Copy = 1 << 15 # 0x00008000
Move = 1 << 19 # 0x00080000
_None = 0 # 0x00000000
All = 0x7FFFFFFF
# Reserved
#Unrestricted = Modify | Copy | Transfer
class PermissionsTarget(object):
""" who the permissions apply to """
Base = 0x01
Owner = 0x02
Group = 0x04
Everyone = 0x08
NextOwner = 0x10
class Permissions(object):
""" class representing the permissions of an object or inventory item """
def __init__(self, BaseMask = None, OwnerMask = None, GroupMask = None, EveryoneMask = None, NextOwnerMask = None):
""" store the values of the various targets permissions """
self.BaseMask = BaseMask
self.OwnerMask = OwnerMask
self.GroupMask = GroupMask
self.EveryoneMask = EveryoneMask
self.NextOwnerMask = NextOwnerMask

View File

@@ -1,627 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
# std lib
from logging import getLogger, ERROR, INFO, DEBUG
import time
# related
from indra.base import llsd
from eventlet import api
# pyogp
from pyogp.lib.base.caps import Capability
from pyogp.lib.base.network.stdlib_client import StdLibClient, HTTPError
from pyogp.lib.base.exc import ResourceNotFound, ResourceError, RegionSeedCapNotAvailable, RegionMessageError
from pyogp.lib.base.settings import Settings
from pyogp.lib.base.utilities.helpers import Helpers
from pyogp.lib.base.event_queue import EventQueueClient
from pyogp.lib.base.objects import ObjectManager
from pyogp.lib.base.datatypes import UUID
from pyogp.lib.base.event_system import AppEventsHandler
from pyogp.lib.base.parcel import ParcelManager
# messaging
from pyogp.lib.base.message.udpdispatcher import UDPDispatcher
from pyogp.lib.base.message.circuit import Host
from pyogp.lib.base.message.message import Message, Block
from pyogp.lib.base.message.message_handler import MessageHandler
# utilities
from pyogp.lib.base.utilities.helpers import Wait
# initialize logging
logger = getLogger('pyogp.lib.base.region')
log = logger.log
class Region(object):
""" a region container
The Region class is a container for region specific data.
It is also a nice place for convenience code.
Example, of initializing a region class:
Initialize the login class
>>> region = Region(256, 256, 'https://somesim.cap/uuid', 'EnableSimulator,TeleportFinish,CrossedRegion', '127.0.0.1', 13000, 650000000, {'agent_id':'00000000-0000-0000-0000-000000000000', 'session_id':'00000000-0000-0000-0000-000000000000', 'secure_session_id:'00000000-0000-0000-0000-000000000000'})
Start the udp and event queue connections to the region
>>> region.connect()
Sample implementations: examples/sample_region_connect.py
Tests: tests/region.txt, tests/test_region.py
"""
def __init__(self, global_x = 0, global_y = 0, seed_capability_url = None, udp_blacklist = None, sim_ip = None, sim_port = None, circuit_code = None, agent = None, settings = None, message_handler = None, handle = None, events_handler = None):
""" initialize a region """
# allow the settings to be passed in
# otherwise, grab the defaults
if settings != None:
self.settings = settings
else:
self.settings = Settings()
# allow the packet_handler to be passed in
# otherwise, grab the defaults
if message_handler != None:
self.message_handler = message_handler
#elif self.settings.HANDLE_PACKETS:
else:
self.message_handler = MessageHandler()
# allow the eventhandler to be passed in
# so that applications running multiple avatars
# may use the same eventhandler
# otherwise, let's just use our own
if events_handler != None:
self.events_handler = events_handler
else:
self.events_handler = AppEventsHandler()
# initialize the init params
self.global_x = int(global_x)
self.global_y = int(global_y)
self.grid_x = self.global_x/256
self.grid_y = self.global_y/256
self.seed_capability_url = seed_capability_url
self.udp_blacklist = udp_blacklist
self.sim_ip = sim_ip
self.sim_port = sim_port
self.circuit_code = circuit_code
self.agent = agent # an agent object
self.handle = handle
self.is_host_region = False
# UDP connection information
if (self.sim_ip != None) and (self.sim_port != None):
self.messenger = UDPDispatcher(settings = self.settings, message_handler = self.message_handler, region = self)
self.host = Host((self.sim_ip, self.sim_port))
else:
self.host = None
# other attributes
self.RegionHandle = None # from AgentMovementComplete
self.SimName = None
self.seed_capability = None
self.capabilities = {}
self.event_queue = None
self.connected = False
self.helpers = Helpers()
self._isUDPRunning = False
self._isEventQueueRunning = False
# data storage containers
self.packet_queue = []
self.objects = ObjectManager(agent = self.agent, region = self, settings = self.settings, message_handler = self.message_handler, events_handler = self.events_handler)
self.parcel_manager = ParcelManager(agent = self.agent, region = self, settings = self.settings, message_handler = self.message_handler, events_handler = self.events_handler)
# required packet handlers
onPacketAck_received = self.message_handler.register('PacketAck')
onPacketAck_received.subscribe(self.helpers.null_packet_handler, self)
# data we need
self.region_caps_list = ['ChatSessionRequest',
'CopyInventoryFromNotecard',
'DispatchRegionInfo',
'EstateChangeInfo',
'EventQueueGet',
'FetchInventory',
'WebFetchInventoryDescendents',
'FetchLib',
'FetchLibDescendents',
'GroupProposalBallot',
'HomeLocation',
'MapLayer',
'MapLayerGod',
'NewFileAgentInventory',
'ParcelPropertiesUpdate',
'ParcelVoiceInfoRequest',
'ProvisionVoiceAccountRequest',
'RemoteParcelRequest',
'RequestTextureDownload',
'SearchStatRequest',
'SearchStatTracking',
'SendPostcard',
'SendUserReport',
'SendUserReportWithScreenshot',
'ServerReleaseNotes',
'StartGroupProposal',
'UpdateAgentLanguage',
'UpdateGestureAgentInventory',
'UpdateNotecardAgentInventory',
'UpdateScriptAgent',
'UpdateGestureTaskInventory',
'UpdateNotecardTaskInventory',
'UpdateScriptTask',
'ViewerStartAuction',
'UntrustedSimulatorMessage',
'ViewerStats'
]
if self.settings.LOG_VERBOSE:
log(DEBUG, 'initializing region domain: %s' %self)
def enable_callbacks(self):
'''enables the callback handles for this Region'''
if self.settings.ENABLE_OBJECT_TRACKING:
self.objects.enable_callbacks()
if self.settings.ENABLE_PARCEL_TRACKING:
self.parcel_manager.enable_callbacks()
if self.settings.HANDLE_PACKETS:
pass
def enable_child_simulator(self, IP, Port, Handle):
log(INFO, "Would enable a simulator at %s:%s with a handle of %s" % (IP, Port, Handle))
def send_message_next(self, packet, reliable = False):
""" inserts this packet at the fron of the queue """
#if str(type(packet)) != '<class \'pyogp.lib.base.message.message.Message\'>':
#packet = packet()
self.packet_queue.insert(0, (packet, reliable))
def enqueue_message(self, packet, reliable = False):
""" queues packets for the messaging system to send """
#if str(type(packet)) != '<class \'pyogp.lib.base.message.message.Message\'>':
#packet = packet()
self.packet_queue.append((packet, reliable))
def send_message(self, packet, reliable = False):
""" send a packet to the host """
#if str(type(packet)) != '<class \'pyogp.lib.base.message.message.Message\'>':
#packet = packet()
if self.host == None or self.messenger == None:
raise RegionMessageError(self)
else:
if reliable == False:
self.messenger.send_message(packet, self.host)
else:
self.messenger.send_reliable(packet, self.host, 0)
def send_reliable(self, packet):
""" send a reliable packet to the host """
#if str(type(packet)) != '<class \'pyogp.lib.base.message.message.Message\'>':
#packet = packet()
if self.host == None or self.messenger == None:
raise RegionMessageError(self)
else:
self.messenger.send_reliable(packet, self.host, 0)
def _set_seed_capability(self, url = None):
""" sets the seed_cap attribute as a RegionSeedCapability instance """
if url != None:
self.seed_capability_url = url
self.seed_cap = RegionSeedCapability('seed_cap', self.seed_capability_url, settings = self.settings)
if self.settings.LOG_VERBOSE:
log(DEBUG, 'setting region domain seed cap: %s' % (self.seed_capability_url))
def _get_region_public_seed(self, custom_headers={'Accept' : 'application/llsd+xml'}):
""" call this capability, return the parsed result """
if self.settings.ENABLE_CAPS_LOGGING:
log(DEBUG, 'Getting region public_seed %s' %(self.region_uri))
try:
restclient = StdLibClient()
response = restclient.GET(self.region_uri, custom_headers)
except HTTPError, e:
if e.code == 404:
raise ResourceNotFound(self.region_uri)
else:
raise ResourceError(self.region_uri, e.code, e.msg, e.fp.read(), method="GET")
data = llsd.parse(response.body)
if self.settings.ENABLE_CAPS_LOGGING:
log(DEBUG, 'Get of cap %s response is: %s' % (self.region_uri, data))
return data
def _get_region_capabilities(self):
""" queries the region seed cap for capabilities """
if (self.seed_cap == None):
raise RegionSeedCapNotAvailable("querying for agent capabilities")
else:
if self.settings.ENABLE_CAPS_LOGGING:
log(INFO, 'Getting caps from region seed cap %s' % (self.seed_cap))
# use self.region_caps.keys() to pass a list to be parsed into LLSD
self.capabilities = self.seed_cap.get(self.region_caps_list, self.settings)
def connect(self):
""" connect to the udp circuit code and event queue"""
self.enable_callbacks()
# if this is the agent's host region, spawn the event queue
# spawn an eventlet api instance that runs the event queue connection
if self.seed_capability_url != None:
# set up the seed capability
self._set_seed_capability()
# grab the agent's capabilities from the sim
self._get_region_capabilities()
log(DEBUG, 'Spawning region event queue connection')
self._startEventQueue()
# send the first few packets necessary to establish presence
self._init_agent_in_region()
self.last_ping = 0
# spawn an eventlet api instance that runs the UDP connection
log(DEBUG, 'Spawning region UDP connection')
if self.settings.LOG_COROUTINE_SPAWNS:
log(INFO, "Spawning a coroutine for udp connection to the agent's host region %s" % (str(self.sim_ip) + ":" + str(self.sim_port)))
api.spawn(self._processUDP)
log(DEBUG, "Spawned region data connections")
def connect_child(self):
""" connect to the a child region udp circuit code """
# send the UseCircuitCode packet
self.sendUseCircuitCode(self.circuit_code, self.agent.session_id, self.agent.agent_id)
self.last_ping = 0
# spawn an eventlet api instance that runs the UDP connection
log(DEBUG, 'Spawning region UDP connection for child region %s' % (str(self.sim_ip) + ":" + str(self.sim_port)))
if self.settings.LOG_COROUTINE_SPAWNS:
log(INFO, "Spawning a coroutine for udp connection to the agent's child region %s" % (str(self.sim_ip) + ":" + str(self.sim_port)))
api.spawn(self._processUDP)
def logout(self):
""" send a logout packet """
log(INFO, "Disconnecting from region %s" % (self.SimName))
try:
self.send_LogoutRequest(self.agent.agent_id, self.agent.session_id)
# ToDo: We should parse a response packet prior to really disconnecting
Wait(1)
self._isUDPRunning = False
self._stopEventQueue()
return True
except Exception, error:
log(ERROR, "Error logging out from region.")
return False
def send_LogoutRequest(self, agent_id, session_id):
""" send a LogoutRequest message to the host simulator """
packet = Message('LogoutRequest',
Block('AgentData',
AgentID = agent_id,
SessionID = session_id))
self.send_message(packet)
def kill_coroutines(self):
""" trigger to end processes spawned by the child regions """
self._isUDPRunning = False
self._stopEventQueue()
def _init_agent_in_region(self):
""" send a few packets to set things up """
# send the UseCircuitCode packet
self.sendUseCircuitCode(self.circuit_code, self.agent.session_id, self.agent.agent_id)
# wait a sec, then send the rest
time.sleep(1)
# send the CompleteAgentMovement packet
self.sendCompleteAgentMovement(self.agent.agent_id, self.agent.session_id, self.circuit_code)
# send a UUIDNameRequest packet
#self.sendUUIDNameRequest()
# send an AgentUpdate packet to complete the loop
self.sendAgentUpdate(self.agent.agent_id, self.agent.session_id)
def sendUseCircuitCode(self, circuit_code, session_id, agent_id):
""" initializing on a simulator requires announcing the circuit code an agent will use """
packet = Message('UseCircuitCode',
Block('CircuitCode',
Code = circuit_code,
SessionID = session_id,
ID = agent_id))
self.send_reliable(packet)
def sendCompleteAgentMovement(self, agent_id, session_id, circuit_code):
""" initializing on a simulator requires sending CompleteAgentMovement, also required on teleport """
packet = Message('CompleteAgentMovement',
Block('AgentData',
AgentID = agent_id,
SessionID = session_id,
CircuitCode = circuit_code))
self.send_reliable(packet)
def sendUUIDNameRequest(self, agent_ids = []):
""" sends a packet requesting the name corresponding to a UUID """
packet = Message('UUIDNameRequest',
*[Block('UUIDNameBlock',
ID = agent_id) for agent_id in agent_ids])
self.send_message(packet)
def sendAgentUpdate(self,
AgentID,
SessionID,
BodyRotation = (0.0,0.0,0.0,1.0),
HeadRotation = (0.0,0.0,0.0,1.0),
State = 0x00,
CameraCenter = (0.0,0.0,0.0),
CameraAtAxis = (0.0,0.0,0.0),
CameraLeftAxis = (0.0,0.0,0.0),
CameraUpAxis = (0.0,0.0,0.0),
Far = 0,
ControlFlags = 0x00,
Flags = 0x00):
""" sends an AgentUpdate packet to *this* simulator"""
packet = Message('AgentUpdate',
Block('AgentData',
AgentID = AgentID,
SessionID = SessionID,
BodyRotation = BodyRotation,
HeadRotation = HeadRotation,
State = State,
CameraCenter = CameraCenter,
CameraAtAxis = CameraAtAxis,
CameraLeftAxis = CameraLeftAxis,
CameraUpAxis = CameraUpAxis,
Far = Far,
ControlFlags = ControlFlags,
Flags = Flags))
self.send_message(packet)
def sendRegionHandshakeReply(self, AgentID, SessionID, Flags = 00):
""" sends a RegionHandshake packet """
packet = Message('RegionHandshakeReply',
Block('AgentData',
AgentID = AgentID,
SessionID = SessionID),
Block('RegionInfo',
Flags = Flags))
self.send_reliable(packet)
def sendCompletePingCheck(self, PingID):
""" sends a CompletePingCheck packet """
packet = Message('CompletePingCheck',
Block('PingID',
PingID = PingID))
self.send_message(packet)
# we need to increment the last ping id
self.last_ping += 1
def _processUDP(self):
""" check for packets and handle certain cases """
self._isUDPRunning = True
# the RegionHandshake packet requires a response
onRegionHandshake_received = self.message_handler.register('RegionHandshake')
onRegionHandshake_received.subscribe(self.onRegionHandshake)
# the StartPingCheck packet requires a response
onStartPingCheck_received = self.message_handler.register('StartPingCheck')
onStartPingCheck_received.subscribe(self.onStartPingCheck)
while self._isUDPRunning:
# free up resources for other stuff to happen
api.sleep(0)
# check for new messages
msg_buf, msg_size = self.messenger.udp_client.receive_packet(self.messenger.socket)
self.messenger.receive_check(self.messenger.udp_client.get_sender(),
msg_buf, msg_size)
if self.messenger.has_unacked():
self.messenger.process_acks()
# if this region is the host region, send agent updates
if self.is_host_region:
# pull the camera back a bit, 20m
# we are currently facing east, so pull back on the x axis
CameraCenter = (self.agent.Position.X - 20.0, self.agent.Position.Y, self.agent.Position.Z)
self.sendAgentUpdate(self.agent.agent_id, self.agent.session_id, CameraCenter = CameraCenter, CameraAtAxis = self.settings.DEFAULT_CAMERA_AT_AXIS, CameraLeftAxis = self.settings.DEFAULT_CAMERA_AT_AXIS, CameraUpAxis = self.settings.DEFAULT_CAMERA_UP_AXIS, Far = self.settings.DEFAULT_CAMERA_DRAW_DISTANCE)
# send pending messages in the queue
for (packet, reliable) in self.packet_queue:
self.send_message(packet, reliable)
self.packet_queue.remove((packet, reliable))
log(DEBUG, "Stopped the UDP connection for %s" % (self.SimName))
def _startEventQueue(self):
""" polls the event queue capability and parses the results """
self.event_queue = EventQueueClient(self.capabilities['EventQueueGet'], settings = self.settings, message_handler = self.message_handler, region = self)
api.spawn(self.event_queue.start)
self._isEventQueueRunning = True
def _stopEventQueue(self):
""" shuts down the running event queue """
if self._isEventQueueRunning == True and self.event_queue._running == True:
self.event_queue.stop()
def onRegionHandshake(self, packet):
""" handles the response to receiving a RegionHandshake packet """
# send the reply
self.sendRegionHandshakeReply(self.agent.agent_id, self.agent.session_id)
# propagate the incoming data
self.SimName = packet.blocks['RegionInfo'][0].get_variable('SimName').data
self.SimAccess = packet.blocks['RegionInfo'][0].get_variable('SimAccess').data
self.SimOwner = packet.blocks['RegionInfo'][0].get_variable('SimOwner').data
self.IsEstateManager = packet.blocks['RegionInfo'][0].get_variable('IsEstateManager').data
self.WaterHeight = packet.blocks['RegionInfo'][0].get_variable('WaterHeight').data
self.BillableFactor = packet.blocks['RegionInfo'][0].get_variable('BillableFactor').data
self.TerrainBase0 = packet.blocks['RegionInfo'][0].get_variable('TerrainBase0').data
self.TerrainBase1 = packet.blocks['RegionInfo'][0].get_variable('TerrainBase1').data
self.TerrainBase2 = packet.blocks['RegionInfo'][0].get_variable('TerrainBase2').data
self.TerrainStartHeight00 = packet.blocks['RegionInfo'][0].get_variable('TerrainStartHeight00').data
self.TerrainStartHeight01 = packet.blocks['RegionInfo'][0].get_variable('TerrainStartHeight01').data
self.TerrainStartHeight10 = packet.blocks['RegionInfo'][0].get_variable('TerrainStartHeight10').data
self.TerrainStartHeight11 = packet.blocks['RegionInfo'][0].get_variable('TerrainStartHeight11').data
self.TerrainHeightRange00 = packet.blocks['RegionInfo'][0].get_variable('TerrainHeightRange00').data
self.TerrainHeightRange01 = packet.blocks['RegionInfo'][0].get_variable('TerrainHeightRange01').data
self.TerrainHeightRange10 = packet.blocks['RegionInfo'][0].get_variable('TerrainHeightRange10').data
self.TerrainHeightRange11 = packet.blocks['RegionInfo'][0].get_variable('TerrainHeightRange11').data
self.CPUClassID = packet.blocks['RegionInfo3'][0].get_variable('CPUClassID').data
self.CPURatio = packet.blocks['RegionInfo3'][0].get_variable('CPURatio').data
self.ColoName = packet.blocks['RegionInfo3'][0].get_variable('ColoName').data
self.ProductSKU = packet.blocks['RegionInfo3'][0].get_variable('ProductSKU').data
self.ProductName = packet.blocks['RegionInfo3'][0].get_variable('ProductName').data
self.RegionID = packet.blocks['RegionInfo2'][0].get_variable('RegionID').data
# we are connected
self.connected = True
log(INFO, "Connected agent \'%s %s\' to region %s" % (self.agent.firstname, self.agent.lastname, self.SimName))
def onStartPingCheck(self, packet):
""" sends the CompletePingCheck packet """
self.sendCompletePingCheck(self.last_ping)
@staticmethod
def xy_to_handle(x, y):
"""Convert an x, y region location into a 64-bit handle"""
return (int(x)*256 << 32) + int(y)*256
@staticmethod
def handle_to_xy(handle):
"""Convert a handle into an x,y region location. Handle can be an int or binary string."""
import struct
if isinstance(handle, str):
handle = struct.unpack('Q', handle)[0]
x = int((handle >> 32)/256)
y = int((handle & 0xffffffff)/256)
return x, y
class RegionSeedCapability(Capability):
""" a seed capability which is able to retrieve other capabilities """
def get(self, names=[], settings = None):
"""if this is a seed cap we can retrieve other caps here"""
# allow the settings to be passed in
# otherwise, grab the defaults
if settings != None:
self.settings = settings
else:
from pyogp.lib.base.settings import Settings
self.settings = Settings()
#log(INFO, 'requesting from the region domain the following caps: %s' % (names))
payload = names
parsed_result = self.POST(payload) #['caps']
if self.settings.ENABLE_CAPS_LOGGING:
log(INFO, 'Request for caps returned: %s' % (parsed_result.keys()))
caps = {}
for name in names:
# TODO: some caps might be seed caps, how do we know?
if parsed_result.has_key(name):
caps[name] = Capability(name, parsed_result[name], settings = self.settings)
else:
if self.settings.ENABLE_CAPS_LOGGING:
log(DEBUG, 'Requested capability \'%s\' is not available' % (name))
#log(INFO, 'got cap: %s' % (name))
return caps
def __repr__(self):
return "<RegionSeedCapability for %s>" % (self.public_url)

View File

@@ -1,539 +0,0 @@
"""
Contributors can be viewed at:
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/trunk/CONTRIBUTORS.txt
$LicenseInfo:firstyear=2008&license=apachev2$
Copyright 2009, Linden Research, Inc.
Licensed under the Apache License, Version 2.0.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
or in
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/lib/base/LICENSE.txt
$/LicenseInfo$
"""
class Param(object):
"""
a visual parameter of an agent
"""
def __init__(self, id, group, name, wearable, value_default, value_min,
value_max, value, label, label_min, label_max):
self.id = id
self.group = group
self.name = name
self.wearable = wearable
self.value_default = float(value_default)
self.value_min = float(value_min)
self.value_max = float(value_max)
self.value = float(value)
self.label = label
self.label_min = label_min
self.label_max = label_max
def floatToByte(self):
"""
Converts value from a float to a byte
"""
result = self.value - self.value_min
result /= self.value_max - self.value_min
return int(255*result)
def byteToFloat(self, val):
"""
Converts val from a byte to a float and stores its to value
"""
result = val * (1.0/255)
result *= self.value_max - self.value_min
result += self.value_min
self.value = round(result, 3)
class VisualParams(object):
"""
The visual params of an agent
"""
params = {}
def __init__(self):
self.params[1] = Param(1, 0, u'Big_Brow', u'shape', 0.0, -.3, 2, 0.0, u'Brow Size', u'Small', u'Large')
self.params[2] = Param(2, 0, u'Nose_Big_Out', u'shape', 0.0, -0.8, 2.5, 0.0, u'Nose Size', u'Small', u'Large')
self.params[4] = Param(4, 0, u'Broad_Nostrils', u'shape', 0.0, -.5, 1, 0.0, u'Nostril Width', u'Narrow', u'Broad')
self.params[5] = Param(5, 0, u'Cleft_Chin', u'shape', 0.0, -.1, 1, 0.0, u'Chin Cleft', u'Round', u'Cleft')
self.params[6] = Param(6, 0, u'Bulbous_Nose_Tip', u'shape', 0.0, -.3, 1, 0.0, u'Nose Tip Shape', u'Pointy', u'Bulbous')
self.params[7] = Param(7, 0, u'Weak_Chin', u'shape', 0.0, -.5, .5, 0.0, u'Chin Angle', u'Chin Out', u'Chin In')
self.params[8] = Param(8, 0, u'Double_Chin', u'shape', 0.0, -.5, 1.5, 0.0, u'Chin-Neck', u'Tight Chin', u'Double Chin')
self.params[10] = Param(10, 0, u'Sunken_Cheeks', u'shape', 0.0, -1.5, 3, 0.0, u'Lower Cheeks', u'Well-Fed', u'Sunken')
self.params[11] = Param(11, 0, u'Noble_Nose_Bridge', u'shape', 0.0, -.5, 1.5, 0.0, u'Upper Bridge', u'Low', u'High')
self.params[12] = Param(12, 0, u'Jowls', u'shape', 0.0, -.5, 2.5, 0.0, '', u'Less', u'More')
self.params[13] = Param(13, 0, u'Cleft_Chin_Upper', u'shape', 0.0, 0, 1.5, 0.0, u'Upper Chin Cleft', u'Round', u'Cleft')
self.params[14] = Param(14, 0, u'High_Cheek_Bones', u'shape', 0.0, -.5, 1, 0.0, u'Cheek Bones', u'Low', u'High')
self.params[15] = Param(15, 0, u'Ears_Out', u'shape', 0.0, -.5, 1.5, 0.0, u'Ear Angle', u'In', u'Out')
self.params[16] = Param(16, 0, u'Pointy_Eyebrows', u'hair', 0.0, -.5, 3, 0.0, u'Eyebrow Points', u'Smooth', u'Pointy')
self.params[17] = Param(17, 0, u'Square_Jaw', u'shape', 0.0, -.5, 1, 0.0, u'Jaw Shape', u'Pointy', u'Square')
self.params[18] = Param(18, 0, u'Puffy_Upper_Cheeks', u'shape', 0.0, -1.5, 2.5, 0.0, u'Upper Cheeks', u'Thin', u'Puffy')
self.params[19] = Param(19, 0, u'Upturned_Nose_Tip', u'shape', 0.0, -1.5, 1, 0.0, u'Nose Tip Angle', u'Downturned', u'Upturned')
self.params[20] = Param(20, 0, u'Bulbous_Nose', u'shape', 0.0, -.5, 1.5, 0.0, u'Nose Thickness', u'Thin Nose', u'Bulbous Nose')
self.params[21] = Param(21, 0, u'Upper_Eyelid_Fold', u'shape', 0.0, -0.2, 1.3, 0.0, u'Upper Eyelid Fold', u'Uncreased', u'Creased')
self.params[22] = Param(22, 0, u'Attached_Earlobes', u'shape', 0.0, 0, 1, 0.0, u'Attached Earlobes', u'Unattached', u'Attached')
self.params[23] = Param(23, 0, u'Baggy_Eyes', u'shape', 0.0, -.5, 1.5, 0.0, u'Eye Bags', u'Smooth', u'Baggy')
self.params[24] = Param(24, 0, u'Wide_Eyes', u'shape', 0.0, -1.5, 2, 0.0, u'Eye Opening', u'Narrow', u'Wide')
self.params[25] = Param(25, 0, u'Wide_Lip_Cleft', u'shape', 0.0, -.8, 1.5, 0.0, u'Lip Cleft', u'Narrow', u'Wide')
self.params[26] = Param(26, 1, u'Lips_Thin', u'shape', 0.0, 0, .7, 0.0, '', '', '')
self.params[27] = Param(27, 0, u'Wide_Nose_Bridge', u'shape', 0.0, -1.3, 1.2, 0.0, u'Bridge Width', u'Narrow', u'Wide')
self.params[28] = Param(28, 1, u'Lips_Fat', u'shape', 0.0, 0, 2, 0.0, '', '', '')
self.params[29] = Param(29, 1, u'Wide_Upper_Lip', u'shape', 0.0, -.7, 1.3, 0.0, '', '', '')
self.params[30] = Param(30, 1, u'Wide_Lower_Lip', u'shape', 0.0, -.7, 1.3, 0.0, '', '', '')
self.params[31] = Param(31, 0, u'Arced_Eyebrows', u'hair', .5, 0, 2, .5, u'Eyebrow Arc', u'Flat', u'Arced')
self.params[32] = Param(32, 1, u'Male_Skeleton', u'shape', 0.0, 0, 1, 0.0, '', u'Female', u'Male')
self.params[33] = Param(33, 0, u'Height', u'shape', 0.0, -2.3, 2, 0.0, u'Height', u'Short', u'Tall')
self.params[34] = Param(34, 0, u'Thickness', u'shape', 0.0, -0.7, 1.5, 0.0, u'Body Thickness', u'Body Thin', u'Body Thick')
self.params[35] = Param(35, 0, u'Big_Ears', u'shape', 0.0, -1, 2, 0.0, u'Ear Size', u'Small', u'Large')
self.params[36] = Param(36, 0, u'Shoulders', u'shape', -0.5, -1.8, 1.4, -0.5, u'Shoulders', u'Narrow', u'Broad')
self.params[37] = Param(37, 0, u'Hip Width', u'shape', 0.0, -3.2, 2.8, 0.0, u'Hip Width', u'Narrow', u'Wide')
self.params[38] = Param(38, 0, u'Torso Length', u'shape', 0.0, -1, 1, 0.0, '', u'Short Torso', u'Long Torso')
self.params[40] = Param(40, 1, u'Male_Head', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[41] = Param(41, 1, u'Old', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[51] = Param(51, 1, u'Furrowed_Eyebrows', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[53] = Param(53, 1, u'Surprised_Eyebrows', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[54] = Param(54, 1, u'Worried_Eyebrows', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[55] = Param(55, 1, u'Frown_Mouth', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[57] = Param(57, 1, u'Smile_Mouth', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[58] = Param(58, 1, u'Blink_Left', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[59] = Param(59, 1, u'Blink_Right', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[70] = Param(70, 1, u'Lipsync_Aah', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[71] = Param(71, 1, u'Lipsync_Ooh', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[80] = Param(80, 0, u'male', u'shape', 0.0, 0, 1, 0.0, '', '', '')
self.params[93] = Param(93, 0, u'Glove Length', u'gloves', .8, .01, 1, .8, '', u'Short', u'Long')
self.params[98] = Param(98, 0, u'Eye Lightness', u'eyes', 0.0, 0, 1, 0.0, '', u'Darker', u'Lighter')
self.params[99] = Param(99, 0, u'Eye Color', u'eyes', 0, 0, 1, 0, '', u'Natural', u'Unnatural')
self.params[100] = Param(100, 1, u'Male_Torso', '', 0.0, 0, 1, 0.0, '', u'Male_Torso', '')
self.params[101] = Param(101, 1, u'Hands_Relaxed', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[102] = Param(102, 1, u'Hands_Point', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[103] = Param(103, 1, u'Hands_Fist', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[104] = Param(104, 1, u'Big_Belly_Torso', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[105] = Param(105, 0, u'Breast Size', u'shape', .5, 0, 1, .5, '', u'Small', u'Large')
self.params[106] = Param(106, 1, u'Muscular_Torso', u'shape', 0.0, 0, 1.4, 0.0, u'Torso Muscles', u'Regular', u'Muscular')
self.params[108] = Param(108, 0, u'Rainbow Color', u'skin', 0.0, 0, 1, 0.0, '', u'None', u'Wild')
self.params[110] = Param(110, 0, u'Red Skin', u'skin', 0.0, 0, 0.1, 0.0, u'Ruddiness', u'Pale', u'Ruddy')
self.params[111] = Param(111, 0, u'Pigment', u'skin', .5, 0, 1, .5, '', u'Light', u'Dark')
self.params[112] = Param(112, 0, u'Rainbow Color', u'hair', 0.0, 0, 1, 0.0, '', u'None', u'Wild')
self.params[113] = Param(113, 0, u'Red Hair', u'hair', 0.0, 0, 1, 0.0, '', u'No Red', u'Very Red')
self.params[114] = Param(114, 0, u'Blonde Hair', u'hair', .5, 0, 1, .5, '', u'Black', u'Blonde')
self.params[115] = Param(115, 0, u'White Hair', u'hair', 0.0, 0, 1, 0.0, '', u'No White', u'All White')
self.params[116] = Param(116, 0, u'Rosy Complexion', u'skin', 0.0, 0, 1, 0.0, '', u'Less Rosy', u'More Rosy')
self.params[117] = Param(117, 0, u'Lip Pinkness', u'skin', 0.0, 0, 1, 0.0, '', u'Darker', u'Pinker')
self.params[118] = Param(118, 1, u'Wrinkles', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[119] = Param(119, 0, u'Eyebrow Size', u'hair', 0.5, 0, 1, 0.5, '', u'Thin Eyebrows', u'Bushy Eyebrows')
self.params[125] = Param(125, 1, u'Shading', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[126] = Param(126, 1, u'Shading', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[130] = Param(130, 0, u'Front Fringe', u'hair', .45, 0, 1, .45, '', u'Short', u'Long')
self.params[131] = Param(131, 0, u'Side Fringe', u'hair', .5, 0, 1, .5, '', u'Short', u'Long')
self.params[132] = Param(132, 0, u'Back Fringe', u'hair', .39, 0, 1, .39, '', u'Short', u'Long')
self.params[133] = Param(133, 0, u'Hair Front', u'hair', .25, 0, 1, .25, '', u'Short', u'Long')
self.params[134] = Param(134, 0, u'Hair Sides', u'hair', .5, 0, 1, .5, '', u'Short', u'Long')
self.params[135] = Param(135, 0, u'Hair Back', u'hair', .55, 0, 1, .55, '', u'Short', u'Long')
self.params[136] = Param(136, 0, u'Hair Sweep', u'hair', .5, 0, 1, .5, '', u'Sweep Forward', u'Sweep Back')
self.params[137] = Param(137, 0, u'Hair Tilt', u'hair', .5, 0, 1, .5, '', u'Left', u'Right')
self.params[140] = Param(140, 0, u'Hair_Part_Middle', u'hair', 0.0, 0, 2, 0.0, u'Middle Part', u'No Part', u'Part')
self.params[141] = Param(141, 0, u'Hair_Part_Right', u'hair', 0.0, 0, 2, 0.0, u'Right Part', u'No Part', u'Part')
self.params[142] = Param(142, 0, u'Hair_Part_Left', u'hair', 0.0, 0, 2, 0.0, u'Left Part', u'No Part', u'Part')
self.params[143] = Param(143, 0, u'Hair_Sides_Full', u'hair', 0.125, -4, 1.5, 0.125, u'Full Hair Sides', u'Mowhawk', u'Full Sides')
self.params[144] = Param(144, 1, u'Bangs_Front_Up', u'hair', 0.0, 0, 1, 0.0, u'Front Bangs Up', u'Bangs', u'Bangs Up')
self.params[145] = Param(145, 1, u'Bangs_Front_Down', u'hair', 0.0, 0, 5, 0.0, u'Front Bangs Down', u'Bangs', u'Bangs Down')
self.params[146] = Param(146, 1, u'Bangs_Sides_Up', u'hair', 0.0, 0, 1, 0.0, u'Side Bangs Up', u'Side Bangs', u'Side Bangs Up')
self.params[147] = Param(147, 1, u'Bangs_Sides_Down', u'hair', 0.0, 0, 2, 0.0, u'Side Bangs Down', u'Side Bangs', u'Side Bangs Down')
self.params[148] = Param(148, 1, u'Bangs_Back_Up', u'hair', 0.0, 0, 1, 0.0, u'Back Bangs Up', u'Back Bangs', u'Back Bangs Up')
self.params[149] = Param(149, 1, u'Bangs_Back_Down', u'hair', 0.0, 0, 2, 0.0, u'Back Bangs Down', u'Back Bangs', u'Back Bangs Down')
self.params[150] = Param(150, 0, u'Body Definition', u'skin', 0, 0, 1, 0, '', u'Less', u'More')
self.params[151] = Param(151, 1, u'Big_Butt_Legs', u'shape', 0.0, 0, 1, 0.0, u'Butt Size', u'Regular', u'Large')
self.params[152] = Param(152, 1, u'Muscular_Legs', u'shape', 0.0, 0, 1.5, 0.0, u'Leg Muscles', u'Regular Muscles', u'More Muscles')
self.params[153] = Param(153, 1, u'Male_Legs', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[155] = Param(155, 0, u'Lip Width', u'shape', 0, -0.9, 1.3, 0, u'Lip Width', u'Narrow Lips', u'Wide Lips')
self.params[156] = Param(156, 1, u'Big_Belly_Legs', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[157] = Param(157, 0, u'Belly Size', u'shape', 0, 0, 1, 0, '', u'Small', u'Big')
self.params[158] = Param(158, 1, u'Shading', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[159] = Param(159, 1, u'Shading', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[160] = Param(160, 1, u'Shading', u'pants', 0.0, 0, 1, 0.0, '', '', '')
self.params[161] = Param(161, 1, u'Shading', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[162] = Param(162, 0, u'Facial Definition', u'skin', 0, 0, 1, 0, '', u'Less', u'More')
self.params[163] = Param(163, 0, u'wrinkles', u'skin', 0, 0, 1, 0, '', u'Less', u'More')
self.params[165] = Param(165, 0, u'Freckles', u'skin', 0.0, 0, 1, 0.0, '', u'Less', u'More')
self.params[166] = Param(166, 0, u'Sideburns', u'hair', 0.0, 0, 1, 0.0, '', u'Short Sideburns', u'Mutton Chops')
self.params[167] = Param(167, 0, u'Moustache', u'hair', 0.0, 0, 1, 0.0, '', u'Chaplin', u'Handlebars')
self.params[168] = Param(168, 0, u'Soulpatch', u'hair', 0.0, 0, 1, 0.0, '', u'Less soul', u'More soul')
self.params[169] = Param(169, 0, u'Chin Curtains', u'hair', 0.0, 0, 1, 0.0, '', u'Less Curtains', u'More Curtains')
self.params[171] = Param(171, 1, u'Hair_Front_Down', u'hair', 0.0, 0, 1, 0.0, u'Front Hair Down', u'Front Hair', u'Front Hair Down')
self.params[172] = Param(172, 1, u'Hair_Front_Up', u'hair', 0.0, 0, 1, 0.0, u'Front Hair Up', u'Front Hair', u'Front Hair Up')
self.params[173] = Param(173, 1, u'Hair_Sides_Down', u'hair', 0.0, 0, 1, 0.0, u'Sides Hair Down', u'Sides Hair', u'Sides Hair Down')
self.params[174] = Param(174, 1, u'Hair_Sides_Up', u'hair', 0.0, 0, 1, 0.0, u'Sides Hair Up', u'Sides Hair', u'Sides Hair Up')
self.params[175] = Param(175, 1, u'Hair_Back_Down', u'hair', 0.0, 0, 3, 0.0, u'Back Hair Down', u'Back Hair', u'Back Hair Down')
self.params[176] = Param(176, 1, u'Hair_Back_Up', u'hair', 0.0, 0, 1, 0.0, u'Back Hair Up', u'Back Hair', u'Back Hair Up')
self.params[177] = Param(177, 0, u'Hair_Rumpled', u'hair', 0.0, 0, 1, 0.0, u'Rumpled Hair', u'Smooth Hair', u'Rumpled Hair')
self.params[178] = Param(178, 1, u'Hair_Swept_Back', u'hair', 0.0, 0, 1, 0.0, u'Swept Back Hair', u'NotHair', u'Swept Back')
self.params[179] = Param(179, 1, u'Hair_Swept_Forward', u'hair', 0.0, 0, 1, 0.0, u'Swept Forward Hair', u'Hair', u'Swept Forward')
self.params[180] = Param(180, 1, u'Hair_Volume', u'hair', 0.0, 0, 1.3, 0.0, u'Hair Volume', u'Less', u'More')
self.params[181] = Param(181, 0, u'Hair_Big_Front', u'hair', 0.14, -1, 1, 0.14, u'Big Hair Front', u'Less', u'More')
self.params[182] = Param(182, 0, u'Hair_Big_Top', u'hair', .7, -1, 1, .7, u'Big Hair Top', u'Less', u'More')
self.params[183] = Param(183, 0, u'Hair_Big_Back', u'hair', 0.05, -1, 1, 0.05, u'Big Hair Back', u'Less', u'More')
self.params[184] = Param(184, 0, u'Hair_Spiked', u'hair', 0.0, 0, 1, 0.0, u'Spiked Hair', u'No Spikes', u'Big Spikes')
self.params[185] = Param(185, 0, u'Deep_Chin', u'shape', 0.0, -1, 1, 0.0, u'Chin Depth', u'Shallow', u'Deep')
self.params[186] = Param(186, 1, u'Egg_Head', u'shape', 0.0, -1.3, 1, 0.0, u'Egg Head', u'Chin Heavy', u'Forehead Heavy')
self.params[187] = Param(187, 1, u'Squash_Stretch_Head', u'shape', 0.0, -.5, 1, 0.0, u'Squash/Stretch Head', u'Squash Head', u'Stretch Head')
self.params[188] = Param(188, 1, u'Square_Head', u'shape', 0.0, 0, .7, 0.0, '', u'Less Square', u'More Square')
self.params[189] = Param(189, 1, u'Round_Head', u'shape', 0.0, 0, 1, 0.0, '', u'Less Round', u'More Round')
self.params[190] = Param(190, 1, u'Hair_Tilt_Right', u'hair', 0.0, 0, 1, 0.0, u'Hair Tilted Right', u'Hair', u'Tilt Right')
self.params[191] = Param(191, 1, u'Hair_Tilt_Left', u'hair', 0.0, 0, 1, 0.0, u'Hair Tilted Left', u'Hair', u'Tilt Left')
self.params[192] = Param(192, 0, u'Bangs_Part_Middle', u'hair', 0.0, 0, 1, 0.0, u'Part Bangs', u'No Part', u'Part Bangs')
self.params[193] = Param(193, 0, u'Head Shape', u'shape', .5, 0, 1, .5, u'Head Shape', u'More Square', u'More Round')
self.params[194] = Param(194, 1, u'Eye_Spread', '', 0.0, -2, 2, 0.0, '', u'Eyes Together', u'Eyes Spread')
self.params[195] = Param(195, 1, u'EyeBone_Spread', u'shape', 0.0, -1, 1, 0.0, '', u'Eyes Together', u'Eyes Spread')
self.params[196] = Param(196, 0, u'Eye Spacing', u'shape', 0, -2, 1, 0, u'Eye Spacing', u'Close Set Eyes', u'Far Set Eyes')
self.params[197] = Param(197, 1, u'Shoe_Heels', u'shoes', 0.0, 0, 1, 0.0, '', u'No Heels', u'High Heels')
self.params[198] = Param(198, 0, u'Heel Height', u'shoes', 0, 0, 1, 0, '', u'Low Heels', u'High Heels')
self.params[300] = Param(300, 1, u'Express_Closed_Mouth', '', 1, 0, 1, 1, '', '', '')
self.params[301] = Param(301, 1, u'Express_Tongue_Out', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[302] = Param(302, 1, u'Express_Surprise_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[303] = Param(303, 1, u'Express_Wink_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[304] = Param(304, 1, u'Express_Embarrassed_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[305] = Param(305, 1, u'Express_Shrug_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[306] = Param(306, 1, u'Express_Kiss', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[307] = Param(307, 1, u'Express_Bored_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[308] = Param(308, 1, u'Express_Repulsed_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[309] = Param(309, 1, u'Express_Disdain', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[310] = Param(310, 1, u'Express_Afraid_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[311] = Param(311, 1, u'Express_Worry_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[312] = Param(312, 1, u'Express_Cry_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[313] = Param(313, 1, u'Express_Sad_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[314] = Param(314, 1, u'Express_Anger_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[315] = Param(315, 1, u'Express_Frown', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[316] = Param(316, 1, u'Express_Laugh_Emote', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[317] = Param(317, 1, u'Express_Toothsmile', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[318] = Param(318, 1, u'Express_Smile', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[400] = Param(400, 1, u'Displace_Hair_Facial', u'hair', 0.0, 0, 2, 0.0, u'Hair Thickess', u'Cropped Hair', u'Bushy Hair')
self.params[500] = Param(500, 1, u'Shoe_Heel_Height', u'shoes', 0.0, 0, 1, 0.0, u'Heel Height', u'Low Heels', u'High Heels')
self.params[501] = Param(501, 1, u'Shoe_Platform_Height', u'shoes', 0.0, 0, 1, 0.0, u'Platform Height', u'Low Platforms', u'High Platforms')
self.params[502] = Param(502, 1, u'Shoe_Platform', u'shoes', 0.0, 0, 1, 0.0, '', u'No Heels', u'High Heels')
self.params[503] = Param(503, 0, u'Platform Height', u'shoes', 0, 0, 1, 0, '', u'Low Platforms', u'High Platforms')
self.params[505] = Param(505, 0, u'Lip Thickness', u'shape', .5, 0, 1, .5, '', u'Thin Lips', u'Fat Lips')
self.params[506] = Param(506, 0, u'Mouth_Height', u'shape', 0.0, -2, 2, 0.0, u'Mouth Position', u'High', u'Low')
self.params[507] = Param(507, 0, u'Breast_Gravity', u'shape', 0, -1.5, 2, 0, u'Breast Buoyancy', u'Less Gravity', u'More Gravity')
self.params[508] = Param(508, 0, u'Shoe_Platform_Width', u'shoes', 0.0, -1, 2, 0.0, u'Platform Width', u'Narrow', u'Wide')
self.params[509] = Param(509, 1, u'Shoe_Heel_Point', u'shoes', 0.0, 0, 1, 0.0, u'Heel Shape', u'Default Heels', u'Pointy Heels')
self.params[510] = Param(510, 1, u'Shoe_Heel_Thick', u'shoes', 0.0, 0, 1, 0.0, u'Heel Shape', u'default Heels', u'Thick Heels')
self.params[511] = Param(511, 1, u'Shoe_Toe_Point', u'shoes', 0.0, 0, 1, 0.0, u'Toe Shape', u'Default Toe', u'Pointy Toe')
self.params[512] = Param(512, 1, u'Shoe_Toe_Square', u'shoes', 0.0, 0, 1, 0.0, u'Toe Shape', u'Default Toe', u'Square Toe')
self.params[513] = Param(513, 0, u'Heel Shape', u'shoes', .5, 0, 1, .5, '', u'Pointy Heels', u'Thick Heels')
self.params[514] = Param(514, 0, u'Toe Shape', u'shoes', .5, 0, 1, .5, '', u'Pointy', u'Square')
self.params[515] = Param(515, 0, u'Foot_Size', u'shape', 0.0, -1, 3, 0.0, u'Foot Size', u'Small', u'Big')
self.params[516] = Param(516, 1, u'Displace_Loose_Lowerbody', u'pants', 0, 0, 1, 0, u'Pants Fit', '', '')
self.params[517] = Param(517, 0, u'Wide_Nose', u'shape', 0.0, -.5, 1, 0.0, u'Nose Width', u'Narrow', u'Wide')
self.params[518] = Param(518, 0, u'Eyelashes_Long', u'shape', 0.0, -.3, 1.5, 0.0, u'Eyelash Length', u'Short', u'Long')
self.params[600] = Param(600, 1, u'Sleeve Length Cloth', u'shirt', .7, 0, 0.85, .7, '', '', '')
self.params[601] = Param(601, 1, u'Shirt Bottom Cloth', u'shirt', .8, 0, 1, .8, '', '', '')
self.params[602] = Param(602, 1, u'Collar Front Height Cloth', u'shirt', .8, 0, 1, .8, '', '', '')
self.params[603] = Param(603, 0, u'Sleeve Length', u'undershirt', .4, .01, 1, .4, '', u'Short', u'Long')
self.params[604] = Param(604, 0, u'Bottom', u'undershirt', .85, 0, 1, .85, '', u'Short', u'Long')
self.params[605] = Param(605, 0, u'Collar Front', u'undershirt', .84, 0, 1, .84, '', u'Low', u'High')
self.params[606] = Param(606, 0, u'Sleeve Length', u'jacket', .8, 0, 1, .8, '', u'Short', u'Long')
self.params[607] = Param(607, 0, u'Collar Front', u'jacket', .8, 0, 1, .8, '', u'Low', u'High')
self.params[608] = Param(608, 0, u'bottom length lower', u'jacket', .8, 0, 1, .8, u'Jacket Length', u'Short', u'Long')
self.params[609] = Param(609, 0, u'open jacket', u'jacket', .2, 0, 1, .2, u'Open Front', u'Open', u'Closed')
self.params[614] = Param(614, 1, u'Waist Height Cloth', u'pants', .8, 0, 1, .8, '', '', '')
self.params[615] = Param(615, 1, u'Pants Length Cloth', u'pants', .8, 0, 1, .8, '', '', '')
self.params[616] = Param(616, 0, u'Shoe Height', u'shoes', 0.1, 0, 1, 0.1, '', u'Short', u'Tall')
self.params[617] = Param(617, 0, u'Socks Length', u'socks', 0.35, 0, 1, 0.35, '', u'Short', u'Long')
self.params[619] = Param(619, 0, u'Pants Length', u'underpants', .3, 0, 1, .3, '', u'Short', u'Long')
self.params[620] = Param(620, 1, u'bottom length upper', u'jacket', .8, 0, 1, .8, '', u'hi cut', u'low cut')
self.params[621] = Param(621, 1, u'bottom length lower', u'jacket', .8, 0, 1, .8, '', u'hi cut', u'low cut')
self.params[622] = Param(622, 1, u'open upper', u'jacket', .8, 0, 1, .8, '', u'closed', u'open')
self.params[623] = Param(623, 1, u'open lower', u'jacket', .8, 0, 1, .8, '', u'open', u'closed')
self.params[624] = Param(624, 0, u'Pants Waist', u'underpants', .8, 0, 1, .8, '', u'Low', u'High')
self.params[625] = Param(625, 0, u'Leg_Pantflair', u'pants', 0.0, 0, 1.5, 0.0, u'Cuff Flare', u'Tight Cuffs', u'Flared Cuffs')
self.params[626] = Param(626, 1, u'Big_Chest', u'shape', 0.0, 0, 1, 0.0, u'Chest Size', u'Small', u'Large')
self.params[627] = Param(627, 1, u'Small_Chest', u'shape', 0.0, 0, 1, 0.0, u'Chest Size', u'Large', u'Small')
self.params[628] = Param(628, 1, u'Displace_Loose_Upperbody', u'shirt', 0, 0, 1, 0, u'Shirt Fit', '', '')
self.params[629] = Param(629, 0, u'Forehead Angle', u'shape', .5, 0, 1, .5, '', u'More Vertical', u'More Sloped')
self.params[630] = Param(630, 1, u'Forehead_Round', u'shape', 0.0, 0, 1, 0.0, u'Round Forehead', u'Less', u'More')
self.params[631] = Param(631, 1, u'Forehead_Slant', u'shape', 0.0, 0, 1, 0.0, u'Slanted Forehead', u'Less', u'More')
self.params[632] = Param(632, 1, u'Express_Open_Mouth', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[633] = Param(633, 1, u'Fat_Head', u'shape', 0.0, 0, 1, 0.0, u'Fat Head', u'Skinny', u'Fat')
self.params[634] = Param(634, 1, u'Fat_Torso', u'shape', 0.0, 0, 1, 0.0, u'Fat Torso', u'skinny', u'fat')
self.params[635] = Param(635, 1, u'Fat_Legs', u'shape', 0.0, 0, 1, 0.0, u'Fat Torso', u'skinny', u'fat')
self.params[637] = Param(637, 0, u'Body Fat', u'shape', 0, 0, 1, 0, '', u'Less Body Fat', u'More Body Fat')
self.params[638] = Param(638, 0, u'Low_Crotch', u'pants', 0.0, 0, 1.3, 0.0, u'Pants Crotch', u'High and Tight', u'Low and Loose')
self.params[640] = Param(640, 1, u'Hair_Egg_Head', u'hair', 0.0, -1.3, 1, 0.0, '', '', '')
self.params[641] = Param(641, 1, u'Hair_Squash_Stretch_Head', u'hair', 0.0, -.5, 1, 0.0, '', '', '')
self.params[642] = Param(642, 1, u'Hair_Square_Head', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[643] = Param(643, 1, u'Hair_Round_Head', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[644] = Param(644, 1, u'Hair_Forehead_Round', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[645] = Param(645, 1, u'Hair_Forehead_Slant', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[646] = Param(646, 0, u'Egg_Head', u'shape', 0, -1.3, 1, 0, u'Egg Head', u'Chin Heavy', u'Forehead Heavy')
self.params[647] = Param(647, 0, u'Squash_Stretch_Head', u'shape', 0, -0.5, 1, 0, u'Head Stretch', u'Squash Head', u'Stretch Head')
self.params[648] = Param(648, 1, u'Scrawny_Torso', u'shape', 0.0, 0, 1.3, 0.0, u'Torso Muscles', u'Regular', u'Scrawny')
self.params[649] = Param(649, 0, u'Torso Muscles', u'shape', .5, 0, 1, .5, u'Torso Muscles', u'Less Muscular', u'More Muscular')
self.params[650] = Param(650, 0, u'Eyelid_Corner_Up', u'shape', 0.0, -1.3, 1.2, 0.0, u'Outer Eye Corner', u'Corner Down', u'Corner Up')
self.params[651] = Param(651, 1, u'Scrawny_Legs', u'shape', 0.0, 0, 1.5, 0.0, u'Scrawny Leg', u'Regular Muscles', u'Less Muscles')
self.params[652] = Param(652, 0, u'Leg Muscles', u'shape', .5, 0, 1, .5, '', u'Less Muscular', u'More Muscular')
self.params[653] = Param(653, 0, u'Tall_Lips', u'shape', 0.0, -1, 2, 0.0, u'Lip Fullness', u'Less Full', u'More Full')
self.params[654] = Param(654, 0, u'Shoe_Toe_Thick', u'shoes', 0.0, 0, 2, 0.0, u'Toe Thickness', u'Flat Toe', u'Thick Toe')
self.params[655] = Param(655, 1, u'Head Size', u'shape', 0.0, -.25, .10, 0.0, u'Head Size', u'Small Head', u'Big Head')
self.params[656] = Param(656, 0, u'Crooked_Nose', u'shape', 0.0, -2, 2, 0.0, u'Crooked Nose', u'Nose Left', u'Nose Right')
self.params[657] = Param(657, 1, u'Smile_Mouth', u'shape', 0.0, 0, 1.4, 0.0, u'Mouth Corner', u'Corner Normal', u'Corner Up')
self.params[658] = Param(658, 1, u'Frown_Mouth', u'shape', 0.0, 0, 1.2, 0.0, u'Mouth Corner', u'Corner Normal', u'Corner Down')
self.params[659] = Param(659, 0, u'Mouth Corner', u'shape', .5, 0, 1, .5, '', u'Corner Down', u'Corner Up')
self.params[660] = Param(660, 1, u'Shear_Head', u'shape', 0, -2, 2, 0, u'Shear Face', u'Shear Left', u'Shear Right')
self.params[661] = Param(661, 1, u'EyeBone_Head_Shear', u'shape', 0.0, -2, 2, 0.0, '', u'Eyes Shear Left Up', u'Eyes Shear Right Up')
self.params[662] = Param(662, 0, u'Face Shear', u'shape', .5, 0, 1, .5, '', u'Shear Right Up', u'Shear Left Up')
self.params[663] = Param(663, 0, u'Shift_Mouth', u'shape', 0, -2, 2, 0, u'Shift Mouth', u'Shift Left', u'Shift Right')
self.params[664] = Param(664, 0, u'Pop_Eye', u'shape', 0, -2, 2, 0, u'Eye Pop', u'Pop Right Eye', u'Pop Left Eye')
self.params[665] = Param(665, 0, u'Jaw_Jut', u'shape', 0, -2, 2, 0, u'Jaw Jut', u'Overbite', u'Underbite')
self.params[666] = Param(666, 1, u'Hands_Relaxed_L', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[667] = Param(667, 1, u'Hands_Point_L', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[668] = Param(668, 1, u'Hands_Fist_L', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[669] = Param(669, 1, u'Hands_Relaxed_R', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[670] = Param(670, 1, u'Hands_Point_R', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[671] = Param(671, 1, u'Hands_Fist_R', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[672] = Param(672, 1, u'Hands_Typing', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[674] = Param(674, 0, u'Hair_Shear_Back', u'hair', -0.3, -1, 2, -0.3, u'Shear Back', u'Full Back', u'Sheared Back')
self.params[675] = Param(675, 0, u'Hand Size', u'shape', 0.0, -.3, .3, 0.0, '', u'Small Hands', u'Large Hands')
self.params[676] = Param(676, 0, u'Love_Handles', u'shape', 0, -1, 2, 0, u'Love Handles', u'Less Love', u'More Love')
self.params[677] = Param(677, 1, u'Scrawny_Torso_Male', u'shape', 0.0, 0, 1.3, 0.0, u'Torso Scrawny', u'Regular', u'Scrawny')
self.params[678] = Param(678, 0, u'Torso Muscles', u'shape', .5, 0, 1, .5, '', u'Less Muscular', u'More Muscular')
self.params[679] = Param(679, 1, u'Eyeball_Size', u'shape', 0.0, -.25, .10, 0.0, u'Eyeball Size', u'small eye', u'big eye')
self.params[680] = Param(680, 1, u'Eyeball_Size', u'shape', 0.0, -.25, .10, 0.0, u'Eyeball Size', u'small eye', u'big eye')
self.params[681] = Param(681, 1, u'Eyeball_Size', u'shape', 0.0, -.25, .10, 0.0, u'Eyeball Size', u'small eye', u'big eye')
self.params[682] = Param(682, 0, u'Head Size', u'shape', .5, 0, 1, .5, u'Head Size', u'Small Head', u'Big Head')
self.params[683] = Param(683, 0, u'Neck Thickness', u'shape', -.15, -.4, .2, -.15, '', u'Skinny Neck', u'Thick Neck')
self.params[684] = Param(684, 0, u'Breast_Female_Cleavage', u'shape', 0, -.3, 1.3, 0, u'Breast Cleavage', u'Separate', u'Join')
self.params[685] = Param(685, 0, u'Chest_Male_No_Pecs', u'shape', 0, -.5, 1.1, 0, u'Pectorals', u'Big Pectorals', u'Sunken Chest')
self.params[686] = Param(686, 1, u'Head_Eyes_Big', u'shape', 0, -2, 2, 0, u'Eye Size', u'Beady Eyes', u'Anime Eyes')
self.params[687] = Param(687, 1, u'Eyeball_Size', u'shape', 0.0, -.25, .25, 0.0, u'Big Eyeball', u'small eye', u'big eye')
self.params[688] = Param(688, 1, u'Eyeball_Size', u'shape', 0.0, -.25, .25, 0.0, u'Big Eyeball', u'small eye', u'big eye')
self.params[689] = Param(689, 1, u'EyeBone_Big_Eyes', u'shape', 0.0, -1, 1, 0.0, '', u'Eyes Back', u'Eyes Forward')
self.params[690] = Param(690, 0, u'Eye Size', u'shape', .5, 0, 1, .5, u'Eye Size', u'Beady Eyes', u'Anime Eyes')
self.params[691] = Param(691, 1, u'Eyeball_Size', u'shape', 0.0, -.25, .25, 0.0, u'Big Eyeball', u'small eye', u'big eye')
self.params[692] = Param(692, 0, u'Leg Length', u'shape', 0.0, -1, 1, 0.0, '', u'Short Legs', u'Long Legs')
self.params[693] = Param(693, 0, u'Arm Length', u'shape', .6, -1, 1, .6, '', u'Short Arms', u'Long arms')
self.params[694] = Param(694, 1, u'Eyeball_Size', u'shape', 0.0, -.25, .10, 0.0, u'Eyeball Size', u'small eye', u'big eye')
self.params[695] = Param(695, 1, u'Eyeball_Size', u'shape', 0.0, -.25, .25, 0.0, u'Big Eyeball', u'small eye', u'big eye')
self.params[700] = Param(700, 0, u'Lipstick Color', u'skin', .25, 0, 1, .25, '', u'Pink', u'Black')
self.params[701] = Param(701, 0, u'Lipstick', u'skin', 0.0, 0, .9, 0.0, '', u'No Lipstick', u'More Lipstick')
self.params[702] = Param(702, 0, u'Lipgloss', u'skin', 0.0, 0, 1, 0.0, '', u'No Lipgloss', u'Glossy')
self.params[703] = Param(703, 0, u'Eyeliner', u'skin', 0.0, 0, 1, 0.0, '', u'No Eyeliner', u'Full Eyeliner')
self.params[704] = Param(704, 0, u'Blush', u'skin', 0, 0, .9, 0, '', u'No Blush', u'More Blush')
self.params[705] = Param(705, 0, u'Blush Color', u'skin', .5, 0, 1, .5, '', u'Pink', u'Orange')
self.params[706] = Param(706, 0, u'Out Shdw Opacity', u'skin', .6, .2, 1, .6, '', u'Clear', u'Opaque')
self.params[707] = Param(707, 0, u'Outer Shadow', u'skin', 0.0, 0, .7, 0.0, '', u'No Eyeshadow', u'More Eyeshadow')
self.params[708] = Param(708, 0, u'Out Shdw Color', u'skin', 0.0, 0, 1, 0.0, '', u'Light', u'Dark')
self.params[709] = Param(709, 0, u'Inner Shadow', u'skin', 0, 0, 1, 0, '', u'No Eyeshadow', u'More Eyeshadow')
self.params[710] = Param(710, 0, u'Nail Polish', u'skin', 0.0, 0, 1, 0.0, '', u'No Polish', u'Painted Nails')
self.params[711] = Param(711, 0, u'Blush Opacity', u'skin', .5, 0, 1, .5, '', u'Clear', u'Opaque')
self.params[712] = Param(712, 0, u'In Shdw Color', u'skin', 0.0, 0, 1, 0.0, '', u'Light', u'Dark')
self.params[713] = Param(713, 0, u'In Shdw Opacity', u'skin', .7, .2, 1, .7, '', u'Clear', u'Opaque')
self.params[714] = Param(714, 0, u'Eyeliner Color', u'skin', 0.0, 0, 1, 0.0, '', u'Dark Green', u'Black')
self.params[715] = Param(715, 0, u'Nail Polish Color', u'skin', 0.0, 0, 1, 0.0, '', u'Pink', u'Black')
self.params[750] = Param(750, 0, u'Eyebrow Density', u'hair', 0.7, 0, 1, 0.7, '', u'Sparse', u'Dense')
self.params[751] = Param(751, 1, u"5 O'Clock Shadow", u'hair', 0.7, 0, 1, 0.7, '', u'Dense hair', u'Shadow hair')
self.params[752] = Param(752, 0, u'Hair Thickness', u'hair', .5, 0, 1, .5, '', u"5 O'Clock Shadow", u'Bushy Hair')
self.params[753] = Param(753, 0, u'Saddlebags', u'shape', 0, -0.5, 3, 0, u'Saddle Bags', u'Less Saddle', u'More Saddle')
self.params[754] = Param(754, 0, u'Hair_Taper_Back', u'hair', 0, -1, 2, 0, u'Taper Back', u'Wide Back', u'Narrow Back')
self.params[755] = Param(755, 0, u'Hair_Taper_Front', u'hair', 0.05, -1.5, 1.5, 0.05, u'Taper Front', u'Wide Front', u'Narrow Front')
self.params[756] = Param(756, 0, u'Neck Length', u'shape', 0, -1, 1, 0, '', u'Short Neck', u'Long Neck')
self.params[757] = Param(757, 0, u'Lower_Eyebrows', u'hair', -1, -4, 2, -1, u'Eyebrow Height', u'Higher', u'Lower')
self.params[758] = Param(758, 0, u'Lower_Bridge_Nose', u'shape', 0.0, -1.5, 1.5, 0.0, u'Lower Bridge', u'Low', u'High')
self.params[759] = Param(759, 0, u'Low_Septum_Nose', u'shape', 0.5, -1, 1.5, 0.5, u'Nostril Division', u'High', u'Low')
self.params[760] = Param(760, 0, u'Jaw_Angle', u'shape', 0, -1.2, 2, 0, u'Jaw Angle', u'Low Jaw', u'High Jaw')
self.params[761] = Param(761, 1, u'Hair_Volume_Small', u'hair', 0.0, 0, 1.3, 0.0, u'Hair Volume', u'Less', u'More')
self.params[762] = Param(762, 0, u'Hair_Shear_Front', u'hair', 0.0, 0, 3, 0.0, u'Shear Front', u'Full Front', u'Sheared Front')
self.params[763] = Param(763, 0, u'Hair Volume', u'hair', .55, 0, 1, .55, '', u'Less Volume', u'More Volume')
self.params[764] = Param(764, 0, u'Lip_Cleft_Deep', u'shape', 0.0, -.5, 1.2, 0.0, u'Lip Cleft Depth', u'Shallow', u'Deep')
self.params[765] = Param(765, 0, u'Puffy_Lower_Lids', u'shape', 0.0, -.3, 2.5, 0.0, u'Puffy Eyelids', u'Flat', u'Puffy')
self.params[766] = Param(766, 1, u'Hands_Salute_R', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[767] = Param(767, 1, u'Bug_Eyed_Head', u'shape', 0, -2, 2, 0, u'Eye Depth', u'Sunken Eyes', u'Bug Eyes')
self.params[768] = Param(768, 1, u'EyeBone_Bug', u'shape', 0.0, -2, 2, 0.0, '', u'Eyes Sunken', u'Eyes Bugged')
self.params[769] = Param(769, 0, u'Eye Depth', u'shape', .5, 0, 1, .5, '', u'Sunken Eyes', u'Bugged Eyes')
self.params[770] = Param(770, 1, u'Elongate_Head', u'shape', 0, -1, 1, 0, u'Shear Face', u'Flat Head', u'Long Head')
self.params[771] = Param(771, 1, u'Elongate_Head_Hair', u'hair', 0.0, -1, 1, 0.0, '', '', '')
self.params[772] = Param(772, 1, u'EyeBone_Head_Elongate', u'shape', 0.0, -1, 1, 0.0, '', u'Eyes Short Head', u'Eyes Long Head')
self.params[773] = Param(773, 0, u'Head Length', u'shape', .5, 0, 1, .5, '', u'Flat Head', u'Long Head')
self.params[774] = Param(774, 1, u'Shear_Head_Hair', u'hair', 0.0, -2, 2, 0.0, '', '', '')
self.params[775] = Param(775, 0, u'Body Freckles', u'skin', 0, 0, 1, 0, '', u'Less Freckles', u'More Freckles')
self.params[776] = Param(776, 1, u'freckles upper', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[777] = Param(777, 1, u'freckles lower', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[778] = Param(778, 1, u'Collar Back Height Cloth', u'shirt', .8, 0, 1, .8, '', '', '')
self.params[779] = Param(779, 0, u'Collar Back', u'undershirt', .84, 0, 1, .84, '', u'Low', u'High')
self.params[780] = Param(780, 0, u'Collar Back', u'jacket', .8, 0, 1, .8, '', u'Low', u'High')
self.params[781] = Param(781, 0, u'Collar Back', u'shirt', .78, 0, 1, .78, '', u'Low', u'High')
self.params[782] = Param(782, 1, u'Hair_Pigtails_Short', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[783] = Param(783, 1, u'Hair_Pigtails_Med', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[784] = Param(784, 1, u'Hair_Pigtails_Long', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[785] = Param(785, 0, u'Pigtails', u'hair', 0, 0, 1, 0, '', u'Short Pigtails', u'Long Pigtails')
self.params[786] = Param(786, 1, u'Hair_Ponytail_Short', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[787] = Param(787, 1, u'Hair_Ponytail_Med', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[788] = Param(788, 1, u'Hair_Ponytail_Long', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[789] = Param(789, 0, u'Ponytail', u'hair', 0, 0, 1, 0, '', u'Short Ponytail', u'Long Ponytail')
self.params[790] = Param(790, 1, u'Hair_Pigtails_Medlong', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[791] = Param(791, 1, u'Hands_Peace_R', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[792] = Param(792, 1, u'Hands_Spread_R', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[793] = Param(793, 1, u'Leg_Longcuffs', u'pants', 0, 0, 3, 0, u'Longcuffs', '', '')
self.params[794] = Param(794, 1, u'Small_Butt', u'shape', 0.0, 0, 1, 0.0, u'Butt Size', u'Regular', u'Small')
self.params[795] = Param(795, 0, u'Butt Size', u'shape', .25, 0, 1, .25, u'Butt Size', u'Flat Butt', u'Big Butt')
self.params[796] = Param(796, 0, u'Pointy_Ears', u'shape', 0.0, -.4, 3, 0.0, u'Ear Tips', u'Flat', u'Pointy')
self.params[797] = Param(797, 1, u'Fat_Upper_Lip', u'shape', 0.0, 0, 1.5, 0.0, u'Fat Upper Lip', u'Normal Upper', u'Fat Upper')
self.params[798] = Param(798, 1, u'Fat_Lower_Lip', u'shape', 0.0, 0, 1.5, 0.0, u'Fat Lower Lip', u'Normal Lower', u'Fat Lower')
self.params[799] = Param(799, 0, u'Lip Ratio', u'shape', .5, 0, 1, .5, u'Lip Ratio', u'More Upper Lip', u'More Lower Lip')
self.params[800] = Param(800, 0, u'Sleeve Length', u'shirt', .89, 0, 1, .89, '', u'Short', u'Long')
self.params[801] = Param(801, 0, u'Shirt Bottom', u'shirt', 1, 0, 1, 1, '', u'Short', u'Long')
self.params[802] = Param(802, 0, u'Collar Front', u'shirt', .78, 0, 1, .78, '', u'Low', u'High')
self.params[803] = Param(803, 0, u'shirt_red', u'shirt', 1, 0, 1, 1, '', '', '')
self.params[804] = Param(804, 0, u'shirt_green', u'shirt', 1, 0, 1, 1, '', '', '')
self.params[805] = Param(805, 0, u'shirt_blue', u'shirt', 1, 0, 1, 1, '', '', '')
self.params[806] = Param(806, 0, u'pants_red', u'pants', 1, 0, 1, 1, '', '', '')
self.params[807] = Param(807, 0, u'pants_green', u'pants', 1, 0, 1, 1, '', '', '')
self.params[808] = Param(808, 0, u'pants_blue', u'pants', 1, 0, 1, 1, '', '', '')
self.params[809] = Param(809, 1, u'lower_jacket_red', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[810] = Param(810, 1, u'lower_jacket_green', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[811] = Param(811, 1, u'lower_jacket_blue', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[812] = Param(812, 0, u'shoes_red', u'shoes', 1, 0, 1, 1, '', '', '')
self.params[813] = Param(813, 0, u'shoes_green', u'shoes', 1, 0, 1, 1, '', '', '')
self.params[814] = Param(814, 0, u'Waist Height', u'pants', 1, 0, 1, 1, '', u'Low', u'High')
self.params[815] = Param(815, 0, u'Pants Length', u'pants', .8, 0, 1, .8, '', u'Short', u'Long')
self.params[816] = Param(816, 0, u'Loose Lower Clothing', u'pants', 0.0, 0, 1, 0.0, u'Pants Fit', u'Tight Pants', u'Loose Pants')
self.params[817] = Param(817, 0, u'shoes_blue', u'shoes', 1, 0, 1, 1, '', '', '')
self.params[818] = Param(818, 0, u'socks_red', u'socks', 1, 0, 1, 1, '', '', '')
self.params[819] = Param(819, 0, u'socks_green', u'socks', 1, 0, 1, 1, '', '', '')
self.params[820] = Param(820, 0, u'socks_blue', u'socks', 1, 0, 1, 1, '', '', '')
self.params[821] = Param(821, 0, u'undershirt_red', u'undershirt', 1, 0, 1, 1, '', '', '')
self.params[822] = Param(822, 0, u'undershirt_green', u'undershirt', 1, 0, 1, 1, '', '', '')
self.params[823] = Param(823, 0, u'undershirt_blue', u'undershirt', 1, 0, 1, 1, '', '', '')
self.params[824] = Param(824, 0, u'underpants_red', u'underpants', 1, 0, 1, 1, '', '', '')
self.params[825] = Param(825, 0, u'underpants_green', u'underpants', 1, 0, 1, 1, '', '', '')
self.params[826] = Param(826, 0, u'underpants_blue', u'underpants', 1, 0, 1, 1, '', '', '')
self.params[827] = Param(827, 0, u'gloves_red', u'gloves', 1, 0, 1, 1, '', '', '')
self.params[828] = Param(828, 0, u'Loose Upper Clothing', u'shirt', 0.0, 0, 1, 0.0, u'Shirt Fit', u'Tight Shirt', u'Loose Shirt')
self.params[829] = Param(829, 0, u'gloves_green', u'gloves', 1, 0, 1, 1, '', '', '')
self.params[830] = Param(830, 0, u'gloves_blue', u'gloves', 1, 0, 1, 1, '', '', '')
self.params[831] = Param(831, 1, u'upper_jacket_red', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[832] = Param(832, 1, u'upper_jacket_green', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[833] = Param(833, 1, u'upper_jacket_blue', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[834] = Param(834, 0, u'jacket_red', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[835] = Param(835, 0, u'jacket_green', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[836] = Param(836, 0, u'jacket_blue', u'jacket', 1, 0, 1, 1, '', '', '')
self.params[840] = Param(840, 0, u'Shirtsleeve_flair', u'shirt', 0.0, 0, 1.5, 0.0, u'Sleeve Looseness', u'Tight Sleeves', u'Loose Sleeves')
self.params[841] = Param(841, 0, u'Bowed_Legs', u'shape', 0, -1, 1, 0, u'Knee Angle', u'Knock Kneed', u'Bow Legged')
self.params[842] = Param(842, 0, u'Hip Length', u'shape', 0.0, -1, 1, 0.0, '', u'Short hips', u'Long Hips')
self.params[843] = Param(843, 1, u'No_Chest', u'shape', 0.0, 0, 1, 0.0, u'Chest Size', u'Some', u'None')
self.params[844] = Param(844, 0, u'Glove Fingers', u'gloves', 1, .01, 1, 1, '', u'Fingerless', u'Fingers')
self.params[845] = Param(845, 1, u'skirt_poofy', u'skirt', 0.0, 0, 1.5, 0.0, u'poofy skirt', u'less poofy', u'more poofy')
self.params[846] = Param(846, 1, u'skirt_loose', u'skirt', 0.0, 0, 1, 0.0, u'loose skirt', u'form fitting', u'loose')
self.params[847] = Param(847, 1, u'skirt_bowlegs', u'skirt', 0, -1, 1, 0, u'legs skirt', '', '')
self.params[848] = Param(848, 0, u'skirt_bustle', u'skirt', .2, 0, 2, .2, u'bustle skirt', u'no bustle', u'more bustle')
self.params[849] = Param(849, 1, u'skirt_belly', '', 0.0, 0, 1, 0.0, u'big belly skirt', '', '')
self.params[850] = Param(850, 1, u'skirt_saddlebags', '', 0.0, -.5, 3, 0.0, '', '', '')
self.params[851] = Param(851, 1, u'skirt_chubby', '', 0, 0, 1, 0, '', u'less', u'more')
self.params[852] = Param(852, 1, u'skirt_bigbutt', '', 0.0, 0, 1, 0.0, u'bigbutt skirt', u'less', u'more')
self.params[853] = Param(853, 1, u'Bowed_Legs', u'shape', 0.0, -1, 1, 0.0, u'Knee Angle', '', '')
self.params[854] = Param(854, 1, u'Saddlebags', '', 0.0, -.5, 3, 0.0, '', '', '')
self.params[855] = Param(855, 1, u'Love_Handles', '', 0, -1, 2, 0, '', '', '')
self.params[856] = Param(856, 1, u'skirt_lovehandles', '', 0, -1, 2, 0, '', u'less', u'more')
self.params[857] = Param(857, 1, u'skirt_male', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[858] = Param(858, 0, u'Skirt Length', u'skirt', .4, .01, 1, .4, '', u'Short', u'Long')
self.params[859] = Param(859, 0, u'Slit Front', u'skirt', 1, 0, 1, 1, '', u'Open Front', u'Closed Front')
self.params[860] = Param(860, 0, u'Slit Back', u'skirt', 1, 0, 1, 1, '', u'Open Back', u'Closed Back')
self.params[861] = Param(861, 0, u'Slit Left', u'skirt', 1, 0, 1, 1, '', u'Open Left', u'Closed Left')
self.params[862] = Param(862, 0, u'Slit Right', u'skirt', 1, 0, 1, 1, '', u'Open Right', u'Closed Right')
self.params[863] = Param(863, 0, u'skirt_looseness', u'skirt', .333, 0, 1, .333, u'Skirt Fit', u'Tight Skirt', u'Poofy Skirt')
self.params[866] = Param(866, 1, u'skirt_tight', u'skirt', 0.0, 0, 1, 0.0, u'tight skirt', u'form fitting', u'loose')
self.params[867] = Param(867, 1, u'skirt_smallbutt', u'skirt', 0.0, 0, 1, 0.0, u'tight skirt', u'form fitting', u'loose')
self.params[868] = Param(868, 0, u'Shirt Wrinkles', u'shirt', 0, 0, 1, 0, '', '', '')
self.params[869] = Param(869, 0, u'Pants Wrinkles', u'pants', 0, 0, 1, 0, '', '', '')
self.params[870] = Param(870, 1, u'Pointy_Eyebrows', u'hair', 0.0, -.5, 1, 0.0, u'Eyebrow Points', u'Smooth', u'Pointy')
self.params[871] = Param(871, 1, u'Lower_Eyebrows', u'hair', 0.0, -2, 2, 0.0, u'Eyebrow Height', u'Higher', u'Lower')
self.params[872] = Param(872, 1, u'Arced_Eyebrows', u'hair', 0.0, 0, 1, 0.0, u'Eyebrow Arc', u'Flat', u'Arced')
self.params[873] = Param(873, 1, u'Bump base', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[874] = Param(874, 1, u'Bump upperdef', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[875] = Param(875, 1, u'jacket upper Wrinkles', u'jacket', 0, 0, 1, 0, '', '', '')
self.params[876] = Param(876, 1, u'jacket upper Wrinkles', u'jacket', 0, 0, 1, 0, '', '', '')
self.params[877] = Param(877, 0, u'Jacket Wrinkles', u'jacket', 0, 0, 1, 0, u'Jacket Wrinkles', u'No Wrinkles', u'Wrinkles')
self.params[878] = Param(878, 1, u'Bump upperdef', u'skin', 0.0, 0, 1, 0.0, '', '', '')
self.params[879] = Param(879, 0, u'Male_Package', u'shape', 0, -.5, 2, 0, u'Package', u'Coin Purse', u'Duffle Bag')
self.params[880] = Param(880, 0, u'Eyelid_Inner_Corner_Up', u'shape', 0.0, -1.3, 1.2, 0.0, u'Inner Eye Corner', u'Corner Down', u'Corner Up')
self.params[899] = Param(899, 1, u'Upper Clothes Shading', u'shirt', 0, 0, 1, 0, '', '', '')
self.params[900] = Param(900, 1, u'Sleeve Length Shadow', u'shirt', 0.02, 0.02, .87, 0.02, '', '', '')
self.params[901] = Param(901, 1, u'Shirt Shadow Bottom', u'shirt', 0.0, 0.02, 1, 0.0, '', '', '')
self.params[902] = Param(902, 1, u'Collar Front Shadow Height', u'shirt', 0.0, 0.02, 1, 0.0, '', '', '')
self.params[903] = Param(903, 1, u'Collar Back Shadow Height', u'shirt', 0.0, 0.02, 1, 0.0, '', '', '')
self.params[913] = Param(913, 1, u'Lower Clothes Shading', u'pants', 0, 0, 1, 0, '', '', '')
self.params[914] = Param(914, 1, u'Waist Height Shadow', u'pants', 0.0, 0.02, 1, 0.0, '', '', '')
self.params[915] = Param(915, 1, u'Pants Length Shadow', u'pants', 0.0, 0.02, 1, 0.0, '', '', '')
self.params[921] = Param(921, 0, u'skirt_red', u'skirt', 1, 0, 1, 1, '', '', '')
self.params[922] = Param(922, 0, u'skirt_green', u'skirt', 1, 0, 1, 1, '', '', '')
self.params[923] = Param(923, 0, u'skirt_blue', u'skirt', 1, 0, 1, 1, '', '', '')
self.params[1000] = Param(1000, 1, u'Eyebrow Size Bump', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[1001] = Param(1001, 1, u'Eyebrow Size', u'hair', 0.5, 0, 1, 0.5, '', '', '')
self.params[1002] = Param(1002, 1, u'Eyebrow Density Bump', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[1003] = Param(1003, 1, u'Eyebrow Density', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[1004] = Param(1004, 1, u'Sideburns bump', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[1005] = Param(1005, 1, u'Sideburns', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[1006] = Param(1006, 1, u'Moustache bump', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[1007] = Param(1007, 1, u'Moustache', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[1008] = Param(1008, 1, u'Soulpatch bump', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[1009] = Param(1009, 1, u'Soulpatch', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[1010] = Param(1010, 1, u'Chin Curtains bump', u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[1011] = Param(1011, 1, u'Chin Curtains', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[1012] = Param(1012, 1, u"5 O'Clock Shadow bump", u'hair', 0.0, 0, 1, 0.0, '', '', '')
self.params[1013] = Param(1013, 1, u'Sleeve Length Cloth', u'shirt', 0.0, 0, 0.85, 0.0, '', '', '')
self.params[1014] = Param(1014, 1, u'Shirt Bottom Cloth', u'shirt', 0.0, 0, 1, 0.0, '', '', '')
self.params[1015] = Param(1015, 1, u'Collar Front Height Cloth', u'shirt', 0.0, 0, 1, 0.0, '', '', '')
self.params[1016] = Param(1016, 1, u'Collar Back Height Cloth', u'shirt', 0.0, 0, 1, 0.0, '', '', '')
self.params[1017] = Param(1017, 1, u'Waist Height Cloth', u'pants', 0.0, 0, 1, 0.0, '', '', '')
self.params[1018] = Param(1018, 1, u'Pants Length Cloth', u'pants', 0.0, 0, 1, 0.0, '', '', '')
self.params[1019] = Param(1019, 1, u'Jacket Sleeve Length bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1020] = Param(1020, 1, u'jacket Sleeve Length', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[1021] = Param(1021, 1, u'Jacket Collar Front bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1022] = Param(1022, 1, u'jacket Collar Front', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[1023] = Param(1023, 1, u'Jacket Collar Back bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1024] = Param(1024, 1, u'jacket Collar Back', '', 0.0, 0, 1, 0.0, '', '', '')
self.params[1025] = Param(1025, 1, u'jacket bottom length upper bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1026] = Param(1026, 1, u'jacket open upper bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1027] = Param(1027, 1, u'jacket bottom length lower bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1028] = Param(1028, 1, u'jacket open lower bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1029] = Param(1029, 1, u'Sleeve Length Cloth', u'shirt', 0.0, 0, 0.85, 0.0, '', '', '')
self.params[1030] = Param(1030, 1, u'Shirt Bottom Cloth', u'shirt', 0.0, 0, 1, 0.0, '', '', '')
self.params[1031] = Param(1031, 1, u'Collar Front Height Cloth', u'shirt', 0.0, 0, 1, 0.0, '', '', '')
self.params[1032] = Param(1032, 1, u'Collar Back Height Cloth', u'shirt', 0.0, 0, 1, 0.0, '', '', '')
self.params[1033] = Param(1033, 1, u'jacket bottom length lower bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1034] = Param(1034, 1, u'jacket open lower bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1035] = Param(1035, 1, u'Waist Height Cloth', u'pants', 0.0, 0, 1, 0.0, '', '', '')
self.params[1036] = Param(1036, 1, u'Pants Length Cloth', u'pants', 0.0, 0, 1, 0.0, '', '', '')
self.params[1037] = Param(1037, 1, u'jacket bottom length upper bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1038] = Param(1038, 1, u'jacket open upper bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1039] = Param(1039, 1, u'Jacket Sleeve Length bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1040] = Param(1040, 1, u'Jacket Collar Front bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1041] = Param(1041, 1, u'Jacket Collar Back bump', u'jacket', 0.0, 0, 1, 0.0, '', '', '')
self.params[1042] = Param(1042, 1, u'Sleeve Length', u'undershirt', .4, .01, 1, .4, '', '', '')
self.params[1043] = Param(1043, 1, u'Sleeve Length bump', u'undershirt', .4, .01, 1, .4, '', '', '')
self.params[1044] = Param(1044, 1, u'Bottom', u'undershirt', .8, 0, 1, .8, '', '', '')
self.params[1045] = Param(1045, 1, u'Bottom bump', u'undershirt', .8, 0, 1, .8, '', '', '')
self.params[1046] = Param(1046, 1, u'Collar Front', u'undershirt', .8, 0, 1, .8, '', '', '')
self.params[1047] = Param(1047, 1, u'Collar Front bump', u'undershirt', .8, 0, 1, .8, '', '', '')
self.params[1048] = Param(1048, 1, u'Collar Back', u'undershirt', .8, 0, 1, .8, '', u'Low', u'High')
self.params[1049] = Param(1049, 1, u'Collar Back bump', u'undershirt', .8, 0, 1, .8, '', '', '')
self.params[1050] = Param(1050, 1, u'Socks Length bump', u'socks', 0.35, 0, 1, 0.35, '', '', '')
self.params[1051] = Param(1051, 1, u'Socks Length bump', u'socks', 0.35, 0, 1, 0.35, '', '', '')
self.params[1052] = Param(1052, 1, u'Shoe Height', u'shoes', 0.1, 0, 1, 0.1, '', '', '')
self.params[1053] = Param(1053, 1, u'Shoe Height bump', u'shoes', 0.1, 0, 1, 0.1, '', '', '')
self.params[1054] = Param(1054, 1, u'Pants Length', u'underpants', .3, 0, 1, .3, '', '', '')
self.params[1055] = Param(1055, 1, u'Pants Length', u'underpants', .3, 0, 1, .3, '', '', '')
self.params[1056] = Param(1056, 1, u'Pants Waist', u'underpants', .8, 0, 1, .8, '', '', '')
self.params[1057] = Param(1057, 1, u'Pants Waist', u'underpants', .8, 0, 1, .8, '', '', '')
self.params[1058] = Param(1058, 1, u'Glove Length', u'gloves', .8, .01, 1, .8, '', '', '')
self.params[1059] = Param(1059, 1, u'Glove Length bump', u'gloves', .8, .01, 1, .8, '', '', '')
self.params[1060] = Param(1060, 1, u'Glove Fingers', u'gloves', 1, .01, 1, 1, '', '', '')
self.params[1061] = Param(1061, 1, u'Glove Fingers bump', u'gloves', 1, .01, 1, 1, '', '', '')