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