OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
PrimCountModule.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Diagnostics;
32 using System.Reflection;
33 using log4net;
34 using Nini.Config;
35 using OpenMetaverse;
36 using OpenSim.Framework;
37 using Mono.Addins;
38 using OpenSim.Region.Framework.Interfaces;
39 using OpenSim.Region.Framework.Scenes;
40 using OpenSim.Services.Interfaces;
41 
42 namespace OpenSim.Region.CoreModules.World.Land
43 {
44  public class ParcelCounts
45  {
46  public int Owner = 0;
47  public int Group = 0;
48  public int Others = 0;
49  public int Selected = 0;
50  public Dictionary <UUID, int> Users = new Dictionary <UUID, int>();
51  }
52 
53  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "PrimCountModule")]
55  {
56 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57 
58  private Scene m_Scene;
59  private Dictionary<UUID, PrimCounts> m_PrimCounts =
60  new Dictionary<UUID, PrimCounts>();
61  private Dictionary<UUID, UUID> m_OwnerMap =
62  new Dictionary<UUID, UUID>();
63  private Dictionary<UUID, int> m_SimwideCounts =
64  new Dictionary<UUID, int>();
65  private Dictionary<UUID, ParcelCounts> m_ParcelCounts =
66  new Dictionary<UUID, ParcelCounts>();
67 
75  private bool m_Tainted = true;
76 
77  private Object m_TaintLock = new Object();
78 
79  public Type ReplaceableInterface
80  {
81  get { return null; }
82  }
83 
84  public void Initialise(IConfigSource source)
85  {
86  }
87 
88  public void AddRegion(Scene scene)
89  {
90  m_Scene = scene;
91 
92  m_Scene.RegisterModuleInterface<IPrimCountModule>(this);
93 
94  m_Scene.EventManager.OnObjectAddedToScene += OnParcelPrimCountAdd;
95  m_Scene.EventManager.OnObjectBeingRemovedFromScene +=
96  OnObjectBeingRemovedFromScene;
97  m_Scene.EventManager.OnParcelPrimCountTainted +=
98  OnParcelPrimCountTainted;
99  m_Scene.EventManager.OnLandObjectAdded += delegate(ILandObject lo) { OnParcelPrimCountTainted(); };
100  }
101 
102  public void RegionLoaded(Scene scene)
103  {
104  }
105 
106  public void RemoveRegion(Scene scene)
107  {
108  }
109 
110  public void Close()
111  {
112  }
113 
114  public string Name
115  {
116  get { return "PrimCountModule"; }
117  }
118 
119  private void OnParcelPrimCountAdd(SceneObjectGroup obj)
120  {
121  // If we're tainted already, don't bother to add. The next
122  // access will cause a recount anyway
123  lock (m_TaintLock)
124  {
125  if (!m_Tainted)
126  AddObject(obj);
127 // else
128 // m_log.DebugFormat(
129 // "[PRIM COUNT MODULE]: Ignoring OnParcelPrimCountAdd() for {0} on {1} since count is tainted",
130 // obj.Name, m_Scene.RegionInfo.RegionName);
131  }
132  }
133 
134  private void OnObjectBeingRemovedFromScene(SceneObjectGroup obj)
135  {
136  // Don't bother to update tainted counts
137  lock (m_TaintLock)
138  {
139  if (!m_Tainted)
140  RemoveObject(obj);
141 // else
142 // m_log.DebugFormat(
143 // "[PRIM COUNT MODULE]: Ignoring OnObjectBeingRemovedFromScene() for {0} on {1} since count is tainted",
144 // obj.Name, m_Scene.RegionInfo.RegionName);
145  }
146  }
147 
148  private void OnParcelPrimCountTainted()
149  {
150 // m_log.DebugFormat(
151 // "[PRIM COUNT MODULE]: OnParcelPrimCountTainted() called on {0}", m_Scene.RegionInfo.RegionName);
152 
153  lock (m_TaintLock)
154  m_Tainted = true;
155  }
156 
157  public void TaintPrimCount(ILandObject land)
158  {
159  lock (m_TaintLock)
160  m_Tainted = true;
161  }
162 
163  public void TaintPrimCount(int x, int y)
164  {
165  lock (m_TaintLock)
166  m_Tainted = true;
167  }
168 
169  public void TaintPrimCount()
170  {
171  lock (m_TaintLock)
172  m_Tainted = true;
173  }
174 
175  // NOTE: Call under Taint Lock
176  private void AddObject(SceneObjectGroup obj)
177  {
178  if (obj.IsAttachment)
179  return;
180  if (((obj.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0))
181  return;
182 
183  Vector3 pos = obj.AbsolutePosition;
184  ILandObject landObject = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
185 
186  // If for some reason there is no land object (perhaps the object is out of bounds) then we can't count it
187  if (landObject == null)
188  {
189 // m_log.WarnFormat(
190 // "[PRIM COUNT MODULE]: Found no land object for {0} at position ({1}, {2}) on {3}",
191 // obj.Name, pos.X, pos.Y, m_Scene.RegionInfo.RegionName);
192 
193  return;
194  }
195 
196  LandData landData = landObject.LandData;
197 
198 // m_log.DebugFormat(
199 // "[PRIM COUNT MODULE]: Adding object {0} with {1} parts to prim count for parcel {2} on {3}",
200 // obj.Name, obj.Parts.Length, landData.Name, m_Scene.RegionInfo.RegionName);
201 
202 // m_log.DebugFormat(
203 // "[PRIM COUNT MODULE]: Object {0} is owned by {1} over land owned by {2}",
204 // obj.Name, obj.OwnerID, landData.OwnerID);
205 
206  ParcelCounts parcelCounts;
207  if (m_ParcelCounts.TryGetValue(landData.GlobalID, out parcelCounts))
208  {
209  UUID landOwner = landData.OwnerID;
210  int partCount = obj.GetPartCount();
211 
212  m_SimwideCounts[landOwner] += partCount;
213  if (parcelCounts.Users.ContainsKey(obj.OwnerID))
214  parcelCounts.Users[obj.OwnerID] += partCount;
215  else
216  parcelCounts.Users[obj.OwnerID] = partCount;
217 
218  if (obj.IsSelected)
219  {
220  parcelCounts.Selected += partCount;
221  }
222  else
223  {
224  if (landData.IsGroupOwned)
225  {
226  if (obj.OwnerID == landData.GroupID)
227  parcelCounts.Owner += partCount;
228  else if (landData.GroupID != UUID.Zero && obj.GroupID == landData.GroupID)
229  parcelCounts.Group += partCount;
230  else
231  parcelCounts.Others += partCount;
232  }
233  else
234  {
235  if (obj.OwnerID == landData.OwnerID)
236  parcelCounts.Owner += partCount;
237  else
238  parcelCounts.Others += partCount;
239  }
240  }
241  }
242  }
243 
244  // NOTE: Call under Taint Lock
245  private void RemoveObject(SceneObjectGroup obj)
246  {
247 // m_log.DebugFormat("[PRIM COUNT MODULE]: Removing object {0} {1} from prim count", obj.Name, obj.UUID);
248 
249  // Currently this is being done by tainting the count instead.
250  }
251 
252  public IPrimCounts GetPrimCounts(UUID parcelID)
253  {
254 // m_log.DebugFormat(
255 // "[PRIM COUNT MODULE]: GetPrimCounts for parcel {0} in {1}", parcelID, m_Scene.RegionInfo.RegionName);
256 
257  PrimCounts primCounts;
258 
259  lock (m_PrimCounts)
260  {
261  if (m_PrimCounts.TryGetValue(parcelID, out primCounts))
262  return primCounts;
263 
264  primCounts = new PrimCounts(parcelID, this);
265  m_PrimCounts[parcelID] = primCounts;
266  }
267  return primCounts;
268  }
269 
270 
276  public int GetOwnerCount(UUID parcelID)
277  {
278  int count = 0;
279 
280  lock (m_TaintLock)
281  {
282  if (m_Tainted)
283  Recount();
284 
285  ParcelCounts counts;
286  if (m_ParcelCounts.TryGetValue(parcelID, out counts))
287  count = counts.Owner;
288  }
289 
290 // m_log.DebugFormat(
291 // "[PRIM COUNT MODULE]: GetOwnerCount for parcel {0} in {1} returning {2}",
292 // parcelID, m_Scene.RegionInfo.RegionName, count);
293 
294  return count;
295  }
296 
302  public int GetGroupCount(UUID parcelID)
303  {
304  int count = 0;
305 
306  lock (m_TaintLock)
307  {
308  if (m_Tainted)
309  Recount();
310 
311  ParcelCounts counts;
312  if (m_ParcelCounts.TryGetValue(parcelID, out counts))
313  count = counts.Group;
314  }
315 
316 // m_log.DebugFormat(
317 // "[PRIM COUNT MODULE]: GetGroupCount for parcel {0} in {1} returning {2}",
318 // parcelID, m_Scene.RegionInfo.RegionName, count);
319 
320  return count;
321  }
322 
328  public int GetOthersCount(UUID parcelID)
329  {
330  int count = 0;
331 
332  lock (m_TaintLock)
333  {
334  if (m_Tainted)
335  Recount();
336 
337  ParcelCounts counts;
338  if (m_ParcelCounts.TryGetValue(parcelID, out counts))
339  count = counts.Others;
340  }
341 
342 // m_log.DebugFormat(
343 // "[PRIM COUNT MODULE]: GetOthersCount for parcel {0} in {1} returning {2}",
344 // parcelID, m_Scene.RegionInfo.RegionName, count);
345 
346  return count;
347  }
348 
354  public int GetSelectedCount(UUID parcelID)
355  {
356  int count = 0;
357 
358  lock (m_TaintLock)
359  {
360  if (m_Tainted)
361  Recount();
362 
363  ParcelCounts counts;
364  if (m_ParcelCounts.TryGetValue(parcelID, out counts))
365  count = counts.Selected;
366  }
367 
368 // m_log.DebugFormat(
369 // "[PRIM COUNT MODULE]: GetSelectedCount for parcel {0} in {1} returning {2}",
370 // parcelID, m_Scene.RegionInfo.RegionName, count);
371 
372  return count;
373  }
374 
381  public int GetTotalCount(UUID parcelID)
382  {
383  int count = 0;
384 
385  lock (m_TaintLock)
386  {
387  if (m_Tainted)
388  Recount();
389 
390  ParcelCounts counts;
391  if (m_ParcelCounts.TryGetValue(parcelID, out counts))
392  {
393  count = counts.Owner;
394  count += counts.Group;
395  count += counts.Others;
396  count += counts.Selected;
397  }
398  }
399 
400 // m_log.DebugFormat(
401 // "[PRIM COUNT MODULE]: GetTotalCount for parcel {0} in {1} returning {2}",
402 // parcelID, m_Scene.RegionInfo.RegionName, count);
403 
404  return count;
405  }
406 
412  public int GetSimulatorCount(UUID parcelID)
413  {
414  int count = 0;
415 
416  lock (m_TaintLock)
417  {
418  if (m_Tainted)
419  Recount();
420 
421  UUID owner;
422  if (m_OwnerMap.TryGetValue(parcelID, out owner))
423  {
424  int val;
425  if (m_SimwideCounts.TryGetValue(owner, out val))
426  count = val;
427  }
428  }
429 
430 // m_log.DebugFormat(
431 // "[PRIM COUNT MODULE]: GetOthersCount for parcel {0} in {1} returning {2}",
432 // parcelID, m_Scene.RegionInfo.RegionName, count);
433 
434  return count;
435  }
436 
443  public int GetUserCount(UUID parcelID, UUID userID)
444  {
445  int count = 0;
446 
447  lock (m_TaintLock)
448  {
449  if (m_Tainted)
450  Recount();
451 
452  ParcelCounts counts;
453  if (m_ParcelCounts.TryGetValue(parcelID, out counts))
454  {
455  int val;
456  if (counts.Users.TryGetValue(userID, out val))
457  count = val;
458  }
459  }
460 
461 // m_log.DebugFormat(
462 // "[PRIM COUNT MODULE]: GetUserCount for user {0} in parcel {1} in region {2} returning {3}",
463 // userID, parcelID, m_Scene.RegionInfo.RegionName, count);
464 
465  return count;
466  }
467 
468  // NOTE: This method MUST be called while holding the taint lock!
469  private void Recount()
470  {
471 // m_log.DebugFormat("[PRIM COUNT MODULE]: Recounting prims on {0}", m_Scene.RegionInfo.RegionName);
472 
473  m_OwnerMap.Clear();
474  m_SimwideCounts.Clear();
475  m_ParcelCounts.Clear();
476 
477  List<ILandObject> land = m_Scene.LandChannel.AllParcels();
478 
479  foreach (ILandObject l in land)
480  {
481  LandData landData = l.LandData;
482 
483  m_OwnerMap[landData.GlobalID] = landData.OwnerID;
484  m_SimwideCounts[landData.OwnerID] = 0;
485 // m_log.DebugFormat(
486 // "[PRIM COUNT MODULE]: Initializing parcel count for {0} on {1}",
487 // landData.Name, m_Scene.RegionInfo.RegionName);
488  m_ParcelCounts[landData.GlobalID] = new ParcelCounts();
489  }
490 
491  m_Scene.ForEachSOG(AddObject);
492 
493  lock (m_PrimCounts)
494  {
495  List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys);
496  foreach (UUID k in primcountKeys)
497  {
498  if (!m_OwnerMap.ContainsKey(k))
499  m_PrimCounts.Remove(k);
500  }
501  }
502 
503  m_Tainted = false;
504  }
505  }
506 
507  public class PrimCounts : IPrimCounts
508  {
509  private PrimCountModule m_Parent;
510  private UUID m_ParcelID;
511  private UserPrimCounts m_UserPrimCounts;
512 
513  public PrimCounts (UUID parcelID, PrimCountModule parent)
514  {
515  m_ParcelID = parcelID;
516  m_Parent = parent;
517 
518  m_UserPrimCounts = new UserPrimCounts(this);
519  }
520 
521  public int Owner
522  {
523  get
524  {
525  return m_Parent.GetOwnerCount(m_ParcelID);
526  }
527  }
528 
529  public int Group
530  {
531  get
532  {
533  return m_Parent.GetGroupCount(m_ParcelID);
534  }
535  }
536 
537  public int Others
538  {
539  get
540  {
541  return m_Parent.GetOthersCount(m_ParcelID);
542  }
543  }
544 
545  public int Selected
546  {
547  get
548  {
549  return m_Parent.GetSelectedCount(m_ParcelID);
550  }
551  }
552 
553  public int Total
554  {
555  get
556  {
557  return m_Parent.GetTotalCount(m_ParcelID);
558  }
559  }
560 
561  public int Simulator
562  {
563  get
564  {
565  return m_Parent.GetSimulatorCount(m_ParcelID);
566  }
567  }
568 
569  public IUserPrimCounts Users
570  {
571  get
572  {
573  return m_UserPrimCounts;
574  }
575  }
576 
577  public int GetUserCount(UUID userID)
578  {
579  return m_Parent.GetUserCount(m_ParcelID, userID);
580  }
581  }
582 
584  {
585  private PrimCounts m_Parent;
586 
587  public UserPrimCounts(PrimCounts parent)
588  {
589  m_Parent = parent;
590  }
591 
592  public int this[UUID userID]
593  {
594  get
595  {
596  return m_Parent.GetUserCount(userID);
597  }
598  }
599  }
600 }
int GetTotalCount(UUID parcelID)
Get the total count of owner, group and others prims on the parcel. FIXME: Need to do selected prims ...
int GetSelectedCount(UUID parcelID)
Get the number of selected prims.
PrimCounts(UUID parcelID, PrimCountModule parent)
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
PrimFlags Flags
Property flags. See OpenMetaverse.PrimFlags
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
UUID GlobalID
Global ID for the parcel. (3rd Party Integration)
Definition: LandData.cs:327
UUID GroupID
Unique ID of the Group that owns
Definition: LandData.cs:342
int GetSimulatorCount(UUID parcelID)
Get the number of prims that are in the entire simulator for the owner of this parcel.
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Details of a Parcel of land
Definition: LandData.cs:47
int GetGroupCount(UUID parcelID)
Get the number of prims on the parcel that have been set to the group that owns the parcel...
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
int GetUserCount(UUID parcelID, UUID userID)
Get the number of prims that a particular user owns on this parcel.
bool IsGroupOwned
Returns true if the Land Parcel is owned by a group
Definition: LandData.cs:357
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
int GetOwnerCount(UUID parcelID)
Get the number of prims on the parcel that are owned by the parcel owner.
int GetOthersCount(UUID parcelID)
Get the number of prims on the parcel that are not owned by the parcel owner or set to the parcel gro...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
bool IsAttachment
Is this scene object acting as an attachment?
UUID OwnerID
Owner Avatar or Group of the parcel. Naturally, all land masses must be owned by someone ...
Definition: LandData.cs:551