diff --git a/pyogp/lib/base/agent.py b/pyogp/lib/base/agent.py index 15f575d..572fb2b 100644 --- a/pyogp/lib/base/agent.py +++ b/pyogp/lib/base/agent.py @@ -1,34 +1,32 @@ # standard python libs -from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG +from logging import getLogger, WARNING, INFO, DEBUG import re import sys import signal -import uuid import sets +import struct #related from eventlet import api # pyogp from pyogp.lib.base.login import Login, LegacyLoginParams, OGPLoginParams -from pyogp.lib.base.datatypes import * +from pyogp.lib.base.datatypes import Quaternion, Vector3, UUID from pyogp.lib.base.exc import LoginError from pyogp.lib.base.region import Region -from pyogp.lib.base.inventory import * -from pyogp.lib.base.groups import * -from pyogp.lib.base.event_system import * -from pyogp.lib.base.appearance import * -from pyogp.lib.base.assets import * +from pyogp.lib.base.inventory import AIS, UDP_Inventory +from pyogp.lib.base.groups import GroupManager, Group +from pyogp.lib.base.event_system import AppEventsHandler, AppEvent +from pyogp.lib.base.appearance import AppearanceManager +from pyogp.lib.base.assets import AssetManager # pyogp messaging -from pyogp.lib.base.message.message_handler import MessageHandler - -from pyogp.lib.base.message.packets import * +from pyogp.lib.base.message.message import Message, Block # pyogp utilities from pyogp.lib.base.utilities.helpers import Helpers -from pyogp.lib.base.utilities.enums import * - +#from pyogp.lib.base.utilities.enums import ImprovedIMDialogue +from pyogp.lib.base.utilities.enums import ImprovedIMDialogue, MoneyTransactionType, TransactionFlags, AgentState, AgentUpdateFlags, AgentControlFlags # initialize logging logger = getLogger('pyogp.lib.base.agent') @@ -83,6 +81,13 @@ class Agent(object): self.session_id = None self.secure_session_id = None self.name = self.Name() + self.active_group_powers = None + self.active_group_name = None + self.active_group_title = None + self.active_group_id = None + self.health = None + self._login_params = None + self.circuit_code = None # other storage containers self.inventory_host = None @@ -112,7 +117,7 @@ class Agent(object): self.Acceleration = Vector3() self.Rotation = Vector3() self.AngularVelocity = Vector3() - + # movement self.state = AgentState.Null # typing, editing self.control_flags = 0 @@ -134,7 +139,8 @@ class Agent(object): # Cache of agent_id->(first_name, last_name); per agent to prevent info leaks self.agent_id_map = {} - if self.settings.LOG_VERBOSE: log(DEBUG, 'Initializing agent: %s' % (self)) + if self.settings.LOG_VERBOSE: + log(DEBUG, 'Initializing agent: %s' % (self)) def Name(self): """ returns a concatenated firstname + ' ' + lastname""" @@ -172,7 +178,7 @@ class Agent(object): else: - self._login_params = self._get_login_params(loginuri, self.firstname, self.lastname, self.password) + self._login_params = self._get_login_params(self.firstname, self.lastname, self.password) else: @@ -191,7 +197,7 @@ class Agent(object): if connect_region: self._enable_current_region() - + def logout(self): """ logs an agent out of the current region. calls Region()._kill_coroutines() for all child regions, and Region().logout() for the host region """ @@ -207,7 +213,7 @@ class Agent(object): else: # kill udp and or event queue for child regions - [region._kill_coroutines() for region in self.child_regions] + [region.kill_coroutines() for region in self.child_regions] if self.region.logout(): self.connected = False @@ -215,7 +221,7 @@ class Agent(object): # zero out the password in case we dump it somewhere self.password = '' - def _get_login_params(self, loginuri, firstname, lastname, password): + def _get_login_params(self, firstname, lastname, password): """ get the proper login parameters of the legacy or ogp enabled grid """ if self.grid_type == 'OGP': @@ -245,7 +251,8 @@ class Agent(object): self.udp_blacklist = self.login_response['udp_blacklist'] self.start_location = self.login_response['start_location'] - if self.login_response.has_key('home'): self.home = Home(self.login_response['home']) + if self.login_response.has_key('home'): + self.home = Home(self.login_response['home']) elif self.grid_type == 'OGP': @@ -271,13 +278,14 @@ class Agent(object): self.region.is_host_region = True # start the simulator udp and event queue connections - if self.settings.LOG_COROUTINE_SPAWNS: log(INFO, "Spawning a coroutine for connecting to the agent's host region.") + if self.settings.LOG_COROUTINE_SPAWNS: + log(INFO, "Spawning a coroutine for connecting to the agent's host region.") api.spawn(self.region.connect) - + self.enable_callbacks() - + def _enable_child_region(self, region_params): """ enables a child region. eligible simulators are sent in EnableSimulator over the event queue, and routed through the packet handler """ @@ -288,13 +296,20 @@ class Agent(object): log(DEBUG, "Not enabling a region we are already connected to: %s" % (str(region_params['IP']) + ":" + str(region_params['Port']))) return - child_region = Region(circuit_code = self.circuit_code, sim_ip = region_params['IP'], sim_port = region_params['Port'], handle = region_params['Handle'], agent = self, settings = self.settings, events_handler = self.events_handler) + child_region = Region(circuit_code = self.circuit_code, + sim_ip = region_params['IP'], + sim_port = region_params['Port'], + handle = region_params['Handle'], + agent = self, + settings = self.settings, + events_handler = self.events_handler) self.child_regions.append(child_region) log(INFO, "Enabling a child region with ip:port of %s" % (str(region_params['IP']) + ":" + str(region_params['Port']))) - if self.settings.LOG_COROUTINE_SPAWNS: log(INFO, "Spawning a coroutine for connecting to a neighboring region.") + if self.settings.LOG_COROUTINE_SPAWNS: + log(INFO, "Spawning a coroutine for connecting to a neighboring region.") api.spawn(child_region.connect_child) @@ -306,7 +321,7 @@ class Agent(object): if len(self._pending_child_regions) > 0: for region_params in self._pending_child_regions: - + self._enable_child_region(region_params) self._pending_child_regions.remove(region_params) @@ -329,28 +344,28 @@ class Agent(object): def enable_callbacks(self): """ enable the Agents() callback handlers for packet received events """ # TODO oopify - + if self.settings.ENABLE_INVENTORY_MANAGEMENT: while self.region.capabilities == {}: api.sleep(0) - + inventory_caps = ['FetchInventory', 'WebFetchInventoryDescendents', 'FetchLib', 'FetchLibDescendents'] - + if sets.Set(self.region.capabilities.keys()).intersection(inventory_caps): - + caps = dict([(capname, self.region.capabilities[capname]) for capname in inventory_caps]) - + log(INFO, "Using the capability based inventory management mechanism") - + self.inventory = AIS(self, caps) - + else: - + log(INFO, "Using the UDP based inventory management mechanism") - + self.inventory = UDP_Inventory(self) - + self.inventory._parse_folders_from_login_response() self.inventory.enable_callbacks() @@ -397,7 +412,7 @@ class Agent(object): if self.settings.ENABLE_COMMUNICATIONS_TRACKING: onChatFromSimulator_received = self.region.message_handler.register('ChatFromSimulator') onChatFromSimulator_received.subscribe(self.onChatFromSimulator) - + def simple_callback(self, blockname): """Generic callback creator for single-block packets.""" @@ -411,18 +426,18 @@ class Agent(object): return AppEvent(packet.name, payload=payload) - return lambda p: self.events_handler._handle(repack(p, blockname)) + return lambda p: self.events_handler.handle(repack(p, blockname)) def send_AgentDataUpdateRequest(self): """ queues a packet requesting an agent data update """ - packet = AgentDataUpdateRequestPacket() + packet = Message('AgentDataUpdateRequest', + Block('AgentData', + AgentID = self.agent_id, + SessionID = self.session_id)) - packet.AgentData['AgentID'] = self.agent_id - packet.AgentData['SessionID'] = self.session_id - - self.region.enqueue_message(packet()) + self.region.enqueue_message(packet) # ~~~~~~~~~~~~~~ # Communications @@ -430,7 +445,10 @@ class Agent(object): # Chat - def say(self, Message, Type = 1, Channel = 0): + def say(self, + _Message, + Type = 1, + Channel = 0): """ queues a packet to send open chat via ChatFromViewer Channel: 0 is open chat @@ -439,25 +457,29 @@ class Agent(object): 2 = Shout """ - packet = ChatFromViewerPacket() + packet = Message('ChatFromViewer', + Block('AgentData', + AgentID = self.agent_id, + SessionID = self.session_id), + Block('ChatData', + Message = _Message, + Type = Type, + Channel = Channel)) - packet.AgentData['AgentID'] = self.agent_id - packet.AgentData['SessionID'] = self.session_id - - packet.ChatData['Message'] = Message - packet.ChatData['Type'] = Type - packet.ChatData['Channel'] = Channel - - self.region.enqueue_message(packet()) + self.region.enqueue_message(packet) # Instant Message (im, group chat) - def instant_message(self, ToAgentID = None, Message = None, _ID = None): + def instant_message(self, + ToAgentID = None, + _Message = None, + _ID = None): """ sends an instant message to another avatar, wrapping Agent().send_ImprovedInstantMessage() with some handy defaults """ - if ToAgentID != None and Message != None: + if ToAgentID != None and _Message != None: - if _ID == None: _ID = self.agent_id + if _ID == None: + _ID = self.agent_id _AgentID = self.agent_id _SessionID = self.session_id @@ -471,65 +493,81 @@ class Agent(object): _ID = _ID _Timestamp = 0 _FromAgentName = self.firstname + ' ' + self.lastname - _Message = Message + _Message = _Message _BinaryBucket = '' - self.send_ImprovedInstantMessage(_AgentID, _SessionID, _FromGroup, _ToAgentID, _ParentEstateID, _RegionID, _Position, _Offline, _Dialog, _ID, _Timestamp, _FromAgentName, _Message, _BinaryBucket) + self.send_ImprovedInstantMessage(_AgentID, + _SessionID, + _FromGroup, + _ToAgentID, + _ParentEstateID, + _RegionID, + _Position, + _Offline, + _Dialog, + _ID, + _Timestamp, + _FromAgentName, + _Message, + _BinaryBucket) else: log(INFO, "Please specify an agentid and message to send in agent.instant_message") - def send_ImprovedInstantMessage(self, AgentID = None, SessionID = None, FromGroup = None, ToAgentID = None, ParentEstateID = None, RegionID = None, Position = None, Offline = None, Dialog = None, _ID = None, Timestamp = None, FromAgentName = None, Message = None, BinaryBucket = None, AgentDataBlock = {}, MessageBlockBlock = {}): + def send_ImprovedInstantMessage(self, + AgentID = None, + SessionID = None, + FromGroup = None, + ToAgentID = None, + ParentEstateID = None, + RegionID = None, + Position = None, + Offline = None, + Dialog = None, + _ID = None, + Timestamp = None, + FromAgentName = None, + _Message = None, + BinaryBucket = None): """ sends an instant message packet to ToAgentID. this is a multi-purpose message for inventory offer handling, im, group chat, and more """ - packet = ImprovedInstantMessagePacket() + packet = Message('ImprovedInstantMessage', + Block('AgentData', + AgentID = AgentID, + SessionID = SessionID), + Block('MessageBlock', + FromGroup = FromGroup, + ToAgentID = ToAgentID, + ParentEstateID = ParentEstateID, + RegionID = RegionID, + Position = Position, + Offline = Offline, + Dialog = Dialog, + ID = UUID(str(_ID)), + Timestamp = Timestamp, + FromAgentName = FromAgentName, + Message = _Message, + BinaryBucket = BinaryBucket)) - if AgentDataBlock == {}: - packet.AgentData['AgentID'] = AgentID - packet.AgentData['SessionID'] = SessionID - else: - packet.AgentData = AgentDataBlock + self.region.enqueue_message(packet, True) - if FromAgentName == None: - FromAgentName = self.Name() - - # ha! when scripting out packets.py, never considered a block named *block - if MessageBlockBlock == {}: - - packet.MessageBlock['FromGroup'] = FromGroup # Bool - packet.MessageBlock['ToAgentID'] = UUID(str(ToAgentID)) # LLUUID - packet.MessageBlock['ParentEstateID'] = ParentEstateID # U32 - packet.MessageBlock['RegionID'] = UUID(str(RegionID)) # LLUUID - packet.MessageBlock['Position'] = Position() # LLVector3 - packet.MessageBlock['Offline'] = Offline # U8 - packet.MessageBlock['Dialog'] = Dialog # U8 IM Type - packet.MessageBlock['ID'] = UUID(str(_ID)) # LLUUID - packet.MessageBlock['Timestamp'] = Timestamp # U32 - packet.MessageBlock['FromAgentName'] = FromAgentName # Variable 1 - packet.MessageBlock['Message'] = Message # Variable 2 - packet.MessageBlock['BinaryBucket'] = BinaryBucket # Variable 2 - - self.region.enqueue_message(packet(), True) - def send_RetrieveInstantMessages(self): """ asks simulator for instant messages stored while agent was offline """ - - packet = RetrieveInstantMessagesPackets() - - packet.AgentDataBlock['AgentID'] = self.agent_id - packet.AgentDataBlock['SessionID'] = self.session_id - + + packet = Message('RetrieveInstantMessages', + Block('AgentData', + AgentID = self.agent_id, + SessionID = self.session_id)) + self.region.enqueue_message(packet()) - def sigint_handler(self, signal, frame): + def sigint_handler(self, signal_sent, frame): """ catches terminal signals (Ctrl-C) to kill running client instances """ - log(INFO, "Caught signal... %d. Stopping" % signal) - #self.running = False + log(INFO, "Caught signal... %d. Stopping" % signal_sent) self.logout() - #sys.exit(0) def __repr__(self): """ returns a representation of the agent """ @@ -551,13 +589,13 @@ class Agent(object): if self.lastname == None: self.firstname = packet.blocks['AgentData'][0].get_variable('LastName').data - self.GroupTitle = packet.blocks['AgentData'][0].get_variable('GroupTitle').data + self.active_group_title = packet.blocks['AgentData'][0].get_variable('GroupTitle').data - self.ActiveGroupID = packet.blocks['AgentData'][0].get_variable('ActiveGroupID').data + self.active_group_id = packet.blocks['AgentData'][0].get_variable('ActiveGroupID').data - self.GroupPowers = packet.blocks['AgentData'][0].get_variable('GroupPowers').data + self.active_group_powers = packet.blocks['AgentData'][0].get_variable('GroupPowers').data - self.GroupName = packet.blocks['AgentData'][0].get_variable('GroupName').data + self.active_group_name = packet.blocks['AgentData'][0].get_variable('GroupName').data def onAgentMovementComplete(self, packet): """ callback handler for received AgentMovementComplete messages which populates various Agent() and Region() attributes """ @@ -586,7 +624,7 @@ class Agent(object): payload['Acceleration'] = self.Acceleration payload['Rotation'] = self.Rotation payload['AngularVelocity'] = self.AngularVelocity - self.events_handler._handle(AppEvent("AgentDynamicsUpdate", payload=payload)) + self.events_handler.handle(AppEvent("AgentDynamicsUpdate", payload=payload)) def onHealthMessage(self, packet): """ callback handler for received HealthMessage messages which populates Agent().health """ @@ -597,7 +635,7 @@ class Agent(object): """ callback handler for received AgentGroupDataUpdate messages which updates stored group instances in the group_manager """ # AgentData block - AgentID = packet.blocks['AgentData'][0].get_variable('AgentID').data + # AgentID = packet.blocks['AgentData'][0].get_variable('AgentID').data # GroupData block for GroupData_block in packet.blocks['GroupData']: @@ -614,15 +652,13 @@ class Agent(object): GroupPowers = [ord(x) for x in GroupPowers] GroupPowers = ''.join([str(x) for x in GroupPowers]) - group = Group(AcceptNotices, GroupPowers, GroupID, GroupName, ListInProfile, Contribution,GroupInsigniaID ) + group = Group(AcceptNotices, GroupPowers, GroupID, GroupName, ListInProfile, Contribution, GroupInsigniaID ) self.group_manager.store_group(group) def onChatFromSimulator(self, packet): """ callback handler for received ChatFromSimulator messages which parses and fires a ChatReceived event. """ - log(INFO, "Working on parsing chat messages....") - FromName = packet.blocks['ChatData'][0].get_variable('FromName').data SourceID = packet.blocks['ChatData'][0].get_variable('SourceID').data OwnerID = packet.blocks['ChatData'][0].get_variable('OwnerID').data @@ -630,19 +666,25 @@ class Agent(object): ChatType = packet.blocks['ChatData'][0].get_variable('ChatType').data Audible = packet.blocks['ChatData'][0].get_variable('Audible').data Position = packet.blocks['ChatData'][0].get_variable('Position').data - Message = packet.blocks['ChatData'][0].get_variable('Message').data + _Message = packet.blocks['ChatData'][0].get_variable('Message').data - message = AppEvent('ChatReceived', FromName = FromName, SourceID = SourceID, OwnerID = OwnerID, SourceType = SourceType, ChatType = ChatType, Audible = Audible, Position = Position, Message = Message) + message = AppEvent('ChatReceived', + FromName = FromName, + SourceID = SourceID, + OwnerID = OwnerID, + SourceType = SourceType, + ChatType = ChatType, + Audible = Audible, + Position = Position, + Message = _Message) - log(INFO, "Received chat from %s: %s" % (FromName, Message)) + log(INFO, "Received chat from %s: %s" % (FromName, _Message)) - self.events_handler._handle(message) + self.events_handler.handle(message) def onImprovedInstantMessage(self, packet): """ callback handler for received ImprovedInstantMessage messages. much is passed in this message, and handling the data is only partially implemented """ - log(INFO, "Working on parsing ImprovedInstantMessage messages....") - Dialog = packet.blocks['MessageBlock'][0].get_variable('Dialog').data FromAgentID = packet.blocks['AgentData'][0].get_variable('AgentID').data @@ -674,13 +716,13 @@ class Agent(object): Position = packet.blocks['MessageBlock'][0].get_variable('Position').data ID = packet.blocks['MessageBlock'][0].get_variable('ID').data FromAgentName = packet.blocks['MessageBlock'][0].get_variable('FromAgentName').data - Message = packet.blocks['MessageBlock'][0].get_variable('Message').data + _Message = packet.blocks['MessageBlock'][0].get_variable('Message').data - message = AppEvent('InstantMessageReceived', FromAgentID = FromAgentID, RegionID = RegionID, Position = Position, ID = ID, FromAgentName = FromAgentName, Message = Message) + message = AppEvent('InstantMessageReceived', FromAgentID = FromAgentID, RegionID = RegionID, Position = Position, ID = ID, FromAgentName = FromAgentName, Message = _Message) - log(INFO, "Received instant message from %s: %s" % (FromAgentName, Message)) + log(INFO, "Received instant message from %s: %s" % (FromAgentName, _Message)) - self.events_handler._handle(message) + self.events_handler.handle(message) else: @@ -689,12 +731,14 @@ class Agent(object): def onAlertMessage(self, packet): """ callback handler for received AlertMessage messages. logs and raises an event """ - # ToDo: raise an event when this is received - AlertMessage = packet.blocks['AlertData'][0].get_variable('Message').data + message = AppEvent('AlertMessage', AlertMessage = AlertMessage) + log(WARNING, "AlertMessage from simulator: %s" % (AlertMessage)) + self.events_handler.handle(message) + def onEnableSimulator(self, packet): """ callback handler for received EnableSimulator messages. stores the region data for later connections """ @@ -752,9 +796,9 @@ class Agent(object): """Initiate a teleport to the specified location. When passing a region name it may be necessary to request the destination region handle from the current sim before the teleport can start.""" - + log(INFO, 'teleport name=%s handle=%s id=%s', str(region_name), str(region_handle), str(region_id)) - + # Handle intra-region teleports even by name if not region_id and region_name and region_name.lower() == self.region.SimName.lower(): region_id = self.region.RegionID @@ -764,30 +808,34 @@ class Agent(object): region_handle = self.region_name_map[region_name.lower()] if region_id: - log(INFO, 'sending TP request packet') - packet = TeleportRequestPacket() - packet.AgentData['AgentID'] = self.agent_id - packet.AgentData['SessionID'] = self.session_id - - packet.Info['RegionID'] = region_id - packet.Info['Position'] = position - packet.Info['LookAt'] = look_at - - self.region.enqueue_message(packet()) + log(INFO, 'sending TP request packet') + + packet = Message('TeleportRequest', + Block('AgentData', + AgentID = self.agent_id, + SessionID = self.session_id), + Block('Info', + RegionID = region_id, + Position = position, + LookAt = look_at)) + + self.region.enqueue_message(packet) elif region_handle: - log(INFO, 'sending TP location request packet') - packet = TeleportLocationRequestPacket() - packet.AgentData['AgentID'] = self.agent_id - packet.AgentData['SessionID'] = self.session_id - - packet.Info['RegionHandle'] = region_handle - packet.Info['Position'] = position - packet.Info['LookAt'] = look_at - - self.region.enqueue_message(packet()) + log(INFO, 'sending TP location request packet') + + packet = Message('TeleportLocationRequest', + Block('AgentData', + AgentID = self.agent_id, + SessionID = self.session_id), + Block('Info', + RegionHandle = region_handle, + Position = position, + LookAt = look_at)) + + self.region.enqueue_message(packet) else: log(INFO, "Target region's handle not known, sending map name request") @@ -795,21 +843,27 @@ class Agent(object): self.send_MapNameRequest( region_name, lambda handle: self.teleport(region_handle=handle, position=position, look_at=look_at)) - - + + def send_MapNameRequest(self, region_name, callback): + """ sends a MapNameRequest message to the host simulator """ handler = self.region.message_handler.register('MapBlockReply') - + def onMapBlockReplyPacket(packet): + """ handles the MapBlockReply message from a simulator """ + log(INFO, 'MapBlockReplyPacket received') + for block in packet.blocks['Data']: + if block.get_variable('Name').data.lower() == region_name.lower(): + handler.unsubscribe(onMapBlockReplyPacket) x = block.get_variable('X').data y = block.get_variable('Y').data - region_handle = Region.xy_to_handle(x,y) + region_handle = Region.xy_to_handle(x, y) if region_handle: self.region_name_map[region_name.lower()] = region_handle @@ -821,20 +875,24 @@ class Agent(object): return # Leave it registered, as the event may come later - + # Register a handler for the response handler.subscribe(onMapBlockReplyPacket) # ...and make the request log(INFO, 'sending MapNameRequestPacket') - packet = MapNameRequestPacket() - packet.AgentData['AgentID'] = self.agent_id - packet.AgentData['SessionID'] = self.session_id - packet.AgentData['Flags'] = 0 - packet.AgentData['EstateID'] = 0 - packet.AgentData['Godlike'] = False - packet.NameData['Name'] = region_name.lower() - self.region.enqueue_message(packet()) + + packet = Message('MapNameRequest', + Block('AgentData', + AgentID = self.agent_id, + SessionID = self.session_id, + Flags = 0, + EstateID = 0, + Godlike = False), + Block('NameData', + Name = region_name.lower())) + + self.region.enqueue_message(packet) def onTeleportFinish(self, packet): """Handle the end of a successful teleport""" @@ -850,12 +908,12 @@ class Agent(object): # packed binary to dotted-octet sim_ip = packet.blocks['Info'][0].get_variable('SimIP').data - sim_ip = '.'.join(map(str,struct.unpack('BBBB', sim_ip))) + sim_ip = '.'.join(map(str, struct.unpack('BBBB', sim_ip))) # *TODO: Make this more graceful log(INFO, "Disconnecting from old region") - [region._kill_coroutines() for region in self.child_regions] - self.region._kill_coroutines() + [region.kill_coroutines() for region in self.child_regions] + self.region.kill_coroutines() self.region = None self.child_regions = [] @@ -870,20 +928,19 @@ class Agent(object): sim_port = packet.blocks['Info'][0].get_variable('SimPort').data ) - def request_agent_names(self, agent_ids, callback): """Request agent names. When all names are known, callback will be called with a list of tuples (agent_id, first_name, last_name). If all names are known, callback will be called immediately.""" - + def _fire_callback(_): cbdata = [(agent_id, self.agent_id_map[agent_id][0], self.agent_id_map[agent_id][1]) for agent_id in agent_ids] callback(cbdata) - + names_to_request = [ agent_id for agent_id in agent_ids if agent_id not in self.agent_id_map ] @@ -894,11 +951,14 @@ class Agent(object): def send_UUIDNameRequest(self, agent_ids, callback): + """ sends a UUIDNameRequest message to the host simulator """ + handler = self.region.message_handler.register('UUIDNameReply') def onUUIDNameReply(packet): + """ handles the UUIDNameReply message from a simulator """ log(INFO, 'UUIDNameReplyPacket received') - + cbdata = [] for block in packet.blocks['UUIDNameBlock']: agent_id = str(block.get_variable('ID').data) @@ -915,13 +975,16 @@ class Agent(object): handler.unsubscribe(onUUIDNameReply) callback(cbdata) else: - log(INFO, 'Still waiting on %d names', len(missing)) - + log(INFO, 'Still waiting on %d names in send_UUIDNameRequest', len(missing)) + handler.subscribe(onUUIDNameReply) + log(INFO, 'sending UUIDNameRequest') - packet = UUIDNameRequestPacket() - packet.UUIDNameBlockBlocks = [ {'ID':UUID(agent_id) } for agent_id in agent_ids ] - self.region.enqueue_message(packet()) + + packet = Message('UUIDNameRequest', + [Block('UUIDNameBlock', ID = UUID(agent_id)) for agent_id in agent_ids]) + + self.region.enqueue_message(packet) # *TODO: Should use this instead, but somehow it fails ?!? #self.region.sendUUIDNameRequest(agent_ids=agent_ids) @@ -931,51 +994,63 @@ class Agent(object): handler = self.region.message_handler.register('MoneyBalanceReply') def onMoneyBalanceReply(packet): + """ handles the MoneyBalanceReply message from a simulator """ log(INFO, 'MoneyBalanceReply received') handler.unsubscribe(onMoneyBalanceReply) # One-shot handler balance = packet.blocks['MoneyData'][0].get_variable('MoneyBalance').data callback(balance) handler.subscribe(onMoneyBalanceReply) + log(INFO, 'sending MoneyBalanceRequest') - packet = MoneyBalanceRequestPacket() - packet.AgentData['AgentID'] = self.agent_id - packet.AgentData['SessionID'] = self.session_id - packet.MoneyData['TransactionID'] = UUID() - self.region.enqueue_message(packet()) - + + packet = Message('MoneyBalanceRequest', + Block('AgentData', + AgentID = self.agent_id, + SessionID = self.session_id), + Block('MoneyData', + TransactionID = UUID())) + + self.region.enqueue_message(packet) def give_money(self, target_id, amount, description='', transaction_type=MoneyTransactionType.Gift, flags=TransactionFlags.Null): """Give money to another agent""" - log(INFO, 'sending MoneyTransferRequest') - packet = MoneyTransferRequestPacket() - packet.AgentData['AgentID'] = self.agent_id - packet.AgentData['SessionID'] = self.session_id - packet.MoneyData['SourceID'] = self.agent_id - packet.MoneyData['DestID'] = UUID(target_id) - packet.MoneyData['Flags'] = flags - packet.MoneyData['Amount'] = amount - packet.MoneyData['AggregatePermNextOwner'] = 0 - packet.MoneyData['AggregatePermInventory'] = 0 - packet.MoneyData['TransactionType'] = transaction_type - packet.MoneyData['Description'] = description - self.region.enqueue_message(packet()) + log(INFO, 'sending MoneyTransferRequest') + + packet = Message('MoneyTransferRequest', + Block('AgentData', + AgentID = self.agent_id, + SessionID = self.session_id), + Block('MoneyData', + SourceID = self.agent_id, + DestID = UUID(target_id), + Flags = flags, + Amount = amount, + AggregatePermNextOwner = 0, + AggregatePermInventory = 0, + TransactionType = transaction_type, + Description = description)) + + self.region.enqueue_message(packet) def sit_on_ground(self): """Sit on the ground at the agent's current location""" + self.control_flags |= AgentControlFlags.SitOnGround self._send_update() def stand(self): """Stand up from sitting""" + # Start standing... self.control_flags &= ~AgentControlFlags.SitOnGround self.control_flags |= AgentControlFlags.StandUp self._send_update() + # And finish standing self.control_flags &= ~AgentControlFlags.StandUp self._send_update() @@ -983,14 +1058,19 @@ class Agent(object): def fly(self, flying=True): """Start or stop flying""" + if flying: self.control_flags |= AgentControlFlags.Fly else: self.control_flags &= ~AgentControlFlags.Fly + self._send_update() def _send_update(self): + """ force a send of an AgentUpdate message to the host simulator """ + log(INFO, 'sending AgentUpdate') + self.region.sendAgentUpdate( State=self.state, ControlFlags=self.control_flags, @@ -1002,7 +1082,7 @@ class Agent(object): Far = self.settings.DEFAULT_CAMERA_DRAW_DISTANCE ) - + class Home(object): """ contains the parameters describing an agent's home location as returned in login_response['home'] """ @@ -1024,9 +1104,9 @@ class Home(object): self.global_x = self.region_handle[0] self.global_y = self.region_handle[1] - self.local_x = self.position[0] - self.local_y = self.position[1] - self.local_z = self.position[2] + # convert the position and lookat to a Vector3 instance + self.look_at = Vector3(X=self.look_at[0], Y=self.look_at[1], Z=self.look_at[2]) + self.position = Vector3(X=self.position[0], Y=self.position[1], Z=self.position[2]) """ Contributors can be viewed at: diff --git a/pyogp/lib/base/event_system.py b/pyogp/lib/base/event_system.py index f476fd9..7fa693d 100644 --- a/pyogp/lib/base/event_system.py +++ b/pyogp/lib/base/event_system.py @@ -49,7 +49,7 @@ class AppEventsHandler(object): return False - def _handle(self, event): + def handle(self, event): """ essentially a case statement to pass event data to notifiers """ try: diff --git a/pyogp/lib/base/region.py b/pyogp/lib/base/region.py index e0e4e74..2b2e57f 100644 --- a/pyogp/lib/base/region.py +++ b/pyogp/lib/base/region.py @@ -337,8 +337,8 @@ class Region(object): raise return False - def _kill_coroutines(self): - """ end processes spawned by the child regions """ + def kill_coroutines(self): + """ trigger to end processes spawned by the child regions """ self._isUDPRunning = False self._stopEventQueue() diff --git a/pyogp/lib/base/tests/test_agent.py b/pyogp/lib/base/tests/test_agent.py index 08a9e45..6a0bdd5 100644 --- a/pyogp/lib/base/tests/test_agent.py +++ b/pyogp/lib/base/tests/test_agent.py @@ -75,14 +75,14 @@ class TestAgent(unittest.TestCase): def test_legacy_get_login_params(self): self.client.grid_type = 'Legacy' - params = self.client._get_login_params(self.legacy_loginuri, self.firstname, self.lastname, self.password) + params = self.client._get_login_params(self.firstname, self.lastname, self.password) self.assertEquals(type(params), type(LegacyLoginParams(self.firstname, self.lastname, self.password))) def test_ogp_get_login_params(self): self.client.grid_type = 'OGP' - params = self.client._get_login_params(self.ogp_loginuri, self.firstname, self.lastname, self.password) + params = self.client._get_login_params(self.firstname, self.lastname, self.password) self.assertEquals(type(params), type(OGPLoginParams(self.firstname, self.lastname, self.password))) @@ -102,7 +102,16 @@ class TestAgent(unittest.TestCase): home = Home(home_string) # Note: have not yet worked out precision on floats. Kinda need to - self.assertEquals(home.__dict__, {'local_z': 79.393799999999999, 'local_y': 148.25999999999999, 'local_x': 171.62200000000001, 'look_at': [0, 1, 0], 'global_x': 261120, 'global_y': 247040, 'region_handle': [261120, 247040], 'position': [171.62200000000001, 148.25999999999999, 79.393799999999999]}) + self.assertEquals(home.region_handle, [261120, 247040]) + self.assertEquals(home.position.X, 171.62200000000001) + self.assertEquals(home.position.Y, 148.25999999999999) + self.assertEquals(home.position.Z, 79.393799999999999) + self.assertEquals(home.look_at.X, 0) + self.assertEquals(home.look_at.Y, 1) + self.assertEquals(home.look_at.Z, 0) + self.assertEquals(home.global_x, 261120) + self.assertEquals(home.global_y, 247040) + def test_suite(): from unittest import TestSuite, makeSuite diff --git a/pyogp/lib/base/tests/test_event_queue.py b/pyogp/lib/base/tests/test_event_queue.py index 3f727a2..56feea0 100644 --- a/pyogp/lib/base/tests/test_event_queue.py +++ b/pyogp/lib/base/tests/test_event_queue.py @@ -87,6 +87,7 @@ class TestEventQueue(unittest.TestCase): self.eq.stopped = True api.sleep(.1) self.assertTrue(self.eq.stopped) + api.sleep(1) self.assertFalse(self.eq._running) def test_suite(): diff --git a/pyogp/lib/base/tests/test_event_system.py b/pyogp/lib/base/tests/test_event_system.py index 504ed9c..f342a0c 100644 --- a/pyogp/lib/base/tests/test_event_system.py +++ b/pyogp/lib/base/tests/test_event_system.py @@ -28,7 +28,7 @@ class TestEvents(unittest.TestCase): handler = eventshandler.register('MockEvent') handler.subscribe(self.onEvent, mock) - eventshandler._handle(mock) + eventshandler.handle(mock) def test_event_handler_timeout(self):