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
///