From 180be7de07014aa33bc6066f12a0819b731c1c9d Mon Sep 17 00:00:00 2001
From: Dr Scofield
Date: Tue, 10 Feb 2009 13:10:57 +0000
Subject: this is step 2 of 2 of the OpenSim.Region.Environment refactor.
NOTHING has been deleted or moved off to forge at this point. what has
happened is that OpenSim.Region.Environment.Modules has been split in two:
- OpenSim.Region.CoreModules: all those modules that are either
directly or indirectly referenced from other OpenSim packages, or
that provide functionality that the OpenSim developer community
considers core functionality:
CoreModules/Agent/AssetTransaction
CoreModules/Agent/Capabilities
CoreModules/Agent/TextureDownload
CoreModules/Agent/TextureSender
CoreModules/Agent/TextureSender/Tests
CoreModules/Agent/Xfer
CoreModules/Avatar/AvatarFactory
CoreModules/Avatar/Chat/ChatModule
CoreModules/Avatar/Combat
CoreModules/Avatar/Currency/SampleMoney
CoreModules/Avatar/Dialog
CoreModules/Avatar/Friends
CoreModules/Avatar/Gestures
CoreModules/Avatar/Groups
CoreModules/Avatar/InstantMessage
CoreModules/Avatar/Inventory
CoreModules/Avatar/Inventory/Archiver
CoreModules/Avatar/Inventory/Transfer
CoreModules/Avatar/Lure
CoreModules/Avatar/ObjectCaps
CoreModules/Avatar/Profiles
CoreModules/Communications/Local
CoreModules/Communications/REST
CoreModules/Framework/EventQueue
CoreModules/Framework/InterfaceCommander
CoreModules/Hypergrid
CoreModules/InterGrid
CoreModules/Scripting/DynamicTexture
CoreModules/Scripting/EMailModules
CoreModules/Scripting/HttpRequest
CoreModules/Scripting/LoadImageURL
CoreModules/Scripting/VectorRender
CoreModules/Scripting/WorldComm
CoreModules/Scripting/XMLRPC
CoreModules/World/Archiver
CoreModules/World/Archiver/Tests
CoreModules/World/Estate
CoreModules/World/Land
CoreModules/World/Permissions
CoreModules/World/Serialiser
CoreModules/World/Sound
CoreModules/World/Sun
CoreModules/World/Terrain
CoreModules/World/Terrain/DefaultEffects
CoreModules/World/Terrain/DefaultEffects/bin
CoreModules/World/Terrain/DefaultEffects/bin/Debug
CoreModules/World/Terrain/Effects
CoreModules/World/Terrain/FileLoaders
CoreModules/World/Terrain/FloodBrushes
CoreModules/World/Terrain/PaintBrushes
CoreModules/World/Terrain/Tests
CoreModules/World/Vegetation
CoreModules/World/Wind
CoreModules/World/WorldMap
- OpenSim.Region.OptionalModules: all those modules that are not core
modules:
OptionalModules/Avatar/Chat/IRC-stuff
OptionalModules/Avatar/Concierge
OptionalModules/Avatar/Voice/AsterixVoice
OptionalModules/Avatar/Voice/SIPVoice
OptionalModules/ContentManagementSystem
OptionalModules/Grid/Interregion
OptionalModules/Python
OptionalModules/SvnSerialiser
OptionalModules/World/NPC
OptionalModules/World/TreePopulator
---
.../ContentManagementSystem/CMController.cs | 757 +++++++++++++++++++++
1 file changed, 757 insertions(+)
create mode 100644 OpenSim/Region/OptionalModules/ContentManagementSystem/CMController.cs
(limited to 'OpenSim/Region/OptionalModules/ContentManagementSystem/CMController.cs')
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 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#region Header
+
+// CMController.cs
+// User: bongiojp
+//
+
+#endregion Header
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+
+using OpenMetaverse;
+
+using OpenSim;
+using OpenSim.Framework;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.Framework.Scenes;
+using OpenSim.Region.Physics.Manager;
+
+using log4net;
+
+namespace OpenSim.Region.OptionalModules.ContentManagement
+{
+ ///
+ /// 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,
+ /// 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.
+ ///
+ public class CMController
+ {
+ #region Static Fields
+
+ private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// The queue that keeps track of which actions have happened. The MainLoop thread eats through this queue.
+ ///
+ private static OpenSim.Framework.BlockingQueue m_WorkQueue = new OpenSim.Framework.BlockingQueue();
+
+ #endregion Static Fields
+
+ #region Fields
+
+ //bool init = false;
+ int m_channel = -1;
+
+ ///
+ /// The estate module is used to identify which clients are estateManagers. Presently, the controller only pays attention to estate managers.
+ ///
+ IEstateModule m_estateModule = null;
+
+ //These have to be global variables, threading doesn't allow for passing parameters. (Used in MainLoop)
+ CMModel m_model = null;
+
+ ///
+ /// A list of all the scenes that should be revisioned. Controller is the only class that keeps track of all scenes in the region.
+ ///
+ Hashtable m_sceneList = Hashtable.Synchronized(new Hashtable());
+ State m_state = State.NONE;
+ Thread m_thread = null;
+ CMView m_view = null;
+
+ #endregion Fields
+
+ #region Constructors
+
+ ///
+ /// Initializes a work thread with an initial scene. Additional scenes should be added through the RegisterNewRegion method.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The first scene to keep track of.
+ ///
+ ///
+ /// The simchat channel number to listen to for instructions
+ ///
+ public CMController(CMModel model, CMView view, Scene scene, int channel)
+ {
+ m_model = model; m_view = view; m_channel = channel;
+ RegisterNewRegion(scene);
+ Initialize(model, view, scene, channel);
+ }
+
+ #endregion Constructors
+
+ #region Private Methods
+
+ //------------------------------------------------ EVENTS ----------------------------------------------------//
+// private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
+// {
+// }
+
+ ///
+ /// 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.
+ ///
+ private SceneObjectGroup GetGroupByPrim(uint localID)
+ {
+ foreach (Object currScene in m_sceneList.Values)
+ {
+ foreach (EntityBase ent in ((Scene)currScene).GetEntities())
+ {
+ if (ent is SceneObjectGroup)
+ {
+ if (((SceneObjectGroup)ent).HasChildPrim(localID))
+ return (SceneObjectGroup)ent;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void Initialize(CMModel model, CMView view, Scene scene, int channel)
+ {
+ lock (this)
+ {
+ m_estateModule = scene.RequestModuleInterface();
+ m_thread = new Thread(MainLoop);
+ m_thread.Name = "Content Management";
+ m_thread.IsBackground = true;
+ m_thread.Start();
+ ThreadTracker.Add(m_thread);
+ m_state = State.NONE;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ private void MainLoop()
+ {
+ try
+ {
+ CMModel model = m_model; CMView view = m_view; int channel = m_channel;
+ Work currentJob = new Work();
+ while (true)
+ {
+ currentJob = m_WorkQueue.Dequeue();
+ m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- DeQueued a request");
+ m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- Work type: " + currentJob.Type);
+ switch (currentJob.Type)
+ {
+ case WorkType.NONE:
+ break;
+ case WorkType.OBJECTATTRIBUTECHANGE:
+ ObjectAttributeChanged(model, view, currentJob.LocalId);
+ break;
+ case WorkType.PRIMITIVEADDED:
+ PrimitiveAdded(model, view, currentJob);
+ break;
+ case WorkType.OBJECTDUPLICATED:
+ ObjectDuplicated(model, view, currentJob.LocalId);
+ break;
+ case WorkType.OBJECTKILLED:
+ ObjectKilled(model, view, (SceneObjectGroup) currentJob.Data1);
+ break;
+ case WorkType.UNDODID:
+ UndoDid(model, view, currentJob.UUID);
+ break;
+ case WorkType.NEWCLIENT:
+ NewClient(view, (IClientAPI) currentJob.Data1);
+ break;
+ case WorkType.SIMCHAT:
+ m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- Message received: " + ((OSChatMessage) currentJob.Data1).Message);
+ SimChat(model, view, (OSChatMessage) currentJob.Data1, channel);
+ break;
+ default:
+ m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- uuuuuuuuuh, what?");
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ // TODO: Let users in the sim and those entering it and possibly an external watchdog know what has happened
+ m_log.ErrorFormat(
+ "[CONTENT MANAGEMENT]: Content management thread terminating with exception. PLEASE REBOOT YOUR SIM - CONTENT MANAGEMENT WILL NOT BE AVAILABLE UNTIL YOU DO. Exception is {0}",
+ e);
+ }
+ }
+
+ ///
+ /// Only called by the MainLoop. Updates the view of a new client with metaentities if diff-mode is currently enabled.
+ ///
+ private void NewClient(CMView view, IClientAPI client)
+ {
+ if ((m_state & State.SHOWING_CHANGES) > 0)
+ view.SendMetaEntitiesToNewClient(client);
+ }
+
+ ///
+ /// Only called by the MainLoop.
+ ///
+ private void ObjectAttributeChanged(CMModel model, CMView view, uint LocalId)
+ {
+ SceneObjectGroup group = null;
+ if ((m_state & State.SHOWING_CHANGES) > 0)
+ {
+ group = GetGroupByPrim(LocalId);
+ if (group != null)
+ {
+ view.DisplayAuras(model.UpdateNormalEntityEffects(group)); //Might be a normal entity (green aura)
+ m_view.DisplayMetaEntity(group.UUID); //Might be a meta entity (blue aura)
+ }
+ }
+ }
+
+ ///
+ /// Only called by the MainLoop. Displays new green auras over the newly created part when a part is shift copied.
+ ///
+ private void ObjectDuplicated(CMModel model, CMView view, uint localId)
+ {
+ if ((m_state & State.SHOWING_CHANGES) > 0)
+ view.DisplayAuras(model.CheckForNewEntitiesMissingAuras(GetGroupByPrim(localId).Scene));
+ }
+
+ ///
+ /// Only called by the MainLoop.
+ ///
+ private void ObjectKilled(CMModel model, CMView view, SceneObjectGroup group)
+ {
+ if ((m_state & State.SHOWING_CHANGES) > 0)
+ {
+ view.RemoveOrUpdateDeletedEntity(group);
+ model.RemoveOrUpdateDeletedEntity(group);
+ }
+ }
+
+ ///
+ /// Only called by the MainLoop.
+ ///
+ private void PrimitiveAdded(CMModel model, CMView view, Work currentJob)
+ {
+ if ((m_state & State.SHOWING_CHANGES) > 0)
+ {
+ foreach (Object scene in m_sceneList.Values)
+ m_view.DisplayAuras(model.CheckForNewEntitiesMissingAuras((Scene) scene));
+ }
+ }
+
+ ///
+ /// Only called by the MainLoop.
+ ///
+ private void UndoDid(CMModel model, CMView view, UUID uuid)
+ {
+ if ((m_state & State.SHOWING_CHANGES) > 0)
+ {
+ ContentManagementEntity ent = model.FindMetaEntityAffectedByUndo(uuid);
+ if (ent != null)
+ view.DisplayEntity(ent);
+ }
+ }
+
+ #endregion Private Methods
+
+ #region Protected Methods
+
+ protected void GroupBeingDeleted(SceneObjectGroup group)
+ {
+ m_log.Debug("[CONTENT MANAGEMENT] Something was deleted!!!");
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTKILLED;
+ moreWork.Data1 = group.Copy();
+ m_WorkQueue.Enqueue(moreWork);
+ }
+
+ protected void ObjectDuplicated(uint localID, Vector3 offset, uint dupeFlags, UUID AgentID, UUID GroupID)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTDUPLICATED;
+ moreWork.LocalId = localID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] dup queue");
+ }
+
+ protected void ObjectDuplicatedOnRay(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID,
+ UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart,
+ bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTDUPLICATED;
+ moreWork.LocalId = localID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] dup queue");
+ }
+
+ protected void OnNewClient(IClientAPI client)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.NEWCLIENT;
+ moreWork.Data1 = client;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] new client");
+ }
+
+ protected void OnUnDid(IClientAPI remoteClient, UUID primId)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.UNDODID;
+ moreWork.UUID = primId;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] undid");
+ }
+
+ ///
+ /// Takes a list of scenes and forms a new orderd list according to the proximity of scenes to the second argument.
+ ///
+ protected static System.Collections.Generic.List ScenesInOrderOfProximity(Hashtable sceneList, Scene scene)
+ {
+ int somethingAddedToList = 1;
+ System.Collections.Generic.List newList = new List();
+ newList.Add(scene);
+
+ if (!sceneList.ContainsValue(scene))
+ {
+ foreach (Object sceneObj in sceneList)
+ newList.Add((Scene) sceneObj);
+ return newList;
+ }
+
+ while (somethingAddedToList > 0)
+ {
+ somethingAddedToList = 0;
+ for (int i = 0; i < newList.Count; i++)
+ {
+ foreach (Object sceneObj in sceneList.Values)
+ {
+ if (newList[i].CheckNeighborRegion(((Scene)sceneObj).RegionInfo) && (!newList.Contains((Scene)sceneObj)))
+ {
+ newList.Add((Scene)sceneObj);
+ somethingAddedToList++;
+ }
+ }
+ }
+ }
+
+ foreach (Object sceneObj in sceneList.Values)
+ if (!newList.Contains((Scene)sceneObj))
+ newList.Add((Scene)sceneObj);
+
+ return newList;
+ }
+
+ //This is stupid, the same information is contained in the first and second argument
+ protected void SimChatSent(Object x, OSChatMessage e)
+ {
+ m_log.Debug("[CONTENT MANAGEMENT] SIMCHAT SENT !!!!!!!");
+ m_log.Debug("[CONTENT MANAGEMENT] message was: " + e.Message);
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.SIMCHAT;
+ moreWork.Data1 = e;
+ m_WorkQueue.Enqueue(moreWork);
+ }
+
+ ///
+ /// Adds extra handlers to a number of events so that the controller can produce work based on the client's actions.
+ ///
+ protected void StartManaging(IClientAPI client)
+ {
+ m_log.Debug("[CONTENT MANAGEMENT] Registering channel with chat services.");
+ // client.OnChatFromClient += SimChatSent;
+ //init = true;
+
+ OnNewClient(client);
+
+ m_log.Debug("[CONTENT MANAGEMENT] Adding handlers to client.");
+ client.OnUpdatePrimScale += UpdateSingleScale;
+ client.OnUpdatePrimGroupScale += UpdateMultipleScale;
+ client.OnUpdatePrimGroupPosition += UpdateMultiplePosition;
+ client.OnUpdatePrimSinglePosition += UpdateSinglePosition;
+ client.OnUpdatePrimGroupRotation += UpdateMultipleRotation;
+ client.OnUpdatePrimSingleRotation += UpdateSingleRotation;
+ client.OnAddPrim += UpdateNewParts;
+ client.OnObjectDuplicate += ObjectDuplicated;
+ client.OnObjectDuplicateOnRay += ObjectDuplicatedOnRay;
+ client.OnUndo += OnUnDid;
+ //client.OnUpdatePrimGroupMouseRotation += m_innerScene.UpdatePrimRotation;
+ }
+
+ ///
+ ///
+ ///
+ protected void StopManaging(UUID clientUUID)
+ {
+ foreach (Object sceneobj in m_sceneList.Values)
+ {
+ ScenePresence presence = ((Scene)sceneobj).GetScenePresence(clientUUID);
+ if (presence != null)
+ {
+ IClientAPI client = presence.ControllingClient;
+ m_log.Debug("[CONTENT MANAGEMENT] Unregistering channel with chat services.");
+ // client.OnChatFromViewer -= SimChatSent;
+
+ m_log.Debug("[CONTENT MANAGEMENT] Removing handlers to client");
+ client.OnUpdatePrimScale -= UpdateSingleScale;
+ client.OnUpdatePrimGroupScale -= UpdateMultipleScale;
+ client.OnUpdatePrimGroupPosition -= UpdateMultiplePosition;
+ client.OnUpdatePrimSinglePosition -= UpdateSinglePosition;
+ client.OnUpdatePrimGroupRotation -= UpdateMultipleRotation;
+ client.OnUpdatePrimSingleRotation -= UpdateSingleRotation;
+ client.OnAddPrim -= UpdateNewParts;
+ client.OnObjectDuplicate -= ObjectDuplicated;
+ client.OnObjectDuplicateOnRay -= ObjectDuplicatedOnRay;
+ client.OnUndo -= OnUnDid;
+ //client.OnUpdatePrimGroupMouseRotation += m_innerScene.UpdatePrimRotation;
+ return;
+ }
+ }
+ }
+
+ protected void UpdateMultiplePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
+ moreWork.LocalId = localID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] pos");
+ }
+
+ protected void UpdateMultipleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
+ moreWork.LocalId = localID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] rot");
+ }
+
+ protected void UpdateMultipleScale(uint localID, Vector3 scale, IClientAPI remoteClient)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
+ moreWork.LocalId = localID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT]scale");
+ }
+
+ protected void UpdateNewParts(UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot, PrimitiveBaseShape shape,
+ byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
+ byte RayEndIsIntersection)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.PRIMITIVEADDED;
+ moreWork.UUID = ownerID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] new parts");
+ }
+
+ protected void UpdateSinglePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
+ moreWork.LocalId = localID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] move");
+ }
+
+ ///
+ ///
+ ///
+ protected void UpdateSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
+ moreWork.LocalId = localID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] rot");
+ }
+
+ protected void UpdateSingleScale(uint localID, Vector3 scale, IClientAPI remoteClient)
+ {
+ Work moreWork = new Work();
+ moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
+ moreWork.LocalId = localID;
+ m_WorkQueue.Enqueue(moreWork);
+ m_log.Debug("[CONTENT MANAGEMENT] scale");
+ }
+
+ ///
+ /// Only called from within the SimChat method.
+ ///
+ protected void commit(string message, Scene scene, CMModel model, CMView view)
+ {
+ System.Collections.Generic.List proximitySceneList = ScenesInOrderOfProximity(m_sceneList, scene);
+
+ string[] args = message.Split(new char[] {' '});
+
+ char[] logMessage = {' '};
+ if (args.Length > 1)
+ {
+ logMessage = new char[message.Length - (args[0].Length)];
+ message.CopyTo(args[0].Length, logMessage, 0, message.Length - (args[0].Length));
+ }
+
+ m_log.Debug("[CONTENT MANAGEMENT] Saving terrain and objects of region.");
+ foreach (Scene currScene in proximitySceneList)
+ {
+ model.CommitRegion(currScene, new String(logMessage));
+ view.SendSimChatMessage(scene, "Region Saved Successfully: " + currScene.RegionInfo.RegionName);
+ }
+
+ view.SendSimChatMessage(scene, "Successfully saved all regions.");
+ m_state |= State.DIRTY;
+
+ if ((m_state & State.SHOWING_CHANGES) > 0) //DISPLAY NEW CHANGES INSTEAD OF OLD CHANGES
+ {
+ view.SendSimChatMessage(scene, "Updating differences between new revision and current environment.");
+ //Hide objects from users and Forget about them
+ view.HideAllMetaEntities();
+ view.HideAllAuras();
+ model.DeleteAllMetaObjects();
+
+ //Recreate them from backend files
+ foreach (Scene currScene in proximitySceneList)
+ {
+ model.UpdateCMEntities(currScene);
+ view.SendSimChatMessage(scene, "Finished updating differences between current scene and last revision: " + currScene.RegionInfo.RegionName);
+ }
+
+ //Display new objects to users1
+ view.DisplayRecentChanges();
+ view.SendSimChatMessage(scene, "Finished updating for DIFF-MODE.");
+ m_state &= ~(State.DIRTY);
+ m_state |= State.SHOWING_CHANGES;
+ }
+ }
+
+ ///
+ /// Only called from within the SimChat method.
+ ///
+ protected void diffmode(Scene scene, CMModel model, CMView view)
+ {
+ System.Collections.Generic.List proximitySceneList = ScenesInOrderOfProximity(m_sceneList, scene);
+
+ if ((m_state & State.SHOWING_CHANGES) > 0) // TURN OFF
+ {
+ view.SendSimChatMessage(scene, "Hiding all meta objects.");
+ view.HideAllMetaEntities();
+ view.HideAllAuras();
+ view.SendSimChatMessage(scene, "Diff-mode = OFF");
+
+ m_state &= ~State.SHOWING_CHANGES;
+ return;
+ }
+ else // TURN ON
+ {
+ if ((m_state & State.DIRTY) != 0 || m_state == State.NONE)
+ {
+ view.SendSimChatMessage(scene, "Hiding meta objects and replacing with latest revision");
+ //Hide objects from users and Forget about them
+ view.HideAllMetaEntities();
+ view.HideAllAuras();
+ model.DeleteAllMetaObjects();
+ //Recreate them from backend files
+ foreach (Object currScene in m_sceneList.Values)
+ model.UpdateCMEntities((Scene) currScene);
+ }
+ else if ((m_state & State.DIRTY) != 0) {
+ view.SendSimChatMessage(scene, "Forming list of meta entities with latest revision");
+ foreach (Scene currScene in proximitySceneList)
+ model.UpdateCMEntities(currScene);
+ }
+
+ view.SendSimChatMessage(scene, "Displaying differences between last revision and current environment");
+ foreach (Scene currScene in proximitySceneList)
+ model.CheckForNewEntitiesMissingAuras(currScene);
+ view.DisplayRecentChanges();
+
+ view.SendSimChatMessage(scene, "Diff-mode = ON");
+ m_state |= State.SHOWING_CHANGES;
+ m_state &= ~State.DIRTY;
+ }
+ }
+
+ ///
+ /// Only called from within the SimChat method. Hides all auras and meta entities,
+ /// retrieves the current scene object list with the most recent revision retrieved from the model for each scene,
+ /// then lets the view update the clients of the new objects.
+ ///
+ protected void rollback(Scene scene, CMModel model, CMView view)
+ {
+ if ((m_state & State.SHOWING_CHANGES) > 0)
+ {
+ view.HideAllAuras();
+ view.HideAllMetaEntities();
+ }
+
+ System.Collections.Generic.List proximitySceneList = ScenesInOrderOfProximity(m_sceneList, scene);
+ foreach (Scene currScene in proximitySceneList)
+ model.RollbackRegion(currScene);
+
+ if ((m_state & State.DIRTY) != 0)
+ {
+ model.DeleteAllMetaObjects();
+ foreach (Scene currScene in proximitySceneList)
+ model.UpdateCMEntities(currScene);
+ }
+
+ if ((m_state & State.SHOWING_CHANGES) > 0)
+ view.DisplayRecentChanges();
+ }
+
+ #endregion Protected Methods
+
+ #region Public Methods
+
+ ///
+ /// Register a new scene object to keep track of for revisioning. Starts the controller monitoring actions of clients within the given scene.
+ ///
+ ///
+ /// A
+ ///
+ public void RegisterNewRegion(Scene scene)
+ {
+ m_sceneList.Add(scene.RegionInfo.RegionID, scene);
+
+ m_log.Debug("[CONTENT MANAGEMENT] Registering new region: " + scene.RegionInfo.RegionID);
+ m_log.Debug("[CONTENT MANAGEMENT] Initializing Content Management System.");
+
+ scene.EventManager.OnNewClient += StartManaging;
+ scene.EventManager.OnChatFromClient += SimChatSent;
+ scene.EventManager.OnRemovePresence += StopManaging;
+ // scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
+ scene.EventManager.OnObjectBeingRemovedFromScene += GroupBeingDeleted;
+ }
+
+ ///
+ /// Only called by the MainLoop. Takes the message from a user sent to the channel and executes the proper command.
+ ///
+ public void SimChat(CMModel model, CMView view, OSChatMessage e, int channel)
+ {
+ if (e.Channel != channel)
+ return;
+ if (e.Sender == null)
+ return;
+
+ m_log.Debug("[CONTENT MANAGEMENT] Message received: " + e.Message);
+
+ IClientAPI client = e.Sender;
+ Scene scene = (Scene) e.Scene;
+ string message = e.Message;
+ string[] args = e.Message.Split(new char[] {' '});
+
+ ScenePresence avatar = scene.GetScenePresence(client.AgentId);
+
+ if (!(m_estateModule.IsManager(avatar.UUID)))
+ {
+ m_log.Debug("[CONTENT MANAGEMENT] Message sent from non Estate Manager ... ignoring.");
+ view.SendSimChatMessage(scene, "You must be an estate manager to perform that action.");
+ return;
+ }
+
+ switch (args[0])
+ {
+ case "ci":
+ case "commit":
+ commit(message, scene, model, view);
+ break;
+ case "dm":
+ case "diff-mode":
+ diffmode(scene, model, view);
+ break;
+ case "rb":
+ case "rollback":
+ rollback(scene, model, view);
+ break;
+ case "help":
+ m_view.DisplayHelpMenu(scene);
+ break;
+ default:
+ view.SendSimChatMessage(scene, "Command not found: " + args[0]);
+ break;
+ }
+ }
+
+ #endregion Public Methods
+
+ #region Other
+
+ ///
+ /// 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.
+ ///
+ [Flags]
+ private enum State
+ {
+ NONE = 0,
+ DIRTY = 1, // The meta entities may not correctly represent the last revision.
+ SHOWING_CHANGES = 1<<1 // The meta entities are being shown to user.
+ }
+
+ ///
+ /// The structure that defines the basic unit of work which is produced when a user sends commands to the ContentMangaementSystem.
+ ///
+ private struct Work
+ {
+ #region Fields
+
+ public Object Data1; //Just space for holding data.
+ public Object Data2; //Just more space for holding data.
+ public uint LocalId; //Convenient
+ public WorkType Type;
+ public UUID UUID; //Convenient
+
+ #endregion Fields
+ }
+
+ ///
+ /// Identifies what the data in struct Work should be used for.
+ ///
+ private enum WorkType
+ {
+ NONE,
+ OBJECTATTRIBUTECHANGE,
+ PRIMITIVEADDED,
+ OBJECTDUPLICATED,
+ OBJECTKILLED,
+ UNDODID,
+ NEWCLIENT,
+ SIMCHAT
+ }
+
+ #endregion Other
+ }
+}
--
cgit v1.1