aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/ContentManagementSystem/CMController.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Environment/Modules/ContentManagementSystem/CMController.cs1359
1 files changed, 698 insertions, 661 deletions
diff --git a/OpenSim/Region/Environment/Modules/ContentManagementSystem/CMController.cs b/OpenSim/Region/Environment/Modules/ContentManagementSystem/CMController.cs
index d3ca3cf..a179fb1 100644
--- a/OpenSim/Region/Environment/Modules/ContentManagementSystem/CMController.cs
+++ b/OpenSim/Region/Environment/Modules/ContentManagementSystem/CMController.cs
@@ -1,684 +1,721 @@
1#region Header
2
1// CMController.cs 3// CMController.cs
2// User: bongiojp 4// User: bongiojp
3// 5//
4 6
7#endregion Header
8
5using System; 9using System;
6using System.Collections.Generic;
7using System.Collections; 10using System.Collections;
11using System.Collections.Generic;
12using System.Diagnostics;
13using System.Threading;
14
8using libsecondlife; 15using libsecondlife;
16
9using OpenSim; 17using OpenSim;
10using OpenSim.Framework; 18using OpenSim.Framework;
11using OpenSim.Region.Environment.Interfaces; 19using OpenSim.Region.Environment.Interfaces;
12using OpenSim.Region.Environment.Scenes; 20using OpenSim.Region.Environment.Scenes;
13using log4net;
14using OpenSim.Region.Physics.Manager; 21using OpenSim.Region.Physics.Manager;
22
23using log4net;
24
15using Axiom.Math; 25using Axiom.Math;
16using System.Threading;
17using System.Diagnostics;
18 26
19namespace OpenSim.Region.Environment.Modules.ContentManagement 27namespace OpenSim.Region.Environment.Modules.ContentManagement
20{ 28{
21 29 /// <summary>
22 /// <summary> 30 /// The controller in a Model-View-Controller framework. This controller catches actions by the avatars, creates work packets, loops through these work packets in a separate thread,
23 /// The controller in a Model-View-Controller framework. This controller catches actions by the avatars, creates work packets, loops through these work packets in a separate thread, 31 /// then dictates to the model how the data should change and dictates to the view which data should be displayed. The main mechanism for interaction is through the simchat system.
24 /// then dictates to the model how the data should change and dictates to the view which data should be displayed. The main mechanism for interaction is through the simchat system. 32 /// </summary>
25 /// </summary> 33 public class CMController
26 public class CMController 34 {
27 { 35 #region Static Fields
28 36
29 /// <value> 37 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
30 /// The structure that defines the basic unit of work which is produced when a user sends commands to the ContentMangaementSystem. 38
31 /// </value> 39 /// <value>
32 private struct Work 40 /// The queue that keeps track of which actions have happened. The MainLoop thread eats through this queue.
33 { 41 /// </value>
34 public WorkType Type; 42 private static OpenSim.Framework.BlockingQueue<Work> m_WorkQueue = new OpenSim.Framework.BlockingQueue<Work>();
35 public Object Data1; //Just space for holding data. 43
36 public Object Data2; //Just more space for holding data. 44 #endregion Static Fields
37 public uint LocalId; //Convenient 45
38 public LLUUID UUID; //Convenient 46 #region Fields
39 } 47
40 48 bool init = false;
41 /// <value> 49 int m_channel = -1;
42 /// Identifies what the data in struct Work should be used for. 50
43 /// </value> 51 /// <value>
44 private enum WorkType 52 /// The estate module is used to identify which clients are estateManagers. Presently, the controller only pays attention to estate managers.
45 { 53 /// </value>
46 NONE, 54 IEstateModule m_estateModule = null;
47 OBJECTATTRIBUTECHANGE, 55
48 PRIMITIVEADDED, 56 //These have to be global variables, threading doesn't allow for passing parameters. (Used in MainLoop)
49 OBJECTDUPLICATED, 57 CMModel m_model = null;
50 OBJECTKILLED, 58
51 UNDODID, 59 /// <value>
52 NEWCLIENT, 60 /// A list of all the scenes that should be revisioned. Controller is the only class that keeps track of all scenes in the region.
53 SIMCHAT 61 /// </value>
54 } 62 Hashtable m_sceneList = Hashtable.Synchronized(new Hashtable());
55 63 State m_state = State.NONE;
56 /// <value> 64 Thread m_thread = null;
57 /// Used to keep track of whether a list has been produced yet and whether that list is up-to-date compard to latest revision on disk. 65 CMView m_view = null;
58 /// </value> 66
59 [Flags] 67 #endregion Fields
60 private enum State 68
61 { 69 #region Constructors
62 NONE = 0, 70
63 DIRTY = 1, // The meta entities may not correctly represent the last revision. 71 /// <summary>
64 SHOWING_CHANGES = 1<<1 // The meta entities are being shown to user. 72 /// Initializes a work thread with an initial scene. Additional scenes should be added through the RegisterNewRegion method.
65 } 73 /// </summary>
66 74 /// <param name="model">
67 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 75 /// <see cref="CMModel"/>
68 76 /// </param>
69 /// <value> 77 /// <param name="view">
70 /// The queue that keeps track of which actions have happened. The MainLoop thread eats through this queue. 78 /// <see cref="CMView"/>
71 /// </value> 79 /// </param>
72 private static OpenSim.Framework.BlockingQueue<Work> m_WorkQueue = new OpenSim.Framework.BlockingQueue<Work>(); 80 /// <param name="scene">
73 81 /// The first scene to keep track of. <see cref="Scene"/>
74 /// <value> 82 /// </param>
75 /// A list of all the scenes that should be revisioned. Controller is the only class that keeps track of all scenes in the region. 83 /// <param name="channel">
76 /// </value> 84 /// The simchat channel number to listen to for instructions <see cref="System.Int32"/>
77 Hashtable m_sceneList = Hashtable.Synchronized(new Hashtable()); 85 /// </param>
78 86 public CMController(CMModel model, CMView view, Scene scene, int channel)
79 /// <value> 87 {
80 /// The estate module is used to identify which clients are estateManagers. Presently, the controller only pays attention to estate managers. 88 m_model = model; m_view = view; m_channel = channel;
81 /// </value> 89 RegisterNewRegion(scene);
82 IEstateModule m_estateModule = null; 90 Initialize(model, view, scene, channel);
83 91 }
84 Thread m_thread = null; 92
85 State m_state = State.NONE; 93 #endregion Constructors
86 bool init = false; 94
87 95 #region Private Methods
88 //These have to be global variables, threading doesn't allow for passing parameters. (Used in MainLoop) 96
89 CMModel m_model = null; 97 //------------------------------------------------ EVENTS ----------------------------------------------------//
90 CMView m_view = null; 98 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
91 int m_channel = -1; 99 {
92 100 }
93 /// <summary> 101
94 /// Initializes a work thread with an initial scene. Additional scenes should be added through the RegisterNewRegion method. 102 /// <summary>
95 /// </summary> 103 /// Searches in all scenes for a SceneObjectGroup that contains a part with a specific localID. If found, the object is returned. Else null is returned.
96 /// <param name="model"> 104 /// </summary>
97 /// <see cref="CMModel"/> 105 private SceneObjectGroup GetGroupByPrim(uint localID)
98 /// </param> 106 {
99 /// <param name="view"> 107 foreach(Object currScene in m_sceneList.Values)
100 /// <see cref="CMView"/> 108 {
101 /// </param> 109 foreach (EntityBase ent in ((Scene)currScene).GetEntities())
102 /// <param name="scene"> 110 {
103 /// The first scene to keep track of. <see cref="Scene"/> 111 if (ent is SceneObjectGroup)
104 /// </param> 112 {
105 /// <param name="channel"> 113 if (((SceneObjectGroup)ent).HasChildPrim(localID))
106 /// The simchat channel number to listen to for instructions <see cref="System.Int32"/> 114 return (SceneObjectGroup)ent;
107 /// </param> 115 }
108 public CMController(CMModel model, CMView view, Scene scene, int channel) 116 }
109 { 117 }
110 m_model = model; m_view = view; m_channel = channel;
111 RegisterNewRegion(scene);
112 Initialize(model, view, scene, channel);
113 }
114
115 private void Initialize(CMModel model, CMView view, Scene scene, int channel)
116 {
117 lock(this)
118 {
119 m_estateModule = scene.RequestModuleInterface<IEstateModule>();
120 m_thread = new Thread( MainLoop );
121 m_thread.Name = "Content Management";
122 m_thread.IsBackground = true;
123 m_thread.Start();
124 ThreadTracker.Add(m_thread);
125 m_state = State.NONE;
126 }
127 }
128
129 /// <summary>
130 /// Register a new scene object to keep track of for revisioning. Starts the controller monitoring actions of clients within the given scene.
131 /// </summary>
132 /// <param name="scene">
133 /// A <see cref="Scene"/>
134 /// </param>
135 public void RegisterNewRegion(Scene scene)
136 {
137 m_sceneList.Add(scene.RegionInfo.RegionID, scene);
138
139 m_log.Debug("[CONTENT MANAGEMENT] Registering new region: " + scene.RegionInfo.RegionID);
140 m_log.Debug("[CONTENT MANAGEMENT] Initializing Content Management System.");
141
142 scene.EventManager.OnNewClient += StartManaging;
143 scene.EventManager.OnRemovePresence += StopManaging;
144 // scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
145 scene.EventManager.OnObjectBeingRemovedFromScene += GroupBeingDeleted;
146 }
147
148 /// <summary>
149 /// Run in a thread of its own. A endless loop that consumes (or blocks on) and work queue. Thw work queue is filled through client actions.
150 /// </summary>
151 private void MainLoop()
152 {
153 CMModel model = m_model; CMView view = m_view; int channel = m_channel;
154 Work currentJob = new Work();
155 while(true)
156 {
157 currentJob = m_WorkQueue.Dequeue();
158 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- DeQueued a request");
159 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- Work type: " + currentJob.Type);
160 switch(currentJob.Type)
161 {
162 case WorkType.NONE:
163 break;
164 case WorkType.OBJECTATTRIBUTECHANGE:
165 ObjectAttributeChanged(model, view, currentJob.LocalId);
166 break;
167 case WorkType.PRIMITIVEADDED:
168 PrimitiveAdded(model, view, currentJob);
169 break;
170 case WorkType.OBJECTDUPLICATED:
171 ObjectDuplicated(model, view, currentJob.LocalId);
172 break;
173 case WorkType.OBJECTKILLED:
174 ObjectKilled(model, view, (SceneObjectGroup) currentJob.Data1);
175 break;
176 case WorkType.UNDODID:
177 UndoDid(model, view, currentJob.UUID);
178 break;
179 case WorkType.NEWCLIENT:
180 NewClient(view, (IClientAPI) currentJob.Data1);
181 break;
182 case WorkType.SIMCHAT:
183 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- Message received: " + ((OSChatMessage) currentJob.Data1).Message);
184 SimChat(model, view, (OSChatMessage) currentJob.Data1, channel);
185 break;
186 default:
187 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- uuuuuuuuuh, what?");
188 break;
189 }
190 }
191 }
192
193 /// <summary>
194 /// Only called by the MainLoop. Updates the view of a new client with metaentities if diff-mode is currently enabled.
195 /// </summary>
196 private void NewClient(CMView view, IClientAPI client)
197 {
198 if ((m_state & State.SHOWING_CHANGES) > 0)
199 view.SendMetaEntitiesToNewClient(client);
200 }
201
202 /// <summary>
203 /// Only called by the MainLoop. Displays new green auras over the newly created part when a part is shift copied.
204 /// </summary>
205 private void ObjectDuplicated(CMModel model, CMView view, uint localId)
206 {
207 if ((m_state & State.SHOWING_CHANGES) > 0)
208 view.DisplayAuras(model.CheckForNewEntitiesMissingAuras( GetGroupByPrim(localId).Scene ));
209 }
210
211 /// <summary>
212 /// Only called by the MainLoop.
213 /// </summary>
214 private void ObjectKilled(CMModel model, CMView view, SceneObjectGroup group)
215 {
216 if ((m_state & State.SHOWING_CHANGES) > 0)
217 {
218 view.RemoveOrUpdateDeletedEntity(group);
219 model.RemoveOrUpdateDeletedEntity(group);
220 }
221 }
222
223 /// <summary>
224 /// Only called by the MainLoop.
225 /// </summary>
226 private void UndoDid(CMModel model, CMView view, LLUUID uuid)
227 {
228 if ((m_state & State.SHOWING_CHANGES) > 0)
229 {
230 ContentManagementEntity ent = model.FindMetaEntityAffectedByUndo(uuid);
231 if (ent != null)
232 view.DisplayEntity(ent);
233 }
234 }
235
236 /// <summary>
237 /// Only called by the MainLoop.
238 /// </summary>
239 private void ObjectAttributeChanged(CMModel model, CMView view, uint LocalId)
240 {
241 SceneObjectGroup group = null;
242 if ((m_state & State.SHOWING_CHANGES) > 0)
243 {
244 group = GetGroupByPrim(LocalId);
245 if (group != null)
246 {
247 view.DisplayAuras( model.UpdateNormalEntityEffects(group) ); //Might be a normal entity (green aura)
248 m_view.DisplayMetaEntity(group.UUID); //Might be a meta entity (blue aura)
249 }
250 }
251 }
252
253 /// <summary>
254 /// Only called by the MainLoop.
255 /// </summary>
256 private void PrimitiveAdded(CMModel model, CMView view, Work currentJob)
257 {
258 if ((m_state & State.SHOWING_CHANGES) > 0)
259 {
260 foreach(Object scene in m_sceneList.Values)
261 m_view.DisplayAuras(model.CheckForNewEntitiesMissingAuras((Scene) scene));
262 }
263 }
264
265 /// <summary>
266 /// Only called by the MainLoop. Takes the message from a user sent to the channel and executes the proper command.
267 /// </summary>
268 public void SimChat(CMModel model, CMView view, OSChatMessage e, int channel)
269 {
270 if (e.Channel != channel)
271 return;
272 if (e.Sender == null)
273 return;
274
275 m_log.Debug("[CONTENT MANAGEMENT] Message received: " + e.Message);
276
277 IClientAPI client = e.Sender;
278 Scene scene = (Scene) e.Scene;
279 string message = e.Message;
280 string[] args = e.Message.Split(new char[] {' '});
281
282 ScenePresence avatar = scene.GetScenePresence(client.AgentId);
283
284 if (!(m_estateModule.IsManager(avatar.UUID)))
285 {
286 m_log.Debug("[CONTENT MANAGEMENT] Message sent from non Estate Manager ... ignoring.");
287 view.SendSimChatMessage(scene, "You must be an estate manager to perform that action.");
288 return;
289 }
290
291 switch(args[0])
292 {
293 case "ci":
294 case "commit":
295 commit(message, scene, model, view);
296 break;
297 case "dm":
298 case "diff-mode":
299 diffmode(scene, model, view);
300 break;
301 case "rb":
302 case "rollback":
303 rollback(scene, model, view);
304 break;
305 case "help":
306 m_view.DisplayHelpMenu(scene);
307 break;
308 default:
309 view.SendSimChatMessage(scene, "Command not found: " + args[0]);
310 break;
311 }
312 }
313
314 /// <summary>
315 /// Only called from within the SimChat method. Hides all auras and meta entities,
316 /// retrieves the current scene object list with the most recent revision retrieved from the model for each scene,
317 /// then lets the view update the clients of the new objects.
318 /// </summary>
319 protected void rollback(Scene scene, CMModel model, CMView view)
320 {
321 if ((m_state & State.SHOWING_CHANGES) > 0)
322 {
323 view.HideAllAuras();
324 view.HideAllMetaEntities();
325 }
326
327 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity( m_sceneList, scene);
328 foreach(Scene currScene in proximitySceneList)
329 model.RollbackRegion(currScene);
330
331 if ((m_state & State.DIRTY) != 0 )
332 {
333 model.DeleteAllMetaObjects();
334 foreach(Scene currScene in proximitySceneList)
335 model.UpdateCMEntities(currScene);
336 }
337
338 if ((m_state & State.SHOWING_CHANGES) > 0)
339 view.DisplayRecentChanges();
340
341 }
342
343 /// <summary>
344 /// Only called from within the SimChat method.
345 /// </summary>
346 protected void diffmode(Scene scene, CMModel model, CMView view)
347 {
348 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity( m_sceneList, scene);
349
350 if ((m_state & State.SHOWING_CHANGES) > 0) // TURN OFF
351 {
352 view.SendSimChatMessage(scene, "Hiding all meta objects.");
353 view.HideAllMetaEntities();
354 view.HideAllAuras();
355 view.SendSimChatMessage(scene, "Diff-mode = OFF");
356
357 m_state &= ~State.SHOWING_CHANGES;
358 return;
359 }
360 else // TURN ON
361 {
362 if ((m_state & State.DIRTY) != 0 || m_state == State.NONE)
363 {
364 view.SendSimChatMessage(scene, "Hiding meta objects and replacing with latest revision");
365 //Hide objects from users and Forget about them
366 view.HideAllMetaEntities();
367 view.HideAllAuras();
368 model.DeleteAllMetaObjects();
369 //Recreate them from backend files
370 foreach(Object currScene in m_sceneList.Values)
371 model.UpdateCMEntities((Scene) currScene);
372 }
373 else if ((m_state & State.DIRTY) != 0) {
374 view.SendSimChatMessage(scene, "Forming list of meta entities with latest revision");
375 foreach(Scene currScene in proximitySceneList)
376 model.UpdateCMEntities(currScene);
377 }
378
379 view.SendSimChatMessage(scene, "Displaying differences between last revision and current environment");
380 foreach(Scene currScene in proximitySceneList)
381 model.CheckForNewEntitiesMissingAuras(currScene);
382 view.DisplayRecentChanges();
383
384 view.SendSimChatMessage(scene, "Diff-mode = ON");
385 m_state |= State.SHOWING_CHANGES;
386 m_state &= ~State.DIRTY;
387 }
388 }
389
390 /// <summary>
391 /// Only called from within the SimChat method.
392 /// </summary>
393 protected void commit(string message, Scene scene, CMModel model, CMView view)
394 {
395 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity( m_sceneList, scene);
396
397 string[] args = message.Split(new char[] {' '});
398
399 char[] logMessage = {' '};
400 if (args.Length > 1)
401 {
402 logMessage = new char[message.Length - (args[0].Length)];
403 message.CopyTo(args[0].Length, logMessage, 0, message.Length - (args[0].Length));
404 }
405
406 m_log.Debug("[CONTENT MANAGEMENT] Saving terrain and objects of region.");
407 foreach(Scene currScene in proximitySceneList)
408 {
409 model.CommitRegion(currScene, new String(logMessage));
410 view.SendSimChatMessage(scene, "Region Saved Successfully: " + currScene.RegionInfo.RegionName);
411 }
412
413 view.SendSimChatMessage(scene, "Successfully saved all regions.");
414 m_state |= State.DIRTY;
415
416 if ((m_state & State.SHOWING_CHANGES) > 0) //DISPLAY NEW CHANGES INSTEAD OF OLD CHANGES
417 {
418 view.SendSimChatMessage(scene, "Updating differences between new revision and current environment.");
419 //Hide objects from users and Forget about them
420 view.HideAllMetaEntities();
421 view.HideAllAuras();
422 model.DeleteAllMetaObjects();
423
424 //Recreate them from backend files
425 foreach(Scene currScene in proximitySceneList)
426 {
427 model.UpdateCMEntities(currScene);
428 view.SendSimChatMessage(scene, "Finished updating differences between current scene and last revision: " + currScene.RegionInfo.RegionName);
429 }
430
431 //Display new objects to users1
432 view.DisplayRecentChanges();
433 view.SendSimChatMessage(scene, "Finished updating for DIFF-MODE.");
434 m_state &= ~(State.DIRTY);
435 m_state |= State.SHOWING_CHANGES;
436 }
437 }
438
439 /// <summary>
440 /// Takes a list of scenes and forms a new orderd list according to the proximity of scenes to the second argument.
441 /// </summary>
442 protected static System.Collections.Generic.List<Scene> ScenesInOrderOfProximity( Hashtable sceneList, Scene scene)
443 {
444 int somethingAddedToList = 1;
445 System.Collections.Generic.List<Scene> newList = new List<Scene>();
446 newList.Add(scene);
447
448 if (! sceneList.ContainsValue(scene))
449 {
450 foreach(Object sceneObj in sceneList)
451 newList.Add((Scene) sceneObj);
452 return newList;
453 }
454
455 while(somethingAddedToList > 0)
456 {
457 somethingAddedToList = 0;
458 for(int i = 0; i < newList.Count; i++)
459 {
460 foreach(Object sceneObj in sceneList.Values)
461 {
462 if (newList[i].CheckNeighborRegion(((Scene)sceneObj).RegionInfo) && (! newList.Contains((Scene)sceneObj)) )
463 {
464 newList.Add((Scene)sceneObj);
465 somethingAddedToList++;
466 }
467 }
468 }
469 }
470
471 foreach(Object sceneObj in sceneList.Values)
472 if (! newList.Contains((Scene)sceneObj))
473 newList.Add((Scene)sceneObj);
474
475 return newList;
476 }
477
478 /// <summary>
479 /// Searches in all scenes for a SceneObjectGroup that contains a part with a specific localID. If found, the object is returned. Else null is returned.
480 /// </summary>
481 private SceneObjectGroup GetGroupByPrim(uint localID)
482 {
483 foreach(Object currScene in m_sceneList.Values)
484 {
485 foreach (EntityBase ent in ((Scene)currScene).GetEntities())
486 {
487 if (ent is SceneObjectGroup)
488 {
489 if (((SceneObjectGroup)ent).HasChildPrim(localID))
490 return (SceneObjectGroup)ent;
491 }
492 }
493 }
494 return null; 118 return null;
495 } 119 }
496 //------------------------------------------------ EVENTS ----------------------------------------------------// 120
497 121 private void Initialize(CMModel model, CMView view, Scene scene, int channel)
498 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, LLUUID regionID) 122 {
499 { 123 lock(this)
500 } 124 {
501 125 m_estateModule = scene.RequestModuleInterface<IEstateModule>();
502 /// <summary> 126 m_thread = new Thread( MainLoop );
503 /// Adds extra handlers to a number of events so that the controller can produce work based on the client's actions. 127 m_thread.Name = "Content Management";
504 /// </summary> 128 m_thread.IsBackground = true;
505 protected void StartManaging(IClientAPI client) 129 m_thread.Start();
506 { 130 ThreadTracker.Add(m_thread);
507 m_log.Debug("[CONTENT MANAGEMENT] Registering channel with chat services."); 131 m_state = State.NONE;
508 client.OnChatFromViewer += SimChatSent; 132 }
509 init = true; 133 }
510 134
511 OnNewClient(client); 135 /// <summary>
512 136 /// Run in a thread of its own. A endless loop that consumes (or blocks on) and work queue. Thw work queue is filled through client actions.
513 m_log.Debug("[CONTENT MANAGEMENT] Adding handlers to client."); 137 /// </summary>
514 client.OnUpdatePrimScale += UpdateSingleScale; 138 private void MainLoop()
139 {
140 CMModel model = m_model; CMView view = m_view; int channel = m_channel;
141 Work currentJob = new Work();
142 while(true)
143 {
144 currentJob = m_WorkQueue.Dequeue();
145 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- DeQueued a request");
146 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- Work type: " + currentJob.Type);
147 switch(currentJob.Type)
148 {
149 case WorkType.NONE:
150 break;
151 case WorkType.OBJECTATTRIBUTECHANGE:
152 ObjectAttributeChanged(model, view, currentJob.LocalId);
153 break;
154 case WorkType.PRIMITIVEADDED:
155 PrimitiveAdded(model, view, currentJob);
156 break;
157 case WorkType.OBJECTDUPLICATED:
158 ObjectDuplicated(model, view, currentJob.LocalId);
159 break;
160 case WorkType.OBJECTKILLED:
161 ObjectKilled(model, view, (SceneObjectGroup) currentJob.Data1);
162 break;
163 case WorkType.UNDODID:
164 UndoDid(model, view, currentJob.UUID);
165 break;
166 case WorkType.NEWCLIENT:
167 NewClient(view, (IClientAPI) currentJob.Data1);
168 break;
169 case WorkType.SIMCHAT:
170 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- Message received: " + ((OSChatMessage) currentJob.Data1).Message);
171 SimChat(model, view, (OSChatMessage) currentJob.Data1, channel);
172 break;
173 default:
174 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- uuuuuuuuuh, what?");
175 break;
176 }
177 }
178 }
179
180 /// <summary>
181 /// Only called by the MainLoop. Updates the view of a new client with metaentities if diff-mode is currently enabled.
182 /// </summary>
183 private void NewClient(CMView view, IClientAPI client)
184 {
185 if ((m_state & State.SHOWING_CHANGES) > 0)
186 view.SendMetaEntitiesToNewClient(client);
187 }
188
189 /// <summary>
190 /// Only called by the MainLoop.
191 /// </summary>
192 private void ObjectAttributeChanged(CMModel model, CMView view, uint LocalId)
193 {
194 SceneObjectGroup group = null;
195 if ((m_state & State.SHOWING_CHANGES) > 0)
196 {
197 group = GetGroupByPrim(LocalId);
198 if (group != null)
199 {
200 view.DisplayAuras( model.UpdateNormalEntityEffects(group) ); //Might be a normal entity (green aura)
201 m_view.DisplayMetaEntity(group.UUID); //Might be a meta entity (blue aura)
202 }
203 }
204 }
205
206 /// <summary>
207 /// Only called by the MainLoop. Displays new green auras over the newly created part when a part is shift copied.
208 /// </summary>
209 private void ObjectDuplicated(CMModel model, CMView view, uint localId)
210 {
211 if ((m_state & State.SHOWING_CHANGES) > 0)
212 view.DisplayAuras(model.CheckForNewEntitiesMissingAuras( GetGroupByPrim(localId).Scene ));
213 }
214
215 /// <summary>
216 /// Only called by the MainLoop.
217 /// </summary>
218 private void ObjectKilled(CMModel model, CMView view, SceneObjectGroup group)
219 {
220 if ((m_state & State.SHOWING_CHANGES) > 0)
221 {
222 view.RemoveOrUpdateDeletedEntity(group);
223 model.RemoveOrUpdateDeletedEntity(group);
224 }
225 }
226
227 /// <summary>
228 /// Only called by the MainLoop.
229 /// </summary>
230 private void PrimitiveAdded(CMModel model, CMView view, Work currentJob)
231 {
232 if ((m_state & State.SHOWING_CHANGES) > 0)
233 {
234 foreach(Object scene in m_sceneList.Values)
235 m_view.DisplayAuras(model.CheckForNewEntitiesMissingAuras((Scene) scene));
236 }
237 }
238
239 /// <summary>
240 /// Only called by the MainLoop.
241 /// </summary>
242 private void UndoDid(CMModel model, CMView view, LLUUID uuid)
243 {
244 if ((m_state & State.SHOWING_CHANGES) > 0)
245 {
246 ContentManagementEntity ent = model.FindMetaEntityAffectedByUndo(uuid);
247 if (ent != null)
248 view.DisplayEntity(ent);
249 }
250 }
251
252 #endregion Private Methods
253
254 #region Protected Methods
255
256 protected void GroupBeingDeleted(SceneObjectGroup group)
257 {
258 m_log.Debug("[CONTENT MANAGEMENT] Something was deleted!!!");
259 Work moreWork = new Work();
260 moreWork.Type = WorkType.OBJECTKILLED;
261 moreWork.Data1 = group.Copy();
262 m_WorkQueue.Enqueue(moreWork);
263 }
264
265 protected void ObjectDuplicated(uint localID, LLVector3 offset, uint dupeFlags, LLUUID AgentID, LLUUID GroupID)
266 {
267 Work moreWork = new Work();
268 moreWork.Type = WorkType.OBJECTDUPLICATED;
269 moreWork.LocalId = localID;
270 m_WorkQueue.Enqueue(moreWork);
271 m_log.Debug("[CONTENT MANAGEMENT] dup queue");
272 }
273
274 protected void ObjectDuplicatedOnRay(uint localID, uint dupeFlags, LLUUID AgentID, LLUUID GroupID,
275 LLUUID RayTargetObj, LLVector3 RayEnd, LLVector3 RayStart,
276 bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates)
277 {
278 Work moreWork = new Work();
279 moreWork.Type = WorkType.OBJECTDUPLICATED;
280 moreWork.LocalId = localID;
281 m_WorkQueue.Enqueue(moreWork);
282 m_log.Debug("[CONTENT MANAGEMENT] dup queue");
283 }
284
285 protected void OnNewClient(IClientAPI client)
286 {
287 Work moreWork = new Work();
288 moreWork.Type = WorkType.NEWCLIENT;
289 moreWork.Data1 = client;
290 m_WorkQueue.Enqueue(moreWork);
291 m_log.Debug("[CONTENT MANAGEMENT] new client");
292 }
293
294 protected void OnUnDid(IClientAPI remoteClient, LLUUID primId)
295 {
296 Work moreWork = new Work();
297 moreWork.Type = WorkType.UNDODID;
298 moreWork.UUID = primId;
299 m_WorkQueue.Enqueue(moreWork);
300 m_log.Debug("[CONTENT MANAGEMENT] undid");
301 }
302
303 /// <summary>
304 /// Takes a list of scenes and forms a new orderd list according to the proximity of scenes to the second argument.
305 /// </summary>
306 protected static System.Collections.Generic.List<Scene> ScenesInOrderOfProximity( Hashtable sceneList, Scene scene)
307 {
308 int somethingAddedToList = 1;
309 System.Collections.Generic.List<Scene> newList = new List<Scene>();
310 newList.Add(scene);
311
312 if (! sceneList.ContainsValue(scene))
313 {
314 foreach(Object sceneObj in sceneList)
315 newList.Add((Scene) sceneObj);
316 return newList;
317 }
318
319 while(somethingAddedToList > 0)
320 {
321 somethingAddedToList = 0;
322 for(int i = 0; i < newList.Count; i++)
323 {
324 foreach(Object sceneObj in sceneList.Values)
325 {
326 if (newList[i].CheckNeighborRegion(((Scene)sceneObj).RegionInfo) && (! newList.Contains((Scene)sceneObj)) )
327 {
328 newList.Add((Scene)sceneObj);
329 somethingAddedToList++;
330 }
331 }
332 }
333 }
334
335 foreach(Object sceneObj in sceneList.Values)
336 if (! newList.Contains((Scene)sceneObj))
337 newList.Add((Scene)sceneObj);
338
339 return newList;
340 }
341
342 //This is stupid, the same information is contained in the first and second argument
343 protected void SimChatSent(Object x, OSChatMessage e)
344 {
345 m_log.Debug("[CONTENT MANAGEMENT] SIMCHAT SENT !!!!!!!");
346 m_log.Debug("[CONTENT MANAGEMENT] message was: " + e.Message);
347 Work moreWork = new Work();
348 moreWork.Type = WorkType.SIMCHAT;
349 moreWork.Data1 = e;
350 m_WorkQueue.Enqueue(moreWork);
351 }
352
353 /// <summary>
354 /// Adds extra handlers to a number of events so that the controller can produce work based on the client's actions.
355 /// </summary>
356 protected void StartManaging(IClientAPI client)
357 {
358 m_log.Debug("[CONTENT MANAGEMENT] Registering channel with chat services.");
359 client.OnChatFromViewer += SimChatSent;
360 init = true;
361
362 OnNewClient(client);
363
364 m_log.Debug("[CONTENT MANAGEMENT] Adding handlers to client.");
365 client.OnUpdatePrimScale += UpdateSingleScale;
515 client.OnUpdatePrimGroupScale += UpdateMultipleScale; 366 client.OnUpdatePrimGroupScale += UpdateMultipleScale;
516 client.OnUpdatePrimGroupPosition += UpdateMultiplePosition; 367 client.OnUpdatePrimGroupPosition += UpdateMultiplePosition;
517 client.OnUpdatePrimSinglePosition += UpdateSinglePosition; 368 client.OnUpdatePrimSinglePosition += UpdateSinglePosition;
518 client.OnUpdatePrimGroupRotation += UpdateMultipleRotation; 369 client.OnUpdatePrimGroupRotation += UpdateMultipleRotation;
519 client.OnUpdatePrimSingleRotation += UpdateSingleRotation; 370 client.OnUpdatePrimSingleRotation += UpdateSingleRotation;
520 client.OnAddPrim += UpdateNewParts; 371 client.OnAddPrim += UpdateNewParts;
521 client.OnObjectDuplicate += ObjectDuplicated; 372 client.OnObjectDuplicate += ObjectDuplicated;
522 client.OnObjectDuplicateOnRay += ObjectDuplicatedOnRay; 373 client.OnObjectDuplicateOnRay += ObjectDuplicatedOnRay;
523 client.OnUndo += OnUnDid; 374 client.OnUndo += OnUnDid;
524 //client.OnUpdatePrimGroupMouseRotation += m_innerScene.UpdatePrimRotation; 375 //client.OnUpdatePrimGroupMouseRotation += m_innerScene.UpdatePrimRotation;
525 } 376 }
526 377
527 /// <summary> 378 /// <summary>
528 /// 379 ///
529 /// </summary> 380 /// </summary>
530 protected void StopManaging(LLUUID clientUUID) 381 protected void StopManaging(LLUUID clientUUID)
531 { 382 {
532 foreach(Object sceneobj in m_sceneList.Values) 383 foreach(Object sceneobj in m_sceneList.Values)
533 { 384 {
534 ScenePresence presence = ((Scene)sceneobj).GetScenePresence(clientUUID); 385 ScenePresence presence = ((Scene)sceneobj).GetScenePresence(clientUUID);
535 if (presence != null) 386 if (presence != null)
536 { 387 {
537 IClientAPI client = presence.ControllingClient; 388 IClientAPI client = presence.ControllingClient;
538 m_log.Debug("[CONTENT MANAGEMENT] Unregistering channel with chat services."); 389 m_log.Debug("[CONTENT MANAGEMENT] Unregistering channel with chat services.");
539 client.OnChatFromViewer -= SimChatSent; 390 client.OnChatFromViewer -= SimChatSent;
540 391
541 m_log.Debug("[CONTENT MANAGEMENT] Removing handlers to client"); 392 m_log.Debug("[CONTENT MANAGEMENT] Removing handlers to client");
542 client.OnUpdatePrimScale -= UpdateSingleScale; 393 client.OnUpdatePrimScale -= UpdateSingleScale;
543 client.OnUpdatePrimGroupScale -= UpdateMultipleScale; 394 client.OnUpdatePrimGroupScale -= UpdateMultipleScale;
544 client.OnUpdatePrimGroupPosition -= UpdateMultiplePosition; 395 client.OnUpdatePrimGroupPosition -= UpdateMultiplePosition;
545 client.OnUpdatePrimSinglePosition -= UpdateSinglePosition; 396 client.OnUpdatePrimSinglePosition -= UpdateSinglePosition;
546 client.OnUpdatePrimGroupRotation -= UpdateMultipleRotation; 397 client.OnUpdatePrimGroupRotation -= UpdateMultipleRotation;
547 client.OnUpdatePrimSingleRotation -= UpdateSingleRotation; 398 client.OnUpdatePrimSingleRotation -= UpdateSingleRotation;
548 client.OnAddPrim -= UpdateNewParts; 399 client.OnAddPrim -= UpdateNewParts;
549 client.OnObjectDuplicate -= ObjectDuplicated; 400 client.OnObjectDuplicate -= ObjectDuplicated;
550 client.OnObjectDuplicateOnRay -= ObjectDuplicatedOnRay; 401 client.OnObjectDuplicateOnRay -= ObjectDuplicatedOnRay;
551 client.OnUndo -= OnUnDid; 402 client.OnUndo -= OnUnDid;
552 //client.OnUpdatePrimGroupMouseRotation += m_innerScene.UpdatePrimRotation; 403 //client.OnUpdatePrimGroupMouseRotation += m_innerScene.UpdatePrimRotation;
553 return; 404 return;
554 } 405 }
555 } 406 }
556 } 407 }
557 408
558 protected void GroupBeingDeleted(SceneObjectGroup group) 409 protected void UpdateMultiplePosition(uint localID, LLVector3 pos, IClientAPI remoteClient)
559 { 410 {
560 m_log.Debug("[CONTENT MANAGEMENT] Something was deleted!!!"); 411 Work moreWork = new Work();
561 Work moreWork = new Work(); 412 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
562 moreWork.Type = WorkType.OBJECTKILLED; 413 moreWork.LocalId = localID;
563 moreWork.Data1 = group.Copy(); 414 m_WorkQueue.Enqueue(moreWork);
564 m_WorkQueue.Enqueue(moreWork); 415 m_log.Debug("[CONTENT MANAGEMENT] pos");
565 } 416 }
566 417
567 //This is stupid, the same information is contained in the first and second argument 418 protected void UpdateMultipleRotation(uint localID, LLQuaternion rot, IClientAPI remoteClient)
568 protected void SimChatSent(Object x, OSChatMessage e) 419 {
569 { 420 Work moreWork = new Work();
570 m_log.Debug("[CONTENT MANAGEMENT] SIMCHAT SENT !!!!!!!"); 421 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
571 m_log.Debug("[CONTENT MANAGEMENT] message was: " + e.Message); 422 moreWork.LocalId = localID;
572 Work moreWork = new Work(); 423 m_WorkQueue.Enqueue(moreWork);
573 moreWork.Type = WorkType.SIMCHAT; 424 m_log.Debug("[CONTENT MANAGEMENT] rot");
574 moreWork.Data1 = e; 425 }
575 m_WorkQueue.Enqueue(moreWork); 426
576 } 427 protected void UpdateMultipleScale(uint localID, LLVector3 scale, IClientAPI remoteClient)
577 428 {
578 protected void ObjectDuplicated(uint localID, LLVector3 offset, uint dupeFlags, LLUUID AgentID, LLUUID GroupID) 429 Work moreWork = new Work();
579 { 430 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
580 Work moreWork = new Work(); 431 moreWork.LocalId = localID;
581 moreWork.Type = WorkType.OBJECTDUPLICATED; 432 m_WorkQueue.Enqueue(moreWork);
582 moreWork.LocalId = localID; 433 m_log.Debug("[CONTENT MANAGEMENT]scale");
583 m_WorkQueue.Enqueue(moreWork); 434 }
584 m_log.Debug("[CONTENT MANAGEMENT] dup queue"); 435
585 } 436 protected void UpdateNewParts(LLUUID ownerID, LLVector3 RayEnd, LLQuaternion rot, PrimitiveBaseShape shape,
586 437 byte bypassRaycast, LLVector3 RayStart, LLUUID RayTargetID,
587 protected void ObjectDuplicatedOnRay(uint localID, uint dupeFlags, LLUUID AgentID, LLUUID GroupID, 438 byte RayEndIsIntersection)
588 LLUUID RayTargetObj, LLVector3 RayEnd, LLVector3 RayStart, 439 {
589 bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates) 440 Work moreWork = new Work();
590 { 441 moreWork.Type = WorkType.PRIMITIVEADDED;
591 Work moreWork = new Work(); 442 moreWork.UUID = ownerID;
592 moreWork.Type = WorkType.OBJECTDUPLICATED; 443 m_WorkQueue.Enqueue(moreWork);
593 moreWork.LocalId = localID; 444 m_log.Debug("[CONTENT MANAGEMENT] new parts");
594 m_WorkQueue.Enqueue(moreWork); 445 }
595 m_log.Debug("[CONTENT MANAGEMENT] dup queue"); 446
596 } 447 protected void UpdateSinglePosition(uint localID, LLVector3 pos, IClientAPI remoteClient)
597 448 {
598 protected void OnNewClient(IClientAPI client) 449 Work moreWork = new Work();
599 { 450 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
600 Work moreWork = new Work(); 451 moreWork.LocalId = localID;
601 moreWork.Type = WorkType.NEWCLIENT; 452 m_WorkQueue.Enqueue(moreWork);
602 moreWork.Data1 = client; 453 m_log.Debug("[CONTENT MANAGEMENT] move");
603 m_WorkQueue.Enqueue(moreWork); 454 }
604 m_log.Debug("[CONTENT MANAGEMENT] new client"); 455
605 } 456 /// <summary>
606 457 ///
607 protected void OnUnDid(IClientAPI remoteClient, LLUUID primId) 458 /// </summary>
608 { 459 protected void UpdateSingleRotation(uint localID, LLQuaternion rot, IClientAPI remoteClient)
609 Work moreWork = new Work(); 460 {
610 moreWork.Type = WorkType.UNDODID; 461 Work moreWork = new Work();
611 moreWork.UUID = primId; 462 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
612 m_WorkQueue.Enqueue(moreWork); 463 moreWork.LocalId = localID;
613 m_log.Debug("[CONTENT MANAGEMENT] undid"); 464 m_WorkQueue.Enqueue(moreWork);
614 } 465 m_log.Debug("[CONTENT MANAGEMENT] rot");
615 466 }
616 protected void UpdateSinglePosition(uint localID, LLVector3 pos, IClientAPI remoteClient) 467
617 { 468 protected void UpdateSingleScale(uint localID, LLVector3 scale, IClientAPI remoteClient)
618 Work moreWork = new Work(); 469 {
619 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE; 470 Work moreWork = new Work();
620 moreWork.LocalId = localID; 471 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
621 m_WorkQueue.Enqueue(moreWork); 472 moreWork.LocalId = localID;
622 m_log.Debug("[CONTENT MANAGEMENT] move"); 473 m_WorkQueue.Enqueue(moreWork);
623 } 474 m_log.Debug("[CONTENT MANAGEMENT] scale");
624 475 }
625 /// <summary> 476
626 /// 477 /// <summary>
627 /// </summary> 478 /// Only called from within the SimChat method.
628 protected void UpdateSingleRotation(uint localID, LLQuaternion rot, IClientAPI remoteClient) 479 /// </summary>
629 { 480 protected void commit(string message, Scene scene, CMModel model, CMView view)
630 Work moreWork = new Work(); 481 {
631 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE; 482 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity( m_sceneList, scene);
632 moreWork.LocalId = localID; 483
633 m_WorkQueue.Enqueue(moreWork); 484 string[] args = message.Split(new char[] {' '});
634 m_log.Debug("[CONTENT MANAGEMENT] rot"); 485
635 } 486 char[] logMessage = {' '};
636 487 if (args.Length > 1)
637 protected void UpdateSingleScale(uint localID, LLVector3 scale, IClientAPI remoteClient) 488 {
638 { 489 logMessage = new char[message.Length - (args[0].Length)];
639 Work moreWork = new Work(); 490 message.CopyTo(args[0].Length, logMessage, 0, message.Length - (args[0].Length));
640 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE; 491 }
641 moreWork.LocalId = localID; 492
642 m_WorkQueue.Enqueue(moreWork); 493 m_log.Debug("[CONTENT MANAGEMENT] Saving terrain and objects of region.");
643 m_log.Debug("[CONTENT MANAGEMENT] scale"); 494 foreach(Scene currScene in proximitySceneList)
644 } 495 {
645 496 model.CommitRegion(currScene, new String(logMessage));
646 protected void UpdateMultiplePosition(uint localID, LLVector3 pos, IClientAPI remoteClient) 497 view.SendSimChatMessage(scene, "Region Saved Successfully: " + currScene.RegionInfo.RegionName);
647 { 498 }
648 Work moreWork = new Work(); 499
649 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE; 500 view.SendSimChatMessage(scene, "Successfully saved all regions.");
650 moreWork.LocalId = localID; 501 m_state |= State.DIRTY;
651 m_WorkQueue.Enqueue(moreWork); 502
652 m_log.Debug("[CONTENT MANAGEMENT] pos"); 503 if ((m_state & State.SHOWING_CHANGES) > 0) //DISPLAY NEW CHANGES INSTEAD OF OLD CHANGES
653 } 504 {
654 505 view.SendSimChatMessage(scene, "Updating differences between new revision and current environment.");
655 protected void UpdateMultipleRotation(uint localID, LLQuaternion rot, IClientAPI remoteClient) 506 //Hide objects from users and Forget about them
656 { 507 view.HideAllMetaEntities();
657 Work moreWork = new Work(); 508 view.HideAllAuras();
658 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE; 509 model.DeleteAllMetaObjects();
659 moreWork.LocalId = localID; 510
660 m_WorkQueue.Enqueue(moreWork); 511 //Recreate them from backend files
661 m_log.Debug("[CONTENT MANAGEMENT] rot"); 512 foreach(Scene currScene in proximitySceneList)
662 } 513 {
663 514 model.UpdateCMEntities(currScene);
664 protected void UpdateMultipleScale(uint localID, LLVector3 scale, IClientAPI remoteClient) 515 view.SendSimChatMessage(scene, "Finished updating differences between current scene and last revision: " + currScene.RegionInfo.RegionName);
665 { 516 }
666 Work moreWork = new Work(); 517
667 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE; 518 //Display new objects to users1
668 moreWork.LocalId = localID; 519 view.DisplayRecentChanges();
669 m_WorkQueue.Enqueue(moreWork); 520 view.SendSimChatMessage(scene, "Finished updating for DIFF-MODE.");
670 m_log.Debug("[CONTENT MANAGEMENT]scale"); 521 m_state &= ~(State.DIRTY);
671 } 522 m_state |= State.SHOWING_CHANGES;
672 523 }
673 protected void UpdateNewParts(LLUUID ownerID, LLVector3 RayEnd, LLQuaternion rot, PrimitiveBaseShape shape, 524 }
674 byte bypassRaycast, LLVector3 RayStart, LLUUID RayTargetID, 525
675 byte RayEndIsIntersection) 526 /// <summary>
676 { 527 /// Only called from within the SimChat method.
677 Work moreWork = new Work(); 528 /// </summary>
678 moreWork.Type = WorkType.PRIMITIVEADDED; 529 protected void diffmode(Scene scene, CMModel model, CMView view)
679 moreWork.UUID = ownerID; 530 {
680 m_WorkQueue.Enqueue(moreWork); 531 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity( m_sceneList, scene);
681 m_log.Debug("[CONTENT MANAGEMENT] new parts"); 532
682 } 533 if ((m_state & State.SHOWING_CHANGES) > 0) // TURN OFF
683 } 534 {
684} 535 view.SendSimChatMessage(scene, "Hiding all meta objects.");
536 view.HideAllMetaEntities();
537 view.HideAllAuras();
538 view.SendSimChatMessage(scene, "Diff-mode = OFF");
539
540 m_state &= ~State.SHOWING_CHANGES;
541 return;
542 }
543 else // TURN ON
544 {
545 if ((m_state & State.DIRTY) != 0 || m_state == State.NONE)
546 {
547 view.SendSimChatMessage(scene, "Hiding meta objects and replacing with latest revision");
548 //Hide objects from users and Forget about them
549 view.HideAllMetaEntities();
550 view.HideAllAuras();
551 model.DeleteAllMetaObjects();
552 //Recreate them from backend files
553 foreach(Object currScene in m_sceneList.Values)
554 model.UpdateCMEntities((Scene) currScene);
555 }
556 else if ((m_state & State.DIRTY) != 0) {
557 view.SendSimChatMessage(scene, "Forming list of meta entities with latest revision");
558 foreach(Scene currScene in proximitySceneList)
559 model.UpdateCMEntities(currScene);
560 }
561
562 view.SendSimChatMessage(scene, "Displaying differences between last revision and current environment");
563 foreach(Scene currScene in proximitySceneList)
564 model.CheckForNewEntitiesMissingAuras(currScene);
565 view.DisplayRecentChanges();
566
567 view.SendSimChatMessage(scene, "Diff-mode = ON");
568 m_state |= State.SHOWING_CHANGES;
569 m_state &= ~State.DIRTY;
570 }
571 }
572
573 /// <summary>
574 /// Only called from within the SimChat method. Hides all auras and meta entities,
575 /// retrieves the current scene object list with the most recent revision retrieved from the model for each scene,
576 /// then lets the view update the clients of the new objects.
577 /// </summary>
578 protected void rollback(Scene scene, CMModel model, CMView view)
579 {
580 if ((m_state & State.SHOWING_CHANGES) > 0)
581 {
582 view.HideAllAuras();
583 view.HideAllMetaEntities();
584 }
585
586 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity( m_sceneList, scene);
587 foreach(Scene currScene in proximitySceneList)
588 model.RollbackRegion(currScene);
589
590 if ((m_state & State.DIRTY) != 0 )
591 {
592 model.DeleteAllMetaObjects();
593 foreach(Scene currScene in proximitySceneList)
594 model.UpdateCMEntities(currScene);
595 }
596
597 if ((m_state & State.SHOWING_CHANGES) > 0)
598 view.DisplayRecentChanges();
599 }
600
601 #endregion Protected Methods
602
603 #region Public Methods
604
605 /// <summary>
606 /// Register a new scene object to keep track of for revisioning. Starts the controller monitoring actions of clients within the given scene.
607 /// </summary>
608 /// <param name="scene">
609 /// A <see cref="Scene"/>
610 /// </param>
611 public void RegisterNewRegion(Scene scene)
612 {
613 m_sceneList.Add(scene.RegionInfo.RegionID, scene);
614
615 m_log.Debug("[CONTENT MANAGEMENT] Registering new region: " + scene.RegionInfo.RegionID);
616 m_log.Debug("[CONTENT MANAGEMENT] Initializing Content Management System.");
617
618 scene.EventManager.OnNewClient += StartManaging;
619 scene.EventManager.OnRemovePresence += StopManaging;
620 // scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
621 scene.EventManager.OnObjectBeingRemovedFromScene += GroupBeingDeleted;
622 }
623
624 /// <summary>
625 /// Only called by the MainLoop. Takes the message from a user sent to the channel and executes the proper command.
626 /// </summary>
627 public void SimChat(CMModel model, CMView view, OSChatMessage e, int channel)
628 {
629 if (e.Channel != channel)
630 return;
631 if (e.Sender == null)
632 return;
633
634 m_log.Debug("[CONTENT MANAGEMENT] Message received: " + e.Message);
635
636 IClientAPI client = e.Sender;
637 Scene scene = (Scene) e.Scene;
638 string message = e.Message;
639 string[] args = e.Message.Split(new char[] {' '});
640
641 ScenePresence avatar = scene.GetScenePresence(client.AgentId);
642
643 if (!(m_estateModule.IsManager(avatar.UUID)))
644 {
645 m_log.Debug("[CONTENT MANAGEMENT] Message sent from non Estate Manager ... ignoring.");
646 view.SendSimChatMessage(scene, "You must be an estate manager to perform that action.");
647 return;
648 }
649
650 switch(args[0])
651 {
652 case "ci":
653 case "commit":
654 commit(message, scene, model, view);
655 break;
656 case "dm":
657 case "diff-mode":
658 diffmode(scene, model, view);
659 break;
660 case "rb":
661 case "rollback":
662 rollback(scene, model, view);
663 break;
664 case "help":
665 m_view.DisplayHelpMenu(scene);
666 break;
667 default:
668 view.SendSimChatMessage(scene, "Command not found: " + args[0]);
669 break;
670 }
671 }
672
673 #endregion Public Methods
674
675 #region Other
676
677 /// <value>
678 /// Used to keep track of whether a list has been produced yet and whether that list is up-to-date compard to latest revision on disk.
679 /// </value>
680 [Flags]
681 private enum State
682 {
683 NONE = 0,
684 DIRTY = 1, // The meta entities may not correctly represent the last revision.
685 SHOWING_CHANGES = 1<<1 // The meta entities are being shown to user.
686 }
687
688 /// <value>
689 /// The structure that defines the basic unit of work which is produced when a user sends commands to the ContentMangaementSystem.
690 /// </value>
691 private struct Work
692 {
693 #region Fields
694
695 public Object Data1; //Just space for holding data.
696 public Object Data2; //Just more space for holding data.
697 public uint LocalId; //Convenient
698 public WorkType Type;
699 public LLUUID UUID; //Convenient
700
701 #endregion Fields
702 }
703
704 /// <value>
705 /// Identifies what the data in struct Work should be used for.
706 /// </value>
707 private enum WorkType
708 {
709 NONE,
710 OBJECTATTRIBUTECHANGE,
711 PRIMITIVEADDED,
712 OBJECTDUPLICATED,
713 OBJECTKILLED,
714 UNDODID,
715 NEWCLIENT,
716 SIMCHAT
717 }
718
719 #endregion Other
720 }
721} \ No newline at end of file