diff --git a/LibreMetaverse/ParcelManager.cs b/LibreMetaverse/ParcelManager.cs index 551c716b..fc763d91 100644 --- a/LibreMetaverse/ParcelManager.cs +++ b/LibreMetaverse/ParcelManager.cs @@ -606,6 +606,137 @@ public Parcel(int localID) Media = new ParcelMedia(); } + /// + /// UpdateParcelAccessList - Update the parcel access or ban list on the simulator + /// + /// The grid client we are using + /// Simulator to send updates to + /// Local ID of the parcel to update + /// what list to update sending AccessList.Both will result in a warning + /// list of avatar entry records + public void UpdateParcelAccessList( + GridClient Client, + Simulator simulator, + int parcelLocalId, + AccessList flags, + List entries) + { + // based on Alchemy Viewer's implementation + // might want to be cleaned up later + if (flags == AccessList.Both) + { + Logger.Log("Warning: UpdateParcelAccessList called with AccessList.Both, this is not supported. " + + "Use AccessList.Access or AccessList.Ban", Helpers.LogLevel.Warning); + return; + } + if (simulator == null) + { + Logger.Log("Simulator is null", Helpers.LogLevel.Error); + } + if (parcelLocalId == 0) + { + Logger.Log("Parcel LocalID is zero", Helpers.LogLevel.Error); + return; + } + if (Client == null) + { + Logger.Log("Client is null", Helpers.LogLevel.Error); + return; + } + if (Client.Network == null) + { + Logger.Log("Client.Network is null", Helpers.LogLevel.Error); + return; + } + if (Client.Network.CurrentSim == null) + { + Logger.Log("Client.Network.CurrentSim is null not sure if network is fully ready", Helpers.LogLevel.Error); + return; + } + if (entries.Count == 0) + { + // send an empty block to clear the list + Guid sendemptyGuid = Guid.NewGuid(); + var packet = new ParcelAccessListUpdatePacket + { + AgentData = { + AgentID = Client.Self.AgentID, + SessionID = Client.Self.SessionID + }, + Data = { + Flags = (uint)flags, + LocalID = parcelLocalId, + TransactionID = new UUID(sendemptyGuid.ToString()), + SequenceID = 1, + Sections = 0 + }, + List = { } + }; + packet.List = new ParcelAccessListUpdatePacket.ListBlock[1]; + packet.List[0] = new ParcelAccessListUpdatePacket.ListBlock + { + ID = UUID.Zero, + Time = 0, + Flags = 0 + }; + simulator.SendPacket(packet); + return; + } + + const int PARCEL_MAX_ENTRIES_PER_PACKET = 48; // ?? matching viewer's limit, but not documented anywhere + int count = entries.Count; + int numSections = (int)Math.Ceiling((double)count / PARCEL_MAX_ENTRIES_PER_PACKET); + int sequenceId = 1; + Guid transactionUUID = Guid.NewGuid(); + int entryIndex = 0; + for (int section = 0; section < numSections; section++) + { + var packet = new ParcelAccessListUpdatePacket + { + AgentData = { + AgentID = Client.Self.AgentID, + SessionID = Client.Self.SessionID + }, + Data = { + Flags = (uint)flags, + LocalID = parcelLocalId, + TransactionID = new UUID(transactionUUID.ToString()), + SequenceID = sequenceId, + Sections = numSections + }, + List = new ParcelAccessListUpdatePacket.ListBlock[ + Math.Min(PARCEL_MAX_ENTRIES_PER_PACKET, count - entryIndex) + ] + }; + + for (int i = 0; i < packet.List.Length; i++, entryIndex++) + { + var entry = entries[entryIndex]; + packet.List[i] = new ParcelAccessListUpdatePacket.ListBlock + { + ID = entry.AgentID, + Time = (int)(entry.Time.Subtract(new DateTime(1970, 1, 1))).TotalSeconds, + Flags = (uint)entry.Flags + }; + } + + // If there are no entries, send an empty block + if (packet.List.Length == 0) + { + packet.List = new ParcelAccessListUpdatePacket.ListBlock[1]; + packet.List[0] = new ParcelAccessListUpdatePacket.ListBlock + { + ID = UUID.Zero, + Time = 0, + Flags = 0 + }; + } + + simulator.SendPacket(packet); + sequenceId++; + } + } + /// /// Update the simulator with any local changes to this Parcel object ///