CMModel.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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. SceneObjectPart[] parts = group.Parts;
  142. for (int i = 0; i < parts.Length; i++)
  143. {
  144. if (m_MetaEntityCollection.Auras.ContainsKey(parts[i].UUID))
  145. m_MetaEntityCollection.RemoveNewlyCreatedEntityAura(parts[i].UUID);
  146. }
  147. }
  148. /// <summary>
  149. /// Retrieves the latest revision of a region in xml form,
  150. /// converts it to scene object groups and scene presences,
  151. /// swaps the current scene's entity list with the revision's list.
  152. /// Note: Since deleted objects while
  153. /// </summary>
  154. public void RollbackRegion(Scene scene)
  155. {
  156. System.Collections.ArrayList xmllist = null;
  157. SceneObjectGroup temp = null;
  158. System.Collections.Hashtable deleteListUUIDs = new Hashtable();
  159. // Dictionary<LLUUID, EntityBase> SearchList = new Dictionary<LLUUID,EntityBase>();
  160. Dictionary<UUID, EntityBase> ReplacementList = new Dictionary<UUID,EntityBase>();
  161. int revision = m_database.GetMostRecentRevision(scene.RegionInfo.RegionID);
  162. // EntityBase[] searchArray;
  163. xmllist = m_database.GetRegionObjectXMLList(scene.RegionInfo.RegionID, revision);
  164. if (xmllist == null)
  165. {
  166. m_log.Info("[CMMODEL]: Region (" + scene.RegionInfo.RegionID + ") does not have given revision number (" + revision + ").");
  167. return;
  168. }
  169. m_log.Info("[CMMODEL]: Region (" + scene.RegionInfo.RegionID + ") revision number (" + revision + ").");
  170. m_log.Info("[CMMODEL]: Scene Objects = " + xmllist.Count);
  171. m_log.Info("[CMMODEL]: Converting scene entities list to specified revision.");
  172. m_log.ErrorFormat("[CMMODEL]: 1");
  173. foreach (string xml in xmllist)
  174. {
  175. try
  176. {
  177. temp = SceneObjectSerializer.FromXml2Format(xml);
  178. temp.SetScene(scene);
  179. SceneObjectPart[] parts = temp.Parts;
  180. for (int i = 0; i < parts.Length; i++)
  181. parts[i].RegionHandle = scene.RegionInfo.RegionHandle;
  182. ReplacementList.Add(temp.UUID, (EntityBase)temp);
  183. }
  184. catch (Exception e)
  185. {
  186. m_log.Info("[CMMODEL]: Error while creating replacement list for rollback: " + e);
  187. }
  188. }
  189. //If in scene but not in revision and not a client, remove them
  190. while (true)
  191. {
  192. try
  193. {
  194. foreach (EntityBase entity in scene.GetEntities())
  195. {
  196. if (entity == null)
  197. continue;
  198. if (entity is ScenePresence)
  199. {
  200. ReplacementList.Add(entity.UUID, entity);
  201. continue;
  202. }
  203. else //if (!ReplacementList.ContainsKey(entity.UUID))
  204. deleteListUUIDs.Add(entity.UUID, 0);
  205. }
  206. }
  207. catch(Exception e)
  208. {
  209. m_log.ErrorFormat("[CMMODEL]: " + e);
  210. deleteListUUIDs.Clear();
  211. ReplacementList.Clear();
  212. continue;
  213. }
  214. break;
  215. }
  216. foreach (UUID uuid in deleteListUUIDs.Keys)
  217. {
  218. try
  219. {
  220. // I thought that the DeleteGroup() function would handle all of this, but it doesn't. I'm not sure WHAT it handles.
  221. ((SceneObjectGroup)scene.Entities[uuid]).DetachFromBackup();
  222. scene.PhysicsScene.RemovePrim(((SceneObjectGroup)scene.Entities[uuid]).RootPart.PhysActor);
  223. scene.SendKillObject(scene.Entities[uuid].LocalId);
  224. scene.SceneGraph.DeleteSceneObject(uuid, false);
  225. ((SceneObjectGroup)scene.Entities[uuid]).DeleteGroupFromScene(false);
  226. }
  227. catch(Exception e)
  228. {
  229. m_log.ErrorFormat("[CMMODEL]: Error while removing objects from scene: " + e);
  230. }
  231. }
  232. lock (scene)
  233. {
  234. scene.Entities.Clear();
  235. foreach (KeyValuePair<UUID,EntityBase> kvp in ReplacementList)
  236. {
  237. scene.Entities.Add(kvp.Value);
  238. }
  239. }
  240. foreach (EntityBase ent in ReplacementList.Values)
  241. {
  242. try
  243. {
  244. if (!(ent is SceneObjectGroup))
  245. continue;
  246. if ((((SceneObjectGroup)ent).RootPart.GetEffectiveObjectFlags() & (uint) PrimFlags.Phantom) == 0)
  247. ((SceneObjectGroup)ent).ApplyPhysics(true);
  248. ((SceneObjectGroup)ent).AttachToBackup();
  249. ((SceneObjectGroup)ent).HasGroupChanged = true; // If not true, then attaching to backup does nothing because no change is detected.
  250. ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate();
  251. }
  252. catch(Exception e)
  253. {
  254. m_log.ErrorFormat("[CMMODEL]: Error while attaching new scene entities to backup and scheduling for a full update: " + e);
  255. }
  256. }
  257. m_log.Info("[CMMODEL]: Scheduling a backup of new scene object groups to backup.");
  258. scene.Backup(true);
  259. }
  260. /// <summary>
  261. /// Downloads the latest revision of the given scene and converts the xml file to CMEntities. After this method, the view can find the differences
  262. /// and display the differences to clients.
  263. /// </summary>
  264. public void UpdateCMEntities(Scene scene)
  265. {
  266. Stopwatch x = new Stopwatch();
  267. x.Start();
  268. System.Collections.ArrayList xmllist = null;
  269. m_log.Debug("[CONTENT MANAGEMENT] Retrieving object xml files for region: " + scene.RegionInfo.RegionID);
  270. xmllist = m_database.GetRegionObjectXMLList(scene.RegionInfo.RegionID);
  271. m_log.Info("[FSDB]: got list");
  272. if (xmllist == null)
  273. return;
  274. Stopwatch y = new Stopwatch();
  275. y.Start();
  276. foreach (string xml in xmllist)
  277. m_MetaEntityCollection.CreateNewEntity(xml, scene);
  278. y.Stop();
  279. TimeToConvertXml += y.ElapsedMilliseconds;
  280. m_log.Info("[FileSystemDatabase] Time spent converting xml to metaentities for " + scene.RegionInfo.RegionName + ": " + y.ElapsedMilliseconds);
  281. m_log.Info("[FileSystemDatabase] Time spent converting xml to metaentities so far: " + TimeToConvertXml);
  282. m_log.Info("[FSDB]: checking for new scene object parts missing green auras and create the auras");
  283. CheckForNewEntitiesMissingAuras(scene);
  284. x.Stop();
  285. TimeToUpdate += x.ElapsedMilliseconds;
  286. m_log.Info("[FileSystemDatabase] Time spent Updating entity list for " + scene.RegionInfo.RegionName + ": " + x.ElapsedMilliseconds);
  287. m_log.Info("[FileSystemDatabase] Time spent Updating so far: " + TimeToUpdate);
  288. }
  289. /// <summary>
  290. /// Detects if a scene object group from the scene list has moved or changed scale. The green aura
  291. /// that surrounds the object is then moved or scaled with the group.
  292. /// </summary>
  293. public System.Collections.ArrayList UpdateNormalEntityEffects(SceneObjectGroup group)
  294. {
  295. System.Collections.ArrayList auraList = new System.Collections.ArrayList();
  296. if (group == null)
  297. return null;
  298. SceneObjectPart[] parts = group.Parts;
  299. for (int i = 0; i < parts.Length; i++)
  300. {
  301. SceneObjectPart part = parts[i];
  302. if (m_MetaEntityCollection.Auras.ContainsKey(part.UUID))
  303. {
  304. ((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]).SetAura(new Vector3(0, 254, 0), part.Scale);
  305. ((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]).RootPart.GroupPosition = part.GetWorldPosition();
  306. auraList.Add((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]);
  307. }
  308. }
  309. return auraList;
  310. }
  311. #endregion Public Methods
  312. }
  313. }