CMModel.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.Diagnostics;
  31. using OpenMetaverse;
  32. using OpenSim;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.Framework.Interfaces;
  35. using OpenSim.Region.Framework.Scenes;
  36. using OpenSim.Region.Framework.Scenes.Serialization;
  37. using OpenSim.Region.Physics.Manager;
  38. using log4net;
  39. namespace OpenSim.Region.OptionalModules.ContentManagement
  40. {
  41. public class CMModel
  42. {
  43. #region Static Fields
  44. static float TimeToUpdate = 0;
  45. static float TimeToConvertXml = 0;
  46. private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  47. #endregion Static Fields
  48. #region Fields
  49. /// <value>
  50. /// The class that contains all auras and metaentities used in the CMS.
  51. /// </value>
  52. CMEntityCollection m_MetaEntityCollection = new CMEntityCollection();
  53. IContentDatabase m_database = null;
  54. #endregion Fields
  55. #region Constructors
  56. public CMModel()
  57. {
  58. }
  59. #endregion Constructors
  60. #region Public Properties
  61. public CMEntityCollection MetaEntityCollection
  62. {
  63. get { return m_MetaEntityCollection; }
  64. }
  65. #endregion Public Properties
  66. #region Public Methods
  67. /// <summary>
  68. /// Compares the scene's object group list to the list of meta entities. If there is an object group that does not have a corresponding meta entity
  69. /// it is a new part that must have a green aura (for diff mode).
  70. /// Returns list of ContentManagementEntities
  71. /// </summary>
  72. public ArrayList CheckForNewEntitiesMissingAuras(Scene scene)
  73. {
  74. ArrayList missingList = null;
  75. ArrayList newList = new ArrayList();
  76. m_log.Debug("[CONTENT MANAGEMENT] Checking for new scene object parts in scene: " + scene.RegionInfo.RegionName);
  77. //Check if the current scene has groups not included in the current list of MetaEntities
  78. //If so, then the current scene's parts that are new should be marked green.
  79. missingList = m_MetaEntityCollection.CheckForMissingEntities(scene.GetEntities());
  80. foreach (Object missingPart in missingList)
  81. {
  82. if (m_MetaEntityCollection.Auras.ContainsKey(((SceneObjectPart)missingPart).UUID))
  83. continue;
  84. newList.Add(m_MetaEntityCollection.CreateAuraForNewlyCreatedEntity((SceneObjectPart)missingPart));
  85. }
  86. m_log.Info("Number of missing objects found: " + newList.Count);
  87. return newList;
  88. }
  89. /// <summary>
  90. /// Uses the database to serialize all current scene objects into xml and save into a database with an accompanying log message.
  91. /// </summary>
  92. public void CommitRegion(Scene scene, String logMessage)
  93. {
  94. m_log.Debug("[CONTENT MANAG] saving " + scene.RegionInfo.RegionName + " with log message: " + logMessage + " length of message: " + logMessage.Length);
  95. m_database.SaveRegion(scene.RegionInfo.RegionID, scene.RegionInfo.RegionName, logMessage);
  96. m_log.Debug("[CONTENT MANAG] the region name we are dealing with heeeeeeeere: " + scene.RegionInfo.RegionName);
  97. }
  98. public void DeleteAllMetaObjects()
  99. {
  100. m_MetaEntityCollection.ClearAll();
  101. }
  102. public ContentManagementEntity FindMetaEntityAffectedByUndo(UUID uuid)
  103. {
  104. ContentManagementEntity ent = GetMetaGroupByPrim(uuid);
  105. return ent;
  106. }
  107. //-------------------------------- HELPERS --------------------------------------------------------------------//
  108. public ContentManagementEntity GetMetaGroupByPrim(UUID uuid)
  109. {
  110. foreach (Object ent in m_MetaEntityCollection.Entities.Values)
  111. {
  112. if (((ContentManagementEntity)ent).HasChildPrim(uuid))
  113. return (ContentManagementEntity)ent;
  114. }
  115. return null;
  116. }
  117. public void Initialise(string database)
  118. {
  119. if (database == "FileSystemDatabase")
  120. m_database = new FileSystemDatabase();
  121. else if (database == "GitDatabase")
  122. m_database = new GitDatabase();
  123. }
  124. public void InitialiseDatabase(Scene scene, string dir)
  125. {
  126. m_database.Initialise(scene, dir);
  127. }
  128. /// <summary>
  129. /// Should be called just once to finish initializing the database.
  130. /// </summary>
  131. public void PostInitialise()
  132. {
  133. m_database.PostInitialise();
  134. }
  135. /// <summary>
  136. /// Removes the green aura when an a new scene object group is deleted.
  137. /// </summary>
  138. public void RemoveOrUpdateDeletedEntity(SceneObjectGroup group)
  139. {
  140. // Deal with new parts not revisioned that have been deleted.
  141. foreach (SceneObjectPart part in group.Children.Values)
  142. if (m_MetaEntityCollection.Auras.ContainsKey(part.UUID))
  143. m_MetaEntityCollection.RemoveNewlyCreatedEntityAura(part.UUID);
  144. }
  145. /// <summary>
  146. /// Retrieves the latest revision of a region in xml form,
  147. /// converts it to scene object groups and scene presences,
  148. /// swaps the current scene's entity list with the revision's list.
  149. /// Note: Since deleted objects while
  150. /// </summary>
  151. public void RollbackRegion(Scene scene)
  152. {
  153. System.Collections.ArrayList xmllist = null;
  154. SceneObjectGroup temp = null;
  155. System.Collections.Hashtable deleteListUUIDs = new Hashtable();
  156. // Dictionary<LLUUID, EntityBase> SearchList = new Dictionary<LLUUID,EntityBase>();
  157. Dictionary<UUID, EntityBase> ReplacementList = new Dictionary<UUID,EntityBase>();
  158. int revision = m_database.GetMostRecentRevision(scene.RegionInfo.RegionID);
  159. // EntityBase[] searchArray;
  160. xmllist = m_database.GetRegionObjectXMLList(scene.RegionInfo.RegionID, revision);
  161. if (xmllist == null)
  162. {
  163. m_log.Info("[CMMODEL]: Region (" + scene.RegionInfo.RegionID + ") does not have given revision number (" + revision + ").");
  164. return;
  165. }
  166. m_log.Info("[CMMODEL]: Region (" + scene.RegionInfo.RegionID + ") revision number (" + revision + ").");
  167. m_log.Info("[CMMODEL]: Scene Objects = " + xmllist.Count);
  168. m_log.Info("[CMMODEL]: Converting scene entities list to specified revision.");
  169. m_log.ErrorFormat("[CMMODEL]: 1");
  170. foreach (string xml in xmllist)
  171. {
  172. try
  173. {
  174. temp = SceneObjectSerializer.FromXml2Format(xml);
  175. temp.SetScene(scene);
  176. foreach (SceneObjectPart part in temp.Children.Values)
  177. part.RegionHandle = scene.RegionInfo.RegionHandle;
  178. ReplacementList.Add(temp.UUID, (EntityBase)temp);
  179. }
  180. catch (Exception e)
  181. {
  182. m_log.Info("[CMMODEL]: Error while creating replacement list for rollback: " + e);
  183. }
  184. }
  185. //If in scene but not in revision and not a client, remove them
  186. while (true)
  187. {
  188. try
  189. {
  190. foreach (EntityBase entity in scene.GetEntities())
  191. {
  192. if (entity == null)
  193. continue;
  194. if (entity is ScenePresence)
  195. {
  196. ReplacementList.Add(entity.UUID, entity);
  197. continue;
  198. }
  199. else //if (!ReplacementList.ContainsKey(entity.UUID))
  200. deleteListUUIDs.Add(entity.UUID, 0);
  201. }
  202. }
  203. catch(Exception e)
  204. {
  205. m_log.ErrorFormat("[CMMODEL]: " + e);
  206. deleteListUUIDs.Clear();
  207. ReplacementList.Clear();
  208. continue;
  209. }
  210. break;
  211. }
  212. foreach (UUID uuid in deleteListUUIDs.Keys)
  213. {
  214. try
  215. {
  216. // I thought that the DeleteGroup() function would handle all of this, but it doesn't. I'm not sure WHAT it handles.
  217. ((SceneObjectGroup)scene.Entities[uuid]).DetachFromBackup();
  218. scene.PhysicsScene.RemovePrim(((SceneObjectGroup)scene.Entities[uuid]).RootPart.PhysActor);
  219. scene.SendKillObject(scene.Entities[uuid].LocalId);
  220. scene.SceneGraph.DeleteSceneObject(uuid, false);
  221. ((SceneObjectGroup)scene.Entities[uuid]).DeleteGroup(false);
  222. }
  223. catch(Exception e)
  224. {
  225. m_log.ErrorFormat("[CMMODEL]: Error while removing objects from scene: " + e);
  226. }
  227. }
  228. lock (scene)
  229. {
  230. scene.Entities.Clear();
  231. foreach (KeyValuePair<UUID,EntityBase> kvp in ReplacementList)
  232. {
  233. scene.Entities.Add(kvp.Value);
  234. }
  235. }
  236. foreach (EntityBase ent in ReplacementList.Values)
  237. {
  238. try
  239. {
  240. if (!(ent is SceneObjectGroup))
  241. continue;
  242. if ((((SceneObjectGroup)ent).RootPart.GetEffectiveObjectFlags() & (uint) PrimFlags.Phantom) == 0)
  243. ((SceneObjectGroup)ent).ApplyPhysics(true);
  244. ((SceneObjectGroup)ent).AttachToBackup();
  245. ((SceneObjectGroup)ent).HasGroupChanged = true; // If not true, then attaching to backup does nothing because no change is detected.
  246. ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate();
  247. }
  248. catch(Exception e)
  249. {
  250. m_log.ErrorFormat("[CMMODEL]: Error while attaching new scene entities to backup and scheduling for a full update: " + e);
  251. }
  252. }
  253. m_log.Info("[CMMODEL]: Scheduling a backup of new scene object groups to backup.");
  254. scene.Backup();
  255. }
  256. /// <summary>
  257. /// Downloads the latest revision of the given scene and converts the xml file to CMEntities. After this method, the view can find the differences
  258. /// and display the differences to clients.
  259. /// </summary>
  260. public void UpdateCMEntities(Scene scene)
  261. {
  262. Stopwatch x = new Stopwatch();
  263. x.Start();
  264. System.Collections.ArrayList xmllist = null;
  265. m_log.Debug("[CONTENT MANAGEMENT] Retrieving object xml files for region: " + scene.RegionInfo.RegionID);
  266. xmllist = m_database.GetRegionObjectXMLList(scene.RegionInfo.RegionID);
  267. m_log.Info("[FSDB]: got list");
  268. if (xmllist == null)
  269. return;
  270. Stopwatch y = new Stopwatch();
  271. y.Start();
  272. foreach (string xml in xmllist)
  273. m_MetaEntityCollection.CreateNewEntity(xml, scene);
  274. y.Stop();
  275. TimeToConvertXml += y.ElapsedMilliseconds;
  276. m_log.Info("[FileSystemDatabase] Time spent converting xml to metaentities for " + scene.RegionInfo.RegionName + ": " + y.ElapsedMilliseconds);
  277. m_log.Info("[FileSystemDatabase] Time spent converting xml to metaentities so far: " + TimeToConvertXml);
  278. m_log.Info("[FSDB]: checking for new scene object parts missing green auras and create the auras");
  279. CheckForNewEntitiesMissingAuras(scene);
  280. x.Stop();
  281. TimeToUpdate += x.ElapsedMilliseconds;
  282. m_log.Info("[FileSystemDatabase] Time spent Updating entity list for " + scene.RegionInfo.RegionName + ": " + x.ElapsedMilliseconds);
  283. m_log.Info("[FileSystemDatabase] Time spent Updating so far: " + TimeToUpdate);
  284. }
  285. /// <summary>
  286. /// Detects if a scene object group from the scene list has moved or changed scale. The green aura
  287. /// that surrounds the object is then moved or scaled with the group.
  288. /// </summary>
  289. public System.Collections.ArrayList UpdateNormalEntityEffects(SceneObjectGroup group)
  290. {
  291. System.Collections.ArrayList auraList = new System.Collections.ArrayList();
  292. if (group == null)
  293. return null;
  294. foreach (SceneObjectPart part in group.Children.Values)
  295. {
  296. if (m_MetaEntityCollection.Auras.ContainsKey(part.UUID))
  297. {
  298. ((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]).SetAura(new Vector3(0,254,0), part.Scale);
  299. ((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]).RootPart.GroupPosition = part.GetWorldPosition();
  300. auraList.Add((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]);
  301. }
  302. }
  303. return auraList;
  304. }
  305. #endregion Public Methods
  306. }
  307. }