1081 lines
40 KiB
Python
1081 lines
40 KiB
Python
# standard python modules
|
|
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
|
|
|
|
# related
|
|
from eventlet import api
|
|
|
|
# pyogp
|
|
from pyogp.lib.base.settings import Settings
|
|
|
|
# pyogp messaging
|
|
from pyogp.lib.base.message.packets import *
|
|
|
|
# utilities
|
|
from pyogp.lib.base.utilities.helpers import Helpers
|
|
|
|
# pyogp messaging
|
|
|
|
# pyogp utilities
|
|
|
|
# initialize logging
|
|
logger = getLogger('pyogp.lib.base.parcel')
|
|
log = logger.log
|
|
|
|
# ToDo: unhandled related messages
|
|
# ForceObjectSelect
|
|
# ParcelBuyPass
|
|
# ParcelAccessListUpdate
|
|
# ParcelDwellRequest
|
|
# ParcelDwellReply
|
|
# ParcelGodMarkAsContent
|
|
# ViewerStartAuction
|
|
# ParcelObjectOwnersRequest
|
|
# ParcelObjectOwnersReply
|
|
|
|
# non client oriented related messages
|
|
# #RequestParcelTransfer (sim->dataserver)
|
|
# #UpdateParcel (sim->dataserver)
|
|
# #RemoveParcel (sim->dataserver)
|
|
# #MergeParcel (sim->dataserver)
|
|
# #LogParcelChanges (sim->dataserver)
|
|
# #CheckParcelSales (sim->dataserver)
|
|
# #ParcelSales (dataserver->sim)
|
|
# #StartAuction (sim->dataserver)
|
|
# #ConfirmAuctionStart (dataserver->sim)
|
|
# #CompleteAuction (sim->dataserver)
|
|
# #CancelAuction (sim->dataserver)
|
|
# #CheckParcelAuctions (sim->dataserver)
|
|
# #ParcelAuctions (dataserver->sim)
|
|
|
|
class ParcelManager(object):
|
|
""" a parcel manager, generally used as an attribute of a region """
|
|
|
|
def __init__(self, region = None, agent = None, packet_handler = None, events_handler = None, settings = None):
|
|
""" initialize the parcel 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 incoming parameters
|
|
self.region = region
|
|
self.agent = agent
|
|
self.packet_handler = packet_handler
|
|
|
|
# otherwise, let's just use our own
|
|
if events_handler != None:
|
|
self.events_handler = events_handler
|
|
else:
|
|
self.events_handler = EventsHandler()
|
|
|
|
self.helpers = Helpers()
|
|
|
|
# initialize the parcel storage container
|
|
self.parcels = []
|
|
# initialize the parcel overlay storage container
|
|
self.parcel_overlay = {}
|
|
|
|
# set up callbacks for parcel related packets
|
|
self.onParcelOverlay_received = self.packet_handler._register('ParcelOverlay')
|
|
self.onParcelOverlay_received.subscribe(self.onParcelOverlay)
|
|
|
|
self.onParcelProperties_received = self.agent.event_queue_handler._register('ParcelProperties')
|
|
self.onParcelProperties_received.subscribe(self.onParcelProperties)
|
|
|
|
self.onParcelPropertiesUpdate_received = self.packet_handler._register('ParcelPropertiesUpdate')
|
|
self.onParcelPropertiesUpdate_received.subscribe(self.onParcelPropertiesUpdate)
|
|
|
|
self.onParcelInfoReply_received = self.packet_handler._register('ParcelInfoReply')
|
|
self.onParcelInfoReply_received.subscribe(self.onParcelInfoReply)
|
|
|
|
if self.settings.LOG_VERBOSE: log(DEBUG, "Initializing the parcel manager for %s in region %s." % (self.agent.Name(), self.region.SimName))
|
|
|
|
def onParcelOverlay(self, packet):
|
|
""" parse and handle an incoming ParcelOverlay packet
|
|
|
|
Currently, we store this data in the ParcelManager.packet_overlay dictionary
|
|
as parcel_overlay[sequence_id] = data (unparsed binary)
|
|
"""
|
|
|
|
# unpack the data
|
|
sequence_id = packet.message_data.blocks['ParcelData'][0].get_variable('SequenceID').data
|
|
data = packet.message_data.blocks['ParcelData'][0].get_variable('Data').data
|
|
|
|
# store the data
|
|
# ToDo: make sense of the binary blob in data
|
|
self.parcel_overlay[sequence_id] = data
|
|
|
|
def onParcelProperties(self, packet):
|
|
""" parse and handle an incoming ParcelProperties packet. Parse and serialize the info into a Parcel() representation, then store it (or replace the stored version) """
|
|
|
|
RequestResult = packet.message_data.blocks['ParcelData'][0].get_variable('RequestResult').data
|
|
SequenceID = packet.message_data.blocks['ParcelData'][0].get_variable('SequenceID').data
|
|
SnapSelection= packet.message_data.blocks['ParcelData'][0].get_variable('SnapSelection').data
|
|
SelfCount = packet.message_data.blocks['ParcelData'][0].get_variable('SelfCount').data
|
|
OtherCount = packet.message_data.blocks['ParcelData'][0].get_variable('OtherCount').data
|
|
PublicCount = packet.message_data.blocks['ParcelData'][0].get_variable('PublicCount').data
|
|
LocalID = packet.message_data.blocks['ParcelData'][0].get_variable('LocalID').data
|
|
OwnerID = packet.message_data.blocks['ParcelData'][0].get_variable('OwnerID').data
|
|
IsGroupOwned = packet.message_data.blocks['ParcelData'][0].get_variable('IsGroupOwned').data
|
|
AuctionID = packet.message_data.blocks['ParcelData'][0].get_variable('AuctionID').data
|
|
ClaimDate = packet.message_data.blocks['ParcelData'][0].get_variable('ClaimDate').data
|
|
ClaimPrice = packet.message_data.blocks['ParcelData'][0].get_variable('ClaimPrice').data
|
|
RentPrice = packet.message_data.blocks['ParcelData'][0].get_variable('RentPrice').data
|
|
AABBMin = packet.message_data.blocks['ParcelData'][0].get_variable('AABBMin').data
|
|
AABBMax = packet.message_data.blocks['ParcelData'][0].get_variable('AABBMax').data
|
|
Bitmap = packet.message_data.blocks['ParcelData'][0].get_variable('Bitmap').data
|
|
Area = packet.message_data.blocks['ParcelData'][0].get_variable('Area').data
|
|
Status = packet.message_data.blocks['ParcelData'][0].get_variable('Status').data
|
|
SimWideMaxPrims = packet.message_data.blocks['ParcelData'][0].get_variable('SimWideMaxPrims').data
|
|
SimWideTotalPrims = packet.message_data.blocks['ParcelData'][0].get_variable('SimWideTotalPrims').data
|
|
MaxPrims = packet.message_data.blocks['ParcelData'][0].get_variable('MaxPrims').data
|
|
TotalPrims = packet.message_data.blocks['ParcelData'][0].get_variable('TotalPrims').data
|
|
OwnerPrims = packet.message_data.blocks['ParcelData'][0].get_variable('OwnerPrims').data
|
|
GroupPrims = packet.message_data.blocks['ParcelData'][0].get_variable('GroupPrims').data
|
|
OtherPrims = packet.message_data.blocks['ParcelData'][0].get_variable('OtherPrims').data
|
|
SelectedPrims = packet.message_data.blocks['ParcelData'][0].get_variable('SelectedPrims').data
|
|
ParcelPrimBonus = packet.message_data.blocks['ParcelData'][0].get_variable('ParcelPrimBonus').data
|
|
OtherCleanTime = packet.message_data.blocks['ParcelData'][0].get_variable('OtherCleanTime').data
|
|
ParcelFlags = packet.message_data.blocks['ParcelData'][0].get_variable('ParcelFlags').data
|
|
SalePrice = packet.message_data.blocks['ParcelData'][0].get_variable('SalePrice').data
|
|
Name = packet.message_data.blocks['ParcelData'][0].get_variable('Name').data
|
|
Desc = packet.message_data.blocks['ParcelData'][0].get_variable('Desc').data
|
|
MusicURL = packet.message_data.blocks['ParcelData'][0].get_variable('MusicURL').data
|
|
MediaURL = packet.message_data.blocks['ParcelData'][0].get_variable('MediaURL').data
|
|
MediaID = packet.message_data.blocks['ParcelData'][0].get_variable('MediaID').data
|
|
MediaAutoScale = packet.message_data.blocks['ParcelData'][0].get_variable('MediaAutoScale').data
|
|
GroupID = packet.message_data.blocks['ParcelData'][0].get_variable('GroupID').data
|
|
PassPrice = packet.message_data.blocks['ParcelData'][0].get_variable('PassPrice').data
|
|
PassHours = packet.message_data.blocks['ParcelData'][0].get_variable('PassHours').data
|
|
Category = packet.message_data.blocks['ParcelData'][0].get_variable('Category').data
|
|
AuthBuyerID = packet.message_data.blocks['ParcelData'][0].get_variable('AuthBuyerID').data
|
|
SnapshotID = packet.message_data.blocks['ParcelData'][0].get_variable('SnapshotID').data
|
|
UserLocation = packet.message_data.blocks['ParcelData'][0].get_variable('UserLocation').data
|
|
UserLookAt = packet.message_data.blocks['ParcelData'][0].get_variable('UserLookAt').data
|
|
LandingType = packet.message_data.blocks['ParcelData'][0].get_variable('LandingType').data
|
|
RegionPushOverride = packet.message_data.blocks['ParcelData'][0].get_variable('RegionPushOverride').data
|
|
RegionDenyAnonymous = packet.message_data.blocks['ParcelData'][0].get_variable('RegionDenyAnonymous').data
|
|
RegionDenyIdentified = packet.message_data.blocks['ParcelData'][0].get_variable('RegionDenyIdentified').data
|
|
RegionDenyTransacted = packet.message_data.blocks['ParcelData'][0].get_variable('RegionDenyTransacted').data
|
|
RegionDenyAgeUnverified = packet.message_data.blocks['AgeVerificationBlock'][0].get_variable('RegionDenyAgeUnverified').data
|
|
|
|
parcel = Parcel(self.region, self.agent, RequestResult = RequestResult, SequenceID = SequenceID, SnapSelection = SnapSelection, SelfCount = SelfCount, OtherCount = OtherCount, PublicCount = PublicCount, LocalID = LocalID, OwnerID = OwnerID, IsGroupOwned = IsGroupOwned, AuctionID = AuctionID, ClaimDate = ClaimDate, ClaimPrice = ClaimPrice, RentPrice = RentPrice, AABBMin = AABBMin, AABBMax = AABBMax, Bitmap = Bitmap, Area = Area, Status = Status, SimWideMaxPrims = SimWideMaxPrims, SimWideTotalPrims = SimWideTotalPrims, MaxPrims = MaxPrims, TotalPrims = TotalPrims, OwnerPrims = OwnerPrims, GroupPrims = GroupPrims, OtherPrims = OtherPrims, SelectedPrims = SelectedPrims, ParcelPrimBonus = ParcelPrimBonus, OtherCleanTime = OtherCleanTime, ParcelFlags = ParcelFlags, SalePrice = SalePrice, Name = Name, Desc = Desc, MusicURL = MusicURL, MediaURL = MediaURL, MediaID = MediaID, MediaAutoScale = MediaAutoScale, GroupID = GroupID, PassPrice = PassPrice, PassHours = PassHours, Category = Category, AuthBuyerID = AuthBuyerID, SnapshotID = SnapshotID, UserLocation = UserLocation, UserLookAt = UserLookAt, LandingType = LandingType, RegionPushOverride = RegionPushOverride, RegionDenyAnonymous = RegionDenyAnonymous, RegionDenyIdentified = RegionDenyIdentified, RegionDenyTransacted = RegionDenyTransacted, RegionDenyAgeUnverified = RegionDenyAgeUnverified, settings = self.settings)
|
|
|
|
self._store_parcel(parcel)
|
|
|
|
def onParcelPropertiesUpdate(self, packet):
|
|
""" parse and handle an incoming ParcelPropertiesUpdate packet. parse the data into a dictionary and pass the blob to the Parcel() instance for self handling """
|
|
|
|
parcel_update = {}
|
|
|
|
parcel_update['LocalID'] = packet.message_data.blocks['ParcelData'][0].get_variable('LocalID').data
|
|
parcel_update['Flags'] = packet.message_data.blocks['ParcelData'][0].get_variable('Flags').data
|
|
parcel_update['ParcelFlags'] = packet.message_data.blocks['ParcelData'][0].get_variable('ParcelFlags').data
|
|
parcel_update['SalePrice'] = packet.message_data.blocks['ParcelData'][0].get_variable('SalePrice').data
|
|
parcel_update['Name'] = packet.message_data.blocks['ParcelData'][0].get_variable('Name').data
|
|
parcel_update['Desc'] = packet.message_data.blocks['ParcelData'][0].get_variable('Desc').data
|
|
parcel_update['MusicURL'] = packet.message_data.blocks['ParcelData'][0].get_variable('MusicURL').data
|
|
parcel_update['MediaURL'] = packet.message_data.blocks['ParcelData'][0].get_variable('MediaURL').data
|
|
parcel_update['MediaID'] = packet.message_data.blocks['ParcelData'][0].get_variable('MediaID').data
|
|
parcel_update['MediaAutoScale'] = packet.message_data.blocks['ParcelData'][0].get_variable('MediaAutoScale').data
|
|
parcel_update['GroupID'] = packet.message_data.blocks['ParcelData'][0].get_variable('GroupID').data
|
|
parcel_update['PassPrice'] = packet.message_data.blocks['ParcelData'][0].get_variable('PassPrice').data
|
|
parcel_update['PassHours'] = packet.message_data.blocks['ParcelData'][0].get_variable('PassHours').data
|
|
parcel_update['Category'] = packet.message_data.blocks['ParcelData'][0].get_variable('Category').data
|
|
parcel_update['AuthBuyerID'] = packet.message_data.blocks['ParcelData'][0].get_variable('AuthBuyerID').data
|
|
parcel_update['SnapshotID'] = packet.message_data.blocks['ParcelData'][0].get_variable('SnapshotID').data
|
|
parcel_update['UserLocation'] = packet.message_data.blocks['ParcelData'][0].get_variable('UserLocation').data
|
|
parcel_update['UserLookAt'] = packet.message_data.blocks['ParcelData'][0].get_variable('UserLookAt').data
|
|
parcel_update['LandingType'] = packet.message_data.blocks['ParcelData'][0].get_variable('LandingType').data
|
|
|
|
self._update_parcel_properties(parcel_update)
|
|
|
|
def _store_parcel(self, new_parcel):
|
|
""" store a representation of a parcel """
|
|
|
|
# replace an existing list member, else, append
|
|
|
|
index = [self.parcels.index(parcel) for parcel in self.parcels if parcel.LocalID == new_parcel.LocalID]
|
|
|
|
if index != []:
|
|
|
|
self.parcels[index[0]] = new_parcel
|
|
|
|
if self.settings.LOG_VERBOSE: log(DEBUG, 'Updating a stored parcel: %s in region \'%s\'' % (new_parcel.LocalID, self.region.SimName))
|
|
|
|
else:
|
|
|
|
self.parcels.append(new_parcel)
|
|
|
|
if self.settings.LOG_VERBOSE: log(DEBUG, 'Stored a new parcel: %s in region \'%s\'' % (new_parcel.LocalID, self.region.SimName))
|
|
|
|
def _update_parcel_properties(self, parcel_properties):
|
|
""" update a stored parcel's properties. finds the stored parcel and passes it a dictionary to process """
|
|
|
|
parcels_found = []
|
|
|
|
if parcel_properties.has_key('LocalID'):
|
|
|
|
LocalID = parcel_properties['LocalID']
|
|
|
|
parcels_found = [parcel for parcel in self.parcels if str(parcel.LocalID) == str(LocalID)]
|
|
|
|
if len(parcels_found) == 0:
|
|
|
|
log(INFO, "Received ParcelPropertiesUpdate for parcel we do not know about yet. Storing a partial representation.")
|
|
|
|
new_parcel = Parcel(self.region, self.agent, LocalID = parcel_properties['LocalID'], Flags = parcel_properties['Flags'], ParcelFlags = parcel_properties['ParcelFlags'], SalePrice = parcel_properties['SalePrice'], Name = parcel_properties['Name'], Desc = parcel_properties['Desc'], MusicURL = parcel_properties['MusicURL'], MediaURL = parcel_properties['MediaURL'], MediaID = parcel_properties['MediaID'], MediaAutoScale = parcel_properties['MediaAutoScale'], GroupID = parcel_properties['GroupID'], PassPrice = parcel_properties['PassPrice'], PassHours = parcel_properties['PassHours'], Category = parcel_properties['Category'], AuthBuyerID = parcel_properties['AuthBuyerID'], SnapshotID = parcel_properties['SnapshotID'], UserLocation = parcel_properties['UserLocation'], UserLookAt = parcel_properties['UserLookAt'], LandingType = parcel_properties['LandingType'], settings = self.settings)
|
|
|
|
self._store_parcel(new_parcel)
|
|
|
|
elif len(parcels_found) == 1:
|
|
|
|
parcel = parcels_found[0]
|
|
|
|
parcel._update_properties(parcel_properties)
|
|
|
|
elif parcel_properties.has_key('ParcelID'):
|
|
|
|
ParcelID = parcel_properties['ParcelID']
|
|
|
|
parcels_found = [parcel for parcel in self.parcels if str(parcel.ParcelID) == str(ParcelID)]
|
|
|
|
if len(parcels_found) == 0:
|
|
|
|
log(INFO, "Received ParcelPropertiesUpdate for parcel we do not know about yet. Storing a partial representation.")
|
|
|
|
new_parcel = Parcel(self.region, self.agent, LocalID = parcel_properties['LocalID'], Flags = parcel_properties['Flags'], ParcelFlags = parcel_properties['ParcelFlags'], SalePrice = parcel_properties['SalePrice'], Name = parcel_properties['Name'], Desc = parcel_properties['Desc'], MusicURL = parcel_properties['MusicURL'], MediaURL = parcel_properties['MediaURL'], MediaID = parcel_properties['MediaID'], MediaAutoScale = parcel_properties['MediaAutoScale'], GroupID = parcel_properties['GroupID'], PassPrice = parcel_properties['PassPrice'], PassHours = parcel_properties['PassHours'], Category = parcel_properties['Category'], AuthBuyerID = parcel_properties['AuthBuyerID'], SnapshotID = parcel_properties['SnapshotID'], UserLocation = parcel_properties['UserLocation'], UserLookAt = parcel_properties['UserLookAt'], LandingType = parcel_properties['LandingType'], settings = self.settings)
|
|
|
|
self._store_parcel(new_parcel)
|
|
|
|
elif len(parcels_found) == 1:
|
|
|
|
parcel = parcels_found[0]
|
|
|
|
parcel._update_properties(parcel_properties)
|
|
|
|
def request_estate_covenant(self, ):
|
|
""" request the estate covenant (for the current estate)"""
|
|
|
|
self.onEstateCovenantReply_received = self.packet_handler._register('EstateCovenantReply')
|
|
self.onEstateCovenantReply_received.subscribe(self.onEstateCovenantReply)
|
|
|
|
self.sendEstateCovenantRequest()
|
|
|
|
def sendEstateCovenantRequest(self):
|
|
""" send an EstateCovenantRequest packet """
|
|
|
|
packet = EstateCovenantRequestPacket()
|
|
|
|
packet.AgentData['AgentID'] = self.agent.agent_id
|
|
packet.AgentData['SessionID'] = self.agent.session_id
|
|
|
|
self.region.enqueue_message(packet)
|
|
|
|
def onEstateCovenantReply(self, packet):
|
|
""" parse and handle an EstateCovenantReply packet """
|
|
|
|
try:
|
|
|
|
self.onEstateCovenantReply_received.unsubscribe(self.onEstateCovenantReply)
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
CovenantID = packet.message_data.blocks['Data'][0].get_variable('CovenantID').data
|
|
CovenantTimestamp = packet.message_data.blocks['Data'][0].get_variable('CovenantTimestamp').data
|
|
EstateName = packet.message_data.blocks['Data'][0].get_variable('EstateName').data
|
|
EstateOwnerID = packet.message_data.blocks['Data'][0].get_variable('EstateOwnerID').data
|
|
|
|
log(INFO, "Received EstateCovenantReply for estate name %s with a CovenantID of %s." % (EstateName, CovenantID))
|
|
|
|
# storing this data as a dict in the parcel manager until we have something better to do with it
|
|
self.estatecovenantreply = {'CovenantID': CovenantID, 'CovenantTimestamp': CovenantTimestamp, 'EstateName': EstateName, 'EstateOwnerID': EstateOwnerID}
|
|
|
|
def sendParcelPropertiesRequest(self, SequenceID, West, South, East, North, SnapSelection):
|
|
""" sends a ParcelPropertiesRequest packet """
|
|
|
|
packet = ParcelPropertiesRequestPacket()
|
|
|
|
packet.AgentData['AgentID'] = self.agent.agent_id
|
|
packet.AgentData['SessionID'] = self.agent.session_id
|
|
|
|
packet.ParcelData['SequenceID'] = SequenceID
|
|
packet.ParcelData['West'] = West
|
|
packet.ParcelData['South'] = South
|
|
packet.ParcelData['East'] = East
|
|
packet.ParcelData['North'] = North
|
|
packet.ParcelData['SnapSelection'] = SnapSelection
|
|
|
|
self.region.enqueue_message(packet)
|
|
|
|
def sendParcelPropertiesRequestByID(self, SequenceID, LocalID):
|
|
""" sends a ParcelPropertiesRequestByID packet """
|
|
|
|
packet = ParcelPropertiesRequestByID()
|
|
|
|
packet.AgentData['AgentID'] = self.agent.agent_id
|
|
packet.AgentData['SessionID'] = self.agent.session_id
|
|
|
|
packet.ParcelData['SequenceID'] = SequenceID
|
|
packet.ParcelData['LocalID'] = LocalID
|
|
|
|
self.region.enqueue_message(packet)
|
|
|
|
def request_parcel_info(self, parcel_id):
|
|
""" request information for a parcel by id """
|
|
|
|
if type(parcel_id) == str:
|
|
|
|
try:
|
|
|
|
parcel_id = UUID(parcel_id)
|
|
|
|
except ValueError:
|
|
|
|
log(WARNING, 'Parcel_id passed to request_parcel_info must but a valid UUID or string representation of a uuid. %s was passed in' % (parcel_id))
|
|
|
|
return
|
|
|
|
elif not isinstance(parcel_id, UUID):
|
|
|
|
log(WARNING, 'Parcel_id passed to request_parcel_info must but a valid UUID or string representation of a uuid. %s was passed in' % (parcel_id))
|
|
|
|
return
|
|
|
|
self.sendParcelInfoRequest(parcel_id)
|
|
|
|
def sendParcelInfoRequest(self, parcel_id):
|
|
""" send a ParcelInfoRequest packet for the specified parcelid """
|
|
|
|
packet = ParcelInfoRequestPacket()
|
|
|
|
# build the agent data block
|
|
packet.AgentData['AgentID'] = self.agent.agent_id
|
|
packet.AgentData['SessionID'] = self.agent.session_id
|
|
|
|
packet.Data['ParcelID'] = parcel_id
|
|
|
|
self.region.enqueue_message(packet)
|
|
|
|
def onParcelInfoReply(self, packet):
|
|
""" parse and handle a ParcelInfoReply packet """
|
|
|
|
parcel_info = {}
|
|
|
|
parcel_info['ParcelID'] = packet.message_data.blocks['Data'][0].get_variable('ParcelID').data
|
|
parcel_info['OwnerID'] = packet.message_data.blocks['Data'][0].get_variable('OwnerID').data
|
|
parcel_info['Name'] = packet.message_data.blocks['Data'][0].get_variable('Name').data
|
|
parcel_info['Desc'] = packet.message_data.blocks['Data'][0].get_variable('Desc').data
|
|
parcel_info['ActualArea'] = packet.message_data.blocks['Data'][0].get_variable('ActualArea').data
|
|
parcel_info['BillableArea'] = packet.message_data.blocks['Data'][0].get_variable('BillableArea').data
|
|
parcel_info['Flags'] = packet.message_data.blocks['Data'][0].get_variable('Flags').data
|
|
parcel_info['GlobalX'] = packet.message_data.blocks['Data'][0].get_variable('GlobalX').data
|
|
parcel_info['GlobalY'] = packet.message_data.blocks['Data'][0].get_variable('GlobalY').data
|
|
parcel_info['GlobalZ'] = packet.message_data.blocks['Data'][0].get_variable('GlobalZ').data
|
|
parcel_info['SimName'] = packet.message_data.blocks['Data'][0].get_variable('SimName').data
|
|
parcel_info['SnapshotID'] = packet.message_data.blocks['Data'][0].get_variable('SnapshotID').data
|
|
parcel_info['Dwell'] = packet.message_data.blocks['Data'][0].get_variable('Dwell').data
|
|
parcel_info['SalePrice'] = packet.message_data.blocks['Data'][0].get_variable('SalePrice').data
|
|
parcel_info['AuctionID'] = packet.message_data.blocks['Data'][0].get_variable('AuctionID').data
|
|
|
|
self._update_parcel_properties(parcel_info)
|
|
|
|
def request_current_parcel_properties(self):
|
|
""" request the properties of the parcel the agent currently inhabits """
|
|
|
|
self.SouthWest = self.agent.Position.X
|
|
self.NorthEast = self.agent.Position.Y
|
|
|
|
self.sendParcelPropertiesRequest(-50000, self.SouthWest, self.SouthWest, self.NorthEast, self.NorthEast, False)
|
|
|
|
def request_all_parcel_properties(self, delay = 1):
|
|
""" request the properties of all of the parcels on the current region. The delay parameter is a sleep between the send of each packet request """
|
|
|
|
# spawn a coroutine so this is non blocking
|
|
api.spawn(self.__request_all_parcel_properties, delay)
|
|
|
|
def __request_all_parcel_properties(self, delay = 1):
|
|
""" request the properties of all of the parcels on the current region """
|
|
|
|
# ugh this is a wretched way to request parcel info, but it is what it is
|
|
for x in range(1,17):
|
|
for y in range(1,17):
|
|
|
|
self.sendParcelPropertiesRequest(-50000, x * 4, x * 4, y * 4, y * 4, False)
|
|
|
|
api.sleep(delay)
|
|
|
|
def return_parcel_objects(self, ):
|
|
""" return the specified objects for the specified parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelReturnObjects
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelReturnObjects Low 199 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ LocalID S32 }
|
|
{ ReturnType U32 }
|
|
}
|
|
{
|
|
TaskIDs Variable
|
|
{ TaskID LLUUID }
|
|
}
|
|
{
|
|
OwnerIDs Variable
|
|
{ OwnerID LLUUID }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def disable_objects(self, ):
|
|
""" set objects nonphysical and disable scripts for the specified parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// Disable makes objects nonphysical and turns off their scripts.
|
|
// ParcelDisableObjects
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelDisableObjects Low 201 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ LocalID S32 }
|
|
{ ReturnType U32 }
|
|
}
|
|
{
|
|
TaskIDs Variable
|
|
{ TaskID LLUUID }
|
|
}
|
|
{
|
|
OwnerIDs Variable
|
|
{ OwnerID LLUUID }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def sendParcelDisableObjects(self, ):
|
|
""" send a ParcelDisableObjects packet """
|
|
|
|
pass
|
|
|
|
'''
|
|
// Disable makes objects nonphysical and turns off their scripts.
|
|
// ParcelDisableObjects
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelDisableObjects Low 201 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ LocalID S32 }
|
|
{ ReturnType U32 }
|
|
}
|
|
{
|
|
TaskIDs Variable
|
|
{ TaskID LLUUID }
|
|
}
|
|
{
|
|
OwnerIDs Variable
|
|
{ OwnerID LLUUID }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def join_parcels(self, ):
|
|
""" joins the specified parcels """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelJoin - Take all parcels which are owned by agent and inside
|
|
// rectangle, and make them 1 parcel if they all are leased.
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelJoin Low 210 NotTrusted Unencoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ West F32 }
|
|
{ South F32 }
|
|
{ East F32 }
|
|
{ North F32 }
|
|
}
|
|
}
|
|
|
|
'''
|
|
|
|
def sendParcelJoin(self, ):
|
|
""" send a ParcelJoin packet """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelJoin - Take all parcels which are owned by agent and inside
|
|
// rectangle, and make them 1 parcel if they all are leased.
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelJoin Low 210 NotTrusted Unencoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ West F32 }
|
|
{ South F32 }
|
|
{ East F32 }
|
|
{ North F32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def divide_parcel(self, ):
|
|
""" divide the selection into a new parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelDivide
|
|
// If the selection is a subsection of exactly one parcel,
|
|
// chop out that section and make a new parcel of it.
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelDivide Low 211 NotTrusted Unencoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ West F32 }
|
|
{ South F32 }
|
|
{ East F32 }
|
|
{ North F32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def sendParcelDivide(self, ):
|
|
""" send a ParcelDivide packet """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelDivide
|
|
// If the selection is a subsection of exactly one parcel,
|
|
// chop out that section and make a new parcel of it.
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelDivide Low 211 NotTrusted Unencoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ West F32 }
|
|
{ South F32 }
|
|
{ East F32 }
|
|
{ North F32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def request_parcel_access_list(self, ):
|
|
""" request an access list for the specified parcel """
|
|
|
|
self.onParcelAccessListReply_received = self.packet_handler._register('ParcelAccessListReply')
|
|
self.onParcelAccessListReply_received.subscribe(self.onParcelAccessListReply)
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelAccessListRequest
|
|
{
|
|
ParcelAccessListRequest Low 215 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
Data Single
|
|
{ SequenceID S32 }
|
|
{ Flags U32 }
|
|
{ LocalID S32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def sendParcelAccessListRequest(self, ):
|
|
""" send a ParcelAccessListRequest packet """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelAccessListRequest
|
|
{
|
|
ParcelAccessListRequest Low 215 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
Data Single
|
|
{ SequenceID S32 }
|
|
{ Flags U32 }
|
|
{ LocalID S32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def onParcelAccessListReply(self, packet):
|
|
""" parse and handle a ParcelAccessListReply packet """
|
|
|
|
self.onParcelAccessListReply_received.unsubscribe(self.onParcelAccessListReply)
|
|
|
|
pass
|
|
|
|
'''
|
|
// sim -> viewer
|
|
// ParcelAccessListReply
|
|
{
|
|
ParcelAccessListReply Low 216 Trusted Zerocoded
|
|
{
|
|
Data Single
|
|
{ AgentID LLUUID }
|
|
{ SequenceID S32 }
|
|
{ Flags U32 }
|
|
{ LocalID S32 }
|
|
}
|
|
{
|
|
List Variable
|
|
{ ID LLUUID }
|
|
{ Time S32 } // time_t
|
|
{ Flags U32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
class Parcel(object):
|
|
""" a representation of a parcel """
|
|
|
|
def __init__(self, region, agent, RequestResult = None, SequenceID = None, SnapSelection = None, SelfCount = None, OtherCount = None, PublicCount = None, LocalID = None, OwnerID = None, IsGroupOwned = None, AuctionID = None, ClaimDate = None, ClaimPrice = None, RentPrice = None, AABBMin = None, AABBMax = None, Bitmap = None, Area = None, Status = None, SimWideMaxPrims = None, SimWideTotalPrims = None, MaxPrims = None, TotalPrims = None, OwnerPrims = None, GroupPrims = None, OtherPrims = None, SelectedPrims = None, ParcelPrimBonus = None, OtherCleanTime = None, ParcelFlags = None, SalePrice = None, Name = None, Desc = None, MusicURL = None, MediaURL = None, MediaID = None, MediaAutoScale = None, GroupID = None, PassPrice = None, PassHours = None, Category = None, AuthBuyerID = None, SnapshotID = None, UserLocation = None, UserLookAt = None, LandingType = None, RegionPushOverride = None, RegionDenyAnonymous = None, RegionDenyIdentified = None, RegionDenyTransacted = None, RegionDenyAgeUnverified = None, ParcelID = None, ActualArea = None, BillableArea = None, Flags = None, GlobalX = None, GlobalY = None, GlobalZ = None, SimName = None, Dwell = None, settings = None):
|
|
""" initialize a representation of a parcel. the data is currently being populated directly from the ParcelProperties message """
|
|
|
|
# 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.region = region
|
|
self.agent = agent
|
|
|
|
# mapping values from the ParcelProperties message
|
|
# not all properties will ultimately live here, but for now
|
|
# mapping all of them will do
|
|
|
|
# from ParcelInfoReply
|
|
self.ParcelID = ParcelID
|
|
self.OwnerID = OwnerID
|
|
self.ActualArea = ActualArea
|
|
self.BillableArea = BillableArea
|
|
self.Flags = Flags
|
|
self.GlobalX = GlobalX
|
|
self.GlobalY = GlobalY
|
|
self.GlobalZ = GlobalZ
|
|
self.SimName = SimName
|
|
self.Dwell = Dwell
|
|
self.AuctionID = AuctionID
|
|
|
|
# from ParcelProperties
|
|
self.RequestResult = RequestResult
|
|
self.SequenceID = SequenceID
|
|
self.SnapSelection = SnapSelection
|
|
self.SelfCount = SelfCount
|
|
self.OtherCount = OtherCount
|
|
self.PublicCount = PublicCount
|
|
self.LocalID = LocalID
|
|
self.OwnerID = OwnerID
|
|
self.IsGroupOwned = IsGroupOwned
|
|
self.AuctionID = AuctionID
|
|
self.ClaimDate = ClaimDate
|
|
self.ClaimPrice = ClaimPrice
|
|
self.RentPrice = RentPrice
|
|
self.AABBMin = AABBMin
|
|
self.AABBMax = AABBMax
|
|
self.Bitmap = Bitmap
|
|
self.Area = Area
|
|
self.Status = Status
|
|
self.SimWideMaxPrims = SimWideMaxPrims
|
|
self.SimWideTotalPrims = SimWideTotalPrims
|
|
self.MaxPrims = MaxPrims
|
|
self.TotalPrims = TotalPrims
|
|
self.OwnerPrims = OwnerPrims
|
|
self.GroupPrims = GroupPrims
|
|
self.OtherPrims = OtherPrims
|
|
self.SelectedPrims = SelectedPrims
|
|
self.ParcelPrimBonus = ParcelPrimBonus
|
|
self.OtherCleanTime = OtherCleanTime
|
|
self.ParcelFlags = ParcelFlags
|
|
self.SalePrice = SalePrice
|
|
self.Name = Name
|
|
self.Desc = Desc
|
|
self.MusicURL = MusicURL
|
|
self.MediaURL = MediaURL
|
|
self.MediaID = MediaID
|
|
self.MediaAutoScale = MediaAutoScale
|
|
self.GroupID = GroupID
|
|
self.PassPrice = PassPrice
|
|
self.PassHours = PassHours
|
|
self.Category = Category
|
|
self.AuthBuyerID = AuthBuyerID
|
|
self.SnapshotID = SnapshotID
|
|
self.UserLocation = UserLocation
|
|
self.UserLookAt = UserLookAt
|
|
self.LandingType = LandingType
|
|
self.RegionPushOverride = RegionPushOverride
|
|
self.RegionDenyAnonymous = RegionDenyAnonymous
|
|
self.RegionDenyIdentified = RegionDenyIdentified
|
|
self.RegionDenyTransacted = RegionDenyTransacted
|
|
self.RegionDenyAgeUnverified = RegionDenyAgeUnverified
|
|
|
|
def _update_properties(self, parcel_properties):
|
|
""" update a parcel's properties via a dictionary """
|
|
|
|
for attribute in parcel_properties:
|
|
|
|
setattr(self, attribute, parcel_properties[attribute])
|
|
|
|
def return_objects(self, ):
|
|
""" return the specified objects for this parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelReturnObjects
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelReturnObjects Low 199 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ LocalID S32 }
|
|
{ ReturnType U32 }
|
|
}
|
|
{
|
|
TaskIDs Variable
|
|
{ TaskID LLUUID }
|
|
}
|
|
{
|
|
OwnerIDs Variable
|
|
{ OwnerID LLUUID }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def set_other_clean_time(self, ):
|
|
""" sends a SetOtherCleanTime packet for this parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelSetOtherCleanTime
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelSetOtherCleanTime Low 200 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ LocalID S32 }
|
|
{ OtherCleanTime S32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def disable_objects(self, ):
|
|
""" set objects nonphysical and disable scripts for this parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// Disable makes objects nonphysical and turns off their scripts.
|
|
// ParcelDisableObjects
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelDisableObjects Low 201 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ LocalID S32 }
|
|
{ ReturnType U32 }
|
|
}
|
|
{
|
|
TaskIDs Variable
|
|
{ TaskID LLUUID }
|
|
}
|
|
{
|
|
OwnerIDs Variable
|
|
{ OwnerID LLUUID }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def select_objects(self, ):
|
|
""" selects the specified objects for this parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelSelectObjects
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelSelectObjects Low 202 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ LocalID S32 }
|
|
{ ReturnType U32 }
|
|
}
|
|
{
|
|
ReturnIDs Variable
|
|
{ ReturnID LLUUID }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def deed_to_group(self, ):
|
|
""" deed this parcel to a group """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelDeedToGroup - deed a patch of land to a group
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelDeedToGroup Low 207 NotTrusted Unencoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
Data Single
|
|
{ GroupID LLUUID }
|
|
{ LocalID S32 } // parcel id
|
|
}
|
|
}
|
|
'''
|
|
|
|
def reclaim(self, ):
|
|
""" reclaim this parcel"""
|
|
|
|
pass
|
|
|
|
'''
|
|
// reserved for when island owners force re-claim parcel
|
|
{
|
|
ParcelReclaim Low 208 NotTrusted Unencoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
Data Single
|
|
{ LocalID S32 } // parcel id
|
|
}
|
|
}
|
|
'''
|
|
|
|
def claim(self, ):
|
|
""" change the owner of a parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelClaim - change the owner of a patch of land
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelClaim Low 209 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
Data Single
|
|
{ GroupID LLUUID }
|
|
{ IsGroupOwned BOOL }
|
|
{ Final BOOL } // true if buyer is in tier
|
|
}
|
|
{
|
|
ParcelData Variable
|
|
{ West F32 }
|
|
{ South F32 }
|
|
{ East F32 }
|
|
{ North F32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def release(self, ):
|
|
""" release this parcel to the public """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelRelease
|
|
// Release a parcel to public
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelRelease Low 212 NotTrusted Unencoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
Data Single
|
|
{ LocalID S32 } // parcel ID
|
|
}
|
|
}
|
|
'''
|
|
|
|
def buy(self, ):
|
|
""" buy this parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelBuy - change the owner of a patch of land.
|
|
// viewer -> sim
|
|
// reliable
|
|
{
|
|
ParcelBuy Low 213 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
Data Single
|
|
{ GroupID LLUUID }
|
|
{ IsGroupOwned BOOL }
|
|
{ RemoveContribution BOOL }
|
|
{ LocalID S32 }
|
|
{ Final BOOL } // true if buyer is in tier
|
|
}
|
|
{
|
|
ParcelData Single
|
|
{ Price S32 }
|
|
{ Area S32 }
|
|
}
|
|
}
|
|
'''
|
|
|
|
def godforce_owner(self, ):
|
|
""" god force own this parcel """
|
|
|
|
pass
|
|
|
|
'''
|
|
// ParcelGodForceOwner Unencoded
|
|
{
|
|
ParcelGodForceOwner Low 214 NotTrusted Zerocoded
|
|
{
|
|
AgentData Single
|
|
{ AgentID LLUUID }
|
|
{ SessionID LLUUID }
|
|
}
|
|
{
|
|
Data Single
|
|
{ OwnerID LLUUID }
|
|
{ LocalID S32 } // parcel ID
|
|
}
|
|
}
|
|
'''
|
|
|
|
"""
|
|
Contributors can be viewed at:
|
|
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt
|
|
|
|
$LicenseInfo:firstyear=2008&license=apachev2$
|
|
|
|
Copyright 2009, Linden Research, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License").
|
|
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/LICENSE.txt
|
|
|
|
$/LicenseInfo$
|
|
"""
|