From b341bc090833695184276c48dd36cd946791a00c Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 13 Jan 2011 11:39:50 -0500 Subject: Make FireAndForgetWrapper a singleton class Made FireAndForgetWrapper a singleton class to allow us to drop dependancy on the BclExtras35 library. BclExtras is broken in Mono 2.8.2 and we used the library in only one function. --- OpenSim/Framework/Util.cs | 27 ++++++++++++++++++++++++--- bin/BclExtras35.dll | Bin 153600 -> 0 bytes prebuild.xml | 2 -- 3 files changed, 24 insertions(+), 5 deletions(-) delete mode 100644 bin/BclExtras35.dll diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8d1671a..d1d8736 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -46,7 +46,7 @@ using System.Threading; using log4net; using Nini.Config; using Nwc.XmlRpc; -using BclExtras; +// using BclExtras; using OpenMetaverse; using OpenMetaverse.StructuredData; using Amib.Threading; @@ -1375,8 +1375,29 @@ namespace OpenSim.Framework /// /// Created to work around a limitation in Mono with nested delegates /// - private class FireAndForgetWrapper + private sealed class FireAndForgetWrapper { + private static volatile FireAndForgetWrapper instance; + private static object syncRoot = new Object(); + + public static FireAndForgetWrapper Instance { + get { + + if (instance == null) + { + lock (syncRoot) + { + if (instance == null) + { + instance = new FireAndForgetWrapper(); + } + } + } + + return instance; + } + } + public void FireAndForget(System.Threading.WaitCallback callback) { callback.BeginInvoke(null, EndFireAndForget, callback); @@ -1445,7 +1466,7 @@ namespace OpenSim.Framework ThreadPool.QueueUserWorkItem(callback, obj); break; case FireAndForgetMethod.BeginInvoke: - FireAndForgetWrapper wrapper = Singleton.GetInstance(); + FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; wrapper.FireAndForget(callback, obj); break; case FireAndForgetMethod.SmartThreadPool: diff --git a/bin/BclExtras35.dll b/bin/BclExtras35.dll deleted file mode 100644 index 7a7480a..0000000 Binary files a/bin/BclExtras35.dll and /dev/null differ diff --git a/prebuild.xml b/prebuild.xml index 48bb2d3..854149b 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -158,7 +158,6 @@ - @@ -1597,7 +1596,6 @@ - -- cgit v1.1 From b492f1ce99d27bcf29eb5805564c8778aa4df748 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sat, 12 Feb 2011 20:50:24 -0500 Subject: Fix unsitting of avatar on linked sets --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index cd70de8..cb2543f 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -472,7 +472,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID); if (part != null) { - return m_parentPosition + (m_pos * part.GetWorldRotation()); + return m_parentPosition + (m_pos * part.RotationOffset); } else { -- cgit v1.1 From 0d495ced4c4077ab456119650693c979eeb9d1ea Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sun, 13 Feb 2011 00:29:06 -0500 Subject: Revert "Fix unsitting of avatar on linked sets" This reverts commit b492f1ce99d27bcf29eb5805564c8778aa4df748. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index cb2543f..cd70de8 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -472,7 +472,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID); if (part != null) { - return m_parentPosition + (m_pos * part.RotationOffset); + return m_parentPosition + (m_pos * part.GetWorldRotation()); } else { -- cgit v1.1 From 6601771f812a360e6bc949da242878980ac0dd72 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sun, 13 Feb 2011 00:30:43 -0500 Subject: Set filter to send proper rotations for root part This allows the root prim, alone or in a set, to send it's rotation. This fixes unsitting the avatar on sit-offsest type teleports where the sit target is in the root prim of a linkset. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 6a92378..4d5eedf 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2099,7 +2099,7 @@ namespace OpenSim.Region.Framework.Scenes { Quaternion newRot; - if (this.LinkNum == 0) + if (this.LinkNum == 0 || this.LinkNum == 1) { newRot = RotationOffset; } -- cgit v1.1 From 61371c7c16eea3b856a852b94c98b18b99ccf8fb Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 28 Mar 2011 10:00:53 -0700 Subject: Implements adaptive queue management and fair queueing for improved networking performance. Reprioritization algorithms need to be ported still. One is in place. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 353 ++++++++++++++------- OpenSim/Region/Framework/Scenes/Prioritizer.cs | 71 ++++- 2 files changed, 304 insertions(+), 120 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 2c6795f..db149a1 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -49,6 +49,8 @@ using Timer = System.Timers.Timer; using AssetLandmark = OpenSim.Framework.AssetLandmark; using Nini.Config; +using System.IO; + namespace OpenSim.Region.ClientStack.LindenUDP { public delegate bool PacketMethod(IClientAPI simClient, Packet packet); @@ -298,6 +300,77 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Used to adjust Sun Orbit values so Linden based viewers properly position sun private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; + // First log file or time has expired, start writing to a new log file +// +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// THIS IS DEBUGGING CODE & SHOULD BE REMOVED +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- + public class QueueLogger + { + public Int32 start = 0; + public StreamWriter Log = null; + private Dictionary m_idMap = new Dictionary(); + + public QueueLogger() + { + DateTime now = DateTime.Now; + String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); + Log = new StreamWriter(fname); + + start = Util.EnvironmentTickCount(); + } + + public int LookupID(UUID uuid) + { + int localid; + if (! m_idMap.TryGetValue(uuid,out localid)) + { + localid = m_idMap.Count + 1; + m_idMap[uuid] = localid; + } + + return localid; + } + } + + public static QueueLogger QueueLog = null; + + // ----------------------------------------------------------------- + public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) + { + if (QueueLog == null) + QueueLog = new QueueLogger(); + + Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); + lock(QueueLog) + { + int cid = QueueLog.LookupID(client); + int aid = QueueLog.LookupID(avatar); + QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); + } + } + + // ----------------------------------------------------------------- + public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) + { + if (QueueLog == null) + QueueLog = new QueueLogger(); + + Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); + lock(QueueLog) + { + int cid = QueueLog.LookupID(client); + QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); + } + } +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients @@ -3547,18 +3620,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Primitive Packet/Data Sending Methods + /// /// Generate one of the object update packets based on PrimUpdateFlags /// and broadcast the packet to clients /// public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) { - double priority = m_prioritizer.GetUpdatePriority(this, entity); + //double priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = m_prioritizer.GetUpdatePriority(this, entity); lock (m_entityUpdates.SyncRoot) - m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation), entity.LocalId); + m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); } + private Int32 m_LastQueueFill = 0; + private uint m_maxUpdates = 0; + private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3566,23 +3644,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); - if (maxUpdates <= 0) maxUpdates = Int32.MaxValue; + if (maxUpdates <= 0) + { + m_maxUpdates = Int32.MaxValue; + } + else + { + if (m_maxUpdates == 0 || m_LastQueueFill == 0) + { + m_maxUpdates = (uint)maxUpdates; + } + else + { + if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) + m_maxUpdates += 5; + else + m_maxUpdates = m_maxUpdates >> 1; + } + m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); + } + m_LastQueueFill = Util.EnvironmentTickCount(); + int updatesThisCall = 0; +// +// DEBUGGING CODE... REMOVE +// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates); +// // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race // condition where a kill can be processed before an out-of-date update for the same object. lock (m_killRecord) { float avgTimeDilation = 1.0f; EntityUpdate update; - while (updatesThisCall < maxUpdates) + Int32 timeinqueue; // this is just debugging code & can be dropped later + + while (updatesThisCall < m_maxUpdates) { lock (m_entityUpdates.SyncRoot) - if (!m_entityUpdates.TryDequeue(out update)) + if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) break; avgTimeDilation += update.TimeDilation; avgTimeDilation *= 0.5f; +// +// DEBUGGING CODE... REMOVE +// if (update.Entity is ScenePresence) +// LogAvatarUpdateEvent(this.m_agentId,update.Entity.UUID,timeinqueue); +// + if (update.Entity is SceneObjectPart) { SceneObjectPart part = (SceneObjectPart)update.Entity; @@ -3679,36 +3789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) - // { - // SceneObjectPart sop = (SceneObjectPart)update.Entity; - // string text = sop.Text; - // if (text.IndexOf("\n") >= 0) - // text = text.Remove(text.IndexOf("\n")); - // - // if (m_attachmentsSent.Contains(sop.ParentID)) - // { - //// m_log.DebugFormat( - //// "[CLIENT]: Sending full info about attached prim {0} text {1}", - //// sop.LocalId, text); - // - // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId)); - // - // m_attachmentsSent.Add(sop.LocalId); - // } - // else - // { - // m_log.DebugFormat( - // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet", - // sop.LocalId, text, sop.ParentID); - // - // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId); - // } - // } - // else - // { - objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); - // } + objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); } } else if (!canUseImproved) @@ -3802,26 +3883,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void ReprioritizeUpdates() { - //m_log.Debug("[CLIENT]: Reprioritizing prim updates for " + m_firstName + " " + m_lastName); - lock (m_entityUpdates.SyncRoot) m_entityUpdates.Reprioritize(UpdatePriorityHandler); } - private bool UpdatePriorityHandler(ref double priority, uint localID) + private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity) { - EntityBase entity; - if (m_scene.Entities.TryGetValue(localID, out entity)) + if (entity != null) { priority = m_prioritizer.GetUpdatePriority(this, entity); + return true; } - return priority != double.NaN; + return false; } public void FlushPrimUpdates() { - m_log.Debug("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName); + m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName); while (m_entityUpdates.Count > 0) ProcessEntityUpdates(-1); @@ -11704,86 +11783,85 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region PriorityQueue public class PriorityQueue { - internal delegate bool UpdatePriorityHandler(ref double priority, uint local_id); + internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); + + // Heap[0] for self updates + // Heap[1..12] for entity updates - private MinHeap[] m_heaps = new MinHeap[1]; + internal const uint m_numberOfQueues = 12; + private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues]; private Dictionary m_lookupTable; - private Comparison m_comparison; private object m_syncRoot = new object(); - + private uint m_nextQueue = 0; + private UInt64 m_nextRequest = 0; + internal PriorityQueue() : - this(MinHeap.DEFAULT_CAPACITY, Comparer.Default) { } - internal PriorityQueue(int capacity) : - this(capacity, Comparer.Default) { } - internal PriorityQueue(IComparer comparer) : - this(new Comparison(comparer.Compare)) { } - internal PriorityQueue(Comparison comparison) : - this(MinHeap.DEFAULT_CAPACITY, comparison) { } - internal PriorityQueue(int capacity, IComparer comparer) : - this(capacity, new Comparison(comparer.Compare)) { } - internal PriorityQueue(int capacity, Comparison comparison) + this(MinHeap.DEFAULT_CAPACITY) { } + internal PriorityQueue(int capacity) { m_lookupTable = new Dictionary(capacity); for (int i = 0; i < m_heaps.Length; ++i) m_heaps[i] = new MinHeap(capacity); - this.m_comparison = comparison; } public object SyncRoot { get { return this.m_syncRoot; } } + internal int Count { get { int count = 0; for (int i = 0; i < m_heaps.Length; ++i) - count = m_heaps[i].Count; + count += m_heaps[i].Count; return count; } } - public bool Enqueue(double priority, EntityUpdate value, uint local_id) + public bool Enqueue(uint pqueue, EntityUpdate value) { - LookupItem item; + LookupItem lookup; - if (m_lookupTable.TryGetValue(local_id, out item)) + uint localid = value.Entity.LocalId; + UInt64 entry = m_nextRequest++; + if (m_lookupTable.TryGetValue(localid, out lookup)) { - // Combine flags - value.Flags |= item.Heap[item.Handle].Value.Flags; - - item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.m_comparison); - return false; - } - else - { - item.Heap = m_heaps[0]; - item.Heap.Add(new MinHeapItem(priority, value, local_id, this.m_comparison), ref item.Handle); - m_lookupTable.Add(local_id, item); - return true; + entry = lookup.Heap[lookup.Handle].EntryOrder; + value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; + lookup.Heap.Remove(lookup.Handle); } - } - internal EntityUpdate Peek() - { - for (int i = 0; i < m_heaps.Length; ++i) - if (m_heaps[i].Count > 0) - return m_heaps[i].Min().Value; - throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); + pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); + lookup.Heap = m_heaps[pqueue]; + lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); + m_lookupTable[localid] = lookup; + + return true; } - internal bool TryDequeue(out EntityUpdate value) + internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) { - for (int i = 0; i < m_heaps.Length; ++i) + for (int i = 0; i < m_numberOfQueues; ++i) { - if (m_heaps[i].Count > 0) + // To get the fair queing, we cycle through each of the + // queues when finding an element to dequeue, this code + // assumes that the distribution of updates in the queues + // is polynomial, probably quadractic (eg distance of PI * R^2) + uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); + if (m_heaps[h].Count > 0) { - MinHeapItem item = m_heaps[i].RemoveMin(); - m_lookupTable.Remove(item.LocalID); + m_nextQueue = (uint)((h + 1) % m_numberOfQueues); + + MinHeapItem item = m_heaps[h].RemoveMin(); + m_lookupTable.Remove(item.Value.Entity.LocalId); + timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); value = item.Value; + return true; } } + timeinqueue = 0; value = default(EntityUpdate); return false; } @@ -11791,68 +11869,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP internal void Reprioritize(UpdatePriorityHandler handler) { MinHeapItem item; - double priority; - foreach (LookupItem lookup in new List(this.m_lookupTable.Values)) { if (lookup.Heap.TryGetValue(lookup.Handle, out item)) { - priority = item.Priority; - if (handler(ref priority, item.LocalID)) + uint pqueue = item.PriorityQueue; + uint localid = item.Value.Entity.LocalId; + + if (handler(ref pqueue, item.Value.Entity)) { - if (lookup.Heap.ContainsHandle(lookup.Handle)) - lookup.Heap[lookup.Handle] = - new MinHeapItem(priority, item.Value, item.LocalID, this.m_comparison); + // unless the priority queue has changed, there is no need to modify + // the entry + pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); + if (pqueue != item.PriorityQueue) + { + lookup.Heap.Remove(lookup.Handle); + + LookupItem litem = lookup; + litem.Heap = m_heaps[pqueue]; + litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle); + m_lookupTable[localid] = litem; + } } else { - m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update"); + m_log.WarnFormat("[LLCLIENTVIEW]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID); lookup.Heap.Remove(lookup.Handle); - this.m_lookupTable.Remove(item.LocalID); + this.m_lookupTable.Remove(localid); } } } } + public override string ToString() + { + string s = ""; + for (int i = 0; i < m_numberOfQueues; i++) + { + if (s != "") s += ","; + s += m_heaps[i].Count.ToString(); + } + return s; + } + #region MinHeapItem private struct MinHeapItem : IComparable { - private double priority; private EntityUpdate value; - private uint local_id; - private Comparison comparison; + internal EntityUpdate Value { + get { + return this.value; + } + } + + private uint pqueue; + internal uint PriorityQueue { + get { + return this.pqueue; + } + } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id) : - this(priority, value, local_id, Comparer.Default) { } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id, IComparer comparer) : - this(priority, value, local_id, new Comparison(comparer.Compare)) { } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id, Comparison comparison) + private Int32 entrytime; + internal Int32 EntryTime { + get { + return this.entrytime; + } + } + + private UInt64 entryorder; + internal UInt64 EntryOrder { - this.priority = priority; + get { + return this.entryorder; + } + } + + internal MinHeapItem(uint pqueue, MinHeapItem other) + { + this.entrytime = other.entrytime; + this.entryorder = other.entryorder; + this.value = other.value; + this.pqueue = pqueue; + } + + internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) + { + this.entrytime = Util.EnvironmentTickCount(); + this.entryorder = entryorder; this.value = value; - this.local_id = local_id; - this.comparison = comparison; + this.pqueue = pqueue; } - internal double Priority { get { return this.priority; } } - internal EntityUpdate Value { get { return this.value; } } - internal uint LocalID { get { return this.local_id; } } - public override string ToString() { - StringBuilder sb = new StringBuilder(); - sb.Append("["); - sb.Append(this.priority.ToString()); - sb.Append(","); - if (this.value != null) - sb.Append(this.value.ToString()); - sb.Append("]"); - return sb.ToString(); + return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId); } public int CompareTo(MinHeapItem other) { - return this.comparison(this.priority, other.priority); + // I'm assuming that the root part of an SOG is added to the update queue + // before the component parts + return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder); } } #endregion diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index f9599f5..2764b05 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Scenes public class Prioritizer { -// private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); /// /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the @@ -76,7 +76,74 @@ namespace OpenSim.Region.Framework.Scenes m_scene = scene; } - public double GetUpdatePriority(IClientAPI client, ISceneEntity entity) +// + public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) + { + if (entity == null) + { + m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); + throw new InvalidOperationException("Prioritization entity not defined"); + } + + // If this is an update for our own avatar give it the highest priority + if (client.AgentId == entity.UUID) + return 0; + + // Get this agent's position + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); + if (presence == null) + { + m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); + throw new InvalidOperationException("Prioritization agent not defined"); + } + + // Use group position for child prims + Vector3 entityPos = entity.AbsolutePosition; + if (entity is SceneObjectPart) + { + SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; + if (group != null) + entityPos = group.AbsolutePosition; + } + + // Use the camera position for local agents and avatar position for remote agents + Vector3 presencePos = (presence.IsChildAgent) ? + presence.AbsolutePosition : + presence.CameraPosition; + + // Compute the distance... + double distance = Vector3.Distance(presencePos, entityPos); + + // And convert the distance to a priority queue, this computation gives queues + // at 10, 20, 40, 80, 160, 320, 640, and 1280m + uint pqueue = 1; + for (int i = 0; i < 8; i++) + { + if (distance < 10 * Math.Pow(2.0,i)) + break; + pqueue++; + } + + // If this is a root agent, then determine front & back + // Bump up the priority queue for any objects behind the avatar + if (! presence.IsChildAgent) + { + // Root agent, decrease priority for objects behind us + Vector3 camPosition = presence.CameraPosition; + Vector3 camAtAxis = presence.CameraAtAxis; + + // Plane equation + float d = -Vector3.Dot(camPosition, camAtAxis); + float p = Vector3.Dot(camAtAxis, entityPos) + d; + if (p < 0.0f) + pqueue++; + } + + return pqueue; + } +// + + public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity) { double priority = 0; -- cgit v1.1 From 6885b7220c6f782034d7c0220762244adf00e3d3 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 28 Mar 2011 10:00:53 -0700 Subject: Implements adaptive queue management and fair queueing for improved networking performance. Reprioritization algorithms need to be ported still. One is in place. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 353 ++++++++++++++------- OpenSim/Region/Framework/Scenes/Prioritizer.cs | 71 ++++- 2 files changed, 304 insertions(+), 120 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 2faffae..e9e1fa3 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -49,6 +49,8 @@ using Timer = System.Timers.Timer; using AssetLandmark = OpenSim.Framework.AssetLandmark; using Nini.Config; +using System.IO; + namespace OpenSim.Region.ClientStack.LindenUDP { public delegate bool PacketMethod(IClientAPI simClient, Packet packet); @@ -298,6 +300,77 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Used to adjust Sun Orbit values so Linden based viewers properly position sun private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; + // First log file or time has expired, start writing to a new log file +// +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// THIS IS DEBUGGING CODE & SHOULD BE REMOVED +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- + public class QueueLogger + { + public Int32 start = 0; + public StreamWriter Log = null; + private Dictionary m_idMap = new Dictionary(); + + public QueueLogger() + { + DateTime now = DateTime.Now; + String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); + Log = new StreamWriter(fname); + + start = Util.EnvironmentTickCount(); + } + + public int LookupID(UUID uuid) + { + int localid; + if (! m_idMap.TryGetValue(uuid,out localid)) + { + localid = m_idMap.Count + 1; + m_idMap[uuid] = localid; + } + + return localid; + } + } + + public static QueueLogger QueueLog = null; + + // ----------------------------------------------------------------- + public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) + { + if (QueueLog == null) + QueueLog = new QueueLogger(); + + Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); + lock(QueueLog) + { + int cid = QueueLog.LookupID(client); + int aid = QueueLog.LookupID(avatar); + QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); + } + } + + // ----------------------------------------------------------------- + public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) + { + if (QueueLog == null) + QueueLog = new QueueLogger(); + + Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); + lock(QueueLog) + { + int cid = QueueLog.LookupID(client); + QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); + } + } +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients @@ -3547,18 +3620,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Primitive Packet/Data Sending Methods + /// /// Generate one of the object update packets based on PrimUpdateFlags /// and broadcast the packet to clients /// public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) { - double priority = m_prioritizer.GetUpdatePriority(this, entity); + //double priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = m_prioritizer.GetUpdatePriority(this, entity); lock (m_entityUpdates.SyncRoot) - m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation), entity.LocalId); + m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); } + private Int32 m_LastQueueFill = 0; + private uint m_maxUpdates = 0; + private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3566,23 +3644,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); - if (maxUpdates <= 0) maxUpdates = Int32.MaxValue; + if (maxUpdates <= 0) + { + m_maxUpdates = Int32.MaxValue; + } + else + { + if (m_maxUpdates == 0 || m_LastQueueFill == 0) + { + m_maxUpdates = (uint)maxUpdates; + } + else + { + if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) + m_maxUpdates += 5; + else + m_maxUpdates = m_maxUpdates >> 1; + } + m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); + } + m_LastQueueFill = Util.EnvironmentTickCount(); + int updatesThisCall = 0; +// +// DEBUGGING CODE... REMOVE +// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates); +// // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race // condition where a kill can be processed before an out-of-date update for the same object. lock (m_killRecord) { float avgTimeDilation = 1.0f; EntityUpdate update; - while (updatesThisCall < maxUpdates) + Int32 timeinqueue; // this is just debugging code & can be dropped later + + while (updatesThisCall < m_maxUpdates) { lock (m_entityUpdates.SyncRoot) - if (!m_entityUpdates.TryDequeue(out update)) + if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) break; avgTimeDilation += update.TimeDilation; avgTimeDilation *= 0.5f; +// +// DEBUGGING CODE... REMOVE +// if (update.Entity is ScenePresence) +// LogAvatarUpdateEvent(this.m_agentId,update.Entity.UUID,timeinqueue); +// + if (update.Entity is SceneObjectPart) { SceneObjectPart part = (SceneObjectPart)update.Entity; @@ -3679,36 +3789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) - // { - // SceneObjectPart sop = (SceneObjectPart)update.Entity; - // string text = sop.Text; - // if (text.IndexOf("\n") >= 0) - // text = text.Remove(text.IndexOf("\n")); - // - // if (m_attachmentsSent.Contains(sop.ParentID)) - // { - //// m_log.DebugFormat( - //// "[CLIENT]: Sending full info about attached prim {0} text {1}", - //// sop.LocalId, text); - // - // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId)); - // - // m_attachmentsSent.Add(sop.LocalId); - // } - // else - // { - // m_log.DebugFormat( - // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet", - // sop.LocalId, text, sop.ParentID); - // - // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId); - // } - // } - // else - // { - objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); - // } + objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); } } else if (!canUseImproved) @@ -3802,26 +3883,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void ReprioritizeUpdates() { - //m_log.Debug("[CLIENT]: Reprioritizing prim updates for " + m_firstName + " " + m_lastName); - lock (m_entityUpdates.SyncRoot) m_entityUpdates.Reprioritize(UpdatePriorityHandler); } - private bool UpdatePriorityHandler(ref double priority, uint localID) + private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity) { - EntityBase entity; - if (m_scene.Entities.TryGetValue(localID, out entity)) + if (entity != null) { priority = m_prioritizer.GetUpdatePriority(this, entity); + return true; } - return priority != double.NaN; + return false; } public void FlushPrimUpdates() { - m_log.Debug("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName); + m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName); while (m_entityUpdates.Count > 0) ProcessEntityUpdates(-1); @@ -11713,86 +11792,85 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region PriorityQueue public class PriorityQueue { - internal delegate bool UpdatePriorityHandler(ref double priority, uint local_id); + internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); + + // Heap[0] for self updates + // Heap[1..12] for entity updates - private MinHeap[] m_heaps = new MinHeap[1]; + internal const uint m_numberOfQueues = 12; + private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues]; private Dictionary m_lookupTable; - private Comparison m_comparison; private object m_syncRoot = new object(); - + private uint m_nextQueue = 0; + private UInt64 m_nextRequest = 0; + internal PriorityQueue() : - this(MinHeap.DEFAULT_CAPACITY, Comparer.Default) { } - internal PriorityQueue(int capacity) : - this(capacity, Comparer.Default) { } - internal PriorityQueue(IComparer comparer) : - this(new Comparison(comparer.Compare)) { } - internal PriorityQueue(Comparison comparison) : - this(MinHeap.DEFAULT_CAPACITY, comparison) { } - internal PriorityQueue(int capacity, IComparer comparer) : - this(capacity, new Comparison(comparer.Compare)) { } - internal PriorityQueue(int capacity, Comparison comparison) + this(MinHeap.DEFAULT_CAPACITY) { } + internal PriorityQueue(int capacity) { m_lookupTable = new Dictionary(capacity); for (int i = 0; i < m_heaps.Length; ++i) m_heaps[i] = new MinHeap(capacity); - this.m_comparison = comparison; } public object SyncRoot { get { return this.m_syncRoot; } } + internal int Count { get { int count = 0; for (int i = 0; i < m_heaps.Length; ++i) - count = m_heaps[i].Count; + count += m_heaps[i].Count; return count; } } - public bool Enqueue(double priority, EntityUpdate value, uint local_id) + public bool Enqueue(uint pqueue, EntityUpdate value) { - LookupItem item; + LookupItem lookup; - if (m_lookupTable.TryGetValue(local_id, out item)) + uint localid = value.Entity.LocalId; + UInt64 entry = m_nextRequest++; + if (m_lookupTable.TryGetValue(localid, out lookup)) { - // Combine flags - value.Flags |= item.Heap[item.Handle].Value.Flags; - - item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.m_comparison); - return false; - } - else - { - item.Heap = m_heaps[0]; - item.Heap.Add(new MinHeapItem(priority, value, local_id, this.m_comparison), ref item.Handle); - m_lookupTable.Add(local_id, item); - return true; + entry = lookup.Heap[lookup.Handle].EntryOrder; + value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; + lookup.Heap.Remove(lookup.Handle); } - } - internal EntityUpdate Peek() - { - for (int i = 0; i < m_heaps.Length; ++i) - if (m_heaps[i].Count > 0) - return m_heaps[i].Min().Value; - throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); + pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); + lookup.Heap = m_heaps[pqueue]; + lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); + m_lookupTable[localid] = lookup; + + return true; } - internal bool TryDequeue(out EntityUpdate value) + internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) { - for (int i = 0; i < m_heaps.Length; ++i) + for (int i = 0; i < m_numberOfQueues; ++i) { - if (m_heaps[i].Count > 0) + // To get the fair queing, we cycle through each of the + // queues when finding an element to dequeue, this code + // assumes that the distribution of updates in the queues + // is polynomial, probably quadractic (eg distance of PI * R^2) + uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); + if (m_heaps[h].Count > 0) { - MinHeapItem item = m_heaps[i].RemoveMin(); - m_lookupTable.Remove(item.LocalID); + m_nextQueue = (uint)((h + 1) % m_numberOfQueues); + + MinHeapItem item = m_heaps[h].RemoveMin(); + m_lookupTable.Remove(item.Value.Entity.LocalId); + timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); value = item.Value; + return true; } } + timeinqueue = 0; value = default(EntityUpdate); return false; } @@ -11800,68 +11878,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP internal void Reprioritize(UpdatePriorityHandler handler) { MinHeapItem item; - double priority; - foreach (LookupItem lookup in new List(this.m_lookupTable.Values)) { if (lookup.Heap.TryGetValue(lookup.Handle, out item)) { - priority = item.Priority; - if (handler(ref priority, item.LocalID)) + uint pqueue = item.PriorityQueue; + uint localid = item.Value.Entity.LocalId; + + if (handler(ref pqueue, item.Value.Entity)) { - if (lookup.Heap.ContainsHandle(lookup.Handle)) - lookup.Heap[lookup.Handle] = - new MinHeapItem(priority, item.Value, item.LocalID, this.m_comparison); + // unless the priority queue has changed, there is no need to modify + // the entry + pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); + if (pqueue != item.PriorityQueue) + { + lookup.Heap.Remove(lookup.Handle); + + LookupItem litem = lookup; + litem.Heap = m_heaps[pqueue]; + litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle); + m_lookupTable[localid] = litem; + } } else { - m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update"); + m_log.WarnFormat("[LLCLIENTVIEW]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID); lookup.Heap.Remove(lookup.Handle); - this.m_lookupTable.Remove(item.LocalID); + this.m_lookupTable.Remove(localid); } } } } + public override string ToString() + { + string s = ""; + for (int i = 0; i < m_numberOfQueues; i++) + { + if (s != "") s += ","; + s += m_heaps[i].Count.ToString(); + } + return s; + } + #region MinHeapItem private struct MinHeapItem : IComparable { - private double priority; private EntityUpdate value; - private uint local_id; - private Comparison comparison; + internal EntityUpdate Value { + get { + return this.value; + } + } + + private uint pqueue; + internal uint PriorityQueue { + get { + return this.pqueue; + } + } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id) : - this(priority, value, local_id, Comparer.Default) { } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id, IComparer comparer) : - this(priority, value, local_id, new Comparison(comparer.Compare)) { } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id, Comparison comparison) + private Int32 entrytime; + internal Int32 EntryTime { + get { + return this.entrytime; + } + } + + private UInt64 entryorder; + internal UInt64 EntryOrder { - this.priority = priority; + get { + return this.entryorder; + } + } + + internal MinHeapItem(uint pqueue, MinHeapItem other) + { + this.entrytime = other.entrytime; + this.entryorder = other.entryorder; + this.value = other.value; + this.pqueue = pqueue; + } + + internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) + { + this.entrytime = Util.EnvironmentTickCount(); + this.entryorder = entryorder; this.value = value; - this.local_id = local_id; - this.comparison = comparison; + this.pqueue = pqueue; } - internal double Priority { get { return this.priority; } } - internal EntityUpdate Value { get { return this.value; } } - internal uint LocalID { get { return this.local_id; } } - public override string ToString() { - StringBuilder sb = new StringBuilder(); - sb.Append("["); - sb.Append(this.priority.ToString()); - sb.Append(","); - if (this.value != null) - sb.Append(this.value.ToString()); - sb.Append("]"); - return sb.ToString(); + return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId); } public int CompareTo(MinHeapItem other) { - return this.comparison(this.priority, other.priority); + // I'm assuming that the root part of an SOG is added to the update queue + // before the component parts + return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder); } } #endregion diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index f9599f5..2764b05 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Scenes public class Prioritizer { -// private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); /// /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the @@ -76,7 +76,74 @@ namespace OpenSim.Region.Framework.Scenes m_scene = scene; } - public double GetUpdatePriority(IClientAPI client, ISceneEntity entity) +// + public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) + { + if (entity == null) + { + m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); + throw new InvalidOperationException("Prioritization entity not defined"); + } + + // If this is an update for our own avatar give it the highest priority + if (client.AgentId == entity.UUID) + return 0; + + // Get this agent's position + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); + if (presence == null) + { + m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); + throw new InvalidOperationException("Prioritization agent not defined"); + } + + // Use group position for child prims + Vector3 entityPos = entity.AbsolutePosition; + if (entity is SceneObjectPart) + { + SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; + if (group != null) + entityPos = group.AbsolutePosition; + } + + // Use the camera position for local agents and avatar position for remote agents + Vector3 presencePos = (presence.IsChildAgent) ? + presence.AbsolutePosition : + presence.CameraPosition; + + // Compute the distance... + double distance = Vector3.Distance(presencePos, entityPos); + + // And convert the distance to a priority queue, this computation gives queues + // at 10, 20, 40, 80, 160, 320, 640, and 1280m + uint pqueue = 1; + for (int i = 0; i < 8; i++) + { + if (distance < 10 * Math.Pow(2.0,i)) + break; + pqueue++; + } + + // If this is a root agent, then determine front & back + // Bump up the priority queue for any objects behind the avatar + if (! presence.IsChildAgent) + { + // Root agent, decrease priority for objects behind us + Vector3 camPosition = presence.CameraPosition; + Vector3 camAtAxis = presence.CameraAtAxis; + + // Plane equation + float d = -Vector3.Dot(camPosition, camAtAxis); + float p = Vector3.Dot(camAtAxis, entityPos) + d; + if (p < 0.0f) + pqueue++; + } + + return pqueue; + } +// + + public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity) { double priority = 0; -- cgit v1.1 From 15c4bbea59066c5d5ed3d76d253a096788ac295a Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 4 Apr 2011 13:19:45 -0700 Subject: Fixed the prioritizer functions for the new priority queues --- OpenSim/Region/Framework/Scenes/Prioritizer.cs | 292 +++++++------------------ 1 file changed, 82 insertions(+), 210 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index 2764b05..a14bb70 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -60,15 +60,6 @@ namespace OpenSim.Region.Framework.Scenes { private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - /// - /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the - /// viewer before child prim updates. - /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up - /// being double. We do it both ways so that there is a still a priority delta even if the priority is already - /// double.MinValue or double.MaxValue. - /// - private double m_childPrimAdjustmentFactor = 0.05; - private Scene m_scene; public Prioritizer(Scene scene) @@ -76,9 +67,19 @@ namespace OpenSim.Region.Framework.Scenes m_scene = scene; } -// + /// + /// Returns the priority queue into which the update should be placed. Updates within a + /// queue will be processed in arrival order. There are currently 12 priority queues + /// implemented in PriorityQueue class in LLClientView. Queue 0 is generally retained + /// for avatar updates. The fair queuing discipline for processing the priority queues + /// assumes that the number of entities in each priority queues increases exponentially. + /// So for example... if queue 1 contains all updates within 10m of the avatar or camera + /// then queue 2 at 20m is about 3X bigger in space & about 3X bigger in total number + /// of updates. + /// public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) { + // If entity is null we have a serious problem if (entity == null) { m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); @@ -89,71 +90,12 @@ namespace OpenSim.Region.Framework.Scenes if (client.AgentId == entity.UUID) return 0; - // Get this agent's position - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence == null) - { - m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); - throw new InvalidOperationException("Prioritization agent not defined"); - } - - // Use group position for child prims - Vector3 entityPos = entity.AbsolutePosition; - if (entity is SceneObjectPart) - { - SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; - if (group != null) - entityPos = group.AbsolutePosition; - } - - // Use the camera position for local agents and avatar position for remote agents - Vector3 presencePos = (presence.IsChildAgent) ? - presence.AbsolutePosition : - presence.CameraPosition; - - // Compute the distance... - double distance = Vector3.Distance(presencePos, entityPos); - - // And convert the distance to a priority queue, this computation gives queues - // at 10, 20, 40, 80, 160, 320, 640, and 1280m - uint pqueue = 1; - for (int i = 0; i < 8; i++) - { - if (distance < 10 * Math.Pow(2.0,i)) - break; - pqueue++; - } - - // If this is a root agent, then determine front & back - // Bump up the priority queue for any objects behind the avatar - if (! presence.IsChildAgent) - { - // Root agent, decrease priority for objects behind us - Vector3 camPosition = presence.CameraPosition; - Vector3 camAtAxis = presence.CameraAtAxis; - - // Plane equation - float d = -Vector3.Dot(camPosition, camAtAxis); - float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) - pqueue++; - } - - return pqueue; - } -// - - public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity) - { - double priority = 0; - - if (entity == null) - return 100000; + uint priority; switch (m_scene.UpdatePrioritizationScheme) { case UpdatePrioritizationSchemes.Time: - priority = GetPriorityByTime(); + priority = GetPriorityByTime(client, entity); break; case UpdatePrioritizationSchemes.Distance: priority = GetPriorityByDistance(client, entity); @@ -171,180 +113,110 @@ namespace OpenSim.Region.Framework.Scenes throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); } - // Adjust priority so that root prims are sent to the viewer first. This is especially important for - // attachments acting as huds, since current viewers fail to display hud child prims if their updates - // arrive before the root one. - if (entity is SceneObjectPart) - { - SceneObjectPart sop = ((SceneObjectPart)entity); - - if (sop.IsRoot) - { - if (priority >= double.MinValue + m_childPrimAdjustmentFactor) - priority -= m_childPrimAdjustmentFactor; - } - else - { - if (priority <= double.MaxValue - m_childPrimAdjustmentFactor) - priority += m_childPrimAdjustmentFactor; - } - } - return priority; } - private double GetPriorityByTime() + + private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) { - return DateTime.UtcNow.ToOADate(); + return 1; } - private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity) + private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity) { - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence != null) - { - // If this is an update for our own avatar give it the highest priority - if (presence == entity) - return 0.0; - - // Use the camera position for local agents and avatar position for remote agents - Vector3 presencePos = (presence.IsChildAgent) ? - presence.AbsolutePosition : - presence.CameraPosition; - - // Use group position for child prims - Vector3 entityPos; - if (entity is SceneObjectPart) - { - // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene - // before its scheduled update was triggered - //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; - entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; - } - else - { - entityPos = entity.AbsolutePosition; - } - - return Vector3.DistanceSquared(presencePos, entityPos); - } - - return double.NaN; + return ComputeDistancePriority(client,entity,false); + } + + private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) + { + return ComputeDistancePriority(client,entity,true); } - private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) + private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) { + uint pqueue = ComputeDistancePriority(client,entity,true); + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); if (presence != null) { - // If this is an update for our own avatar give it the highest priority - if (presence == entity) - return 0.0; - - // Use group position for child prims - Vector3 entityPos = entity.AbsolutePosition; - if (entity is SceneObjectPart) - { - // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene - // before its scheduled update was triggered - //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; - entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; - } - else - { - entityPos = entity.AbsolutePosition; - } - if (!presence.IsChildAgent) { - // Root agent. Use distance from camera and a priority decrease for objects behind us - Vector3 camPosition = presence.CameraPosition; - Vector3 camAtAxis = presence.CameraAtAxis; - - // Distance - double priority = Vector3.DistanceSquared(camPosition, entityPos); - - // Plane equation - float d = -Vector3.Dot(camPosition, camAtAxis); - float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) priority *= 2.0; - - return priority; - } - else - { - // Child agent. Use the normal distance method - Vector3 presencePos = presence.AbsolutePosition; + if (entity is SceneObjectPart) + { + // Non physical prims are lower priority than physical prims + PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; + if (physActor == null || !physActor.IsPhysical) + pqueue++; - return Vector3.DistanceSquared(presencePos, entityPos); + // Attachments are high priority, + // MIC: shouldn't these already be in the highest priority queue already + // since their root position is same as the avatars? + if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) + pqueue = 1; + } } } - return double.NaN; + return pqueue; } - private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) + private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack) { - // If this is an update for our own avatar give it the highest priority - if (client.AgentId == entity.UUID) - return 0.0; - if (entity == null) - return double.NaN; - - // Use group position for child prims + // Get this agent's position + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); + if (presence == null) + { + m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); + throw new InvalidOperationException("Prioritization agent not defined"); + } + + // Use group position for child prims, since we are putting child prims in + // the same queue with the root of the group, the root prim (which goes into + // the queue first) should always be sent first, no need to adjust child prim + // priorities Vector3 entityPos = entity.AbsolutePosition; if (entity is SceneObjectPart) { SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; if (group != null) entityPos = group.AbsolutePosition; - else - entityPos = entity.AbsolutePosition; } - else - entityPos = entity.AbsolutePosition; - - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence != null) - { - if (!presence.IsChildAgent) - { - if (entity is ScenePresence) - return 1.0; - // Root agent. Use distance from camera and a priority decrease for objects behind us - Vector3 camPosition = presence.CameraPosition; - Vector3 camAtAxis = presence.CameraAtAxis; - - // Distance - double priority = Vector3.DistanceSquared(camPosition, entityPos); - - // Plane equation - float d = -Vector3.Dot(camPosition, camAtAxis); - float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) priority *= 2.0; + // Use the camera position for local agents and avatar position for remote agents + Vector3 presencePos = (presence.IsChildAgent) ? + presence.AbsolutePosition : + presence.CameraPosition; - if (entity is SceneObjectPart) - { - PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; - if (physActor == null || !physActor.IsPhysical) - priority += 100; + // Compute the distance... + double distance = Vector3.Distance(presencePos, entityPos); - if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) - priority = 1.0; - } - return priority; - } - else - { - // Child agent. Use the normal distance method - Vector3 presencePos = presence.AbsolutePosition; + // And convert the distance to a priority queue, this computation gives queues + // at 10, 20, 40, 80, 160, 320, 640, and 1280m + uint pqueue = 1; + for (int i = 0; i < 8; i++) + { + if (distance < 10 * Math.Pow(2.0,i)) + break; + pqueue++; + } + + // If this is a root agent, then determine front & back + // Bump up the priority queue (drop the priority) for any objects behind the avatar + if (useFrontBack && ! presence.IsChildAgent) + { + // Root agent, decrease priority for objects behind us + Vector3 camPosition = presence.CameraPosition; + Vector3 camAtAxis = presence.CameraAtAxis; - return Vector3.DistanceSquared(presencePos, entityPos); - } + // Plane equation + float d = -Vector3.Dot(camPosition, camAtAxis); + float p = Vector3.Dot(camAtAxis, entityPos) + d; + if (p < 0.0f) + pqueue++; } - return double.NaN; + return pqueue; } + } } -- cgit v1.1 From 8b134f37f2c8cc7895153af2fdc79e785f3b93e2 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 4 Apr 2011 14:18:26 -0700 Subject: Fix a bug in the computation of the RTO. Basically... the RTO (the time to wait to retransmit packets) always maxed out (no retransmissions for 24 or 48 seconds. Note that this is going to cause faster (and more) retransmissions. Fix for dynamic throttling needs to go with this. --- OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 65a8fe3..9a8bfd3 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Caches packed throttle information private byte[] m_packedThrottles; - private int m_defaultRTO = 3000; + private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC private int m_maxRTO = 60000; /// @@ -557,7 +557,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); // Clamp the retransmission timeout to manageable values - rto = Utils.Clamp(RTO, m_defaultRTO, m_maxRTO); + rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO); RTO = rto; -- cgit v1.1 From 77cf9405de10f016d85d67b6016ed27d28ed898f Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 28 Mar 2011 10:00:53 -0700 Subject: Implements adaptive queue management and fair queueing for improved networking performance. Reprioritization algorithms need to be ported still. One is in place. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 353 ++++++++++++++------- OpenSim/Region/Framework/Scenes/Prioritizer.cs | 71 ++++- 2 files changed, 304 insertions(+), 120 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 34d72ac..a3f2c15 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -49,6 +49,8 @@ using Timer = System.Timers.Timer; using AssetLandmark = OpenSim.Framework.AssetLandmark; using Nini.Config; +using System.IO; + namespace OpenSim.Region.ClientStack.LindenUDP { public delegate bool PacketMethod(IClientAPI simClient, Packet packet); @@ -298,6 +300,77 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Used to adjust Sun Orbit values so Linden based viewers properly position sun private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; + // First log file or time has expired, start writing to a new log file +// +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// THIS IS DEBUGGING CODE & SHOULD BE REMOVED +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- + public class QueueLogger + { + public Int32 start = 0; + public StreamWriter Log = null; + private Dictionary m_idMap = new Dictionary(); + + public QueueLogger() + { + DateTime now = DateTime.Now; + String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); + Log = new StreamWriter(fname); + + start = Util.EnvironmentTickCount(); + } + + public int LookupID(UUID uuid) + { + int localid; + if (! m_idMap.TryGetValue(uuid,out localid)) + { + localid = m_idMap.Count + 1; + m_idMap[uuid] = localid; + } + + return localid; + } + } + + public static QueueLogger QueueLog = null; + + // ----------------------------------------------------------------- + public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) + { + if (QueueLog == null) + QueueLog = new QueueLogger(); + + Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); + lock(QueueLog) + { + int cid = QueueLog.LookupID(client); + int aid = QueueLog.LookupID(avatar); + QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); + } + } + + // ----------------------------------------------------------------- + public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) + { + if (QueueLog == null) + QueueLog = new QueueLogger(); + + Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); + lock(QueueLog) + { + int cid = QueueLog.LookupID(client); + QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); + } + } +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients @@ -3547,18 +3620,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Primitive Packet/Data Sending Methods + /// /// Generate one of the object update packets based on PrimUpdateFlags /// and broadcast the packet to clients /// public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) { - double priority = m_prioritizer.GetUpdatePriority(this, entity); + //double priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = m_prioritizer.GetUpdatePriority(this, entity); lock (m_entityUpdates.SyncRoot) - m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation), entity.LocalId); + m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); } + private Int32 m_LastQueueFill = 0; + private uint m_maxUpdates = 0; + private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3566,23 +3644,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); - if (maxUpdates <= 0) maxUpdates = Int32.MaxValue; + if (maxUpdates <= 0) + { + m_maxUpdates = Int32.MaxValue; + } + else + { + if (m_maxUpdates == 0 || m_LastQueueFill == 0) + { + m_maxUpdates = (uint)maxUpdates; + } + else + { + if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) + m_maxUpdates += 5; + else + m_maxUpdates = m_maxUpdates >> 1; + } + m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); + } + m_LastQueueFill = Util.EnvironmentTickCount(); + int updatesThisCall = 0; +// +// DEBUGGING CODE... REMOVE +// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates); +// // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race // condition where a kill can be processed before an out-of-date update for the same object. lock (m_killRecord) { float avgTimeDilation = 1.0f; EntityUpdate update; - while (updatesThisCall < maxUpdates) + Int32 timeinqueue; // this is just debugging code & can be dropped later + + while (updatesThisCall < m_maxUpdates) { lock (m_entityUpdates.SyncRoot) - if (!m_entityUpdates.TryDequeue(out update)) + if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) break; avgTimeDilation += update.TimeDilation; avgTimeDilation *= 0.5f; +// +// DEBUGGING CODE... REMOVE +// if (update.Entity is ScenePresence) +// LogAvatarUpdateEvent(this.m_agentId,update.Entity.UUID,timeinqueue); +// + if (update.Entity is SceneObjectPart) { SceneObjectPart part = (SceneObjectPart)update.Entity; @@ -3679,36 +3789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) - // { - // SceneObjectPart sop = (SceneObjectPart)update.Entity; - // string text = sop.Text; - // if (text.IndexOf("\n") >= 0) - // text = text.Remove(text.IndexOf("\n")); - // - // if (m_attachmentsSent.Contains(sop.ParentID)) - // { - //// m_log.DebugFormat( - //// "[CLIENT]: Sending full info about attached prim {0} text {1}", - //// sop.LocalId, text); - // - // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId)); - // - // m_attachmentsSent.Add(sop.LocalId); - // } - // else - // { - // m_log.DebugFormat( - // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet", - // sop.LocalId, text, sop.ParentID); - // - // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId); - // } - // } - // else - // { - objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); - // } + objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); } } else if (!canUseImproved) @@ -3802,26 +3883,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void ReprioritizeUpdates() { - //m_log.Debug("[CLIENT]: Reprioritizing prim updates for " + m_firstName + " " + m_lastName); - lock (m_entityUpdates.SyncRoot) m_entityUpdates.Reprioritize(UpdatePriorityHandler); } - private bool UpdatePriorityHandler(ref double priority, uint localID) + private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity) { - EntityBase entity; - if (m_scene.Entities.TryGetValue(localID, out entity)) + if (entity != null) { priority = m_prioritizer.GetUpdatePriority(this, entity); + return true; } - return priority != double.NaN; + return false; } public void FlushPrimUpdates() { - m_log.Debug("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName); + m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName); while (m_entityUpdates.Count > 0) ProcessEntityUpdates(-1); @@ -11729,86 +11808,85 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region PriorityQueue public class PriorityQueue { - internal delegate bool UpdatePriorityHandler(ref double priority, uint local_id); + internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); + + // Heap[0] for self updates + // Heap[1..12] for entity updates - private MinHeap[] m_heaps = new MinHeap[1]; + internal const uint m_numberOfQueues = 12; + private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues]; private Dictionary m_lookupTable; - private Comparison m_comparison; private object m_syncRoot = new object(); - + private uint m_nextQueue = 0; + private UInt64 m_nextRequest = 0; + internal PriorityQueue() : - this(MinHeap.DEFAULT_CAPACITY, Comparer.Default) { } - internal PriorityQueue(int capacity) : - this(capacity, Comparer.Default) { } - internal PriorityQueue(IComparer comparer) : - this(new Comparison(comparer.Compare)) { } - internal PriorityQueue(Comparison comparison) : - this(MinHeap.DEFAULT_CAPACITY, comparison) { } - internal PriorityQueue(int capacity, IComparer comparer) : - this(capacity, new Comparison(comparer.Compare)) { } - internal PriorityQueue(int capacity, Comparison comparison) + this(MinHeap.DEFAULT_CAPACITY) { } + internal PriorityQueue(int capacity) { m_lookupTable = new Dictionary(capacity); for (int i = 0; i < m_heaps.Length; ++i) m_heaps[i] = new MinHeap(capacity); - this.m_comparison = comparison; } public object SyncRoot { get { return this.m_syncRoot; } } + internal int Count { get { int count = 0; for (int i = 0; i < m_heaps.Length; ++i) - count = m_heaps[i].Count; + count += m_heaps[i].Count; return count; } } - public bool Enqueue(double priority, EntityUpdate value, uint local_id) + public bool Enqueue(uint pqueue, EntityUpdate value) { - LookupItem item; + LookupItem lookup; - if (m_lookupTable.TryGetValue(local_id, out item)) + uint localid = value.Entity.LocalId; + UInt64 entry = m_nextRequest++; + if (m_lookupTable.TryGetValue(localid, out lookup)) { - // Combine flags - value.Flags |= item.Heap[item.Handle].Value.Flags; - - item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.m_comparison); - return false; - } - else - { - item.Heap = m_heaps[0]; - item.Heap.Add(new MinHeapItem(priority, value, local_id, this.m_comparison), ref item.Handle); - m_lookupTable.Add(local_id, item); - return true; + entry = lookup.Heap[lookup.Handle].EntryOrder; + value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; + lookup.Heap.Remove(lookup.Handle); } - } - internal EntityUpdate Peek() - { - for (int i = 0; i < m_heaps.Length; ++i) - if (m_heaps[i].Count > 0) - return m_heaps[i].Min().Value; - throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); + pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); + lookup.Heap = m_heaps[pqueue]; + lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); + m_lookupTable[localid] = lookup; + + return true; } - internal bool TryDequeue(out EntityUpdate value) + internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) { - for (int i = 0; i < m_heaps.Length; ++i) + for (int i = 0; i < m_numberOfQueues; ++i) { - if (m_heaps[i].Count > 0) + // To get the fair queing, we cycle through each of the + // queues when finding an element to dequeue, this code + // assumes that the distribution of updates in the queues + // is polynomial, probably quadractic (eg distance of PI * R^2) + uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); + if (m_heaps[h].Count > 0) { - MinHeapItem item = m_heaps[i].RemoveMin(); - m_lookupTable.Remove(item.LocalID); + m_nextQueue = (uint)((h + 1) % m_numberOfQueues); + + MinHeapItem item = m_heaps[h].RemoveMin(); + m_lookupTable.Remove(item.Value.Entity.LocalId); + timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); value = item.Value; + return true; } } + timeinqueue = 0; value = default(EntityUpdate); return false; } @@ -11816,68 +11894,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP internal void Reprioritize(UpdatePriorityHandler handler) { MinHeapItem item; - double priority; - foreach (LookupItem lookup in new List(this.m_lookupTable.Values)) { if (lookup.Heap.TryGetValue(lookup.Handle, out item)) { - priority = item.Priority; - if (handler(ref priority, item.LocalID)) + uint pqueue = item.PriorityQueue; + uint localid = item.Value.Entity.LocalId; + + if (handler(ref pqueue, item.Value.Entity)) { - if (lookup.Heap.ContainsHandle(lookup.Handle)) - lookup.Heap[lookup.Handle] = - new MinHeapItem(priority, item.Value, item.LocalID, this.m_comparison); + // unless the priority queue has changed, there is no need to modify + // the entry + pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); + if (pqueue != item.PriorityQueue) + { + lookup.Heap.Remove(lookup.Handle); + + LookupItem litem = lookup; + litem.Heap = m_heaps[pqueue]; + litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle); + m_lookupTable[localid] = litem; + } } else { - m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update"); + m_log.WarnFormat("[LLCLIENTVIEW]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID); lookup.Heap.Remove(lookup.Handle); - this.m_lookupTable.Remove(item.LocalID); + this.m_lookupTable.Remove(localid); } } } } + public override string ToString() + { + string s = ""; + for (int i = 0; i < m_numberOfQueues; i++) + { + if (s != "") s += ","; + s += m_heaps[i].Count.ToString(); + } + return s; + } + #region MinHeapItem private struct MinHeapItem : IComparable { - private double priority; private EntityUpdate value; - private uint local_id; - private Comparison comparison; + internal EntityUpdate Value { + get { + return this.value; + } + } + + private uint pqueue; + internal uint PriorityQueue { + get { + return this.pqueue; + } + } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id) : - this(priority, value, local_id, Comparer.Default) { } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id, IComparer comparer) : - this(priority, value, local_id, new Comparison(comparer.Compare)) { } - internal MinHeapItem(double priority, EntityUpdate value, uint local_id, Comparison comparison) + private Int32 entrytime; + internal Int32 EntryTime { + get { + return this.entrytime; + } + } + + private UInt64 entryorder; + internal UInt64 EntryOrder { - this.priority = priority; + get { + return this.entryorder; + } + } + + internal MinHeapItem(uint pqueue, MinHeapItem other) + { + this.entrytime = other.entrytime; + this.entryorder = other.entryorder; + this.value = other.value; + this.pqueue = pqueue; + } + + internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) + { + this.entrytime = Util.EnvironmentTickCount(); + this.entryorder = entryorder; this.value = value; - this.local_id = local_id; - this.comparison = comparison; + this.pqueue = pqueue; } - internal double Priority { get { return this.priority; } } - internal EntityUpdate Value { get { return this.value; } } - internal uint LocalID { get { return this.local_id; } } - public override string ToString() { - StringBuilder sb = new StringBuilder(); - sb.Append("["); - sb.Append(this.priority.ToString()); - sb.Append(","); - if (this.value != null) - sb.Append(this.value.ToString()); - sb.Append("]"); - return sb.ToString(); + return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId); } public int CompareTo(MinHeapItem other) { - return this.comparison(this.priority, other.priority); + // I'm assuming that the root part of an SOG is added to the update queue + // before the component parts + return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder); } } #endregion diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index f9599f5..2764b05 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Scenes public class Prioritizer { -// private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); /// /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the @@ -76,7 +76,74 @@ namespace OpenSim.Region.Framework.Scenes m_scene = scene; } - public double GetUpdatePriority(IClientAPI client, ISceneEntity entity) +// + public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) + { + if (entity == null) + { + m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); + throw new InvalidOperationException("Prioritization entity not defined"); + } + + // If this is an update for our own avatar give it the highest priority + if (client.AgentId == entity.UUID) + return 0; + + // Get this agent's position + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); + if (presence == null) + { + m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); + throw new InvalidOperationException("Prioritization agent not defined"); + } + + // Use group position for child prims + Vector3 entityPos = entity.AbsolutePosition; + if (entity is SceneObjectPart) + { + SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; + if (group != null) + entityPos = group.AbsolutePosition; + } + + // Use the camera position for local agents and avatar position for remote agents + Vector3 presencePos = (presence.IsChildAgent) ? + presence.AbsolutePosition : + presence.CameraPosition; + + // Compute the distance... + double distance = Vector3.Distance(presencePos, entityPos); + + // And convert the distance to a priority queue, this computation gives queues + // at 10, 20, 40, 80, 160, 320, 640, and 1280m + uint pqueue = 1; + for (int i = 0; i < 8; i++) + { + if (distance < 10 * Math.Pow(2.0,i)) + break; + pqueue++; + } + + // If this is a root agent, then determine front & back + // Bump up the priority queue for any objects behind the avatar + if (! presence.IsChildAgent) + { + // Root agent, decrease priority for objects behind us + Vector3 camPosition = presence.CameraPosition; + Vector3 camAtAxis = presence.CameraAtAxis; + + // Plane equation + float d = -Vector3.Dot(camPosition, camAtAxis); + float p = Vector3.Dot(camAtAxis, entityPos) + d; + if (p < 0.0f) + pqueue++; + } + + return pqueue; + } +// + + public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity) { double priority = 0; -- cgit v1.1 From 0bd06d8ba85595a1707d2093a08a901b950ca120 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 4 Apr 2011 13:19:45 -0700 Subject: Fixed the prioritizer functions for the new priority queues --- OpenSim/Region/Framework/Scenes/Prioritizer.cs | 292 +++++++------------------ 1 file changed, 82 insertions(+), 210 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index 2764b05..a14bb70 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -60,15 +60,6 @@ namespace OpenSim.Region.Framework.Scenes { private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - /// - /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the - /// viewer before child prim updates. - /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up - /// being double. We do it both ways so that there is a still a priority delta even if the priority is already - /// double.MinValue or double.MaxValue. - /// - private double m_childPrimAdjustmentFactor = 0.05; - private Scene m_scene; public Prioritizer(Scene scene) @@ -76,9 +67,19 @@ namespace OpenSim.Region.Framework.Scenes m_scene = scene; } -// + /// + /// Returns the priority queue into which the update should be placed. Updates within a + /// queue will be processed in arrival order. There are currently 12 priority queues + /// implemented in PriorityQueue class in LLClientView. Queue 0 is generally retained + /// for avatar updates. The fair queuing discipline for processing the priority queues + /// assumes that the number of entities in each priority queues increases exponentially. + /// So for example... if queue 1 contains all updates within 10m of the avatar or camera + /// then queue 2 at 20m is about 3X bigger in space & about 3X bigger in total number + /// of updates. + /// public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) { + // If entity is null we have a serious problem if (entity == null) { m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); @@ -89,71 +90,12 @@ namespace OpenSim.Region.Framework.Scenes if (client.AgentId == entity.UUID) return 0; - // Get this agent's position - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence == null) - { - m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); - throw new InvalidOperationException("Prioritization agent not defined"); - } - - // Use group position for child prims - Vector3 entityPos = entity.AbsolutePosition; - if (entity is SceneObjectPart) - { - SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; - if (group != null) - entityPos = group.AbsolutePosition; - } - - // Use the camera position for local agents and avatar position for remote agents - Vector3 presencePos = (presence.IsChildAgent) ? - presence.AbsolutePosition : - presence.CameraPosition; - - // Compute the distance... - double distance = Vector3.Distance(presencePos, entityPos); - - // And convert the distance to a priority queue, this computation gives queues - // at 10, 20, 40, 80, 160, 320, 640, and 1280m - uint pqueue = 1; - for (int i = 0; i < 8; i++) - { - if (distance < 10 * Math.Pow(2.0,i)) - break; - pqueue++; - } - - // If this is a root agent, then determine front & back - // Bump up the priority queue for any objects behind the avatar - if (! presence.IsChildAgent) - { - // Root agent, decrease priority for objects behind us - Vector3 camPosition = presence.CameraPosition; - Vector3 camAtAxis = presence.CameraAtAxis; - - // Plane equation - float d = -Vector3.Dot(camPosition, camAtAxis); - float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) - pqueue++; - } - - return pqueue; - } -// - - public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity) - { - double priority = 0; - - if (entity == null) - return 100000; + uint priority; switch (m_scene.UpdatePrioritizationScheme) { case UpdatePrioritizationSchemes.Time: - priority = GetPriorityByTime(); + priority = GetPriorityByTime(client, entity); break; case UpdatePrioritizationSchemes.Distance: priority = GetPriorityByDistance(client, entity); @@ -171,180 +113,110 @@ namespace OpenSim.Region.Framework.Scenes throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); } - // Adjust priority so that root prims are sent to the viewer first. This is especially important for - // attachments acting as huds, since current viewers fail to display hud child prims if their updates - // arrive before the root one. - if (entity is SceneObjectPart) - { - SceneObjectPart sop = ((SceneObjectPart)entity); - - if (sop.IsRoot) - { - if (priority >= double.MinValue + m_childPrimAdjustmentFactor) - priority -= m_childPrimAdjustmentFactor; - } - else - { - if (priority <= double.MaxValue - m_childPrimAdjustmentFactor) - priority += m_childPrimAdjustmentFactor; - } - } - return priority; } - private double GetPriorityByTime() + + private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) { - return DateTime.UtcNow.ToOADate(); + return 1; } - private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity) + private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity) { - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence != null) - { - // If this is an update for our own avatar give it the highest priority - if (presence == entity) - return 0.0; - - // Use the camera position for local agents and avatar position for remote agents - Vector3 presencePos = (presence.IsChildAgent) ? - presence.AbsolutePosition : - presence.CameraPosition; - - // Use group position for child prims - Vector3 entityPos; - if (entity is SceneObjectPart) - { - // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene - // before its scheduled update was triggered - //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; - entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; - } - else - { - entityPos = entity.AbsolutePosition; - } - - return Vector3.DistanceSquared(presencePos, entityPos); - } - - return double.NaN; + return ComputeDistancePriority(client,entity,false); + } + + private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) + { + return ComputeDistancePriority(client,entity,true); } - private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) + private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) { + uint pqueue = ComputeDistancePriority(client,entity,true); + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); if (presence != null) { - // If this is an update for our own avatar give it the highest priority - if (presence == entity) - return 0.0; - - // Use group position for child prims - Vector3 entityPos = entity.AbsolutePosition; - if (entity is SceneObjectPart) - { - // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene - // before its scheduled update was triggered - //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; - entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; - } - else - { - entityPos = entity.AbsolutePosition; - } - if (!presence.IsChildAgent) { - // Root agent. Use distance from camera and a priority decrease for objects behind us - Vector3 camPosition = presence.CameraPosition; - Vector3 camAtAxis = presence.CameraAtAxis; - - // Distance - double priority = Vector3.DistanceSquared(camPosition, entityPos); - - // Plane equation - float d = -Vector3.Dot(camPosition, camAtAxis); - float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) priority *= 2.0; - - return priority; - } - else - { - // Child agent. Use the normal distance method - Vector3 presencePos = presence.AbsolutePosition; + if (entity is SceneObjectPart) + { + // Non physical prims are lower priority than physical prims + PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; + if (physActor == null || !physActor.IsPhysical) + pqueue++; - return Vector3.DistanceSquared(presencePos, entityPos); + // Attachments are high priority, + // MIC: shouldn't these already be in the highest priority queue already + // since their root position is same as the avatars? + if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) + pqueue = 1; + } } } - return double.NaN; + return pqueue; } - private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) + private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack) { - // If this is an update for our own avatar give it the highest priority - if (client.AgentId == entity.UUID) - return 0.0; - if (entity == null) - return double.NaN; - - // Use group position for child prims + // Get this agent's position + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); + if (presence == null) + { + m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); + throw new InvalidOperationException("Prioritization agent not defined"); + } + + // Use group position for child prims, since we are putting child prims in + // the same queue with the root of the group, the root prim (which goes into + // the queue first) should always be sent first, no need to adjust child prim + // priorities Vector3 entityPos = entity.AbsolutePosition; if (entity is SceneObjectPart) { SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; if (group != null) entityPos = group.AbsolutePosition; - else - entityPos = entity.AbsolutePosition; } - else - entityPos = entity.AbsolutePosition; - - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence != null) - { - if (!presence.IsChildAgent) - { - if (entity is ScenePresence) - return 1.0; - // Root agent. Use distance from camera and a priority decrease for objects behind us - Vector3 camPosition = presence.CameraPosition; - Vector3 camAtAxis = presence.CameraAtAxis; - - // Distance - double priority = Vector3.DistanceSquared(camPosition, entityPos); - - // Plane equation - float d = -Vector3.Dot(camPosition, camAtAxis); - float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) priority *= 2.0; + // Use the camera position for local agents and avatar position for remote agents + Vector3 presencePos = (presence.IsChildAgent) ? + presence.AbsolutePosition : + presence.CameraPosition; - if (entity is SceneObjectPart) - { - PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; - if (physActor == null || !physActor.IsPhysical) - priority += 100; + // Compute the distance... + double distance = Vector3.Distance(presencePos, entityPos); - if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) - priority = 1.0; - } - return priority; - } - else - { - // Child agent. Use the normal distance method - Vector3 presencePos = presence.AbsolutePosition; + // And convert the distance to a priority queue, this computation gives queues + // at 10, 20, 40, 80, 160, 320, 640, and 1280m + uint pqueue = 1; + for (int i = 0; i < 8; i++) + { + if (distance < 10 * Math.Pow(2.0,i)) + break; + pqueue++; + } + + // If this is a root agent, then determine front & back + // Bump up the priority queue (drop the priority) for any objects behind the avatar + if (useFrontBack && ! presence.IsChildAgent) + { + // Root agent, decrease priority for objects behind us + Vector3 camPosition = presence.CameraPosition; + Vector3 camAtAxis = presence.CameraAtAxis; - return Vector3.DistanceSquared(presencePos, entityPos); - } + // Plane equation + float d = -Vector3.Dot(camPosition, camAtAxis); + float p = Vector3.Dot(camAtAxis, entityPos) + d; + if (p < 0.0f) + pqueue++; } - return double.NaN; + return pqueue; } + } } -- cgit v1.1 From 83dc2470f2e815f6f9d469104be3a2806438a29a Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 4 Apr 2011 14:18:26 -0700 Subject: Fix a bug in the computation of the RTO. Basically... the RTO (the time to wait to retransmit packets) always maxed out (no retransmissions for 24 or 48 seconds. Note that this is going to cause faster (and more) retransmissions. Fix for dynamic throttling needs to go with this. --- OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 65a8fe3..9a8bfd3 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Caches packed throttle information private byte[] m_packedThrottles; - private int m_defaultRTO = 3000; + private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC private int m_maxRTO = 60000; /// @@ -557,7 +557,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); // Clamp the retransmission timeout to manageable values - rto = Utils.Clamp(RTO, m_defaultRTO, m_maxRTO); + rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO); RTO = rto; -- cgit v1.1 From 19c6d1d569e081418e139d139c15ea66640288ba Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Wed, 6 Apr 2011 09:26:38 -0700 Subject: Split the priority queue class into a seperate file. LLClientView is big enough. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 205 ----------------- .../Region/ClientStack/LindenUDP/PriorityQueue.cs | 245 +++++++++++++++++++++ 2 files changed, 245 insertions(+), 205 deletions(-) create mode 100644 OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index a3f2c15..a724099 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -11805,209 +11805,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } - #region PriorityQueue - public class PriorityQueue - { - internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); - - // Heap[0] for self updates - // Heap[1..12] for entity updates - - internal const uint m_numberOfQueues = 12; - private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues]; - private Dictionary m_lookupTable; - private object m_syncRoot = new object(); - private uint m_nextQueue = 0; - private UInt64 m_nextRequest = 0; - - internal PriorityQueue() : - this(MinHeap.DEFAULT_CAPACITY) { } - internal PriorityQueue(int capacity) - { - m_lookupTable = new Dictionary(capacity); - - for (int i = 0; i < m_heaps.Length; ++i) - m_heaps[i] = new MinHeap(capacity); - } - - public object SyncRoot { get { return this.m_syncRoot; } } - - internal int Count - { - get - { - int count = 0; - for (int i = 0; i < m_heaps.Length; ++i) - count += m_heaps[i].Count; - return count; - } - } - - public bool Enqueue(uint pqueue, EntityUpdate value) - { - LookupItem lookup; - - uint localid = value.Entity.LocalId; - UInt64 entry = m_nextRequest++; - if (m_lookupTable.TryGetValue(localid, out lookup)) - { - entry = lookup.Heap[lookup.Handle].EntryOrder; - value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; - lookup.Heap.Remove(lookup.Handle); - } - - pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); - lookup.Heap = m_heaps[pqueue]; - lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); - m_lookupTable[localid] = lookup; - - return true; - } - - internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) - { - for (int i = 0; i < m_numberOfQueues; ++i) - { - // To get the fair queing, we cycle through each of the - // queues when finding an element to dequeue, this code - // assumes that the distribution of updates in the queues - // is polynomial, probably quadractic (eg distance of PI * R^2) - uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); - if (m_heaps[h].Count > 0) - { - m_nextQueue = (uint)((h + 1) % m_numberOfQueues); - - MinHeapItem item = m_heaps[h].RemoveMin(); - m_lookupTable.Remove(item.Value.Entity.LocalId); - timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); - value = item.Value; - - return true; - } - } - - timeinqueue = 0; - value = default(EntityUpdate); - return false; - } - - internal void Reprioritize(UpdatePriorityHandler handler) - { - MinHeapItem item; - foreach (LookupItem lookup in new List(this.m_lookupTable.Values)) - { - if (lookup.Heap.TryGetValue(lookup.Handle, out item)) - { - uint pqueue = item.PriorityQueue; - uint localid = item.Value.Entity.LocalId; - - if (handler(ref pqueue, item.Value.Entity)) - { - // unless the priority queue has changed, there is no need to modify - // the entry - pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); - if (pqueue != item.PriorityQueue) - { - lookup.Heap.Remove(lookup.Handle); - - LookupItem litem = lookup; - litem.Heap = m_heaps[pqueue]; - litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle); - m_lookupTable[localid] = litem; - } - } - else - { - m_log.WarnFormat("[LLCLIENTVIEW]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID); - lookup.Heap.Remove(lookup.Handle); - this.m_lookupTable.Remove(localid); - } - } - } - } - - public override string ToString() - { - string s = ""; - for (int i = 0; i < m_numberOfQueues; i++) - { - if (s != "") s += ","; - s += m_heaps[i].Count.ToString(); - } - return s; - } - - #region MinHeapItem - private struct MinHeapItem : IComparable - { - private EntityUpdate value; - internal EntityUpdate Value { - get { - return this.value; - } - } - - private uint pqueue; - internal uint PriorityQueue { - get { - return this.pqueue; - } - } - - private Int32 entrytime; - internal Int32 EntryTime { - get { - return this.entrytime; - } - } - - private UInt64 entryorder; - internal UInt64 EntryOrder - { - get { - return this.entryorder; - } - } - - internal MinHeapItem(uint pqueue, MinHeapItem other) - { - this.entrytime = other.entrytime; - this.entryorder = other.entryorder; - this.value = other.value; - this.pqueue = pqueue; - } - - internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) - { - this.entrytime = Util.EnvironmentTickCount(); - this.entryorder = entryorder; - this.value = value; - this.pqueue = pqueue; - } - - public override string ToString() - { - return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId); - } - - public int CompareTo(MinHeapItem other) - { - // I'm assuming that the root part of an SOG is added to the update queue - // before the component parts - return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder); - } - } - #endregion - - #region LookupItem - private struct LookupItem - { - internal MinHeap Heap; - internal IHandle Handle; - } - #endregion - } - public struct PacketProcessor { public PacketMethod method; @@ -12028,8 +11825,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - #endregion - public static OSD BuildEvent(string eventName, OSD eventBody) { OSDMap osdEvent = new OSDMap(2); diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs new file mode 100644 index 0000000..364ce4b --- /dev/null +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -0,0 +1,245 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +using OpenSim.Framework; +using OpenSim.Framework.Client; +using log4net; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public class PriorityQueue + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); + + // Heap[0] for self updates + // Heap[1..12] for entity updates + + internal const uint m_numberOfQueues = 12; + + private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues]; + private Dictionary m_lookupTable; + private uint m_nextQueue = 0; + private UInt64 m_nextRequest = 0; + + private object m_syncRoot = new object(); + public object SyncRoot { + get { return this.m_syncRoot; } + } + + internal PriorityQueue() : this(MinHeap.DEFAULT_CAPACITY) { } + + internal PriorityQueue(int capacity) + { + m_lookupTable = new Dictionary(capacity); + + for (int i = 0; i < m_heaps.Length; ++i) + m_heaps[i] = new MinHeap(capacity); + } + + internal int Count + { + get + { + int count = 0; + for (int i = 0; i < m_heaps.Length; ++i) + count += m_heaps[i].Count; + return count; + } + } + + public bool Enqueue(uint pqueue, EntityUpdate value) + { + LookupItem lookup; + + uint localid = value.Entity.LocalId; + UInt64 entry = m_nextRequest++; + if (m_lookupTable.TryGetValue(localid, out lookup)) + { + entry = lookup.Heap[lookup.Handle].EntryOrder; + value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; + lookup.Heap.Remove(lookup.Handle); + } + + pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); + lookup.Heap = m_heaps[pqueue]; + lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); + m_lookupTable[localid] = lookup; + + return true; + } + + internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) + { + for (int i = 0; i < m_numberOfQueues; ++i) + { + // To get the fair queing, we cycle through each of the + // queues when finding an element to dequeue, this code + // assumes that the distribution of updates in the queues + // is polynomial, probably quadractic (eg distance of PI * R^2) + uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); + if (m_heaps[h].Count > 0) + { + m_nextQueue = (uint)((h + 1) % m_numberOfQueues); + + MinHeapItem item = m_heaps[h].RemoveMin(); + m_lookupTable.Remove(item.Value.Entity.LocalId); + timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); + value = item.Value; + + return true; + } + } + + timeinqueue = 0; + value = default(EntityUpdate); + return false; + } + + internal void Reprioritize(UpdatePriorityHandler handler) + { + MinHeapItem item; + foreach (LookupItem lookup in new List(this.m_lookupTable.Values)) + { + if (lookup.Heap.TryGetValue(lookup.Handle, out item)) + { + uint pqueue = item.PriorityQueue; + uint localid = item.Value.Entity.LocalId; + + if (handler(ref pqueue, item.Value.Entity)) + { + // unless the priority queue has changed, there is no need to modify + // the entry + pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1); + if (pqueue != item.PriorityQueue) + { + lookup.Heap.Remove(lookup.Handle); + + LookupItem litem = lookup; + litem.Heap = m_heaps[pqueue]; + litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle); + m_lookupTable[localid] = litem; + } + } + else + { + // m_log.WarnFormat("[PQUEUE]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID); + lookup.Heap.Remove(lookup.Handle); + this.m_lookupTable.Remove(localid); + } + } + } + } + + public override string ToString() + { + string s = ""; + for (int i = 0; i < m_numberOfQueues; i++) + { + if (s != "") s += ","; + s += m_heaps[i].Count.ToString(); + } + return s; + } + +#region MinHeapItem + private struct MinHeapItem : IComparable + { + private EntityUpdate value; + internal EntityUpdate Value { + get { + return this.value; + } + } + + private uint pqueue; + internal uint PriorityQueue { + get { + return this.pqueue; + } + } + + private Int32 entrytime; + internal Int32 EntryTime { + get { + return this.entrytime; + } + } + + private UInt64 entryorder; + internal UInt64 EntryOrder + { + get { + return this.entryorder; + } + } + + internal MinHeapItem(uint pqueue, MinHeapItem other) + { + this.entrytime = other.entrytime; + this.entryorder = other.entryorder; + this.value = other.value; + this.pqueue = pqueue; + } + + internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) + { + this.entrytime = Util.EnvironmentTickCount(); + this.entryorder = entryorder; + this.value = value; + this.pqueue = pqueue; + } + + public override string ToString() + { + return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId); + } + + public int CompareTo(MinHeapItem other) + { + // I'm assuming that the root part of an SOG is added to the update queue + // before the component parts + return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder); + } + } +#endregion + +#region LookupItem + private struct LookupItem + { + internal MinHeap Heap; + internal IHandle Handle; + } +#endregion + } +} -- cgit v1.1 From ebc249e3bef57aee656936f5e63842d83ee29fff Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Sun, 10 Apr 2011 17:02:40 -0700 Subject: Changed the "not in scene" check in the prioritizier to just a warning. There appears to be a race condition on slow logins that attempts to prioritize before the scene presence is fully initialized. --- OpenSim/Region/Framework/Scenes/Prioritizer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index a14bb70..4694e2b 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -166,8 +166,9 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence presence = m_scene.GetScenePresence(client.AgentId); if (presence == null) { - m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); - throw new InvalidOperationException("Prioritization agent not defined"); + m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); + // throw new InvalidOperationException("Prioritization agent not defined"); + return Int32.MaxValue; } // Use group position for child prims, since we are putting child prims in -- cgit v1.1 From f778056c7a81443b11c0c4288979af3a8c6b5b9f Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 11 Apr 2011 08:37:43 -0700 Subject: Removed some priority queue debugging code --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 80 ---------------------- 1 file changed, 80 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index a724099..b5bf26d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -300,77 +300,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Used to adjust Sun Orbit values so Linden based viewers properly position sun private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; - // First log file or time has expired, start writing to a new log file -// -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// THIS IS DEBUGGING CODE & SHOULD BE REMOVED -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- - public class QueueLogger - { - public Int32 start = 0; - public StreamWriter Log = null; - private Dictionary m_idMap = new Dictionary(); - - public QueueLogger() - { - DateTime now = DateTime.Now; - String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); - Log = new StreamWriter(fname); - - start = Util.EnvironmentTickCount(); - } - - public int LookupID(UUID uuid) - { - int localid; - if (! m_idMap.TryGetValue(uuid,out localid)) - { - localid = m_idMap.Count + 1; - m_idMap[uuid] = localid; - } - - return localid; - } - } - - public static QueueLogger QueueLog = null; - - // ----------------------------------------------------------------- - public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - int aid = QueueLog.LookupID(avatar); - QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); - } - } - - // ----------------------------------------------------------------- - public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); - } - } -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients @@ -3667,10 +3596,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP int updatesThisCall = 0; -// -// DEBUGGING CODE... REMOVE -// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates); -// // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race // condition where a kill can be processed before an out-of-date update for the same object. lock (m_killRecord) @@ -3687,11 +3612,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP avgTimeDilation += update.TimeDilation; avgTimeDilation *= 0.5f; -// -// DEBUGGING CODE... REMOVE -// if (update.Entity is ScenePresence) -// LogAvatarUpdateEvent(this.m_agentId,update.Entity.UUID,timeinqueue); -// if (update.Entity is SceneObjectPart) { -- cgit v1.1 From 6e9cdb9ce32807ddd1a39e72c436b8fd788768d2 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 11 Apr 2011 09:06:28 -0700 Subject: New tokenbucket algorithm. This one provides fair sharing of the queues when client and simulator throttles are set. This algorithm also uses pre-defined burst rate of 150% of the sustained rate for each of the throttles. Removed the "state" queue. The state queue is not a Linden queue and appeared to be used just to get kill packets sent. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 6 +- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 96 ++++--- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 2 +- .../Region/ClientStack/LindenUDP/TokenBucket.cs | 300 ++++++++++++++------- 4 files changed, 259 insertions(+), 145 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 8de31d7..934a2d5 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -1610,7 +1610,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - OutPacket(kill, ThrottleOutPacketType.State); + // OutPacket(kill, ThrottleOutPacketType.State); + OutPacket(kill, ThrottleOutPacketType.Task); } } @@ -2440,7 +2441,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Effect = effectBlocks; - OutPacket(packet, ThrottleOutPacketType.State); + // OutPacket(packet, ThrottleOutPacketType.State); + OutPacket(packet, ThrottleOutPacketType.Task); } public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 9a8bfd3..5a69851 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -135,7 +135,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_nextOnQueueEmpty = 1; /// Throttle bucket for this agent's connection - private readonly TokenBucket m_throttle; + private readonly TokenBucket m_throttleClient; + /// Throttle bucket for this agent's connection + private readonly TokenBucket m_throttleCategory; /// Throttle buckets for each packet category private readonly TokenBucket[] m_throttleCategories; /// Outgoing queues for throttled packets @@ -174,7 +176,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_maxRTO = maxRTO; // Create a token bucket throttle for this client that has the scene token bucket as a parent - m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); + m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); + // Create a token bucket throttle for the total categary with the client bucket as a throttle + m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); // Create an array of token buckets for this clients different throttle categories m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; @@ -185,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Initialize the packet outboxes, where packets sit while they are waiting for tokens m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue(); // Initialize the token buckets that control the throttling for each category - m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); + m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type)); } // Default the retransmission timeout to three seconds @@ -206,6 +210,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_packetOutboxes[i].Clear(); m_nextPackets[i] = null; } + + // pull the throttle out of the scene throttle + m_throttleClient.Parent.UnregisterRequest(m_throttleClient); OnPacketStats = null; OnQueueEmpty = null; } @@ -216,6 +223,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Information about the client connection public ClientInfo GetClientInfo() { +/// + TokenBucket tb; + + tb = m_throttleClient.Parent; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT"); + + tb = m_throttleClient; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT"); + + tb = m_throttleCategory; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY"); + + for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) + { + tb = m_throttleCategories[i]; + m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET"); + } + +/// + // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists // of pending and needed ACKs for every client every time some method wants information about // this connection is a recipe for poor performance @@ -223,13 +250,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP info.pendingAcks = new Dictionary(); info.needAck = new Dictionary(); - info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; - info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; - info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; - info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; - info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; - info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; - info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; + info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; + info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; + info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; + info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; + // info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; + info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + info.taskThrottle + info.assetThrottle + info.textureThrottle; @@ -317,8 +345,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); // State is a subcategory of task that we allocate a percentage to - int state = (int)((float)task * STATE_TASK_PERCENTAGE); - task -= state; + int state = 0; + // int state = (int)((float)task * STATE_TASK_PERCENTAGE); + // task -= state; // Make sure none of the throttles are set below our packet MTU, // otherwise a throttle could become permanently clogged @@ -339,40 +368,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Update the token buckets with new throttle values TokenBucket bucket; - bucket = m_throttle; - bucket.MaxBurst = total; + bucket = m_throttleCategory; + bucket.RequestedDripRate = total; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; - bucket.DripRate = resend; - bucket.MaxBurst = resend; + bucket.RequestedDripRate = resend; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; - bucket.DripRate = land; - bucket.MaxBurst = land; + bucket.RequestedDripRate = land; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; - bucket.DripRate = wind; - bucket.MaxBurst = wind; + bucket.RequestedDripRate = wind; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; - bucket.DripRate = cloud; - bucket.MaxBurst = cloud; + bucket.RequestedDripRate = cloud; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; - bucket.DripRate = asset; - bucket.MaxBurst = asset; + bucket.RequestedDripRate = asset; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; - bucket.DripRate = task + state; - bucket.MaxBurst = task + state; + bucket.RequestedDripRate = task; bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; - bucket.DripRate = state; - bucket.MaxBurst = state; + bucket.RequestedDripRate = state; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; - bucket.DripRate = texture; - bucket.MaxBurst = texture; + bucket.RequestedDripRate = texture; // Reset the packed throttles cached data m_packedThrottles = null; @@ -387,14 +408,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP data = new byte[7 * 4]; int i = 0; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + - m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4; m_packedThrottles = data; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 583214c..d08b25f 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -228,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } #endregion BinaryStats - m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); + m_throttle = new TokenBucket(null, sceneThrottleBps); ThrottleRates = new ThrottleRates(configSource); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index 0a8331f..e4d59ff 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs @@ -26,6 +26,10 @@ */ using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using log4net; namespace OpenSim.Region.ClientStack.LindenUDP { @@ -35,89 +39,126 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public class TokenBucket { - /// Parent bucket to this bucket, or null if this is a root - /// bucket - TokenBucket parent; - /// Size of the bucket in bytes. If zero, the bucket has - /// infinite capacity - int maxBurst; - /// Rate that the bucket fills, in bytes per millisecond. If - /// zero, the bucket always remains full - int tokensPerMS; - /// Number of tokens currently in the bucket - int content; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static Int32 m_counter = 0; + + private Int32 m_identifier; + + /// + /// Number of ticks (ms) per quantum, drip rate and max burst + /// are defined over this interval. + /// + private const Int32 m_ticksPerQuantum = 1000; + + /// + /// This is the number of quantums worth of packets that can + /// be accommodated during a burst + /// + private const Double m_quantumsPerBurst = 1.5; + + /// + /// + private const Int32 m_minimumDripRate = 1400; + /// Time of the last drip, in system ticks - int lastDrip; + private Int32 m_lastDrip; + + /// + /// The number of bytes that can be sent at this moment. This is the + /// current number of tokens in the bucket + /// + private Int64 m_tokenCount; - #region Properties + /// + /// Map of children buckets and their requested maximum burst rate + /// + private Dictionary m_children = new Dictionary(); + +#region Properties /// /// The parent bucket of this bucket, or null if this bucket has no /// parent. The parent bucket will limit the aggregate bandwidth of all /// of its children buckets /// + private TokenBucket m_parent; public TokenBucket Parent { - get { return parent; } + get { return m_parent; } + set { m_parent = value; } } /// /// Maximum burst rate in bytes per second. This is the maximum number - /// of tokens that can accumulate in the bucket at any one time + /// of tokens that can accumulate in the bucket at any one time. This + /// also sets the total request for leaf nodes /// - public int MaxBurst + private Int64 m_burstRate; + public Int64 RequestedBurstRate { - get { return maxBurst; } - set { maxBurst = (value >= 0 ? value : 0); } + get { return m_burstRate; } + set { m_burstRate = (value < 0 ? 0 : value); } } + public Int64 BurstRate + { + get { + double rate = RequestedBurstRate * BurstRateModifier(); + if (rate < m_minimumDripRate * m_quantumsPerBurst) + rate = m_minimumDripRate * m_quantumsPerBurst; + + return (Int64) rate; + } + } + /// /// The speed limit of this bucket in bytes per second. This is the - /// number of tokens that are added to the bucket per second + /// number of tokens that are added to the bucket per quantum /// /// Tokens are added to the bucket any time /// is called, at the granularity of /// the system tick interval (typically around 15-22ms) - public int DripRate + private Int64 m_dripRate; + public Int64 RequestedDripRate { - get { return tokensPerMS * 1000; } - set - { - if (value == 0) - tokensPerMS = 0; - else - { - int bpms = (int)((float)value / 1000.0f); - - if (bpms <= 0) - tokensPerMS = 1; // 1 byte/ms is the minimum granularity - else - tokensPerMS = bpms; - } + get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } + set { + m_dripRate = (value < 0 ? 0 : value); + m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); + m_totalDripRequest = m_dripRate; + if (m_parent != null) + m_parent.RegisterRequest(this,m_dripRate); } } - /// - /// The speed limit of this bucket in bytes per millisecond - /// - public int DripPerMS + public Int64 DripRate { - get { return tokensPerMS; } + get { + if (m_parent == null) + return Math.Min(RequestedDripRate,TotalDripRequest); + + double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); + if (rate < m_minimumDripRate) + rate = m_minimumDripRate; + + return (Int64)rate; + } } /// - /// The number of bytes that can be sent at this moment. This is the - /// current number of tokens in the bucket - /// If this bucket has a parent bucket that does not have - /// enough tokens for a request, will - /// return false regardless of the content of this bucket + /// The current total of the requested maximum burst rates of + /// this bucket's children buckets. /// - public int Content - { - get { return content; } - } + private Int64 m_totalDripRequest; + public Int64 TotalDripRequest + { + get { return m_totalDripRequest; } + set { m_totalDripRequest = value; } + } + +#endregion Properties - #endregion Properties +#region Constructor /// /// Default constructor @@ -128,56 +169,115 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// zero if this bucket has no maximum capacity /// Rate that the bucket fills, in bytes per /// second. If zero, the bucket always remains full - public TokenBucket(TokenBucket parent, int maxBurst, int dripRate) + public TokenBucket(TokenBucket parent, Int64 dripRate) { - this.parent = parent; - MaxBurst = maxBurst; - DripRate = dripRate; - lastDrip = Environment.TickCount & Int32.MaxValue; + m_identifier = m_counter++; + + Parent = parent; + RequestedDripRate = dripRate; + // TotalDripRequest = dripRate; // this will be overwritten when a child node registers + // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); + m_lastDrip = Environment.TickCount & Int32.MaxValue; } +#endregion Constructor + /// - /// Remove a given number of tokens from the bucket + /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning + /// no modification if the requested bandwidth is less than the + /// max burst bandwidth all the way to the root of the throttle + /// hierarchy. However, if any of the parents is over-booked, then + /// the modifier will be less than 1. /// - /// Number of tokens to remove from the bucket - /// True if the requested number of tokens were removed from - /// the bucket, otherwise false - public bool RemoveTokens(int amount) + private double DripRateModifier() + { + Int64 driprate = DripRate; + return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; + } + + /// + /// + private double BurstRateModifier() + { + // for now... burst rate is always m_quantumsPerBurst (constant) + // larger than drip rate so the ratio of burst requests is the + // same as the drip ratio + return DripRateModifier(); + } + + /// + /// Register drip rate requested by a child of this throttle. Pass the + /// changes up the hierarchy. + /// + public void RegisterRequest(TokenBucket child, Int64 request) { - bool dummy; - return RemoveTokens(amount, out dummy); + m_children[child] = request; + // m_totalDripRequest = m_children.Values.Sum(); + + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; + + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); } /// + /// Remove the rate requested by a child of this throttle. Pass the + /// changes up the hierarchy. + /// + public void UnregisterRequest(TokenBucket child) + { + m_children.Remove(child); + // m_totalDripRequest = m_children.Values.Sum(); + + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; + + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); + } + + /// /// Remove a given number of tokens from the bucket /// /// Number of tokens to remove from the bucket - /// True if tokens were added to the bucket - /// during this call, otherwise false /// True if the requested number of tokens were removed from /// the bucket, otherwise false - public bool RemoveTokens(int amount, out bool dripSucceeded) + public bool RemoveTokens(Int64 amount) { - if (maxBurst == 0) + // Deposit tokens for this interval + Drip(); + + // If we have enough tokens then remove them and return + if (m_tokenCount - amount >= 0) { - dripSucceeded = true; - return true; + if (m_parent == null || m_parent.RemoveTokens(amount)) + { + m_tokenCount -= amount; + return true; + } } - dripSucceeded = Drip(); + return false; + } - if (content - amount >= 0) - { - if (parent != null && !parent.RemoveTokens(amount)) - return false; + /// + /// Deposit tokens into the bucket from a child bucket that did + /// not use all of its available tokens + /// + private void Deposit(Int64 count) + { + m_tokenCount += count; - content -= amount; - return true; - } - else - { - return false; - } + // Deposit the overflow in the parent bucket, this is how we share + // unused bandwidth + Int64 burstrate = BurstRate; + if (m_tokenCount > burstrate) + m_tokenCount = burstrate; } /// @@ -186,37 +286,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// call to Drip /// /// True if tokens were added to the bucket, otherwise false - public bool Drip() + private void Drip() { - if (tokensPerMS == 0) + // This should never happen... means we are a leaf node and were created + // with no drip rate... + if (DripRate == 0) { - content = maxBurst; - return true; + m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0"); + return; } - else - { - int now = Environment.TickCount & Int32.MaxValue; - int deltaMS = now - lastDrip; - - if (deltaMS <= 0) - { - if (deltaMS < 0) - lastDrip = now; - return false; - } + + // Determine the interval over which we are adding tokens, never add + // more than a single quantum of tokens + Int32 now = Environment.TickCount & Int32.MaxValue; + Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum); - int dripAmount = deltaMS * tokensPerMS; + m_lastDrip = now; - content = Math.Min(content + dripAmount, maxBurst); - lastDrip = now; + // This can be 0 in the very unusual case that the timer wrapped + // It can be 0 if we try add tokens at a sub-tick rate + if (deltaMS <= 0) + return; - if (dripAmount < 0 || content < 0) - // sim has been idle for too long, integer has overflown - // previous calculation is meaningless, let's put it at correct max - content = maxBurst; - - return true; - } + Deposit(deltaMS * DripRate / m_ticksPerQuantum); } } } -- cgit v1.1 From e9c2beadecf8f531d2bbfcd3f44636cfeff08667 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 20:43:11 +0100 Subject: Add more instructions to OpenSim.ini.example to try and make it more understandable for new users. --- bin/OpenSim.ini.example | 103 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 35 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 5bac56e..390fe09 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1,4 +1,22 @@ -;; A note on the format of this file +;; This is the main configuration file for OpenSimulator. If it's named OpenSim.ini +;; then it will be loaded by OpenSimulator. If it's named OpenSim.ini.example then +;; you will need to copy it to OpenSim.ini first (if that file does not already exist) +;; +;; If you are copying, then once you have copied OpenSim.ini.example to OpenSim.ini you will +;; need to pick an architecture in the [Architecture] section at the end of this file. +;; +;; The settings in this file are in the form " = ". For example, save_crashes = false +;; in the [Startup] section below. +;; +;; All settings are initially commented out and the default value used, as found in +;; OpenSimDefaults.ini. To change a setting, first uncomment it by deleting the initial semicolon (;) +;; and then change the value. This will override the value in OpenSimDefaults.ini +;; +;; If you want to find out what configuration OpenSimulator has used then type "config get" on the +;; region console command line. +;; +;; +;; NOTES FOR DEVELOPERS REGARDING FORMAT OF TIHS FILE ;; ;; All leading white space is ignored, but preserved. ;; @@ -8,15 +26,14 @@ ;; formatted as: ;; {option} {depends on} {question to ask} {choices} default value ;; Any text comments following the declaration, up to the next blank line. -;; will be copied to the generated file. -;; A * in the choices list will allow an empty entry.\ +;; will be copied to the generated file (NOTE: generation is not yet implemented) +;; A * in the choices list will allow an empty entry. ;; An empty question will set the default if the dependencies are ;; satisfied. ;; -;; ; denotes a commented out option. Uncomment it to actvate it -;; and change it to the desired value -;; Any options added to OpenSim.ini.exmaple must be commented out, -;; and their value must represent the default. +;; ; denotes a commented out option. +;; Any options added to OpenSim.ini.example should be initially commented out. + [Startup] ;# {save_crashes} {} {Save crashes to disk?} {true false} false @@ -35,7 +52,7 @@ ;; Determine where OpenSimulator looks for the files which tell it ;; which regions to server - ;; Defaults to "filesystem" if this setting isn't present + ;; Default is "filesystem" ; region_info_source = "filesystem" ; region_info_source = "web" @@ -131,6 +148,7 @@ ;; ZeroMesher is faster but leaves the physics engine to model the mesh ;; using the basic shapes that it supports. ;; Usually this is only a box. + ;; Default is Meshmerizer ; meshing = Meshmerizer ; meshing = ZeroMesher @@ -138,6 +156,7 @@ ;; OpenDynamicsEngine is by some distance the most developed physics engine ;; basicphysics effectively does not model physics at all, making all ;; objects phantom + ;; Default is OpenDynamicsEngine ; physics = OpenDynamicsEngine ; physics = basicphysics ; physics = POS @@ -154,7 +173,6 @@ ;; permission checks (allowing anybody to copy ;; any item, etc. This may not yet be implemented uniformally. ;; If set to true, then all permissions checks are carried out - ;; Default is false ; serverside_object_permissions = false ;; This allows users with a UserLevel of 200 or more to assume god @@ -188,6 +206,7 @@ ;; server to send mail through. ; emailmodule = DefaultEmailModule + [SMTP] ;; The SMTP server enabled the email module to send email to external ;; destinations. @@ -214,6 +233,7 @@ ;# {SMTP_SERVER_PASSWORD} {[Startup]emailmodule:DefaultEmailModule enabled:true} {SMTP server password} {} ; SMTP_SERVER_PASSWORD = "" + [Network] ;; Configure the remote console user here. This will not actually be used ;; unless you use -console=rest at startup. @@ -247,6 +267,7 @@ ;; " (Mozilla Compatible)" to the text where there are problems with a web server ; user_agent = "OpenSim LSL (Mozilla Compatible)" + [ClientStack.LindenUDP] ;; See OpensSimDefaults.ini for the throttle options. You can copy the ;; relevant sections and override them here. @@ -263,17 +284,18 @@ ;; building's lights to possibly not be rendered. ; DisableFacelights = "false" + [Chat] ;# {whisper_distance} {} {Distance at which a whisper is heard, in meters?} {} 10 - ;; Distance in meters that whispers should travel. Default is 10m + ;; Distance in meters that whispers should travel. ; whisper_distance = 10 ;# {say_distance} {} {Distance at which normal chat is heard, in meters? (SL uses 20 here)} {} 30 - ;; Distance in meters that ordinary chat should travel. Default is 30m + ;; Distance in meters that ordinary chat should travel. ; say_distance = 30 ;# {shout_distance} {Distance at which a shout is heard, in meters?} {} 100 - ;; Distance in meters that shouts should travel. Default is 100m + ;; Distance in meters that shouts should travel. ; shout_distance = 100 @@ -337,13 +359,13 @@ ;# {create_region_enable_voice} {enabled:true} {Enable voice for newly created regions?} {true false} false ;; set this variable to true if you want the create_region XmlRpc ;; call to unconditionally enable voice on all parcels for a newly - ;; created region [default: false] + ;; created region ; create_region_enable_voice = false ;# {create_region_public} {enabled:true} {Make newly created regions public?} {true false} false ;; set this variable to false if you want the create_region XmlRpc ;; call to create all regions as private per default (can be - ;; overridden in the XmlRpc call) [default: true] + ;; overridden in the XmlRpc call) ; create_region_public = false ;# {enabled_methods} {enabled:true} {List of methods to allow, separated by |} {} all @@ -372,15 +394,16 @@ ;; default avatars ; default_appearance = default_appearance.xml + [Wind] ;# {enabled} {} {Enable wind module?} {true false} true - ;; Enables the wind module. Default is true - ;enabled = true + ;; Enables the wind module. + ; enabled = true ;# {wind_update_rate} {enabled:true} {Wind update rate in frames?} {} 150 ;; How often should wind be updated, as a function of world frames. ;; Approximately 50 frames a second - wind_update_rate = 150 + ; wind_update_rate = 150 ;; The Default Wind Plugin to load ; wind_plugin = SimpleRandomWind @@ -396,9 +419,10 @@ ;# {strength} {enabled:true wind_plugin:SimpleRandomWind} {Wind strength?} {} 1.0 ;; This setting is specific to the SimpleRandomWind plugin - ;; Adjusts wind strength. 0.0 = no wind, 1.0 = normal wind. Default is 1.0 + ;; Adjusts wind strength. 0.0 = no wind, 1.0 = normal wind. ; strength = 1.0 + [LightShare] ;# {enable_windlight} {} {Enable LightShare technology?} {true false} false ;; This enables the transmission of Windlight scenes to supporting clients, @@ -406,7 +430,8 @@ ;; It has no ill effect on viewers which do not support server-side ;; windlight settings. ;; Currently we only have support for MySQL databases. - ; enable_windlight = false; + ; enable_windlight = false + [DataSnapshot] ;# {index_sims} {} {Enable data snapshotting (search)?} {true false} false @@ -417,7 +442,6 @@ ;; and you can ignore the rest of these search-related configs. ; index_sims = false - ;# {data_exposure} {index_sims:true} {How much data should be exposed?} {minimum all} minimum ;; The variable data_exposure controls what the regions expose: ;; minimum: exposes only things explicitly marked for search @@ -462,6 +486,7 @@ ;; Money Unit fee to create groups ; PriceGroupCreate = 0 + [XEngine] ;# {Enabled} {} {Enable the XEngine scripting engine?} {true false} true ;; Enable this engine in this OpenSim instance @@ -556,9 +581,9 @@ ;; Default is ./bin/ScriptEngines ; ScriptEnginesPath = "ScriptEngines" + [MRM] ;; Enables the Mini Region Modules Script Engine. - ;; default is false ; Enabled = false ;; Runs MRM in a Security Sandbox @@ -580,6 +605,7 @@ ;; May represent a security risk if you disable this. ; OwnerOnly = true + [FreeSwitchVoice] ;; In order for this to work you need a functioning FreeSWITCH PBX set up. ;; Configuration details at http://opensimulator.org/wiki/Freeswitch_Module @@ -593,6 +619,7 @@ ;; If using a remote module, specify the server URL ; FreeswitchServiceURL = http://my.grid.server:8003/fsapi + [FreeswitchService] ;; !!!!!!!!!!!!!!!!!!!!!!!!!!! ;; !!!!!!STANDALONE ONLY!!!!!! @@ -611,6 +638,7 @@ ; UserName = "freeswitch" ; Password = "password" + [Groups] ;# {Enabled} {} {Enable groups?} {true false} false ;; Enables the groups module @@ -634,7 +662,7 @@ ;# {ServicesConnectorModule} {Module:GroupsModule} {Service connector to use for groups} {XmlRpcGroupsServicesConnector SimianGroupsServicesConnector} XmlRpcGroupsServicesConnector ;; Service connectors to the Groups Service as used in the GroupsModule. Select one depending on ;; whether you're using a Flotsam XmlRpc backend or a SimianGrid backend - ; ServicesConnectorModule = SimianGroupsServicesConnector + ; ServicesConnectorModule = XmlRpcGroupsServicesConnector ;# {GroupsServerURI} {Module:GroupsModule} {Groups Server URI} {} ;; URI for the groups services @@ -654,6 +682,7 @@ ; XmlRpcServiceReadKey = 1234 ; XmlRpcServiceWriteKey = 1234 + [InterestManagement] ;# {UpdatePrioritizationScheme} {} {Update prioritization scheme?} {BestAvatarResponsiveness Time Distance SimpleAngularDistance FrontBack} BestAvatarResponsiveness ;; This section controls how state updates are prioritized for each client @@ -661,24 +690,28 @@ ;; SimpleAngularDistance, FrontBack ; UpdatePrioritizationScheme = BestAvatarResponsiveness + [MediaOnAPrim] ;# {Enabled} {} {Enable Media-on-a-Prim (MOAP)} {true false} true ;; Enable media on a prim facilities ; Enabled = true; + [Architecture] ;# {Include-Architecture} {} {Choose one of the following architectures} {config-include/Standalone.ini config-include/StandaloneHypergrid.ini config-include/Grid.ini config-include/GridHypergrid.ini config-include/SimianGrid.ini config-include/HyperSimianGrid.ini} config-include/Standalone.ini - ;; Choose one of these architecture includes: - ;; Include-Architecture = "config-include/Standalone.ini" - ;; Include-Architecture = "config-include/StandaloneHypergrid.ini" - ;; Include-Architecture = "config-include/Grid.ini" - ;; Include-Architecture = "config-include/GridHypergrid.ini" - ;; Include-Architecture = "config-include/SimianGrid.ini" - ;; Include-Architecture = "config-include/HyperSimianGrid.ini" + ;; Uncomment one of the following includes as required. For instance, to create a standalone OpenSim, + ;; uncomment Include-Architecture = "config-include/Standalone.ini" + ;; + ;; Then you will need to copy and edit the corresponding *Common.example file in config-include/ + ;; that the referenced .ini file goes on to include. + ;; + ;; For instance, if you chose "config-include/Standalone.ini" then you will need to copy + ;; "config-include/StandaloneCommon.ini.example" to "config-include/StandaloneCommon.ini" before + ;; editing it to set the database and backend services that OpenSim will use. + ;; ; Include-Architecture = "config-include/Standalone.ini" - - ;; Then choose - ;; config-include/StandaloneCommon.ini.example (if you're in standlone) OR - ;; config-include/GridCommon.ini.example (if you're connected to a grid) - ;; Copy to your own .ini there (without .example extension) and edit it - ;; to customize your data + ; Include-Architecture = "config-include/StandaloneHypergrid.ini" + ; Include-Architecture = "config-include/Grid.ini" + ; Include-Architecture = "config-include/GridHypergrid.ini" + ; Include-Architecture = "config-include/SimianGrid.ini" + ; Include-Architecture = "config-include/HyperSimianGrid.ini" -- cgit v1.1 From fda393b088e625b5811520af6bd502e2471cd8e7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 21:42:28 +0100 Subject: Add information comment to top of OpenSimDefaults.ini and make file consistent --- bin/OpenSimDefaults.ini | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 96ffb7e..d6eee0e 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1,3 +1,7 @@ +; This file contains defaults for various settings in OpenSimulator. These can be overriden +; by changing the same setting in OpenSim.ini (once OpenSim.ini.example has been copied to OpenSim.ini). + + [Startup] ; Set this to true if you want to log crashes to disk ; this can be useful when submitting bug reports. @@ -287,6 +291,7 @@ ;SMTP_SERVER_LOGIN=foo ;SMTP_SERVER_PASSWORD=bar + [Network] ConsoleUser = "Test" ConsolePass = "secret" @@ -317,6 +322,7 @@ ; " (Mozilla Compatible)" to the text where there are problems with a web server ;user_agent = "OpenSim LSL (Mozilla Compatible)" + [XMLRPC] ; ## ; ## Scripting XMLRPC mapper @@ -330,6 +336,7 @@ ;XmlRpcRouterModule = "XmlRpcRouterModule" ;XmlRpcPort = 20800 + [ClientStack.LindenUDP] ; Set this to true to process incoming packets asynchronously. Networking is ; already separated from packet handling with a queue, so this will only @@ -422,6 +429,7 @@ ; ;DisableFacelights = "false" + [Chat] ; Controls whether the chat module is enabled. Default is true. enabled = true; @@ -680,6 +688,7 @@ ; path to default appearance XML file that specifies the look of the default avatars ;default_appearance = default_appearance.xml + [RestPlugins] ; Change this to true to enable REST Plugins. This must be true if you wish to use ; REST Region or REST Asset and Inventory Plugins @@ -706,11 +715,10 @@ flush-on-error = true -; Uncomment the following for IRC bridge -; experimental, so if it breaks... keep both parts... yada yada +; IRC bridge is experimental, so if it breaks... keep both parts... yada yada ; also, not good error detection when it fails -;[IRC] - ;enabled = true ; you need to set this otherwise it won't connect +[IRC] + enabled = false; you need to set this to true otherwise it won't connect ;server = name.of.irc.server.on.the.net ;; user password - only use this if the server requires one ;password = mypass @@ -767,14 +775,14 @@ ;exclude_list=User 1,User 2,User 3 -;[CMS] - ;enabled = true +[CMS] + enabled = false ;channel = 345 -; Uncomment the following to control the progression of daytime -; in the Sim. The defaults are what is shown below -;[Sun] +; The following settings control the progression of daytime +; in the Sim. The defaults are the same as the commented out settings +[Sun] ; number of wall clock hours for an opensim day. 24.0 would mean realtime ;day_length = 4 ; Year length in days @@ -821,12 +829,13 @@ ; default is 1000 cloud_update_rate = 1000 -[LightShare] +[LightShare] ; This enables the transmission of Windlight scenes to supporting clients, such as the Meta7 viewer. ; It has no ill effect on viewers which do not support server-side windlight settings. ; Currently we only have support for MySQL databases. - enable_windlight = false; + enable_windlight = false + [Trees] ; Enable this to allow the tree module to manage your sim trees, including growing, reproducing and dying @@ -838,7 +847,6 @@ [VectorRender] - ; the font to use for rendering text (default: Arial) ; font_name = "Arial" @@ -1032,6 +1040,7 @@ ;; Path to script assemblies ; ScriptEnginesPath = "ScriptEngines" + [OpenGridProtocol] ;These are the settings for the Open Grid Protocol.. the Agent Domain, Region Domain, you know.. ;On/true or Off/false @@ -1240,11 +1249,11 @@ ChildReprioritizationDistance = 20.0 -[WebStats] ; View region statistics via a web page ; See http://opensimulator.org/wiki/FAQ#Region_Statistics_on_a_Web_Page ; Use a web browser and type in the "Login URI" + "/SStats/" ; For example- http://127.0.0.1:9000/SStats/ +[WebStats] ; enabled=false -- cgit v1.1 From d6948b15c47fd067be6d7cef31caf8e49e9c9afa Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 21:51:17 +0100 Subject: Make it more obvious when it happens that DLL plugin loading fails. Improve exception output on Windows. --- OpenSim/Region/Framework/ModuleLoader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/ModuleLoader.cs b/OpenSim/Region/Framework/ModuleLoader.cs index 23be9c2..14ecd44 100644 --- a/OpenSim/Region/Framework/ModuleLoader.cs +++ b/OpenSim/Region/Framework/ModuleLoader.cs @@ -223,7 +223,8 @@ namespace OpenSim.Region.Framework catch (Exception e) { m_log.ErrorFormat( - "[MODULES]: Could not load types for [{0}]. Exception {1}", pluginAssembly.FullName, e); + "[MODULES]: Could not load types for plugin DLL {0}. Exception {1} {2}", + pluginAssembly.FullName, e.Message, e.StackTrace); // justincc: Right now this is fatal to really get the user's attention throw e; -- cgit v1.1 From 0bd6bc8fba1ed35344218e2aa25e30a3294f2ed1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 21:59:26 +0100 Subject: create "config show" as a region console command synonym for "config get". This is to create greater consistency with all the other show commands. --- OpenSim/Region/Application/OpenSim.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index ec1fb04..39004d4 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -341,10 +341,15 @@ namespace OpenSim m_console.Commands.AddCommand("region", false, "config get", "config get [
] []", - "Show a config option", + "Synonym for config show", + HandleConfig); + + m_console.Commands.AddCommand("region", false, "config show", + "config show [
] []", + "Show config information", "If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine + "If a section is given but not a field, then all fields in that section are printed.", - HandleConfig); + HandleConfig); m_console.Commands.AddCommand("region", false, "config save", "config save ", @@ -593,7 +598,9 @@ namespace OpenSim if (cmdparams.Length > 0) { - switch (cmdparams[0].ToLower()) + string firstParam = cmdparams[0].ToLower(); + + switch (firstParam) { case "set": if (cmdparams.Length < 4) @@ -618,6 +625,7 @@ namespace OpenSim break; case "get": + case "show": if (cmdparams.Length == 1) { foreach (IConfig config in m_config.Source.Configs) @@ -654,8 +662,8 @@ namespace OpenSim } else { - Notice("Syntax: config get [
] []"); - Notice("Example: config get ScriptEngine.DotNetEngine NumberOfScriptThreads"); + Notice("Syntax: config {0} [
] []", firstParam); + Notice("Example: config {0} ScriptEngine.DotNetEngine NumberOfScriptThreads", firstParam); } break; -- cgit v1.1 From 333a2913cfb8b536939b1d9d4b3ac6ea59dd55ca Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 22:02:12 +0100 Subject: slightly tweak OpenSim.ini.example text --- bin/OpenSim.ini.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 390fe09..55723d1 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -12,8 +12,8 @@ ;; OpenSimDefaults.ini. To change a setting, first uncomment it by deleting the initial semicolon (;) ;; and then change the value. This will override the value in OpenSimDefaults.ini ;; -;; If you want to find out what configuration OpenSimulator has used then type "config get" on the -;; region console command line. +;; If you want to find out what configuration OpenSimulator has finished with once all the configuration +;; files are loaded then type "config show" on the region console command line. ;; ;; ;; NOTES FOR DEVELOPERS REGARDING FORMAT OF TIHS FILE -- cgit v1.1 From 464fa45ec90767af13bd8edcc7c67de4ec3db6a7 Mon Sep 17 00:00:00 2001 From: E. Allen Soard Date: Fri, 8 Apr 2011 18:30:20 -0700 Subject: Implimented HTTP_VERIFY_CERT for llHttpRequest --- .../Scripting/HttpRequest/ScriptsHttpRequests.cs | 34 ++++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index d78931a..a37c781 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -29,8 +29,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Security; using System.Text; using System.Threading; +using System.Security.Cryptography.X509Certificates; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; @@ -84,6 +86,7 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { + public class HttpRequestModule : IRegionModule, IHttpRequestModule { private object HttpListLock = new object(); @@ -100,8 +103,23 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public HttpRequestModule() { + ServicePointManager.ServerCertificateValidationCallback +=ValidateServerCertificate; } + public static bool ValidateServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + HttpWebRequest Request = (HttpWebRequest)sender; + + if(Request.Headers.Get("NoVerifyCert") != null) + { + return true; + } + return chain.Build(new X509Certificate2(certificate)); + } #region IHttpRequestModule Members public UUID MakeHttpRequest(string url, string parameters, string body) @@ -141,8 +159,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest break; case (int)HttpRequestConstants.HTTP_VERIFY_CERT: - - // TODO implement me + htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0); break; } } @@ -282,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public string HttpMethod = "GET"; public string HttpMIMEType = "text/plain;charset=utf-8"; public int HttpTimeout; - // public bool HttpVerifyCert = true; // not implemented + public bool HttpVerifyCert = true; // not implemented private Thread httpThread; // Request info @@ -344,6 +361,17 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest Request.Method = HttpMethod; Request.ContentType = HttpMIMEType; + if(!HttpVerifyCert) + { + // Connection Group Name is probably not used so we hijack it to identify + // a desired security exception +// Request.ConnectionGroupName="NoVerify"; + Request.Headers.Add("NoVerifyCert" , "true"); + } +// else +// { +// Request.ConnectionGroupName="Verify"; +// } if (proxyurl != null && proxyurl.Length > 0) { if (proxyexcepts != null && proxyexcepts.Length > 0) -- cgit v1.1 From 3a98fb080a751d21999bb2baa769462426b5d776 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 22:29:08 +0100 Subject: minor: adjust some spacing and indentation --- .../Scripting/HttpRequest/ScriptsHttpRequests.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index a37c781..23e15ef 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -86,7 +86,6 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { - public class HttpRequestModule : IRegionModule, IHttpRequestModule { private object HttpListLock = new object(); @@ -114,10 +113,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { HttpWebRequest Request = (HttpWebRequest)sender; - if(Request.Headers.Get("NoVerifyCert") != null) + if (Request.Headers.Get("NoVerifyCert") != null) { return true; } + return chain.Build(new X509Certificate2(certificate)); } #region IHttpRequestModule Members @@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest * Not sure how important ordering is is here - the next first * one completed in the list is returned, based soley on its list * position, not the order in which the request was started or - * finsihed. I thought about setting up a queue for this, but + * finished. I thought about setting up a queue for this, but * it will need some refactoring and this works 'enough' right now */ @@ -254,8 +254,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest m_scene.RegisterModuleInterface(this); - m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); - m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); + m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); + m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); m_pendingRequests = new Dictionary(); } @@ -363,10 +363,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest if(!HttpVerifyCert) { - // Connection Group Name is probably not used so we hijack it to identify - // a desired security exception -// Request.ConnectionGroupName="NoVerify"; - Request.Headers.Add("NoVerifyCert" , "true"); + // We could hijack Connection Group Name to identify + // a desired security exception. But at the moment we'll use a dummy header instead. +// Request.ConnectionGroupName = "NoVerify"; + Request.Headers.Add("NoVerifyCert", "true"); } // else // { @@ -464,4 +464,4 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest } } } -} +} \ No newline at end of file -- cgit v1.1 From e8ecb2898c55bb97d47e9b1efb7dac98d40609cd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 22:33:24 +0100 Subject: minor: remove some mono compiler warnings --- .../ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index c16a985..aa28fa0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -10289,12 +10289,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID rq = UUID.Random(); - UUID tid = AsyncCommands. - DataserverPlugin.RegisterRequest(m_localID, - m_itemID, rq.ToString()); + AsyncCommands.DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString()); - AsyncCommands. - DataserverPlugin.DataserverReply(rq.ToString(), Name2Username(llKey2Name(id))); + AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), Name2Username(llKey2Name(id))); return rq.ToString(); } @@ -10308,12 +10305,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID rq = UUID.Random(); - UUID tid = AsyncCommands. - DataserverPlugin.RegisterRequest(m_localID, - m_itemID, rq.ToString()); + AsyncCommands.DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString()); - AsyncCommands. - DataserverPlugin.DataserverReply(rq.ToString(), llKey2Name(id)); + AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), llKey2Name(id)); return rq.ToString(); } -- cgit v1.1 From 64dc7e9f141fd0f168ed90c11f932a8bdb077dc7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 22:35:07 +0100 Subject: minor: remove now inaccurate comment --- OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 23e15ef..4c8424d 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -299,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public string HttpMethod = "GET"; public string HttpMIMEType = "text/plain;charset=utf-8"; public int HttpTimeout; - public bool HttpVerifyCert = true; // not implemented + public bool HttpVerifyCert = true; private Thread httpThread; // Request info -- cgit v1.1 From 49d80f5711e1bc1afb6c650038619ade6d9a9e97 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 23:07:56 +0100 Subject: Include code to return more information about the NullReferenceException seen in http://opensimulator.org/mantis/view.php?id=5403 prior to doing something about it. --- OpenSim/Data/MySQL/MySQLGenericTableHandler.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs index 8efe4e9..50b6dbe 100644 --- a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs +++ b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs @@ -39,6 +39,8 @@ namespace OpenSim.Data.MySQL { public class MySQLGenericTableHandler : MySqlFramework where T: class, new() { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + protected Dictionary m_Fields = new Dictionary(); @@ -217,7 +219,6 @@ namespace OpenSim.Data.MySQL { using (MySqlCommand cmd = new MySqlCommand()) { - string query = ""; List names = new List(); List values = new List(); @@ -226,6 +227,16 @@ namespace OpenSim.Data.MySQL { names.Add(fi.Name); values.Add("?" + fi.Name); + + // Temporarily return more information about what field is unexpectedly null for + // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the + // InventoryTransferModule or we may be required to substitute a DBNull here. + if (fi.GetValue(row) == null) + throw new NullReferenceException( + string.Format( + "[MYSQL GENERIC TABLE HANDLER]: Trying to store field {0} for {1} which is unexpectedly null", + fi.Name, row)); + cmd.Parameters.AddWithValue(fi.Name, fi.GetValue(row).ToString()); } @@ -268,4 +279,4 @@ namespace OpenSim.Data.MySQL } } } -} +} \ No newline at end of file -- cgit v1.1 From 621d5b58e1a9bc24aab384a5e9bd6eb881928505 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Apr 2011 23:56:04 +0100 Subject: minor: add a bit more method doc to IInventoryService.GetItem() --- OpenSim/Services/Interfaces/IInventoryService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Services/Interfaces/IInventoryService.cs b/OpenSim/Services/Interfaces/IInventoryService.cs index d19faed..a8bfe47 100644 --- a/OpenSim/Services/Interfaces/IInventoryService.cs +++ b/OpenSim/Services/Interfaces/IInventoryService.cs @@ -169,7 +169,7 @@ namespace OpenSim.Services.Interfaces /// Get an item, given by its UUID ///
/// - /// + /// null if no item was found, otherwise the found item InventoryItemBase GetItem(InventoryItemBase item); /// -- cgit v1.1 From 98d7de22dc44ca1e5971301c02a6a1fe49620889 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Apr 2011 18:31:41 +0100 Subject: Fix (add) ability to rez objects by dragging them out of another prim's inventory. This should happen if the client supplies a task ID with the RezObject call. The rez goes through the same code as llRezObject(), so the same perms are applied. Rotation isn't yet preserved, this should be fixed shortly. --- .../InventoryAccess/InventoryAccessModule.cs | 4 ++ OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 59 ++++++++++++++++++++-- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 9fbfc34..cdee53c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -552,8 +552,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// Rez an object into the scene from the user's inventory /// + /// /// FIXME: It would be really nice if inventory access modules didn't also actually do the work of rezzing /// things to the scene. The caller should be doing that, I think. + /// /// /// /// @@ -570,6 +572,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { +// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); + // Work out position details byte bRayEndIsIntersection = (byte)0; diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 73dd531..4370850 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1955,11 +1955,60 @@ namespace OpenSim.Region.Framework.Scenes UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID) { - IInventoryAccessModule invAccess = RequestModuleInterface(); - if (invAccess != null) - invAccess.RezObject( - remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, - RezSelected, RemoveItem, fromTaskID, false); +// m_log.DebugFormat( +// "[PRIM INVENTORY]: RezObject from {0} for item {1} from task id {2}", +// remoteClient.Name, itemID, fromTaskID); + + if (fromTaskID == UUID.Zero) + { + IInventoryAccessModule invAccess = RequestModuleInterface(); + if (invAccess != null) + invAccess.RezObject( + remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, + RezSelected, RemoveItem, fromTaskID, false); + } + else + { + SceneObjectPart part = GetSceneObjectPart(fromTaskID); + if (part == null) + { + m_log.ErrorFormat( + "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such scene object", + remoteClient.Name, itemID, fromTaskID); + + return; + } + + TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID); + if (item == null) + { + m_log.ErrorFormat( + "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such item", + remoteClient.Name, itemID, fromTaskID); + + return; + } + + // Work out position details + byte bRayEndIsIntersection = (byte)0; + + if (RayEndIsIntersection) + { + bRayEndIsIntersection = (byte)1; + } + else + { + bRayEndIsIntersection = (byte)0; + } + + Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); + Vector3 pos + = GetNewRezLocation( + RayStart, RayEnd, RayTargetID, Quaternion.Identity, + BypassRayCast, bRayEndIsIntersection, true, scale, false); + + RezObject(part, item, pos, Quaternion.Identity, Vector3.Zero, 0); + } } /// -- cgit v1.1 From 095e602c4ac6da315f3f6711e24f034b6c490a02 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 12:36:36 -0700 Subject: First pass at moving object property requests into a queue similar to the entity update queue. The number of property packets can become significant when selecting/deselecting large numbers of objects. This is experimental code. --- OpenSim/Client/MXP/ClientStack/MXPClientView.cs | 4 +- .../Client/VWoHTTP/ClientStack/VWHClientView.cs | 4 +- OpenSim/Framework/IClientAPI.cs | 39 +-- .../Region/ClientStack/LindenUDP/LLClientView.cs | 351 +++++++++++++-------- .../Region/ClientStack/LindenUDP/PriorityQueue.cs | 12 +- .../Region/Examples/SimpleModule/MyNpcCharacter.cs | 12 +- .../Region/Framework/Scenes/SceneObjectGroup.cs | 10 +- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 10 +- .../Server/IRCClientView.cs | 5 +- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 12 +- OpenSim/Tests/Common/Mock/TestClient.cs | 11 +- 11 files changed, 262 insertions(+), 208 deletions(-) diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index d1a0440..a604a2e 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs @@ -1337,12 +1337,12 @@ namespace OpenSim.Client.MXP.ClientStack // Need to translate to MXP somehow } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { //throw new System.NotImplementedException(); } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { //throw new System.NotImplementedException(); } diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs index fc27f01..d8cd0ac 100644 --- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs +++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs @@ -884,12 +884,12 @@ namespace OpenSim.Client.VWoHTTP.ClientStack throw new System.NotImplementedException(); } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { throw new System.NotImplementedException(); } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { throw new System.NotImplementedException(); } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 5bf0b7b..c56a756 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -570,16 +570,30 @@ namespace OpenSim.Framework public float dwell; } - public class EntityUpdate + public class IEntityUpdate { public ISceneEntity Entity; - public PrimUpdateFlags Flags; - public float TimeDilation; + public uint Flags; - public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) + public IEntityUpdate(ISceneEntity entity, uint flags) { Entity = entity; Flags = flags; + } + } + + + public class EntityUpdate : IEntityUpdate + { + // public ISceneEntity Entity; + // public PrimUpdateFlags Flags; + public float TimeDilation; + + public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) + : base(entity,(uint)flags) + { + //Entity = entity; + // Flags = flags; TimeDilation = timedilation; } } @@ -1211,20 +1225,9 @@ namespace OpenSim.Framework /// void SendSimStats(SimStats stats); - void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, - uint Category, - UUID LastOwnerID, string ObjectName, string Description); - - void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, - UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, - string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, - uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice); + void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags); + + void SendObjectPropertiesReply(ISceneEntity Entity); void SendAgentOffline(UUID[] agentIDs); diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 934a2d5..b96343e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -386,6 +386,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_cachedTextureSerial; private PriorityQueue m_entityUpdates; + private PriorityQueue m_entityProps; private Prioritizer m_prioritizer; private bool m_disableFacelights = false; @@ -433,9 +434,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected IAssetService m_assetService; private const bool m_checkPackets = true; - private Timer m_propertiesPacketTimer; - private List m_propertiesBlocks = new List(); - #endregion Class Members #region Properties @@ -511,6 +509,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = scene; m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); + m_entityProps = new PriorityQueue(m_scene.Entities.Count); m_fullUpdateDataBlocksBuilder = new List(); m_killRecord = new HashSet(); // m_attachmentsSent = new HashSet(); @@ -534,9 +533,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpClient.OnQueueEmpty += HandleQueueEmpty; m_udpClient.OnPacketStats += PopulateStats; - m_propertiesPacketTimer = new Timer(100); - m_propertiesPacketTimer.Elapsed += ProcessObjectPropertiesPacket; - m_prioritizer = new Prioritizer(m_scene); RegisterLocalPacketHandlers(); @@ -3636,9 +3632,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); } - private Int32 m_LastQueueFill = 0; - private uint m_maxUpdates = 0; - private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3646,46 +3639,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); + // Check to see if this is a flush if (maxUpdates <= 0) { - m_maxUpdates = Int32.MaxValue; + maxUpdates = Int32.MaxValue; } - else - { - if (m_maxUpdates == 0 || m_LastQueueFill == 0) - { - m_maxUpdates = (uint)maxUpdates; - } - else - { - if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) - m_maxUpdates += 5; - else - m_maxUpdates = m_maxUpdates >> 1; - } - m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); - } - m_LastQueueFill = Util.EnvironmentTickCount(); - + int updatesThisCall = 0; -// -// DEBUGGING CODE... REMOVE -// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates); -// // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race // condition where a kill can be processed before an out-of-date update for the same object. lock (m_killRecord) { float avgTimeDilation = 1.0f; - EntityUpdate update; + IEntityUpdate iupdate; Int32 timeinqueue; // this is just debugging code & can be dropped later - while (updatesThisCall < m_maxUpdates) + while (updatesThisCall < maxUpdates) { lock (m_entityUpdates.SyncRoot) - if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) + if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) break; + + EntityUpdate update = (EntityUpdate)iupdate; + avgTimeDilation += update.TimeDilation; avgTimeDilation *= 0.5f; @@ -3725,7 +3702,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region UpdateFlags to packet type conversion - PrimUpdateFlags updateFlags = update.Flags; + PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; bool canUseCompressed = true; bool canUseImproved = true; @@ -3804,6 +3781,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Block Construction } + #region Packet Sending @@ -3904,12 +3882,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Primitive Packet/Data Sending Methods + // These are used to implement an adaptive backoff in the number + // of updates converted to packets. Since we don't want packets + // to sit in the queue with old data, only convert enough updates + // to packets that can be sent in 200ms. + private Int32 m_LastQueueFill = 0; + private Int32 m_maxUpdates = 0; + void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) { if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) { + if (m_maxUpdates == 0 || m_LastQueueFill == 0) + { + m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; + } + else + { + if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) + m_maxUpdates += 5; + else + m_maxUpdates = m_maxUpdates >> 1; + } + m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); + m_LastQueueFill = Util.EnvironmentTickCount(); + if (m_entityUpdates.Count > 0) - ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback); + ProcessEntityUpdates(m_maxUpdates); + + if (m_entityProps.Count > 0) + ProcessEntityPropertyRequests(m_maxUpdates); } if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) @@ -4023,134 +4025,192 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) - { - ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - // TODO: don't create new blocks if recycling an old packet - - ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - objPropDB.RequestFlags = RequestFlags; - objPropDB.ObjectID = ObjectUUID; - if (OwnerID == GroupID) - objPropDB.OwnerID = UUID.Zero; - else - objPropDB.OwnerID = OwnerID; - objPropDB.GroupID = GroupID; - objPropDB.BaseMask = BaseMask; - objPropDB.OwnerMask = OwnerMask; - objPropDB.GroupMask = GroupMask; - objPropDB.EveryoneMask = EveryoneMask; - objPropDB.NextOwnerMask = NextOwnerMask; +/// ----------------------------------------------------------------- +/// +/// ----------------------------------------------------------------- - // TODO: More properties are needed in SceneObjectPart! - objPropDB.OwnershipCost = OwnershipCost; - objPropDB.SaleType = SaleType; - objPropDB.SalePrice = SalePrice; - objPropDB.Category = Category; - objPropDB.LastOwnerID = LastOwnerID; - objPropDB.Name = Util.StringToBytes256(ObjectName); - objPropDB.Description = Util.StringToBytes256(Description); - objPropFamilyPack.ObjectData = objPropDB; - objPropFamilyPack.Header.Zerocoded = true; - OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task); - } - - public void SendObjectPropertiesReply( - UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + private class ObjectPropertyUpdate : IEntityUpdate { - //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - // TODO: don't create new blocks if recycling an old packet + internal bool SendFamilyProps; + + public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam) + : base(entity,flags) + { + SendFamilyProps = sendfam; + } + } + + public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) + { + uint priority = m_prioritizer.GetUpdatePriority(this, entity); + lock (m_entityProps.SyncRoot) + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true)); + } - ObjectPropertiesPacket.ObjectDataBlock block = - new ObjectPropertiesPacket.ObjectDataBlock(); + public void SendObjectPropertiesReply(ISceneEntity entity) + { + uint priority = m_prioritizer.GetUpdatePriority(this, entity); + lock (m_entityProps.SyncRoot) + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false)); + } - block.ItemID = ItemID; - block.CreationDate = CreationDate; - block.CreatorID = CreatorUUID; - block.FolderID = FolderUUID; - block.FromTaskID = FromTaskUUID; - block.GroupID = GroupUUID; - block.InventorySerial = InventorySerial; + private void ProcessEntityPropertyRequests(int maxUpdates) + { + OpenSim.Framework.Lazy> objectFamilyBlocks = + new OpenSim.Framework.Lazy>(); - block.LastOwnerID = LastOwnerUUID; - // proper.ObjectData[0].LastOwnerID = UUID.Zero; + OpenSim.Framework.Lazy> objectPropertiesBlocks = + new OpenSim.Framework.Lazy>(); - block.ObjectID = ObjectUUID; - if (OwnerUUID == GroupUUID) - block.OwnerID = UUID.Zero; - else - block.OwnerID = OwnerUUID; - block.TouchName = Util.StringToBytes256(TouchTitle); - block.TextureID = TextureID; - block.SitName = Util.StringToBytes256(SitTitle); - block.Name = Util.StringToBytes256(ItemName); - block.Description = Util.StringToBytes256(ItemDescription); - block.OwnerMask = OwnerMask; - block.NextOwnerMask = NextOwnerMask; - block.GroupMask = GroupMask; - block.EveryoneMask = EveryoneMask; - block.BaseMask = BaseMask; - // proper.ObjectData[0].AggregatePerms = 53; - // proper.ObjectData[0].AggregatePermTextures = 0; - // proper.ObjectData[0].AggregatePermTexturesOwner = 0; - block.SaleType = saleType; - block.SalePrice = salePrice; + IEntityUpdate iupdate; + Int32 timeinqueue; // this is just debugging code & can be dropped later - lock (m_propertiesPacketTimer) + int updatesThisCall = 0; + while (updatesThisCall < m_maxUpdates) { - m_propertiesBlocks.Add(block); + lock (m_entityProps.SyncRoot) + if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) + break; - int length = 0; - foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) + ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; + if (update.SendFamilyProps) { - length += b.Length; + if (update.Entity is SceneObjectPart) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); + objectFamilyBlocks.Value.Add(objPropDB); + } } - if (length > 1100) // FIXME: use real MTU + else { - ProcessObjectPropertiesPacket(null, null); - m_propertiesPacketTimer.Stop(); - return; + if (update.Entity is SceneObjectPart) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); + objectPropertiesBlocks.Value.Add(objPropDB); + } } + } + + + if (objectPropertiesBlocks.IsValueCreated) + { + List blocks = objectPropertiesBlocks.Value; - m_propertiesPacketTimer.Stop(); - m_propertiesPacketTimer.Start(); + ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; + for (int i = 0; i < blocks.Count; i++) + packet.ObjectData[i] = blocks[i]; + + packet.Header.Zerocoded = true; + OutPacket(packet, ThrottleOutPacketType.Task, true); } + + + if (objectFamilyBlocks.IsValueCreated) + { + List blocks = objectFamilyBlocks.Value; + + // ObjectPropertiesFamilyPacket objPropFamilyPack = + // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); + // + // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count]; + // for (int i = 0; i < blocks.Count; i++) + // objPropFamilyPack.ObjectData[i] = blocks[i]; + // + // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true); + + // one packet per object block... uggh... + for (int i = 0; i < blocks.Count; i++) + { + ObjectPropertiesFamilyPacket packet = + (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - //proper.Header.Zerocoded = true; - //OutPacket(proper, ThrottleOutPacketType.Task); + packet.ObjectData = blocks[i]; + packet.Header.Zerocoded = true; + OutPacket(packet, ThrottleOutPacketType.Task); + } + + } + } - private void ProcessObjectPropertiesPacket(Object sender, ElapsedEventArgs e) + private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) { - ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - lock (m_propertiesPacketTimer) - { - m_propertiesPacketTimer.Stop(); + block.RequestFlags = requestFlags; + block.ObjectID = sop.UUID; + if (sop.OwnerID == sop.GroupID) + block.OwnerID = UUID.Zero; + else + block.OwnerID = sop.OwnerID; + block.GroupID = sop.GroupID; + block.BaseMask = sop.BaseMask; + block.OwnerMask = sop.OwnerMask; + block.GroupMask = sop.GroupMask; + block.EveryoneMask = sop.EveryoneMask; + block.NextOwnerMask = sop.NextOwnerMask; - proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; + // TODO: More properties are needed in SceneObjectPart! + block.OwnershipCost = sop.OwnershipCost; + block.SaleType = sop.ObjectSaleType; + block.SalePrice = sop.SalePrice; + block.Category = sop.Category; + block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right? + block.Name = Util.StringToBytes256(sop.Name); + block.Description = Util.StringToBytes256(sop.Description); - int index = 0; + return block; + } - foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) - { - proper.ObjectData[index++] = b; - } + private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) + { + //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + // TODO: don't create new blocks if recycling an old packet - m_propertiesBlocks.Clear(); - } + ObjectPropertiesPacket.ObjectDataBlock block = + new ObjectPropertiesPacket.ObjectDataBlock(); + + block.ObjectID = sop.UUID; + block.Name = Util.StringToBytes256(sop.Name); + block.Description = Util.StringToBytes256(sop.Description); - proper.Header.Zerocoded = true; - OutPacket(proper, ThrottleOutPacketType.Task); + block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds + block.CreatorID = sop.CreatorID; + block.GroupID = sop.GroupID; + block.LastOwnerID = sop.LastOwnerID; + if (sop.OwnerID == sop.GroupID) + block.OwnerID = UUID.Zero; + else + block.OwnerID = sop.OwnerID; + + block.ItemID = sop.FromUserInventoryItemID; + block.FolderID = UUID.Zero; // sop.FromFolderID ?? + block.FromTaskID = UUID.Zero; // ??? + block.InventorySerial = (short)sop.InventorySerial; + + SceneObjectPart root = sop.ParentGroup.RootPart; + + block.TouchName = Util.StringToBytes256(root.TouchName); + block.TextureID = new byte[0]; // TextureID ??? + block.SitName = Util.StringToBytes256(root.SitName); + block.OwnerMask = root.OwnerMask; + block.NextOwnerMask = root.NextOwnerMask; + block.GroupMask = root.GroupMask; + block.EveryoneMask = root.EveryoneMask; + block.BaseMask = root.BaseMask; + block.SaleType = root.ObjectSaleType; + block.SalePrice = root.SalePrice; + + return block; } +/// ----------------------------------------------------------------- +/// +/// ----------------------------------------------------------------- + #region Estate Data Sending Methods private static bool convertParamStringToBool(byte[] field) @@ -4482,6 +4542,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendForceClientSelectObjects(List ObjectIDs) { + m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); + bool firstCall = true; const int MAX_OBJECTS_PER_PACKET = 251; ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); @@ -11374,6 +11436,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); } + if (throttlePacketType == ThrottleOutPacketType.Task) + { + System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); // get call stack + System.Diagnostics.StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + + string stack = ""; + for (int count = 1; count < stackFrames.Length; count++) + { + stack += (stack == "" ? "" : ",") + stackFrames[count].GetMethod().Name; + if (count > 5) break; + } + + // m_log.WarnFormat("[BADGUY] {0}", stack); + } + m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 364ce4b..6521a00 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -78,7 +78,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public bool Enqueue(uint pqueue, EntityUpdate value) + public bool Enqueue(uint pqueue, IEntityUpdate value) { LookupItem lookup; @@ -99,7 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } - internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) + internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) { for (int i = 0; i < m_numberOfQueues; ++i) { @@ -122,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } timeinqueue = 0; - value = default(EntityUpdate); + value = default(IEntityUpdate); return false; } @@ -175,8 +175,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region MinHeapItem private struct MinHeapItem : IComparable { - private EntityUpdate value; - internal EntityUpdate Value { + private IEntityUpdate value; + internal IEntityUpdate Value { get { return this.value; } @@ -212,7 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP this.pqueue = pqueue; } - internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) + internal MinHeapItem(uint pqueue, UInt64 entryorder, IEntityUpdate value) { this.entrytime = Util.EnvironmentTickCount(); this.entryorder = entryorder; diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index d939329..89e9e20 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -702,18 +702,12 @@ namespace OpenSim.Region.Examples.SimpleModule { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { + } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index ca7d9d9..30563d4 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1765,10 +1765,12 @@ namespace OpenSim.Region.Framework.Scenes /// public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) { - remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, - RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, - RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, - RootPart.CreatorID, RootPart.Name, RootPart.Description); + remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); + +// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, +// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, +// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, +// RootPart.CreatorID, RootPart.Name, RootPart.Description); } public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4d5eedf..3d2eacd 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2055,15 +2055,7 @@ namespace OpenSim.Region.Framework.Scenes public void GetProperties(IClientAPI client) { - //Viewer wants date in microseconds so multiply it by 1,000,000. - client.SendObjectPropertiesReply( - m_fromUserInventoryItemID, (ulong)_creationDate*(ulong)1e6, _creatorID, UUID.Zero, UUID.Zero, - _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID, - ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description, - ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask, - ParentGroup.RootPart._baseMask, - ParentGroup.RootPart.ObjectSaleType, - ParentGroup.RootPart.SalePrice); + client.SendObjectPropertiesReply(this); } public UUID GetRootPartUUID() diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 821cd4b..4b6e52e 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1332,14 +1332,13 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { - } public void SendAgentOffline(UUID[] agentIDs) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 96760a2..2504e30 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -786,18 +786,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { + } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index d1dc17f..dca5626 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -816,18 +816,11 @@ namespace OpenSim.Tests.Common.Mock { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } -- cgit v1.1 From 3ba5eeb6c3b7c6381ca1e0ed87bce44049f96e37 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Apr 2011 22:15:40 +0100 Subject: Allow a null rotation to be passed in to RezObject so that we can control whether to use the serialized rotation or not. Not used yet. --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 4370850..87b4cb8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -2016,14 +2016,14 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - /// - /// - /// + /// The position of the rezzed object. + /// The rotation of the rezzed object. If null, then the rotation stored with the object + /// will be used if it exists. + /// The velocity of the rezzed object. /// /// The SceneObjectGroup rezzed or null if rez was unsuccessful public virtual SceneObjectGroup RezObject( - SceneObjectPart sourcePart, TaskInventoryItem item, - Vector3 pos, Quaternion rot, Vector3 vel, int param) + SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param) { if (null == item) return null; @@ -2041,8 +2041,14 @@ namespace OpenSim.Region.Framework.Scenes if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) sourcePart.Inventory.RemoveInventoryItem(item.ItemID); } - - AddNewSceneObject(group, true, pos, rot, vel); + + AddNewSceneObject(group, true); + + group.AbsolutePosition = pos; + group.Velocity = vel; + + if (rot != null) + group.UpdateGroupRotationR((Quaternion)rot); // We can only call this after adding the scene object, since the scene object references the scene // to find out if scripts should be activated at all. -- cgit v1.1 From 8e0d2cc43b63046b0dd6b9a3a7dafd70a70362d0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Apr 2011 22:21:46 +0100 Subject: If an object is rezzed directly from a prim inventory then give it the rotation it was stored with. --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 87b4cb8..254879b 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -2007,7 +2007,7 @@ namespace OpenSim.Region.Framework.Scenes RayStart, RayEnd, RayTargetID, Quaternion.Identity, BypassRayCast, bRayEndIsIntersection, true, scale, false); - RezObject(part, item, pos, Quaternion.Identity, Vector3.Zero, 0); + RezObject(part, item, pos, null, Vector3.Zero, 0); } } -- cgit v1.1 From b0889ed92a3c7d152f9b05aec1ce00dfc010e34e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Apr 2011 22:30:43 +0100 Subject: refactor: simplify bRayEndIsIntersection boolean set from RayEndIsIntersection byte --- .../Framework/InventoryAccess/InventoryAccessModule.cs | 15 +-------------- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 13 +------------ 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index cdee53c..73b0a35 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -574,21 +574,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { // m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); - // Work out position details - byte bRayEndIsIntersection = (byte)0; - - if (RayEndIsIntersection) - { - bRayEndIsIntersection = (byte)1; - } - else - { - bRayEndIsIntersection = (byte)0; - } - + byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); - - Vector3 pos = m_Scene.GetNewRezLocation( RayStart, RayEnd, RayTargetID, Quaternion.Identity, BypassRayCast, bRayEndIsIntersection, true, scale, false); diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 254879b..0f85925 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1989,18 +1989,7 @@ namespace OpenSim.Region.Framework.Scenes return; } - // Work out position details - byte bRayEndIsIntersection = (byte)0; - - if (RayEndIsIntersection) - { - bRayEndIsIntersection = (byte)1; - } - else - { - bRayEndIsIntersection = (byte)0; - } - + byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); Vector3 pos = GetNewRezLocation( -- cgit v1.1 From da4a9653a27cbb1ecc779774a3d8715afb079086 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Apr 2011 22:33:06 +0100 Subject: minor: remove some mono compiler warnings --- OpenSim/Data/Null/NullEstateData.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Data/Null/NullEstateData.cs b/OpenSim/Data/Null/NullEstateData.cs index 0cebff5..8db8064 100755 --- a/OpenSim/Data/Null/NullEstateData.cs +++ b/OpenSim/Data/Null/NullEstateData.cs @@ -38,9 +38,9 @@ namespace OpenSim.Data.Null { public class NullEstateStore : IEstateDataStore { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private string m_connectionString; +// private string m_connectionString; protected virtual Assembly Assembly { @@ -58,7 +58,7 @@ namespace OpenSim.Data.Null public void Initialise(string connectionString) { - m_connectionString = connectionString; +// m_connectionString = connectionString; } private string[] FieldList -- cgit v1.1 From 7fa085b3fa8eacbfec4b9f8969bcbcc210ee50f0 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 14:40:57 -0700 Subject: fixed a couple bugs with the property queues --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 38 +++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index b96343e..4db5b22 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4091,9 +4091,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectPropertiesBlocks.Value.Add(objPropDB); } } + + updatesThisCall++; } + Int32 ppcnt = 0; + Int32 pbcnt = 0; + if (objectPropertiesBlocks.IsValueCreated) { List blocks = objectPropertiesBlocks.Value; @@ -4105,9 +4110,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Header.Zerocoded = true; OutPacket(packet, ThrottleOutPacketType.Task, true); + + pbcnt += blocks.Count; + ppcnt++; } + Int32 fpcnt = 0; + Int32 fbcnt = 0; + if (objectFamilyBlocks.IsValueCreated) { List blocks = objectFamilyBlocks.Value; @@ -4130,10 +4141,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.ObjectData = blocks[i]; packet.Header.Zerocoded = true; OutPacket(packet, ThrottleOutPacketType.Task); + + fpcnt++; + fbcnt++; } } + m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); + m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); } private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) @@ -11401,6 +11417,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, throttlePacketType, true); } +/// + Dictionary pktsrc = new Dictionary(); + uint pktcnt = 0; +/// + /// /// This is the starting point for sending a simulator packet out to the client /// @@ -11448,7 +11469,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (count > 5) break; } - // m_log.WarnFormat("[BADGUY] {0}", stack); + lock(pktsrc) + { + if (! pktsrc.ContainsKey(stack)) + pktsrc.Add(stack,0); + pktsrc[stack]++; + + if (++pktcnt > 500) + { + pktcnt = 0; + m_log.WarnFormat("[PACKETCOUNTS] START"); + foreach (KeyValuePair pkt in pktsrc) + m_log.WarnFormat("[PACKETCOUNTS] {0,8}, {1}", pkt.Value, pkt.Key); + pktsrc.Clear(); + m_log.WarnFormat("[PACKETCOUNTS] END"); + } + } } m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); -- cgit v1.1 From bed463666cdc023bab8db2b725fb85736d2067df Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Apr 2011 23:16:43 +0100 Subject: minor typo correction. thanks Ai Austin. --- bin/OpenSim.ini.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 55723d1..823daa0 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -16,7 +16,7 @@ ;; files are loaded then type "config show" on the region console command line. ;; ;; -;; NOTES FOR DEVELOPERS REGARDING FORMAT OF TIHS FILE +;; NOTES FOR DEVELOPERS REGARDING THE FORMAT OF THIS FILE ;; ;; All leading white space is ignored, but preserved. ;; -- cgit v1.1 From 424995e1384178462799469e0200615308035460 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Apr 2011 23:22:21 +0100 Subject: Move example HttpProxy setting to OpenSim.ini.example and tidy --- bin/OpenSim.ini.example | 8 ++++++++ bin/OpenSimDefaults.ini | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 823daa0..c05c3de 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -201,6 +201,14 @@ ;; If not generating maptiles, use this static texture asset ID ; MaptileStaticUUID = "00000000-0000-0000-0000-000000000000" + ;; Http proxy setting for llHTTPRequest and dynamic texture loading, if required + ; HttpProxy = "http://proxy.com:8080" + + ;; If you're using HttpProxy, then you can set HttpProxyExceptions to a list of regular expressions for URLs that you don't want to go through the proxy + ;; For example, servers inside your firewall. + ;; Separate patterns with a ';' + ; HttpProxyExceptions = ".mydomain.com;localhost" + ;# {emailmodule} {} {Provide llEmail and llGetNextEmail functionality? (requires SMTP server)} {true false} false ;; The email module requires some configuration. It needs an SMTP ;; server to send mail through. diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index d6eee0e..f857b8d 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -14,15 +14,6 @@ ; Place to create a PID file ; PIDFile = "/tmp/my.pid" - ; Http proxy support for llHTTPRequest and dynamic texture loading - ; Set HttpProxy to the URL for your proxy server if you would like - ; to proxy llHTTPRequests through a firewall - ; HttpProxy = "http://proxy.com" - ; Set HttpProxyExceptions to a list of regular expressions for - ; URLs that you don't want going through the proxy such as servers - ; inside your firewall, separate patterns with a ';' - ; HttpProxyExceptions = ".mydomain.com;localhost" - startup_console_commands_file = "startup_commands.txt" shutdown_console_commands_file = "shutdown_commands.txt" -- cgit v1.1 From 80ba3de90240d190bad1bd15ff89dfdb390c5e24 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 15:40:57 -0700 Subject: Fixed the update of items in the priority queue to enable both types of property updates to be specified. Not sure if one form of property update should supercede another. But for now the old OpenSim behavior is preserved by sending both. --- OpenSim/Framework/IClientAPI.cs | 5 +++++ .../Region/ClientStack/LindenUDP/LLClientView.cs | 21 +++++++++++++++------ .../Region/ClientStack/LindenUDP/PriorityQueue.cs | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index c56a756..f573c32 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -575,6 +575,11 @@ namespace OpenSim.Framework public ISceneEntity Entity; public uint Flags; + public virtual void Update(IEntityUpdate update) + { + this.Flags |= update.Flags; + } + public IEntityUpdate(ISceneEntity entity, uint flags) { Entity = entity; diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 4db5b22..92a76ac 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4032,26 +4032,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP private class ObjectPropertyUpdate : IEntityUpdate { internal bool SendFamilyProps; + internal bool SendObjectProps; - public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam) + public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) : base(entity,flags) { SendFamilyProps = sendfam; + SendObjectProps = sendobj; + } + public void Update(ObjectPropertyUpdate update) + { + SendFamilyProps = SendFamilyProps || update.SendFamilyProps; + SendObjectProps = SendObjectProps || update.SendObjectProps; + Flags |= update.Flags; } } public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) { - uint priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); } public void SendObjectPropertiesReply(ISceneEntity entity) { - uint priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); } private void ProcessEntityPropertyRequests(int maxUpdates) @@ -4082,7 +4090,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectFamilyBlocks.Value.Add(objPropDB); } } - else + + if (update.SendObjectProps) { if (update.Entity is SceneObjectPart) { diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 6521a00..b62ec07 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_lookupTable.TryGetValue(localid, out lookup)) { entry = lookup.Heap[lookup.Handle].EntryOrder; - value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; + value.Update(lookup.Heap[lookup.Handle].Value); lookup.Heap.Remove(lookup.Handle); } -- cgit v1.1 From 317617cfda5356e9d375d00c93cd0d23a489107e Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 15:55:21 -0700 Subject: remove packet monitoring debugging code --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 118 +-------------------- 1 file changed, 2 insertions(+), 116 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 92a76ac..cf04f0d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -300,77 +300,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Used to adjust Sun Orbit values so Linden based viewers properly position sun private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; - // First log file or time has expired, start writing to a new log file -// -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// THIS IS DEBUGGING CODE & SHOULD BE REMOVED -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- - public class QueueLogger - { - public Int32 start = 0; - public StreamWriter Log = null; - private Dictionary m_idMap = new Dictionary(); - - public QueueLogger() - { - DateTime now = DateTime.Now; - String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); - Log = new StreamWriter(fname); - - start = Util.EnvironmentTickCount(); - } - - public int LookupID(UUID uuid) - { - int localid; - if (! m_idMap.TryGetValue(uuid,out localid)) - { - localid = m_idMap.Count + 1; - m_idMap[uuid] = localid; - } - - return localid; - } - } - - public static QueueLogger QueueLog = null; - - // ----------------------------------------------------------------- - public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - int aid = QueueLog.LookupID(avatar); - QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); - } - } - - // ----------------------------------------------------------------- - public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); - } - } -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients @@ -4025,10 +3954,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } -/// ----------------------------------------------------------------- -/// -/// ----------------------------------------------------------------- - private class ObjectPropertyUpdate : IEntityUpdate { internal bool SendFamilyProps; @@ -4157,8 +4082,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } - m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); - m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); + // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); + // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); } private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) @@ -4232,10 +4157,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return block; } -/// ----------------------------------------------------------------- -/// -/// ----------------------------------------------------------------- - #region Estate Data Sending Methods private static bool convertParamStringToBool(byte[] field) @@ -11426,11 +11347,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, throttlePacketType, true); } -/// - Dictionary pktsrc = new Dictionary(); - uint pktcnt = 0; -/// - /// /// This is the starting point for sending a simulator packet out to the client /// @@ -11465,36 +11381,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (logPacket) m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); } - - if (throttlePacketType == ThrottleOutPacketType.Task) - { - System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); // get call stack - System.Diagnostics.StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) - - string stack = ""; - for (int count = 1; count < stackFrames.Length; count++) - { - stack += (stack == "" ? "" : ",") + stackFrames[count].GetMethod().Name; - if (count > 5) break; - } - - lock(pktsrc) - { - if (! pktsrc.ContainsKey(stack)) - pktsrc.Add(stack,0); - pktsrc[stack]++; - - if (++pktcnt > 500) - { - pktcnt = 0; - m_log.WarnFormat("[PACKETCOUNTS] START"); - foreach (KeyValuePair pkt in pktsrc) - m_log.WarnFormat("[PACKETCOUNTS] {0,8}, {1}", pkt.Value, pkt.Key); - pktsrc.Clear(); - m_log.WarnFormat("[PACKETCOUNTS] END"); - } - } - } m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); } -- cgit v1.1 From 2f436875899f432a88f432ab86a6858b3a4cc373 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 11 Apr 2011 09:06:28 -0700 Subject: New tokenbucket algorithm. This one provides fair sharing of the queues when client and simulator throttles are set. This algorithm also uses pre-defined burst rate of 150% of the sustained rate for each of the throttles. Removed the "state" queue. The state queue is not a Linden queue and appeared to be used just to get kill packets sent. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 6 +- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 96 ++++--- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 2 +- .../Region/ClientStack/LindenUDP/TokenBucket.cs | 300 ++++++++++++++------- 4 files changed, 259 insertions(+), 145 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 8de31d7..934a2d5 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -1610,7 +1610,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - OutPacket(kill, ThrottleOutPacketType.State); + // OutPacket(kill, ThrottleOutPacketType.State); + OutPacket(kill, ThrottleOutPacketType.Task); } } @@ -2440,7 +2441,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Effect = effectBlocks; - OutPacket(packet, ThrottleOutPacketType.State); + // OutPacket(packet, ThrottleOutPacketType.State); + OutPacket(packet, ThrottleOutPacketType.Task); } public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 9a8bfd3..5a69851 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -135,7 +135,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_nextOnQueueEmpty = 1; /// Throttle bucket for this agent's connection - private readonly TokenBucket m_throttle; + private readonly TokenBucket m_throttleClient; + /// Throttle bucket for this agent's connection + private readonly TokenBucket m_throttleCategory; /// Throttle buckets for each packet category private readonly TokenBucket[] m_throttleCategories; /// Outgoing queues for throttled packets @@ -174,7 +176,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_maxRTO = maxRTO; // Create a token bucket throttle for this client that has the scene token bucket as a parent - m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); + m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); + // Create a token bucket throttle for the total categary with the client bucket as a throttle + m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); // Create an array of token buckets for this clients different throttle categories m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; @@ -185,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Initialize the packet outboxes, where packets sit while they are waiting for tokens m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue(); // Initialize the token buckets that control the throttling for each category - m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); + m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type)); } // Default the retransmission timeout to three seconds @@ -206,6 +210,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_packetOutboxes[i].Clear(); m_nextPackets[i] = null; } + + // pull the throttle out of the scene throttle + m_throttleClient.Parent.UnregisterRequest(m_throttleClient); OnPacketStats = null; OnQueueEmpty = null; } @@ -216,6 +223,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Information about the client connection public ClientInfo GetClientInfo() { +/// + TokenBucket tb; + + tb = m_throttleClient.Parent; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT"); + + tb = m_throttleClient; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT"); + + tb = m_throttleCategory; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY"); + + for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) + { + tb = m_throttleCategories[i]; + m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET"); + } + +/// + // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists // of pending and needed ACKs for every client every time some method wants information about // this connection is a recipe for poor performance @@ -223,13 +250,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP info.pendingAcks = new Dictionary(); info.needAck = new Dictionary(); - info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; - info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; - info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; - info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; - info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; - info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; - info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; + info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; + info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; + info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; + info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; + // info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; + info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + info.taskThrottle + info.assetThrottle + info.textureThrottle; @@ -317,8 +345,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); // State is a subcategory of task that we allocate a percentage to - int state = (int)((float)task * STATE_TASK_PERCENTAGE); - task -= state; + int state = 0; + // int state = (int)((float)task * STATE_TASK_PERCENTAGE); + // task -= state; // Make sure none of the throttles are set below our packet MTU, // otherwise a throttle could become permanently clogged @@ -339,40 +368,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Update the token buckets with new throttle values TokenBucket bucket; - bucket = m_throttle; - bucket.MaxBurst = total; + bucket = m_throttleCategory; + bucket.RequestedDripRate = total; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; - bucket.DripRate = resend; - bucket.MaxBurst = resend; + bucket.RequestedDripRate = resend; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; - bucket.DripRate = land; - bucket.MaxBurst = land; + bucket.RequestedDripRate = land; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; - bucket.DripRate = wind; - bucket.MaxBurst = wind; + bucket.RequestedDripRate = wind; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; - bucket.DripRate = cloud; - bucket.MaxBurst = cloud; + bucket.RequestedDripRate = cloud; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; - bucket.DripRate = asset; - bucket.MaxBurst = asset; + bucket.RequestedDripRate = asset; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; - bucket.DripRate = task + state; - bucket.MaxBurst = task + state; + bucket.RequestedDripRate = task; bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; - bucket.DripRate = state; - bucket.MaxBurst = state; + bucket.RequestedDripRate = state; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; - bucket.DripRate = texture; - bucket.MaxBurst = texture; + bucket.RequestedDripRate = texture; // Reset the packed throttles cached data m_packedThrottles = null; @@ -387,14 +408,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP data = new byte[7 * 4]; int i = 0; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + - m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4; m_packedThrottles = data; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 583214c..d08b25f 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -228,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } #endregion BinaryStats - m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); + m_throttle = new TokenBucket(null, sceneThrottleBps); ThrottleRates = new ThrottleRates(configSource); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index 0a8331f..e4d59ff 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs @@ -26,6 +26,10 @@ */ using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using log4net; namespace OpenSim.Region.ClientStack.LindenUDP { @@ -35,89 +39,126 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public class TokenBucket { - /// Parent bucket to this bucket, or null if this is a root - /// bucket - TokenBucket parent; - /// Size of the bucket in bytes. If zero, the bucket has - /// infinite capacity - int maxBurst; - /// Rate that the bucket fills, in bytes per millisecond. If - /// zero, the bucket always remains full - int tokensPerMS; - /// Number of tokens currently in the bucket - int content; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static Int32 m_counter = 0; + + private Int32 m_identifier; + + /// + /// Number of ticks (ms) per quantum, drip rate and max burst + /// are defined over this interval. + /// + private const Int32 m_ticksPerQuantum = 1000; + + /// + /// This is the number of quantums worth of packets that can + /// be accommodated during a burst + /// + private const Double m_quantumsPerBurst = 1.5; + + /// + /// + private const Int32 m_minimumDripRate = 1400; + /// Time of the last drip, in system ticks - int lastDrip; + private Int32 m_lastDrip; + + /// + /// The number of bytes that can be sent at this moment. This is the + /// current number of tokens in the bucket + /// + private Int64 m_tokenCount; - #region Properties + /// + /// Map of children buckets and their requested maximum burst rate + /// + private Dictionary m_children = new Dictionary(); + +#region Properties /// /// The parent bucket of this bucket, or null if this bucket has no /// parent. The parent bucket will limit the aggregate bandwidth of all /// of its children buckets /// + private TokenBucket m_parent; public TokenBucket Parent { - get { return parent; } + get { return m_parent; } + set { m_parent = value; } } /// /// Maximum burst rate in bytes per second. This is the maximum number - /// of tokens that can accumulate in the bucket at any one time + /// of tokens that can accumulate in the bucket at any one time. This + /// also sets the total request for leaf nodes /// - public int MaxBurst + private Int64 m_burstRate; + public Int64 RequestedBurstRate { - get { return maxBurst; } - set { maxBurst = (value >= 0 ? value : 0); } + get { return m_burstRate; } + set { m_burstRate = (value < 0 ? 0 : value); } } + public Int64 BurstRate + { + get { + double rate = RequestedBurstRate * BurstRateModifier(); + if (rate < m_minimumDripRate * m_quantumsPerBurst) + rate = m_minimumDripRate * m_quantumsPerBurst; + + return (Int64) rate; + } + } + /// /// The speed limit of this bucket in bytes per second. This is the - /// number of tokens that are added to the bucket per second + /// number of tokens that are added to the bucket per quantum /// /// Tokens are added to the bucket any time /// is called, at the granularity of /// the system tick interval (typically around 15-22ms) - public int DripRate + private Int64 m_dripRate; + public Int64 RequestedDripRate { - get { return tokensPerMS * 1000; } - set - { - if (value == 0) - tokensPerMS = 0; - else - { - int bpms = (int)((float)value / 1000.0f); - - if (bpms <= 0) - tokensPerMS = 1; // 1 byte/ms is the minimum granularity - else - tokensPerMS = bpms; - } + get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } + set { + m_dripRate = (value < 0 ? 0 : value); + m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); + m_totalDripRequest = m_dripRate; + if (m_parent != null) + m_parent.RegisterRequest(this,m_dripRate); } } - /// - /// The speed limit of this bucket in bytes per millisecond - /// - public int DripPerMS + public Int64 DripRate { - get { return tokensPerMS; } + get { + if (m_parent == null) + return Math.Min(RequestedDripRate,TotalDripRequest); + + double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); + if (rate < m_minimumDripRate) + rate = m_minimumDripRate; + + return (Int64)rate; + } } /// - /// The number of bytes that can be sent at this moment. This is the - /// current number of tokens in the bucket - /// If this bucket has a parent bucket that does not have - /// enough tokens for a request, will - /// return false regardless of the content of this bucket + /// The current total of the requested maximum burst rates of + /// this bucket's children buckets. /// - public int Content - { - get { return content; } - } + private Int64 m_totalDripRequest; + public Int64 TotalDripRequest + { + get { return m_totalDripRequest; } + set { m_totalDripRequest = value; } + } + +#endregion Properties - #endregion Properties +#region Constructor /// /// Default constructor @@ -128,56 +169,115 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// zero if this bucket has no maximum capacity /// Rate that the bucket fills, in bytes per /// second. If zero, the bucket always remains full - public TokenBucket(TokenBucket parent, int maxBurst, int dripRate) + public TokenBucket(TokenBucket parent, Int64 dripRate) { - this.parent = parent; - MaxBurst = maxBurst; - DripRate = dripRate; - lastDrip = Environment.TickCount & Int32.MaxValue; + m_identifier = m_counter++; + + Parent = parent; + RequestedDripRate = dripRate; + // TotalDripRequest = dripRate; // this will be overwritten when a child node registers + // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); + m_lastDrip = Environment.TickCount & Int32.MaxValue; } +#endregion Constructor + /// - /// Remove a given number of tokens from the bucket + /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning + /// no modification if the requested bandwidth is less than the + /// max burst bandwidth all the way to the root of the throttle + /// hierarchy. However, if any of the parents is over-booked, then + /// the modifier will be less than 1. /// - /// Number of tokens to remove from the bucket - /// True if the requested number of tokens were removed from - /// the bucket, otherwise false - public bool RemoveTokens(int amount) + private double DripRateModifier() + { + Int64 driprate = DripRate; + return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; + } + + /// + /// + private double BurstRateModifier() + { + // for now... burst rate is always m_quantumsPerBurst (constant) + // larger than drip rate so the ratio of burst requests is the + // same as the drip ratio + return DripRateModifier(); + } + + /// + /// Register drip rate requested by a child of this throttle. Pass the + /// changes up the hierarchy. + /// + public void RegisterRequest(TokenBucket child, Int64 request) { - bool dummy; - return RemoveTokens(amount, out dummy); + m_children[child] = request; + // m_totalDripRequest = m_children.Values.Sum(); + + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; + + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); } /// + /// Remove the rate requested by a child of this throttle. Pass the + /// changes up the hierarchy. + /// + public void UnregisterRequest(TokenBucket child) + { + m_children.Remove(child); + // m_totalDripRequest = m_children.Values.Sum(); + + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; + + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); + } + + /// /// Remove a given number of tokens from the bucket /// /// Number of tokens to remove from the bucket - /// True if tokens were added to the bucket - /// during this call, otherwise false /// True if the requested number of tokens were removed from /// the bucket, otherwise false - public bool RemoveTokens(int amount, out bool dripSucceeded) + public bool RemoveTokens(Int64 amount) { - if (maxBurst == 0) + // Deposit tokens for this interval + Drip(); + + // If we have enough tokens then remove them and return + if (m_tokenCount - amount >= 0) { - dripSucceeded = true; - return true; + if (m_parent == null || m_parent.RemoveTokens(amount)) + { + m_tokenCount -= amount; + return true; + } } - dripSucceeded = Drip(); + return false; + } - if (content - amount >= 0) - { - if (parent != null && !parent.RemoveTokens(amount)) - return false; + /// + /// Deposit tokens into the bucket from a child bucket that did + /// not use all of its available tokens + /// + private void Deposit(Int64 count) + { + m_tokenCount += count; - content -= amount; - return true; - } - else - { - return false; - } + // Deposit the overflow in the parent bucket, this is how we share + // unused bandwidth + Int64 burstrate = BurstRate; + if (m_tokenCount > burstrate) + m_tokenCount = burstrate; } /// @@ -186,37 +286,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// call to Drip /// /// True if tokens were added to the bucket, otherwise false - public bool Drip() + private void Drip() { - if (tokensPerMS == 0) + // This should never happen... means we are a leaf node and were created + // with no drip rate... + if (DripRate == 0) { - content = maxBurst; - return true; + m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0"); + return; } - else - { - int now = Environment.TickCount & Int32.MaxValue; - int deltaMS = now - lastDrip; - - if (deltaMS <= 0) - { - if (deltaMS < 0) - lastDrip = now; - return false; - } + + // Determine the interval over which we are adding tokens, never add + // more than a single quantum of tokens + Int32 now = Environment.TickCount & Int32.MaxValue; + Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum); - int dripAmount = deltaMS * tokensPerMS; + m_lastDrip = now; - content = Math.Min(content + dripAmount, maxBurst); - lastDrip = now; + // This can be 0 in the very unusual case that the timer wrapped + // It can be 0 if we try add tokens at a sub-tick rate + if (deltaMS <= 0) + return; - if (dripAmount < 0 || content < 0) - // sim has been idle for too long, integer has overflown - // previous calculation is meaningless, let's put it at correct max - content = maxBurst; - - return true; - } + Deposit(deltaMS * DripRate / m_ticksPerQuantum); } } } -- cgit v1.1 From 69d014e1dcb0e05a4ec927a5501156627856bccb Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 12:36:36 -0700 Subject: First pass at moving object property requests into a queue similar to the entity update queue. The number of property packets can become significant when selecting/deselecting large numbers of objects. This is experimental code. --- OpenSim/Client/MXP/ClientStack/MXPClientView.cs | 4 +- .../Client/VWoHTTP/ClientStack/VWHClientView.cs | 4 +- OpenSim/Framework/IClientAPI.cs | 39 +-- .../Region/ClientStack/LindenUDP/LLClientView.cs | 351 +++++++++++++-------- .../Region/ClientStack/LindenUDP/PriorityQueue.cs | 12 +- .../Region/Examples/SimpleModule/MyNpcCharacter.cs | 12 +- .../Region/Framework/Scenes/SceneObjectGroup.cs | 10 +- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 10 +- .../Server/IRCClientView.cs | 5 +- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 12 +- OpenSim/Tests/Common/Mock/TestClient.cs | 11 +- 11 files changed, 262 insertions(+), 208 deletions(-) diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index d1a0440..a604a2e 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs @@ -1337,12 +1337,12 @@ namespace OpenSim.Client.MXP.ClientStack // Need to translate to MXP somehow } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { //throw new System.NotImplementedException(); } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { //throw new System.NotImplementedException(); } diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs index fc27f01..d8cd0ac 100644 --- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs +++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs @@ -884,12 +884,12 @@ namespace OpenSim.Client.VWoHTTP.ClientStack throw new System.NotImplementedException(); } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { throw new System.NotImplementedException(); } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { throw new System.NotImplementedException(); } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 5bf0b7b..c56a756 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -570,16 +570,30 @@ namespace OpenSim.Framework public float dwell; } - public class EntityUpdate + public class IEntityUpdate { public ISceneEntity Entity; - public PrimUpdateFlags Flags; - public float TimeDilation; + public uint Flags; - public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) + public IEntityUpdate(ISceneEntity entity, uint flags) { Entity = entity; Flags = flags; + } + } + + + public class EntityUpdate : IEntityUpdate + { + // public ISceneEntity Entity; + // public PrimUpdateFlags Flags; + public float TimeDilation; + + public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) + : base(entity,(uint)flags) + { + //Entity = entity; + // Flags = flags; TimeDilation = timedilation; } } @@ -1211,20 +1225,9 @@ namespace OpenSim.Framework /// void SendSimStats(SimStats stats); - void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, - uint Category, - UUID LastOwnerID, string ObjectName, string Description); - - void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, - UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, - string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, - uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice); + void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags); + + void SendObjectPropertiesReply(ISceneEntity Entity); void SendAgentOffline(UUID[] agentIDs); diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 934a2d5..b96343e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -386,6 +386,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_cachedTextureSerial; private PriorityQueue m_entityUpdates; + private PriorityQueue m_entityProps; private Prioritizer m_prioritizer; private bool m_disableFacelights = false; @@ -433,9 +434,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected IAssetService m_assetService; private const bool m_checkPackets = true; - private Timer m_propertiesPacketTimer; - private List m_propertiesBlocks = new List(); - #endregion Class Members #region Properties @@ -511,6 +509,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = scene; m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); + m_entityProps = new PriorityQueue(m_scene.Entities.Count); m_fullUpdateDataBlocksBuilder = new List(); m_killRecord = new HashSet(); // m_attachmentsSent = new HashSet(); @@ -534,9 +533,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpClient.OnQueueEmpty += HandleQueueEmpty; m_udpClient.OnPacketStats += PopulateStats; - m_propertiesPacketTimer = new Timer(100); - m_propertiesPacketTimer.Elapsed += ProcessObjectPropertiesPacket; - m_prioritizer = new Prioritizer(m_scene); RegisterLocalPacketHandlers(); @@ -3636,9 +3632,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); } - private Int32 m_LastQueueFill = 0; - private uint m_maxUpdates = 0; - private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3646,46 +3639,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); + // Check to see if this is a flush if (maxUpdates <= 0) { - m_maxUpdates = Int32.MaxValue; + maxUpdates = Int32.MaxValue; } - else - { - if (m_maxUpdates == 0 || m_LastQueueFill == 0) - { - m_maxUpdates = (uint)maxUpdates; - } - else - { - if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) - m_maxUpdates += 5; - else - m_maxUpdates = m_maxUpdates >> 1; - } - m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); - } - m_LastQueueFill = Util.EnvironmentTickCount(); - + int updatesThisCall = 0; -// -// DEBUGGING CODE... REMOVE -// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates); -// // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race // condition where a kill can be processed before an out-of-date update for the same object. lock (m_killRecord) { float avgTimeDilation = 1.0f; - EntityUpdate update; + IEntityUpdate iupdate; Int32 timeinqueue; // this is just debugging code & can be dropped later - while (updatesThisCall < m_maxUpdates) + while (updatesThisCall < maxUpdates) { lock (m_entityUpdates.SyncRoot) - if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) + if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) break; + + EntityUpdate update = (EntityUpdate)iupdate; + avgTimeDilation += update.TimeDilation; avgTimeDilation *= 0.5f; @@ -3725,7 +3702,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region UpdateFlags to packet type conversion - PrimUpdateFlags updateFlags = update.Flags; + PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; bool canUseCompressed = true; bool canUseImproved = true; @@ -3804,6 +3781,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Block Construction } + #region Packet Sending @@ -3904,12 +3882,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Primitive Packet/Data Sending Methods + // These are used to implement an adaptive backoff in the number + // of updates converted to packets. Since we don't want packets + // to sit in the queue with old data, only convert enough updates + // to packets that can be sent in 200ms. + private Int32 m_LastQueueFill = 0; + private Int32 m_maxUpdates = 0; + void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) { if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) { + if (m_maxUpdates == 0 || m_LastQueueFill == 0) + { + m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; + } + else + { + if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) + m_maxUpdates += 5; + else + m_maxUpdates = m_maxUpdates >> 1; + } + m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); + m_LastQueueFill = Util.EnvironmentTickCount(); + if (m_entityUpdates.Count > 0) - ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback); + ProcessEntityUpdates(m_maxUpdates); + + if (m_entityProps.Count > 0) + ProcessEntityPropertyRequests(m_maxUpdates); } if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) @@ -4023,134 +4025,192 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) - { - ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - // TODO: don't create new blocks if recycling an old packet - - ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - objPropDB.RequestFlags = RequestFlags; - objPropDB.ObjectID = ObjectUUID; - if (OwnerID == GroupID) - objPropDB.OwnerID = UUID.Zero; - else - objPropDB.OwnerID = OwnerID; - objPropDB.GroupID = GroupID; - objPropDB.BaseMask = BaseMask; - objPropDB.OwnerMask = OwnerMask; - objPropDB.GroupMask = GroupMask; - objPropDB.EveryoneMask = EveryoneMask; - objPropDB.NextOwnerMask = NextOwnerMask; +/// ----------------------------------------------------------------- +/// +/// ----------------------------------------------------------------- - // TODO: More properties are needed in SceneObjectPart! - objPropDB.OwnershipCost = OwnershipCost; - objPropDB.SaleType = SaleType; - objPropDB.SalePrice = SalePrice; - objPropDB.Category = Category; - objPropDB.LastOwnerID = LastOwnerID; - objPropDB.Name = Util.StringToBytes256(ObjectName); - objPropDB.Description = Util.StringToBytes256(Description); - objPropFamilyPack.ObjectData = objPropDB; - objPropFamilyPack.Header.Zerocoded = true; - OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task); - } - - public void SendObjectPropertiesReply( - UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + private class ObjectPropertyUpdate : IEntityUpdate { - //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - // TODO: don't create new blocks if recycling an old packet + internal bool SendFamilyProps; + + public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam) + : base(entity,flags) + { + SendFamilyProps = sendfam; + } + } + + public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) + { + uint priority = m_prioritizer.GetUpdatePriority(this, entity); + lock (m_entityProps.SyncRoot) + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true)); + } - ObjectPropertiesPacket.ObjectDataBlock block = - new ObjectPropertiesPacket.ObjectDataBlock(); + public void SendObjectPropertiesReply(ISceneEntity entity) + { + uint priority = m_prioritizer.GetUpdatePriority(this, entity); + lock (m_entityProps.SyncRoot) + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false)); + } - block.ItemID = ItemID; - block.CreationDate = CreationDate; - block.CreatorID = CreatorUUID; - block.FolderID = FolderUUID; - block.FromTaskID = FromTaskUUID; - block.GroupID = GroupUUID; - block.InventorySerial = InventorySerial; + private void ProcessEntityPropertyRequests(int maxUpdates) + { + OpenSim.Framework.Lazy> objectFamilyBlocks = + new OpenSim.Framework.Lazy>(); - block.LastOwnerID = LastOwnerUUID; - // proper.ObjectData[0].LastOwnerID = UUID.Zero; + OpenSim.Framework.Lazy> objectPropertiesBlocks = + new OpenSim.Framework.Lazy>(); - block.ObjectID = ObjectUUID; - if (OwnerUUID == GroupUUID) - block.OwnerID = UUID.Zero; - else - block.OwnerID = OwnerUUID; - block.TouchName = Util.StringToBytes256(TouchTitle); - block.TextureID = TextureID; - block.SitName = Util.StringToBytes256(SitTitle); - block.Name = Util.StringToBytes256(ItemName); - block.Description = Util.StringToBytes256(ItemDescription); - block.OwnerMask = OwnerMask; - block.NextOwnerMask = NextOwnerMask; - block.GroupMask = GroupMask; - block.EveryoneMask = EveryoneMask; - block.BaseMask = BaseMask; - // proper.ObjectData[0].AggregatePerms = 53; - // proper.ObjectData[0].AggregatePermTextures = 0; - // proper.ObjectData[0].AggregatePermTexturesOwner = 0; - block.SaleType = saleType; - block.SalePrice = salePrice; + IEntityUpdate iupdate; + Int32 timeinqueue; // this is just debugging code & can be dropped later - lock (m_propertiesPacketTimer) + int updatesThisCall = 0; + while (updatesThisCall < m_maxUpdates) { - m_propertiesBlocks.Add(block); + lock (m_entityProps.SyncRoot) + if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) + break; - int length = 0; - foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) + ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; + if (update.SendFamilyProps) { - length += b.Length; + if (update.Entity is SceneObjectPart) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); + objectFamilyBlocks.Value.Add(objPropDB); + } } - if (length > 1100) // FIXME: use real MTU + else { - ProcessObjectPropertiesPacket(null, null); - m_propertiesPacketTimer.Stop(); - return; + if (update.Entity is SceneObjectPart) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); + objectPropertiesBlocks.Value.Add(objPropDB); + } } + } + + + if (objectPropertiesBlocks.IsValueCreated) + { + List blocks = objectPropertiesBlocks.Value; - m_propertiesPacketTimer.Stop(); - m_propertiesPacketTimer.Start(); + ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; + for (int i = 0; i < blocks.Count; i++) + packet.ObjectData[i] = blocks[i]; + + packet.Header.Zerocoded = true; + OutPacket(packet, ThrottleOutPacketType.Task, true); } + + + if (objectFamilyBlocks.IsValueCreated) + { + List blocks = objectFamilyBlocks.Value; + + // ObjectPropertiesFamilyPacket objPropFamilyPack = + // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); + // + // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count]; + // for (int i = 0; i < blocks.Count; i++) + // objPropFamilyPack.ObjectData[i] = blocks[i]; + // + // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true); + + // one packet per object block... uggh... + for (int i = 0; i < blocks.Count; i++) + { + ObjectPropertiesFamilyPacket packet = + (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - //proper.Header.Zerocoded = true; - //OutPacket(proper, ThrottleOutPacketType.Task); + packet.ObjectData = blocks[i]; + packet.Header.Zerocoded = true; + OutPacket(packet, ThrottleOutPacketType.Task); + } + + } + } - private void ProcessObjectPropertiesPacket(Object sender, ElapsedEventArgs e) + private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) { - ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - lock (m_propertiesPacketTimer) - { - m_propertiesPacketTimer.Stop(); + block.RequestFlags = requestFlags; + block.ObjectID = sop.UUID; + if (sop.OwnerID == sop.GroupID) + block.OwnerID = UUID.Zero; + else + block.OwnerID = sop.OwnerID; + block.GroupID = sop.GroupID; + block.BaseMask = sop.BaseMask; + block.OwnerMask = sop.OwnerMask; + block.GroupMask = sop.GroupMask; + block.EveryoneMask = sop.EveryoneMask; + block.NextOwnerMask = sop.NextOwnerMask; - proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; + // TODO: More properties are needed in SceneObjectPart! + block.OwnershipCost = sop.OwnershipCost; + block.SaleType = sop.ObjectSaleType; + block.SalePrice = sop.SalePrice; + block.Category = sop.Category; + block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right? + block.Name = Util.StringToBytes256(sop.Name); + block.Description = Util.StringToBytes256(sop.Description); - int index = 0; + return block; + } - foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) - { - proper.ObjectData[index++] = b; - } + private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) + { + //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + // TODO: don't create new blocks if recycling an old packet - m_propertiesBlocks.Clear(); - } + ObjectPropertiesPacket.ObjectDataBlock block = + new ObjectPropertiesPacket.ObjectDataBlock(); + + block.ObjectID = sop.UUID; + block.Name = Util.StringToBytes256(sop.Name); + block.Description = Util.StringToBytes256(sop.Description); - proper.Header.Zerocoded = true; - OutPacket(proper, ThrottleOutPacketType.Task); + block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds + block.CreatorID = sop.CreatorID; + block.GroupID = sop.GroupID; + block.LastOwnerID = sop.LastOwnerID; + if (sop.OwnerID == sop.GroupID) + block.OwnerID = UUID.Zero; + else + block.OwnerID = sop.OwnerID; + + block.ItemID = sop.FromUserInventoryItemID; + block.FolderID = UUID.Zero; // sop.FromFolderID ?? + block.FromTaskID = UUID.Zero; // ??? + block.InventorySerial = (short)sop.InventorySerial; + + SceneObjectPart root = sop.ParentGroup.RootPart; + + block.TouchName = Util.StringToBytes256(root.TouchName); + block.TextureID = new byte[0]; // TextureID ??? + block.SitName = Util.StringToBytes256(root.SitName); + block.OwnerMask = root.OwnerMask; + block.NextOwnerMask = root.NextOwnerMask; + block.GroupMask = root.GroupMask; + block.EveryoneMask = root.EveryoneMask; + block.BaseMask = root.BaseMask; + block.SaleType = root.ObjectSaleType; + block.SalePrice = root.SalePrice; + + return block; } +/// ----------------------------------------------------------------- +/// +/// ----------------------------------------------------------------- + #region Estate Data Sending Methods private static bool convertParamStringToBool(byte[] field) @@ -4482,6 +4542,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendForceClientSelectObjects(List ObjectIDs) { + m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); + bool firstCall = true; const int MAX_OBJECTS_PER_PACKET = 251; ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); @@ -11374,6 +11436,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); } + if (throttlePacketType == ThrottleOutPacketType.Task) + { + System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); // get call stack + System.Diagnostics.StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + + string stack = ""; + for (int count = 1; count < stackFrames.Length; count++) + { + stack += (stack == "" ? "" : ",") + stackFrames[count].GetMethod().Name; + if (count > 5) break; + } + + // m_log.WarnFormat("[BADGUY] {0}", stack); + } + m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 364ce4b..6521a00 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -78,7 +78,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public bool Enqueue(uint pqueue, EntityUpdate value) + public bool Enqueue(uint pqueue, IEntityUpdate value) { LookupItem lookup; @@ -99,7 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } - internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) + internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) { for (int i = 0; i < m_numberOfQueues; ++i) { @@ -122,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } timeinqueue = 0; - value = default(EntityUpdate); + value = default(IEntityUpdate); return false; } @@ -175,8 +175,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region MinHeapItem private struct MinHeapItem : IComparable { - private EntityUpdate value; - internal EntityUpdate Value { + private IEntityUpdate value; + internal IEntityUpdate Value { get { return this.value; } @@ -212,7 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP this.pqueue = pqueue; } - internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) + internal MinHeapItem(uint pqueue, UInt64 entryorder, IEntityUpdate value) { this.entrytime = Util.EnvironmentTickCount(); this.entryorder = entryorder; diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index d939329..89e9e20 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -702,18 +702,12 @@ namespace OpenSim.Region.Examples.SimpleModule { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { + } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index ca7d9d9..30563d4 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1765,10 +1765,12 @@ namespace OpenSim.Region.Framework.Scenes /// public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) { - remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, - RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, - RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, - RootPart.CreatorID, RootPart.Name, RootPart.Description); + remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); + +// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, +// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, +// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, +// RootPart.CreatorID, RootPart.Name, RootPart.Description); } public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4d5eedf..3d2eacd 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2055,15 +2055,7 @@ namespace OpenSim.Region.Framework.Scenes public void GetProperties(IClientAPI client) { - //Viewer wants date in microseconds so multiply it by 1,000,000. - client.SendObjectPropertiesReply( - m_fromUserInventoryItemID, (ulong)_creationDate*(ulong)1e6, _creatorID, UUID.Zero, UUID.Zero, - _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID, - ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description, - ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask, - ParentGroup.RootPart._baseMask, - ParentGroup.RootPart.ObjectSaleType, - ParentGroup.RootPart.SalePrice); + client.SendObjectPropertiesReply(this); } public UUID GetRootPartUUID() diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 821cd4b..4b6e52e 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1332,14 +1332,13 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { - } public void SendAgentOffline(UUID[] agentIDs) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 96760a2..2504e30 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -786,18 +786,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { + } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index d1dc17f..dca5626 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -816,18 +816,11 @@ namespace OpenSim.Tests.Common.Mock { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } -- cgit v1.1 From 1a0f107012ae96f5030b564cc51b6f36b949a467 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 14:40:57 -0700 Subject: fixed a couple bugs with the property queues --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 38 +++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index b96343e..4db5b22 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4091,9 +4091,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectPropertiesBlocks.Value.Add(objPropDB); } } + + updatesThisCall++; } + Int32 ppcnt = 0; + Int32 pbcnt = 0; + if (objectPropertiesBlocks.IsValueCreated) { List blocks = objectPropertiesBlocks.Value; @@ -4105,9 +4110,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Header.Zerocoded = true; OutPacket(packet, ThrottleOutPacketType.Task, true); + + pbcnt += blocks.Count; + ppcnt++; } + Int32 fpcnt = 0; + Int32 fbcnt = 0; + if (objectFamilyBlocks.IsValueCreated) { List blocks = objectFamilyBlocks.Value; @@ -4130,10 +4141,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.ObjectData = blocks[i]; packet.Header.Zerocoded = true; OutPacket(packet, ThrottleOutPacketType.Task); + + fpcnt++; + fbcnt++; } } + m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); + m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); } private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) @@ -11401,6 +11417,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, throttlePacketType, true); } +/// + Dictionary pktsrc = new Dictionary(); + uint pktcnt = 0; +/// + /// /// This is the starting point for sending a simulator packet out to the client /// @@ -11448,7 +11469,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (count > 5) break; } - // m_log.WarnFormat("[BADGUY] {0}", stack); + lock(pktsrc) + { + if (! pktsrc.ContainsKey(stack)) + pktsrc.Add(stack,0); + pktsrc[stack]++; + + if (++pktcnt > 500) + { + pktcnt = 0; + m_log.WarnFormat("[PACKETCOUNTS] START"); + foreach (KeyValuePair pkt in pktsrc) + m_log.WarnFormat("[PACKETCOUNTS] {0,8}, {1}", pkt.Value, pkt.Key); + pktsrc.Clear(); + m_log.WarnFormat("[PACKETCOUNTS] END"); + } + } } m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); -- cgit v1.1 From 78c04d61caed7dc62eb299a09148934d95a1c882 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 15:40:57 -0700 Subject: Fixed the update of items in the priority queue to enable both types of property updates to be specified. Not sure if one form of property update should supercede another. But for now the old OpenSim behavior is preserved by sending both. --- OpenSim/Framework/IClientAPI.cs | 5 +++++ .../Region/ClientStack/LindenUDP/LLClientView.cs | 21 +++++++++++++++------ .../Region/ClientStack/LindenUDP/PriorityQueue.cs | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index c56a756..f573c32 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -575,6 +575,11 @@ namespace OpenSim.Framework public ISceneEntity Entity; public uint Flags; + public virtual void Update(IEntityUpdate update) + { + this.Flags |= update.Flags; + } + public IEntityUpdate(ISceneEntity entity, uint flags) { Entity = entity; diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 4db5b22..92a76ac 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4032,26 +4032,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP private class ObjectPropertyUpdate : IEntityUpdate { internal bool SendFamilyProps; + internal bool SendObjectProps; - public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam) + public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) : base(entity,flags) { SendFamilyProps = sendfam; + SendObjectProps = sendobj; + } + public void Update(ObjectPropertyUpdate update) + { + SendFamilyProps = SendFamilyProps || update.SendFamilyProps; + SendObjectProps = SendObjectProps || update.SendObjectProps; + Flags |= update.Flags; } } public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) { - uint priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); } public void SendObjectPropertiesReply(ISceneEntity entity) { - uint priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); } private void ProcessEntityPropertyRequests(int maxUpdates) @@ -4082,7 +4090,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectFamilyBlocks.Value.Add(objPropDB); } } - else + + if (update.SendObjectProps) { if (update.Entity is SceneObjectPart) { diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 6521a00..b62ec07 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_lookupTable.TryGetValue(localid, out lookup)) { entry = lookup.Heap[lookup.Handle].EntryOrder; - value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; + value.Update(lookup.Heap[lookup.Handle].Value); lookup.Heap.Remove(lookup.Handle); } -- cgit v1.1 From b84ad81740ea1c732711b7f555d44c56b3858178 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 15:55:21 -0700 Subject: remove packet monitoring debugging code --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 118 +-------------------- 1 file changed, 2 insertions(+), 116 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 92a76ac..cf04f0d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -300,77 +300,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Used to adjust Sun Orbit values so Linden based viewers properly position sun private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; - // First log file or time has expired, start writing to a new log file -// -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// THIS IS DEBUGGING CODE & SHOULD BE REMOVED -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- - public class QueueLogger - { - public Int32 start = 0; - public StreamWriter Log = null; - private Dictionary m_idMap = new Dictionary(); - - public QueueLogger() - { - DateTime now = DateTime.Now; - String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); - Log = new StreamWriter(fname); - - start = Util.EnvironmentTickCount(); - } - - public int LookupID(UUID uuid) - { - int localid; - if (! m_idMap.TryGetValue(uuid,out localid)) - { - localid = m_idMap.Count + 1; - m_idMap[uuid] = localid; - } - - return localid; - } - } - - public static QueueLogger QueueLog = null; - - // ----------------------------------------------------------------- - public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - int aid = QueueLog.LookupID(avatar); - QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); - } - } - - // ----------------------------------------------------------------- - public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); - } - } -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients @@ -4025,10 +3954,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } -/// ----------------------------------------------------------------- -/// -/// ----------------------------------------------------------------- - private class ObjectPropertyUpdate : IEntityUpdate { internal bool SendFamilyProps; @@ -4157,8 +4082,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } - m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); - m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); + // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); + // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); } private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) @@ -4232,10 +4157,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return block; } -/// ----------------------------------------------------------------- -/// -/// ----------------------------------------------------------------- - #region Estate Data Sending Methods private static bool convertParamStringToBool(byte[] field) @@ -11426,11 +11347,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, throttlePacketType, true); } -/// - Dictionary pktsrc = new Dictionary(); - uint pktcnt = 0; -/// - /// /// This is the starting point for sending a simulator packet out to the client /// @@ -11465,36 +11381,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (logPacket) m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); } - - if (throttlePacketType == ThrottleOutPacketType.Task) - { - System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); // get call stack - System.Diagnostics.StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) - - string stack = ""; - for (int count = 1; count < stackFrames.Length; count++) - { - stack += (stack == "" ? "" : ",") + stackFrames[count].GetMethod().Name; - if (count > 5) break; - } - - lock(pktsrc) - { - if (! pktsrc.ContainsKey(stack)) - pktsrc.Add(stack,0); - pktsrc[stack]++; - - if (++pktcnt > 500) - { - pktcnt = 0; - m_log.WarnFormat("[PACKETCOUNTS] START"); - foreach (KeyValuePair pkt in pktsrc) - m_log.WarnFormat("[PACKETCOUNTS] {0,8}, {1}", pkt.Value, pkt.Key); - pktsrc.Clear(); - m_log.WarnFormat("[PACKETCOUNTS] END"); - } - } - } m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); } -- cgit v1.1 From 5c870fce548eeca24ae0491a2261ce4fb330a57b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 12 Apr 2011 19:45:33 -0700 Subject: Bug fix in object serialization -- sculpt data was wrong. --- OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 57ae4fd..b412e25 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1318,7 +1318,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteStartElement("SculptData"); byte[] sd; if (shp.SculptData != null) - sd = shp.ExtraParams; + sd = shp.SculptData; else sd = Utils.EmptyBytes; writer.WriteBase64(sd, 0, sd.Length); -- cgit v1.1 From 16c911dcbb883e60d7a49176db8b2cea650cc929 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 12 Apr 2011 19:46:27 -0700 Subject: Implemented terrain save-tile command. Does the opposite of load-tile. For now, only saves to .png. --- .../Terrain/FileLoaders/GenericSystemDrawing.cs | 46 ++++++++++++++++++ .../CoreModules/World/Terrain/FileLoaders/JPEG.cs | 8 ++++ .../CoreModules/World/Terrain/FileLoaders/LLRAW.cs | 8 ++++ .../CoreModules/World/Terrain/FileLoaders/RAW32.cs | 7 +++ .../World/Terrain/FileLoaders/Terragen.cs | 8 ++++ .../CoreModules/World/Terrain/ITerrainLoader.cs | 1 + .../CoreModules/World/Terrain/TerrainModule.cs | 54 ++++++++++++++++++++++ 7 files changed, 132 insertions(+) diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs index d6fa093..21a9999 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs @@ -124,6 +124,52 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders colours.Save(stream, ImageFormat.Png); } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + + { + // We need to do this because: + // "Saving the image to the same file it was constructed from is not allowed and throws an exception." + string tempName = offsetX + "_ " + offsetY + "_" + filename; + + Bitmap entireBitmap = null; + Bitmap thisBitmap = null; + if (File.Exists(filename)) + { + File.Copy(filename, tempName); + entireBitmap = new Bitmap(tempName); + if (entireBitmap.Width != fileWidth * regionSizeX || entireBitmap.Height != fileHeight * regionSizeY) + { + // old file, let's overwrite it + entireBitmap = new Bitmap(fileWidth * regionSizeX, fileHeight * regionSizeY); + } + } + else + { + entireBitmap = new Bitmap(fileWidth * regionSizeX, fileHeight * regionSizeY); + } + + thisBitmap = CreateGrayscaleBitmapFromMap(m_channel); + Console.WriteLine("offsetX=" + offsetX + " offsetY=" + offsetY); + for (int x = 0; x < regionSizeX; x++) + for (int y = 0; y < regionSizeY; y++) + entireBitmap.SetPixel(x + offsetX * regionSizeX, y + (fileHeight - 1 - offsetY) * regionSizeY, thisBitmap.GetPixel(x, y)); + + Save(entireBitmap, filename); + thisBitmap.Dispose(); + entireBitmap.Dispose(); + + if (File.Exists(tempName)) + File.Delete(tempName); + } + + protected virtual void Save(Bitmap bmp, string filename) + { + bmp.Save(filename, ImageFormat.Png); + } + #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs index 8667607..1a0d8ec 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs @@ -76,6 +76,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders colours.Save(stream, ImageFormat.Jpeg); } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + { + throw new System.Exception("Not Implemented"); + } + #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs index a70ef13..fad7641 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs @@ -240,6 +240,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders get { return ".raw"; } } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + { + throw new System.Exception("Not Implemented"); + } + #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs index 3c76665..ba073ca 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs @@ -160,6 +160,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders bs.Close(); } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + { + throw new System.Exception("Not Implemented"); + } #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs index 2919897..2f37d9d 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs @@ -308,6 +308,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders get { return ".ter"; } } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + { + throw new System.Exception("Not Implemented"); + } + #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs index 7403281..7237f90 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs @@ -38,5 +38,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain ITerrainChannel LoadStream(Stream stream); void SaveFile(string filename, ITerrainChannel map); void SaveStream(Stream stream, ITerrainChannel map); + void SaveFile(ITerrainChannel map, string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int regionSizeX, int regionSizeY); } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 8a79d78..9c7b2fa 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -541,6 +541,39 @@ namespace OpenSim.Region.CoreModules.World.Terrain } /// + /// Saves the terrain to a larger terrain file. + /// + /// The terrain file to save + /// The width of the file in units + /// The height of the file in units + /// Where to begin our slice + /// Where to begin our slice + public void SaveToFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) + { + int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX; + int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY; + + if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) + { + // this region is included in the tile request + foreach (KeyValuePair loader in m_loaders) + { + if (filename.EndsWith(loader.Key)) + { + lock (m_scene) + { + loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, + fileWidth, fileHeight, + (int)Constants.RegionSize, + (int)Constants.RegionSize); + } + return; + } + } + } + } + + /// /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections /// private void EventManager_OnTerrainTick() @@ -860,6 +893,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain SaveToFile((string) args[0]); } + private void InterfaceSaveTileFile(Object[] args) + { + SaveToFile((string)args[0], + (int)args[1], + (int)args[2], + (int)args[3], + (int)args[4]); + } + private void InterfaceBakeTerrain(Object[] args) { UpdateRevertMap(); @@ -1115,6 +1157,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain loadFromTileCommand.AddArgument("minimum Y tile", "The Y region coordinate of the first section on the file", "Integer"); + Command saveToTileCommand = + new Command("save-tile", CommandIntentions.COMMAND_HAZARDOUS, InterfaceSaveTileFile, "Saves the current heightmap to the larger file."); + saveToTileCommand.AddArgument("filename", + "The file you wish to save to, the file extension determines the loader to be used. Supported extensions include: " + + supportedFileExtensions, "String"); + saveToTileCommand.AddArgument("file width", "The width of the file in tiles", "Integer"); + saveToTileCommand.AddArgument("file height", "The height of the file in tiles", "Integer"); + saveToTileCommand.AddArgument("minimum X tile", "The X region coordinate of the first section on the file", + "Integer"); + saveToTileCommand.AddArgument("minimum Y tile", "The Y region coordinate of the first section on the file", + "Integer"); // Terrain adjustments Command fillRegionCommand = new Command("fill", CommandIntentions.COMMAND_HAZARDOUS, InterfaceFillTerrain, "Fills the current heightmap with a specified value."); @@ -1166,6 +1219,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_commander.RegisterCommand("load", loadFromFileCommand); m_commander.RegisterCommand("load-tile", loadFromTileCommand); m_commander.RegisterCommand("save", saveToFileCommand); + m_commander.RegisterCommand("save-tile", saveToTileCommand); m_commander.RegisterCommand("fill", fillRegionCommand); m_commander.RegisterCommand("elevate", elevateCommand); m_commander.RegisterCommand("lower", lowerCommand); -- cgit v1.1 From 7592a033df4f81ba985e1d6f57ad0ef488dc5745 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 12 Apr 2011 20:24:28 -0700 Subject: Moved 3 request handlers from OpenSim.Framework.Servers.HttpServer up to OpenSim.Framework -- just pasted them in WebUtil. This is so that code that uses the Service connectors don't need to include the HttpServer dll -- that was odd. --- .../HttpServer/AsynchronousRestObjectRequester.cs | 192 ------------ .../HttpServer/SynchronousRestFormsRequester.cs | 131 -------- .../HttpServer/SynchronousRestObjectRequester.cs | 122 -------- OpenSim/Framework/WebUtil.cs | 335 +++++++++++++++++++++ .../CoreModules/Avatar/Friends/FriendsModule.cs | 2 +- .../Avatar/InstantMessage/OfflineMessageModule.cs | 1 - .../Asset/AssetServiceInConnectorModule.cs | 1 - .../AuthenticationServiceInConnectorModule.cs | 1 - .../Grid/GridInfoServiceInConnectorModule.cs | 1 - .../Hypergrid/HypergridServiceInConnectorModule.cs | 1 - .../Inventory/InventoryServiceInConnectorModule.cs | 3 +- .../Land/LandServiceInConnectorModule.cs | 1 - .../Login/LLLoginServiceInConnectorModule.cs | 1 - .../Neighbour/NeighbourServiceInConnectorModule.cs | 1 - .../SimulationServiceInConnectorModule.cs | 1 - .../Connectors/Asset/AssetServiceConnector.cs | 1 - .../AuthenticationServiceConnector.cs | 1 - .../Authorization/AuthorizationServiceConnector.cs | 1 - .../Connectors/Avatar/AvatarServiceConnector.cs | 1 - .../Freeswitch/RemoteFreeswitchConnector.cs | 1 - .../Connectors/Friends/FriendsServiceConnector.cs | 1 - .../Connectors/Friends/FriendsSimConnector.cs | 2 +- .../Connectors/Grid/GridServiceConnector.cs | 1 - .../GridUser/GridUserServiceConnector.cs | 1 - .../Connectors/Inventory/XInventoryConnector.cs | 1 - .../Connectors/Land/LandServiceConnector.cs | 1 - .../Neighbour/NeighbourServiceConnector.cs | 1 - .../Presence/PresenceServiceConnector.cs | 1 - .../UserAccounts/UserAccountServiceConnector.cs | 1 - prebuild.xml | 1 - 30 files changed, 338 insertions(+), 472 deletions(-) delete mode 100644 OpenSim/Framework/Servers/HttpServer/AsynchronousRestObjectRequester.cs delete mode 100644 OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs delete mode 100644 OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs diff --git a/OpenSim/Framework/Servers/HttpServer/AsynchronousRestObjectRequester.cs b/OpenSim/Framework/Servers/HttpServer/AsynchronousRestObjectRequester.cs deleted file mode 100644 index 03c12dd..0000000 --- a/OpenSim/Framework/Servers/HttpServer/AsynchronousRestObjectRequester.cs +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; -using System.Xml; -using System.Xml.Serialization; -using log4net; - -namespace OpenSim.Framework.Servers.HttpServer -{ - public class AsynchronousRestObjectRequester - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// Perform an asynchronous REST request. - /// - /// GET or POST - /// - /// - /// - /// - /// - /// Thrown if we encounter a - /// network issue while posting the request. You'll want to make - /// sure you deal with this as they're not uncommon - // - public static void MakeRequest(string verb, - string requestUrl, TRequest obj, Action action) - { -// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl); - - Type type = typeof (TRequest); - - WebRequest request = WebRequest.Create(requestUrl); - WebResponse response = null; - TResponse deserial = default(TResponse); - XmlSerializer deserializer = new XmlSerializer(typeof (TResponse)); - - request.Method = verb; - - if (verb == "POST") - { - request.ContentType = "text/xml"; - - MemoryStream buffer = new MemoryStream(); - - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; - - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, obj); - writer.Flush(); - } - - int length = (int) buffer.Length; - request.ContentLength = length; - - request.BeginGetRequestStream(delegate(IAsyncResult res) - { - Stream requestStream = request.EndGetRequestStream(res); - - requestStream.Write(buffer.ToArray(), 0, length); - requestStream.Close(); - - request.BeginGetResponse(delegate(IAsyncResult ar) - { - response = request.EndGetResponse(ar); - Stream respStream = null; - try - { - respStream = response.GetResponseStream(); - deserial = (TResponse)deserializer.Deserialize( - respStream); - } - catch (System.InvalidOperationException) - { - } - finally - { - // Let's not close this - //buffer.Close(); - respStream.Close(); - response.Close(); - } - - action(deserial); - - }, null); - }, null); - - - return; - } - - request.BeginGetResponse(delegate(IAsyncResult res2) - { - try - { - // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't - // documented in MSDN - response = request.EndGetResponse(res2); - - Stream respStream = null; - try - { - respStream = response.GetResponseStream(); - deserial = (TResponse)deserializer.Deserialize(respStream); - } - catch (System.InvalidOperationException) - { - } - finally - { - respStream.Close(); - response.Close(); - } - } - catch (WebException e) - { - if (e.Status == WebExceptionStatus.ProtocolError) - { - if (e.Response is HttpWebResponse) - { - HttpWebResponse httpResponse = (HttpWebResponse)e.Response; - - if (httpResponse.StatusCode != HttpStatusCode.NotFound) - { - // We don't appear to be handling any other status codes, so log these feailures to that - // people don't spend unnecessary hours hunting phantom bugs. - m_log.DebugFormat( - "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", - verb, requestUrl, httpResponse.StatusCode); - } - } - } - else - { - m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", verb, requestUrl, e.Status, e.Message); - } - } - catch (Exception e) - { - m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with exception {2}", verb, requestUrl, e); - } - - // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); - - try - { - action(deserial); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}", verb, requestUrl, e); - } - - }, null); - } - } -} diff --git a/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs b/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs deleted file mode 100644 index 41ece86..0000000 --- a/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; -using System.Xml; -using System.Xml.Serialization; - -using log4net; - -namespace OpenSim.Framework.Servers.HttpServer -{ - public class SynchronousRestFormsRequester - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// Perform a synchronous REST request. - /// - /// - /// - /// - /// - /// - /// Thrown if we encounter a network issue while posting - /// the request. You'll want to make sure you deal with this as they're not uncommon - public static string MakeRequest(string verb, string requestUrl, string obj) - { - WebRequest request = WebRequest.Create(requestUrl); - request.Method = verb; - string respstring = String.Empty; - - using (MemoryStream buffer = new MemoryStream()) - { - if ((verb == "POST") || (verb == "PUT")) - { - request.ContentType = "text/www-form-urlencoded"; - - int length = 0; - using (StreamWriter writer = new StreamWriter(buffer)) - { - writer.Write(obj); - writer.Flush(); - } - - length = (int)obj.Length; - request.ContentLength = length; - - Stream requestStream = null; - try - { - requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); - } - catch (Exception e) - { - m_log.DebugFormat("[FORMS]: exception occured on sending request to {0}: " + e.ToString(), requestUrl); - } - finally - { - if (requestStream != null) - requestStream.Close(); - } - } - - try - { - using (WebResponse resp = request.GetResponse()) - { - if (resp.ContentLength != 0) - { - Stream respStream = null; - try - { - respStream = resp.GetResponseStream(); - using (StreamReader reader = new StreamReader(respStream)) - { - respstring = reader.ReadToEnd(); - } - } - catch (Exception e) - { - m_log.DebugFormat("[FORMS]: exception occured on receiving reply " + e.ToString()); - } - finally - { - if (respStream != null) - respStream.Close(); - } - } - } - } - catch (System.InvalidOperationException) - { - // This is what happens when there is invalid XML - m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving request"); - } - } - return respstring; - } - } -} diff --git a/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs b/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs deleted file mode 100644 index eab463c..0000000 --- a/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Xml; -using System.Xml.Serialization; - -namespace OpenSim.Framework.Servers.HttpServer -{ - public class SynchronousRestObjectPoster - { - [Obsolete] - public static TResponse BeginPostObject(string verb, string requestUrl, TRequest obj) - { - return SynchronousRestObjectRequester.MakeRequest(verb, requestUrl, obj); - } - } - - public class SynchronousRestObjectRequester - { - /// - /// Perform a synchronous REST request. - /// - /// - /// - /// - /// - /// - /// Thrown if we encounter a network issue while posting - /// the request. You'll want to make sure you deal with this as they're not uncommon - public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj) - { - Type type = typeof (TRequest); - TResponse deserial = default(TResponse); - - WebRequest request = WebRequest.Create(requestUrl); - request.Method = verb; - - if ((verb == "POST") || (verb == "PUT")) - { - request.ContentType = "text/xml"; - - MemoryStream buffer = new MemoryStream(); - - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; - - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, obj); - writer.Flush(); - } - - int length = (int) buffer.Length; - request.ContentLength = length; - - Stream requestStream = null; - try - { - requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); - } - catch (Exception) - { - return deserial; - } - finally - { - if (requestStream != null) - requestStream.Close(); - } - } - - try - { - using (WebResponse resp = request.GetResponse()) - { - if (resp.ContentLength > 0) - { - Stream respStream = resp.GetResponseStream(); - XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); - deserial = (TResponse)deserializer.Deserialize(respStream); - respStream.Close(); - } - } - } - catch (System.InvalidOperationException) - { - // This is what happens when there is invalid XML - } - return deserial; - } - } -} diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 1feeeb3..64cd014 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -36,6 +36,9 @@ using System.Net.Security; using System.Reflection; using System.Text; using System.Web; +using System.Xml; +using System.Xml.Serialization; + using log4net; using OpenSim.Framework.Servers.HttpServer; using OpenMetaverse.StructuredData; @@ -625,4 +628,336 @@ namespace OpenSim.Framework } + + public static class AsynchronousRestObjectRequester + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Perform an asynchronous REST request. + /// + /// GET or POST + /// + /// + /// + /// + /// + /// Thrown if we encounter a + /// network issue while posting the request. You'll want to make + /// sure you deal with this as they're not uncommon + // + public static void MakeRequest(string verb, + string requestUrl, TRequest obj, Action action) + { + // m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl); + + Type type = typeof(TRequest); + + WebRequest request = WebRequest.Create(requestUrl); + WebResponse response = null; + TResponse deserial = default(TResponse); + XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); + + request.Method = verb; + + if (verb == "POST") + { + request.ContentType = "text/xml"; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } + + int length = (int)buffer.Length; + request.ContentLength = length; + + request.BeginGetRequestStream(delegate(IAsyncResult res) + { + Stream requestStream = request.EndGetRequestStream(res); + + requestStream.Write(buffer.ToArray(), 0, length); + requestStream.Close(); + + request.BeginGetResponse(delegate(IAsyncResult ar) + { + response = request.EndGetResponse(ar); + Stream respStream = null; + try + { + respStream = response.GetResponseStream(); + deserial = (TResponse)deserializer.Deserialize( + respStream); + } + catch (System.InvalidOperationException) + { + } + finally + { + // Let's not close this + //buffer.Close(); + respStream.Close(); + response.Close(); + } + + action(deserial); + + }, null); + }, null); + + + return; + } + + request.BeginGetResponse(delegate(IAsyncResult res2) + { + try + { + // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't + // documented in MSDN + response = request.EndGetResponse(res2); + + Stream respStream = null; + try + { + respStream = response.GetResponseStream(); + deserial = (TResponse)deserializer.Deserialize(respStream); + } + catch (System.InvalidOperationException) + { + } + finally + { + respStream.Close(); + response.Close(); + } + } + catch (WebException e) + { + if (e.Status == WebExceptionStatus.ProtocolError) + { + if (e.Response is HttpWebResponse) + { + HttpWebResponse httpResponse = (HttpWebResponse)e.Response; + + if (httpResponse.StatusCode != HttpStatusCode.NotFound) + { + // We don't appear to be handling any other status codes, so log these feailures to that + // people don't spend unnecessary hours hunting phantom bugs. + m_log.DebugFormat( + "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", + verb, requestUrl, httpResponse.StatusCode); + } + } + } + else + { + m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", verb, requestUrl, e.Status, e.Message); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with exception {2}", verb, requestUrl, e); + } + + // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); + + try + { + action(deserial); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}", verb, requestUrl, e); + } + + }, null); + } + } + + public static class SynchronousRestFormsRequester + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Perform a synchronous REST request. + /// + /// + /// + /// + /// + /// + /// Thrown if we encounter a network issue while posting + /// the request. You'll want to make sure you deal with this as they're not uncommon + public static string MakeRequest(string verb, string requestUrl, string obj) + { + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + string respstring = String.Empty; + + using (MemoryStream buffer = new MemoryStream()) + { + if ((verb == "POST") || (verb == "PUT")) + { + request.ContentType = "text/www-form-urlencoded"; + + int length = 0; + using (StreamWriter writer = new StreamWriter(buffer)) + { + writer.Write(obj); + writer.Flush(); + } + + length = (int)obj.Length; + request.ContentLength = length; + + Stream requestStream = null; + try + { + requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + } + catch (Exception e) + { + m_log.DebugFormat("[FORMS]: exception occured on sending request to {0}: " + e.ToString(), requestUrl); + } + finally + { + if (requestStream != null) + requestStream.Close(); + } + } + + try + { + using (WebResponse resp = request.GetResponse()) + { + if (resp.ContentLength != 0) + { + Stream respStream = null; + try + { + respStream = resp.GetResponseStream(); + using (StreamReader reader = new StreamReader(respStream)) + { + respstring = reader.ReadToEnd(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[FORMS]: exception occured on receiving reply " + e.ToString()); + } + finally + { + if (respStream != null) + respStream.Close(); + } + } + } + } + catch (System.InvalidOperationException) + { + // This is what happens when there is invalid XML + m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving request"); + } + } + return respstring; + } + } + + public class SynchronousRestObjectPoster + { + [Obsolete] + public static TResponse BeginPostObject(string verb, string requestUrl, TRequest obj) + { + return SynchronousRestObjectRequester.MakeRequest(verb, requestUrl, obj); + } + } + + public class SynchronousRestObjectRequester + { + /// + /// Perform a synchronous REST request. + /// + /// + /// + /// + /// + /// + /// Thrown if we encounter a network issue while posting + /// the request. You'll want to make sure you deal with this as they're not uncommon + public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj) + { + Type type = typeof(TRequest); + TResponse deserial = default(TResponse); + + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + + if ((verb == "POST") || (verb == "PUT")) + { + request.ContentType = "text/xml"; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } + + int length = (int)buffer.Length; + request.ContentLength = length; + + Stream requestStream = null; + try + { + requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + } + catch (Exception) + { + return deserial; + } + finally + { + if (requestStream != null) + requestStream.Close(); + } + } + + try + { + using (WebResponse resp = request.GetResponse()) + { + if (resp.ContentLength > 0) + { + Stream respStream = resp.GetResponseStream(); + XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); + deserial = (TResponse)deserializer.Deserialize(respStream); + respStream.Close(); + } + } + } + catch (System.InvalidOperationException) + { + // This is what happens when there is invalid XML + } + return deserial; + } + } } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 4d74b2a..5baf078 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -34,13 +34,13 @@ using Nini.Config; using Nwc.XmlRpc; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; using OpenSim.Framework.Communications; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using OpenSim.Services.Connectors.Friends; using OpenSim.Server.Base; -using OpenSim.Framework.Servers.HttpServer; using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; using GridRegion = OpenSim.Services.Interfaces.GridRegion; diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index fdfcd10..919ea33 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs @@ -33,7 +33,6 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Communications; using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Framework.Client; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs index e25700d..422f394 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs index 02acddc..2b5beba 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs index 6d975af..f29c074 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs index 2f96bcb..d2343c9 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs index 209cf0d..53a8ace 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs @@ -31,9 +31,8 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; using OpenSim.Server.Base; using OpenSim.Server.Handlers.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs index fcc69e9..fc64203 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs index 2a9366c..f759470 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs index 35518d5..5c32632 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs index 5ee1c97..86b4926 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs index 65b3537..f1da4fa 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs @@ -34,7 +34,6 @@ using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs index 6f77a2d..c04e7a4 100644 --- a/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs b/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs index 4eb4bd2..35b7109 100644 --- a/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs b/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs index 1cd6bf8..1a93ae7 100644 --- a/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs +++ b/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; diff --git a/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs index c9bba0b..d688299 100644 --- a/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs +++ b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs index 36b5083..861c475 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs index 0a7b277..4ffa68c 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs @@ -32,7 +32,7 @@ using System.Reflection; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; -using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework; using OpenMetaverse; using log4net; diff --git a/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs b/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs index 5092d74..e57f28b 100644 --- a/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs +++ b/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs index b3ea865..738cc06 100644 --- a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs +++ b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs index b3bfcc2..cd9f2bf 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs @@ -34,7 +34,6 @@ using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs b/OpenSim/Services/Connectors/Land/LandServiceConnector.cs index 252f7a1..30a73a4 100644 --- a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs +++ b/OpenSim/Services/Connectors/Land/LandServiceConnector.cs @@ -34,7 +34,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenMetaverse; using Nwc.XmlRpc; diff --git a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs b/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs index 9e444c4..2cae02d 100644 --- a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs +++ b/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs @@ -36,7 +36,6 @@ using System.Text; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenMetaverse; using OpenMetaverse.StructuredData; diff --git a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs index 41ebeaf..7238afc 100644 --- a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs index 2a5df83..f6835b9 100644 --- a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenMetaverse; diff --git a/prebuild.xml b/prebuild.xml index 870ebf3..8171664 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -931,7 +931,6 @@ - -- cgit v1.1 From 90b810c27ef4fe3da1796842940af13db61fb91d Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 12 Apr 2011 22:47:30 -0700 Subject: force mesh proxy for simple box prims with path cut --- OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs | 3 +++ OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs index 85e34c1..6df213d 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs @@ -648,6 +648,9 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin if (pbs.ProfileHollow != 0) iPropertiesNotSupportedDefault++; + if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) + iPropertiesNotSupportedDefault++; + if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) iPropertiesNotSupportedDefault++; diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index eb97f41..a0101af 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -2528,6 +2528,9 @@ namespace OpenSim.Region.Physics.OdePlugin if (pbs.ProfileHollow != 0) iPropertiesNotSupportedDefault++; + if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) + iPropertiesNotSupportedDefault++; + if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) iPropertiesNotSupportedDefault++; -- cgit v1.1 From 6613daa82a3bf0d45b0be1b2941646042f9008f4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Apr 2011 17:46:36 +0100 Subject: Add a regression test for rezzing a single object into a scene from user inventory --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 9 +- .../Tests/InventoryAccessModuleTests.cs | 133 +++++++++++++++++++++ .../World/Estate/EstateManagementModule.cs | 4 + prebuild.xml | 1 + 4 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 8de31d7..76d7f79 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4290,6 +4290,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendEstateCovenantInformation(UUID covenant) { +// m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name); + EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket(); EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock(); edata.CovenantID = covenant; @@ -4300,8 +4302,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(einfopack, ThrottleOutPacketType.Task); } - public void SendDetailedEstateData(UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, UUID covenant, string abuseEmail, UUID estateOwner) + public void SendDetailedEstateData( + UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, + UUID covenant, string abuseEmail, UUID estateOwner) { +// m_log.DebugFormat( +// "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant); + EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); packet.MethodData.Invoice = invoice; packet.AgentData.TransactionID = UUID.Random(); diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs new file mode 100644 index 0000000..ecf70ac --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -0,0 +1,133 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Framework.Communications; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; +using OpenSim.Tests.Common.Setup; + +namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests +{ + [TestFixture] + public class InventoryAccessModuleTests + { + protected TestScene m_scene; + protected BasicInventoryAccessModule m_iam; + + [SetUp] + public void SetUp() + { + m_iam = new BasicInventoryAccessModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + m_scene = SceneSetupHelpers.SetupScene("Inventory"); + SceneSetupHelpers.SetupSceneModules(m_scene, config, m_iam); + } + + [Test] + public void TestRezObject() + { + TestHelper.InMethod(); + log4net.Config.XmlConfigurator.Configure(); + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + UserProfileTestUtils.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); + + // Create asset + SceneObjectGroup object1; + SceneObjectPart part1; + { + string partName = "My Little Dog Object"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 offsetPosition = new Vector3(5, 10, 15); + + part1 + = new SceneObjectPart( + ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Name = partName; + + object1 = new SceneObjectGroup(part1); + } + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); + m_scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + string item1Name = "My Little Dog"; + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = item1Name; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + m_scene.AddInventoryItem(item1); + + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = userId; + TestClient tc = new TestClient(acd, m_scene); + + SceneObjectGroup so + = m_iam.RezObject( + tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + + Assert.That(so, Is.Not.Null); + + SceneObjectPart retrievedPart = m_scene.GetSceneObjectPart(so.UUID); + Assert.That(retrievedPart, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index b6d64ac..ab90e90 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -259,6 +259,10 @@ namespace OpenSim.Region.CoreModules.World.Estate private void handleChangeEstateCovenantRequest(IClientAPI remoteClient, UUID estateCovenantID) { +// m_log.DebugFormat( +// "[ESTATE MANAGEMENT MODULE]: Handling request from {0} to change estate covenant to {1}", +// remoteClient.Name, estateCovenantID); + Scene.RegionInfo.RegionSettings.Covenant = estateCovenantID; Scene.RegionInfo.RegionSettings.Save(); TriggerRegionInfoChange(); diff --git a/prebuild.xml b/prebuild.xml index 8171664..49063da 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2888,6 +2888,7 @@ + -- cgit v1.1 From 08fd1d9bbd0878e6ea0ce4abc0a664a70865ea01 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Apr 2011 18:11:04 +0100 Subject: factor out some test code into the SetUp() --- .../Tests/InventoryAccessModuleTests.cs | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index ecf70ac..5eca753 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -54,6 +54,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests { protected TestScene m_scene; protected BasicInventoryAccessModule m_iam; + protected UUID m_userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + protected TestClient m_tc; [SetUp] public void SetUp() @@ -66,20 +68,23 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests m_scene = SceneSetupHelpers.SetupScene("Inventory"); SceneSetupHelpers.SetupSceneModules(m_scene, config, m_iam); + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UserProfileTestUtils.CreateUserWithInventory(m_scene, userFirstName, userLastName, m_userId, userPassword); + + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = m_userId; + m_tc = new TestClient(acd, m_scene); } [Test] public void TestRezObject() { TestHelper.InMethod(); - log4net.Config.XmlConfigurator.Configure(); - - // Create user - string userFirstName = "Jock"; - string userLastName = "Stirrup"; - string userPassword = "troll"; - UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); - UserProfileTestUtils.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); +// log4net.Config.XmlConfigurator.Configure(); // Create asset SceneObjectGroup object1; @@ -112,17 +117,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests item1.AssetID = asset1.FullID; item1.ID = item1Id; InventoryFolderBase objsFolder - = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; + = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; item1.Folder = objsFolder.ID; m_scene.AddInventoryItem(item1); - AgentCircuitData acd = new AgentCircuitData(); - acd.AgentID = userId; - TestClient tc = new TestClient(acd, m_scene); - SceneObjectGroup so = m_iam.RezObject( - tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); Assert.That(so, Is.Not.Null); -- cgit v1.1 From dec9c2283b548818409c91a93307334d1c0d9774 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 13 Apr 2011 16:10:18 -0400 Subject: Add ColladaMesh switch --- OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs | 13 +++++++++++-- .../Assets/NewFileAgentInventoryVariablePriceModule.cs | 11 ++++++++++- bin/OpenSimDefaults.ini | 6 +++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs index 878242a..d2278bc 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs @@ -54,6 +54,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets private Scene m_scene; private IAssetService m_assetService; + private bool m_enabled = true; #region IRegionModuleBase Members @@ -65,7 +66,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void Initialise(IConfigSource source) { - + IConfig startupConfig = source.Configs["Startup"]; + if (startupConfig == null) + return; + + if (!startupConfig.GetBoolean("ColladaMesh",true)) + m_enabled = false; } public void AddRegion(Scene pScene) @@ -101,16 +107,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void RegisterCaps(UUID agentID, Caps caps) { + if(!m_enabled) + return; + UUID capID = UUID.Random(); // m_log.Info("[GETMESH]: /CAPS/" + capID); + caps.RegisterHandler("GetMesh", new RestHTTPHandler("GET", "/CAPS/" + capID, delegate(Hashtable m_dhttpMethod) { return ProcessGetMesh(m_dhttpMethod, agentID, caps); })); - } #endregion diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs index 4a42c93..fb07cc9 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs @@ -56,6 +56,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets private Scene m_scene; // private IAssetService m_assetService; private bool m_dumpAssetsToFile = false; + private bool m_enabled = true; #region IRegionModuleBase Members @@ -67,7 +68,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void Initialise(IConfigSource source) { - + IConfig startupConfig = source.Configs["Startup"]; + if (startupConfig == null) + return; + + if (!startupConfig.GetBoolean("ColladaMesh",true)) + m_enabled = false; } public void AddRegion(Scene pScene) @@ -103,6 +109,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void RegisterCaps(UUID agentID, Caps caps) { + if(!m_enabled) + return; + UUID capID = UUID.Random(); // m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID); diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index f857b8d..107e859 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -154,7 +154,11 @@ ; mesh, and use it for collisions. This is currently experimental code and enabling ; it may cause unexpected physics problems. ;UseMeshiesPhysicsMesh = false - + + ; enable / disable Collada mesh support + ; default is true + ; ColladaMesh = true + ; Choose one of the physics engines below ; OpenDynamicsEngine is by some distance the most developed physics engine ; basicphysics effectively does not model physics at all, making all objects phantom -- cgit v1.1 From 58efd761d13bd4f2617fcb3f94bbe265880589e3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Apr 2011 21:17:43 +0100 Subject: Add coalesced scene objects class and serializer. This is currently only used by the TestRezCoalescedObject() regression test. This structure matches the existing one for SceneObjects and will allow code to be reused by the uuid gatherer, other tests, etc. Test is not yet fully implemented due to a bug in rezzing coalesced objects where they all get the same name as the item. Only one object should get the same name as the item, which appears to be the one selected last when the the objects were coalesced in the first place. This bug will be addressed shortly. --- .../InventoryAccess/InventoryAccessModule.cs | 19 ++- .../Tests/InventoryAccessModuleTests.cs | 79 +++++++++++++ .../Framework/Scenes/CoalescedSceneObjects.cs | 128 +++++++++++++++++++++ OpenSim/Region/Framework/Scenes/Scene.cs | 15 ++- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 2 + .../CoalescedSceneObjectsSerializer.cs | 117 +++++++++++++++++++ .../Scenes/Serialization/SceneObjectSerializer.cs | 23 +++- OpenSim/Tests/Common/Setup/AssetHelpers.cs | 15 +++ 8 files changed, 389 insertions(+), 9 deletions(-) create mode 100644 OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs create mode 100644 OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 73b0a35..cfcfc79 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -274,7 +274,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess float minX, minY, minZ; float maxX, maxY, maxZ; - Vector3[] offsets = m_Scene.GetCombinedBoundingBox(objlist, + Vector3[] offsets = Scene.GetCombinedBoundingBox(objlist, out minX, out maxX, out minY, out maxY, out minZ, out maxZ); @@ -289,7 +289,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess XmlDocument doc = new XmlDocument(); SceneObjectGroup g = objlist[i]; doc.LoadXml(xmlStrings[g.UUID]); - XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup"); + XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup"); e.SetAttribute("offsetx", offsets[i].X.ToString()); e.SetAttribute("offsety", offsets[i].Y.ToString()); e.SetAttribute("offsetz", offsets[i].Z.ToString()); @@ -659,9 +659,18 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess itemId, n.OuterXml); objlist.Add(g); XmlElement el = (XmlElement)n; - float x = Convert.ToSingle(el.GetAttribute("offsetx")); - float y = Convert.ToSingle(el.GetAttribute("offsety")); - float z = Convert.ToSingle(el.GetAttribute("offsetz")); + + string rawX = el.GetAttribute("offsetx"); + string rawY = el.GetAttribute("offsety"); + string rawZ = el.GetAttribute("offsetz"); +// +// m_log.DebugFormat( +// "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>", +// g.Name, rawX, rawY, rawZ); + + float x = Convert.ToSingle(rawX); + float y = Convert.ToSingle(rawY); + float z = Convert.ToSingle(rawZ); veclist.Add(new Vector3(x, y, z)); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 5eca753..f8fa424 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -81,6 +81,85 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests } [Test] + public void TestRezCoalescedObject() + { + TestHelper.InMethod(); + log4net.Config.XmlConfigurator.Configure(); + + // Create asset + SceneObjectGroup object1; + { + string partName = "Object1"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 offsetPosition = new Vector3(5, 10, 15); + + SceneObjectPart part1 + = new SceneObjectPart( + ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Name = partName; + + object1 = new SceneObjectGroup(part1); + } + + SceneObjectGroup object2; + { + string partName = "Object2"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 offsetPosition = new Vector3(5, 10, 15); + + SceneObjectPart part1 + = new SceneObjectPart( + ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Name = partName; + + object2 = new SceneObjectGroup(part1); + } + + CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, coa); + m_scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + string item1Name = "My Little Dog"; + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = item1Name; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + m_scene.AddInventoryItem(item1); + + SceneObjectGroup so + = m_iam.RezObject( + m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + + Assert.That(so, Is.Not.Null); + + Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(2)); + + SceneObjectPart retrievedObj1Part = m_scene.GetSceneObjectPart(object1.Name); + Assert.That(retrievedObj1Part, Is.Null); + + retrievedObj1Part = m_scene.GetSceneObjectPart(item1.Name); + Assert.That(retrievedObj1Part, Is.Not.Null); + Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); + + // FIXME: Can't test yet due to a bug where objects in coalescence all get the item name when rerezzed. +// SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); +// Assert.That(retrievedObj2Part, Is.Not.Null); + } + + [Test] public void TestRezObject() { TestHelper.InMethod(); diff --git a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs new file mode 100644 index 0000000..51eac5f --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs @@ -0,0 +1,128 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenMetaverse; + +namespace OpenSim.Region.Framework.Scenes +{ + /// + /// Represents a coalescene of scene objects. A coalescence occurs when objects that are not in the same linkset + /// are grouped together. + /// + public class CoalescedSceneObjects + { + /// + /// The creator of this coalesence, though not necessarily the objects within it. + /// + public UUID CreatorId { get; set; } + + /// + /// The number of objects in this coalesence + /// + public int Count + { + get + { + lock (m_memberObjects) + return m_memberObjects.Count; + } + } + + /// + /// Does this coalesence have any member objects? + /// + public bool HasObjects { get { return Count > 0; } } + + /// + /// Get the objects currently in this coalescence + /// + public List Objects + { + get + { + lock (m_memberObjects) + return new List(m_memberObjects); + } + } + + /// + /// Get the scene that contains the objects in this coalescence. If there are no objects then null is returned. + /// + public Scene Scene + { + get + { + if (!HasObjects) + return null; + else + return Objects[0].Scene; + } + } + + /// + /// At this point, we need to preserve the order of objects added to the coalescence, since the first + /// one will end up matching the item name when rerezzed. + /// + protected List m_memberObjects = new List(); + + public CoalescedSceneObjects(UUID creatorId) + { + CreatorId = creatorId; + } + + public CoalescedSceneObjects(UUID creatorId, params SceneObjectGroup[] objs) : this(creatorId) + { + foreach (SceneObjectGroup obj in objs) + Add(obj); + } + + /// + /// Add an object to the coalescence. + /// + /// + /// The offset of the object within the group + public void Add(SceneObjectGroup obj) + { + lock (m_memberObjects) + m_memberObjects.Add(obj); + } + + /// + /// Removes a scene object from the coalescene + /// + /// + /// true if the object was there to be removed, false if not. + public bool Remove(SceneObjectGroup obj) + { + lock (m_memberObjects) + return m_memberObjects.Remove(obj); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f0acc38..e6dd489 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4839,7 +4839,20 @@ namespace OpenSim.Region.Framework.Scenes } } - public Vector3[] GetCombinedBoundingBox(List objects, out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) + /// + /// Get the volume of space that will encompass all the given objects. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static Vector3[] GetCombinedBoundingBox( + List objects, + out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) { minX = 256; maxX = -256; diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 97af0a0..72f0402 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -997,6 +997,8 @@ namespace OpenSim.Region.Framework.Scenes { foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts) { +// m_log.DebugFormat("[SCENE GRAPH]: Part {0} has name {1}", p.UUID, p.Name); + if (p.Name == name) { sop = p; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs new file mode 100644 index 0000000..3af2f76 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -0,0 +1,117 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Reflection; +using System.Xml; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.Framework.Scenes.Serialization +{ + /// + /// Serialize and deserialize coalesced scene objects. + /// + public class CoalescedSceneObjectsSerializer + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Serialize coalesced objects to Xml + /// + /// + /// + public static string ToXml(CoalescedSceneObjects coa) + { + // TODO: Should probably return an empty xml serialization rather than a blank string + if (!coa.HasObjects) + return ""; + + using (StringWriter sw = new StringWriter()) + { + using (XmlTextWriter writer = new XmlTextWriter(sw)) + { + List coaObjects = coa.Objects; + +// m_log.DebugFormat( +// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object", +// coaObjects.Count); + + float minX, minY, minZ; + float maxX, maxY, maxZ; + + Vector3[] offsets = Scene.GetCombinedBoundingBox(coaObjects, + out minX, out maxX, out minY, out maxY, + out minZ, out maxZ); + + writer.WriteStartElement("CoalescedObject"); + + float sizeX = maxX - minX; + float sizeY = maxY - minY; + float sizeZ = maxZ - minZ; + + writer.WriteAttributeString("x", sizeX.ToString()); + writer.WriteAttributeString("y", sizeY.ToString()); + writer.WriteAttributeString("z", sizeZ.ToString()); + + // Embed the offsets into the group XML + for (int i = 0; i < coaObjects.Count; i++) + { + SceneObjectGroup obj = coaObjects[i]; + +// m_log.DebugFormat( +// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing offset for object {0}, {1}", +// i, obj.Name); + + writer.WriteStartElement("SceneObjectGroup"); + writer.WriteAttributeString("offsetx", offsets[i].X.ToString()); + writer.WriteAttributeString("offsety", offsets[i].Y.ToString()); + writer.WriteAttributeString("offsetz", offsets[i].Z.ToString()); + + SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, true); + + writer.WriteEndElement(); + } + + writer.WriteEndElement(); // CoalescedObject + } + + string output = sw.ToString(); + +// m_log.Debug(output); + + return output; + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index b412e25..bb8a83a 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -139,6 +139,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization return sw.ToString(); } } + /// /// Serialize a scene object to the original xml format @@ -147,10 +148,24 @@ namespace OpenSim.Region.Framework.Scenes.Serialization /// public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer) { + ToOriginalXmlFormat(sceneObject, writer, false); + } + + /// + /// Serialize a scene object to the original xml format + /// + /// + /// + /// If false, don't write the enclosing SceneObjectGroup element + /// + public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer, bool noRootElement) + { //m_log.DebugFormat("[SERIALIZER]: Starting serialization of {0}", Name); //int time = System.Environment.TickCount; - writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); + if (!noRootElement) + writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); + writer.WriteStartElement(String.Empty, "RootPart", String.Empty); ToXmlFormat(sceneObject.RootPart, writer); writer.WriteEndElement(); @@ -170,10 +185,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteEndElement(); // OtherParts sceneObject.SaveScriptedState(writer); - writer.WriteEndElement(); // SceneObjectGroup + + if (!noRootElement) + writer.WriteEndElement(); // SceneObjectGroup //m_log.DebugFormat("[SERIALIZER]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time); - } + } protected static void ToXmlFormat(SceneObjectPart part, XmlTextWriter writer) { diff --git a/OpenSim/Tests/Common/Setup/AssetHelpers.cs b/OpenSim/Tests/Common/Setup/AssetHelpers.cs index ff4423f..af66d7f 100644 --- a/OpenSim/Tests/Common/Setup/AssetHelpers.cs +++ b/OpenSim/Tests/Common/Setup/AssetHelpers.cs @@ -71,6 +71,21 @@ namespace OpenSim.Tests.Common Encoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(sog)), sog.OwnerID); } + + /// + /// Create an asset from the given scene object. + /// + /// + /// + /// + public static AssetBase CreateAsset(UUID assetUuid, CoalescedSceneObjects coa) + { + return CreateAsset( + assetUuid, + AssetType.Object, + Encoding.ASCII.GetBytes(CoalescedSceneObjectsSerializer.ToXml(coa)), + coa.CreatorId); + } /// /// Create an asset from the given data. -- cgit v1.1 From d8d28c37372718aa593ead5c85cd45ced83766a5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Apr 2011 21:31:45 +0100 Subject: Fix bug where rezzing coalesced objects would give all objects the same name as the item. This now only happens for the first object (which was the item selected last when the coalesce was originally taken) This matches the expected behaviour of the environment as seen on the Linden Labs grid. --- .../Framework/InventoryAccess/InventoryAccessModule.cs | 13 +++++++++---- .../InventoryAccess/Tests/InventoryAccessModuleTests.cs | 5 ++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index cfcfc79..1f8bad1 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -762,10 +762,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // affect the name stored in the serialization, transfer // the correct name from the inventory to the // object itself before we rez. - rootPart.Name = item.Name; - rootPart.Description = item.Description; - rootPart.ObjectSaleType = item.SaleType; - rootPart.SalePrice = item.SalePrice; + // + // Only do these for the first object if we are rezzing a coalescence. + if (i == 0) + { + rootPart.Name = item.Name; + rootPart.Description = item.Description; + rootPart.ObjectSaleType = item.SaleType; + rootPart.SalePrice = item.SalePrice; + } group.SetGroup(remoteClient.ActiveGroupId, remoteClient); if ((rootPart.OwnerID != item.Owner) || diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index f8fa424..0f2b610 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -154,9 +154,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests Assert.That(retrievedObj1Part, Is.Not.Null); Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); - // FIXME: Can't test yet due to a bug where objects in coalescence all get the item name when rerezzed. -// SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); -// Assert.That(retrievedObj2Part, Is.Not.Null); + SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); + Assert.That(retrievedObj2Part, Is.Not.Null); } [Test] -- cgit v1.1 From 68cc5b46fefdf4db68cae1202086257ce731f8a1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Apr 2011 21:48:16 +0100 Subject: refactor: move code to obtain the coalescence size and object offsets into CoalescedSceneObjects from the serializer. --- .../Tests/InventoryAccessModuleTests.cs | 2 +- .../Framework/Scenes/CoalescedSceneObjects.cs | 26 +++++++++++++++++++++ .../CoalescedSceneObjectsSerializer.cs | 27 ++++++++++------------ 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 0f2b610..c197cb9 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -84,7 +84,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests public void TestRezCoalescedObject() { TestHelper.InMethod(); - log4net.Config.XmlConfigurator.Configure(); +// log4net.Config.XmlConfigurator.Configure(); // Create asset SceneObjectGroup object1; diff --git a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs index 51eac5f..af8ccda 100644 --- a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs +++ b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs @@ -124,5 +124,31 @@ namespace OpenSim.Region.Framework.Scenes lock (m_memberObjects) return m_memberObjects.Remove(obj); } + + /// + /// Get the total size of the coalescence (the size required to cover all the objects within it) and the + /// offsets of each of those objects. + /// + /// + /// + /// An array of offsets. The order of objects is the same as returned from the Objects property + /// + public Vector3[] GetSizeAndOffsets(out Vector3 size) + { + float minX, minY, minZ; + float maxX, maxY, maxZ; + + Vector3[] offsets + = Scene.GetCombinedBoundingBox( + Objects, out minX, out maxX, out minY, out maxY, out minZ, out maxZ); + + float sizeX = maxX - minX; + float sizeY = maxY - minY; + float sizeZ = maxZ - minZ; + + size = new Vector3(sizeX, sizeY, sizeZ); + + return offsets; + } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index 3af2f76..a0e120a 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -42,6 +42,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization /// /// Serialize and deserialize coalesced scene objects. /// + /// + /// Deserialization not yet here. + /// public class CoalescedSceneObjectsSerializer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -60,29 +63,23 @@ namespace OpenSim.Region.Framework.Scenes.Serialization using (StringWriter sw = new StringWriter()) { using (XmlTextWriter writer = new XmlTextWriter(sw)) - { + { + Vector3 size; + List coaObjects = coa.Objects; // m_log.DebugFormat( // "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object", // coaObjects.Count); - float minX, minY, minZ; - float maxX, maxY, maxZ; - - Vector3[] offsets = Scene.GetCombinedBoundingBox(coaObjects, - out minX, out maxX, out minY, out maxY, - out minZ, out maxZ); + // This is weak - we're relying on the set of coalesced objects still being identical + Vector3[] offsets = coa.GetSizeAndOffsets(out size); writer.WriteStartElement("CoalescedObject"); - float sizeX = maxX - minX; - float sizeY = maxY - minY; - float sizeZ = maxZ - minZ; - - writer.WriteAttributeString("x", sizeX.ToString()); - writer.WriteAttributeString("y", sizeY.ToString()); - writer.WriteAttributeString("z", sizeZ.ToString()); + writer.WriteAttributeString("x", size.X.ToString()); + writer.WriteAttributeString("y", size.Y.ToString()); + writer.WriteAttributeString("z", size.Z.ToString()); // Embed the offsets into the group XML for (int i = 0; i < coaObjects.Count; i++) @@ -100,7 +97,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, true); - writer.WriteEndElement(); + writer.WriteEndElement(); // SceneObjectGroup } writer.WriteEndElement(); // CoalescedObject -- cgit v1.1 From c81f5bfc5c3cb0bac2a89ee846099dcaae1f357b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Apr 2011 22:29:12 +0100 Subject: Adjust the quanterions used in the rez coalsced object tests to get sensible bounding box and offset numbers. Extend test to check position of objects in the rezzed coalescence. --- .../InventoryAccess/Tests/InventoryAccessModuleTests.cs | 16 ++++++++++++---- OpenSim/Region/Framework/Scenes/Scene.cs | 4 ++++ OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 9 ++++++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index c197cb9..c76a30a 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -93,12 +93,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); Vector3 groupPosition = new Vector3(10, 20, 30); - Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Quaternion rotationOffset = Quaternion.Identity; Vector3 offsetPosition = new Vector3(5, 10, 15); SceneObjectPart part1 = new SceneObjectPart( ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Scale = new Vector3(1, 1, 1); part1.Name = partName; object1 = new SceneObjectGroup(part1); @@ -109,13 +110,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests string partName = "Object2"; UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); - Vector3 groupPosition = new Vector3(10, 20, 30); - Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 groupPosition = new Vector3(20, 40, 60); + Quaternion rotationOffset = Quaternion.Identity; Vector3 offsetPosition = new Vector3(5, 10, 15); SceneObjectPart part1 = new SceneObjectPart( ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Scale = new Vector3(1, 1, 1); part1.Name = partName; object2 = new SceneObjectGroup(part1); @@ -141,7 +143,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests SceneObjectGroup so = m_iam.RezObject( - m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + m_tc, item1Id, new Vector3(100, 100, 100), Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); Assert.That(so, Is.Not.Null); @@ -154,8 +156,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests Assert.That(retrievedObj1Part, Is.Not.Null); Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); + // Bottom of coalescence is placed on ground, hence we end up with 100.5 rather than 85 since the bottom + // object is unit square. + Assert.That(retrievedObj1Part.AbsolutePosition, Is.EqualTo(new Vector3(95, 90, 100.5f))); + SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); Assert.That(retrievedObj2Part, Is.Not.Null); + Assert.That(retrievedObj2Part.Name, Is.EqualTo(object2.Name)); + Assert.That(retrievedObj2Part.AbsolutePosition, Is.EqualTo(new Vector3(105, 110, 130.5f))); } [Test] diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e6dd489..fdd5205 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4870,6 +4870,10 @@ namespace OpenSim.Region.Framework.Scenes Vector3 vec = g.AbsolutePosition; g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ); + +// m_log.DebugFormat( +// "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}", +// g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ)); ominX += vec.X; omaxX += vec.X; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4d5eedf..ce1e6b8 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2088,7 +2088,14 @@ namespace OpenSim.Region.Framework.Scenes axPos *= parentRot; Vector3 translationOffsetPosition = axPos; - return GroupPosition + translationOffsetPosition; + +// m_log.DebugFormat("[SCENE OBJECT PART]: Found group pos {0} for part {1}", GroupPosition, Name); + + Vector3 worldPos = GroupPosition + translationOffsetPosition; + +// m_log.DebugFormat("[SCENE OBJECT PART]: Found world pos {0} for part {1}", worldPos, Name); + + return worldPos; } /// -- cgit v1.1 From c5465414b64d835128827976cc3da32aa462e6a3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Apr 2011 22:55:26 +0100 Subject: Use common coalesced serialization code for both tests and the InventoryAccessModule. Continue to restore original absolute positions of stored scene objects, though it's possible that these aren't used again --- .../InventoryAccess/InventoryAccessModule.cs | 67 +++++----------------- 1 file changed, 13 insertions(+), 54 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 1f8bad1..c0946f4 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -222,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess deletes[g.OwnerID].Add(g); } - // This is pethod scoped and will be returned. It will be the + // This is method scoped and will be returned. It will be the // last created asset id UUID assetID = UUID.Zero; @@ -230,8 +230,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // with distinct destinations as well. foreach (List objlist in deletes.Values) { - Dictionary xmlStrings = - new Dictionary(); + CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); + Dictionary originalPositions = new Dictionary(); foreach (SceneObjectGroup objectGroup in objlist) { @@ -245,7 +245,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess : objectGroup.AbsolutePosition.X, objectGroup.AbsolutePosition.Z); - Vector3 originalPosition = objectGroup.AbsolutePosition; + originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; objectGroup.AbsolutePosition = inventoryStoredPosition; @@ -259,59 +259,20 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess (uint)PermissionMask.Modify); objectGroup.RootPart.NextOwnerMask |= (uint)PermissionMask.Move; - - string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup); - - objectGroup.AbsolutePosition = originalPosition; - - xmlStrings[objectGroup.UUID] = sceneObjectXml; + + coa.Add(objectGroup); } string itemXml; if (objlist.Count > 1) - { - float minX, minY, minZ; - float maxX, maxY, maxZ; - - Vector3[] offsets = Scene.GetCombinedBoundingBox(objlist, - out minX, out maxX, out minY, out maxY, - out minZ, out maxZ); - - // CreateWrapper - XmlDocument itemDoc = new XmlDocument(); - XmlElement root = itemDoc.CreateElement("", "CoalescedObject", ""); - itemDoc.AppendChild(root); - - // Embed the offsets into the group XML - for ( int i = 0 ; i < objlist.Count ; i++ ) - { - XmlDocument doc = new XmlDocument(); - SceneObjectGroup g = objlist[i]; - doc.LoadXml(xmlStrings[g.UUID]); - XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup"); - e.SetAttribute("offsetx", offsets[i].X.ToString()); - e.SetAttribute("offsety", offsets[i].Y.ToString()); - e.SetAttribute("offsetz", offsets[i].Z.ToString()); - - XmlNode objectNode = itemDoc.ImportNode(e, true); - root.AppendChild(objectNode); - } - - float sizeX = maxX - minX; - float sizeY = maxY - minY; - float sizeZ = maxZ - minZ; - - root.SetAttribute("x", sizeX.ToString()); - root.SetAttribute("y", sizeY.ToString()); - root.SetAttribute("z", sizeZ.ToString()); - - itemXml = itemDoc.InnerXml; - } + itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); else - { - itemXml = xmlStrings[objlist[0].UUID]; - } + itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); + + // Restore the position of each group now that it has been stored to inventory. + foreach (SceneObjectGroup objectGroup in objlist) + objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; // Get the user info of the item destination // @@ -332,7 +293,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { // All returns / deletes go to the object owner // - userID = objlist[0].RootPart.OwnerID; } @@ -346,7 +306,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Delete is treated like return in this case // Deleting your own items makes them go to trash // - + InventoryFolderBase folder = null; InventoryItemBase item = null; @@ -548,7 +508,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return assetID; } - /// /// Rez an object into the scene from the user's inventory /// -- cgit v1.1 From 5b89c66c9704f2bd219a35f8a70ac60e751d7f49 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 11 Apr 2011 09:06:28 -0700 Subject: New tokenbucket algorithm. This one provides fair sharing of the queues when client and simulator throttles are set. This algorithm also uses pre-defined burst rate of 150% of the sustained rate for each of the throttles. Removed the "state" queue. The state queue is not a Linden queue and appeared to be used just to get kill packets sent. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 6 +- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 96 ++++--- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 2 +- .../Region/ClientStack/LindenUDP/TokenBucket.cs | 300 ++++++++++++++------- 4 files changed, 259 insertions(+), 145 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 76d7f79..5980669 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -1610,7 +1610,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - OutPacket(kill, ThrottleOutPacketType.State); + // OutPacket(kill, ThrottleOutPacketType.State); + OutPacket(kill, ThrottleOutPacketType.Task); } } @@ -2440,7 +2441,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Effect = effectBlocks; - OutPacket(packet, ThrottleOutPacketType.State); + // OutPacket(packet, ThrottleOutPacketType.State); + OutPacket(packet, ThrottleOutPacketType.Task); } public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 9a8bfd3..5a69851 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -135,7 +135,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_nextOnQueueEmpty = 1; /// Throttle bucket for this agent's connection - private readonly TokenBucket m_throttle; + private readonly TokenBucket m_throttleClient; + /// Throttle bucket for this agent's connection + private readonly TokenBucket m_throttleCategory; /// Throttle buckets for each packet category private readonly TokenBucket[] m_throttleCategories; /// Outgoing queues for throttled packets @@ -174,7 +176,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_maxRTO = maxRTO; // Create a token bucket throttle for this client that has the scene token bucket as a parent - m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); + m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); + // Create a token bucket throttle for the total categary with the client bucket as a throttle + m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); // Create an array of token buckets for this clients different throttle categories m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; @@ -185,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Initialize the packet outboxes, where packets sit while they are waiting for tokens m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue(); // Initialize the token buckets that control the throttling for each category - m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); + m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type)); } // Default the retransmission timeout to three seconds @@ -206,6 +210,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_packetOutboxes[i].Clear(); m_nextPackets[i] = null; } + + // pull the throttle out of the scene throttle + m_throttleClient.Parent.UnregisterRequest(m_throttleClient); OnPacketStats = null; OnQueueEmpty = null; } @@ -216,6 +223,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Information about the client connection public ClientInfo GetClientInfo() { +/// + TokenBucket tb; + + tb = m_throttleClient.Parent; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT"); + + tb = m_throttleClient; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT"); + + tb = m_throttleCategory; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY"); + + for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) + { + tb = m_throttleCategories[i]; + m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET"); + } + +/// + // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists // of pending and needed ACKs for every client every time some method wants information about // this connection is a recipe for poor performance @@ -223,13 +250,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP info.pendingAcks = new Dictionary(); info.needAck = new Dictionary(); - info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; - info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; - info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; - info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; - info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; - info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; - info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; + info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; + info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; + info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; + info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; + // info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; + info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + info.taskThrottle + info.assetThrottle + info.textureThrottle; @@ -317,8 +345,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); // State is a subcategory of task that we allocate a percentage to - int state = (int)((float)task * STATE_TASK_PERCENTAGE); - task -= state; + int state = 0; + // int state = (int)((float)task * STATE_TASK_PERCENTAGE); + // task -= state; // Make sure none of the throttles are set below our packet MTU, // otherwise a throttle could become permanently clogged @@ -339,40 +368,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Update the token buckets with new throttle values TokenBucket bucket; - bucket = m_throttle; - bucket.MaxBurst = total; + bucket = m_throttleCategory; + bucket.RequestedDripRate = total; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; - bucket.DripRate = resend; - bucket.MaxBurst = resend; + bucket.RequestedDripRate = resend; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; - bucket.DripRate = land; - bucket.MaxBurst = land; + bucket.RequestedDripRate = land; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; - bucket.DripRate = wind; - bucket.MaxBurst = wind; + bucket.RequestedDripRate = wind; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; - bucket.DripRate = cloud; - bucket.MaxBurst = cloud; + bucket.RequestedDripRate = cloud; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; - bucket.DripRate = asset; - bucket.MaxBurst = asset; + bucket.RequestedDripRate = asset; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; - bucket.DripRate = task + state; - bucket.MaxBurst = task + state; + bucket.RequestedDripRate = task; bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; - bucket.DripRate = state; - bucket.MaxBurst = state; + bucket.RequestedDripRate = state; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; - bucket.DripRate = texture; - bucket.MaxBurst = texture; + bucket.RequestedDripRate = texture; // Reset the packed throttles cached data m_packedThrottles = null; @@ -387,14 +408,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP data = new byte[7 * 4]; int i = 0; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + - m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4; m_packedThrottles = data; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 583214c..d08b25f 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -228,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } #endregion BinaryStats - m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); + m_throttle = new TokenBucket(null, sceneThrottleBps); ThrottleRates = new ThrottleRates(configSource); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index 0a8331f..e4d59ff 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs @@ -26,6 +26,10 @@ */ using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using log4net; namespace OpenSim.Region.ClientStack.LindenUDP { @@ -35,89 +39,126 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public class TokenBucket { - /// Parent bucket to this bucket, or null if this is a root - /// bucket - TokenBucket parent; - /// Size of the bucket in bytes. If zero, the bucket has - /// infinite capacity - int maxBurst; - /// Rate that the bucket fills, in bytes per millisecond. If - /// zero, the bucket always remains full - int tokensPerMS; - /// Number of tokens currently in the bucket - int content; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static Int32 m_counter = 0; + + private Int32 m_identifier; + + /// + /// Number of ticks (ms) per quantum, drip rate and max burst + /// are defined over this interval. + /// + private const Int32 m_ticksPerQuantum = 1000; + + /// + /// This is the number of quantums worth of packets that can + /// be accommodated during a burst + /// + private const Double m_quantumsPerBurst = 1.5; + + /// + /// + private const Int32 m_minimumDripRate = 1400; + /// Time of the last drip, in system ticks - int lastDrip; + private Int32 m_lastDrip; + + /// + /// The number of bytes that can be sent at this moment. This is the + /// current number of tokens in the bucket + /// + private Int64 m_tokenCount; - #region Properties + /// + /// Map of children buckets and their requested maximum burst rate + /// + private Dictionary m_children = new Dictionary(); + +#region Properties /// /// The parent bucket of this bucket, or null if this bucket has no /// parent. The parent bucket will limit the aggregate bandwidth of all /// of its children buckets /// + private TokenBucket m_parent; public TokenBucket Parent { - get { return parent; } + get { return m_parent; } + set { m_parent = value; } } /// /// Maximum burst rate in bytes per second. This is the maximum number - /// of tokens that can accumulate in the bucket at any one time + /// of tokens that can accumulate in the bucket at any one time. This + /// also sets the total request for leaf nodes /// - public int MaxBurst + private Int64 m_burstRate; + public Int64 RequestedBurstRate { - get { return maxBurst; } - set { maxBurst = (value >= 0 ? value : 0); } + get { return m_burstRate; } + set { m_burstRate = (value < 0 ? 0 : value); } } + public Int64 BurstRate + { + get { + double rate = RequestedBurstRate * BurstRateModifier(); + if (rate < m_minimumDripRate * m_quantumsPerBurst) + rate = m_minimumDripRate * m_quantumsPerBurst; + + return (Int64) rate; + } + } + /// /// The speed limit of this bucket in bytes per second. This is the - /// number of tokens that are added to the bucket per second + /// number of tokens that are added to the bucket per quantum /// /// Tokens are added to the bucket any time /// is called, at the granularity of /// the system tick interval (typically around 15-22ms) - public int DripRate + private Int64 m_dripRate; + public Int64 RequestedDripRate { - get { return tokensPerMS * 1000; } - set - { - if (value == 0) - tokensPerMS = 0; - else - { - int bpms = (int)((float)value / 1000.0f); - - if (bpms <= 0) - tokensPerMS = 1; // 1 byte/ms is the minimum granularity - else - tokensPerMS = bpms; - } + get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } + set { + m_dripRate = (value < 0 ? 0 : value); + m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); + m_totalDripRequest = m_dripRate; + if (m_parent != null) + m_parent.RegisterRequest(this,m_dripRate); } } - /// - /// The speed limit of this bucket in bytes per millisecond - /// - public int DripPerMS + public Int64 DripRate { - get { return tokensPerMS; } + get { + if (m_parent == null) + return Math.Min(RequestedDripRate,TotalDripRequest); + + double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); + if (rate < m_minimumDripRate) + rate = m_minimumDripRate; + + return (Int64)rate; + } } /// - /// The number of bytes that can be sent at this moment. This is the - /// current number of tokens in the bucket - /// If this bucket has a parent bucket that does not have - /// enough tokens for a request, will - /// return false regardless of the content of this bucket + /// The current total of the requested maximum burst rates of + /// this bucket's children buckets. /// - public int Content - { - get { return content; } - } + private Int64 m_totalDripRequest; + public Int64 TotalDripRequest + { + get { return m_totalDripRequest; } + set { m_totalDripRequest = value; } + } + +#endregion Properties - #endregion Properties +#region Constructor /// /// Default constructor @@ -128,56 +169,115 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// zero if this bucket has no maximum capacity /// Rate that the bucket fills, in bytes per /// second. If zero, the bucket always remains full - public TokenBucket(TokenBucket parent, int maxBurst, int dripRate) + public TokenBucket(TokenBucket parent, Int64 dripRate) { - this.parent = parent; - MaxBurst = maxBurst; - DripRate = dripRate; - lastDrip = Environment.TickCount & Int32.MaxValue; + m_identifier = m_counter++; + + Parent = parent; + RequestedDripRate = dripRate; + // TotalDripRequest = dripRate; // this will be overwritten when a child node registers + // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); + m_lastDrip = Environment.TickCount & Int32.MaxValue; } +#endregion Constructor + /// - /// Remove a given number of tokens from the bucket + /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning + /// no modification if the requested bandwidth is less than the + /// max burst bandwidth all the way to the root of the throttle + /// hierarchy. However, if any of the parents is over-booked, then + /// the modifier will be less than 1. /// - /// Number of tokens to remove from the bucket - /// True if the requested number of tokens were removed from - /// the bucket, otherwise false - public bool RemoveTokens(int amount) + private double DripRateModifier() + { + Int64 driprate = DripRate; + return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; + } + + /// + /// + private double BurstRateModifier() + { + // for now... burst rate is always m_quantumsPerBurst (constant) + // larger than drip rate so the ratio of burst requests is the + // same as the drip ratio + return DripRateModifier(); + } + + /// + /// Register drip rate requested by a child of this throttle. Pass the + /// changes up the hierarchy. + /// + public void RegisterRequest(TokenBucket child, Int64 request) { - bool dummy; - return RemoveTokens(amount, out dummy); + m_children[child] = request; + // m_totalDripRequest = m_children.Values.Sum(); + + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; + + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); } /// + /// Remove the rate requested by a child of this throttle. Pass the + /// changes up the hierarchy. + /// + public void UnregisterRequest(TokenBucket child) + { + m_children.Remove(child); + // m_totalDripRequest = m_children.Values.Sum(); + + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; + + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); + } + + /// /// Remove a given number of tokens from the bucket /// /// Number of tokens to remove from the bucket - /// True if tokens were added to the bucket - /// during this call, otherwise false /// True if the requested number of tokens were removed from /// the bucket, otherwise false - public bool RemoveTokens(int amount, out bool dripSucceeded) + public bool RemoveTokens(Int64 amount) { - if (maxBurst == 0) + // Deposit tokens for this interval + Drip(); + + // If we have enough tokens then remove them and return + if (m_tokenCount - amount >= 0) { - dripSucceeded = true; - return true; + if (m_parent == null || m_parent.RemoveTokens(amount)) + { + m_tokenCount -= amount; + return true; + } } - dripSucceeded = Drip(); + return false; + } - if (content - amount >= 0) - { - if (parent != null && !parent.RemoveTokens(amount)) - return false; + /// + /// Deposit tokens into the bucket from a child bucket that did + /// not use all of its available tokens + /// + private void Deposit(Int64 count) + { + m_tokenCount += count; - content -= amount; - return true; - } - else - { - return false; - } + // Deposit the overflow in the parent bucket, this is how we share + // unused bandwidth + Int64 burstrate = BurstRate; + if (m_tokenCount > burstrate) + m_tokenCount = burstrate; } /// @@ -186,37 +286,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// call to Drip /// /// True if tokens were added to the bucket, otherwise false - public bool Drip() + private void Drip() { - if (tokensPerMS == 0) + // This should never happen... means we are a leaf node and were created + // with no drip rate... + if (DripRate == 0) { - content = maxBurst; - return true; + m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0"); + return; } - else - { - int now = Environment.TickCount & Int32.MaxValue; - int deltaMS = now - lastDrip; - - if (deltaMS <= 0) - { - if (deltaMS < 0) - lastDrip = now; - return false; - } + + // Determine the interval over which we are adding tokens, never add + // more than a single quantum of tokens + Int32 now = Environment.TickCount & Int32.MaxValue; + Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum); - int dripAmount = deltaMS * tokensPerMS; + m_lastDrip = now; - content = Math.Min(content + dripAmount, maxBurst); - lastDrip = now; + // This can be 0 in the very unusual case that the timer wrapped + // It can be 0 if we try add tokens at a sub-tick rate + if (deltaMS <= 0) + return; - if (dripAmount < 0 || content < 0) - // sim has been idle for too long, integer has overflown - // previous calculation is meaningless, let's put it at correct max - content = maxBurst; - - return true; - } + Deposit(deltaMS * DripRate / m_ticksPerQuantum); } } } -- cgit v1.1 From 3fe22126ca3974b2a10365121ee0141fb54806e6 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 12:36:36 -0700 Subject: First pass at moving object property requests into a queue similar to the entity update queue. The number of property packets can become significant when selecting/deselecting large numbers of objects. This is experimental code. --- OpenSim/Client/MXP/ClientStack/MXPClientView.cs | 4 +- .../Client/VWoHTTP/ClientStack/VWHClientView.cs | 4 +- OpenSim/Framework/IClientAPI.cs | 39 +-- .../Region/ClientStack/LindenUDP/LLClientView.cs | 351 +++++++++++++-------- .../Region/ClientStack/LindenUDP/PriorityQueue.cs | 12 +- .../Region/Examples/SimpleModule/MyNpcCharacter.cs | 12 +- .../Region/Framework/Scenes/SceneObjectGroup.cs | 10 +- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 10 +- .../Server/IRCClientView.cs | 5 +- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 12 +- OpenSim/Tests/Common/Mock/TestClient.cs | 11 +- 11 files changed, 262 insertions(+), 208 deletions(-) diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index d1a0440..a604a2e 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs @@ -1337,12 +1337,12 @@ namespace OpenSim.Client.MXP.ClientStack // Need to translate to MXP somehow } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { //throw new System.NotImplementedException(); } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { //throw new System.NotImplementedException(); } diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs index fc27f01..d8cd0ac 100644 --- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs +++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs @@ -884,12 +884,12 @@ namespace OpenSim.Client.VWoHTTP.ClientStack throw new System.NotImplementedException(); } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { throw new System.NotImplementedException(); } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { throw new System.NotImplementedException(); } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 5bf0b7b..c56a756 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -570,16 +570,30 @@ namespace OpenSim.Framework public float dwell; } - public class EntityUpdate + public class IEntityUpdate { public ISceneEntity Entity; - public PrimUpdateFlags Flags; - public float TimeDilation; + public uint Flags; - public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) + public IEntityUpdate(ISceneEntity entity, uint flags) { Entity = entity; Flags = flags; + } + } + + + public class EntityUpdate : IEntityUpdate + { + // public ISceneEntity Entity; + // public PrimUpdateFlags Flags; + public float TimeDilation; + + public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) + : base(entity,(uint)flags) + { + //Entity = entity; + // Flags = flags; TimeDilation = timedilation; } } @@ -1211,20 +1225,9 @@ namespace OpenSim.Framework /// void SendSimStats(SimStats stats); - void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, - uint Category, - UUID LastOwnerID, string ObjectName, string Description); - - void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, - UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, - string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, - uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice); + void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags); + + void SendObjectPropertiesReply(ISceneEntity Entity); void SendAgentOffline(UUID[] agentIDs); diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 5980669..33b9909 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -386,6 +386,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_cachedTextureSerial; private PriorityQueue m_entityUpdates; + private PriorityQueue m_entityProps; private Prioritizer m_prioritizer; private bool m_disableFacelights = false; @@ -433,9 +434,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected IAssetService m_assetService; private const bool m_checkPackets = true; - private Timer m_propertiesPacketTimer; - private List m_propertiesBlocks = new List(); - #endregion Class Members #region Properties @@ -511,6 +509,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = scene; m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); + m_entityProps = new PriorityQueue(m_scene.Entities.Count); m_fullUpdateDataBlocksBuilder = new List(); m_killRecord = new HashSet(); // m_attachmentsSent = new HashSet(); @@ -534,9 +533,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpClient.OnQueueEmpty += HandleQueueEmpty; m_udpClient.OnPacketStats += PopulateStats; - m_propertiesPacketTimer = new Timer(100); - m_propertiesPacketTimer.Elapsed += ProcessObjectPropertiesPacket; - m_prioritizer = new Prioritizer(m_scene); RegisterLocalPacketHandlers(); @@ -3636,9 +3632,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); } - private Int32 m_LastQueueFill = 0; - private uint m_maxUpdates = 0; - private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3646,46 +3639,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); + // Check to see if this is a flush if (maxUpdates <= 0) { - m_maxUpdates = Int32.MaxValue; + maxUpdates = Int32.MaxValue; } - else - { - if (m_maxUpdates == 0 || m_LastQueueFill == 0) - { - m_maxUpdates = (uint)maxUpdates; - } - else - { - if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) - m_maxUpdates += 5; - else - m_maxUpdates = m_maxUpdates >> 1; - } - m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); - } - m_LastQueueFill = Util.EnvironmentTickCount(); - + int updatesThisCall = 0; -// -// DEBUGGING CODE... REMOVE -// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates); -// // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race // condition where a kill can be processed before an out-of-date update for the same object. lock (m_killRecord) { float avgTimeDilation = 1.0f; - EntityUpdate update; + IEntityUpdate iupdate; Int32 timeinqueue; // this is just debugging code & can be dropped later - while (updatesThisCall < m_maxUpdates) + while (updatesThisCall < maxUpdates) { lock (m_entityUpdates.SyncRoot) - if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) + if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) break; + + EntityUpdate update = (EntityUpdate)iupdate; + avgTimeDilation += update.TimeDilation; avgTimeDilation *= 0.5f; @@ -3725,7 +3702,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region UpdateFlags to packet type conversion - PrimUpdateFlags updateFlags = update.Flags; + PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; bool canUseCompressed = true; bool canUseImproved = true; @@ -3804,6 +3781,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Block Construction } + #region Packet Sending @@ -3904,12 +3882,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Primitive Packet/Data Sending Methods + // These are used to implement an adaptive backoff in the number + // of updates converted to packets. Since we don't want packets + // to sit in the queue with old data, only convert enough updates + // to packets that can be sent in 200ms. + private Int32 m_LastQueueFill = 0; + private Int32 m_maxUpdates = 0; + void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) { if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) { + if (m_maxUpdates == 0 || m_LastQueueFill == 0) + { + m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; + } + else + { + if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) + m_maxUpdates += 5; + else + m_maxUpdates = m_maxUpdates >> 1; + } + m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); + m_LastQueueFill = Util.EnvironmentTickCount(); + if (m_entityUpdates.Count > 0) - ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback); + ProcessEntityUpdates(m_maxUpdates); + + if (m_entityProps.Count > 0) + ProcessEntityPropertyRequests(m_maxUpdates); } if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) @@ -4023,134 +4025,192 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) - { - ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - // TODO: don't create new blocks if recycling an old packet - - ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - objPropDB.RequestFlags = RequestFlags; - objPropDB.ObjectID = ObjectUUID; - if (OwnerID == GroupID) - objPropDB.OwnerID = UUID.Zero; - else - objPropDB.OwnerID = OwnerID; - objPropDB.GroupID = GroupID; - objPropDB.BaseMask = BaseMask; - objPropDB.OwnerMask = OwnerMask; - objPropDB.GroupMask = GroupMask; - objPropDB.EveryoneMask = EveryoneMask; - objPropDB.NextOwnerMask = NextOwnerMask; +/// ----------------------------------------------------------------- +/// +/// ----------------------------------------------------------------- - // TODO: More properties are needed in SceneObjectPart! - objPropDB.OwnershipCost = OwnershipCost; - objPropDB.SaleType = SaleType; - objPropDB.SalePrice = SalePrice; - objPropDB.Category = Category; - objPropDB.LastOwnerID = LastOwnerID; - objPropDB.Name = Util.StringToBytes256(ObjectName); - objPropDB.Description = Util.StringToBytes256(Description); - objPropFamilyPack.ObjectData = objPropDB; - objPropFamilyPack.Header.Zerocoded = true; - OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task); - } - - public void SendObjectPropertiesReply( - UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + private class ObjectPropertyUpdate : IEntityUpdate { - //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - // TODO: don't create new blocks if recycling an old packet + internal bool SendFamilyProps; + + public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam) + : base(entity,flags) + { + SendFamilyProps = sendfam; + } + } + + public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) + { + uint priority = m_prioritizer.GetUpdatePriority(this, entity); + lock (m_entityProps.SyncRoot) + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true)); + } - ObjectPropertiesPacket.ObjectDataBlock block = - new ObjectPropertiesPacket.ObjectDataBlock(); + public void SendObjectPropertiesReply(ISceneEntity entity) + { + uint priority = m_prioritizer.GetUpdatePriority(this, entity); + lock (m_entityProps.SyncRoot) + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false)); + } - block.ItemID = ItemID; - block.CreationDate = CreationDate; - block.CreatorID = CreatorUUID; - block.FolderID = FolderUUID; - block.FromTaskID = FromTaskUUID; - block.GroupID = GroupUUID; - block.InventorySerial = InventorySerial; + private void ProcessEntityPropertyRequests(int maxUpdates) + { + OpenSim.Framework.Lazy> objectFamilyBlocks = + new OpenSim.Framework.Lazy>(); - block.LastOwnerID = LastOwnerUUID; - // proper.ObjectData[0].LastOwnerID = UUID.Zero; + OpenSim.Framework.Lazy> objectPropertiesBlocks = + new OpenSim.Framework.Lazy>(); - block.ObjectID = ObjectUUID; - if (OwnerUUID == GroupUUID) - block.OwnerID = UUID.Zero; - else - block.OwnerID = OwnerUUID; - block.TouchName = Util.StringToBytes256(TouchTitle); - block.TextureID = TextureID; - block.SitName = Util.StringToBytes256(SitTitle); - block.Name = Util.StringToBytes256(ItemName); - block.Description = Util.StringToBytes256(ItemDescription); - block.OwnerMask = OwnerMask; - block.NextOwnerMask = NextOwnerMask; - block.GroupMask = GroupMask; - block.EveryoneMask = EveryoneMask; - block.BaseMask = BaseMask; - // proper.ObjectData[0].AggregatePerms = 53; - // proper.ObjectData[0].AggregatePermTextures = 0; - // proper.ObjectData[0].AggregatePermTexturesOwner = 0; - block.SaleType = saleType; - block.SalePrice = salePrice; + IEntityUpdate iupdate; + Int32 timeinqueue; // this is just debugging code & can be dropped later - lock (m_propertiesPacketTimer) + int updatesThisCall = 0; + while (updatesThisCall < m_maxUpdates) { - m_propertiesBlocks.Add(block); + lock (m_entityProps.SyncRoot) + if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) + break; - int length = 0; - foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) + ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; + if (update.SendFamilyProps) { - length += b.Length; + if (update.Entity is SceneObjectPart) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); + objectFamilyBlocks.Value.Add(objPropDB); + } } - if (length > 1100) // FIXME: use real MTU + else { - ProcessObjectPropertiesPacket(null, null); - m_propertiesPacketTimer.Stop(); - return; + if (update.Entity is SceneObjectPart) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); + objectPropertiesBlocks.Value.Add(objPropDB); + } } + } + + + if (objectPropertiesBlocks.IsValueCreated) + { + List blocks = objectPropertiesBlocks.Value; - m_propertiesPacketTimer.Stop(); - m_propertiesPacketTimer.Start(); + ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; + for (int i = 0; i < blocks.Count; i++) + packet.ObjectData[i] = blocks[i]; + + packet.Header.Zerocoded = true; + OutPacket(packet, ThrottleOutPacketType.Task, true); } + + + if (objectFamilyBlocks.IsValueCreated) + { + List blocks = objectFamilyBlocks.Value; + + // ObjectPropertiesFamilyPacket objPropFamilyPack = + // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); + // + // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count]; + // for (int i = 0; i < blocks.Count; i++) + // objPropFamilyPack.ObjectData[i] = blocks[i]; + // + // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true); + + // one packet per object block... uggh... + for (int i = 0; i < blocks.Count; i++) + { + ObjectPropertiesFamilyPacket packet = + (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - //proper.Header.Zerocoded = true; - //OutPacket(proper, ThrottleOutPacketType.Task); + packet.ObjectData = blocks[i]; + packet.Header.Zerocoded = true; + OutPacket(packet, ThrottleOutPacketType.Task); + } + + } + } - private void ProcessObjectPropertiesPacket(Object sender, ElapsedEventArgs e) + private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) { - ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - lock (m_propertiesPacketTimer) - { - m_propertiesPacketTimer.Stop(); + block.RequestFlags = requestFlags; + block.ObjectID = sop.UUID; + if (sop.OwnerID == sop.GroupID) + block.OwnerID = UUID.Zero; + else + block.OwnerID = sop.OwnerID; + block.GroupID = sop.GroupID; + block.BaseMask = sop.BaseMask; + block.OwnerMask = sop.OwnerMask; + block.GroupMask = sop.GroupMask; + block.EveryoneMask = sop.EveryoneMask; + block.NextOwnerMask = sop.NextOwnerMask; - proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; + // TODO: More properties are needed in SceneObjectPart! + block.OwnershipCost = sop.OwnershipCost; + block.SaleType = sop.ObjectSaleType; + block.SalePrice = sop.SalePrice; + block.Category = sop.Category; + block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right? + block.Name = Util.StringToBytes256(sop.Name); + block.Description = Util.StringToBytes256(sop.Description); - int index = 0; + return block; + } - foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) - { - proper.ObjectData[index++] = b; - } + private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) + { + //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + // TODO: don't create new blocks if recycling an old packet - m_propertiesBlocks.Clear(); - } + ObjectPropertiesPacket.ObjectDataBlock block = + new ObjectPropertiesPacket.ObjectDataBlock(); + + block.ObjectID = sop.UUID; + block.Name = Util.StringToBytes256(sop.Name); + block.Description = Util.StringToBytes256(sop.Description); - proper.Header.Zerocoded = true; - OutPacket(proper, ThrottleOutPacketType.Task); + block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds + block.CreatorID = sop.CreatorID; + block.GroupID = sop.GroupID; + block.LastOwnerID = sop.LastOwnerID; + if (sop.OwnerID == sop.GroupID) + block.OwnerID = UUID.Zero; + else + block.OwnerID = sop.OwnerID; + + block.ItemID = sop.FromUserInventoryItemID; + block.FolderID = UUID.Zero; // sop.FromFolderID ?? + block.FromTaskID = UUID.Zero; // ??? + block.InventorySerial = (short)sop.InventorySerial; + + SceneObjectPart root = sop.ParentGroup.RootPart; + + block.TouchName = Util.StringToBytes256(root.TouchName); + block.TextureID = new byte[0]; // TextureID ??? + block.SitName = Util.StringToBytes256(root.SitName); + block.OwnerMask = root.OwnerMask; + block.NextOwnerMask = root.NextOwnerMask; + block.GroupMask = root.GroupMask; + block.EveryoneMask = root.EveryoneMask; + block.BaseMask = root.BaseMask; + block.SaleType = root.ObjectSaleType; + block.SalePrice = root.SalePrice; + + return block; } +/// ----------------------------------------------------------------- +/// +/// ----------------------------------------------------------------- + #region Estate Data Sending Methods private static bool convertParamStringToBool(byte[] field) @@ -4489,6 +4549,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendForceClientSelectObjects(List ObjectIDs) { + m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); + bool firstCall = true; const int MAX_OBJECTS_PER_PACKET = 251; ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); @@ -11381,6 +11443,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); } + if (throttlePacketType == ThrottleOutPacketType.Task) + { + System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); // get call stack + System.Diagnostics.StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + + string stack = ""; + for (int count = 1; count < stackFrames.Length; count++) + { + stack += (stack == "" ? "" : ",") + stackFrames[count].GetMethod().Name; + if (count > 5) break; + } + + // m_log.WarnFormat("[BADGUY] {0}", stack); + } + m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 364ce4b..6521a00 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -78,7 +78,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public bool Enqueue(uint pqueue, EntityUpdate value) + public bool Enqueue(uint pqueue, IEntityUpdate value) { LookupItem lookup; @@ -99,7 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } - internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) + internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) { for (int i = 0; i < m_numberOfQueues; ++i) { @@ -122,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } timeinqueue = 0; - value = default(EntityUpdate); + value = default(IEntityUpdate); return false; } @@ -175,8 +175,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region MinHeapItem private struct MinHeapItem : IComparable { - private EntityUpdate value; - internal EntityUpdate Value { + private IEntityUpdate value; + internal IEntityUpdate Value { get { return this.value; } @@ -212,7 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP this.pqueue = pqueue; } - internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) + internal MinHeapItem(uint pqueue, UInt64 entryorder, IEntityUpdate value) { this.entrytime = Util.EnvironmentTickCount(); this.entryorder = entryorder; diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index d939329..89e9e20 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -702,18 +702,12 @@ namespace OpenSim.Region.Examples.SimpleModule { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { + } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index ca7d9d9..30563d4 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1765,10 +1765,12 @@ namespace OpenSim.Region.Framework.Scenes /// public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) { - remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, - RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, - RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, - RootPart.CreatorID, RootPart.Name, RootPart.Description); + remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); + +// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, +// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, +// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, +// RootPart.CreatorID, RootPart.Name, RootPart.Description); } public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ce1e6b8..8a8a699 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2055,15 +2055,7 @@ namespace OpenSim.Region.Framework.Scenes public void GetProperties(IClientAPI client) { - //Viewer wants date in microseconds so multiply it by 1,000,000. - client.SendObjectPropertiesReply( - m_fromUserInventoryItemID, (ulong)_creationDate*(ulong)1e6, _creatorID, UUID.Zero, UUID.Zero, - _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID, - ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description, - ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask, - ParentGroup.RootPart._baseMask, - ParentGroup.RootPart.ObjectSaleType, - ParentGroup.RootPart.SalePrice); + client.SendObjectPropertiesReply(this); } public UUID GetRootPartUUID() diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 821cd4b..4b6e52e 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1332,14 +1332,13 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { - } public void SendAgentOffline(UUID[] agentIDs) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 96760a2..2504e30 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -786,18 +786,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { + } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index d1dc17f..dca5626 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -816,18 +816,11 @@ namespace OpenSim.Tests.Common.Mock { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } -- cgit v1.1 From 5e7aba4f88a90e266e01b5509c4ba04730815475 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 14:40:57 -0700 Subject: fixed a couple bugs with the property queues --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 38 +++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 33b9909..f926c35 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4091,9 +4091,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectPropertiesBlocks.Value.Add(objPropDB); } } + + updatesThisCall++; } + Int32 ppcnt = 0; + Int32 pbcnt = 0; + if (objectPropertiesBlocks.IsValueCreated) { List blocks = objectPropertiesBlocks.Value; @@ -4105,9 +4110,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Header.Zerocoded = true; OutPacket(packet, ThrottleOutPacketType.Task, true); + + pbcnt += blocks.Count; + ppcnt++; } + Int32 fpcnt = 0; + Int32 fbcnt = 0; + if (objectFamilyBlocks.IsValueCreated) { List blocks = objectFamilyBlocks.Value; @@ -4130,10 +4141,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.ObjectData = blocks[i]; packet.Header.Zerocoded = true; OutPacket(packet, ThrottleOutPacketType.Task); + + fpcnt++; + fbcnt++; } } + m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); + m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); } private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) @@ -11408,6 +11424,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, throttlePacketType, true); } +/// + Dictionary pktsrc = new Dictionary(); + uint pktcnt = 0; +/// + /// /// This is the starting point for sending a simulator packet out to the client /// @@ -11455,7 +11476,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (count > 5) break; } - // m_log.WarnFormat("[BADGUY] {0}", stack); + lock(pktsrc) + { + if (! pktsrc.ContainsKey(stack)) + pktsrc.Add(stack,0); + pktsrc[stack]++; + + if (++pktcnt > 500) + { + pktcnt = 0; + m_log.WarnFormat("[PACKETCOUNTS] START"); + foreach (KeyValuePair pkt in pktsrc) + m_log.WarnFormat("[PACKETCOUNTS] {0,8}, {1}", pkt.Value, pkt.Key); + pktsrc.Clear(); + m_log.WarnFormat("[PACKETCOUNTS] END"); + } + } } m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); -- cgit v1.1 From b33aac737a3e7ae28216cb98de99d9c6eba1d563 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 15:40:57 -0700 Subject: Fixed the update of items in the priority queue to enable both types of property updates to be specified. Not sure if one form of property update should supercede another. But for now the old OpenSim behavior is preserved by sending both. --- OpenSim/Framework/IClientAPI.cs | 5 +++++ .../Region/ClientStack/LindenUDP/LLClientView.cs | 21 +++++++++++++++------ .../Region/ClientStack/LindenUDP/PriorityQueue.cs | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index c56a756..f573c32 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -575,6 +575,11 @@ namespace OpenSim.Framework public ISceneEntity Entity; public uint Flags; + public virtual void Update(IEntityUpdate update) + { + this.Flags |= update.Flags; + } + public IEntityUpdate(ISceneEntity entity, uint flags) { Entity = entity; diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index f926c35..a6f2d09 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4032,26 +4032,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP private class ObjectPropertyUpdate : IEntityUpdate { internal bool SendFamilyProps; + internal bool SendObjectProps; - public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam) + public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) : base(entity,flags) { SendFamilyProps = sendfam; + SendObjectProps = sendobj; + } + public void Update(ObjectPropertyUpdate update) + { + SendFamilyProps = SendFamilyProps || update.SendFamilyProps; + SendObjectProps = SendObjectProps || update.SendObjectProps; + Flags |= update.Flags; } } public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) { - uint priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); } public void SendObjectPropertiesReply(ISceneEntity entity) { - uint priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); } private void ProcessEntityPropertyRequests(int maxUpdates) @@ -4082,7 +4090,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectFamilyBlocks.Value.Add(objPropDB); } } - else + + if (update.SendObjectProps) { if (update.Entity is SceneObjectPart) { diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 6521a00..b62ec07 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_lookupTable.TryGetValue(localid, out lookup)) { entry = lookup.Heap[lookup.Handle].EntryOrder; - value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; + value.Update(lookup.Heap[lookup.Handle].Value); lookup.Heap.Remove(lookup.Handle); } -- cgit v1.1 From bf91d1b07784f3c03744efd2d6dea1b621620cce Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 15:55:21 -0700 Subject: remove packet monitoring debugging code --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 118 +-------------------- 1 file changed, 2 insertions(+), 116 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index a6f2d09..613a921 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -300,77 +300,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Used to adjust Sun Orbit values so Linden based viewers properly position sun private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; - // First log file or time has expired, start writing to a new log file -// -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// THIS IS DEBUGGING CODE & SHOULD BE REMOVED -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- - public class QueueLogger - { - public Int32 start = 0; - public StreamWriter Log = null; - private Dictionary m_idMap = new Dictionary(); - - public QueueLogger() - { - DateTime now = DateTime.Now; - String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); - Log = new StreamWriter(fname); - - start = Util.EnvironmentTickCount(); - } - - public int LookupID(UUID uuid) - { - int localid; - if (! m_idMap.TryGetValue(uuid,out localid)) - { - localid = m_idMap.Count + 1; - m_idMap[uuid] = localid; - } - - return localid; - } - } - - public static QueueLogger QueueLog = null; - - // ----------------------------------------------------------------- - public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - int aid = QueueLog.LookupID(avatar); - QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); - } - } - - // ----------------------------------------------------------------- - public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); - } - } -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients @@ -4025,10 +3954,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } -/// ----------------------------------------------------------------- -/// -/// ----------------------------------------------------------------- - private class ObjectPropertyUpdate : IEntityUpdate { internal bool SendFamilyProps; @@ -4157,8 +4082,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } - m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); - m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); + // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); + // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); } private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) @@ -4232,10 +4157,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return block; } -/// ----------------------------------------------------------------- -/// -/// ----------------------------------------------------------------- - #region Estate Data Sending Methods private static bool convertParamStringToBool(byte[] field) @@ -11433,11 +11354,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, throttlePacketType, true); } -/// - Dictionary pktsrc = new Dictionary(); - uint pktcnt = 0; -/// - /// /// This is the starting point for sending a simulator packet out to the client /// @@ -11472,36 +11388,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (logPacket) m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); } - - if (throttlePacketType == ThrottleOutPacketType.Task) - { - System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); // get call stack - System.Diagnostics.StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) - - string stack = ""; - for (int count = 1; count < stackFrames.Length; count++) - { - stack += (stack == "" ? "" : ",") + stackFrames[count].GetMethod().Name; - if (count > 5) break; - } - - lock(pktsrc) - { - if (! pktsrc.ContainsKey(stack)) - pktsrc.Add(stack,0); - pktsrc[stack]++; - - if (++pktcnt > 500) - { - pktcnt = 0; - m_log.WarnFormat("[PACKETCOUNTS] START"); - foreach (KeyValuePair pkt in pktsrc) - m_log.WarnFormat("[PACKETCOUNTS] {0,8}, {1}", pkt.Value, pkt.Key); - pktsrc.Clear(); - m_log.WarnFormat("[PACKETCOUNTS] END"); - } - } - } m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); } -- cgit v1.1 From 6ed6b46aad85b66dd3c50fcf17d108a8da42c5ff Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Wed, 13 Apr 2011 21:01:51 -0700 Subject: Comment out the warning if the prioritizer runs without a fully initialized scene presence. Not sure why we are dumping updates to a client that isn't there yet... --- OpenSim/Region/Framework/Scenes/Prioritizer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index 4694e2b..e3ed905 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -166,7 +166,11 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence presence = m_scene.GetScenePresence(client.AgentId); if (presence == null) { - m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); + // this shouldn't happen, it basically means that we are prioritizing + // updates to send to a client that doesn't have a presence in the scene + // seems like there's race condition here... + + // m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); // throw new InvalidOperationException("Prioritization agent not defined"); return Int32.MaxValue; } -- cgit v1.1 From aaf912586948a3d0d9bb918952766ba48e90fd18 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Apr 2011 17:33:55 +0100 Subject: simplify coalesced object tests by using existing scene object set up utils this change makes it possible to set an absolute position on a group before it is put into a scene. --- .../Tests/InventoryAccessModuleTests.cs | 40 ++++------------------ .../Region/Framework/Scenes/SceneObjectGroup.cs | 21 ++++++++---- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index c76a30a..9fc77a7 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -87,41 +87,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests // log4net.Config.XmlConfigurator.Configure(); // Create asset - SceneObjectGroup object1; - { - string partName = "Object1"; - UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); - PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); - Vector3 groupPosition = new Vector3(10, 20, 30); - Quaternion rotationOffset = Quaternion.Identity; - Vector3 offsetPosition = new Vector3(5, 10, 15); - - SceneObjectPart part1 - = new SceneObjectPart( - ownerId, shape, groupPosition, rotationOffset, offsetPosition); - part1.Scale = new Vector3(1, 1, 1); - part1.Name = partName; - - object1 = new SceneObjectGroup(part1); - } + SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, m_userId, "Object1", 0x20); + object1.AbsolutePosition = new Vector3(15, 30, 45); + object1.Parts[0].Scale = new Vector3(1, 1, 1); - SceneObjectGroup object2; - { - string partName = "Object2"; - UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); - PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); - Vector3 groupPosition = new Vector3(20, 40, 60); - Quaternion rotationOffset = Quaternion.Identity; - Vector3 offsetPosition = new Vector3(5, 10, 15); - - SceneObjectPart part1 - = new SceneObjectPart( - ownerId, shape, groupPosition, rotationOffset, offsetPosition); - part1.Scale = new Vector3(1, 1, 1); - part1.Name = partName; - - object2 = new SceneObjectGroup(part1); - } + SceneObjectGroup object2 = SceneSetupHelpers.CreateSceneObject(1, m_userId, "Object2", 0x40); + object2.AbsolutePosition = new Vector3(25, 50, 75); + object2.Parts[0].Scale = new Vector3(1, 1, 1); CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index ca7d9d9..9bb50db 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -296,11 +296,14 @@ namespace OpenSim.Region.Framework.Scenes { Vector3 val = value; - if ((m_scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || m_scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) - || m_scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || m_scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) - && !IsAttachmentCheckFull() && (!m_scene.LoadingPrims)) + if (Scene != null) { - m_scene.CrossPrimGroupIntoNewRegion(val, this, true); + if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) + || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) + && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) + { + m_scene.CrossPrimGroupIntoNewRegion(val, this, true); + } } if (RootPart.GetStatusSandbox()) @@ -308,8 +311,11 @@ namespace OpenSim.Region.Framework.Scenes if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) { RootPart.ScriptSetPhysicsStatus(false); - Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), - ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); + + if (Scene != null) + Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), + ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); + return; } } @@ -326,7 +332,8 @@ namespace OpenSim.Region.Framework.Scenes //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); //} - m_scene.EventManager.TriggerParcelPrimCountTainted(); + if (Scene != null) + Scene.EventManager.TriggerParcelPrimCountTainted(); } } -- cgit v1.1 From c644ab6a2c902c829a0dc88d08780a4411b4cd29 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Apr 2011 20:21:44 +0100 Subject: Make scene object parts created by the test utils unit sized. --- .../Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs | 4 +--- OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 9fc77a7..60a932d 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -89,11 +89,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests // Create asset SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, m_userId, "Object1", 0x20); object1.AbsolutePosition = new Vector3(15, 30, 45); - object1.Parts[0].Scale = new Vector3(1, 1, 1); SceneObjectGroup object2 = SceneSetupHelpers.CreateSceneObject(1, m_userId, "Object2", 0x40); - object2.AbsolutePosition = new Vector3(25, 50, 75); - object2.Parts[0].Scale = new Vector3(1, 1, 1); + object2.AbsolutePosition = new Vector3(25, 50, 75); CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index 709dd78..eb08b62 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -472,10 +472,10 @@ namespace OpenSim.Tests.Common.Setup /// /// public static SceneObjectPart CreateSceneObjectPart(string name, UUID id, UUID ownerId) - { + { return new SceneObjectPart( ownerId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) - { Name = name, UUID = id }; + { Name = name, UUID = id, Scale = new Vector3(1, 1, 1) }; } /// -- cgit v1.1 From e4392648248d11699772aac42db753ae4f84495f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Apr 2011 20:23:48 +0100 Subject: simplify TestRezObject() --- .../Tests/InventoryAccessModuleTests.cs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 60a932d..7a7a8c2 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -143,23 +143,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests // log4net.Config.XmlConfigurator.Configure(); // Create asset - SceneObjectGroup object1; - SceneObjectPart part1; - { - string partName = "My Little Dog Object"; - UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); - PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); - Vector3 groupPosition = new Vector3(10, 20, 30); - Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); - Vector3 offsetPosition = new Vector3(5, 10, 15); - - part1 - = new SceneObjectPart( - ownerId, shape, groupPosition, rotationOffset, offsetPosition); - part1.Name = partName; - - object1 = new SceneObjectGroup(part1); - } + SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, m_userId, "My Little Dog Object", 0x40); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); -- cgit v1.1 From 1569148b49f188f3c46f9fd8ffa096efc70f72fa Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Apr 2011 20:32:27 +0100 Subject: simplify TestSaveItemToIarV0_1() --- .../Archiver/Tests/InventoryArchiverTests.cs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index 7f156f8..9e3e7d4 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -84,24 +84,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests UserProfileTestUtils.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); // Create asset - SceneObjectGroup object1; - SceneObjectPart part1; - { - string partName = "My Little Dog Object"; - UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); - PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); - Vector3 groupPosition = new Vector3(10, 20, 30); - Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); - Vector3 offsetPosition = new Vector3(5, 10, 15); - - part1 - = new SceneObjectPart( - ownerId, shape, groupPosition, rotationOffset, offsetPosition); - part1.Name = partName; - - object1 = new SceneObjectGroup(part1); - m_scene.AddNewSceneObject(object1, false); - } + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); -- cgit v1.1 From 55387542eaae8ab27c4709ae5b923d9d2d2a4431 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Apr 2011 20:35:00 +0100 Subject: simplify InventoryArchiveTestCase setup --- .../Archiver/Tests/InventoryArchiveTestCase.cs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs index e5127a0..7ee6f28 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs @@ -105,24 +105,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests MemoryStream archiveWriteStream = new MemoryStream(); // Create asset - SceneObjectGroup object1; - SceneObjectPart part1; - { - string partName = "Ray Gun Object"; - UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); - PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); - Vector3 groupPosition = new Vector3(10, 20, 30); - Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); - Vector3 offsetPosition = new Vector3(5, 10, 15); - - part1 - = new SceneObjectPart( - ownerId, shape, groupPosition, rotationOffset, offsetPosition); - part1.Name = partName; - - object1 = new SceneObjectGroup(part1); - scene.AddNewSceneObject(object1, false); - } + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, ownerId, "Ray Gun Object", 0x50); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); -- cgit v1.1 From 821e67fb950721c0bb8105318e41d7982cf986f2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Apr 2011 20:59:52 +0100 Subject: implement stub TestLoadCoalesecedItem(). Doesn't do what it's meant to do yet. --- .../Archiver/Tests/InventoryArchiveTestCase.cs | 35 +++++++++++++++++++--- .../Archiver/Tests/InventoryArchiverTests.cs | 17 +++++++++++ OpenSim/Tests/Common/Setup/AssetHelpers.cs | 18 +++++++++-- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs index 7ee6f28..f2d050c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs @@ -68,17 +68,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000555"), FirstName = "Mr", LastName = "Tiddles" }; + protected UserAccount m_uaLL1 = new UserAccount { PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000666"), FirstName = "Lord", LastName = "Lucan" }; + protected UserAccount m_uaLL2 = new UserAccount { PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000777"), FirstName = "Lord", - LastName = "Lucan" }; + LastName = "Lucan" }; + protected string m_item1Name = "Ray Gun Item"; + protected string m_coaItemName = "Coalesced Item"; [SetUp] public virtual void SetUp() @@ -104,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests MemoryStream archiveWriteStream = new MemoryStream(); - // Create asset + // Create scene object asset UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, ownerId, "Ray Gun Object", 0x50); @@ -112,7 +116,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); scene.AssetService.Store(asset1); - // Create item + // Create scene object item InventoryItemBase item1 = new InventoryItemBase(); item1.Name = m_item1Name; item1.ID = UUID.Parse("00000000-0000-0000-0000-000000000020"); @@ -123,8 +127,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests item1.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID; scene.AddInventoryItem(item1); + // Create coalesced objects asset + SceneObjectGroup cobj1 = SceneSetupHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object1", 0x120); + cobj1.AbsolutePosition = new Vector3(15, 30, 45); + + SceneObjectGroup cobj2 = SceneSetupHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object2", 0x140); + cobj2.AbsolutePosition = new Vector3(25, 50, 75); + + CoalescedSceneObjects coa = new CoalescedSceneObjects(m_uaLL1.PrincipalID, cobj1, cobj2); + + AssetBase coaAsset = AssetHelpers.CreateAsset(0x160, coa); + scene.AssetService.Store(coaAsset); + + // Create coalesced objects inventory item + InventoryItemBase coaItem = new InventoryItemBase(); + coaItem.Name = m_coaItemName; + coaItem.ID = UUID.Parse("00000000-0000-0000-0000-000000000180"); + coaItem.AssetID = asset1.FullID; + coaItem.GroupID = UUID.Random(); + coaItem.CreatorIdAsUuid = m_uaLL1.PrincipalID; + coaItem.Owner = m_uaLL1.PrincipalID; + coaItem.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID; + scene.AddInventoryItem(coaItem); + archiverModule.ArchiveInventory( - Guid.NewGuid(), m_uaLL1.FirstName, m_uaLL1.LastName, m_item1Name, "hampshire", archiveWriteStream); + Guid.NewGuid(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream); m_iarStreamBytes = archiveWriteStream.ToArray(); } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index 9e3e7d4..0c4e364 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -257,5 +257,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID)); } + + [Test] + public void TestLoadCoalesecedItem() + { + TestHelper.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UserProfileTestUtils.CreateUserWithInventory(m_scene, m_uaLL1, "password"); + m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); + + InventoryItemBase coaItem + = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName); + + Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1"); + + // TODO: Check that the loaded coalesence is valid and that the required scene object assets are around + } } } \ No newline at end of file diff --git a/OpenSim/Tests/Common/Setup/AssetHelpers.cs b/OpenSim/Tests/Common/Setup/AssetHelpers.cs index af66d7f..971c6bc 100644 --- a/OpenSim/Tests/Common/Setup/AssetHelpers.cs +++ b/OpenSim/Tests/Common/Setup/AssetHelpers.cs @@ -55,7 +55,7 @@ namespace OpenSim.Tests.Common AssetBase asset = CreateAsset(UUID.Random(), AssetType.Notecard, "hello", creatorId); scene.AssetService.Store(asset); return asset; - } + } /// /// Create an asset from the given scene object. @@ -75,6 +75,20 @@ namespace OpenSim.Tests.Common /// /// Create an asset from the given scene object. /// + /// + /// The hexadecimal last part of the UUID for the asset created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" + /// will be used. + /// + /// + /// + public static AssetBase CreateAsset(int assetUuidTail, CoalescedSceneObjects coa) + { + return CreateAsset(new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", assetUuidTail)), coa); + } + + /// + /// Create an asset from the given scene object. + /// /// /// /// @@ -85,7 +99,7 @@ namespace OpenSim.Tests.Common AssetType.Object, Encoding.ASCII.GetBytes(CoalescedSceneObjectsSerializer.ToXml(coa)), coa.CreatorId); - } + } /// /// Create an asset from the given data. -- cgit v1.1 From a0d80140f2d0ad6dd63970a3a3d5c0da8320ae75 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 00:42:06 +0100 Subject: Make all the objects in a coalescence reappears after being loaded from an IAR. This still doesn't work proprerly since some required textures/contained item assets might be missing. From pure code inspection, it looks like the uuid gatherer may get most asset uuids because the scene object serializer naively pulls non-root parts from all contained scene objects into one mega-object. However, root part uuids may well still be missing, and there may be other odd artifacts from this bug. It appears that storing the size of the coalescence and the offsets is redundant, since one can work out this information from the position data already in the scene object groups. --- .../Archiver/InventoryArchiveReadRequest.cs | 28 +++++++++---- .../Archiver/Tests/InventoryArchiveTestCase.cs | 2 +- .../Archiver/Tests/InventoryArchiverTests.cs | 43 +++++++++++--------- .../Asset/LocalAssetServiceConnector.cs | 2 + .../CoalescedSceneObjectsSerializer.cs | 47 +++++++++++++++++++--- OpenSim/Services/AssetService/AssetService.cs | 10 ++++- OpenSim/Services/Interfaces/IAssetService.cs | 5 +++ OpenSim/Tests/Common/Mock/MockAssetService.cs | 22 ++++++++-- OpenSim/Tests/Common/Setup/AssetHelpers.cs | 7 ++++ OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs | 7 +++- 10 files changed, 134 insertions(+), 39 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 01170aa..f3d2f26 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -471,16 +471,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (m_creatorIdForAssetId.ContainsKey(assetId)) { string xmlData = Utils.BytesToString(data); - SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); - foreach (SceneObjectPart sop in sog.Parts) + List sceneObjects = new List(); + + CoalescedSceneObjects coa = null; + if (CoalescedSceneObjectsSerializer.TryFromXml(xmlData, out coa)) + { +// m_log.DebugFormat( +// "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count); + + sceneObjects.AddRange(coa.Objects); + } + else { - if (sop.CreatorData == null || sop.CreatorData == "") - { - sop.CreatorID = m_creatorIdForAssetId[assetId]; - } + sceneObjects.Add(SceneObjectSerializer.FromOriginalXmlFormat(xmlData)); } - data = Utils.StringToBytes(SceneObjectSerializer.ToOriginalXmlFormat(sog)); + foreach (SceneObjectGroup sog in sceneObjects) + foreach (SceneObjectPart sop in sog.Parts) + if (sop.CreatorData == null || sop.CreatorData == "") + sop.CreatorID = m_creatorIdForAssetId[assetId]; + + if (coa != null) + data = Utils.StringToBytes(CoalescedSceneObjectsSerializer.ToXml(coa)); + else + data = Utils.StringToBytes(SceneObjectSerializer.ToOriginalXmlFormat(sceneObjects[0])); } } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs index f2d050c..e2316f0 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs @@ -143,7 +143,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryItemBase coaItem = new InventoryItemBase(); coaItem.Name = m_coaItemName; coaItem.ID = UUID.Parse("00000000-0000-0000-0000-000000000180"); - coaItem.AssetID = asset1.FullID; + coaItem.AssetID = coaAsset.FullID; coaItem.GroupID = UUID.Random(); coaItem.CreatorIdAsUuid = m_uaLL1.PrincipalID; coaItem.Owner = m_uaLL1.PrincipalID; diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index 0c4e364..f747c89 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -62,9 +62,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests SerialiserModule serialiserModule = new SerialiserModule(); m_archiverModule = new InventoryArchiverModule(); - m_scene = SceneSetupHelpers.SetupScene("Inventory"); + m_scene = SceneSetupHelpers.SetupScene("asset inventory"); SceneSetupHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); } + + [Test] + public void TestLoadCoalesecedItem() + { + TestHelper.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UserProfileTestUtils.CreateUserWithInventory(m_scene, m_uaLL1, "password"); + m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); + + InventoryItemBase coaItem + = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName); + + Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1"); + + string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID); + + CoalescedSceneObjects coa; + bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa); + + Assert.That(readResult, Is.True); + + // TODO: Check that the loaded coalesence is valid and that the required scene object assets are around + } /// /// Test saving a single inventory item to a V0.1 OpenSim Inventory Archive @@ -257,22 +281,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID)); } - - [Test] - public void TestLoadCoalesecedItem() - { - TestHelper.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - - UserProfileTestUtils.CreateUserWithInventory(m_scene, m_uaLL1, "password"); - m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); - - InventoryItemBase coaItem - = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName); - - Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1"); - - // TODO: Check that the loaded coalesence is valid and that the required scene object assets are around - } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 1b3419d..51d1d59 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs @@ -195,6 +195,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset public byte[] GetData(string id) { +// m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Requesting data for asset {0}", id); + AssetBase asset = m_Cache.Get(id); if (asset != null) diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index a0e120a..babcb54 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -55,11 +55,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization /// /// public static string ToXml(CoalescedSceneObjects coa) - { - // TODO: Should probably return an empty xml serialization rather than a blank string - if (!coa.HasObjects) - return ""; - + { using (StringWriter sw = new StringWriter()) { using (XmlTextWriter writer = new XmlTextWriter(sw)) @@ -105,10 +101,49 @@ namespace OpenSim.Region.Framework.Scenes.Serialization string output = sw.ToString(); -// m_log.Debug(output); +// Console.WriteLine(output); return output; } } + + public static bool TryFromXml(string xml, out CoalescedSceneObjects coa) + { +// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml); + + coa = null; + + using (StringReader sr = new StringReader(xml)) + { + using (XmlTextReader reader = new XmlTextReader(sr)) + { + reader.Read(); + if (reader.Name != "CoalescedObject") + { +// m_log.DebugFormat( +// "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", +// reader.Name); + + return false; + } + + coa = new CoalescedSceneObjects(UUID.Zero); + reader.Read(); + + while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "CoalescedObject") + { + if (reader.Name == "SceneObjectGroup") + { + string soXml = reader.ReadOuterXml(); + coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml)); + } + } + + reader.ReadEndElement(); // CoalescedObject + } + } + + return true; + } } } \ No newline at end of file diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index a81af43..e1f90b6 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -89,6 +89,8 @@ namespace OpenSim.Services.AssetService public virtual AssetBase Get(string id) { +// m_log.DebugFormat("[ASSET SERVICE]: Get asset for {0}", id); + UUID assetID; if (!UUID.TryParse(id, out assetID)) @@ -107,6 +109,8 @@ namespace OpenSim.Services.AssetService public virtual AssetMetadata GetMetadata(string id) { +// m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id); + UUID assetID; if (!UUID.TryParse(id, out assetID)) @@ -121,6 +125,8 @@ namespace OpenSim.Services.AssetService public virtual byte[] GetData(string id) { +// m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", id); + UUID assetID; if (!UUID.TryParse(id, out assetID)) @@ -150,7 +156,9 @@ namespace OpenSim.Services.AssetService public virtual string Store(AssetBase asset) { - //m_log.DebugFormat("[ASSET SERVICE]: Store asset {0} {1}", asset.Name, asset.ID); +// m_log.DebugFormat( +// "[ASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.ID, asset.Data.Length); + m_Database.StoreAsset(asset); return asset.ID; diff --git a/OpenSim/Services/Interfaces/IAssetService.cs b/OpenSim/Services/Interfaces/IAssetService.cs index 3be6815..1ac1cec 100644 --- a/OpenSim/Services/Interfaces/IAssetService.cs +++ b/OpenSim/Services/Interfaces/IAssetService.cs @@ -48,6 +48,11 @@ namespace OpenSim.Services.Interfaces /// AssetMetadata GetMetadata(string id); + /// + /// Get an asset's data, ignoring the metadata. + /// + /// + /// null if there is no such asset byte[] GetData(string id); /// diff --git a/OpenSim/Tests/Common/Mock/MockAssetService.cs b/OpenSim/Tests/Common/Mock/MockAssetService.cs index 4118308..9d7c5e2 100644 --- a/OpenSim/Tests/Common/Mock/MockAssetService.cs +++ b/OpenSim/Tests/Common/Mock/MockAssetService.cs @@ -54,13 +54,19 @@ namespace OpenSim.Tests.Common.Mock public AssetBase Get(string id) { - m_log.DebugFormat("[MOCK ASSET SERVICE]: Getting asset with id {0}", id); +// m_log.DebugFormat("[MOCK ASSET SERVICE]: Getting asset with id {0}", id); AssetBase asset; if (Assets.ContainsKey(id)) + { asset = Assets[id]; +// m_log.DebugFormat( +// "[MOCK ASSET SERVICE]: Got asset {0} {1}, bytes {2}", asset.Name, asset.ID, asset.Data.Length); + } else - asset = null; + { + asset = null; + } return asset; } @@ -77,7 +83,14 @@ namespace OpenSim.Tests.Common.Mock public byte[] GetData(string id) { - throw new System.NotImplementedException(); +// m_log.DebugFormat("[MOCK ASSET SERVICE]: Requesting data for asset {0}", id); + + AssetBase asset = Get(id); + + if (asset == null) + return null; + else + return asset.Data; } public bool Get(string id, object sender, AssetRetrieved handler) @@ -89,7 +102,8 @@ namespace OpenSim.Tests.Common.Mock public string Store(AssetBase asset) { - m_log.DebugFormat("[MOCK ASSET SERVICE]: Storing asset {0}", asset.ID); +// m_log.DebugFormat( +// "[MOCK ASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.ID, asset.Data.Length); Assets[asset.ID] = asset; diff --git a/OpenSim/Tests/Common/Setup/AssetHelpers.cs b/OpenSim/Tests/Common/Setup/AssetHelpers.cs index 971c6bc..d572249 100644 --- a/OpenSim/Tests/Common/Setup/AssetHelpers.cs +++ b/OpenSim/Tests/Common/Setup/AssetHelpers.cs @@ -30,6 +30,7 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; namespace OpenSim.Tests.Common { @@ -118,5 +119,11 @@ namespace OpenSim.Tests.Common asset.Data = data; return asset; } + + public static string ReadAssetAsString(IAssetService assetService, UUID uuid) + { + byte[] assetData = assetService.GetData(uuid.ToString()); + return Encoding.ASCII.GetString(assetData); + } } } diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index eb08b62..837f4e2 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -168,14 +168,17 @@ namespace OpenSim.Tests.Common.Setup { LocalAssetServicesConnector assetService = new LocalAssetServicesConnector(); IConfigSource config = new IniConfigSource(); - config.AddConfig("Modules"); - config.AddConfig("AssetService"); + config.AddConfig("Modules"); config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); + + config.AddConfig("AssetService"); if (real) config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); else config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Tests.Common.dll:MockAssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + assetService.Initialise(config); assetService.AddRegion(testScene); assetService.RegionLoaded(testScene); -- cgit v1.1 From ad70cddcfc48182f75be7643297cea2a9d20ac91 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 00:56:40 +0100 Subject: extend TestLoadCoalesecedItem() to check loaded object ids and positions --- .../Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index f747c89..69c5dcd 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -86,8 +86,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa); Assert.That(readResult, Is.True); + Assert.That(coa.Count, Is.EqualTo(2)); - // TODO: Check that the loaded coalesence is valid and that the required scene object assets are around + List coaObjects = coa.Objects; + Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120"))); + Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45))); + + Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140"))); + Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); } /// -- cgit v1.1 From 79bd430e08b9e8612194d9b02504f8f4acd889f6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 01:10:26 +0100 Subject: Remove the mock inventory service for tests and just use the real one all the time with an in-memory data plugin --- OpenSim/Tests/Common/Mock/MockInventoryService.cs | 186 ---------------------- OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs | 19 +-- 2 files changed, 6 insertions(+), 199 deletions(-) delete mode 100644 OpenSim/Tests/Common/Mock/MockInventoryService.cs diff --git a/OpenSim/Tests/Common/Mock/MockInventoryService.cs b/OpenSim/Tests/Common/Mock/MockInventoryService.cs deleted file mode 100644 index 4ac1078..0000000 --- a/OpenSim/Tests/Common/Mock/MockInventoryService.cs +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using OpenSim.Framework; -using OpenMetaverse; -using OpenSim.Services.Interfaces; -using Nini.Config; - -namespace OpenSim.Tests.Common.Mock -{ - public class MockInventoryService : IInventoryService - { - public MockInventoryService() {} - - public MockInventoryService(IConfigSource config) {} - - /// - /// - /// - /// - /// - public bool CreateUserInventory(UUID userId) - { - return false; - } - - /// - /// - /// - /// - /// - public List GetInventorySkeleton(UUID userId) - { - List folders = new List(); - InventoryFolderBase folder = new InventoryFolderBase(); - folder.ID = UUID.Random(); - folder.Owner = userId; - folders.Add(folder); - return folders; - } - - public InventoryFolderBase GetRootFolder(UUID userID) - { - return new InventoryFolderBase(); - } - - public InventoryCollection GetFolderContent(UUID userID, UUID folderID) - { - return null; - } - - public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) - { - return null; - } - - /// - /// Returns a list of all the active gestures in a user's inventory. - /// - /// - /// The of the user - /// - /// - /// A flat list of the gesture items. - /// - public List GetActiveGestures(UUID userId) - { - return null; - } - - public InventoryCollection GetUserInventory(UUID userID) - { - return null; - } - - public void GetUserInventory(UUID userID, OpenSim.Services.Interfaces.InventoryReceiptCallback callback) - { - } - - public List GetFolderItems(UUID userID, UUID folderID) - { - return null; - } - - public bool AddFolder(InventoryFolderBase folder) - { - return false; - } - - public bool UpdateFolder(InventoryFolderBase folder) - { - return false; - } - - public bool MoveFolder(InventoryFolderBase folder) - { - return false; - } - - public bool DeleteFolders(UUID ownerID, List ids) - { - return false; - } - - public bool PurgeFolder(InventoryFolderBase folder) - { - return false; - } - - public bool AddItem(InventoryItemBase item) - { - return true; - } - - public bool UpdateItem(InventoryItemBase item) - { - return false; - } - - public bool MoveItems(UUID ownerID, List items) - { - return false; - } - - public bool DeleteItems(UUID ownerID, List itemIDs) - { - return false; - } - - public InventoryItemBase GetItem(InventoryItemBase item) - { - return null; - } - - public InventoryFolderBase GetFolder(InventoryFolderBase folder) - { - return null; - } - - public bool HasInventoryForUser(UUID userID) - { - return false; - } - - public InventoryFolderBase RequestRootFolder(UUID userID) - { - InventoryFolderBase root = new InventoryFolderBase(); - root.ID = UUID.Random(); - root.Owner = userID; - root.ParentID = UUID.Zero; - return root; - } - - public int GetAssetPermissions(UUID userID, UUID assetID) - { - return 1; - } - } -} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index 837f4e2..97d4ace 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -137,7 +137,7 @@ namespace OpenSim.Tests.Common.Setup // For now, always started a 'real' authentication service StartAuthenticationService(testScene, true); - LocalInventoryServicesConnector inventoryService = StartInventoryService(testScene, realServices.Contains("inventory")); + LocalInventoryServicesConnector inventoryService = StartInventoryService(testScene); StartGridService(testScene, true); LocalUserAccountServicesConnector userAccountService = StartUserAccountService(testScene); LocalPresenceServicesConnector presenceService = StartPresenceService(testScene); @@ -208,24 +208,17 @@ namespace OpenSim.Tests.Common.Setup //m_authenticationService = service; } - private static LocalInventoryServicesConnector StartInventoryService(Scene testScene, bool real) + private static LocalInventoryServicesConnector StartInventoryService(Scene testScene) { LocalInventoryServicesConnector inventoryService = new LocalInventoryServicesConnector(); - IConfigSource config = new IniConfigSource(); + + IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); config.AddConfig("InventoryService"); config.Configs["Modules"].Set("InventoryServices", "LocalInventoryServicesConnector"); - - if (real) - { - config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:InventoryService"); - } - else - { - config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Tests.Common.dll:MockInventoryService"); - } - + config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:InventoryService"); config.Configs["InventoryService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + inventoryService.Initialise(config); inventoryService.AddRegion(testScene); inventoryService.RegionLoaded(testScene); -- cgit v1.1 From 54e885581989ddfaf525753ede12c4d4d797cba0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 01:23:26 +0100 Subject: remove mock asset service for tests in favour of always using the real one --- .../Framework/Scenes/Tests/UuidGathererTests.cs | 4 +- OpenSim/Tests/Common/Mock/MockAssetService.cs | 123 --------------------- OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs | 14 +-- 3 files changed, 8 insertions(+), 133 deletions(-) delete mode 100644 OpenSim/Tests/Common/Mock/MockAssetService.cs diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs index 6b70865..dbf9e0f 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs @@ -47,7 +47,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests [SetUp] public void Init() { - m_assetService = new MockAssetService(); + // FIXME: We don't need a full scene here - it would be enough to set up the asset service. + Scene scene = SceneSetupHelpers.SetupScene(); + m_assetService = scene.AssetService; m_uuidGatherer = new UuidGatherer(m_assetService); } diff --git a/OpenSim/Tests/Common/Mock/MockAssetService.cs b/OpenSim/Tests/Common/Mock/MockAssetService.cs deleted file mode 100644 index 9d7c5e2..0000000 --- a/OpenSim/Tests/Common/Mock/MockAssetService.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Data; -using OpenSim.Services.Interfaces; -using Nini.Config; - -namespace OpenSim.Tests.Common.Mock -{ - public class MockAssetService : IAssetService - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private readonly Dictionary Assets = new Dictionary(); - - public MockAssetService() {} - - /// - /// This constructor is required if the asset service is being created reflectively (which is the case in some - /// tests). - /// - /// - public MockAssetService(IConfigSource config) {} - - public AssetBase Get(string id) - { -// m_log.DebugFormat("[MOCK ASSET SERVICE]: Getting asset with id {0}", id); - - AssetBase asset; - if (Assets.ContainsKey(id)) - { - asset = Assets[id]; -// m_log.DebugFormat( -// "[MOCK ASSET SERVICE]: Got asset {0} {1}, bytes {2}", asset.Name, asset.ID, asset.Data.Length); - } - else - { - asset = null; - } - - return asset; - } - - public AssetBase GetCached(string id) - { - return Get(id); - } - - public AssetMetadata GetMetadata(string id) - { - throw new System.NotImplementedException(); - } - - public byte[] GetData(string id) - { -// m_log.DebugFormat("[MOCK ASSET SERVICE]: Requesting data for asset {0}", id); - - AssetBase asset = Get(id); - - if (asset == null) - return null; - else - return asset.Data; - } - - public bool Get(string id, object sender, AssetRetrieved handler) - { - handler(id, sender, Get(id)); - - return true; - } - - public string Store(AssetBase asset) - { -// m_log.DebugFormat( -// "[MOCK ASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.ID, asset.Data.Length); - - Assets[asset.ID] = asset; - - return asset.ID; - } - - public bool UpdateContent(string id, byte[] data) - { - throw new System.NotImplementedException(); - } - - public bool Delete(string id) - { - throw new System.NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index 97d4ace..484a97d 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -132,7 +132,7 @@ namespace OpenSim.Tests.Common.Setup testScene.AddModule(godsModule.Name, godsModule); realServices = realServices.ToLower(); - LocalAssetServicesConnector assetService = StartAssetService(testScene, realServices.Contains("asset")); + LocalAssetServicesConnector assetService = StartAssetService(testScene); // For now, always started a 'real' authentication service StartAuthenticationService(testScene, true); @@ -164,19 +164,15 @@ namespace OpenSim.Tests.Common.Setup return testScene; } - private static LocalAssetServicesConnector StartAssetService(Scene testScene, bool real) + private static LocalAssetServicesConnector StartAssetService(Scene testScene) { LocalAssetServicesConnector assetService = new LocalAssetServicesConnector(); IConfigSource config = new IniConfigSource(); - config.AddConfig("Modules"); - config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); config.AddConfig("AssetService"); - if (real) - config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); - else - config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Tests.Common.dll:MockAssetService"); - + config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); assetService.Initialise(config); -- cgit v1.1 From ba73df39a3824a91ffc848d9b6dc2356d1b307cf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 01:26:07 +0100 Subject: remove any reference to a mock authentication service since it doesn't exist and we don't use it --- OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index 484a97d..b819581 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -132,11 +132,8 @@ namespace OpenSim.Tests.Common.Setup testScene.AddModule(godsModule.Name, godsModule); realServices = realServices.ToLower(); - LocalAssetServicesConnector assetService = StartAssetService(testScene); - - // For now, always started a 'real' authentication service - StartAuthenticationService(testScene, true); - + LocalAssetServicesConnector assetService = StartAssetService(testScene); + StartAuthenticationService(testScene); LocalInventoryServicesConnector inventoryService = StartInventoryService(testScene); StartGridService(testScene, true); LocalUserAccountServicesConnector userAccountService = StartUserAccountService(testScene); @@ -183,20 +180,18 @@ namespace OpenSim.Tests.Common.Setup return assetService; } - private static void StartAuthenticationService(Scene testScene, bool real) + private static void StartAuthenticationService(Scene testScene) { ISharedRegionModule service = new LocalAuthenticationServicesConnector(); IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); config.AddConfig("AuthenticationService"); config.Configs["Modules"].Set("AuthenticationServices", "LocalAuthenticationServicesConnector"); - if (real) - config.Configs["AuthenticationService"].Set( - "LocalServiceModule", "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService"); - else - config.Configs["AuthenticationService"].Set( - "LocalServiceModule", "OpenSim.Tests.Common.dll:MockAuthenticationService"); + config.Configs["AuthenticationService"].Set( + "LocalServiceModule", "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService"); config.Configs["AuthenticationService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + service.Initialise(config); service.AddRegion(testScene); service.RegionLoaded(testScene); -- cgit v1.1 From 631654a38d2ace833f8cd2dc3b6b3860352f8b13 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 01:30:49 +0100 Subject: remove old code for a mock grid service, which got removed some time back --- OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index b819581..5d08764 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -135,7 +135,7 @@ namespace OpenSim.Tests.Common.Setup LocalAssetServicesConnector assetService = StartAssetService(testScene); StartAuthenticationService(testScene); LocalInventoryServicesConnector inventoryService = StartInventoryService(testScene); - StartGridService(testScene, true); + StartGridService(testScene); LocalUserAccountServicesConnector userAccountService = StartUserAccountService(testScene); LocalPresenceServicesConnector presenceService = StartPresenceService(testScene); @@ -218,24 +218,19 @@ namespace OpenSim.Tests.Common.Setup return inventoryService; } - private static LocalGridServicesConnector StartGridService(Scene testScene, bool real) + private static LocalGridServicesConnector StartGridService(Scene testScene) { IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); config.AddConfig("GridService"); config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector"); config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll:NullRegionData"); - if (real) - config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); + config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); LocalGridServicesConnector gridService = new LocalGridServicesConnector(); gridService.Initialise(config); - - //else - // config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Tests.Common.dll:TestGridService"); gridService.AddRegion(testScene); gridService.RegionLoaded(testScene); - //testScene.AddRegionModule(m_gridService.Name, m_gridService); return gridService; } -- cgit v1.1 From 66a62678e5da89b0fa004eca3a370d202c239884 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 01:37:27 +0100 Subject: get rid of all traces of the now used mock service infrastructure --- .../Archiver/Tests/InventoryArchiveTestCase.cs | 2 +- .../Archiver/Tests/InventoryArchiverTests.cs | 2 +- .../Avatar/Inventory/Archiver/Tests/PathTests.cs | 14 +++++----- .../Tests/InventoryAccessModuleTests.cs | 2 +- .../World/Serialiser/Tests/SerialiserTests.cs | 2 +- .../Scenes/Tests/StandaloneTeleportTests.cs | 4 +-- .../Framework/Scenes/Tests/TaskInventoryTests.cs | 4 +-- OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs | 32 ++-------------------- 8 files changed, 17 insertions(+), 45 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs index e2316f0..5ba08ee 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs @@ -101,7 +101,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests // log4net.Config.XmlConfigurator.Configure(); InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - Scene scene = SceneSetupHelpers.SetupScene("Inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); SceneSetupHelpers.SetupSceneModules(scene, archiverModule); UserProfileTestUtils.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index 69c5dcd..d03f6da 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -62,7 +62,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests SerialiserModule serialiserModule = new SerialiserModule(); m_archiverModule = new InventoryArchiverModule(); - m_scene = SceneSetupHelpers.SetupScene("asset inventory"); + m_scene = SceneSetupHelpers.SetupScene(); SceneSetupHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs index 0e8f647..c7dae52 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - Scene scene = SceneSetupHelpers.SetupScene("Inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); SceneSetupHelpers.SetupSceneModules(scene, archiverModule); // Create user @@ -180,7 +180,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryArchiverModule archiverModule = new InventoryArchiverModule(); // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene - Scene scene = SceneSetupHelpers.SetupScene("inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); @@ -223,7 +223,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests SerialiserModule serialiserModule = new SerialiserModule(); InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - Scene scene = SceneSetupHelpers.SetupScene("inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); UserProfileTestUtils.CreateUserWithInventory(scene, m_uaMT, "password"); @@ -248,7 +248,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - Scene scene = SceneSetupHelpers.SetupScene("Inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); SceneSetupHelpers.SetupSceneModules(scene, archiverModule); // Create user @@ -327,7 +327,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests TestHelper.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneSetupHelpers.SetupScene("inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); Dictionary foldersCreated = new Dictionary(); @@ -394,7 +394,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests TestHelper.InMethod(); //log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneSetupHelpers.SetupScene("inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); string folder1ExistingName = "a"; @@ -445,7 +445,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests TestHelper.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneSetupHelpers.SetupScene("inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); string folder1ExistingName = "a"; diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 7a7a8c2..8d53cf1 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests config.AddConfig("Modules"); config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); - m_scene = SceneSetupHelpers.SetupScene("Inventory"); + m_scene = SceneSetupHelpers.SetupScene(); SceneSetupHelpers.SetupSceneModules(m_scene, config, m_iam); // Create user diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs index dafaa0c..a866fd9 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs @@ -237,7 +237,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests public void Init() { m_serialiserModule = new SerialiserModule(); - m_scene = SceneSetupHelpers.SetupScene(""); + m_scene = SceneSetupHelpers.SetupScene(); SceneSetupHelpers.SetupSceneModules(m_scene, m_serialiserModule); } diff --git a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs index 8588f7f..dd28416 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs @@ -117,11 +117,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); - Scene sceneB = SceneSetupHelpers.SetupScene("sceneB", sceneBId, 1010, 1010, "grid"); + Scene sceneB = SceneSetupHelpers.SetupScene("sceneB", sceneBId, 1010, 1010); SceneSetupHelpers.SetupSceneModules(sceneB, new IniConfigSource(), interregionComms); sceneB.RegisterRegionWithGrid(); - Scene sceneA = SceneSetupHelpers.SetupScene("sceneA", sceneAId, 1000, 1000, "grid"); + Scene sceneA = SceneSetupHelpers.SetupScene("sceneA", sceneAId, 1000, 1000); SceneSetupHelpers.SetupSceneModules(sceneA, new IniConfigSource(), interregionComms); sceneA.RegisterRegionWithGrid(); diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs index 8138bcc..2aef4b0 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs @@ -101,7 +101,7 @@ namespace OpenSim.Region.Framework.Tests TestHelper.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneSetupHelpers.SetupScene("inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); UserAccount user1 = CreateUser(scene); SceneObjectGroup sog1 = CreateSO1(scene, user1.PrincipalID); SceneObjectPart sop1 = sog1.RootPart; @@ -127,7 +127,7 @@ namespace OpenSim.Region.Framework.Tests TestHelper.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneSetupHelpers.SetupScene("inventory"); + Scene scene = SceneSetupHelpers.SetupScene(); UserAccount user1 = CreateUser(scene); SceneObjectGroup sog1 = CreateSO1(scene, user1.PrincipalID); SceneObjectPart sop1 = sog1.RootPart; diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index 5d08764..99517d2 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs @@ -66,32 +66,7 @@ namespace OpenSim.Tests.Common.Setup /// public static TestScene SetupScene() { - return SetupScene(""); - } - - /// - /// Set up a test scene - /// - /// - /// Starts real inventory and asset services, as opposed to mock ones, if true - /// - public static TestScene SetupScene(String realServices) - { - return SetupScene("Unit test region", UUID.Random(), 1000, 1000, realServices); - } - - /// - /// Set up a test scene - /// - /// Name of the region - /// ID of the region - /// X co-ordinate of the region - /// Y co-ordinate of the region - /// This should be the same if simulating two scenes within a standalone - /// - public static TestScene SetupScene(string name, UUID id, uint x, uint y) - { - return SetupScene(name, id, x, y, ""); + return SetupScene("Unit test region", UUID.Random(), 1000, 1000); } /// @@ -103,10 +78,8 @@ namespace OpenSim.Tests.Common.Setup /// X co-ordinate of the region /// Y co-ordinate of the region /// This should be the same if simulating two scenes within a standalone - /// Starts real inventory and asset services, as opposed to mock ones, if true /// - public static TestScene SetupScene( - string name, UUID id, uint x, uint y, String realServices) + public static TestScene SetupScene(string name, UUID id, uint x, uint y) { Console.WriteLine("Setting up test scene {0}", name); @@ -130,7 +103,6 @@ namespace OpenSim.Tests.Common.Setup IRegionModule godsModule = new GodsModule(); godsModule.Initialise(testScene, new IniConfigSource()); testScene.AddModule(godsModule.Name, godsModule); - realServices = realServices.ToLower(); LocalAssetServicesConnector assetService = StartAssetService(testScene); StartAuthenticationService(testScene); -- cgit v1.1 From 40bf417da7705711f33c64b82611203ff2a0adad Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 13 Apr 2011 16:10:18 -0400 Subject: Add ColladaMesh switch --- OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs | 13 +++++++++++-- .../Assets/NewFileAgentInventoryVariablePriceModule.cs | 11 ++++++++++- bin/OpenSimDefaults.ini | 6 +++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs index 878242a..d2278bc 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs @@ -54,6 +54,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets private Scene m_scene; private IAssetService m_assetService; + private bool m_enabled = true; #region IRegionModuleBase Members @@ -65,7 +66,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void Initialise(IConfigSource source) { - + IConfig startupConfig = source.Configs["Startup"]; + if (startupConfig == null) + return; + + if (!startupConfig.GetBoolean("ColladaMesh",true)) + m_enabled = false; } public void AddRegion(Scene pScene) @@ -101,16 +107,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void RegisterCaps(UUID agentID, Caps caps) { + if(!m_enabled) + return; + UUID capID = UUID.Random(); // m_log.Info("[GETMESH]: /CAPS/" + capID); + caps.RegisterHandler("GetMesh", new RestHTTPHandler("GET", "/CAPS/" + capID, delegate(Hashtable m_dhttpMethod) { return ProcessGetMesh(m_dhttpMethod, agentID, caps); })); - } #endregion diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs index 4a42c93..fb07cc9 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs @@ -56,6 +56,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets private Scene m_scene; // private IAssetService m_assetService; private bool m_dumpAssetsToFile = false; + private bool m_enabled = true; #region IRegionModuleBase Members @@ -67,7 +68,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void Initialise(IConfigSource source) { - + IConfig startupConfig = source.Configs["Startup"]; + if (startupConfig == null) + return; + + if (!startupConfig.GetBoolean("ColladaMesh",true)) + m_enabled = false; } public void AddRegion(Scene pScene) @@ -103,6 +109,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void RegisterCaps(UUID agentID, Caps caps) { + if(!m_enabled) + return; + UUID capID = UUID.Random(); // m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID); diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index f857b8d..107e859 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -154,7 +154,11 @@ ; mesh, and use it for collisions. This is currently experimental code and enabling ; it may cause unexpected physics problems. ;UseMeshiesPhysicsMesh = false - + + ; enable / disable Collada mesh support + ; default is true + ; ColladaMesh = true + ; Choose one of the physics engines below ; OpenDynamicsEngine is by some distance the most developed physics engine ; basicphysics effectively does not model physics at all, making all objects phantom -- cgit v1.1 From 52d92303926c8be46af734707274e6d8ecd70602 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 22:47:47 +0100 Subject: refactor: split out some rez code into a separate CreateItemForObject() method --- .../InventoryAccess/InventoryAccessModule.cs | 302 +++++++++++---------- 1 file changed, 159 insertions(+), 143 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index c0946f4..0f2b9a6 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -274,154 +274,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess foreach (SceneObjectGroup objectGroup in objlist) objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; - // Get the user info of the item destination - // - UUID userID = UUID.Zero; - - if (action == DeRezAction.Take || action == DeRezAction.TakeCopy || - action == DeRezAction.SaveToExistingUserInventoryItem) - { - // Take or take copy require a taker - // Saving changes requires a local user - // - if (remoteClient == null) - return UUID.Zero; - - userID = remoteClient.AgentId; - } - else - { - // All returns / deletes go to the object owner - // - userID = objlist[0].RootPart.OwnerID; - } - - if (userID == UUID.Zero) // Can't proceed - { + InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); + if (item == null) return UUID.Zero; - } - - // If we're returning someone's item, it goes back to the - // owner's Lost And Found folder. - // Delete is treated like return in this case - // Deleting your own items makes them go to trash - // - - InventoryFolderBase folder = null; - InventoryItemBase item = null; - - if (DeRezAction.SaveToExistingUserInventoryItem == action) + + // Can't know creator is the same, so null it in inventory + if (objlist.Count > 1) { - item = new InventoryItemBase(objlist[0].RootPart.FromUserInventoryItemID, userID); - item = m_Scene.InventoryService.GetItem(item); - - //item = userInfo.RootFolder.FindItem( - // objectGroup.RootPart.FromUserInventoryItemID); - - if (null == item) - { - m_log.DebugFormat( - "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.", - objlist[0].Name, objlist[0].UUID); - return UUID.Zero; - } + item.CreatorId = UUID.Zero.ToString(); + item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; } else { - // Folder magic - // - if (action == DeRezAction.Delete) - { - // Deleting someone else's item - // - if (remoteClient == null || - objlist[0].OwnerID != remoteClient.AgentId) - { - - folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); - } - else - { - folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); - } - } - else if (action == DeRezAction.Return) - { - - // Dump to lost + found unconditionally - // - folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); - } - - if (folderID == UUID.Zero && folder == null) - { - if (action == DeRezAction.Delete) - { - // Deletes go to trash by default - // - folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); - } - else - { - if (remoteClient == null || - objlist[0].OwnerID != remoteClient.AgentId) - { - // Taking copy of another person's item. Take to - // Objects folder. - folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); - } - else - { - // Catch all. Use lost & found - // - - folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); - } - } - } - - // Override and put into where it came from, if it came - // from anywhere in inventory - // - if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) - { - if (objlist[0].RootPart.FromFolderID != UUID.Zero) - { - InventoryFolderBase f = new InventoryFolderBase(objlist[0].RootPart.FromFolderID, userID); - folder = m_Scene.InventoryService.GetFolder(f); - } - } - - if (folder == null) // None of the above - { - folder = new InventoryFolderBase(folderID); - - if (folder == null) // Nowhere to put it - { - return UUID.Zero; - } - } - - item = new InventoryItemBase(); - // Can't know creator is the same, so null it in inventory - if (objlist.Count > 1) - item.CreatorId = UUID.Zero.ToString(); - else - item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); - item.ID = UUID.Random(); - item.InvType = (int)InventoryType.Object; - item.Folder = folder.ID; - item.Owner = userID; - if (objlist.Count > 1) - { - item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; - } - else - { - item.SaleType = objlist[0].RootPart.ObjectSaleType; - item.SalePrice = objlist[0].RootPart.SalePrice; - } - } + item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); + item.SaleType = objlist[0].RootPart.ObjectSaleType; + item.SalePrice = objlist[0].RootPart.SalePrice; + } AssetBase asset = CreateAsset( objlist[0].GetPartName(objlist[0].RootPart.LocalId), @@ -505,8 +373,156 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } } + return assetID; } + + /// + /// Create an item using details for the given scene object. + /// + /// + /// + /// + /// + /// + protected InventoryItemBase CreateItemForObject( + DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID) + { + // Get the user info of the item destination + // + UUID userID = UUID.Zero; + + if (action == DeRezAction.Take || action == DeRezAction.TakeCopy || + action == DeRezAction.SaveToExistingUserInventoryItem) + { + // Take or take copy require a taker + // Saving changes requires a local user + // + if (remoteClient == null) + return null; + + userID = remoteClient.AgentId; + } + else + { + // All returns / deletes go to the object owner + // + userID = so.RootPart.OwnerID; + } + + if (userID == UUID.Zero) // Can't proceed + { + return null; + } + + // If we're returning someone's item, it goes back to the + // owner's Lost And Found folder. + // Delete is treated like return in this case + // Deleting your own items makes them go to trash + // + + InventoryFolderBase folder = null; + InventoryItemBase item = null; + + if (DeRezAction.SaveToExistingUserInventoryItem == action) + { + item = new InventoryItemBase(so.RootPart.FromUserInventoryItemID, userID); + item = m_Scene.InventoryService.GetItem(item); + + //item = userInfo.RootFolder.FindItem( + // objectGroup.RootPart.FromUserInventoryItemID); + + if (null == item) + { + m_log.DebugFormat( + "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.", + so.Name, so.UUID); + + return null; + } + } + else + { + // Folder magic + // + if (action == DeRezAction.Delete) + { + // Deleting someone else's item + // + if (remoteClient == null || + so.OwnerID != remoteClient.AgentId) + { + folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); + } + else + { + folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); + } + } + else if (action == DeRezAction.Return) + { + // Dump to lost + found unconditionally + // + folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); + } + + if (folderID == UUID.Zero && folder == null) + { + if (action == DeRezAction.Delete) + { + // Deletes go to trash by default + // + folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); + } + else + { + if (remoteClient == null || so.OwnerID != remoteClient.AgentId) + { + // Taking copy of another person's item. Take to + // Objects folder. + folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); + } + else + { + // Catch all. Use lost & found + // + + folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); + } + } + } + + // Override and put into where it came from, if it came + // from anywhere in inventory + // + if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) + { + if (so.RootPart.FromFolderID != UUID.Zero) + { + InventoryFolderBase f = new InventoryFolderBase(so.RootPart.FromFolderID, userID); + folder = m_Scene.InventoryService.GetFolder(f); + } + } + + if (folder == null) // None of the above + { + folder = new InventoryFolderBase(folderID); + + if (folder == null) // Nowhere to put it + { + return null; + } + } + + item = new InventoryItemBase(); + item.ID = UUID.Random(); + item.InvType = (int)InventoryType.Object; + item.Folder = folder.ID; + item.Owner = userID; + } + + return item; + } /// /// Rez an object into the scene from the user's inventory -- cgit v1.1 From 9c7f14bf366eaa113ca7a89d3b40a42529e7726e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 23:07:23 +0100 Subject: minor: remove a small amount of code duplication --- .../CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 0f2b9a6..5d19025 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -298,17 +298,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess Utils.StringToBytes(itemXml), objlist[0].OwnerID.ToString()); m_Scene.AssetService.Store(asset); - assetID = asset.FullID; + + item.AssetID = asset.FullID; + assetID = asset.FullID; if (DeRezAction.SaveToExistingUserInventoryItem == action) { - item.AssetID = asset.FullID; m_Scene.InventoryService.UpdateItem(item); } else { - item.AssetID = asset.FullID; - uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; foreach (SceneObjectGroup grp in objlist) effectivePerms &= grp.GetEffectivePermissions(); -- cgit v1.1 From fc365f2a31d46b9c6517159330c7f6953eb60e9f Mon Sep 17 00:00:00 2001 From: BlueWall Date: Fri, 15 Apr 2011 18:23:37 -0400 Subject: Thanks Snoopy for a patch that allows setting of perms on items given to new avatars --- .../RemoteController/RemoteAdminPlugin.cs | 35 +++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 1b4d1ea..c6b34f9 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -1587,6 +1587,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController { InventoryItemBase destinationItem = new InventoryItemBase(UUID.Random(), destination); destinationItem.Name = item.Name; + destinationItem.Owner = destination; destinationItem.Description = item.Description; destinationItem.InvType = item.InvType; destinationItem.CreatorId = item.CreatorId; @@ -1606,6 +1607,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController destinationItem.Flags = item.Flags; destinationItem.CreationDate = item.CreationDate; destinationItem.Folder = destinationFolder.ID; + ApplyNextOwnerPermissions(destinationItem); m_application.SceneManager.CurrentOrFirstScene.AddInventoryItem(destinationItem); m_log.DebugFormat("[RADMIN]: Added item {0} to folder {1}", destinationItem.ID, destinationFolder.ID); @@ -1640,6 +1642,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController { InventoryItemBase destinationItem = new InventoryItemBase(UUID.Random(), destination); destinationItem.Name = item.Name; + destinationItem.Owner = destination; destinationItem.Description = item.Description; destinationItem.InvType = item.InvType; destinationItem.CreatorId = item.CreatorId; @@ -1659,6 +1662,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController destinationItem.Flags = item.Flags; destinationItem.CreationDate = item.CreationDate; destinationItem.Folder = destinationFolder.ID; + ApplyNextOwnerPermissions(destinationItem); m_application.SceneManager.CurrentOrFirstScene.AddInventoryItem(destinationItem); m_log.DebugFormat("[RADMIN]: Added item {0} to folder {1}", destinationItem.ID, destinationFolder.ID); @@ -1716,7 +1720,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController { destinationFolder = new InventoryFolderBase(); destinationFolder.ID = UUID.Random(); - destinationFolder.Name = assetType.ToString(); + if (assetType == AssetType.Clothing) { + destinationFolder.Name = "Clothing"; + } else { + destinationFolder.Name = "Body Parts"; + } destinationFolder.Owner = destination; destinationFolder.Type = (short)assetType; destinationFolder.ParentID = inventoryService.GetRootFolder(destination).ID; @@ -1748,6 +1756,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController { InventoryItemBase destinationItem = new InventoryItemBase(UUID.Random(), destination); destinationItem.Name = item.Name; + destinationItem.Owner = destination; destinationItem.Description = item.Description; destinationItem.InvType = item.InvType; destinationItem.CreatorId = item.CreatorId; @@ -1767,6 +1776,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController destinationItem.Flags = item.Flags; destinationItem.CreationDate = item.CreationDate; destinationItem.Folder = extraFolder.ID; + ApplyNextOwnerPermissions(destinationItem); m_application.SceneManager.CurrentOrFirstScene.AddInventoryItem(destinationItem); inventoryMap.Add(item.ID, destinationItem.ID); @@ -1784,6 +1794,29 @@ namespace OpenSim.ApplicationPlugins.RemoteController } /// + /// Apply next owner permissions. + /// + + private void ApplyNextOwnerPermissions(InventoryItemBase item) + { + if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) + { + if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) + item.CurrentPermissions &= ~(uint)PermissionMask.Copy; + if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) + item.CurrentPermissions &= ~(uint)PermissionMask.Transfer; + if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0) + item.CurrentPermissions &= ~(uint)PermissionMask.Modify; + } + item.CurrentPermissions &= item.NextPermissions; + item.BasePermissions &= item.NextPermissions; + item.EveryOnePermissions &= item.NextPermissions; + // item.OwnerChanged = true; + // item.PermsMask = 0; + // item.PermsGranter = UUID.Zero; + } + + /// /// This method is called if a given model avatar name can not be found. If the external /// file has already been loaded once, then control returns immediately. If not, then it /// looks for a default appearance file. This file contains XML definitions of zero or more named -- cgit v1.1 From 1dba671f45b691bcf024e9ffd5568e8a7ea2165c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 23:32:46 +0100 Subject: refactor: separate out code that adds permissions --- .../InventoryAccess/InventoryAccessModule.cs | 101 ++++++++++++--------- 1 file changed, 59 insertions(+), 42 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 5d19025..8b68dbe 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -308,48 +308,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } else { - uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; - foreach (SceneObjectGroup grp in objlist) - effectivePerms &= grp.GetEffectivePermissions(); - effectivePerms |= (uint)PermissionMask.Move; - - if (remoteClient != null && (remoteClient.AgentId != objlist[0].RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) - { - uint perms = effectivePerms; - uint nextPerms = (perms & 7) << 13; - if ((nextPerms & (uint)PermissionMask.Copy) == 0) - perms &= ~(uint)PermissionMask.Copy; - if ((nextPerms & (uint)PermissionMask.Transfer) == 0) - perms &= ~(uint)PermissionMask.Transfer; - if ((nextPerms & (uint)PermissionMask.Modify) == 0) - perms &= ~(uint)PermissionMask.Modify; - - item.BasePermissions = perms & objlist[0].RootPart.NextOwnerMask; - item.CurrentPermissions = item.BasePermissions; - item.NextPermissions = perms & objlist[0].RootPart.NextOwnerMask; - item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & objlist[0].RootPart.NextOwnerMask; - item.GroupPermissions = objlist[0].RootPart.GroupMask & objlist[0].RootPart.NextOwnerMask; - - // Magic number badness. Maybe this deserves an enum. - // bit 4 (16) is the "Slam" bit, it means treat as passed - // and apply next owner perms on rez - item.CurrentPermissions |= 16; // Slam! - } - else - { - item.BasePermissions = effectivePerms; - item.CurrentPermissions = effectivePerms; - item.NextPermissions = objlist[0].RootPart.NextOwnerMask & effectivePerms; - item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & effectivePerms; - item.GroupPermissions = objlist[0].RootPart.GroupMask & effectivePerms; - - item.CurrentPermissions &= - ((uint)PermissionMask.Copy | - (uint)PermissionMask.Transfer | - (uint)PermissionMask.Modify | - (uint)PermissionMask.Move | - 7); // Preserve folded permissions - } + AddPermissions(item, objlist[0], objlist, remoteClient); item.CreationDate = Util.UnixTimeSinceEpoch(); item.Description = asset.Description; @@ -377,6 +336,64 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } /// + /// Add relevant permissions for an object to the item. + /// + /// + /// + /// + /// + /// + protected InventoryItemBase AddPermissions( + InventoryItemBase item, SceneObjectGroup so, List objsForEffectivePermissions, + IClientAPI remoteClient) + { + uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; + foreach (SceneObjectGroup grp in objsForEffectivePermissions) + effectivePerms &= grp.GetEffectivePermissions(); + effectivePerms |= (uint)PermissionMask.Move; + + if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) + { + uint perms = effectivePerms; + uint nextPerms = (perms & 7) << 13; + if ((nextPerms & (uint)PermissionMask.Copy) == 0) + perms &= ~(uint)PermissionMask.Copy; + if ((nextPerms & (uint)PermissionMask.Transfer) == 0) + perms &= ~(uint)PermissionMask.Transfer; + if ((nextPerms & (uint)PermissionMask.Modify) == 0) + perms &= ~(uint)PermissionMask.Modify; + + item.BasePermissions = perms & so.RootPart.NextOwnerMask; + item.CurrentPermissions = item.BasePermissions; + item.NextPermissions = perms & so.RootPart.NextOwnerMask; + item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask; + item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask; + + // Magic number badness. Maybe this deserves an enum. + // bit 4 (16) is the "Slam" bit, it means treat as passed + // and apply next owner perms on rez + item.CurrentPermissions |= 16; // Slam! + } + else + { + item.BasePermissions = effectivePerms; + item.CurrentPermissions = effectivePerms; + item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms; + item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms; + item.GroupPermissions = so.RootPart.GroupMask & effectivePerms; + + item.CurrentPermissions &= + ((uint)PermissionMask.Copy | + (uint)PermissionMask.Transfer | + (uint)PermissionMask.Modify | + (uint)PermissionMask.Move | + 7); // Preserve folded permissions + } + + return item; + } + + /// /// Create an item using details for the given scene object. /// /// -- cgit v1.1 From ed74be65995afe192ce03177325c98b0100ab157 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Apr 2011 23:54:30 +0100 Subject: Make remote admin error messages more helpful on windows. Also, make log messages conform more with convention. --- .../RemoteController/RemoteAdminPlugin.cs | 161 ++++++++++----------- 1 file changed, 73 insertions(+), 88 deletions(-) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index c6b34f9..dc4309f 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -94,7 +94,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController public void Initialise() { - m_log.Info("[RADMIN]: " + Name + " cannot be default-initialized!"); + m_log.Error("[RADMIN]: " + Name + " cannot be default-initialized!"); throw new PluginNotInitialisedException(Name); } @@ -111,7 +111,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController else { m_config = m_configSource.Configs["RemoteAdmin"]; - m_log.Info("[RADMIN]: Remote Admin Plugin Enabled"); + m_log.Debug("[RADMIN]: Remote Admin Plugin Enabled"); m_requiredPassword = m_config.GetString("access_password", String.Empty); int port = m_config.GetInt("port", 0); @@ -230,8 +230,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN]: Restart region: failed: {0}", e.Message); - m_log.DebugFormat("[RADMIN]: Restart region: failed: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: Restart region: failed: {0} {1}", e.Message, e.StackTrace); responseData["accepted"] = false; responseData["success"] = false; responseData["rebooting"] = false; @@ -277,8 +276,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN]: Broadcasting: failed: {0}", e.Message); - m_log.DebugFormat("[RADMIN]: Broadcasting: failed: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: Broadcasting: failed: {0}", e.Message, e.StackTrace); responseData["accepted"] = false; responseData["success"] = false; @@ -301,7 +299,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController { Hashtable requestData = (Hashtable) request.Params[0]; - m_log.DebugFormat("[RADMIN]: Load Terrain: XmlRpc {0}", request.ToString()); + m_log.DebugFormat("[RADMIN]: Load Terrain: XmlRpc {0}", request); // foreach (string k in requestData.Keys) // { // m_log.DebugFormat("[RADMIN]: Load Terrain: XmlRpc {0}: >{1}< {2}", @@ -348,8 +346,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN]: Terrain Loading: failed: {0}", e.Message); - m_log.DebugFormat("[RADMIN]: Terrain Loading: failed: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: Terrain Loading: failed: {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -417,14 +414,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN] Shutdown: failed: {0}", e.Message); - m_log.DebugFormat("[RADMIN] Shutdown: failed: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: Shutdown: failed: {0} {1}", e.Message, e.StackTrace); responseData["accepted"] = false; responseData["error"] = e.Message; response.Value = responseData; } + m_log.Info("[RADMIN]: Shutdown Administrator Request complete"); return response; } @@ -725,8 +722,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN] CreateRegion: failed {0}", e.Message); - m_log.DebugFormat("[RADMIN] CreateRegion: failed {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN] CreateRegion: failed {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -792,8 +788,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN] DeleteRegion: failed {0}", e.Message); - m_log.DebugFormat("[RADMIN] DeleteRegion: failed {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN] DeleteRegion: failed {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -884,8 +879,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN] CloseRegion: failed {0}", e.Message); - m_log.DebugFormat("[RADMIN] CloseRegion: failed {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: CloseRegion: failed {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -982,8 +976,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN] ModifyRegion: failed {0}", e.Message); - m_log.DebugFormat("[RADMIN] ModifyRegion: failed {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN] ModifyRegion: failed {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -1106,8 +1099,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN] CreateUser: failed: {0}", e.Message); - m_log.DebugFormat("[RADMIN] CreateUser: failed: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: CreateUser: failed: {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["avatar_uuid"] = UUID.Zero.ToString(); @@ -1198,8 +1190,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.ErrorFormat("[RADMIN] UserExists: failed: {0}", e.Message); - m_log.DebugFormat("[RADMIN] UserExists: failed: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: UserExists: failed: {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -1372,9 +1363,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - - m_log.ErrorFormat("[RADMIN] UpdateUserAccount: failed: {0}", e.Message); - m_log.DebugFormat("[RADMIN] UpdateUserAccount: failed: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN] UpdateUserAccount: failed: {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["avatar_uuid"] = UUID.Zero.ToString(); @@ -1382,6 +1371,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController response.Value = responseData; } + m_log.Info("[RADMIN]: UpdateUserAccount: request complete"); return response; } @@ -1397,7 +1387,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController private void UpdateUserAppearance(Hashtable responseData, Hashtable requestData, UUID userid) { - m_log.DebugFormat("[RADMIN] updateUserAppearance"); + m_log.DebugFormat("[RADMIN]: updateUserAppearance"); string defaultMale = m_config.GetString("default_male", "Default Male"); string defaultFemale = m_config.GetString("default_female", "Default Female"); @@ -1437,16 +1427,16 @@ namespace OpenSim.ApplicationPlugins.RemoteController if (String.IsNullOrEmpty(model)) { - m_log.DebugFormat("[RADMIN] Appearance update not requested"); + m_log.DebugFormat("[RADMIN]: Appearance update not requested"); return; } - m_log.DebugFormat("[RADMIN] Setting appearance for avatar {0}, using model <{1}>", userid, model); + m_log.DebugFormat("[RADMIN]: Setting appearance for avatar {0}, using model <{1}>", userid, model); string[] modelSpecifiers = model.Split(); if (modelSpecifiers.Length != 2) { - m_log.WarnFormat("[RADMIN] User appearance not set for {0}. Invalid model name : <{1}>", userid, model); + m_log.WarnFormat("[RADMIN]: User appearance not set for {0}. Invalid model name : <{1}>", userid, model); // modelSpecifiers = dmodel.Split(); return; } @@ -1457,7 +1447,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController if (modelProfile == null) { - m_log.WarnFormat("[RADMIN] Requested model ({0}) not found. Appearance unchanged", model); + m_log.WarnFormat("[RADMIN]: Requested model ({0}) not found. Appearance unchanged", model); return; } @@ -1467,7 +1457,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController EstablishAppearance(userid, modelProfile.PrincipalID); - m_log.DebugFormat("[RADMIN] Finished setting appearance for avatar {0}, using model {1}", + m_log.DebugFormat("[RADMIN]: Finished setting appearance for avatar {0}, using model {1}", userid, model); } @@ -1479,7 +1469,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController private void EstablishAppearance(UUID destination, UUID source) { - m_log.DebugFormat("[RADMIN] Initializing inventory for {0} from {1}", destination, source); + m_log.DebugFormat("[RADMIN]: Initializing inventory for {0} from {1}", destination, source); Scene scene = m_application.SceneManager.CurrentOrFirstScene; // If the model has no associated appearance we're done. @@ -1501,7 +1491,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.WarnFormat("[RADMIN] Error transferring appearance for {0} : {1}", + m_log.WarnFormat("[RADMIN]: Error transferring appearance for {0} : {1}", destination, e.Message); } @@ -1532,7 +1522,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.WarnFormat("[RADMIN] Error transferring appearance for {0} : {1}", + m_log.WarnFormat("[RADMIN]: Error transferring appearance for {0} : {1}", destination, e.Message); } @@ -1567,7 +1557,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController destinationFolder.ParentID = inventoryService.GetRootFolder(destination).ID; destinationFolder.Version = 1; inventoryService.AddFolder(destinationFolder); // store base record - m_log.ErrorFormat("[RADMIN] Created folder for destination {0}", source); + m_log.ErrorFormat("[RADMIN]: Created folder for destination {0}", source); } // Wearables @@ -1730,7 +1720,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController destinationFolder.ParentID = inventoryService.GetRootFolder(destination).ID; destinationFolder.Version = 1; inventoryService.AddFolder(destinationFolder); // store base record - m_log.ErrorFormat("[RADMIN] Created folder for destination {0}", source); + m_log.ErrorFormat("[RADMIN]: Created folder for destination {0}", source); } InventoryFolderBase extraFolder; @@ -1748,7 +1738,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController extraFolder.ParentID = destinationFolder.ID; inventoryService.AddFolder(extraFolder); - m_log.DebugFormat("[RADMIN] Added folder {0} to folder {1}", extraFolder.ID, sourceFolder.ID); + m_log.DebugFormat("[RADMIN]: Added folder {0} to folder {1}", extraFolder.ID, sourceFolder.ID); List items = inventoryService.GetFolderContent(source, folder.ID).Items; @@ -1825,7 +1815,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController /// indicate which outfit is the default, and this outfit will be automatically worn. The /// other outfits are provided to allow "real" avatars a way to easily change their outfits. /// - private bool CreateDefaultAvatars() { // Only load once @@ -1834,7 +1823,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController return false; } - m_log.DebugFormat("[RADMIN] Creating default avatar entries"); + m_log.DebugFormat("[RADMIN]: Creating default avatar entries"); m_defaultAvatarsLoaded = true; @@ -1890,7 +1879,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController foreach (XmlElement avatar in avatars) { - m_log.DebugFormat("[RADMIN] Loading appearance for {0}, gender = {1}", + m_log.DebugFormat("[RADMIN]: Loading appearance for {0}, gender = {1}", GetStringAttribute(avatar,"name","?"), GetStringAttribute(avatar,"gender","?")); // Create the user identified by the avatar entry @@ -1912,7 +1901,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController account = CreateUser(scopeID, names[0], names[1], password, email); if (null == account) { - m_log.ErrorFormat("[RADMIN] Avatar {0} {1} was not created", names[0], names[1]); + m_log.ErrorFormat("[RADMIN]: Avatar {0} {1} was not created", names[0], names[1]); return false; } } @@ -1930,12 +1919,12 @@ namespace OpenSim.ApplicationPlugins.RemoteController ID = account.PrincipalID; - m_log.DebugFormat("[RADMIN] User {0}[{1}] created or retrieved", name, ID); + m_log.DebugFormat("[RADMIN]: User {0}[{1}] created or retrieved", name, ID); include = true; } catch (Exception e) { - m_log.DebugFormat("[RADMIN] Error creating user {0} : {1}", name, e.Message); + m_log.DebugFormat("[RADMIN]: Error creating user {0} : {1}", name, e.Message); include = false; } @@ -1975,7 +1964,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController clothingFolder.ParentID = inventoryService.GetRootFolder(ID).ID; clothingFolder.Version = 1; inventoryService.AddFolder(clothingFolder); // store base record - m_log.ErrorFormat("[RADMIN] Created clothing folder for {0}/{1}", name, ID); + m_log.ErrorFormat("[RADMIN]: Created clothing folder for {0}/{1}", name, ID); } // OK, now we have an inventory for the user, read in the outfits from the @@ -1988,7 +1977,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController foreach (XmlElement outfit in outfits) { - m_log.DebugFormat("[RADMIN] Loading outfit {0} for {1}", + m_log.DebugFormat("[RADMIN]: Loading outfit {0} for {1}", GetStringAttribute(outfit,"name","?"), GetStringAttribute(avatar,"name","?")); outfitName = GetStringAttribute(outfit,"name",""); @@ -2012,7 +2001,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController // Otherwise, we must create the folder. if (extraFolder == null) { - m_log.DebugFormat("[RADMIN] Creating outfit folder {0} for {1}", outfitName, name); + m_log.DebugFormat("[RADMIN]: Creating outfit folder {0} for {1}", outfitName, name); extraFolder = new InventoryFolderBase(); extraFolder.ID = UUID.Random(); extraFolder.Name = outfitName; @@ -2021,7 +2010,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController extraFolder.Version = 1; extraFolder.ParentID = clothingFolder.ID; inventoryService.AddFolder(extraFolder); - m_log.DebugFormat("[RADMIN] Adding outfile folder {0} to folder {1}", extraFolder.ID, clothingFolder.ID); + m_log.DebugFormat("[RADMIN]: Adding outfile folder {0} to folder {1}", extraFolder.ID, clothingFolder.ID); } // Now get the pieces that make up the outfit @@ -2036,7 +2025,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController switch (child.Name) { case "Permissions" : - m_log.DebugFormat("[RADMIN] Permissions specified"); + m_log.DebugFormat("[RADMIN]: Permissions specified"); perms = child; break; case "Asset" : @@ -2086,7 +2075,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController inventoryItem.Folder = extraFolder.ID; // Parent folder m_application.SceneManager.CurrentOrFirstScene.AddInventoryItem(inventoryItem); - m_log.DebugFormat("[RADMIN] Added item {0} to folder {1}", inventoryItem.ID, extraFolder.ID); + m_log.DebugFormat("[RADMIN]: Added item {0} to folder {1}", inventoryItem.ID, extraFolder.ID); } // Attach item, if attachpoint is specified @@ -2094,7 +2083,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController if (attachpoint != 0) { avatarAppearance.SetAttachment(attachpoint, inventoryItem.ID, inventoryItem.AssetID); - m_log.DebugFormat("[RADMIN] Attached {0}", inventoryItem.ID); + m_log.DebugFormat("[RADMIN]: Attached {0}", inventoryItem.ID); } // Record whether or not the item is to be initially worn @@ -2107,32 +2096,32 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.WarnFormat("[RADMIN] Error wearing item {0} : {1}", inventoryItem.ID, e.Message); + m_log.WarnFormat("[RADMIN]: Error wearing item {0} : {1}", inventoryItem.ID, e.Message); } } // foreach item in outfit - m_log.DebugFormat("[RADMIN] Outfit {0} load completed", outfitName); + m_log.DebugFormat("[RADMIN]: Outfit {0} load completed", outfitName); } // foreach outfit - m_log.DebugFormat("[RADMIN] Inventory update complete for {0}", name); + m_log.DebugFormat("[RADMIN]: Inventory update complete for {0}", name); scene.AvatarService.SetAppearance(ID, avatarAppearance); } catch (Exception e) { - m_log.WarnFormat("[RADMIN] Inventory processing incomplete for user {0} : {1}", + m_log.WarnFormat("[RADMIN]: Inventory processing incomplete for user {0} : {1}", name, e.Message); } } // End of include } - m_log.DebugFormat("[RADMIN] Default avatar loading complete"); + m_log.DebugFormat("[RADMIN]: Default avatar loading complete"); } else { - m_log.DebugFormat("[RADMIN] No default avatar information available"); + m_log.DebugFormat("[RADMIN]: No default avatar information available"); return false; } } catch (Exception e) { - m_log.WarnFormat("[RADMIN] Exception whilst loading default avatars ; {0}", e.Message); + m_log.WarnFormat("[RADMIN]: Exception whilst loading default avatars ; {0}", e.Message); return false; } @@ -2227,8 +2216,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] LoadOAR: {0}", e.Message); - m_log.DebugFormat("[RADMIN] LoadOAR: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: LoadOAR: {0} {1}", e.Message, e.StackTrace); responseData["loaded"] = false; responseData["error"] = e.Message; @@ -2333,8 +2321,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] SaveOAR: {0}", e.Message); - m_log.DebugFormat("[RADMIN] SaveOAR: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: SaveOAR: {0} {1}", e.Message, e.StackTrace); responseData["saved"] = false; responseData["error"] = e.Message; @@ -2348,7 +2335,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController private void RemoteAdminOarSaveCompleted(Guid uuid, string name) { - m_log.DebugFormat("[RADMIN] File processing complete for {0}", name); + m_log.DebugFormat("[RADMIN]: File processing complete for {0}", name); lock (m_saveOarLock) Monitor.Pulse(m_saveOarLock); } @@ -2386,14 +2373,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController UUID region_uuid = (UUID) (string) requestData["region_uuid"]; if (!m_application.SceneManager.TrySetCurrentScene(region_uuid)) throw new Exception(String.Format("failed to switch to region {0}", region_uuid.ToString())); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_uuid.ToString()); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_uuid.ToString()); } else if (requestData.Contains("region_name")) { string region_name = (string) requestData["region_name"]; if (!m_application.SceneManager.TrySetCurrentScene(region_name)) throw new Exception(String.Format("failed to switch to region {0}", region_name)); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_name); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_name); } else throw new Exception("neither region_name nor region_uuid given"); @@ -2424,8 +2411,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] LoadXml: {0}", e.Message); - m_log.DebugFormat("[RADMIN] LoadXml: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN] LoadXml: {0} {1}", e.Message, e.StackTrace); responseData["loaded"] = false; responseData["switched"] = false; @@ -2471,14 +2457,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController UUID region_uuid = (UUID) (string) requestData["region_uuid"]; if (!m_application.SceneManager.TrySetCurrentScene(region_uuid)) throw new Exception(String.Format("failed to switch to region {0}", region_uuid.ToString())); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_uuid.ToString()); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_uuid.ToString()); } else if (requestData.Contains("region_name")) { string region_name = (string) requestData["region_name"]; if (!m_application.SceneManager.TrySetCurrentScene(region_name)) throw new Exception(String.Format("failed to switch to region {0}", region_name)); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_name); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_name); } else throw new Exception("neither region_name nor region_uuid given"); @@ -2510,8 +2496,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] SaveXml: {0}", e.Message); - m_log.DebugFormat("[RADMIN] SaveXml: {0}", e.ToString()); + m_log.ErrorFormat("[RADMIN]: SaveXml: {0} {1}", e.Message, e.StackTrace); responseData["saved"] = false; responseData["switched"] = false; @@ -2550,14 +2535,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController UUID region_uuid = (UUID) (string) requestData["region_uuid"]; if (!m_application.SceneManager.TrySetCurrentScene(region_uuid)) throw new Exception(String.Format("failed to switch to region {0}", region_uuid.ToString())); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_uuid.ToString()); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_uuid.ToString()); } else if (requestData.Contains("region_name")) { string region_name = (string) requestData["region_name"]; if (!m_application.SceneManager.TrySetCurrentScene(region_name)) throw new Exception(String.Format("failed to switch to region {0}", region_name)); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_name); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_name); } else throw new Exception("neither region_name nor region_uuid given"); @@ -2569,7 +2554,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] RegionQuery: {0}", e.Message); + m_log.InfoFormat("[RADMIN]: RegionQuery: {0}", e.Message); responseData["success"] = false; responseData["error"] = e.Message; @@ -2610,7 +2595,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] ConsoleCommand: {0}", e.Message); + m_log.InfoFormat("[RADMIN]: ConsoleCommand: {0}", e.Message); responseData["success"] = false; responseData["error"] = e.Message; @@ -2647,14 +2632,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController UUID region_uuid = (UUID) (string) requestData["region_uuid"]; if (!m_application.SceneManager.TrySetCurrentScene(region_uuid)) throw new Exception(String.Format("failed to switch to region {0}", region_uuid.ToString())); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_uuid.ToString()); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_uuid.ToString()); } else if (requestData.Contains("region_name")) { string region_name = (string) requestData["region_name"]; if (!m_application.SceneManager.TrySetCurrentScene(region_name)) throw new Exception(String.Format("failed to switch to region {0}", region_name)); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_name); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_name); } else throw new Exception("neither region_name nor region_uuid given"); @@ -2665,7 +2650,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] Access List Clear Request: {0}", e.Message); + m_log.ErrorFormat("[RADMIN]: Access List Clear Request: {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -2704,14 +2689,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController UUID region_uuid = (UUID) (string) requestData["region_uuid"]; if (!m_application.SceneManager.TrySetCurrentScene(region_uuid)) throw new Exception(String.Format("failed to switch to region {0}", region_uuid.ToString())); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_uuid.ToString()); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_uuid.ToString()); } else if (requestData.Contains("region_name")) { string region_name = (string) requestData["region_name"]; if (!m_application.SceneManager.TrySetCurrentScene(region_name)) throw new Exception(String.Format("failed to switch to region {0}", region_name)); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_name); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_name); } else throw new Exception("neither region_name nor region_uuid given"); @@ -2731,7 +2716,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController if (account != null) { uuids.Add(account.PrincipalID); - m_log.DebugFormat("[RADMIN] adding \"{0}\" to ACL for \"{1}\"", name, scene.RegionInfo.RegionName); + m_log.DebugFormat("[RADMIN]: adding \"{0}\" to ACL for \"{1}\"", name, scene.RegionInfo.RegionName); } } List accessControlList = new List(scene.RegionInfo.EstateSettings.EstateAccess); @@ -2752,7 +2737,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] Access List Add Request: {0}", e.Message); + m_log.ErrorFormat("[RADMIN]: Access List Add Request: {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -2791,14 +2776,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController UUID region_uuid = (UUID) (string) requestData["region_uuid"]; if (!m_application.SceneManager.TrySetCurrentScene(region_uuid)) throw new Exception(String.Format("failed to switch to region {0}", region_uuid.ToString())); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_uuid.ToString()); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_uuid.ToString()); } else if (requestData.Contains("region_name")) { string region_name = (string) requestData["region_name"]; if (!m_application.SceneManager.TrySetCurrentScene(region_name)) throw new Exception(String.Format("failed to switch to region {0}", region_name)); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_name); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_name); } else throw new Exception("neither region_name nor region_uuid given"); @@ -2839,7 +2824,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] Access List Remove Request: {0}", e.Message); + m_log.ErrorFormat("[RADMIN]: Access List Remove Request: {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; @@ -2878,14 +2863,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController UUID region_uuid = (UUID) (string) requestData["region_uuid"]; if (!m_application.SceneManager.TrySetCurrentScene(region_uuid)) throw new Exception(String.Format("failed to switch to region {0}", region_uuid.ToString())); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_uuid.ToString()); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_uuid.ToString()); } else if (requestData.Contains("region_name")) { string region_name = (string) requestData["region_name"]; if (!m_application.SceneManager.TrySetCurrentScene(region_name)) throw new Exception(String.Format("failed to switch to region {0}", region_name)); - m_log.InfoFormat("[RADMIN] Switched to region {0}", region_name); + m_log.InfoFormat("[RADMIN]: Switched to region {0}", region_name); } else throw new Exception("neither region_name nor region_uuid given"); @@ -2907,7 +2892,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } catch (Exception e) { - m_log.InfoFormat("[RADMIN] Acces List List: {0}", e.Message); + m_log.ErrorFormat("[RADMIN]: Access List List: {0} {1}", e.Message, e.StackTrace); responseData["success"] = false; responseData["error"] = e.Message; -- cgit v1.1 From cd6dce11086a4e8a06257659c19eaa66d3b1a951 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 15 Apr 2011 16:42:40 -0700 Subject: Fixes mantis #5431 -- coalesced objects in HG-enabled regions. Needs more testing to make sure HG inventory isn't broken by this (it shouldn't). --- .../InventoryAccess/HGInventoryAccessModule.cs | 27 +++------------------- .../InventoryAccess/InventoryAccessModule.cs | 10 +++++++- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 4565d10..8c99983 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -129,35 +129,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } /// - /// DeleteToInventory + /// Used in DeleteToInventory /// - public override UUID DeleteToInventory(DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient) + protected override void ExportAsset(UUID agentID, UUID assetID) { - UUID ret = UUID.Zero; - - // HACK: Only works for lists of length one. - // Intermediate version, just to make things compile - foreach (SceneObjectGroup g in objectGroups) - ret = DeleteToInventory(action, folderID, g, remoteClient); - - return ret; - } - - // DO NOT OVERRIDE THE BASE METHOD - public new virtual UUID DeleteToInventory(DeRezAction action, UUID folderID, - SceneObjectGroup objectGroup, IClientAPI remoteClient) - { - UUID assetID = base.DeleteToInventory(action, folderID, new List() {objectGroup}, remoteClient); - if (!assetID.Equals(UUID.Zero)) - { - if (remoteClient != null) - UploadInventoryItem(remoteClient.AgentId, assetID, "", 0); - } + UploadInventoryItem(agentID, assetID, "", 0); else m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); - - return assetID; } /// diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 8b68dbe..a716326 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -330,11 +330,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } } + + // This is a hook to do some per-asset post-processing for subclasses that need that + ExportAsset(remoteClient.AgentId, assetID); } return assetID; } - + + protected virtual void ExportAsset(UUID agentID, UUID assetID) + { + // nothing to do here + } + /// /// Add relevant permissions for an object to the item. /// -- cgit v1.1 From 3e0e1057acffa2c92a6f949cef0183193033d8c2 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Fri, 15 Apr 2011 16:44:53 -0700 Subject: Remove the call to remove tokens from the parent. Under heavy load this appears to cause problems with the system timer resolution. This caused a problem with tokens going into the root throttle as bursts leading to some starvation. Also changed EnqueueOutgoing to always queue a packet if there are already packets in the queue. Ensures consistent ordering of packet sends. --- OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 10 ++++++++++ OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | 9 ++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 5a69851..7be8a0a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -440,6 +440,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.LocklessQueue queue = m_packetOutboxes[category]; TokenBucket bucket = m_throttleCategories[category]; + // Don't send this packet if there is already a packet waiting in the queue + // even if we have the tokens to send it, tokens should go to the already + // queued packets + if (queue.Count > 0) + { + queue.Enqueue(packet); + return true; + } + + if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) { // Enough tokens were removed from the bucket, the packet will not be queued diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index e4d59ff..07b0a1d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs @@ -255,11 +255,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP // If we have enough tokens then remove them and return if (m_tokenCount - amount >= 0) { - if (m_parent == null || m_parent.RemoveTokens(amount)) - { - m_tokenCount -= amount; - return true; - } + // we don't have to remove from the parent, the drip rate is already + // reflective of the drip rate limits in the parent + m_tokenCount -= amount; + return true; } return false; -- cgit v1.1 From 70084c5e3a34e681357baf5506bd0c8f9815049b Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Sat, 16 Apr 2011 15:29:28 -0700 Subject: More descriptive debug msg for ServiceOSDRequest failures. --- OpenSim/Framework/WebUtil.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 64cd014..9d70f63 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -222,8 +222,8 @@ namespace OpenSim.Framework m_log.InfoFormat("[WEB UTIL]: osd request <{0}> (URI:{1}, METHOD:{2}) took {3}ms overall, {4}ms writing", reqnum,url,method,tickdiff,tickdata); } - - m_log.WarnFormat("[WEB UTIL] <{0}> osd request failed: {1}",reqnum,errorMessage); + + m_log.WarnFormat("[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage); return ErrorResponseMap(errorMessage); } -- cgit v1.1 From 03e725ad87916965ebcd8cb264f7a614342da9b7 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 17 Apr 2011 21:43:16 +0100 Subject: Mantis #5442: Add admin_save_heightmap --- .../RemoteController/RemoteAdminPlugin.cs | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index dc4309f..5a011ce 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -130,6 +130,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController availableMethods["admin_broadcast"] = XmlRpcAlertMethod; availableMethods["admin_restart"] = XmlRpcRestartMethod; availableMethods["admin_load_heightmap"] = XmlRpcLoadHeightmapMethod; + availableMethods["admin_save_heightmap"] = XmlRpcSaveHeightmapMethod; // User management availableMethods["admin_create_user"] = XmlRpcCreateUserMethod; availableMethods["admin_create_user_email"] = XmlRpcCreateUserMethod; @@ -357,6 +358,61 @@ namespace OpenSim.ApplicationPlugins.RemoteController return response; } + public XmlRpcResponse XmlRpcSaveHeightmapMethod(XmlRpcRequest request, IPEndPoint remoteClient) + + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + + m_log.Info("[RADMIN]: Save height maps request started"); + + try + { + Hashtable requestData = (Hashtable)request.Params[0]; + + m_log.DebugFormat("[RADMIN]: Save Terrain: XmlRpc {0}", request.ToString()); + + CheckStringParameters(request, new string[] { "password", "filename", "regionid" }); + + if (m_requiredPassword != String.Empty && + (!requestData.Contains("password") || (string)requestData["password"] != m_requiredPassword)) + throw new Exception("wrong password"); + + string file = (string)requestData["filename"]; + UUID regionID = (UUID)(string)requestData["regionid"]; + m_log.InfoFormat("[RADMIN]: Terrain Saving: {0}", file); + + responseData["accepted"] = true; + + Scene region = null; + + if (!m_application.SceneManager.TryGetScene(regionID, out region)) + throw new Exception("1: unable to get a scene with that name"); + + ITerrainModule terrainModule = region.RequestModuleInterface(); + if (null == terrainModule) throw new Exception("terrain module not available"); + + terrainModule.SaveToFile(file); + + responseData["success"] = false; + + response.Value = responseData; + } + catch (Exception e) + { + m_log.ErrorFormat("[RADMIN]: Terrain Saving: failed: {0}", e.Message); + m_log.DebugFormat("[RADMIN]: Terrain Saving: failed: {0}", e.ToString()); + + responseData["success"] = false; + responseData["error"] = e.Message; + + } + + m_log.Info("[RADMIN]: Save height maps request complete"); + + return response; + } + public XmlRpcResponse XmlRpcShutdownMethod(XmlRpcRequest request, IPEndPoint remoteClient) { m_log.Info("[RADMIN]: Received Shutdown Administrator Request"); -- cgit v1.1 From 419fc9427ef14eea443ec6f57501c6915c2de3b9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 20:03:53 +0100 Subject: Provide a configuration setting to control whether multiple taken objects are coalesced to inventory This is the CoalesceMultipleObjectsToInventory setting in [Inventory] in OpenSimDefaults.ini Default is true. --- .../InventoryAccess/HGInventoryAccessModule.cs | 3 ++ .../InventoryAccess/InventoryAccessModule.cs | 59 ++++++++++++++++------ bin/OpenSimDefaults.ini | 7 +++ 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 8c99983..52791cb 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -75,6 +75,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (name == Name) { m_Enabled = true; + + InitialiseCommon(source); + m_log.InfoFormat("[HG INVENTORY ACCESS MODULE]: {0} enabled.", Name); IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index a716326..e030ba1 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -64,7 +64,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return m_UserManagement; } } - + + public bool CoalesceMultipleObjectsToInventory { get; set; } #region INonSharedRegionModule @@ -87,10 +88,28 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (name == Name) { m_Enabled = true; - m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name); + + InitialiseCommon(source); + + m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name); } } } + + /// + /// Common module config for both this and descendant classes. + /// + /// + protected virtual void InitialiseCommon(IConfigSource source) + { + IConfig inventoryConfig = source.Configs["Inventory"]; + + if (inventoryConfig != null) + CoalesceMultipleObjectsToInventory + = inventoryConfig.GetBoolean("CoalesceMultipleObjectsToInventory", true); + else + CoalesceMultipleObjectsToInventory = true; + } public virtual void PostInitialise() { @@ -206,20 +225,30 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient) { - UUID ret = UUID.Zero; - - // The following code groups the SOG's by owner. No objects - // belonging to different people can be coalesced, for obvious - // reasons. - Dictionary> deletes = - new Dictionary>(); - - foreach (SceneObjectGroup g in objectGroups) + Dictionary> deletes = new Dictionary>(); + + if (CoalesceMultipleObjectsToInventory) { - if (!deletes.ContainsKey(g.OwnerID)) - deletes[g.OwnerID] = new List(); - - deletes[g.OwnerID].Add(g); + // The following code groups the SOG's by owner. No objects + // belonging to different people can be coalesced, for obvious + // reasons. + foreach (SceneObjectGroup g in objectGroups) + { + if (!deletes.ContainsKey(g.OwnerID)) + deletes[g.OwnerID] = new List(); + + deletes[g.OwnerID].Add(g); + } + } + else + { + // If we don't want to coalesce then put every object in its own bundle. + foreach (SceneObjectGroup g in objectGroups) + { + List bundle = new List(); + bundle.Add(g); + deletes[g.UUID] = bundle; + } } // This is method scoped and will be returned. It will be the diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 107e859..2e0a22b 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -453,6 +453,13 @@ ; ForwardOfflineGroupMessages = true +[Inventory] + ; Control whether multiple objects sent to inventory should be coaleseced into a single item + ; There are still some issues with coalescence, including the fact that rotation is not restored + ; and some assets may be missing from archive files. + CoalesceMultipleObjectsToInventory = true + + [ODEPhysicsSettings] ;## ;## World Settings -- cgit v1.1 From 5a404a9ab1b8c684e5704efe09205f44d4a2e353 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 21:07:11 +0100 Subject: Fix bug where objects were being coalesced in the wrong positions. This addresses http://opensimulator.org/mantis/view.php?id=5441 The bug was due to a pre-existing mistake in creating the inventory stored position --- .../CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index e030ba1..326ef28 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -269,9 +269,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess ? 250 : objectGroup.AbsolutePosition.X) , - (objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) + (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) ? 250 - : objectGroup.AbsolutePosition.X, + : objectGroup.AbsolutePosition.Y, objectGroup.AbsolutePosition.Z); originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; -- cgit v1.1 From 71114d4ad1c4aacbfedea9f4ab5307162ae5d9e0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 21:34:26 +0100 Subject: refactor: rename DeleteToInventory() to CopyToInventory() DeleteToInventory() is misleading - it is the caller that decides whether to delete or not --- .../Framework/InventoryAccess/InventoryAccessModule.cs | 2 +- .../Framework/Interfaces/IInventoryAccessModule.cs | 18 +++++++++++++++++- .../Framework/Scenes/AsyncSceneObjectGroupDeleter.cs | 3 ++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 326ef28..666f353 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -222,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// /// - public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID, + public virtual UUID CopyToInventory(DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient) { Dictionary> deletes = new Dictionary>(); diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index 05fc2ad..305975e 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs @@ -38,7 +38,23 @@ namespace OpenSim.Region.Framework.Interfaces public interface IInventoryAccessModule { UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data); - UUID DeleteToInventory(DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient); + + /// + /// Copy objects to a user's inventory. + /// + /// + /// Is it left to the caller to delete them from the scene if required. + /// + /// + /// + /// + /// + /// + /// Returns the UUID of the newly created item asset (not the item itself). + /// FIXME: This is not very useful. It would be far more useful to return a list of items instead. + /// + UUID CopyToInventory(DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient); + SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index 8feb022..3423542 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs @@ -143,7 +143,8 @@ namespace OpenSim.Region.Framework.Scenes { IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); if (invAccess != null) - invAccess.DeleteToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient); + invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient); + if (x.permissionToDelete) { foreach (SceneObjectGroup g in x.objectGroups) -- cgit v1.1 From 61619ddefc96be2c1f802360cca48b1b36be8bb2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 21:59:01 +0100 Subject: refactor: split out the code which actually copies a particular bundle to inventory --- .../InventoryAccess/InventoryAccessModule.cs | 221 +++++++++++---------- 1 file changed, 115 insertions(+), 106 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 666f353..6b3df9d 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -213,19 +213,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return UUID.Zero; } - - /// - /// Delete a scene object from a scene and place in the given avatar's inventory. - /// Returns the UUID of the newly created asset. - /// - /// - /// - /// - /// + public virtual UUID CopyToInventory(DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient) { - Dictionary> deletes = new Dictionary>(); + Dictionary> bundlesToCopy = new Dictionary>(); if (CoalesceMultipleObjectsToInventory) { @@ -234,10 +226,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // reasons. foreach (SceneObjectGroup g in objectGroups) { - if (!deletes.ContainsKey(g.OwnerID)) - deletes[g.OwnerID] = new List(); + if (!bundlesToCopy.ContainsKey(g.OwnerID)) + bundlesToCopy[g.OwnerID] = new List(); - deletes[g.OwnerID].Add(g); + bundlesToCopy[g.OwnerID].Add(g); } } else @@ -247,7 +239,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { List bundle = new List(); bundle.Add(g); - deletes[g.UUID] = bundle; + bundlesToCopy[g.UUID] = bundle; } } @@ -257,112 +249,129 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Each iteration is really a separate asset being created, // with distinct destinations as well. - foreach (List objlist in deletes.Values) + foreach (List bundle in bundlesToCopy.Values) + assetID = CopyBundleToInventory(action, folderID, bundle, remoteClient); + + return assetID; + } + + /// + /// Copy a bundle of objects to inventory. If there is only one object, then this will create an object + /// item. If there are multiple objects then these will be saved as a single coalesced item. + /// + /// + /// + /// + /// + /// + protected UUID CopyBundleToInventory( + DeRezAction action, UUID folderID, List objlist, IClientAPI remoteClient) + { + UUID assetID = UUID.Zero; + + CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); + Dictionary originalPositions = new Dictionary(); + + foreach (SceneObjectGroup objectGroup in objlist) { - CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); - Dictionary originalPositions = new Dictionary(); + Vector3 inventoryStoredPosition = new Vector3 + (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) + ? 250 + : objectGroup.AbsolutePosition.X) + , + (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) + ? 250 + : objectGroup.AbsolutePosition.Y, + objectGroup.AbsolutePosition.Z); + + originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; + + objectGroup.AbsolutePosition = inventoryStoredPosition; + + // Make sure all bits but the ones we want are clear + // on take. + // This will be applied to the current perms, so + // it will do what we want. + objectGroup.RootPart.NextOwnerMask &= + ((uint)PermissionMask.Copy | + (uint)PermissionMask.Transfer | + (uint)PermissionMask.Modify); + objectGroup.RootPart.NextOwnerMask |= + (uint)PermissionMask.Move; + + coa.Add(objectGroup); + } - foreach (SceneObjectGroup objectGroup in objlist) - { - Vector3 inventoryStoredPosition = new Vector3 - (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) - ? 250 - : objectGroup.AbsolutePosition.X) - , - (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) - ? 250 - : objectGroup.AbsolutePosition.Y, - objectGroup.AbsolutePosition.Z); - - originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; - - objectGroup.AbsolutePosition = inventoryStoredPosition; - - // Make sure all bits but the ones we want are clear - // on take. - // This will be applied to the current perms, so - // it will do what we want. - objectGroup.RootPart.NextOwnerMask &= - ((uint)PermissionMask.Copy | - (uint)PermissionMask.Transfer | - (uint)PermissionMask.Modify); - objectGroup.RootPart.NextOwnerMask |= - (uint)PermissionMask.Move; - - coa.Add(objectGroup); - } + string itemXml; - string itemXml; + if (objlist.Count > 1) + itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); + else + itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); + + // Restore the position of each group now that it has been stored to inventory. + foreach (SceneObjectGroup objectGroup in objlist) + objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; - if (objlist.Count > 1) - itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); - else - itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); - - // Restore the position of each group now that it has been stored to inventory. - foreach (SceneObjectGroup objectGroup in objlist) - objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; + InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); + if (item == null) + return UUID.Zero; + + // Can't know creator is the same, so null it in inventory + if (objlist.Count > 1) + { + item.CreatorId = UUID.Zero.ToString(); + item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; + } + else + { + item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); + item.SaleType = objlist[0].RootPart.ObjectSaleType; + item.SalePrice = objlist[0].RootPart.SalePrice; + } + + AssetBase asset = CreateAsset( + objlist[0].GetPartName(objlist[0].RootPart.LocalId), + objlist[0].GetPartDescription(objlist[0].RootPart.LocalId), + (sbyte)AssetType.Object, + Utils.StringToBytes(itemXml), + objlist[0].OwnerID.ToString()); + m_Scene.AssetService.Store(asset); + + item.AssetID = asset.FullID; + assetID = asset.FullID; - InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); - if (item == null) - return UUID.Zero; - - // Can't know creator is the same, so null it in inventory - if (objlist.Count > 1) - { - item.CreatorId = UUID.Zero.ToString(); - item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; - } - else - { - item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); - item.SaleType = objlist[0].RootPart.ObjectSaleType; - item.SalePrice = objlist[0].RootPart.SalePrice; - } - - AssetBase asset = CreateAsset( - objlist[0].GetPartName(objlist[0].RootPart.LocalId), - objlist[0].GetPartDescription(objlist[0].RootPart.LocalId), - (sbyte)AssetType.Object, - Utils.StringToBytes(itemXml), - objlist[0].OwnerID.ToString()); - m_Scene.AssetService.Store(asset); - - item.AssetID = asset.FullID; - assetID = asset.FullID; + if (DeRezAction.SaveToExistingUserInventoryItem == action) + { + m_Scene.InventoryService.UpdateItem(item); + } + else + { + AddPermissions(item, objlist[0], objlist, remoteClient); + + item.CreationDate = Util.UnixTimeSinceEpoch(); + item.Description = asset.Description; + item.Name = asset.Name; + item.AssetType = asset.Type; - if (DeRezAction.SaveToExistingUserInventoryItem == action) + m_Scene.AddInventoryItem(item); + + if (remoteClient != null && item.Owner == remoteClient.AgentId) { - m_Scene.InventoryService.UpdateItem(item); + remoteClient.SendInventoryItemCreateUpdate(item, 0); } else { - AddPermissions(item, objlist[0], objlist, remoteClient); - - item.CreationDate = Util.UnixTimeSinceEpoch(); - item.Description = asset.Description; - item.Name = asset.Name; - item.AssetType = asset.Type; - - m_Scene.AddInventoryItem(item); - - if (remoteClient != null && item.Owner == remoteClient.AgentId) + ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner); + if (notifyUser != null) { - remoteClient.SendInventoryItemCreateUpdate(item, 0); - } - else - { - ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner); - if (notifyUser != null) - { - notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); - } + notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); } } - - // This is a hook to do some per-asset post-processing for subclasses that need that - ExportAsset(remoteClient.AgentId, assetID); } + + // This is a hook to do some per-asset post-processing for subclasses that need that + ExportAsset(remoteClient.AgentId, assetID); return assetID; } -- cgit v1.1 From e00e518692bd3d123db69dceb98b80d3bdd59156 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 22:24:42 +0100 Subject: add test to ensure that an IAR starts with the control file --- .../Archiver/InventoryArchiveReadRequest.cs | 21 ++++++++-------- .../Archiver/Tests/InventoryArchiverTests.cs | 29 +++++++++++++++++++++- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index f3d2f26..9acdc90 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -77,12 +77,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// private Stream m_loadStream; - /// - /// FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things - /// (I thought they weren't). We will need to bump the version number and perform this check on all - /// subsequent IAR versions only - /// - protected bool m_controlFileLoaded = true; + public bool ControlFileLoaded { get; private set; } + protected bool m_assetsLoaded; protected bool m_inventoryNodesLoaded; @@ -131,6 +127,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_userInfo = userInfo; m_invPath = invPath; m_loadStream = loadStream; + + // FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things + // (I thought they weren't). We will need to bump the version number and perform this check on all + // subsequent IAR versions only + ControlFileLoaded = true; } /// @@ -522,7 +523,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// /// - protected void LoadControlFile(string path, byte[] data) + public void LoadControlFile(string path, byte[] data) { XDocument doc = XDocument.Parse(Encoding.ASCII.GetString(data)); XElement archiveElement = doc.Element("archive"); @@ -538,7 +539,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver majorVersion, MAX_MAJOR_VERSION)); } - m_controlFileLoaded = true; + ControlFileLoaded = true; m_log.InfoFormat("[INVENTORY ARCHIVER]: Loading IAR with version {0}", version); } @@ -550,7 +551,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// protected void LoadInventoryFile(string path, TarArchiveReader.TarEntryType entryType, byte[] data) { - if (!m_controlFileLoaded) + if (!ControlFileLoaded) throw new Exception( string.Format( "The IAR you are trying to load does not list {0} before {1}. Aborting load", @@ -597,7 +598,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// protected void LoadAssetFile(string path, byte[] data) { - if (!m_controlFileLoaded) + if (!ControlFileLoaded) throw new Exception( string.Format( "The IAR you are trying to load does not list {0} before {1}. Aborting load", diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index d03f6da..52232a0 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -94,7 +94,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140"))); Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); - } + } + + /// + /// Test that the IAR has the required files in the right order. + /// + /// + /// At the moment, the only thing that matters is that the control file is the very first one. + /// + [Test] + public void TestOrder() + { + TestHelper.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + MemoryStream archiveReadStream = new MemoryStream(m_iarStreamBytes); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + + byte[] data = tar.ReadEntry(out filePath, out tarEntryType); + Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); + + InventoryArchiveReadRequest iarr + = new InventoryArchiveReadRequest(null, null, null, (Stream)null, false); + iarr.LoadControlFile(filePath, data); + + Assert.That(iarr.ControlFileLoaded, Is.True); + } /// /// Test saving a single inventory item to a V0.1 OpenSim Inventory Archive -- cgit v1.1 From 6600aa2baf56e1f58e50eb5589de876e910131bb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 22:35:33 +0100 Subject: Add regression test to check that OARs start with the control file. --- .../Inventory/Archiver/InventoryArchiveReadRequest.cs | 3 +++ .../CoreModules/World/Archiver/ArchiveReadRequest.cs | 9 ++++++++- .../CoreModules/World/Archiver/Tests/ArchiverTests.cs | 18 ++++++++++-------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 9acdc90..a12931f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -77,6 +77,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// private Stream m_loadStream; + /// + /// Has the control file been loaded for this archive? + /// public bool ControlFileLoaded { get; private set; } protected bool m_assetsLoaded; diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index fd8f546..82bef48 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs @@ -57,6 +57,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// bumps here should be compatible. /// public static int MAX_MAJOR_VERSION = 1; + + /// + /// Has the control file been loaded for this archive? + /// + public bool ControlFileLoaded { get; private set; } protected Scene m_scene; protected Stream m_loadStream; @@ -527,7 +532,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// /// - protected void LoadControlFile(string path, byte[] data) + public void LoadControlFile(string path, byte[] data) { XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); @@ -573,6 +578,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver } currentRegionSettings.Save(); + + ControlFileLoaded = true; } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index e2760a2..2307c8e 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs @@ -171,7 +171,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests MemoryStream archiveReadStream = new MemoryStream(archive); TarArchiveReader tar = new TarArchiveReader(archiveReadStream); - bool gotControlFile = false; bool gotNcAssetFile = false; string expectedNcAssetFileName = string.Format("{0}_{1}", ncAssetUuid, "notecard.txt"); @@ -182,15 +181,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2)); string filePath; - TarArchiveReader.TarEntryType tarEntryType; + TarArchiveReader.TarEntryType tarEntryType; + byte[] data = tar.ReadEntry(out filePath, out tarEntryType); + Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); + + ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); + arr.LoadControlFile(filePath, data); + + Assert.That(arr.ControlFileLoaded, Is.True); + while (tar.ReadEntry(out filePath, out tarEntryType) != null) { - if (ArchiveConstants.CONTROL_FILE_PATH == filePath) - { - gotControlFile = true; - } - else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) + if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) { string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); @@ -203,7 +206,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests } } - Assert.That(gotControlFile, Is.True, "No control file in archive"); Assert.That(gotNcAssetFile, Is.True, "No notecard asset file in archive"); Assert.That(foundPaths, Is.EquivalentTo(expectedPaths)); -- cgit v1.1 From 61096050386c8ec63d8d92c6ac7b183ddaa77c26 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 22:42:36 +0100 Subject: bump oar version number to 0.6. This commit contains no data changes - the version bump is to establish a version at which the control file must come first in the archive. --- .../Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs index f2d487e..597b780 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs @@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// public static string CreateControlFile(Dictionary options) { - int majorVersion = MAX_MAJOR_VERSION, minorVersion = 5; + int majorVersion = MAX_MAJOR_VERSION, minorVersion = 6; // // if (options.ContainsKey("version")) // { -- cgit v1.1 From f5a041d01292adb2b1e650cb9eba0806121d2ddf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 23:00:41 +0100 Subject: bump default IAR version to 0.2 and 1.1 for the --profile version. There are no changes in this bump, they just signal a point at which the control file comes first in the archive. --- .../Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index dc4900f..c039b5a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -394,12 +394,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (options.ContainsKey("profile")) { majorVersion = 1; - minorVersion = 0; + minorVersion = 1; } else { majorVersion = 0; - minorVersion = 1; + minorVersion = 2; } m_log.InfoFormat("[INVENTORY ARCHIVER]: Creating version {0}.{1} IAR", majorVersion, minorVersion); -- cgit v1.1 From 36c4e94ef739f2d58ff26ae2313e5a930ff02021 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Apr 2011 23:22:04 +0100 Subject: Move mesh on/off swtich from [Startup] to [Mesh] in anticipation of future config parameters. Default remains true. OpenSimDefault.ini changed so if you haven't overriden this switch then you don't need to do anything. --- OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs | 7 +++---- .../Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs | 7 +++---- .../Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs | 6 ++++++ bin/OpenSimDefaults.ini | 10 ++++++---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs index d2278bc..deec444 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs @@ -66,12 +66,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void Initialise(IConfigSource source) { - IConfig startupConfig = source.Configs["Startup"]; - if (startupConfig == null) + IConfig meshConfig = source.Configs["Mesh"]; + if (meshConfig == null) return; - if (!startupConfig.GetBoolean("ColladaMesh",true)) - m_enabled = false; + m_enabled = meshConfig.GetBoolean("ColladaMesh", true); } public void AddRegion(Scene pScene) diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs index fb07cc9..d651cb2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs @@ -68,12 +68,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void Initialise(IConfigSource source) { - IConfig startupConfig = source.Configs["Startup"]; - if (startupConfig == null) + IConfig meshConfig = source.Configs["Mesh"]; + if (meshConfig == null) return; - if (!startupConfig.GetBoolean("ColladaMesh",true)) - m_enabled = false; + m_enabled = meshConfig.GetBoolean("ColladaMesh", true); } public void AddRegion(Scene pScene) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index a12931f..6b24718 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -82,6 +82,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// public bool ControlFileLoaded { get; private set; } + /// + /// Do we want to enforce the check. IAR versions before 0.2 and 1.1 do not guarantee this order, so we can't + /// enforce. + /// + public bool EnforceControlFileCheck { get; private set; } + protected bool m_assetsLoaded; protected bool m_inventoryNodesLoaded; diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 2e0a22b..e72e851 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -155,10 +155,6 @@ ; it may cause unexpected physics problems. ;UseMeshiesPhysicsMesh = false - ; enable / disable Collada mesh support - ; default is true - ; ColladaMesh = true - ; Choose one of the physics engines below ; OpenDynamicsEngine is by some distance the most developed physics engine ; basicphysics effectively does not model physics at all, making all objects phantom @@ -460,6 +456,12 @@ CoalesceMultipleObjectsToInventory = true +[Mesh] + ; enable / disable Collada mesh support + ; default is true + ; ColladaMesh = true + + [ODEPhysicsSettings] ;## ;## World Settings -- cgit v1.1 From 2fa210243b64bb10fbca37f89176f10efeb25f41 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 19 Apr 2011 21:54:26 +0100 Subject: Clean up freeswitch config to what is currently required. Add explanation to config parameters. Clean up some log messages. --- .../Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs | 28 ++++++++------- .../FreeswitchService/FreeswitchService.cs | 29 ++++++++------- .../FreeswitchService/FreeswitchServiceBase.cs | 2 +- bin/OpenSim.ini.example | 42 +++++++++++++++------- bin/Robust.ini.example | 38 ++++++++++++++------ bin/config-include/StandaloneCommon.ini.example | 18 +++------- 6 files changed, 95 insertions(+), 62 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs index 7909d8a..962b5ca 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs @@ -118,7 +118,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice if (serviceDll == String.Empty) { - m_log.Error("[FreeSwitchVoice]: No LocalServiceModule named in section FreeSwitchVoice"); + m_log.Error("[FreeSwitchVoice]: No LocalServiceModule named in section FreeSwitchVoice. Not starting."); return; } @@ -143,8 +143,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice if (String.IsNullOrEmpty(m_freeSwitchRealm) || String.IsNullOrEmpty(m_freeSwitchAPIPrefix)) { - m_log.Error("[FreeSwitchVoice] plugin mis-configured"); - m_log.Info("[FreeSwitchVoice] plugin disabled: incomplete configuration"); + m_log.Error("[FreeSwitchVoice]: Freeswitch service mis-configured. Not starting."); return; } @@ -172,16 +171,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_buddy.php", m_freeSwitchAPIPrefix), FreeSwitchSLVoiceBuddyHTTPHandler); - m_log.InfoFormat("[FreeSwitchVoice] using FreeSwitch server {0}", m_freeSwitchRealm); + m_log.InfoFormat("[FreeSwitchVoice]: using FreeSwitch server {0}", m_freeSwitchRealm); m_Enabled = true; - m_log.Info("[FreeSwitchVoice] plugin enabled"); + m_log.Info("[FreeSwitchVoice]: plugin enabled"); } catch (Exception e) { - m_log.ErrorFormat("[FreeSwitchVoice] plugin initialization failed: {0}", e.Message); - m_log.DebugFormat("[FreeSwitchVoice] plugin initialization failed: {0}", e.ToString()); + m_log.ErrorFormat("[FreeSwitchVoice]: plugin initialization failed: {0} {1}", e.Message, e.StackTrace); return; } @@ -240,7 +238,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice { if (m_Enabled) { - m_log.Info("[FreeSwitchVoice] registering IVoiceModule with the scene"); + m_log.Info("[FreeSwitchVoice]: registering IVoiceModule with the scene"); // register the voice interface for this module, so the script engine can call us scene.RegisterModuleInterface(this); @@ -302,7 +300,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice // public void OnRegisterCaps(Scene scene, UUID agentID, Caps caps) { - m_log.DebugFormat("[FreeSwitchVoice] OnRegisterCaps: agentID {0} caps {1}", agentID, caps); + m_log.DebugFormat( + "[FreeSwitchVoice]: OnRegisterCaps called with agentID {0} caps {1} in scene {2}", + agentID, caps, scene.RegionInfo.RegionName); string capsBase = "/CAPS/" + caps.CapsObjectPath; caps.RegisterHandler("ProvisionVoiceAccountRequest", @@ -558,7 +558,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request) { - m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceGetPreloginHTTPHandler called"); + m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceGetPreloginHTTPHandler called"); Hashtable response = new Hashtable(); response["content_type"] = "text/xml"; @@ -664,7 +664,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request) { - m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceSigninHTTPHandler called"); + m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceSigninHTTPHandler called"); // string requestbody = (string)request["body"]; // string uri = (string)request["uri"]; // string contenttype = (string)request["content-type"]; @@ -795,16 +795,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice response["keepalive"] = false; response["int_response_code"] = 500; - Hashtable requestBody = ParseRequestBody((string) request["body"]); + Hashtable requestBody = ParseRequestBody((string)request["body"]); string section = (string) requestBody["section"]; + + m_log.DebugFormat("[FreeSwitchVoice]: Received request for config section {0}", section); if (section == "directory") response = m_FreeswitchService.HandleDirectoryRequest(requestBody); else if (section == "dialplan") response = m_FreeswitchService.HandleDialplanRequest(requestBody); else - m_log.WarnFormat("[FreeSwitchVoice]: section was {0}", section); + m_log.WarnFormat("[FreeSwitchVoice]: Unknown section {0} was requested.", section); return response; } diff --git a/OpenSim/Services/FreeswitchService/FreeswitchService.cs b/OpenSim/Services/FreeswitchService/FreeswitchService.cs index fe6f5cd..1ec89da 100644 --- a/OpenSim/Services/FreeswitchService/FreeswitchService.cs +++ b/OpenSim/Services/FreeswitchService/FreeswitchService.cs @@ -50,13 +50,13 @@ namespace OpenSim.Services.FreeswitchService public Hashtable HandleDialplanRequest(Hashtable request) { - m_log.DebugFormat("[FreeSwitchVoice] HandleDialplanRequest called with {0}",request.ToString()); + m_log.DebugFormat("[FreeSwitchVoice]: HandleDialplanRequest called with {0}",request.ToString()); Hashtable response = new Hashtable(); foreach (DictionaryEntry item in request) { - m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}",item.Key, item.Value); + m_log.InfoFormat("[FreeSwitchDirectory]: requestBody item {0} {1}",item.Key, item.Value); } string requestcontext = (string) request["Hunt-Context"]; @@ -66,7 +66,7 @@ namespace OpenSim.Services.FreeswitchService if (m_freeSwitchContext != String.Empty && m_freeSwitchContext != requestcontext) { - m_log.Debug("[FreeSwitchDirectory] returning empty as it's for another context"); + m_log.Debug("[FreeSwitchDirectory]: returning empty as it's for another context"); response["str_response_string"] = ""; } else @@ -116,13 +116,16 @@ namespace OpenSim.Services.FreeswitchService { Hashtable response = new Hashtable(); string domain = (string) request["domain"]; - if (domain != m_freeSwitchRealm) { + if (domain != m_freeSwitchRealm) + { response["content_type"] = "text/xml"; response["keepalive"] = false; response["int_response_code"] = 200; response["str_response_string"] = ""; - } else { - m_log.DebugFormat("[FreeSwitchDirectory] HandleDirectoryRequest called with {0}",request.ToString()); + } + else + { +// m_log.DebugFormat("[FreeSwitchDirectory]: HandleDirectoryRequest called with {0}",request.ToString()); // information in the request we might be interested in @@ -145,7 +148,7 @@ namespace OpenSim.Services.FreeswitchService foreach (DictionaryEntry item in request) { - m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}", item.Key, item.Value); + m_log.DebugFormat("[FreeSwitchDirectory]: requestBody item {0} {1}", item.Key, item.Value); } string eventCallingFunction = (string) request["Event-Calling-Function"]; @@ -173,7 +176,7 @@ namespace OpenSim.Services.FreeswitchService } else { - m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown sip_auth_method {0}",sipAuthMethod); + m_log.ErrorFormat("[FreeSwitchVoice]: HandleDirectoryRequest unknown sip_auth_method {0}",sipAuthMethod); response["int_response_code"] = 404; response["content_type"] = "text/xml"; response["str_response_string"] = ""; @@ -205,7 +208,7 @@ namespace OpenSim.Services.FreeswitchService } else { - m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown Event-Calling-Function {0}",eventCallingFunction); + m_log.ErrorFormat("[FreeSwitchVoice]: HandleDirectoryRequest unknown Event-Calling-Function {0}",eventCallingFunction); response["int_response_code"] = 404; response["keepalive"] = false; response["content_type"] = "text/xml"; @@ -217,7 +220,7 @@ namespace OpenSim.Services.FreeswitchService private Hashtable HandleRegister(string Context, string Realm, Hashtable request) { - m_log.Info("[FreeSwitchDirectory] HandleRegister called"); + m_log.Info("[FreeSwitchDirectory]: HandleRegister called"); // TODO the password we return needs to match that sent in the request, this is hard coded for now string password = "1234"; @@ -254,7 +257,7 @@ namespace OpenSim.Services.FreeswitchService private Hashtable HandleInvite(string Context, string Realm, Hashtable request) { - m_log.Info("[FreeSwitchDirectory] HandleInvite called"); + m_log.Info("[FreeSwitchDirectory]: HandleInvite called"); // TODO the password we return needs to match that sent in the request, this is hard coded for now string password = "1234"; @@ -301,7 +304,7 @@ namespace OpenSim.Services.FreeswitchService private Hashtable HandleLocateUser(String Realm, Hashtable request) { - m_log.Info("[FreeSwitchDirectory] HandleLocateUser called"); + m_log.Info("[FreeSwitchDirectory]: HandleLocateUser called"); // TODO the password we return needs to match that sent in the request, this is hard coded for now string domain = (string) request["domain"]; @@ -335,7 +338,7 @@ namespace OpenSim.Services.FreeswitchService private Hashtable HandleConfigSofia(string Context, string Realm, Hashtable request) { - m_log.Info("[FreeSwitchDirectory] HandleConfigSofia called"); + m_log.Info("[FreeSwitchDirectory]: HandleConfigSofia called."); // TODO the password we return needs to match that sent in the request, this is hard coded for now string domain = (string) request["domain"]; diff --git a/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs b/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs index ebbb1b0..25c18b6 100644 --- a/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs +++ b/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs @@ -64,7 +64,7 @@ namespace OpenSim.Services.FreeswitchService m_freeSwitchDefaultWellKnownIP = freeswitchConfig.GetString("ServerAddress", String.Empty); if (m_freeSwitchDefaultWellKnownIP == String.Empty) { - m_log.Error("[FREESWITCH]: No FreeswitchServerAddress given, can't continue"); + m_log.Error("[FREESWITCH]: No ServerAddress given, cannot start service."); return; } diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index c05c3de..fbaa590 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -621,10 +621,11 @@ ;; You need to load a local service for a standalone, and a remote service ;; for a grid region. Use one of the lines below, as appropriate + ;; If you're using Freeswitch on a standalone then you will also need to configure the [FreeswitchService] section ; LocalServiceModule = OpenSim.Services.FreeswitchService.dll:FreeswitchService ; LocalServiceModule = OpenSim.Services.Connectors.dll:RemoteFreeswitchConnector - ;; If using a remote module, specify the server URL + ;; If using a remote connector, specify the server URL ; FreeswitchServiceURL = http://my.grid.server:8003/fsapi @@ -632,20 +633,37 @@ ;; !!!!!!!!!!!!!!!!!!!!!!!!!!! ;; !!!!!!STANDALONE ONLY!!!!!! ;; !!!!!!!!!!!!!!!!!!!!!!!!!!! - ;; IP of your FS server - ;ServerAddress = 85.25.142.92 + ;; The IP address of your FreeSWITCH server. The common case is for this to be the same as the server running the OpenSim standalone + ;; This has to be set for the FreeSWITCH service to work + ;ServerAddress = 127.0.0.1 - ;; All other options are - well - optional - ; Realm = "127.0.0.1" - ; SIPProxy = "127.0.0.1:5060" - ; EchoServer = "127.0.0.1" - ; EchoPort = 50505 - ; AttemptSTUN = "false" + ;; The following configuration parameters are optional + + ;; By default, this is the same as the ServerAddress + ; Realm = 127.0.0.1 + + ;; By default, this is the same as the ServerAddress on port 5060 + ; SIPProxy = 127.0.0.1:5060 + + ;; Default is 5000ms ; DefaultTimeout = 5000 - ; Context = "default" - ; UserName = "freeswitch" - ; Password = "password" + ;; The dial plan context. Default is "default" + ; Context = default + + ;; Currently unused + ; UserName = freeswitch + + ;; Currently unused + ; Password = password + + ;; The following parameters are for STUN = Simple Traversal of UDP through NATs + ;; See http://wiki.freeswitch.org/wiki/NAT_Traversal + ;; stun.freeswitch.org is not guaranteed to be running so use it in + ;; production at your own risk + ; EchoServer = 127.0.0.1 + ; EchoPort = 50505 + ; AttemptSTUN = false [Groups] ;# {Enabled} {} {Enable groups?} {true false} false diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 7c13076..4d16236 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -69,19 +69,37 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ; * This is the configuration for the freeswitch server in grid mode [FreeswitchService] LocalServiceModule = "OpenSim.Services.FreeswitchService.dll:FreeswitchService" - ;; IP of your FS server + + ;; The IP address of your FreeSWITCH server. ; ServerAddress = 127.0.0.1 - ;; All other options are - well - optional - ; Realm = "127.0.0.1" - ; SIPProxy = "127.0.0.1:5060" - ; EchoServer = "127.0.0.1" - ; EchoPort = 50505 - ; AttemptSTUN = "false" + ;; The following configuration parameters are optional + + ;; By default, this is the same as the ServerAddress + ; Realm = 127.0.0.1 + + ;; By default, this is the same as the ServerAddress on port 5060 + ; SIPProxy = 127.0.0.1:5060 + + ;; Default is 5000ms ; DefaultTimeout = 5000 - ; Context = "default" - ; UserName = "freeswitch" - ; Password = "password" + + ;; The dial plan context. Default is "default" + ; Context = default + + ;; Currently unused + ; UserName = freeswitch + + ;; Currently unused + ; Password = password + + ;; The following parameters are for STUN = Simple Traversal of UDP through NATs + ;; See http://wiki.freeswitch.org/wiki/NAT_Traversal + ;; stun.freeswitch.org is not guaranteed to be running so use it in + ;; production at your own risk + ; EchoServer = 127.0.0.1 + ; EchoPort = 50505 + ; AttemptSTUN = false ; * This is the new style authentication service. Currently, only MySQL ; * is implemented. diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index d6f15bb..dcebd63 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -28,10 +28,10 @@ [HGInventoryAccessModule] ProfileServerURI = "http://127.0.0.1:9000/profiles" - ;; If you want to protect your assets from being copied by foreign visitors - ;; uncomment the next line. You may want to do this on sims that have licensed content. - ; OutboundPermission = False + ;; If you want to protect your assets from being copied by foreign visitors + ;; uncomment the next line. You may want to do this on sims that have licensed content. + ; OutboundPermission = False [Modules] ;; Choose 0 or 1 cache modules, and the corresponding config file, if it exists. @@ -45,16 +45,9 @@ AssetCaching = "CenomeMemoryAssetCache" Include-CenomeCache = "config-include/CenomeCache.ini" - ;; Enable this to use Freeswitch on a standalone - ;FreeswitchServiceInConnector = True - ;; Authorization is not on by default, as it depends on external php ;AuthorizationServices = "LocalAuthorizationServicesConnector" -[FreeswitchService] - ;; Configuration for the freeswitch service goes here - LocalServiceModule = "OpenSim.Services.FreeswitchService.dll:FreeswitchService" - [GridService] ;; For in-memory region storage (default) StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" @@ -74,9 +67,8 @@ Region_Welcome_Area = "DefaultRegion, FallbackRegion" ; === HG ONLY === - ;; change this to the address of your simulator - Gatekeeper="http://127.0.0.1:9000" - + ;; change this to the address of your simulator + Gatekeeper="http://127.0.0.1:9000" [LibraryModule] ; Set this if you want to change the name of the OpenSim Library -- cgit v1.1 From 575257f3fe7c18bd831c6b0ad63ba30488b075cc Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 19 Apr 2011 21:58:55 +0100 Subject: For consistency, uncomment ColladaMesh option in OpenSimDefaults.ini. Thanks for the spot, Ai Austin. --- bin/OpenSimDefaults.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index e72e851..30ebf84 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -459,7 +459,7 @@ [Mesh] ; enable / disable Collada mesh support ; default is true - ; ColladaMesh = true + ColladaMesh = true [ODEPhysicsSettings] -- cgit v1.1 From b786860bac7adec165843374ebe72b28f9519b78 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 19 Apr 2011 22:38:15 +0100 Subject: synchronize Robust.HG.ini.example FreeSWITCH config with other config files --- bin/Robust.HG.ini.example | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index f12a143..ced2857 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -85,19 +85,41 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ; * This is the configuration for the freeswitch server in grid mode [FreeswitchService] LocalServiceModule = "OpenSim.Services.FreeswitchService.dll:FreeswitchService" - ;; IP of your FS server + + ;; The IP address of your FreeSWITCH server. ; ServerAddress = 127.0.0.1 - ;; All other options are - well - optional - ; Realm = "127.0.0.1" - ; SIPProxy = "127.0.0.1:5060" - ; EchoServer = "127.0.0.1" - ; EchoPort = 50505 - ; AttemptSTUN = "false" + ;; The following configuration parameters are optional + + ;; By default, this is the same as the ServerAddress + ; Realm = 127.0.0.1 + + ;; By default, this is the same as the ServerAddress on port 5060 + ; SIPProxy = 127.0.0.1:5060 + + ;; Default is 5000ms ; DefaultTimeout = 5000 - ; Context = "default" - ; UserName = "freeswitch" - ; Password = "password" + + ;; The dial plan context. Default is "default" + ; Context = default + + ;; Currently unused + ; UserName = freeswitch + + ;; Currently unused + ; Password = password + + ;; The following parameters are for STUN = Simple Traversal of UDP through NATs + ;; See http://wiki.freeswitch.org/wiki/NAT_Traversal + ;; stun.freeswitch.org is not guaranteed to be running so use it in + ;; production at your own risk + ; EchoServer = 127.0.0.1 + ; EchoPort = 50505 + ; AttemptSTUN = false + + LocalServiceModule = "OpenSim.Services.FreeswitchService.dll:FreeswitchService" + ;; IP of your FS server + ; ServerAddress = 127.0.0.1 ; * This is the new style authentication service. Currently, only MySQL ; * is implemented. -- cgit v1.1 From ccc26f74436f0e3069587efd96497053e4129c3c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 20 Apr 2011 01:02:40 +0100 Subject: Get Viewer 2 voice working with OpenSim. See http://opensimulator.org/mantis/view.php?id=5336 It turns out that viewer 2 was upset by the lack of a response to viv_watcher.php. This would send it into a continuous login loop. Viewer 1 was quite happy to ignore the lack of response. This commit puts in the bare minimum 'OK' message in response to viv_watcher.php. This allows viewer 2 voice to connect and appears to work. However, at some point we need to fill out the watcher response, whatever that is. --- .../Framework/Servers/HttpServer/BaseHttpServer.cs | 2 +- .../Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs | 79 ++++++++++++++++++---- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index ccec9b7..ba89e21 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -430,7 +430,7 @@ namespace OpenSim.Framework.Servers.HttpServer string path = request.RawUrl; string handlerKey = GetHandlerKey(request.HttpMethod, path); - //m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); +// m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); if (TryGetStreamHandler(handlerKey, out requestHandler)) { diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs index 962b5ca..373ffeb 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs @@ -163,13 +163,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice // String.Format("{0}/viv_get_prelogin.php", m_freeSwitchAPIPrefix), FreeSwitchSLVoiceGetPreloginHTTPHandler); // MainServer.Instance.AddStreamHandler(h); - - MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_signin.php", m_freeSwitchAPIPrefix), FreeSwitchSLVoiceSigninHTTPHandler); MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_buddy.php", m_freeSwitchAPIPrefix), FreeSwitchSLVoiceBuddyHTTPHandler); + + MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_watcher.php", m_freeSwitchAPIPrefix), + FreeSwitchSLVoiceWatcherHTTPHandler); m_log.InfoFormat("[FreeSwitchVoice]: using FreeSwitch server {0}", m_freeSwitchRealm); @@ -301,7 +302,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice public void OnRegisterCaps(Scene scene, UUID agentID, Caps caps) { m_log.DebugFormat( - "[FreeSwitchVoice]: OnRegisterCaps called with agentID {0} caps {1} in scene {2}", + "[FreeSwitchVoice]: OnRegisterCaps() called with agentID {0} caps {1} in scene {2}", agentID, caps, scene.RegionInfo.RegionName); string capsBase = "/CAPS/" + caps.CapsObjectPath; @@ -344,6 +345,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice public string ProvisionVoiceAccountRequest(Scene scene, string request, string path, string param, UUID agentID, Caps caps) { + m_log.DebugFormat( + "[FreeSwitchVoice][PROVISIONVOICE]: ProvisionVoiceAccountRequest() request: {0}, path: {1}, param: {2}", request, path, param); + ScenePresence avatar = scene.GetScenePresence(agentID); if (avatar == null) { @@ -357,9 +361,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice try { - //m_log.DebugFormat("[FreeSwitchVoice][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}", - // request, path, param); - //XmlElement resp; string agentname = "x" + Convert.ToBase64String(agentID.GetBytes()); string password = "1234";//temp hack//new UUID(Guid.NewGuid()).ToString().Replace('-','Z').Substring(0,16); @@ -416,6 +417,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice public string ParcelVoiceInfoRequest(Scene scene, string request, string path, string param, UUID agentID, Caps caps) { +// m_log.DebugFormat( +// "[FreeSwitchVoice][PARCELVOICE]: ParcelVoiceInfoRequest() on {0} for {1}", +// scene.RegionInfo.RegionName, agentID); + ScenePresence avatar = scene.GetScenePresence(agentID); string avatarName = avatar.Name; @@ -502,6 +507,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice m_log.DebugFormat("[FreeSwitchVoice][CHATSESSION]: avatar \"{0}\": request: {1}, path: {2}, param: {3}", avatarName, request, path, param); + return "true"; } @@ -555,7 +561,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice return response; } - public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request) { m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceGetPreloginHTTPHandler called"); @@ -592,6 +597,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice public Hashtable FreeSwitchSLVoiceBuddyHTTPHandler(Hashtable request) { + m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceBuddyHTTPHandler called"); + Hashtable response = new Hashtable(); response["int_response_code"] = 200; response["str_response_string"] = string.Empty; @@ -650,18 +657,61 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice A {3} - ", ids[i],i,m_freeSwitchRealm,dt)); + ", ids[i], i ,m_freeSwitchRealm, dt)); } resp.Append(""); response["str_response_string"] = resp.ToString(); -// Regex normalizeEndLines = new Regex(@"\r\n", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline); - - //m_log.DebugFormat("[FREESWITCH]: {0}", normalizeEndLines.Replace((string)response["str_response_string"],"")); +// Regex normalizeEndLines = new Regex(@"(\r\n|\n)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline); +// +// m_log.DebugFormat( +// "[FREESWITCH]: FreeSwitchSLVoiceBuddyHTTPHandler() response {0}", +// normalizeEndLines.Replace((string)response["str_response_string"],"")); + return response; } + public Hashtable FreeSwitchSLVoiceWatcherHTTPHandler(Hashtable request) + { + m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceWatcherHTTPHandler called"); + + Hashtable response = new Hashtable(); + response["int_response_code"] = 200; + response["content-type"] = "text/xml"; + + Hashtable requestBody = ParseRequestBody((string)request["body"]); + + string auth_token = (string)requestBody["auth_token"]; + //string[] auth_tokenvals = auth_token.Split(':'); + //string username = auth_tokenvals[0]; + + StringBuilder resp = new StringBuilder(); + resp.Append(""); + + // FIXME: This is enough of a response to stop viewer 2 complaining about a login failure and get voice to work. If we don't + // give an OK response, then viewer 2 engages in an continuous viv_signin.php, viv_buddy.php, viv_watcher.php loop + // Viewer 1 appeared happy to ignore the lack of reply and still works with this reply. + // + // However, really we need to fill in whatever watcher data should be here (whatever that is). + resp.Append(string.Format(@" + OK + lib_session + {0} + {0} + ", auth_token)); + + response["str_response_string"] = resp.ToString(); + +// Regex normalizeEndLines = new Regex(@"(\r\n|\n)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline); +// +// m_log.DebugFormat( +// "[FREESWITCH]: FreeSwitchSLVoiceWatcherHTTPHandler() response {0}", +// normalizeEndLines.Replace((string)response["str_response_string"],"")); + + return response; + } + public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request) { m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceSigninHTTPHandler called"); @@ -709,7 +759,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice ", userid, pos, avatarName); - response["int_response_code"] = 200; + response["int_response_code"] = 200; + +// m_log.DebugFormat("[FreeSwitchVoice]: Sending FreeSwitchSLVoiceSigninHTTPHandler response"); + return response; } @@ -823,4 +876,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice #endregion } -} +} \ No newline at end of file -- cgit v1.1 From 212326eeb0a7aa2180661e4c0ad253e2e7ae4515 Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 19 Apr 2011 22:16:10 -0700 Subject: fix meshing failure on sculpt maps smaller than 64x64 --- OpenSim/Region/Physics/Meshing/SculptMap.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/SculptMap.cs b/OpenSim/Region/Physics/Meshing/SculptMap.cs index d2d71de..740424e 100644 --- a/OpenSim/Region/Physics/Meshing/SculptMap.cs +++ b/OpenSim/Region/Physics/Meshing/SculptMap.cs @@ -62,6 +62,8 @@ namespace PrimMesher bool needsScaling = false; + bool smallMap = bmW * bmH <= lod * lod; + width = bmW; height = bmH; while (width * height > numLodPixels) @@ -104,9 +106,14 @@ namespace PrimMesher { for (int x = 0; x <= width; x++) { - int bmY = y < height ? y * 2 : y * 2 - 1; - int bmX = x < width ? x * 2 : x * 2 - 1; - Color c = bm.GetPixel(bmX, bmY); + Color c; + + if (smallMap) + c = bm.GetPixel(x < width ? x : x - 1, + y < height ? y : y - 1); + else + c = bm.GetPixel(x < width ? x * 2 : x * 2 - 1, + y < height ? y * 2 : y * 2 - 1); redBytes[byteNdx] = c.R; greenBytes[byteNdx] = c.G; -- cgit v1.1 From 63c1b7e4754271ec898592ba6209dbc776469370 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 21 Apr 2011 18:12:29 +0100 Subject: Alter uuid gather so that it properly analyzes coalesced objects. This should correct save all the assets required for the items within the coalesced objects in an IAR. This should also correctly gather the items on hypergrid takes. --- .../CoalescedSceneObjectsSerializer.cs | 47 +++++++++++++--------- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 18 +++++++-- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index babcb54..55455cc 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -117,29 +117,40 @@ namespace OpenSim.Region.Framework.Scenes.Serialization { using (XmlTextReader reader = new XmlTextReader(sr)) { - reader.Read(); - if (reader.Name != "CoalescedObject") + try { -// m_log.DebugFormat( -// "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", -// reader.Name); + reader.Read(); + if (reader.Name != "CoalescedObject") + { + // m_log.DebugFormat( + // "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", + // reader.Name); + + return false; + } - return false; - } - - coa = new CoalescedSceneObjects(UUID.Zero); - reader.Read(); - - while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "CoalescedObject") - { - if (reader.Name == "SceneObjectGroup") + coa = new CoalescedSceneObjects(UUID.Zero); + reader.Read(); + + while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "CoalescedObject") { - string soXml = reader.ReadOuterXml(); - coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml)); + if (reader.Name == "SceneObjectGroup") + { + string soXml = reader.ReadOuterXml(); + coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml)); + } } + + reader.ReadEndElement(); // CoalescedObject } - - reader.ReadEndElement(); // CoalescedObject + catch (Exception e) + { + m_log.ErrorFormat( + "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed with {0} {1}", + e.Message, e.StackTrace); + + return false; + } } } diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 83906d7..77b1535 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -298,10 +298,20 @@ namespace OpenSim.Region.Framework.Scenes if (null != objectAsset) { string xml = Utils.BytesToString(objectAsset.Data); - SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); - - if (null != sog) - GatherAssetUuids(sog, assetUuids); + + CoalescedSceneObjects coa; + if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) + { + foreach (SceneObjectGroup sog in coa.Objects) + GatherAssetUuids(sog, assetUuids); + } + else + { + SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); + + if (null != sog) + GatherAssetUuids(sog, assetUuids); + } } } -- cgit v1.1 From e36cab99fddc4dca338386101d5c204e6de5d2c5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 21 Apr 2011 18:45:05 +0100 Subject: minor: small amount of method doc and some commented out odds and ends --- .../Framework/Scenes/SceneObjectGroup.Inventory.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index e8095c0..4bca3d0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -81,16 +81,20 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Add an inventory item to a prim in this group. + /// Add an inventory item from a user's inventory to a prim in this scene object. /// - /// - /// - /// + /// The client adding the item. + /// The local ID of the part receiving the add. + /// The user inventory item being added. /// The item UUID that should be used by the new item. /// public bool AddInventoryItem(IClientAPI remoteClient, uint localID, InventoryItemBase item, UUID copyItemID) { +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Adding inventory item {0} from {1} to part with local ID {2}", +// item.Name, remoteClient.Name, localID); + UUID newItemId = (copyItemID != UUID.Zero) ? copyItemID : item.ID; SceneObjectPart part = GetChildPart(localID); @@ -132,15 +136,20 @@ namespace OpenSim.Region.Framework.Scenes taskItem.GroupPermissions = item.GroupPermissions; taskItem.NextPermissions = item.NextPermissions; } - + taskItem.Flags = item.Flags; + +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Flags are 0x{0:X} for item {1} added to part {2} by {3}", +// taskItem.Flags, taskItem.Name, localID, remoteClient.Name); + // TODO: These are pending addition of those fields to TaskInventoryItem // taskItem.SalePrice = item.SalePrice; // taskItem.SaleType = item.SaleType; taskItem.CreationDate = (uint)item.CreationDate; bool addFromAllowedDrop = false; - if (remoteClient!=null) + if (remoteClient != null) { addFromAllowedDrop = remoteClient.AgentId != part.OwnerID; } -- cgit v1.1 From 60685c35179c74c5714abdb0c17611fb59d52c10 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 21 Apr 2011 19:17:38 +0100 Subject: Adjust freeswitch logging to be somewhat less noisy. However, there is still quite a large amount of logging present for debug purposes. --- .../Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs | 27 ++++++++++++++-------- .../FreeswitchService/FreeswitchService.cs | 8 +++---- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs index 373ffeb..42efd67 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs @@ -391,7 +391,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse); - m_log.DebugFormat("[FreeSwitchVoice][PROVISIONVOICE]: avatar \"{0}\": {1}", avatarName, r); +// m_log.DebugFormat("[FreeSwitchVoice][PROVISIONVOICE]: avatar \"{0}\": {1}", avatarName, r); return r; } @@ -458,8 +458,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice if ((land.Flags & (uint)ParcelFlags.AllowVoiceChat) == 0) { - m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": voice not enabled for parcel", - scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName); +// m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": voice not enabled for parcel", +// scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName); channelUri = String.Empty; } else @@ -474,8 +474,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice parcelVoiceInfo = new LLSDParcelVoiceInfoResponse(scene.RegionInfo.RegionName, land.LocalID, creds); string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo); - m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": {4}", - scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, r); +// m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": {4}", +// scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, r); return r; } catch (Exception e) @@ -850,16 +850,25 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice Hashtable requestBody = ParseRequestBody((string)request["body"]); - string section = (string) requestBody["section"]; - - m_log.DebugFormat("[FreeSwitchVoice]: Received request for config section {0}", section); + string section = (string) requestBody["section"]; if (section == "directory") + { + string eventCallingFunction = (string)requestBody["Event-Calling-Function"]; + m_log.DebugFormat( + "[FreeSwitchVoice]: Received request for config section directory, event calling function '{0}'", + eventCallingFunction); + response = m_FreeswitchService.HandleDirectoryRequest(requestBody); + } else if (section == "dialplan") + { + m_log.DebugFormat("[FreeSwitchVoice]: Received request for config section dialplan"); + response = m_FreeswitchService.HandleDialplanRequest(requestBody); + } else - m_log.WarnFormat("[FreeSwitchVoice]: Unknown section {0} was requested.", section); + m_log.WarnFormat("[FreeSwitchVoice]: Unknown section {0} was requested from config.", section); return response; } diff --git a/OpenSim/Services/FreeswitchService/FreeswitchService.cs b/OpenSim/Services/FreeswitchService/FreeswitchService.cs index 1ec89da..c3f1056 100644 --- a/OpenSim/Services/FreeswitchService/FreeswitchService.cs +++ b/OpenSim/Services/FreeswitchService/FreeswitchService.cs @@ -56,7 +56,7 @@ namespace OpenSim.Services.FreeswitchService foreach (DictionaryEntry item in request) { - m_log.InfoFormat("[FreeSwitchDirectory]: requestBody item {0} {1}",item.Key, item.Value); +// m_log.InfoFormat("[FreeSwitchDirectory]: requestBody item {0} {1}",item.Key, item.Value); } string requestcontext = (string) request["Hunt-Context"]; @@ -146,10 +146,8 @@ namespace OpenSim.Services.FreeswitchService //domain=9.20.151.43 //ip=9.167.220.137 // this is the correct IP rather than sip_contact_host above when through a vpn or NAT setup - foreach (DictionaryEntry item in request) - { - m_log.DebugFormat("[FreeSwitchDirectory]: requestBody item {0} {1}", item.Key, item.Value); - } +// foreach (DictionaryEntry item in request) +// m_log.DebugFormat("[FreeSwitchDirectory]: requestBody item {0} {1}", item.Key, item.Value); string eventCallingFunction = (string) request["Event-Calling-Function"]; if (eventCallingFunction == null) -- cgit v1.1 From 223c90c7510e9dcf0bbf15535dbd6e9e9d2cfa96 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 21 Apr 2011 19:31:37 +0100 Subject: Remove duplicated freeswitch settings. --- bin/Robust.HG.ini.example | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index ced2857..e2e9624 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -117,10 +117,6 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ; EchoPort = 50505 ; AttemptSTUN = false - LocalServiceModule = "OpenSim.Services.FreeswitchService.dll:FreeswitchService" - ;; IP of your FS server - ; ServerAddress = 127.0.0.1 - ; * This is the new style authentication service. Currently, only MySQL ; * is implemented. ; * -- cgit v1.1 From d9055c8dc3f5a768b300aa72318c813bbc024e09 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 21 Apr 2011 15:12:52 -0400 Subject: Group collada meshies settings under [Mesh] in OpensimDefaults.ini --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 3 ++- bin/OpenSimDefaults.ini | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 211a0a7..64774d8 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -84,10 +84,11 @@ namespace OpenSim.Region.Physics.Meshing public Meshmerizer(IConfigSource config) { IConfig start_config = config.Configs["Startup"]; + IConfig mesh_config = config.Configs["Mesh"]; decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); - useMeshiesPhysicsMesh = start_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); + useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); try { diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index e72e851..b134b7e 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -149,12 +149,6 @@ ; to false if you have compatibility problems. ;CacheSculptMaps = true - ; if you use Meshmerizer and want collisions for meshies, setting this to true - ; will cause OpenSim to attempt to decode meshies assets, extract the physics - ; mesh, and use it for collisions. This is currently experimental code and enabling - ; it may cause unexpected physics problems. - ;UseMeshiesPhysicsMesh = false - ; Choose one of the physics engines below ; OpenDynamicsEngine is by some distance the most developed physics engine ; basicphysics effectively does not model physics at all, making all objects phantom @@ -461,6 +455,12 @@ ; default is true ; ColladaMesh = true + ; if you use Meshmerizer and want collisions for meshies, setting this to true + ; will cause OpenSim to attempt to decode meshies assets, extract the physics + ; mesh, and use it for collisions. This is currently experimental code and enabling + ; it may cause unexpected physics problems. + ;UseMeshiesPhysicsMesh = false + [ODEPhysicsSettings] ;## -- cgit v1.1 From 13d6e05d5a346dcb9dbaec29af37ee63be790acb Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 21 Apr 2011 23:03:38 +0100 Subject: Implement agent limits --- OpenSim/Region/Framework/Scenes/Scene.cs | 20 ++++++++++++++++++++ OpenSim/Region/Framework/Scenes/SceneGraph.cs | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index fdd5205..01de824 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3665,6 +3665,15 @@ namespace OpenSim.Region.Framework.Scenes return false; } + int num = m_sceneGraph.GetNumberOfScenePresences(); + + if (num >= RegionInfo.RegionSettings.AgentLimit) + { + if (!Permissions.IsAdministrator(cAgentData.AgentID)) + return false; + } + + ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); if (childAgentUpdate != null) @@ -4966,6 +4975,17 @@ namespace OpenSim.Region.Framework.Scenes // child agent creation, thereby emulating the SL behavior. public bool QueryAccess(UUID agentID, Vector3 position, out string reason) { + int num = m_sceneGraph.GetNumberOfScenePresences(); + + if (num >= RegionInfo.RegionSettings.AgentLimit) + { + if (!Permissions.IsAdministrator(agentID)) + { + reason = "The region is full"; + return false; + } + } + reason = String.Empty; return true; } diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 72f0402..fc31b65 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -800,6 +800,11 @@ namespace OpenSim.Region.Framework.Scenes return m_scenePresenceArray; } + public int GetNumberOfScenePresences() + { + return m_scenePresenceArray.Count; + } + /// /// Request a scene presence by UUID. Fast, indexed lookup. /// -- cgit v1.1 From e0002f6b64e7aeb29de9f1db92ed39d3d1df578c Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 21 Apr 2011 19:04:41 -0400 Subject: some mesh config asthetics --- OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs | 2 +- .../Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs | 2 +- bin/OpenSimDefaults.ini | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs index deec444..fc1ddef 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs @@ -70,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets if (meshConfig == null) return; - m_enabled = meshConfig.GetBoolean("ColladaMesh", true); + m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true); } public void AddRegion(Scene pScene) diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs index d651cb2..3d4c7b7 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs @@ -72,7 +72,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets if (meshConfig == null) return; - m_enabled = meshConfig.GetBoolean("ColladaMesh", true); + m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true); } public void AddRegion(Scene pScene) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index b134b7e..7ea98d4 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -453,7 +453,7 @@ [Mesh] ; enable / disable Collada mesh support ; default is true - ; ColladaMesh = true + ; AllowMeshUpload = true ; if you use Meshmerizer and want collisions for meshies, setting this to true ; will cause OpenSim to attempt to decode meshies assets, extract the physics -- cgit v1.1 From d5256094d975583876766b630bcf0ede1d3dd3e4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 23 Apr 2011 00:16:55 +0100 Subject: print invalid command message to the console, not the log --- OpenSim/Framework/Console/CommandConsole.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs index 52bcd55..be36cf2 100644 --- a/OpenSim/Framework/Console/CommandConsole.cs +++ b/OpenSim/Framework/Console/CommandConsole.cs @@ -592,9 +592,7 @@ namespace OpenSim.Framework.Console string line = ReadLine(m_defaultPrompt + "# ", true, true); if (line != String.Empty) - { - m_log.Info("[CONSOLE] Invalid command"); - } + Output("Invalid command"); } public void RunCommand(string cmd) -- cgit v1.1 From 44e43d9d240735695668849fbd7aaafd339f262d Mon Sep 17 00:00:00 2001 From: E. Allen Soard Date: Fri, 15 Apr 2011 06:17:26 -0700 Subject: Added MaxAgents configuration option to RegionConfig.ini allowing region hosters to setup regions maintaining more control over system resources. --- OpenSim/Framework/RegionInfo.cs | 17 +++++++++++++++++ .../CoreModules/World/Estate/EstateManagementModule.cs | 5 ++++- bin/RegionConfig.ini.example | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index daf0a25..239ce3d 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -369,6 +369,7 @@ namespace OpenSim.Framework private int m_physPrimMax = 0; private bool m_clampPrimSize = false; private int m_objectCapacity = 0; + private int m_agentCapacity = 0; private string m_regionType = String.Empty; private RegionLightShareData m_windlight = new RegionLightShareData(); protected uint m_httpPort; @@ -547,6 +548,11 @@ namespace OpenSim.Framework get { return m_objectCapacity; } } + public int AgentCapacity + { + get { return m_agentCapacity; } + } + public byte AccessLevel { get { return (byte)Util.ConvertMaturityToAccessLevel((uint)RegionSettings.Maturity); } @@ -821,6 +827,8 @@ namespace OpenSim.Framework m_objectCapacity = config.GetInt("MaxPrims", 15000); + m_agentCapacity = config.GetInt("MaxAgents", 100); + // Multi-tenancy // @@ -857,6 +865,9 @@ namespace OpenSim.Framework if (m_objectCapacity != 0) config.Set("MaxPrims", m_objectCapacity); + if (m_agentCapacity != 0) + config.Set("MaxAgents", m_agentCapacity); + if (ScopeID != UUID.Zero) config.Set("ScopeID", ScopeID.ToString()); @@ -943,6 +954,9 @@ namespace OpenSim.Framework configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, "Max objects this sim will hold", m_objectCapacity.ToString(), true); + configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, + "Max avatars this sim will hold", m_agentCapacity.ToString(), true); + configMember.addConfigurationOption("scope_id", ConfigurationOption.ConfigurationTypes.TYPE_UUID, "Scope ID for this region", ScopeID.ToString(), true); @@ -1055,6 +1069,9 @@ namespace OpenSim.Framework case "object_capacity": m_objectCapacity = (int)configuration_result; break; + case "agent_capacity": + m_agentCapacity = (int)configuration_result; + break; case "scope_id": ScopeID = (UUID)configuration_result; break; diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index ab90e90..3aed6ba 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -125,7 +125,10 @@ namespace OpenSim.Region.CoreModules.World.Estate else Scene.RegionInfo.RegionSettings.AllowLandResell = true; - Scene.RegionInfo.RegionSettings.AgentLimit = (byte) maxAgents; + if((byte)maxAgents <= Scene.RegionInfo.AgentCapacity) + Scene.RegionInfo.RegionSettings.AgentLimit = (byte) maxAgents; + else + Scene.RegionInfo.RegionSettings.AgentLimit = Scene.RegionInfo.AgentCapacity; Scene.RegionInfo.RegionSettings.ObjectBonus = objectBonusFactor; diff --git a/bin/RegionConfig.ini.example b/bin/RegionConfig.ini.example index d45fe9d..ff00ddf 100644 --- a/bin/RegionConfig.ini.example +++ b/bin/RegionConfig.ini.example @@ -28,6 +28,7 @@ ExternalHostName = "SYSTEMIP" ; PhysicalPrimMax = 10 ; ClampPrimSize = False ; MaxPrims = 15000 +; MaxAgents = 100 ; * ; * Multi-Tenancy. Only set if needed -- cgit v1.1