removing components from base that will llive in client
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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))
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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']
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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, '', '', '')
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user