opensim – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | eva | 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 | |||
28 | using System; |
||
29 | using System.Collections.Generic; |
||
30 | using System.IO; |
||
31 | using System.IO.Compression; |
||
32 | using System.Net; |
||
33 | using System.Reflection; |
||
34 | using System.Text; |
||
35 | using System.Xml; |
||
36 | using log4net; |
||
37 | using OpenMetaverse; |
||
38 | using OpenSim.Framework; |
||
39 | using OpenSim.Framework.Serialization; |
||
40 | using OpenSim.Framework.Serialization.External; |
||
41 | using OpenSim.Region.CoreModules.World.Terrain; |
||
42 | using OpenSim.Region.Framework.Interfaces; |
||
43 | using OpenSim.Region.Framework.Scenes; |
||
44 | using OpenSim.Region.Framework.Scenes.Serialization; |
||
45 | using OpenSim.Services.Interfaces; |
||
46 | using System.Threading; |
||
47 | |||
48 | namespace OpenSim.Region.CoreModules.World.Archiver |
||
49 | { |
||
50 | /// <summary> |
||
51 | /// Handles an individual archive read request |
||
52 | /// </summary> |
||
53 | public class ArchiveReadRequest |
||
54 | { |
||
55 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
56 | |||
57 | /// <summary> |
||
58 | /// Contains data used while dearchiving a single scene. |
||
59 | /// </summary> |
||
60 | private class DearchiveContext |
||
61 | { |
||
62 | public Scene Scene { get; set; } |
||
63 | |||
64 | public List<string> SerialisedSceneObjects { get; set; } |
||
65 | |||
66 | public List<string> SerialisedParcels { get; set; } |
||
67 | |||
68 | public List<SceneObjectGroup> SceneObjects { get; set; } |
||
69 | |||
70 | public DearchiveContext(Scene scene) |
||
71 | { |
||
72 | Scene = scene; |
||
73 | SerialisedSceneObjects = new List<string>(); |
||
74 | SerialisedParcels = new List<string>(); |
||
75 | SceneObjects = new List<SceneObjectGroup>(); |
||
76 | } |
||
77 | } |
||
78 | |||
79 | |||
80 | /// <summary> |
||
81 | /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version |
||
82 | /// bumps here should be compatible. |
||
83 | /// </summary> |
||
84 | public static int MAX_MAJOR_VERSION = 1; |
||
85 | |||
86 | /// <summary> |
||
87 | /// Has the control file been loaded for this archive? |
||
88 | /// </summary> |
||
89 | public bool ControlFileLoaded { get; private set; } |
||
90 | |||
91 | protected string m_loadPath; |
||
92 | protected Scene m_rootScene; |
||
93 | protected Stream m_loadStream; |
||
94 | protected Guid m_requestId; |
||
95 | protected string m_errorMessage; |
||
96 | |||
97 | /// <value> |
||
98 | /// Should the archive being loaded be merged with what is already on the region? |
||
99 | /// Merging usually suppresses terrain and parcel loading |
||
100 | /// </value> |
||
101 | protected bool m_merge; |
||
102 | |||
103 | /// <value> |
||
104 | /// If true, force the loading of terrain from the oar file |
||
105 | /// </value> |
||
106 | protected bool m_forceTerrain; |
||
107 | |||
108 | /// <value> |
||
109 | /// If true, force the loading of parcels from the oar file |
||
110 | /// </value> |
||
111 | protected bool m_forceParcels; |
||
112 | |||
113 | /// <value> |
||
114 | /// Should we ignore any assets when reloading the archive? |
||
115 | /// </value> |
||
116 | protected bool m_skipAssets; |
||
117 | |||
118 | /// <value> |
||
119 | /// Displacement added to each object as it is added to the world |
||
120 | /// </value> |
||
121 | protected Vector3 m_displacement = Vector3.Zero; |
||
122 | |||
123 | /// <value> |
||
124 | /// Rotation (in radians) to apply to the objects as they are loaded. |
||
125 | /// </value> |
||
126 | protected float m_rotation = 0f; |
||
127 | |||
128 | /// <value> |
||
129 | /// Center around which to apply the rotation relative to the origional oar position |
||
130 | /// </value> |
||
131 | protected Vector3 m_rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f); |
||
132 | |||
133 | protected bool m_noObjects = false; |
||
134 | |||
135 | /// <summary> |
||
136 | /// Used to cache lookups for valid uuids. |
||
137 | /// </summary> |
||
138 | private IDictionary<UUID, bool> m_validUserUuids = new Dictionary<UUID, bool>(); |
||
139 | |||
140 | private IUserManagement m_UserMan; |
||
141 | private IUserManagement UserManager |
||
142 | { |
||
143 | get |
||
144 | { |
||
145 | if (m_UserMan == null) |
||
146 | { |
||
147 | m_UserMan = m_rootScene.RequestModuleInterface<IUserManagement>(); |
||
148 | } |
||
149 | return m_UserMan; |
||
150 | } |
||
151 | } |
||
152 | |||
153 | /// <summary> |
||
154 | /// Used to cache lookups for valid groups. |
||
155 | /// </summary> |
||
156 | private IDictionary<UUID, bool> m_validGroupUuids = new Dictionary<UUID, bool>(); |
||
157 | |||
158 | private IGroupsModule m_groupsModule; |
||
159 | |||
160 | private IAssetService m_assetService = null; |
||
161 | |||
162 | |||
163 | public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary<string,object>options) |
||
164 | { |
||
165 | m_rootScene = scene; |
||
166 | |||
167 | m_loadPath = loadPath; |
||
168 | try |
||
169 | { |
||
170 | m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress); |
||
171 | } |
||
172 | catch (EntryPointNotFoundException e) |
||
173 | { |
||
174 | m_log.ErrorFormat( |
||
175 | "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." |
||
176 | + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); |
||
177 | m_log.Error(e); |
||
178 | } |
||
179 | |||
180 | m_errorMessage = String.Empty; |
||
181 | m_merge = options.ContainsKey("merge"); |
||
182 | m_forceTerrain = options.ContainsKey("force-terrain"); |
||
183 | m_forceParcels = options.ContainsKey("force-parcels"); |
||
184 | m_noObjects = options.ContainsKey("no-objects"); |
||
185 | m_skipAssets = options.ContainsKey("skipAssets"); |
||
186 | m_requestId = requestId; |
||
187 | m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero; |
||
188 | m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f; |
||
189 | m_rotationCenter = options.ContainsKey("rotation-center") ? (Vector3)options["rotation-center"] |
||
190 | : new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 0f); |
||
191 | |||
192 | // Zero can never be a valid user id |
||
193 | m_validUserUuids[UUID.Zero] = false; |
||
194 | |||
195 | m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); |
||
196 | m_assetService = m_rootScene.AssetService; |
||
197 | } |
||
198 | |||
199 | public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary<string, object>options) |
||
200 | { |
||
201 | m_rootScene = scene; |
||
202 | m_loadPath = null; |
||
203 | m_loadStream = loadStream; |
||
204 | m_skipAssets = options.ContainsKey("skipAssets"); |
||
205 | m_merge = options.ContainsKey("merge"); |
||
206 | m_requestId = requestId; |
||
207 | |||
208 | // Zero can never be a valid user id |
||
209 | m_validUserUuids[UUID.Zero] = false; |
||
210 | |||
211 | m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); |
||
212 | m_assetService = m_rootScene.AssetService; |
||
213 | } |
||
214 | |||
215 | /// <summary> |
||
216 | /// Dearchive the region embodied in this request. |
||
217 | /// </summary> |
||
218 | public void DearchiveRegion() |
||
219 | { |
||
220 | int successfulAssetRestores = 0; |
||
221 | int failedAssetRestores = 0; |
||
222 | |||
223 | DearchiveScenesInfo dearchivedScenes; |
||
224 | |||
225 | // We dearchive all the scenes at once, because the files in the TAR archive might be mixed. |
||
226 | // Therefore, we have to keep track of the dearchive context of all the scenes. |
||
227 | Dictionary<UUID, DearchiveContext> sceneContexts = new Dictionary<UUID, DearchiveContext>(); |
||
228 | |||
229 | string fullPath = "NONE"; |
||
230 | TarArchiveReader archive = null; |
||
231 | byte[] data; |
||
232 | TarArchiveReader.TarEntryType entryType; |
||
233 | |||
234 | try |
||
235 | { |
||
236 | FindAndLoadControlFile(out archive, out dearchivedScenes); |
||
237 | |||
238 | while ((data = archive.ReadEntry(out fullPath, out entryType)) != null) |
||
239 | { |
||
240 | //m_log.DebugFormat( |
||
241 | // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length); |
||
242 | |||
243 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) |
||
244 | continue; |
||
245 | |||
246 | |||
247 | // Find the scene that this file belongs to |
||
248 | |||
249 | Scene scene; |
||
250 | string filePath; |
||
251 | if (!dearchivedScenes.GetRegionFromPath(fullPath, out scene, out filePath)) |
||
252 | continue; // this file belongs to a region that we're not loading |
||
253 | |||
254 | DearchiveContext sceneContext = null; |
||
255 | if (scene != null) |
||
256 | { |
||
257 | if (!sceneContexts.TryGetValue(scene.RegionInfo.RegionID, out sceneContext)) |
||
258 | { |
||
259 | sceneContext = new DearchiveContext(scene); |
||
260 | sceneContexts.Add(scene.RegionInfo.RegionID, sceneContext); |
||
261 | } |
||
262 | } |
||
263 | |||
264 | |||
265 | // Process the file |
||
266 | |||
267 | if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH) && !m_noObjects) |
||
268 | { |
||
269 | sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); |
||
270 | } |
||
271 | else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets) |
||
272 | { |
||
273 | if (LoadAsset(filePath, data)) |
||
274 | successfulAssetRestores++; |
||
275 | else |
||
276 | failedAssetRestores++; |
||
277 | |||
278 | if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) |
||
279 | m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); |
||
280 | } |
||
281 | else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH) && (!m_merge || m_forceTerrain)) |
||
282 | { |
||
283 | LoadTerrain(scene, filePath, data); |
||
284 | } |
||
285 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) |
||
286 | { |
||
287 | LoadRegionSettings(scene, filePath, data, dearchivedScenes); |
||
288 | } |
||
289 | else if (filePath.StartsWith(ArchiveConstants.LANDDATA_PATH) && (!m_merge || m_forceParcels)) |
||
290 | { |
||
291 | sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); |
||
292 | } |
||
293 | else if (filePath == ArchiveConstants.CONTROL_FILE_PATH) |
||
294 | { |
||
295 | // Ignore, because we already read the control file |
||
296 | } |
||
297 | } |
||
298 | |||
299 | //m_log.Debug("[ARCHIVER]: Reached end of archive"); |
||
300 | } |
||
301 | catch (Exception e) |
||
302 | { |
||
303 | m_log.Error( |
||
304 | String.Format("[ARCHIVER]: Aborting load with error in archive file {0} ", fullPath), e); |
||
305 | m_errorMessage += e.ToString(); |
||
306 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage); |
||
307 | return; |
||
308 | } |
||
309 | finally |
||
310 | { |
||
311 | if (archive != null) |
||
312 | archive.Close(); |
||
313 | } |
||
314 | |||
315 | if (!m_skipAssets) |
||
316 | { |
||
317 | m_log.InfoFormat("[ARCHIVER]: Restored {0} assets", successfulAssetRestores); |
||
318 | |||
319 | if (failedAssetRestores > 0) |
||
320 | { |
||
321 | m_log.ErrorFormat("[ARCHIVER]: Failed to load {0} assets", failedAssetRestores); |
||
322 | m_errorMessage += String.Format("Failed to load {0} assets", failedAssetRestores); |
||
323 | } |
||
324 | } |
||
325 | |||
326 | foreach (DearchiveContext sceneContext in sceneContexts.Values) |
||
327 | { |
||
328 | m_log.InfoFormat("[ARCHIVER]: Loading region {0}", sceneContext.Scene.RegionInfo.RegionName); |
||
329 | |||
330 | if (!m_merge) |
||
331 | { |
||
332 | m_log.Info("[ARCHIVER]: Clearing all existing scene objects"); |
||
333 | sceneContext.Scene.DeleteAllSceneObjects(); |
||
334 | } |
||
335 | |||
336 | try |
||
337 | { |
||
338 | LoadParcels(sceneContext.Scene, sceneContext.SerialisedParcels); |
||
339 | LoadObjects(sceneContext.Scene, sceneContext.SerialisedSceneObjects, sceneContext.SceneObjects); |
||
340 | |||
341 | // Inform any interested parties that the region has changed. We waited until now so that all |
||
342 | // of the region's objects will be loaded when we send this notification. |
||
343 | IEstateModule estateModule = sceneContext.Scene.RequestModuleInterface<IEstateModule>(); |
||
344 | if (estateModule != null) |
||
345 | estateModule.TriggerRegionInfoChange(); |
||
346 | } |
||
347 | catch (Exception e) |
||
348 | { |
||
349 | m_log.Error("[ARCHIVER]: Error loading parcels or objects ", e); |
||
350 | m_errorMessage += e.ToString(); |
||
351 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage); |
||
352 | return; |
||
353 | } |
||
354 | } |
||
355 | |||
356 | // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so |
||
357 | // that users can enter the scene. If we allow the scripts to start in the loop above |
||
358 | // then they significantly increase the time until the OAR finishes loading. |
||
359 | Util.FireAndForget(delegate(object o) |
||
360 | { |
||
361 | Thread.Sleep(15000); |
||
362 | m_log.Info("[ARCHIVER]: Starting scripts in scene objects"); |
||
363 | |||
364 | foreach (DearchiveContext sceneContext in sceneContexts.Values) |
||
365 | { |
||
366 | foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects) |
||
367 | { |
||
368 | sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart |
||
369 | sceneObject.ResumeScripts(); |
||
370 | } |
||
371 | |||
372 | sceneContext.SceneObjects.Clear(); |
||
373 | } |
||
374 | }); |
||
375 | |||
376 | m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); |
||
377 | |||
378 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, dearchivedScenes.GetLoadedScenes(), m_errorMessage); |
||
379 | } |
||
380 | |||
381 | /// <summary> |
||
382 | /// Searches through the files in the archive for the control file, and reads it. |
||
383 | /// We must read the control file first, in order to know which regions are available. |
||
384 | /// </summary> |
||
385 | /// <remarks> |
||
386 | /// In most cases the control file *is* first, since that's how we create archives. However, |
||
387 | /// it's possible that someone rewrote the archive externally so we can't rely on this fact. |
||
388 | /// </remarks> |
||
389 | /// <param name="archive"></param> |
||
390 | /// <param name="dearchivedScenes"></param> |
||
391 | private void FindAndLoadControlFile(out TarArchiveReader archive, out DearchiveScenesInfo dearchivedScenes) |
||
392 | { |
||
393 | archive = new TarArchiveReader(m_loadStream); |
||
394 | dearchivedScenes = new DearchiveScenesInfo(); |
||
395 | |||
396 | string filePath; |
||
397 | byte[] data; |
||
398 | TarArchiveReader.TarEntryType entryType; |
||
399 | bool firstFile = true; |
||
400 | |||
401 | while ((data = archive.ReadEntry(out filePath, out entryType)) != null) |
||
402 | { |
||
403 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) |
||
404 | continue; |
||
405 | |||
406 | if (filePath == ArchiveConstants.CONTROL_FILE_PATH) |
||
407 | { |
||
408 | LoadControlFile(filePath, data, dearchivedScenes); |
||
409 | |||
410 | // Find which scenes are available in the simulator |
||
411 | ArchiveScenesGroup simulatorScenes = new ArchiveScenesGroup(); |
||
412 | SceneManager.Instance.ForEachScene(delegate(Scene scene2) |
||
413 | { |
||
414 | simulatorScenes.AddScene(scene2); |
||
415 | }); |
||
416 | simulatorScenes.CalcSceneLocations(); |
||
417 | dearchivedScenes.SetSimulatorScenes(m_rootScene, simulatorScenes); |
||
418 | |||
419 | // If the control file wasn't the first file then reset the read pointer |
||
420 | if (!firstFile) |
||
421 | { |
||
422 | m_log.Warn("Control file wasn't the first file in the archive"); |
||
423 | if (m_loadStream.CanSeek) |
||
424 | { |
||
425 | m_loadStream.Seek(0, SeekOrigin.Begin); |
||
426 | } |
||
427 | else if (m_loadPath != null) |
||
428 | { |
||
429 | archive.Close(); |
||
430 | archive = null; |
||
431 | m_loadStream.Close(); |
||
432 | m_loadStream = null; |
||
433 | m_loadStream = new GZipStream(ArchiveHelpers.GetStream(m_loadPath), CompressionMode.Decompress); |
||
434 | archive = new TarArchiveReader(m_loadStream); |
||
435 | } |
||
436 | else |
||
437 | { |
||
438 | // There isn't currently a scenario where this happens, but it's best to add a check just in case |
||
439 | throw new Exception("Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking"); |
||
440 | } |
||
441 | } |
||
442 | |||
443 | return; |
||
444 | } |
||
445 | |||
446 | firstFile = false; |
||
447 | } |
||
448 | |||
449 | throw new Exception("Control file not found"); |
||
450 | } |
||
451 | |||
452 | /// <summary> |
||
453 | /// Load serialized scene objects. |
||
454 | /// </summary> |
||
455 | protected void LoadObjects(Scene scene, List<string> serialisedSceneObjects, List<SceneObjectGroup> sceneObjects) |
||
456 | { |
||
457 | // Reload serialized prims |
||
458 | m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); |
||
459 | |||
460 | OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, m_rotation); |
||
461 | |||
462 | UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; |
||
463 | |||
464 | IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); |
||
465 | int sceneObjectsLoadedCount = 0; |
||
466 | |||
467 | foreach (string serialisedSceneObject in serialisedSceneObjects) |
||
468 | { |
||
469 | /* |
||
470 | m_log.DebugFormat("[ARCHIVER]: Loading xml with raw size {0}", serialisedSceneObject.Length); |
||
471 | |||
472 | // Really large xml files (multi megabyte) appear to cause |
||
473 | // memory problems |
||
474 | // when loading the xml. But don't enable this check yet |
||
475 | |||
476 | if (serialisedSceneObject.Length > 5000000) |
||
477 | { |
||
478 | m_log.Error("[ARCHIVER]: Ignoring xml since size > 5000000);"); |
||
479 | continue; |
||
480 | } |
||
481 | */ |
||
482 | |||
483 | SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); |
||
484 | |||
485 | // Happily this does not do much to the object since it hasn't been added to the scene yet |
||
486 | if (sceneObject.AttachmentPoint == 0) |
||
487 | { |
||
488 | if (m_displacement != Vector3.Zero || m_rotation != 0f) |
||
489 | { |
||
490 | Vector3 pos = sceneObject.AbsolutePosition; |
||
491 | if (m_rotation != 0f) |
||
492 | { |
||
493 | // Rotate the object |
||
494 | sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; |
||
495 | // Get object position relative to rotation axis |
||
496 | Vector3 offset = pos - m_rotationCenter; |
||
497 | // Rotate the object position |
||
498 | offset *= rot; |
||
499 | // Restore the object position back to relative to the region |
||
500 | pos = m_rotationCenter + offset; |
||
501 | } |
||
502 | if (m_displacement != Vector3.Zero) |
||
503 | { |
||
504 | pos += m_displacement; |
||
505 | } |
||
506 | sceneObject.AbsolutePosition = pos; |
||
507 | } |
||
508 | } |
||
509 | |||
510 | |||
511 | bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); |
||
512 | |||
513 | // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned |
||
514 | // on the same region server and multiple examples a single object archive to be imported |
||
515 | // to the same scene (when this is possible). |
||
516 | sceneObject.ResetIDs(); |
||
517 | |||
518 | if (isTelehub) |
||
519 | { |
||
520 | // Change the Telehub Object to the new UUID |
||
521 | scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID; |
||
522 | scene.RegionInfo.RegionSettings.Save(); |
||
523 | oldTelehubUUID = UUID.Zero; |
||
524 | } |
||
525 | |||
526 | // Try to retain the original creator/owner/lastowner if their uuid is present on this grid |
||
527 | // or creator data is present. Otherwise, use the estate owner instead. |
||
528 | foreach (SceneObjectPart part in sceneObject.Parts) |
||
529 | { |
||
530 | if (string.IsNullOrEmpty(part.CreatorData)) |
||
531 | { |
||
532 | if (!ResolveUserUuid(scene, part.CreatorID)) |
||
533 | part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
534 | } |
||
535 | if (UserManager != null) |
||
536 | UserManager.AddUser(part.CreatorID, part.CreatorData); |
||
537 | |||
538 | if (!ResolveUserUuid(scene, part.OwnerID)) |
||
539 | part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
540 | |||
541 | if (!ResolveUserUuid(scene, part.LastOwnerID)) |
||
542 | part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
543 | |||
544 | if (!ResolveGroupUuid(part.GroupID)) |
||
545 | part.GroupID = UUID.Zero; |
||
546 | |||
547 | // And zap any troublesome sit target information |
||
548 | // part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); |
||
549 | // part.SitTargetPosition = new Vector3(0, 0, 0); |
||
550 | |||
551 | // Fix ownership/creator of inventory items |
||
552 | // Not doing so results in inventory items |
||
553 | // being no copy/no mod for everyone |
||
554 | lock (part.TaskInventory) |
||
555 | { |
||
556 | TaskInventoryDictionary inv = part.TaskInventory; |
||
557 | foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) |
||
558 | { |
||
559 | if (!ResolveUserUuid(scene, kvp.Value.OwnerID)) |
||
560 | { |
||
561 | kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
562 | } |
||
563 | |||
564 | if (string.IsNullOrEmpty(kvp.Value.CreatorData)) |
||
565 | { |
||
566 | if (!ResolveUserUuid(scene, kvp.Value.CreatorID)) |
||
567 | kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
568 | } |
||
569 | |||
570 | if (UserManager != null) |
||
571 | UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); |
||
572 | |||
573 | if (!ResolveGroupUuid(kvp.Value.GroupID)) |
||
574 | kvp.Value.GroupID = UUID.Zero; |
||
575 | } |
||
576 | } |
||
577 | } |
||
578 | |||
579 | if (scene.AddRestoredSceneObject(sceneObject, true, false)) |
||
580 | { |
||
581 | sceneObjectsLoadedCount++; |
||
582 | sceneObject.CreateScriptInstances(0, false, scene.DefaultScriptEngine, 0); |
||
583 | sceneObject.ResumeScripts(); |
||
584 | } |
||
585 | } |
||
586 | |||
587 | m_log.InfoFormat("[ARCHIVER]: Restored {0} scene objects to the scene", sceneObjectsLoadedCount); |
||
588 | |||
589 | int ignoredObjects = serialisedSceneObjects.Count - sceneObjectsLoadedCount; |
||
590 | |||
591 | if (ignoredObjects > 0) |
||
592 | m_log.WarnFormat("[ARCHIVER]: Ignored {0} scene objects that already existed in the scene", ignoredObjects); |
||
593 | |||
594 | if (oldTelehubUUID != UUID.Zero) |
||
595 | { |
||
596 | m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID); |
||
597 | scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero; |
||
598 | scene.RegionInfo.RegionSettings.ClearSpawnPoints(); |
||
599 | } |
||
600 | } |
||
601 | |||
602 | /// <summary> |
||
603 | /// Load serialized parcels. |
||
604 | /// </summary> |
||
605 | /// <param name="scene"></param> |
||
606 | /// <param name="serialisedParcels"></param> |
||
607 | protected void LoadParcels(Scene scene, List<string> serialisedParcels) |
||
608 | { |
||
609 | // Reload serialized parcels |
||
610 | m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count); |
||
611 | List<LandData> landData = new List<LandData>(); |
||
612 | foreach (string serialisedParcel in serialisedParcels) |
||
613 | { |
||
614 | LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); |
||
615 | |||
616 | if (m_displacement != Vector3.Zero) |
||
617 | { |
||
618 | Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f); |
||
619 | parcel.AABBMin += parcelDisp; |
||
620 | parcel.AABBMax += parcelDisp; |
||
621 | } |
||
622 | |||
623 | // Validate User and Group UUID's |
||
624 | |||
625 | if (parcel.IsGroupOwned) |
||
626 | { |
||
627 | if (!ResolveGroupUuid(parcel.GroupID)) |
||
628 | { |
||
629 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; |
||
630 | parcel.GroupID = UUID.Zero; |
||
631 | parcel.IsGroupOwned = false; |
||
632 | } |
||
633 | } |
||
634 | else |
||
635 | { |
||
636 | if (!ResolveUserUuid(scene, parcel.OwnerID)) |
||
637 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; |
||
638 | |||
639 | if (!ResolveGroupUuid(parcel.GroupID)) |
||
640 | parcel.GroupID = UUID.Zero; |
||
641 | } |
||
642 | |||
643 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); |
||
644 | foreach (LandAccessEntry entry in parcel.ParcelAccessList) |
||
645 | { |
||
646 | if (ResolveUserUuid(scene, entry.AgentID)) |
||
647 | accessList.Add(entry); |
||
648 | // else, drop this access rule |
||
649 | } |
||
650 | parcel.ParcelAccessList = accessList; |
||
651 | |||
652 | // m_log.DebugFormat( |
||
653 | // "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}", |
||
654 | // parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area); |
||
655 | |||
656 | landData.Add(parcel); |
||
657 | } |
||
658 | |||
659 | if (!m_merge) |
||
660 | { |
||
661 | bool setupDefaultParcel = (landData.Count == 0); |
||
662 | scene.LandChannel.Clear(setupDefaultParcel); |
||
663 | } |
||
664 | |||
665 | scene.EventManager.TriggerIncomingLandDataFromStorage(landData); |
||
666 | m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count); |
||
667 | } |
||
668 | |||
669 | /// <summary> |
||
670 | /// Look up the given user id to check whether it's one that is valid for this grid. |
||
671 | /// </summary> |
||
672 | /// <param name="scene"></param> |
||
673 | /// <param name="uuid"></param> |
||
674 | /// <returns></returns> |
||
675 | private bool ResolveUserUuid(Scene scene, UUID uuid) |
||
676 | { |
||
677 | lock (m_validUserUuids) |
||
678 | { |
||
679 | if (!m_validUserUuids.ContainsKey(uuid)) |
||
680 | { |
||
681 | // Note: we call GetUserAccount() inside the lock because this UserID is likely |
||
682 | // to occur many times, and we only want to query the users service once. |
||
683 | UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); |
||
684 | m_validUserUuids.Add(uuid, account != null); |
||
685 | } |
||
686 | |||
687 | return m_validUserUuids[uuid]; |
||
688 | } |
||
689 | } |
||
690 | |||
691 | /// <summary> |
||
692 | /// Look up the given group id to check whether it's one that is valid for this grid. |
||
693 | /// </summary> |
||
694 | /// <param name="uuid"></param> |
||
695 | /// <returns></returns> |
||
696 | private bool ResolveGroupUuid(UUID uuid) |
||
697 | { |
||
698 | if (uuid == UUID.Zero) |
||
699 | return true; // this means the object has no group |
||
700 | |||
701 | lock (m_validGroupUuids) |
||
702 | { |
||
703 | if (!m_validGroupUuids.ContainsKey(uuid)) |
||
704 | { |
||
705 | bool exists; |
||
706 | if (m_groupsModule == null) |
||
707 | { |
||
708 | exists = false; |
||
709 | } |
||
710 | else |
||
711 | { |
||
712 | // Note: we call GetGroupRecord() inside the lock because this GroupID is likely |
||
713 | // to occur many times, and we only want to query the groups service once. |
||
714 | exists = (m_groupsModule.GetGroupRecord(uuid) != null); |
||
715 | } |
||
716 | m_validGroupUuids.Add(uuid, exists); |
||
717 | } |
||
718 | |||
719 | return m_validGroupUuids[uuid]; |
||
720 | } |
||
721 | } |
||
722 | |||
723 | /// Load an asset |
||
724 | /// </summary> |
||
725 | /// <param name="assetFilename"></param> |
||
726 | /// <param name="data"></param> |
||
727 | /// <returns>true if asset was successfully loaded, false otherwise</returns> |
||
728 | private bool LoadAsset(string assetPath, byte[] data) |
||
729 | { |
||
730 | // Right now we're nastily obtaining the UUID from the filename |
||
731 | string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); |
||
732 | int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR); |
||
733 | |||
734 | if (i == -1) |
||
735 | { |
||
736 | m_log.ErrorFormat( |
||
737 | "[ARCHIVER]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping", |
||
738 | assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR); |
||
739 | |||
740 | return false; |
||
741 | } |
||
742 | |||
743 | string extension = filename.Substring(i); |
||
744 | string uuid = filename.Remove(filename.Length - extension.Length); |
||
745 | |||
746 | if (m_assetService.GetMetadata(uuid) != null) |
||
747 | { |
||
748 | // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid); |
||
749 | return true; |
||
750 | } |
||
751 | |||
752 | if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) |
||
753 | { |
||
754 | sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; |
||
755 | |||
756 | if (assetType == (sbyte)AssetType.Unknown) |
||
757 | m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); |
||
758 | |||
759 | //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); |
||
760 | |||
761 | AssetBase asset = new AssetBase(new UUID(uuid), String.Empty, assetType, UUID.Zero.ToString()); |
||
762 | asset.Data = data; |
||
763 | |||
764 | // We're relying on the asset service to do the sensible thing and not store the asset if it already |
||
765 | // exists. |
||
766 | m_assetService.Store(asset); |
||
767 | |||
768 | /** |
||
769 | * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so |
||
770 | * it might be best done when dearchive takes place on a separate thread |
||
771 | if (asset.Type=AssetType.Texture) |
||
772 | { |
||
773 | IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>(); |
||
774 | if (cacheLayerDecode != null) |
||
775 | cacheLayerDecode.syncdecode(asset.FullID, asset.Data); |
||
776 | } |
||
777 | */ |
||
778 | |||
779 | return true; |
||
780 | } |
||
781 | else |
||
782 | { |
||
783 | m_log.ErrorFormat( |
||
784 | "[ARCHIVER]: Tried to dearchive data with path {0} with an unknown type extension {1}", |
||
785 | assetPath, extension); |
||
786 | |||
787 | return false; |
||
788 | } |
||
789 | } |
||
790 | |||
791 | /// <summary> |
||
792 | /// Load region settings data |
||
793 | /// </summary> |
||
794 | /// <param name="scene"></param> |
||
795 | /// <param name="settingsPath"></param> |
||
796 | /// <param name="data"></param> |
||
797 | /// <param name="dearchivedScenes"></param> |
||
798 | /// <returns> |
||
799 | /// true if settings were loaded successfully, false otherwise |
||
800 | /// </returns> |
||
801 | private bool LoadRegionSettings(Scene scene, string settingsPath, byte[] data, DearchiveScenesInfo dearchivedScenes) |
||
802 | { |
||
803 | RegionSettings loadedRegionSettings; |
||
804 | |||
805 | try |
||
806 | { |
||
807 | loadedRegionSettings = RegionSettingsSerializer.Deserialize(data); |
||
808 | } |
||
809 | catch (Exception e) |
||
810 | { |
||
811 | m_log.ErrorFormat( |
||
812 | "[ARCHIVER]: Could not parse region settings file {0}. Ignoring. Exception was {1}", |
||
813 | settingsPath, e); |
||
814 | return false; |
||
815 | } |
||
816 | |||
817 | RegionSettings currentRegionSettings = scene.RegionInfo.RegionSettings; |
||
818 | |||
819 | currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit; |
||
820 | currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage; |
||
821 | currentRegionSettings.AllowLandJoinDivide = loadedRegionSettings.AllowLandJoinDivide; |
||
822 | currentRegionSettings.AllowLandResell = loadedRegionSettings.AllowLandResell; |
||
823 | currentRegionSettings.BlockFly = loadedRegionSettings.BlockFly; |
||
824 | currentRegionSettings.BlockShowInSearch = loadedRegionSettings.BlockShowInSearch; |
||
825 | currentRegionSettings.BlockTerraform = loadedRegionSettings.BlockTerraform; |
||
826 | currentRegionSettings.DisableCollisions = loadedRegionSettings.DisableCollisions; |
||
827 | currentRegionSettings.DisablePhysics = loadedRegionSettings.DisablePhysics; |
||
828 | currentRegionSettings.DisableScripts = loadedRegionSettings.DisableScripts; |
||
829 | currentRegionSettings.Elevation1NE = loadedRegionSettings.Elevation1NE; |
||
830 | currentRegionSettings.Elevation1NW = loadedRegionSettings.Elevation1NW; |
||
831 | currentRegionSettings.Elevation1SE = loadedRegionSettings.Elevation1SE; |
||
832 | currentRegionSettings.Elevation1SW = loadedRegionSettings.Elevation1SW; |
||
833 | currentRegionSettings.Elevation2NE = loadedRegionSettings.Elevation2NE; |
||
834 | currentRegionSettings.Elevation2NW = loadedRegionSettings.Elevation2NW; |
||
835 | currentRegionSettings.Elevation2SE = loadedRegionSettings.Elevation2SE; |
||
836 | currentRegionSettings.Elevation2SW = loadedRegionSettings.Elevation2SW; |
||
837 | currentRegionSettings.FixedSun = loadedRegionSettings.FixedSun; |
||
838 | currentRegionSettings.SunPosition = loadedRegionSettings.SunPosition; |
||
839 | currentRegionSettings.ObjectBonus = loadedRegionSettings.ObjectBonus; |
||
840 | currentRegionSettings.RestrictPushing = loadedRegionSettings.RestrictPushing; |
||
841 | currentRegionSettings.TerrainLowerLimit = loadedRegionSettings.TerrainLowerLimit; |
||
842 | currentRegionSettings.TerrainRaiseLimit = loadedRegionSettings.TerrainRaiseLimit; |
||
843 | currentRegionSettings.TerrainTexture1 = loadedRegionSettings.TerrainTexture1; |
||
844 | currentRegionSettings.TerrainTexture2 = loadedRegionSettings.TerrainTexture2; |
||
845 | currentRegionSettings.TerrainTexture3 = loadedRegionSettings.TerrainTexture3; |
||
846 | currentRegionSettings.TerrainTexture4 = loadedRegionSettings.TerrainTexture4; |
||
847 | currentRegionSettings.UseEstateSun = loadedRegionSettings.UseEstateSun; |
||
848 | currentRegionSettings.WaterHeight = loadedRegionSettings.WaterHeight; |
||
849 | currentRegionSettings.TelehubObject = loadedRegionSettings.TelehubObject; |
||
850 | currentRegionSettings.ClearSpawnPoints(); |
||
851 | foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints()) |
||
852 | currentRegionSettings.AddSpawnPoint(sp); |
||
853 | |||
854 | currentRegionSettings.LoadedCreationDateTime = dearchivedScenes.LoadedCreationDateTime; |
||
855 | currentRegionSettings.LoadedCreationID = dearchivedScenes.GetOriginalRegionID(scene.RegionInfo.RegionID).ToString(); |
||
856 | |||
857 | currentRegionSettings.Save(); |
||
858 | |||
859 | scene.TriggerEstateSunUpdate(); |
||
860 | |||
861 | IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>(); |
||
862 | if (estateModule != null) |
||
863 | estateModule.sendRegionHandshakeToAll(); |
||
864 | |||
865 | return true; |
||
866 | } |
||
867 | |||
868 | /// <summary> |
||
869 | /// Load terrain data |
||
870 | /// </summary> |
||
871 | /// <param name="scene"></param> |
||
872 | /// <param name="terrainPath"></param> |
||
873 | /// <param name="data"></param> |
||
874 | /// <returns> |
||
875 | /// true if terrain was resolved successfully, false otherwise. |
||
876 | /// </returns> |
||
877 | private bool LoadTerrain(Scene scene, string terrainPath, byte[] data) |
||
878 | { |
||
879 | ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); |
||
880 | |||
881 | MemoryStream ms = new MemoryStream(data); |
||
882 | if (m_displacement != Vector3.Zero || m_rotation != 0f) |
||
883 | { |
||
884 | Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y); |
||
885 | terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms); |
||
886 | } |
||
887 | else |
||
888 | { |
||
889 | terrainModule.LoadFromStream(terrainPath, ms); |
||
890 | } |
||
891 | ms.Close(); |
||
892 | |||
893 | m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); |
||
894 | |||
895 | return true; |
||
896 | } |
||
897 | |||
898 | /// <summary> |
||
899 | /// Load oar control file |
||
900 | /// </summary> |
||
901 | /// <param name="path"></param> |
||
902 | /// <param name="data"></param> |
||
903 | /// <param name="dearchivedScenes"></param> |
||
904 | public DearchiveScenesInfo LoadControlFile(string path, byte[] data, DearchiveScenesInfo dearchivedScenes) |
||
905 | { |
||
906 | XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); |
||
907 | XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); |
||
908 | XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context); |
||
909 | |||
910 | // Loaded metadata will be empty if no information exists in the archive |
||
911 | dearchivedScenes.LoadedCreationDateTime = 0; |
||
912 | dearchivedScenes.DefaultOriginalID = ""; |
||
913 | |||
914 | bool multiRegion = false; |
||
915 | |||
916 | while (xtr.Read()) |
||
917 | { |
||
918 | if (xtr.NodeType == XmlNodeType.Element) |
||
919 | { |
||
920 | if (xtr.Name.ToString() == "archive") |
||
921 | { |
||
922 | int majorVersion = int.Parse(xtr["major_version"]); |
||
923 | int minorVersion = int.Parse(xtr["minor_version"]); |
||
924 | string version = string.Format("{0}.{1}", majorVersion, minorVersion); |
||
925 | |||
926 | if (majorVersion > MAX_MAJOR_VERSION) |
||
927 | { |
||
928 | throw new Exception( |
||
929 | string.Format( |
||
930 | "The OAR you are trying to load has major version number of {0} but this version of OpenSim can only load OARs with major version number {1} and below", |
||
931 | majorVersion, MAX_MAJOR_VERSION)); |
||
932 | } |
||
933 | |||
934 | m_log.InfoFormat("[ARCHIVER]: Loading OAR with version {0}", version); |
||
935 | } |
||
936 | if (xtr.Name.ToString() == "datetime") |
||
937 | { |
||
938 | int value; |
||
939 | if (Int32.TryParse(xtr.ReadElementContentAsString(), out value)) |
||
940 | dearchivedScenes.LoadedCreationDateTime = value; |
||
941 | } |
||
942 | else if (xtr.Name.ToString() == "row") |
||
943 | { |
||
944 | multiRegion = true; |
||
945 | dearchivedScenes.StartRow(); |
||
946 | } |
||
947 | else if (xtr.Name.ToString() == "region") |
||
948 | { |
||
949 | dearchivedScenes.StartRegion(); |
||
950 | } |
||
951 | else if (xtr.Name.ToString() == "id") |
||
952 | { |
||
953 | string id = xtr.ReadElementContentAsString(); |
||
954 | dearchivedScenes.DefaultOriginalID = id; |
||
955 | if (multiRegion) |
||
956 | dearchivedScenes.SetRegionOriginalID(id); |
||
957 | } |
||
958 | else if (xtr.Name.ToString() == "dir") |
||
959 | { |
||
960 | dearchivedScenes.SetRegionDirectory(xtr.ReadElementContentAsString()); |
||
961 | } |
||
962 | } |
||
963 | } |
||
964 | |||
965 | dearchivedScenes.MultiRegionFormat = multiRegion; |
||
966 | if (!multiRegion) |
||
967 | { |
||
968 | // Add the single scene |
||
969 | dearchivedScenes.StartRow(); |
||
970 | dearchivedScenes.StartRegion(); |
||
971 | dearchivedScenes.SetRegionOriginalID(dearchivedScenes.DefaultOriginalID); |
||
972 | dearchivedScenes.SetRegionDirectory(""); |
||
973 | } |
||
974 | |||
975 | ControlFileLoaded = true; |
||
976 | |||
977 | return dearchivedScenes; |
||
978 | } |
||
979 | } |
||
980 | } |