diff --git a/OpenMetaverse.Utilities/Utilities.cs b/OpenMetaverse.Utilities/Utilities.cs index 741ded24..11d68650 100644 --- a/OpenMetaverse.Utilities/Utilities.cs +++ b/OpenMetaverse.Utilities/Utilities.cs @@ -526,14 +526,14 @@ namespace OpenMetaverse.Utilities } } - private void Parcels_OnParcelProperties(Parcel parcel, ParcelManager.ParcelResult result, int sequenceID, - bool snapSelection) + private void Parcels_OnParcelProperties(Simulator simulator, Parcel parcel, ParcelResult result, + int selectedPrims, int sequenceID, bool snapSelection) { // Check if this is for a simulator we're concerned with - if (!active_sims.Contains(parcel.Simulator)) return; + if (!active_sims.Contains(simulator)) return; // Warn about parcel property request errors and bail out - if (result == ParcelManager.ParcelResult.NoData) + if (result == ParcelResult.NoData) { Logger.Log("ParcelDownloader received a NoData response, sequenceID " + sequenceID, Helpers.LogLevel.Warning, Client); @@ -541,24 +541,24 @@ namespace OpenMetaverse.Utilities } // Warn about unexpected data and bail out - if (!ParcelMarked.ContainsKey(parcel.Simulator)) + if (!ParcelMarked.ContainsKey(simulator)) { - Logger.Log("ParcelDownloader received unexpected parcel data for " + parcel.Simulator, + Logger.Log("ParcelDownloader received unexpected parcel data for " + simulator, Helpers.LogLevel.Warning, Client); return; } int x, y, index, bit; - int[,] markers = ParcelMarked[parcel.Simulator]; + int[,] markers = ParcelMarked[simulator]; // Add this parcel to the dictionary of LocalID -> Parcel mappings - lock (Parcels[parcel.Simulator]) - if (!Parcels[parcel.Simulator].ContainsKey(parcel.LocalID)) - Parcels[parcel.Simulator][parcel.LocalID] = parcel; + lock (Parcels[simulator]) + if (!Parcels[simulator].ContainsKey(parcel.LocalID)) + Parcels[simulator][parcel.LocalID] = parcel; // Request the access list for this parcel - Client.Parcels.AccessListRequest(parcel.Simulator, parcel.LocalID, - ParcelManager.AccessList.Both, 0); + Client.Parcels.AccessListRequest(simulator, parcel.LocalID, + AccessList.Both, 0); // Mark this area as downloaded for (y = 0; y < 64; y++) @@ -584,10 +584,9 @@ namespace OpenMetaverse.Utilities { if (markers[y, x] == 0) { - Client.Parcels.PropertiesRequest(parcel.Simulator, + Client.Parcels.PropertiesRequest(simulator, (y + 1) * 4.0f, (x + 1) * 4.0f, y * 4.0f, x * 4.0f, 0, false); - return; } } @@ -596,12 +595,12 @@ namespace OpenMetaverse.Utilities // If we get here, there are no more zeroes in the markers map lock (active_sims) { - active_sims.Remove(parcel.Simulator); + active_sims.Remove(simulator); if (OnParcelsDownloaded != null) { // This map is complete, fire callback - try { OnParcelsDownloaded(parcel.Simulator, Parcels[parcel.Simulator], markers); } + try { OnParcelsDownloaded(simulator, Parcels[simulator], markers); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } diff --git a/OpenMetaverse/NetworkManager.cs b/OpenMetaverse/NetworkManager.cs index 04ab1688..9076fa65 100644 --- a/OpenMetaverse/NetworkManager.cs +++ b/OpenMetaverse/NetworkManager.cs @@ -297,7 +297,6 @@ namespace OpenMetaverse // Register the internal callbacks RegisterCallback(PacketType.RegionHandshake, new PacketCallback(RegionHandshakeHandler)); RegisterCallback(PacketType.StartPingCheck, new PacketCallback(StartPingCheckHandler)); - RegisterCallback(PacketType.ParcelOverlay, new PacketCallback(ParcelOverlayHandler)); RegisterCallback(PacketType.EnableSimulator, new PacketCallback(EnableSimulatorHandler)); RegisterCallback(PacketType.DisableSimulator, new PacketCallback(DisableSimulatorHandler)); RegisterCallback(PacketType.KickUser, new PacketCallback(KickUserHandler)); @@ -1098,29 +1097,6 @@ namespace OpenMetaverse simulator.ConnectedEvent.Set(); } - private void ParcelOverlayHandler(Packet packet, Simulator simulator) - { - ParcelOverlayPacket overlay = (ParcelOverlayPacket)packet; - - if (overlay.ParcelData.SequenceID >= 0 && overlay.ParcelData.SequenceID <= 3) - { - Buffer.BlockCopy(overlay.ParcelData.Data, 0, simulator.ParcelOverlay, - overlay.ParcelData.SequenceID * 1024, 1024); - simulator.ParcelOverlaysReceived++; - - if (simulator.ParcelOverlaysReceived > 3) - { - // TODO: ParcelOverlaysReceived should become internal, and reset to zero every - // time it hits four. Also need a callback here - } - } - else - { - Logger.Log("Parcel overlay with sequence ID of " + overlay.ParcelData.SequenceID + - " received from " + simulator.ToString(), Helpers.LogLevel.Warning, Client); - } - } - private void EnableSimulatorHandler(Packet packet, Simulator simulator) { if (!Client.Settings.MULTIPLE_SIMS) return; diff --git a/OpenMetaverse/ParcelManager.cs b/OpenMetaverse/ParcelManager.cs index 840293fe..d4954ba9 100644 --- a/OpenMetaverse/ParcelManager.cs +++ b/OpenMetaverse/ParcelManager.cs @@ -33,6 +33,164 @@ using OpenMetaverse.StructuredData; namespace OpenMetaverse { + #region Enums + + /// + /// Type of return to use when returning objects from a parcel + /// + public enum ObjectReturnType : uint + { + /// + None = 0, + /// Return objects owned by parcel owner + Owner = 1 << 1, + /// Return objects set to group + Group = 1 << 2, + /// Return objects not owned by parcel owner or set to group + Other = 1 << 3, + /// Return a specific list of objects on parcel + List = 1 << 4, + /// Return objects that are marked for-sale + Sell = 1 << 5 + } + + /// + /// Blacklist/Whitelist flags used in parcels Access List + /// + public enum ParcelAccessFlags : uint + { + /// Agent is denied access + NoAccess = 0, + /// Agent is granted access + Access = 1 + } + + /// + /// The result of a request for parcel properties + /// + public enum ParcelResult : int + { + /// No matches were found for the request + NoData = -1, + /// Request matched a single parcel + Single = 0, + /// Request matched multiple parcels + Multiple = 1 + } + + /// + /// Flags used in the ParcelAccessListRequest packet to specify whether + /// we want the access list (whitelist), ban list (blacklist), or both + /// + [Flags] + public enum AccessList : uint + { + /// Request the access list + Access = 1 << 0, + /// Request the ban list + Ban = 1 << 1, + /// Request both the access list and ban list + Both = Access | Ban + } + + /// + /// Sequence ID in ParcelPropertiesReply packets (sent when avatar + /// tries to cross a parcel border) + /// + public enum ParcelStatus : int + { + /// Parcel is currently selected + ParcelSelected = -10000, + /// Parcel restricted to a group the avatar is not a + /// member of + CollisionNotInGroup = -20000, + /// Avatar is banned from the parcel + CollisionBanned = -30000, + /// Parcel is restricted to an access list that the + /// avatar is not on + CollisionNotOnAccessList = -40000, + /// Response to hovering over a parcel + HoveredOverParcel = -50000 + } + + /// + /// + /// + public enum TerraformAction : byte + { + /// + Level = 0, + /// + Raise = 1, + /// + Lower = 2, + /// + Smooth = 3, + /// + Noise = 4, + /// + Revert = 5 + } + + /// + /// + /// + public enum TerraformBrushSize : byte + { + /// + Small = 1, + /// + Medium = 2, + /// + Large = 4 + } + + /// + /// Reasons agent is denied access to a parcel on the simulator + /// + public enum AccessDeniedReason : byte + { + /// Agent is not denied, access is granted + NotDenied = 0, + /// Agent is not a member of the group set for the parcel, or which owns the parcel + NotInGroup = 1, + /// Agent is not on the parcels specific allow list + NotOnAllowList = 2, + /// Agent is on the parcels ban list + BannedFromParcel = 3, + /// Unknown + NoAccess = 4, + /// Agent is not age verified and parcel settings deny access to non age verified avatars + NotAgeVerified = 5 + } + + /// + /// Parcel overlay type. This is used primarily for highlighting and + /// coloring which is why it is a single integer instead of a set of + /// flags + /// + public enum ParcelOverlayType : byte + { + /// Public land + Public = 0, + /// Land is owned by another avatar + OwnedByOther = 1, + /// Land is owned by a group + OwnedByGroup = 2, + /// Land is owned by the current avatar + OwnedBySelf = 3, + /// Land is for sale + ForSale = 4, + /// Land is being auctioned + Auction = 5, + /// To the west of this area is a parcel border + BorderWest = 64, + /// To the south of this area is a parcel border + BorderSouth = 128 + } + + #endregion Enums + #region Structs /// @@ -255,13 +413,6 @@ namespace OpenMetaverse #endregion Enums - /// - public int RequestResult; - /// - public int SequenceID; - /// Used by the viewer in conjunction with the BitMap - /// for highlighting the borders of a parcel - public bool SnapSelection; /// public int SelfCount; /// @@ -311,9 +462,6 @@ namespace OpenMetaverse public int GroupPrims; /// Total number of other primitives on this parcel public int OtherPrims; - /// Total number of primitives you are currently selecting and - /// sitting on - public int SelectedPrims; /// public float ParcelPrimBonus; /// Autoreturn value in minutes for others' objects @@ -355,8 +503,6 @@ namespace OpenMetaverse public bool RegionDenyAnonymous; /// public bool RegionPushOverride; - /// Simulator Object, containing details from Simulator class - public Simulator Simulator; /// Access list of who is whitelisted or blacklisted on this /// parcel public List AccessList; @@ -389,13 +535,9 @@ namespace OpenMetaverse /// /// Simulator this parcel resides in /// Local ID of this parcel - public Parcel(Simulator simulator, int localID) + public Parcel(int localID) { - Simulator = simulator; LocalID = localID; - RequestResult = 0; - SequenceID = 0; - SnapSelection = false; SelfCount = 0; OtherCount = 0; PublicCount = 0; @@ -417,7 +559,6 @@ namespace OpenMetaverse OwnerPrims = 0; GroupPrims = 0; OtherPrims = 0; - SelectedPrims = 0; ParcelPrimBonus = 0; OtherCleanTime = 0; Flags = ParcelFlags.None; @@ -447,14 +588,15 @@ namespace OpenMetaverse /// /// Update the simulator with any local changes to this Parcel object /// + /// Simulator to send updates to /// Whether we want the simulator to confirm /// the update with a reply packet or not - public void Update(bool wantReply) + public void Update(Simulator simulator, bool wantReply) { ParcelPropertiesUpdatePacket request = new ParcelPropertiesUpdatePacket(); - request.AgentData.AgentID = Simulator.Client.Self.AgentID; - request.AgentData.SessionID = Simulator.Client.Self.SessionID; + request.AgentData.AgentID = simulator.Client.Self.AgentID; + request.AgentData.SessionID = simulator.Client.Self.SessionID; request.ParcelData.LocalID = this.LocalID; @@ -478,23 +620,24 @@ namespace OpenMetaverse request.ParcelData.UserLocation = this.UserLocation; request.ParcelData.UserLookAt = this.UserLookAt; - Simulator.Client.Network.SendPacket(request, Simulator); + simulator.SendPacket(request, true); - UpdateOtherCleanTime(); + UpdateOtherCleanTime(simulator); } /// /// Set Autoreturn time /// - public void UpdateOtherCleanTime() + /// Simulator to send the update to + public void UpdateOtherCleanTime(Simulator simulator) { ParcelSetOtherCleanTimePacket request = new ParcelSetOtherCleanTimePacket(); - request.AgentData.AgentID = Simulator.Client.Self.AgentID; - request.AgentData.SessionID = Simulator.Client.Self.SessionID; + request.AgentData.AgentID = simulator.Client.Self.AgentID; + request.AgentData.SessionID = simulator.Client.Self.SessionID; request.ParcelData.LocalID = this.LocalID; request.ParcelData.OtherCleanTime = this.OtherCleanTime; - Simulator.Client.Network.SendPacket(request, Simulator); + simulator.SendPacket(request, true); } } @@ -505,136 +648,6 @@ namespace OpenMetaverse /// public class ParcelManager { - #region Enums - - /// - /// Type of return to use when returning objects from a parcel - /// - public enum ObjectReturnType : uint - { - /// - None = 0, - /// Return objects owned by parcel owner - Owner = 1 << 1, - /// Return objects set to group - Group = 1 << 2, - /// Return objects not owned by parcel owner or set to group - Other = 1 << 3, - /// Return a specific list of objects on parcel - List = 1 << 4, - /// Return objects that are marked for-sale - Sell = 1 << 5 - } - - /// - /// Blacklist/Whitelist flags used in parcels Access List - /// - public enum ParcelAccessFlags : uint - { - /// Agent is denied access - NoAccess = 0, - /// Agent is granted access - Access = 1 - } - - /// - /// The result of a request for parcel properties - /// - public enum ParcelResult : int - { - /// No matches were found for the request - NoData = -1, - /// Request matched a single parcel - Single = 0, - /// Request matched multiple parcels - Multiple = 1 - } - - /// - /// Flags used in the ParcelAccessListRequest packet to specify whether - /// we want the access list (whitelist), ban list (blacklist), or both - /// - [Flags] - public enum AccessList : uint - { - /// Request the access list - Access = 1 << 0, - /// Request the ban list - Ban = 1 << 1, - /// Request both the access list and ban list - Both = Access | Ban - } - - /// - /// Simulator sent Sequence IDs for ParcelPropertiesReply packets (sent when avatar tries to cross - /// parcel border) - /// - public enum SequenceStatus : int - { - /// Parcel currently selected - ParcelSelected = -10000, - /// Parcel restricted to group avatar not member of - Collision_Not_In_Group = -20000, - /// Avatar banned from parcel - Collision_Banned = -30000, - /// Parcel restricted to access list in which avatar is not on. - Collision_Not_On_AccessList = -40000, - /// response to hovered over parcel - Hovered_Over_Parcel = -50000 - } - - /// - /// - /// - public enum TerraformAction : byte - { - /// - Level = 0, - /// - Raise = 1, - /// - Lower = 2, - /// - Smooth = 3, - /// - Noise = 4, - /// - Revert = 5 - } - - /// - /// - /// - public enum TerraformBrushSize : byte - { - /// - Small = 1, - /// - Medium = 2, - /// - Large = 4 - } - - /// - /// Reasons agent is denied access to a parcel on the simulator - /// - public enum AccessDeniedReason : byte - { - /// Agent is not denied, access is granted - NotDenied = 0, - /// Agent is not a member of the group set for the parcel, or which owns the parcel - NotInGroup = 1, - /// Agent is not on the parcels specific allow list - NotOnAllowList = 2, - /// Agent is on the parcels ban list - BannedFromParcel = 3, - /// Unknown - NoAccess = 4, - /// Agent is not age verified and parcel settings deny access to non age verified avatars - NotAgeVerified = 5 - } - #endregion Enums - #region Structs /// @@ -686,21 +699,26 @@ namespace OpenMetaverse /// /// /// + /// Simulator the parcel is in /// Full properties for a single parcel. If result /// is NoData this will be incomplete or incorrect data /// Success of the query + /// Number of primitives your avatar is currently + /// selecting and sitting on in this parcel /// User-assigned identifier for the query /// User-assigned boolean for the query - public delegate void ParcelPropertiesCallback(Parcel parcel, ParcelResult result, int sequenceID, bool snapSelection); + public delegate void ParcelPropertiesCallback(Simulator simulator, Parcel parcel, ParcelResult result, int selectedPrims, + int sequenceID, bool snapSelection); /// /// /// - /// simulator parcel is in + /// Simulator the parcel is in /// /// /// /// - public delegate void ParcelAccessListReplyCallback(Simulator simulator, int sequenceID, int localID, uint flags, List accessEntries); + public delegate void ParcelAccessListReplyCallback(Simulator simulator, int sequenceID, int localID, uint flags, + List accessEntries); /// /// Responses to a request for prim owners on a parcel @@ -787,6 +805,7 @@ namespace OpenMetaverse Client.Network.RegisterCallback(PacketType.ParcelObjectOwnersReply, new NetworkManager.PacketCallback(ParcelObjectOwnersReplyHandler)); Client.Network.RegisterCallback(PacketType.ForceObjectSelect, new NetworkManager.PacketCallback(SelectParcelObjectsReplyHandler)); Client.Network.RegisterCallback(PacketType.ParcelMediaUpdate, new NetworkManager.PacketCallback(ParcelMediaUpdateHandler)); + Client.Network.RegisterCallback(PacketType.ParcelOverlay, new NetworkManager.PacketCallback(ParcelOverlayHandler)); } /// @@ -1408,7 +1427,7 @@ namespace OpenMetaverse LLSDMap ageVerifyBlock = (LLSDMap)(((LLSDArray)map["AgeVerificationBlock"])[0]); LLSDMap mediaDataBlock = (LLSDMap)(((LLSDArray)map["MediaData"])[0]); - Parcel parcel = new Parcel(simulator, parcelDataBlock["LocalID"].AsInteger()); + Parcel parcel = new Parcel(parcelDataBlock["LocalID"].AsInteger()); parcel.AABBMax = ((LLSDArray)parcelDataBlock["AABBMax"]).AsVector3(); parcel.AABBMin = ((LLSDArray)parcelDataBlock["AABBMin"]).AsVector3(); @@ -1450,15 +1469,14 @@ namespace OpenMetaverse parcel.RegionDenyAnonymous = parcelDataBlock["RegionDenyAnonymous"].AsBoolean(); parcel.RegionPushOverride = parcelDataBlock["RegionPushOverride"].AsBoolean(); parcel.RentPrice = parcelDataBlock["RentPrice"].AsInteger(); - parcel.RequestResult = parcelDataBlock["RequestResult"].AsInteger(); + ParcelResult result = (ParcelResult)parcelDataBlock["RequestResult"].AsInteger(); parcel.SalePrice = parcelDataBlock["SalePrice"].AsInteger(); - parcel.SelectedPrims = parcelDataBlock["SelectedPrims"].AsInteger(); + int selectedPrims = parcelDataBlock["SelectedPrims"].AsInteger(); parcel.SelfCount = parcelDataBlock["SelfCount"].AsInteger(); - parcel.SequenceID = parcelDataBlock["SequenceID"].AsInteger(); - parcel.Simulator = simulator; + int sequenceID = parcelDataBlock["SequenceID"].AsInteger(); parcel.SimWideMaxPrims = parcelDataBlock["SimWideMaxPrims"].AsInteger(); parcel.SimWideTotalPrims = parcelDataBlock["SimWideTotalPrims"].AsInteger(); - parcel.SnapSelection = parcelDataBlock["SnapSelection"].AsBoolean(); + bool snapSelection = parcelDataBlock["SnapSelection"].AsBoolean(); parcel.SnapshotID = parcelDataBlock["SnapshotID"].AsUUID(); parcel.Status = (Parcel.ParcelStatus)parcelDataBlock["Status"].AsInteger(); parcel.TotalPrims = parcelDataBlock["TotalPrims"].AsInteger(); @@ -1474,7 +1492,7 @@ namespace OpenMetaverse if (Client.Settings.PARCEL_TRACKING) { - if(parcel.SequenceID.Equals(int.MaxValue)) + if(sequenceID.Equals(int.MaxValue)) WaitForSimParcel.Set(); lock (simulator.Parcels.Dictionary) @@ -1495,14 +1513,13 @@ namespace OpenMetaverse simulator.ParcelMap[y, x] = parcel.LocalID; } } - } } // auto request acl, will be stored in parcel tracking dictionary if enabled if (Client.Settings.ALWAYS_REQUEST_PARCEL_ACL) Client.Parcels.AccessListRequest(simulator, parcel.LocalID, - AccessList.Both, parcel.SequenceID); + AccessList.Both, sequenceID); // auto request dwell, will be stored in parcel tracking dictionary if enables if (Client.Settings.ALWAYS_REQUEST_PARCEL_DWELL) @@ -1511,11 +1528,7 @@ namespace OpenMetaverse // Fire the callback for parcel properties being received if (OnParcelProperties != null) { - try - { - OnParcelProperties(parcel, (ParcelResult)parcel.RequestResult, - parcel.SequenceID, parcel.SnapSelection); - } + try { OnParcelProperties(simulator, parcel, result, selectedPrims, sequenceID, snapSelection); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } @@ -1539,7 +1552,7 @@ namespace OpenMetaverse { ParcelPropertiesPacket properties = (ParcelPropertiesPacket)packet; - Parcel parcel = new Parcel(simulator, properties.ParcelData.LocalID); + Parcel parcel = new Parcel(properties.ParcelData.LocalID); parcel.AABBMax = properties.ParcelData.AABBMax; parcel.AABBMin = properties.ParcelData.AABBMin; @@ -1576,7 +1589,7 @@ namespace OpenMetaverse parcel.RegionPushOverride = properties.ParcelData.RegionPushOverride; parcel.RentPrice = properties.ParcelData.RentPrice; parcel.SalePrice = properties.ParcelData.SalePrice; - parcel.SelectedPrims = properties.ParcelData.SelectedPrims; + int selectedPrims = properties.ParcelData.SelectedPrims; parcel.SelfCount = properties.ParcelData.SelfCount; parcel.SimWideMaxPrims = properties.ParcelData.SimWideMaxPrims; parcel.SimWideTotalPrims = properties.ParcelData.SimWideTotalPrims; @@ -1625,8 +1638,8 @@ namespace OpenMetaverse { try { - OnParcelProperties(parcel, (ParcelResult)properties.ParcelData.RequestResult, - properties.ParcelData.SequenceID, properties.ParcelData.SnapSelection); + OnParcelProperties(simulator, parcel, (ParcelResult)properties.ParcelData.RequestResult, + selectedPrims, properties.ParcelData.SequenceID, properties.ParcelData.SnapSelection); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } @@ -1745,6 +1758,33 @@ namespace OpenMetaverse } } + private void ParcelOverlayHandler(Packet packet, Simulator simulator) + { + const int OVERLAY_COUNT = 4; + + ParcelOverlayPacket overlay = (ParcelOverlayPacket)packet; + + if (overlay.ParcelData.SequenceID >= 0 && overlay.ParcelData.SequenceID < OVERLAY_COUNT) + { + int length = overlay.ParcelData.Data.Length; + + Buffer.BlockCopy(overlay.ParcelData.Data, 0, simulator.ParcelOverlay, + overlay.ParcelData.SequenceID * length, length); + simulator.ParcelOverlaysReceived++; + + if (simulator.ParcelOverlaysReceived >= OVERLAY_COUNT) + { + // TODO: ParcelOverlaysReceived should become internal, and reset to zero every + // time it hits four. Also need a callback here + } + } + else + { + Logger.Log("Parcel overlay with sequence ID of " + overlay.ParcelData.SequenceID + + " received from " + simulator.ToString(), Helpers.LogLevel.Warning, Client); + } + } + #endregion Packet Handlers } } diff --git a/OpenMetaverse/Simulator.cs b/OpenMetaverse/Simulator.cs index 8638f32d..7dbd2340 100644 --- a/OpenMetaverse/Simulator.cs +++ b/OpenMetaverse/Simulator.cs @@ -244,7 +244,7 @@ namespace OpenMetaverse /// public string Name = String.Empty; /// - public byte[] ParcelOverlay = new byte[4096]; + public ParcelOverlayType[] ParcelOverlay = new ParcelOverlayType[4096]; /// public int ParcelOverlaysReceived; /// diff --git a/Programs/examples/TestClient/Commands/Land/ParcelSelectObjectsCommand.cs b/Programs/examples/TestClient/Commands/Land/ParcelSelectObjectsCommand.cs index 3ff1a98a..ec14e089 100644 --- a/Programs/examples/TestClient/Commands/Land/ParcelSelectObjectsCommand.cs +++ b/Programs/examples/TestClient/Commands/Land/ParcelSelectObjectsCommand.cs @@ -44,7 +44,7 @@ namespace OpenMetaverse.TestClient }; Client.Parcels.OnParcelSelectedObjects += callback; - Client.Parcels.SelectObjects(parcelID, (ParcelManager.ObjectReturnType)16, ownerUUID); + Client.Parcels.SelectObjects(parcelID, (ObjectReturnType)16, ownerUUID); Client.Parcels.ObjectOwnersRequest(Client.Network.CurrentSim, parcelID);