diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/World')
61 files changed, 7061 insertions, 2257 deletions
diff --git a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs index 1599f15..f567cab 100644 --- a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs +++ b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs | |||
@@ -91,13 +91,17 @@ namespace OpenSim.Region.CoreModules.World | |||
91 | 91 | ||
92 | public void AddRegion(Scene scene) | 92 | public void AddRegion(Scene scene) |
93 | { | 93 | { |
94 | if (!m_SceneList.Contains(scene)) | 94 | lock (m_SceneList) |
95 | m_SceneList.Add(scene); | 95 | { |
96 | if (!m_SceneList.Contains(scene)) | ||
97 | m_SceneList.Add(scene); | ||
98 | } | ||
96 | } | 99 | } |
97 | 100 | ||
98 | public void RemoveRegion(Scene scene) | 101 | public void RemoveRegion(Scene scene) |
99 | { | 102 | { |
100 | m_SceneList.Remove(scene); | 103 | lock (m_SceneList) |
104 | m_SceneList.Remove(scene); | ||
101 | } | 105 | } |
102 | 106 | ||
103 | public void RegionLoaded(Scene scene) | 107 | public void RegionLoaded(Scene scene) |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index c810242..9c6706f 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs | |||
@@ -36,6 +36,7 @@ using System.Xml; | |||
36 | using log4net; | 36 | using log4net; |
37 | using OpenMetaverse; | 37 | using OpenMetaverse; |
38 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
39 | using OpenSim.Framework.Monitoring; | ||
39 | using OpenSim.Framework.Serialization; | 40 | using OpenSim.Framework.Serialization; |
40 | using OpenSim.Framework.Serialization.External; | 41 | using OpenSim.Framework.Serialization.External; |
41 | using OpenSim.Region.CoreModules.World.Terrain; | 42 | using OpenSim.Region.CoreModules.World.Terrain; |
@@ -96,14 +97,42 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
96 | 97 | ||
97 | /// <value> | 98 | /// <value> |
98 | /// Should the archive being loaded be merged with what is already on the region? | 99 | /// Should the archive being loaded be merged with what is already on the region? |
100 | /// Merging usually suppresses terrain and parcel loading | ||
99 | /// </value> | 101 | /// </value> |
100 | protected bool m_merge; | 102 | protected bool m_merge; |
101 | 103 | ||
102 | /// <value> | 104 | /// <value> |
105 | /// If true, force the loading of terrain from the oar file | ||
106 | /// </value> | ||
107 | protected bool m_forceTerrain; | ||
108 | |||
109 | /// <value> | ||
110 | /// If true, force the loading of parcels from the oar file | ||
111 | /// </value> | ||
112 | protected bool m_forceParcels; | ||
113 | |||
114 | /// <value> | ||
103 | /// Should we ignore any assets when reloading the archive? | 115 | /// Should we ignore any assets when reloading the archive? |
104 | /// </value> | 116 | /// </value> |
105 | protected bool m_skipAssets; | 117 | protected bool m_skipAssets; |
106 | 118 | ||
119 | /// <value> | ||
120 | /// Displacement added to each object as it is added to the world | ||
121 | /// </value> | ||
122 | protected Vector3 m_displacement = Vector3.Zero; | ||
123 | |||
124 | /// <value> | ||
125 | /// Rotation (in radians) to apply to the objects as they are loaded. | ||
126 | /// </value> | ||
127 | protected float m_rotation = 0f; | ||
128 | |||
129 | /// <value> | ||
130 | /// Center around which to apply the rotation relative to the origional oar position | ||
131 | /// </value> | ||
132 | protected Vector3 m_rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f); | ||
133 | |||
134 | protected bool m_noObjects = false; | ||
135 | |||
107 | /// <summary> | 136 | /// <summary> |
108 | /// Used to cache lookups for valid uuids. | 137 | /// Used to cache lookups for valid uuids. |
109 | /// </summary> | 138 | /// </summary> |
@@ -132,10 +161,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
132 | private IAssetService m_assetService = null; | 161 | private IAssetService m_assetService = null; |
133 | 162 | ||
134 | 163 | ||
135 | public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) | 164 | private UUID m_defaultUser; |
165 | |||
166 | public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary<string,object>options) | ||
136 | { | 167 | { |
137 | m_rootScene = scene; | 168 | m_rootScene = scene; |
138 | 169 | ||
170 | if (options.ContainsKey("default-user")) | ||
171 | { | ||
172 | m_defaultUser = (UUID)options["default-user"]; | ||
173 | m_log.InfoFormat("Using User {0} as default user", m_defaultUser.ToString()); | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner; | ||
178 | } | ||
179 | |||
139 | m_loadPath = loadPath; | 180 | m_loadPath = loadPath; |
140 | try | 181 | try |
141 | { | 182 | { |
@@ -150,26 +191,36 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
150 | } | 191 | } |
151 | 192 | ||
152 | m_errorMessage = String.Empty; | 193 | m_errorMessage = String.Empty; |
153 | m_merge = merge; | 194 | m_merge = options.ContainsKey("merge"); |
154 | m_skipAssets = skipAssets; | 195 | m_forceTerrain = options.ContainsKey("force-terrain"); |
196 | m_forceParcels = options.ContainsKey("force-parcels"); | ||
197 | m_noObjects = options.ContainsKey("no-objects"); | ||
198 | m_skipAssets = options.ContainsKey("skipAssets"); | ||
155 | m_requestId = requestId; | 199 | m_requestId = requestId; |
200 | m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero; | ||
201 | m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f; | ||
202 | m_rotationCenter = options.ContainsKey("rotation-center") ? (Vector3)options["rotation-center"] | ||
203 | : new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 0f); | ||
156 | 204 | ||
157 | // Zero can never be a valid user id | 205 | // Zero can never be a valid user or group id |
158 | m_validUserUuids[UUID.Zero] = false; | 206 | m_validUserUuids[UUID.Zero] = false; |
207 | m_validGroupUuids[UUID.Zero] = false; | ||
159 | 208 | ||
160 | m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); | 209 | m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); |
161 | m_assetService = m_rootScene.AssetService; | 210 | m_assetService = m_rootScene.AssetService; |
162 | } | 211 | } |
163 | 212 | ||
164 | public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) | 213 | public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary<string, object>options) |
165 | { | 214 | { |
166 | m_rootScene = scene; | 215 | m_rootScene = scene; |
167 | m_loadPath = null; | 216 | m_loadPath = null; |
168 | m_loadStream = loadStream; | 217 | m_loadStream = loadStream; |
169 | m_merge = merge; | 218 | m_skipAssets = options.ContainsKey("skipAssets"); |
170 | m_skipAssets = skipAssets; | 219 | m_merge = options.ContainsKey("merge"); |
171 | m_requestId = requestId; | 220 | m_requestId = requestId; |
172 | 221 | ||
222 | m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner; | ||
223 | |||
173 | // Zero can never be a valid user id | 224 | // Zero can never be a valid user id |
174 | m_validUserUuids[UUID.Zero] = false; | 225 | m_validUserUuids[UUID.Zero] = false; |
175 | 226 | ||
@@ -229,7 +280,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
229 | 280 | ||
230 | // Process the file | 281 | // Process the file |
231 | 282 | ||
232 | if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) | 283 | if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH) && !m_noObjects) |
233 | { | 284 | { |
234 | sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); | 285 | sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); |
235 | } | 286 | } |
@@ -243,7 +294,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
243 | if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) | 294 | if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) |
244 | m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); | 295 | m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); |
245 | } | 296 | } |
246 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) | 297 | else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH) && (!m_merge || m_forceTerrain)) |
247 | { | 298 | { |
248 | LoadTerrain(scene, filePath, data); | 299 | LoadTerrain(scene, filePath, data); |
249 | } | 300 | } |
@@ -251,7 +302,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
251 | { | 302 | { |
252 | LoadRegionSettings(scene, filePath, data, dearchivedScenes); | 303 | LoadRegionSettings(scene, filePath, data, dearchivedScenes); |
253 | } | 304 | } |
254 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) | 305 | else if (filePath.StartsWith(ArchiveConstants.LANDDATA_PATH) && (!m_merge || m_forceParcels)) |
255 | { | 306 | { |
256 | sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); | 307 | sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); |
257 | } | 308 | } |
@@ -321,7 +372,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
321 | // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so | 372 | // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so |
322 | // that users can enter the scene. If we allow the scripts to start in the loop above | 373 | // that users can enter the scene. If we allow the scripts to start in the loop above |
323 | // then they significantly increase the time until the OAR finishes loading. | 374 | // then they significantly increase the time until the OAR finishes loading. |
324 | Util.FireAndForget(delegate(object o) | 375 | WorkManager.RunInThread(o => |
325 | { | 376 | { |
326 | Thread.Sleep(15000); | 377 | Thread.Sleep(15000); |
327 | m_log.Info("[ARCHIVER]: Starting scripts in scene objects"); | 378 | m_log.Info("[ARCHIVER]: Starting scripts in scene objects"); |
@@ -336,7 +387,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
336 | 387 | ||
337 | sceneContext.SceneObjects.Clear(); | 388 | sceneContext.SceneObjects.Clear(); |
338 | } | 389 | } |
339 | }); | 390 | }, null, string.Format("ReadArchiveStartScripts (request {0})", m_requestId)); |
340 | 391 | ||
341 | m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); | 392 | m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); |
342 | 393 | ||
@@ -422,6 +473,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
422 | // Reload serialized prims | 473 | // Reload serialized prims |
423 | m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); | 474 | m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); |
424 | 475 | ||
476 | OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, m_rotation); | ||
477 | |||
425 | UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; | 478 | UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; |
426 | 479 | ||
427 | IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); | 480 | IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); |
@@ -445,6 +498,32 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
445 | 498 | ||
446 | SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); | 499 | SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); |
447 | 500 | ||
501 | // Happily this does not do much to the object since it hasn't been added to the scene yet | ||
502 | if (!sceneObject.IsAttachment) | ||
503 | { | ||
504 | if (m_displacement != Vector3.Zero || m_rotation != 0f) | ||
505 | { | ||
506 | Vector3 pos = sceneObject.AbsolutePosition; | ||
507 | if (m_rotation != 0f) | ||
508 | { | ||
509 | // Rotate the object | ||
510 | sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; | ||
511 | // Get object position relative to rotation axis | ||
512 | Vector3 offset = pos - m_rotationCenter; | ||
513 | // Rotate the object position | ||
514 | offset *= rot; | ||
515 | // Restore the object position back to relative to the region | ||
516 | pos = m_rotationCenter + offset; | ||
517 | } | ||
518 | if (m_displacement != Vector3.Zero) | ||
519 | { | ||
520 | pos += m_displacement; | ||
521 | } | ||
522 | sceneObject.AbsolutePosition = pos; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | |||
448 | bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); | 527 | bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); |
449 | 528 | ||
450 | // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned | 529 | // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned |
@@ -460,58 +539,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
460 | oldTelehubUUID = UUID.Zero; | 539 | oldTelehubUUID = UUID.Zero; |
461 | } | 540 | } |
462 | 541 | ||
463 | // Try to retain the original creator/owner/lastowner if their uuid is present on this grid | 542 | ModifySceneObject(scene, sceneObject); |
464 | // or creator data is present. Otherwise, use the estate owner instead. | ||
465 | foreach (SceneObjectPart part in sceneObject.Parts) | ||
466 | { | ||
467 | if (part.CreatorData == null || part.CreatorData == string.Empty) | ||
468 | { | ||
469 | if (!ResolveUserUuid(scene, part.CreatorID)) | ||
470 | part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; | ||
471 | } | ||
472 | if (UserManager != null) | ||
473 | UserManager.AddUser(part.CreatorID, part.CreatorData); | ||
474 | |||
475 | if (!ResolveUserUuid(scene, part.OwnerID)) | ||
476 | part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; | ||
477 | |||
478 | if (!ResolveUserUuid(scene, part.LastOwnerID)) | ||
479 | part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner; | ||
480 | |||
481 | if (!ResolveGroupUuid(part.GroupID)) | ||
482 | part.GroupID = UUID.Zero; | ||
483 | |||
484 | // And zap any troublesome sit target information | ||
485 | // part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); | ||
486 | // part.SitTargetPosition = new Vector3(0, 0, 0); | ||
487 | |||
488 | // Fix ownership/creator of inventory items | ||
489 | // Not doing so results in inventory items | ||
490 | // being no copy/no mod for everyone | ||
491 | lock (part.TaskInventory) | ||
492 | { | ||
493 | TaskInventoryDictionary inv = part.TaskInventory; | ||
494 | foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) | ||
495 | { | ||
496 | if (!ResolveUserUuid(scene, kvp.Value.OwnerID)) | ||
497 | { | ||
498 | kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; | ||
499 | } | ||
500 | |||
501 | if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty) | ||
502 | { | ||
503 | if (!ResolveUserUuid(scene, kvp.Value.CreatorID)) | ||
504 | kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; | ||
505 | } | ||
506 | |||
507 | if (UserManager != null) | ||
508 | UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); | ||
509 | |||
510 | if (!ResolveGroupUuid(kvp.Value.GroupID)) | ||
511 | kvp.Value.GroupID = UUID.Zero; | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | 543 | ||
516 | if (scene.AddRestoredSceneObject(sceneObject, true, false)) | 544 | if (scene.AddRestoredSceneObject(sceneObject, true, false)) |
517 | { | 545 | { |
@@ -535,6 +563,67 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
535 | scene.RegionInfo.RegionSettings.ClearSpawnPoints(); | 563 | scene.RegionInfo.RegionSettings.ClearSpawnPoints(); |
536 | } | 564 | } |
537 | } | 565 | } |
566 | |||
567 | /// <summary> | ||
568 | /// Optionally modify a loaded SceneObjectGroup. Currently this just ensures that the | ||
569 | /// User IDs and Group IDs are valid, but other manipulations could be done as well. | ||
570 | /// </summary> | ||
571 | private void ModifySceneObject(Scene scene, SceneObjectGroup sceneObject) | ||
572 | { | ||
573 | // Try to retain the original creator/owner/lastowner if their uuid is present on this grid | ||
574 | // or creator data is present. Otherwise, use the estate owner instead. | ||
575 | foreach (SceneObjectPart part in sceneObject.Parts) | ||
576 | { | ||
577 | if (string.IsNullOrEmpty(part.CreatorData)) | ||
578 | { | ||
579 | if (!ResolveUserUuid(scene, part.CreatorID)) | ||
580 | part.CreatorID = m_defaultUser; | ||
581 | } | ||
582 | if (UserManager != null) | ||
583 | UserManager.AddUser(part.CreatorID, part.CreatorData); | ||
584 | |||
585 | if (!(ResolveUserUuid(scene, part.OwnerID) || ResolveGroupUuid(part.OwnerID))) | ||
586 | part.OwnerID = m_defaultUser; | ||
587 | |||
588 | if (!(ResolveUserUuid(scene, part.LastOwnerID) || ResolveGroupUuid(part.LastOwnerID))) | ||
589 | part.LastOwnerID = m_defaultUser; | ||
590 | |||
591 | if (!ResolveGroupUuid(part.GroupID)) | ||
592 | part.GroupID = UUID.Zero; | ||
593 | |||
594 | // And zap any troublesome sit target information | ||
595 | // part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); | ||
596 | // part.SitTargetPosition = new Vector3(0, 0, 0); | ||
597 | |||
598 | // Fix ownership/creator of inventory items | ||
599 | // Not doing so results in inventory items | ||
600 | // being no copy/no mod for everyone | ||
601 | lock (part.TaskInventory) | ||
602 | { | ||
603 | TaskInventoryDictionary inv = part.TaskInventory; | ||
604 | foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) | ||
605 | { | ||
606 | if (!(ResolveUserUuid(scene, kvp.Value.OwnerID) || ResolveGroupUuid(kvp.Value.OwnerID))) | ||
607 | { | ||
608 | kvp.Value.OwnerID = m_defaultUser; | ||
609 | } | ||
610 | |||
611 | if (string.IsNullOrEmpty(kvp.Value.CreatorData)) | ||
612 | { | ||
613 | if (!ResolveUserUuid(scene, kvp.Value.CreatorID)) | ||
614 | kvp.Value.CreatorID = m_defaultUser; | ||
615 | } | ||
616 | |||
617 | if (UserManager != null) | ||
618 | UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); | ||
619 | |||
620 | if (!ResolveGroupUuid(kvp.Value.GroupID)) | ||
621 | kvp.Value.GroupID = UUID.Zero; | ||
622 | } | ||
623 | } | ||
624 | } | ||
625 | } | ||
626 | |||
538 | 627 | ||
539 | /// <summary> | 628 | /// <summary> |
540 | /// Load serialized parcels. | 629 | /// Load serialized parcels. |
@@ -549,15 +638,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
549 | foreach (string serialisedParcel in serialisedParcels) | 638 | foreach (string serialisedParcel in serialisedParcels) |
550 | { | 639 | { |
551 | LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); | 640 | LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); |
641 | |||
642 | if (m_displacement != Vector3.Zero) | ||
643 | { | ||
644 | Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f); | ||
645 | parcel.AABBMin += parcelDisp; | ||
646 | parcel.AABBMax += parcelDisp; | ||
647 | } | ||
552 | 648 | ||
553 | // Validate User and Group UUID's | 649 | // Validate User and Group UUID's |
554 | 650 | ||
651 | if (!ResolveGroupUuid(parcel.GroupID)) | ||
652 | parcel.GroupID = UUID.Zero; | ||
653 | |||
555 | if (parcel.IsGroupOwned) | 654 | if (parcel.IsGroupOwned) |
556 | { | 655 | { |
557 | if (!ResolveGroupUuid(parcel.GroupID)) | 656 | if (parcel.GroupID != UUID.Zero) |
657 | { | ||
658 | // In group-owned parcels, OwnerID=GroupID. This should already be the case, but let's make sure. | ||
659 | parcel.OwnerID = parcel.GroupID; | ||
660 | } | ||
661 | else | ||
558 | { | 662 | { |
559 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; | 663 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; |
560 | parcel.GroupID = UUID.Zero; | ||
561 | parcel.IsGroupOwned = false; | 664 | parcel.IsGroupOwned = false; |
562 | } | 665 | } |
563 | } | 666 | } |
@@ -565,9 +668,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
565 | { | 668 | { |
566 | if (!ResolveUserUuid(scene, parcel.OwnerID)) | 669 | if (!ResolveUserUuid(scene, parcel.OwnerID)) |
567 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; | 670 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; |
568 | |||
569 | if (!ResolveGroupUuid(parcel.GroupID)) | ||
570 | parcel.GroupID = UUID.Zero; | ||
571 | } | 671 | } |
572 | 672 | ||
573 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); | 673 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); |
@@ -604,13 +704,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
604 | /// <returns></returns> | 704 | /// <returns></returns> |
605 | private bool ResolveUserUuid(Scene scene, UUID uuid) | 705 | private bool ResolveUserUuid(Scene scene, UUID uuid) |
606 | { | 706 | { |
607 | if (!m_validUserUuids.ContainsKey(uuid)) | 707 | lock (m_validUserUuids) |
608 | { | 708 | { |
609 | UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); | 709 | if (!m_validUserUuids.ContainsKey(uuid)) |
610 | m_validUserUuids.Add(uuid, account != null); | 710 | { |
611 | } | 711 | // Note: we call GetUserAccount() inside the lock because this UserID is likely |
712 | // to occur many times, and we only want to query the users service once. | ||
713 | UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); | ||
714 | m_validUserUuids.Add(uuid, account != null); | ||
715 | } | ||
612 | 716 | ||
613 | return m_validUserUuids[uuid]; | 717 | return m_validUserUuids[uuid]; |
718 | } | ||
614 | } | 719 | } |
615 | 720 | ||
616 | /// <summary> | 721 | /// <summary> |
@@ -620,22 +725,26 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
620 | /// <returns></returns> | 725 | /// <returns></returns> |
621 | private bool ResolveGroupUuid(UUID uuid) | 726 | private bool ResolveGroupUuid(UUID uuid) |
622 | { | 727 | { |
623 | if (uuid == UUID.Zero) | 728 | lock (m_validGroupUuids) |
624 | return true; // this means the object has no group | ||
625 | |||
626 | if (!m_validGroupUuids.ContainsKey(uuid)) | ||
627 | { | 729 | { |
628 | bool exists; | 730 | if (!m_validGroupUuids.ContainsKey(uuid)) |
629 | 731 | { | |
630 | if (m_groupsModule == null) | 732 | bool exists; |
631 | exists = false; | 733 | if (m_groupsModule == null) |
632 | else | 734 | { |
633 | exists = (m_groupsModule.GetGroupRecord(uuid) != null); | 735 | exists = false; |
736 | } | ||
737 | else | ||
738 | { | ||
739 | // Note: we call GetGroupRecord() inside the lock because this GroupID is likely | ||
740 | // to occur many times, and we only want to query the groups service once. | ||
741 | exists = (m_groupsModule.GetGroupRecord(uuid) != null); | ||
742 | } | ||
743 | m_validGroupUuids.Add(uuid, exists); | ||
744 | } | ||
634 | 745 | ||
635 | m_validGroupUuids.Add(uuid, exists); | 746 | return m_validGroupUuids[uuid]; |
636 | } | 747 | } |
637 | |||
638 | return m_validGroupUuids[uuid]; | ||
639 | } | 748 | } |
640 | 749 | ||
641 | /// Load an asset | 750 | /// Load an asset |
@@ -672,7 +781,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
672 | sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; | 781 | sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; |
673 | 782 | ||
674 | if (assetType == (sbyte)AssetType.Unknown) | 783 | if (assetType == (sbyte)AssetType.Unknown) |
784 | { | ||
675 | m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); | 785 | m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); |
786 | } | ||
787 | else if (assetType == (sbyte)AssetType.Object) | ||
788 | { | ||
789 | data = SceneObjectSerializer.ModifySerializedObject(UUID.Parse(uuid), data, | ||
790 | sog => | ||
791 | { | ||
792 | ModifySceneObject(m_rootScene, sog); | ||
793 | return true; | ||
794 | }); | ||
795 | |||
796 | if (data == null) | ||
797 | return false; | ||
798 | } | ||
676 | 799 | ||
677 | //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); | 800 | //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); |
678 | 801 | ||
@@ -796,9 +919,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
796 | { | 919 | { |
797 | ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); | 920 | ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); |
798 | 921 | ||
799 | MemoryStream ms = new MemoryStream(data); | 922 | using (MemoryStream ms = new MemoryStream(data)) |
800 | terrainModule.LoadFromStream(terrainPath, ms); | 923 | { |
801 | ms.Close(); | 924 | if (m_displacement != Vector3.Zero || m_rotation != 0f) |
925 | { | ||
926 | Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y); | ||
927 | terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms); | ||
928 | } | ||
929 | else | ||
930 | { | ||
931 | terrainModule.LoadFromStream(terrainPath, ms); | ||
932 | } | ||
933 | } | ||
802 | 934 | ||
803 | m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); | 935 | m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); |
804 | 936 | ||
@@ -887,4 +1019,4 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
887 | return dearchivedScenes; | 1019 | return dearchivedScenes; |
888 | } | 1020 | } |
889 | } | 1021 | } |
890 | } \ No newline at end of file | 1022 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index 7bdd65c..cb2c7f1 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs | |||
@@ -36,6 +36,7 @@ using System.Xml; | |||
36 | using log4net; | 36 | using log4net; |
37 | using OpenMetaverse; | 37 | using OpenMetaverse; |
38 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
39 | using OpenSim.Framework.Monitoring; | ||
39 | using OpenSim.Framework.Serialization; | 40 | using OpenSim.Framework.Serialization; |
40 | using OpenSim.Region.CoreModules.World.Terrain; | 41 | using OpenSim.Region.CoreModules.World.Terrain; |
41 | using OpenSim.Region.Framework.Interfaces; | 42 | using OpenSim.Region.Framework.Interfaces; |
@@ -43,7 +44,9 @@ using OpenSim.Region.Framework.Scenes; | |||
43 | using Ionic.Zlib; | 44 | using Ionic.Zlib; |
44 | using GZipStream = Ionic.Zlib.GZipStream; | 45 | using GZipStream = Ionic.Zlib.GZipStream; |
45 | using CompressionMode = Ionic.Zlib.CompressionMode; | 46 | using CompressionMode = Ionic.Zlib.CompressionMode; |
47 | using CompressionLevel = Ionic.Zlib.CompressionLevel; | ||
46 | using OpenSim.Framework.Serialization.External; | 48 | using OpenSim.Framework.Serialization.External; |
49 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
47 | 50 | ||
48 | namespace OpenSim.Region.CoreModules.World.Archiver | 51 | namespace OpenSim.Region.CoreModules.World.Archiver |
49 | { | 52 | { |
@@ -78,7 +81,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
78 | /// Determines which objects will be included in the archive, according to their permissions. | 81 | /// Determines which objects will be included in the archive, according to their permissions. |
79 | /// Default is null, meaning no permission checks. | 82 | /// Default is null, meaning no permission checks. |
80 | /// </summary> | 83 | /// </summary> |
81 | public string CheckPermissions { get; set; } | 84 | public string FilterContent { get; set; } |
82 | 85 | ||
83 | protected Scene m_rootScene; | 86 | protected Scene m_rootScene; |
84 | protected Stream m_saveStream; | 87 | protected Stream m_saveStream; |
@@ -129,7 +132,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
129 | 132 | ||
130 | MultiRegionFormat = false; | 133 | MultiRegionFormat = false; |
131 | SaveAssets = true; | 134 | SaveAssets = true; |
132 | CheckPermissions = null; | 135 | FilterContent = null; |
133 | } | 136 | } |
134 | 137 | ||
135 | /// <summary> | 138 | /// <summary> |
@@ -148,7 +151,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
148 | 151 | ||
149 | Object temp; | 152 | Object temp; |
150 | if (options.TryGetValue("checkPermissions", out temp)) | 153 | if (options.TryGetValue("checkPermissions", out temp)) |
151 | CheckPermissions = (string)temp; | 154 | FilterContent = (string)temp; |
152 | 155 | ||
153 | 156 | ||
154 | // Find the regions to archive | 157 | // Find the regions to archive |
@@ -177,7 +180,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
177 | 180 | ||
178 | // Archive the regions | 181 | // Archive the regions |
179 | 182 | ||
180 | Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>(); | 183 | Dictionary<UUID, sbyte> assetUuids = new Dictionary<UUID, sbyte>(); |
181 | 184 | ||
182 | scenesGroup.ForEachScene(delegate(Scene scene) | 185 | scenesGroup.ForEachScene(delegate(Scene scene) |
183 | { | 186 | { |
@@ -198,7 +201,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
198 | m_rootScene.AssetService, m_rootScene.UserAccountService, | 201 | m_rootScene.AssetService, m_rootScene.UserAccountService, |
199 | m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); | 202 | m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); |
200 | 203 | ||
201 | Util.FireAndForget(o => ar.Execute()); | 204 | WorkManager.RunInThread(o => ar.Execute(), null, "Archive Assets Request"); |
202 | 205 | ||
203 | // CloseArchive() will be called from ReceivedAllAssets() | 206 | // CloseArchive() will be called from ReceivedAllAssets() |
204 | } | 207 | } |
@@ -215,9 +218,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
215 | } | 218 | } |
216 | } | 219 | } |
217 | 220 | ||
218 | private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) | 221 | private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, sbyte> assetUuids) |
219 | { | 222 | { |
220 | m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); | 223 | m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.Name); |
221 | 224 | ||
222 | EntityBase[] entities = scene.GetEntities(); | 225 | EntityBase[] entities = scene.GetEntities(); |
223 | List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); | 226 | List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); |
@@ -236,7 +239,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
236 | 239 | ||
237 | if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) | 240 | if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) |
238 | { | 241 | { |
239 | if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, CheckPermissions, permissionsModule)) | 242 | if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, FilterContent, permissionsModule)) |
240 | { | 243 | { |
241 | // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR. | 244 | // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR. |
242 | ++numObjectsSkippedPermissions; | 245 | ++numObjectsSkippedPermissions; |
@@ -251,13 +254,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
251 | 254 | ||
252 | if (SaveAssets) | 255 | if (SaveAssets) |
253 | { | 256 | { |
254 | UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService); | 257 | UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService, assetUuids); |
255 | int prevAssets = assetUuids.Count; | 258 | int prevAssets = assetUuids.Count; |
256 | 259 | ||
257 | foreach (SceneObjectGroup sceneObject in sceneObjects) | 260 | foreach (SceneObjectGroup sceneObject in sceneObjects) |
258 | { | 261 | assetGatherer.AddForInspection(sceneObject); |
259 | assetGatherer.GatherAssetUuids(sceneObject, assetUuids); | 262 | |
260 | } | 263 | assetGatherer.GatherAll(); |
261 | 264 | ||
262 | m_log.DebugFormat( | 265 | m_log.DebugFormat( |
263 | "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", | 266 | "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", |
@@ -275,16 +278,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
275 | RegionSettings regionSettings = scene.RegionInfo.RegionSettings; | 278 | RegionSettings regionSettings = scene.RegionInfo.RegionSettings; |
276 | 279 | ||
277 | if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) | 280 | if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) |
278 | assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture; | 281 | assetUuids[regionSettings.TerrainTexture1] = (sbyte)AssetType.Texture; |
279 | 282 | ||
280 | if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) | 283 | if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) |
281 | assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture; | 284 | assetUuids[regionSettings.TerrainTexture2] = (sbyte)AssetType.Texture; |
282 | 285 | ||
283 | if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) | 286 | if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) |
284 | assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture; | 287 | assetUuids[regionSettings.TerrainTexture3] = (sbyte)AssetType.Texture; |
285 | 288 | ||
286 | if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) | 289 | if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) |
287 | assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture; | 290 | assetUuids[regionSettings.TerrainTexture4] = (sbyte)AssetType.Texture; |
288 | 291 | ||
289 | Save(scene, sceneObjects, regionDir); | 292 | Save(scene, sceneObjects, regionDir); |
290 | } | 293 | } |
@@ -294,12 +297,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
294 | /// </summary> | 297 | /// </summary> |
295 | /// <param name="user">The user</param> | 298 | /// <param name="user">The user</param> |
296 | /// <param name="objGroup">The object group</param> | 299 | /// <param name="objGroup">The object group</param> |
297 | /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param> | 300 | /// <param name="filterContent">Which permissions to check: "C" = Copy, "T" = Transfer</param> |
298 | /// <param name="permissionsModule">The scene's permissions module</param> | 301 | /// <param name="permissionsModule">The scene's permissions module</param> |
299 | /// <returns>Whether the user is allowed to export the object to an OAR</returns> | 302 | /// <returns>Whether the user is allowed to export the object to an OAR</returns> |
300 | private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions, IPermissionsModule permissionsModule) | 303 | private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string filterContent, IPermissionsModule permissionsModule) |
301 | { | 304 | { |
302 | if (checkPermissions == null) | 305 | if (filterContent == null) |
303 | return true; | 306 | return true; |
304 | 307 | ||
305 | if (permissionsModule == null) | 308 | if (permissionsModule == null) |
@@ -341,9 +344,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
341 | canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0; | 344 | canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0; |
342 | 345 | ||
343 | bool partPermitted = true; | 346 | bool partPermitted = true; |
344 | if (checkPermissions.Contains("C") && !canCopy) | 347 | if (filterContent.Contains("C") && !canCopy) |
345 | partPermitted = false; | 348 | partPermitted = false; |
346 | if (checkPermissions.Contains("T") && !canTransfer) | 349 | if (filterContent.Contains("T") && !canTransfer) |
347 | partPermitted = false; | 350 | partPermitted = false; |
348 | 351 | ||
349 | // If the user is the Creator of the object then it can always be included in the OAR | 352 | // If the user is the Creator of the object then it can always be included in the OAR |
@@ -532,7 +535,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
532 | if (isMegaregion) | 535 | if (isMegaregion) |
533 | size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); | 536 | size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); |
534 | else | 537 | else |
535 | size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); | 538 | size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY); |
536 | 539 | ||
537 | xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); | 540 | xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); |
538 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); | 541 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); |
@@ -568,10 +571,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
568 | string terrainPath = String.Format("{0}{1}{2}.r32", | 571 | string terrainPath = String.Format("{0}{1}{2}.r32", |
569 | regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName); | 572 | regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName); |
570 | 573 | ||
571 | MemoryStream ms = new MemoryStream(); | 574 | using (MemoryStream ms = new MemoryStream()) |
572 | scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms); | 575 | { |
573 | m_archiveWriter.WriteFile(terrainPath, ms.ToArray()); | 576 | scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms); |
574 | ms.Close(); | 577 | m_archiveWriter.WriteFile(terrainPath, ms.ToArray()); |
578 | } | ||
575 | 579 | ||
576 | m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive."); | 580 | m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive."); |
577 | 581 | ||
@@ -587,19 +591,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
587 | } | 591 | } |
588 | } | 592 | } |
589 | 593 | ||
590 | protected void ReceivedAllAssets( | 594 | protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut) |
591 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) | ||
592 | { | 595 | { |
593 | foreach (UUID uuid in assetsNotFoundUuids) | 596 | string errorMessage; |
597 | |||
598 | if (timedOut) | ||
594 | { | 599 | { |
595 | m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); | 600 | errorMessage = "Loading assets timed out"; |
596 | } | 601 | } |
602 | else | ||
603 | { | ||
604 | foreach (UUID uuid in assetsNotFoundUuids) | ||
605 | { | ||
606 | m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); | ||
607 | } | ||
597 | 608 | ||
598 | // m_log.InfoFormat( | 609 | // m_log.InfoFormat( |
599 | // "[ARCHIVER]: Received {0} of {1} assets requested", | 610 | // "[ARCHIVER]: Received {0} of {1} assets requested", |
600 | // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); | 611 | // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); |
601 | 612 | ||
602 | CloseArchive(String.Empty); | 613 | errorMessage = String.Empty; |
614 | } | ||
615 | |||
616 | CloseArchive(errorMessage); | ||
603 | } | 617 | } |
604 | 618 | ||
605 | /// <summary> | 619 | /// <summary> |
@@ -626,4 +640,4 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
626 | m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); | 640 | m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); |
627 | } | 641 | } |
628 | } | 642 | } |
629 | } \ No newline at end of file | 643 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index 1be6386..6a09caf 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs | |||
@@ -33,11 +33,14 @@ using log4net; | |||
33 | using NDesk.Options; | 33 | using NDesk.Options; |
34 | using Nini.Config; | 34 | using Nini.Config; |
35 | using Mono.Addins; | 35 | using Mono.Addins; |
36 | |||
36 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
37 | using OpenSim.Framework.Console; | 38 | using OpenSim.Framework.Console; |
38 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
40 | 41 | ||
42 | using OpenMetaverse; | ||
43 | |||
41 | namespace OpenSim.Region.CoreModules.World.Archiver | 44 | namespace OpenSim.Region.CoreModules.World.Archiver |
42 | { | 45 | { |
43 | /// <summary> | 46 | /// <summary> |
@@ -101,9 +104,62 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
101 | { | 104 | { |
102 | bool mergeOar = false; | 105 | bool mergeOar = false; |
103 | bool skipAssets = false; | 106 | bool skipAssets = false; |
107 | bool forceTerrain = false; | ||
108 | bool forceParcels = false; | ||
109 | bool noObjects = false; | ||
110 | Vector3 displacement = new Vector3(0f, 0f, 0f); | ||
111 | String defaultUser = ""; | ||
112 | float rotation = 0f; | ||
113 | Vector3 rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0); | ||
104 | 114 | ||
105 | OptionSet options = new OptionSet().Add("m|merge", delegate (string v) { mergeOar = v != null; }); | 115 | OptionSet options = new OptionSet(); |
106 | options.Add("s|skip-assets", delegate (string v) { skipAssets = v != null; }); | 116 | options.Add("m|merge", delegate (string v) { mergeOar = (v != null); }); |
117 | options.Add("s|skip-assets", delegate (string v) { skipAssets = (v != null); }); | ||
118 | options.Add("force-terrain", delegate (string v) { forceTerrain = (v != null); }); | ||
119 | options.Add("forceterrain", delegate (string v) { forceTerrain = (v != null); }); // downward compatibility | ||
120 | options.Add("force-parcels", delegate (string v) { forceParcels = (v != null); }); | ||
121 | options.Add("forceparcels", delegate (string v) { forceParcels = (v != null); }); // downward compatibility | ||
122 | options.Add("no-objects", delegate (string v) { noObjects = (v != null); }); | ||
123 | options.Add("default-user=", delegate(string v) { defaultUser = (v == null) ? "" : v; }); | ||
124 | options.Add("displacement=", delegate (string v) { | ||
125 | try | ||
126 | { | ||
127 | displacement = v == null ? Vector3.Zero : Vector3.Parse(v); | ||
128 | } | ||
129 | catch | ||
130 | { | ||
131 | m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing displacement"); | ||
132 | m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --displacement \"<128,128,0>\""); | ||
133 | return; | ||
134 | } | ||
135 | }); | ||
136 | options.Add("rotation=", delegate(string v) | ||
137 | { | ||
138 | try | ||
139 | { | ||
140 | rotation = v == null ? 0f : float.Parse(v); | ||
141 | } | ||
142 | catch | ||
143 | { | ||
144 | m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation"); | ||
145 | m_log.ErrorFormat("[ARCHIVER MODULE] Must be an angle in degrees between -360 and +360: --rotation 45"); | ||
146 | return; | ||
147 | } | ||
148 | // Convert to radians for internals | ||
149 | rotation = Util.Clamp<float>(rotation, -359f, 359f) / 180f * (float)Math.PI; | ||
150 | }); | ||
151 | options.Add("rotation-center=", delegate (string v) { | ||
152 | try | ||
153 | { | ||
154 | rotationCenter = v == null ? Vector3.Zero : Vector3.Parse(v); | ||
155 | } | ||
156 | catch | ||
157 | { | ||
158 | m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation displacement"); | ||
159 | m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --rotation-center \"<128,128,0>\""); | ||
160 | return; | ||
161 | } | ||
162 | }); | ||
107 | 163 | ||
108 | // Send a message to the region ready module | 164 | // Send a message to the region ready module |
109 | /* bluewall* Disable this for the time being | 165 | /* bluewall* Disable this for the time being |
@@ -122,13 +178,44 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
122 | // foreach (string param in mainParams) | 178 | // foreach (string param in mainParams) |
123 | // m_log.DebugFormat("GOT PARAM [{0}]", param); | 179 | // m_log.DebugFormat("GOT PARAM [{0}]", param); |
124 | 180 | ||
181 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); | ||
182 | if (mergeOar) archiveOptions.Add("merge", null); | ||
183 | if (skipAssets) archiveOptions.Add("skipAssets", null); | ||
184 | if (forceTerrain) archiveOptions.Add("force-terrain", null); | ||
185 | if (forceParcels) archiveOptions.Add("force-parcels", null); | ||
186 | if (noObjects) archiveOptions.Add("no-objects", null); | ||
187 | if (defaultUser != "") | ||
188 | { | ||
189 | UUID defaultUserUUID = UUID.Zero; | ||
190 | try | ||
191 | { | ||
192 | defaultUserUUID = Scene.UserManagementModule.GetUserIdByName(defaultUser); | ||
193 | } | ||
194 | catch | ||
195 | { | ||
196 | m_log.ErrorFormat("[ARCHIVER MODULE] default user must be in format \"First Last\"", defaultUser); | ||
197 | } | ||
198 | if (defaultUserUUID == UUID.Zero) | ||
199 | { | ||
200 | m_log.ErrorFormat("[ARCHIVER MODULE] cannot find specified default user {0}", defaultUser); | ||
201 | return; | ||
202 | } | ||
203 | else | ||
204 | { | ||
205 | archiveOptions.Add("default-user", defaultUserUUID); | ||
206 | } | ||
207 | } | ||
208 | archiveOptions.Add("displacement", displacement); | ||
209 | archiveOptions.Add("rotation", rotation); | ||
210 | archiveOptions.Add("rotation-center", rotationCenter); | ||
211 | |||
125 | if (mainParams.Count > 2) | 212 | if (mainParams.Count > 2) |
126 | { | 213 | { |
127 | DearchiveRegion(mainParams[2], mergeOar, skipAssets, Guid.Empty); | 214 | DearchiveRegion(mainParams[2], Guid.Empty, archiveOptions); |
128 | } | 215 | } |
129 | else | 216 | else |
130 | { | 217 | { |
131 | DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, mergeOar, skipAssets, Guid.Empty); | 218 | DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, Guid.Empty, archiveOptions); |
132 | } | 219 | } |
133 | } | 220 | } |
134 | 221 | ||
@@ -198,25 +285,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
198 | 285 | ||
199 | public void DearchiveRegion(string loadPath) | 286 | public void DearchiveRegion(string loadPath) |
200 | { | 287 | { |
201 | DearchiveRegion(loadPath, false, false, Guid.Empty); | 288 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
289 | DearchiveRegion(loadPath, Guid.Empty, archiveOptions); | ||
202 | } | 290 | } |
203 | 291 | ||
204 | public void DearchiveRegion(string loadPath, bool merge, bool skipAssets, Guid requestId) | 292 | public void DearchiveRegion(string loadPath, Guid requestId, Dictionary<string,object> options) |
205 | { | 293 | { |
206 | m_log.InfoFormat( | 294 | m_log.InfoFormat( |
207 | "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); | 295 | "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); |
208 | 296 | ||
209 | new ArchiveReadRequest(Scene, loadPath, merge, skipAssets, requestId).DearchiveRegion(); | 297 | new ArchiveReadRequest(Scene, loadPath, requestId, options).DearchiveRegion(); |
210 | } | 298 | } |
211 | 299 | ||
212 | public void DearchiveRegion(Stream loadStream) | 300 | public void DearchiveRegion(Stream loadStream) |
213 | { | 301 | { |
214 | DearchiveRegion(loadStream, false, false, Guid.Empty); | 302 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
303 | DearchiveRegion(loadStream, Guid.Empty, archiveOptions); | ||
215 | } | 304 | } |
216 | 305 | ||
217 | public void DearchiveRegion(Stream loadStream, bool merge, bool skipAssets, Guid requestId) | 306 | public void DearchiveRegion(Stream loadStream, Guid requestId, Dictionary<string, object> options) |
218 | { | 307 | { |
219 | new ArchiveReadRequest(Scene, loadStream, merge, skipAssets, requestId).DearchiveRegion(); | 308 | new ArchiveReadRequest(Scene, loadStream, requestId, options).DearchiveRegion(); |
220 | } | 309 | } |
221 | } | 310 | } |
222 | } | 311 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs index 95d109c..a8eae56 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs | |||
@@ -145,17 +145,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
145 | m_assetsWritten++; | 145 | m_assetsWritten++; |
146 | 146 | ||
147 | //m_log.DebugFormat("[ARCHIVER]: Added asset {0}", m_assetsWritten); | 147 | //m_log.DebugFormat("[ARCHIVER]: Added asset {0}", m_assetsWritten); |
148 | 148 | ||
149 | if (m_assetsWritten % LOG_ASSET_LOAD_NOTIFICATION_INTERVAL == 0) | 149 | if (m_assetsWritten % LOG_ASSET_LOAD_NOTIFICATION_INTERVAL == 0) |
150 | m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); | 150 | m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); |
151 | } | 151 | } |
152 | 152 | ||
153 | /// <summary> | ||
154 | /// Only call this if you need to force a close on the underlying writer. | ||
155 | /// </summary> | ||
156 | public void ForceClose() | ||
157 | { | ||
158 | m_archiveWriter.Close(); | ||
159 | } | ||
160 | } | 153 | } |
161 | } | 154 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index 103eb47..db66c83 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs | |||
@@ -33,6 +33,7 @@ using System.Timers; | |||
33 | using log4net; | 33 | using log4net; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Monitoring; | ||
36 | using OpenSim.Framework.Serialization; | 37 | using OpenSim.Framework.Serialization; |
37 | using OpenSim.Framework.Serialization.External; | 38 | using OpenSim.Framework.Serialization.External; |
38 | using OpenSim.Services.Interfaces; | 39 | using OpenSim.Services.Interfaces; |
@@ -50,7 +51,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
50 | /// Method called when all the necessary assets for an archive request have been received. | 51 | /// Method called when all the necessary assets for an archive request have been received. |
51 | /// </summary> | 52 | /// </summary> |
52 | public delegate void AssetsRequestCallback( | 53 | public delegate void AssetsRequestCallback( |
53 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids); | 54 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut); |
54 | 55 | ||
55 | enum RequestState | 56 | enum RequestState |
56 | { | 57 | { |
@@ -81,7 +82,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
81 | /// <value> | 82 | /// <value> |
82 | /// uuids to request | 83 | /// uuids to request |
83 | /// </value> | 84 | /// </value> |
84 | protected IDictionary<UUID, AssetType> m_uuids; | 85 | protected IDictionary<UUID, sbyte> m_uuids; |
85 | 86 | ||
86 | /// <value> | 87 | /// <value> |
87 | /// Callback used when all the assets requested have been received. | 88 | /// Callback used when all the assets requested have been received. |
@@ -115,7 +116,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
115 | protected Dictionary<string, object> m_options; | 116 | protected Dictionary<string, object> m_options; |
116 | 117 | ||
117 | protected internal AssetsRequest( | 118 | protected internal AssetsRequest( |
118 | AssetsArchiver assetsArchiver, IDictionary<UUID, AssetType> uuids, | 119 | AssetsArchiver assetsArchiver, IDictionary<UUID, sbyte> uuids, |
119 | IAssetService assetService, IUserAccountService userService, | 120 | IAssetService assetService, IUserAccountService userService, |
120 | UUID scope, Dictionary<string, object> options, | 121 | UUID scope, Dictionary<string, object> options, |
121 | AssetsRequestCallback assetsRequestCallback) | 122 | AssetsRequestCallback assetsRequestCallback) |
@@ -143,19 +144,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
143 | m_requestState = RequestState.Running; | 144 | m_requestState = RequestState.Running; |
144 | 145 | ||
145 | m_log.DebugFormat("[ARCHIVER]: AssetsRequest executed looking for {0} possible assets", m_repliesRequired); | 146 | m_log.DebugFormat("[ARCHIVER]: AssetsRequest executed looking for {0} possible assets", m_repliesRequired); |
146 | 147 | ||
147 | // We can stop here if there are no assets to fetch | 148 | // We can stop here if there are no assets to fetch |
148 | if (m_repliesRequired == 0) | 149 | if (m_repliesRequired == 0) |
149 | { | 150 | { |
150 | m_requestState = RequestState.Completed; | 151 | m_requestState = RequestState.Completed; |
151 | PerformAssetsRequestCallback(null); | 152 | PerformAssetsRequestCallback(false); |
152 | return; | 153 | return; |
153 | } | 154 | } |
154 | 155 | ||
155 | m_requestCallbackTimer.Enabled = true; | 156 | m_requestCallbackTimer.Enabled = true; |
156 | 157 | ||
157 | foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids) | 158 | foreach (KeyValuePair<UUID, sbyte> kvp in m_uuids) |
158 | { | 159 | { |
160 | // m_log.DebugFormat("[ARCHIVER]: Requesting asset {0}", kvp.Key); | ||
161 | |||
159 | // m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); | 162 | // m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); |
160 | AssetBase asset = m_assetService.Get(kvp.Key.ToString()); | 163 | AssetBase asset = m_assetService.Get(kvp.Key.ToString()); |
161 | PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset); | 164 | PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset); |
@@ -164,7 +167,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
164 | 167 | ||
165 | protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) | 168 | protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) |
166 | { | 169 | { |
167 | bool close = true; | 170 | bool timedOut = true; |
168 | 171 | ||
169 | try | 172 | try |
170 | { | 173 | { |
@@ -174,7 +177,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
174 | // the final request came in (assuming that such a thing is possible) | 177 | // the final request came in (assuming that such a thing is possible) |
175 | if (m_requestState == RequestState.Completed) | 178 | if (m_requestState == RequestState.Completed) |
176 | { | 179 | { |
177 | close = false; | 180 | timedOut = false; |
178 | return; | 181 | return; |
179 | } | 182 | } |
180 | 183 | ||
@@ -223,8 +226,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
223 | } | 226 | } |
224 | finally | 227 | finally |
225 | { | 228 | { |
226 | if (close) | 229 | if (timedOut) |
227 | m_assetsArchiver.ForceClose(); | 230 | WorkManager.RunInThread(PerformAssetsRequestCallback, true, "Archive Assets Request Callback"); |
228 | } | 231 | } |
229 | } | 232 | } |
230 | 233 | ||
@@ -233,9 +236,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
233 | // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer | 236 | // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer |
234 | if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown) | 237 | if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown) |
235 | { | 238 | { |
236 | AssetType type = (AssetType)assetType; | 239 | m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, SLUtil.AssetTypeFromCode((sbyte)assetType)); |
237 | m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, type); | 240 | fetchedAsset.Type = (sbyte)assetType; |
238 | fetchedAsset.Type = (sbyte)type; | ||
239 | } | 241 | } |
240 | 242 | ||
241 | AssetRequestCallback(fetchedAssetID, this, fetchedAsset); | 243 | AssetRequestCallback(fetchedAssetID, this, fetchedAsset); |
@@ -294,7 +296,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
294 | 296 | ||
295 | // We want to stop using the asset cache thread asap | 297 | // We want to stop using the asset cache thread asap |
296 | // as we now need to do the work of producing the rest of the archive | 298 | // as we now need to do the work of producing the rest of the archive |
297 | Util.FireAndForget(PerformAssetsRequestCallback); | 299 | WorkManager.RunInThread(PerformAssetsRequestCallback, false, "Archive Assets Request Callback"); |
298 | } | 300 | } |
299 | else | 301 | else |
300 | { | 302 | { |
@@ -315,9 +317,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
315 | { | 317 | { |
316 | Culture.SetCurrentCulture(); | 318 | Culture.SetCurrentCulture(); |
317 | 319 | ||
320 | Boolean timedOut = (Boolean)o; | ||
321 | |||
318 | try | 322 | try |
319 | { | 323 | { |
320 | m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids); | 324 | m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids, timedOut); |
321 | } | 325 | } |
322 | catch (Exception e) | 326 | catch (Exception e) |
323 | { | 327 | { |
@@ -331,7 +335,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
331 | if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) | 335 | if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) |
332 | { | 336 | { |
333 | //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); | 337 | //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); |
334 | string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), m_options["home"].ToString(), m_userAccountService, m_scopeID); | 338 | string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), string.Empty, m_options["home"].ToString(), m_userAccountService, m_scopeID); |
335 | asset.Data = Utils.StringToBytes(xml); | 339 | asset.Data = Utils.StringToBytes(xml); |
336 | } | 340 | } |
337 | return asset; | 341 | return asset; |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index eec1cec..9f197f5 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs | |||
@@ -45,7 +45,6 @@ using OpenSim.Region.Framework.Scenes; | |||
45 | using OpenSim.Region.Framework.Scenes.Serialization; | 45 | using OpenSim.Region.Framework.Scenes.Serialization; |
46 | using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; | 46 | using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; |
47 | using OpenSim.Tests.Common; | 47 | using OpenSim.Tests.Common; |
48 | using OpenSim.Tests.Common.Mock; | ||
49 | using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; | 48 | using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; |
50 | using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; | 49 | using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; |
51 | using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; | 50 | using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; |
@@ -224,8 +223,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
224 | 223 | ||
225 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); | 224 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); |
226 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | 225 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); |
227 | 226 | ||
228 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | 227 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
228 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); | ||
229 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); | 229 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); |
230 | 230 | ||
231 | Assert.That(arr.ControlFileLoaded, Is.True); | 231 | Assert.That(arr.ControlFileLoaded, Is.True); |
@@ -308,8 +308,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
308 | 308 | ||
309 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); | 309 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); |
310 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | 310 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); |
311 | 311 | ||
312 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | 312 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
313 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); | ||
313 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); | 314 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); |
314 | 315 | ||
315 | Assert.That(arr.ControlFileLoaded, Is.True); | 316 | Assert.That(arr.ControlFileLoaded, Is.True); |
@@ -577,13 +578,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
577 | ArchiveConstants.CONTROL_FILE_PATH, | 578 | ArchiveConstants.CONTROL_FILE_PATH, |
578 | new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); | 579 | new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); |
579 | 580 | ||
580 | LandObject lo = new LandObject(groupID, true, null); | 581 | LandObject lo = new LandObject(groupID, true, m_scene); |
581 | lo.SetLandBitmap(lo.BasicFullRegionLandBitmap()); | 582 | lo.SetLandBitmap(lo.BasicFullRegionLandBitmap()); |
582 | LandData ld = lo.LandData; | 583 | LandData ld = lo.LandData; |
583 | ld.GlobalID = landID; | 584 | ld.GlobalID = landID; |
584 | 585 | ||
585 | string ldPath = ArchiveConstants.CreateOarLandDataPath(ld); | 586 | string ldPath = ArchiveConstants.CreateOarLandDataPath(ld); |
586 | tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null)); | 587 | Dictionary<string, object> options = new Dictionary<string, object>(); |
588 | tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, options)); | ||
587 | tar.Close(); | 589 | tar.Close(); |
588 | 590 | ||
589 | oarStream = new MemoryStream(oarStream.ToArray()); | 591 | oarStream = new MemoryStream(oarStream.ToArray()); |
@@ -752,7 +754,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
752 | byte[] archive = archiveWriteStream.ToArray(); | 754 | byte[] archive = archiveWriteStream.ToArray(); |
753 | MemoryStream archiveReadStream = new MemoryStream(archive); | 755 | MemoryStream archiveReadStream = new MemoryStream(archive); |
754 | 756 | ||
755 | m_archiverModule.DearchiveRegion(archiveReadStream, true, false, Guid.Empty); | 757 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
758 | archiveOptions.Add("merge", null); | ||
759 | m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions); | ||
756 | 760 | ||
757 | SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); | 761 | SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); |
758 | Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); | 762 | Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); |
@@ -860,7 +864,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
860 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); | 864 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); |
861 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | 865 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); |
862 | 866 | ||
863 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | 867 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
868 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); | ||
864 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); | 869 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); |
865 | 870 | ||
866 | Assert.That(arr.ControlFileLoaded, Is.True); | 871 | Assert.That(arr.ControlFileLoaded, Is.True); |
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs index 4d49794..702b503 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs | |||
@@ -39,6 +39,7 @@ using OpenSim.Framework.Console; | |||
39 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | 39 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; |
40 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Services.Interfaces; | ||
42 | 43 | ||
43 | namespace OpenSim.Region.CoreModules.World.Estate | 44 | namespace OpenSim.Region.CoreModules.World.Estate |
44 | { | 45 | { |
@@ -50,9 +51,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
51 | 52 | ||
52 | protected EstateManagementModule m_module; | 53 | protected EstateManagementModule m_module; |
53 | 54 | ||
54 | protected Commander m_commander = new Commander("estate"); | ||
55 | |||
56 | public EstateManagementCommands(EstateManagementModule module) | 55 | public EstateManagementCommands(EstateManagementModule module) |
57 | { | 56 | { |
58 | m_module = module; | 57 | m_module = module; |
@@ -60,7 +59,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
60 | 59 | ||
61 | public void Initialise() | 60 | public void Initialise() |
62 | { | 61 | { |
63 | m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName); | 62 | // m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName); |
64 | 63 | ||
65 | m_module.Scene.AddCommand("Regions", m_module, "set terrain texture", | 64 | m_module.Scene.AddCommand("Regions", m_module, "set terrain texture", |
66 | "set terrain texture <number> <uuid> [<x>] [<y>]", | 65 | "set terrain texture <number> <uuid> [<x>] [<y>]", |
@@ -76,12 +75,19 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
76 | " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.", | 75 | " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.", |
77 | consoleSetTerrainHeights); | 76 | consoleSetTerrainHeights); |
78 | 77 | ||
78 | m_module.Scene.AddCommand("Regions", m_module, "set water height", | ||
79 | "set water height <height> [<x>] [<y>]", | ||
80 | "Sets the water height in meters. If <x> and <y> are specified, it will only set it on regions with a matching coordinate. " + | ||
81 | "Specify -1 in <x> or <y> to wildcard that coordinate.", | ||
82 | consoleSetWaterHeight); | ||
83 | |||
79 | m_module.Scene.AddCommand( | 84 | m_module.Scene.AddCommand( |
80 | "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand); | 85 | "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand); |
81 | } | 86 | } |
82 | 87 | ||
83 | public void Close() {} | 88 | public void Close() {} |
84 | 89 | ||
90 | #region CommandHandlers | ||
85 | protected void consoleSetTerrainTexture(string module, string[] args) | 91 | protected void consoleSetTerrainTexture(string module, string[] args) |
86 | { | 92 | { |
87 | string num = args[3]; | 93 | string num = args[3]; |
@@ -121,7 +127,29 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
121 | } | 127 | } |
122 | } | 128 | } |
123 | } | 129 | } |
124 | 130 | protected void consoleSetWaterHeight(string module, string[] args) | |
131 | { | ||
132 | string heightstring = args[3]; | ||
133 | |||
134 | int x = (args.Length > 4 ? int.Parse(args[4]) : -1); | ||
135 | int y = (args.Length > 5 ? int.Parse(args[5]) : -1); | ||
136 | |||
137 | if (x == -1 || m_module.Scene.RegionInfo.RegionLocX == x) | ||
138 | { | ||
139 | if (y == -1 || m_module.Scene.RegionInfo.RegionLocY == y) | ||
140 | { | ||
141 | double selectedheight = double.Parse(heightstring); | ||
142 | |||
143 | m_log.Debug("[ESTATEMODULE]: Setting water height in " + m_module.Scene.RegionInfo.RegionName + " to " + | ||
144 | string.Format(" {0}", selectedheight)); | ||
145 | m_module.Scene.RegionInfo.RegionSettings.WaterHeight = selectedheight; | ||
146 | |||
147 | m_module.Scene.RegionInfo.RegionSettings.Save(); | ||
148 | m_module.TriggerRegionInfoChange(); | ||
149 | m_module.sendRegionHandshakeToAll(); | ||
150 | } | ||
151 | } | ||
152 | } | ||
125 | protected void consoleSetTerrainHeights(string module, string[] args) | 153 | protected void consoleSetTerrainHeights(string module, string[] args) |
126 | { | 154 | { |
127 | string num = args[3]; | 155 | string num = args[3]; |
@@ -196,6 +224,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
196 | es.EstateName, es.EstateID, m_module.UserManager.GetUserName(es.EstateOwner)); | 224 | es.EstateName, es.EstateID, m_module.UserManager.GetUserName(es.EstateOwner)); |
197 | 225 | ||
198 | MainConsole.Instance.Output(report.ToString()); | 226 | MainConsole.Instance.Output(report.ToString()); |
199 | } | 227 | } |
228 | #endregion | ||
200 | } | 229 | } |
201 | } \ No newline at end of file | 230 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 311707b..80fa08a 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs | |||
@@ -32,6 +32,7 @@ using System.IO; | |||
32 | using System.Linq; | 32 | using System.Linq; |
33 | using System.Reflection; | 33 | using System.Reflection; |
34 | using System.Security; | 34 | using System.Security; |
35 | using System.Timers; | ||
35 | using log4net; | 36 | using log4net; |
36 | using Mono.Addins; | 37 | using Mono.Addins; |
37 | using Nini.Config; | 38 | using Nini.Config; |
@@ -39,6 +40,7 @@ using OpenMetaverse; | |||
39 | using OpenSim.Framework; | 40 | using OpenSim.Framework; |
40 | using OpenSim.Region.Framework.Interfaces; | 41 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Framework.Scenes; | 42 | using OpenSim.Region.Framework.Scenes; |
43 | using OpenSim.Services.Interfaces; | ||
42 | using RegionFlags = OpenMetaverse.RegionFlags; | 44 | using RegionFlags = OpenMetaverse.RegionFlags; |
43 | 45 | ||
44 | namespace OpenSim.Region.CoreModules.World.Estate | 46 | namespace OpenSim.Region.CoreModules.World.Estate |
@@ -48,6 +50,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
48 | { | 50 | { |
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
50 | 52 | ||
53 | private Timer m_regionChangeTimer = new Timer(); | ||
51 | public Scene Scene { get; private set; } | 54 | public Scene Scene { get; private set; } |
52 | public IUserManagement UserManager { get; private set; } | 55 | public IUserManagement UserManager { get; private set; } |
53 | 56 | ||
@@ -112,13 +115,287 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
112 | 115 | ||
113 | #endregion | 116 | #endregion |
114 | 117 | ||
118 | #region IEstateModule Functions | ||
119 | public uint GetRegionFlags() | ||
120 | { | ||
121 | RegionFlags flags = RegionFlags.None; | ||
122 | |||
123 | // Fully implemented | ||
124 | // | ||
125 | if (Scene.RegionInfo.RegionSettings.AllowDamage) | ||
126 | flags |= RegionFlags.AllowDamage; | ||
127 | if (Scene.RegionInfo.RegionSettings.BlockTerraform) | ||
128 | flags |= RegionFlags.BlockTerraform; | ||
129 | if (!Scene.RegionInfo.RegionSettings.AllowLandResell) | ||
130 | flags |= RegionFlags.BlockLandResell; | ||
131 | if (Scene.RegionInfo.RegionSettings.DisableCollisions) | ||
132 | flags |= RegionFlags.SkipCollisions; | ||
133 | if (Scene.RegionInfo.RegionSettings.DisableScripts) | ||
134 | flags |= RegionFlags.SkipScripts; | ||
135 | if (Scene.RegionInfo.RegionSettings.DisablePhysics) | ||
136 | flags |= RegionFlags.SkipPhysics; | ||
137 | if (Scene.RegionInfo.RegionSettings.BlockFly) | ||
138 | flags |= RegionFlags.NoFly; | ||
139 | if (Scene.RegionInfo.RegionSettings.RestrictPushing) | ||
140 | flags |= RegionFlags.RestrictPushObject; | ||
141 | if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide) | ||
142 | flags |= RegionFlags.AllowParcelChanges; | ||
143 | if (Scene.RegionInfo.RegionSettings.BlockShowInSearch) | ||
144 | flags |= RegionFlags.BlockParcelSearch; | ||
145 | |||
146 | if (Scene.RegionInfo.RegionSettings.FixedSun) | ||
147 | flags |= RegionFlags.SunFixed; | ||
148 | if (Scene.RegionInfo.RegionSettings.Sandbox) | ||
149 | flags |= RegionFlags.Sandbox; | ||
150 | if (Scene.RegionInfo.EstateSettings.AllowVoice) | ||
151 | flags |= RegionFlags.AllowVoice; | ||
152 | if (Scene.RegionInfo.EstateSettings.AllowLandmark) | ||
153 | flags |= RegionFlags.AllowLandmark; | ||
154 | if (Scene.RegionInfo.EstateSettings.AllowSetHome) | ||
155 | flags |= RegionFlags.AllowSetHome; | ||
156 | if (Scene.RegionInfo.EstateSettings.BlockDwell) | ||
157 | flags |= RegionFlags.BlockDwell; | ||
158 | if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport) | ||
159 | flags |= RegionFlags.ResetHomeOnTeleport; | ||
160 | |||
161 | |||
162 | // TODO: SkipUpdateInterestList | ||
163 | |||
164 | // Omitted | ||
165 | // | ||
166 | // Omitted: NullLayer (what is that?) | ||
167 | // Omitted: SkipAgentAction (what does it do?) | ||
168 | |||
169 | return (uint)flags; | ||
170 | } | ||
171 | |||
172 | public bool IsManager(UUID avatarID) | ||
173 | { | ||
174 | if (avatarID == Scene.RegionInfo.EstateSettings.EstateOwner) | ||
175 | return true; | ||
176 | |||
177 | List<UUID> ems = new List<UUID>(Scene.RegionInfo.EstateSettings.EstateManagers); | ||
178 | if (ems.Contains(avatarID)) | ||
179 | return true; | ||
180 | |||
181 | return false; | ||
182 | } | ||
183 | |||
184 | public void sendRegionHandshakeToAll() | ||
185 | { | ||
186 | Scene.ForEachClient(sendRegionHandshake); | ||
187 | } | ||
188 | |||
189 | public void TriggerEstateInfoChange() | ||
190 | { | ||
191 | ChangeDelegate change = OnEstateInfoChange; | ||
192 | |||
193 | if (change != null) | ||
194 | change(Scene.RegionInfo.RegionID); | ||
195 | } | ||
196 | |||
197 | public void TriggerRegionInfoChange() | ||
198 | { | ||
199 | m_regionChangeTimer.Stop(); | ||
200 | m_regionChangeTimer.Start(); | ||
201 | |||
202 | ChangeDelegate change = OnRegionInfoChange; | ||
203 | |||
204 | if (change != null) | ||
205 | change(Scene.RegionInfo.RegionID); | ||
206 | } | ||
207 | |||
208 | public void setEstateTerrainBaseTexture(int level, UUID texture) | ||
209 | { | ||
210 | setEstateTerrainBaseTexture(null, level, texture); | ||
211 | sendRegionHandshakeToAll(); | ||
212 | } | ||
213 | |||
214 | public void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue) | ||
215 | { | ||
216 | setEstateTerrainTextureHeights(null, corner, lowValue, highValue); | ||
217 | } | ||
218 | |||
219 | public bool IsTerrainXfer(ulong xferID) | ||
220 | { | ||
221 | lock (this) | ||
222 | { | ||
223 | if (TerrainUploader == null) | ||
224 | return false; | ||
225 | else | ||
226 | return TerrainUploader.XferID == xferID; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | public string SetEstateOwner(int estateID, UserAccount account) | ||
231 | { | ||
232 | string response; | ||
233 | |||
234 | // get the current settings from DB | ||
235 | EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | ||
236 | if (dbSettings.EstateID == 0) | ||
237 | { | ||
238 | response = String.Format("No estate found with ID {0}", estateID); | ||
239 | } | ||
240 | else if (account.PrincipalID == dbSettings.EstateOwner) | ||
241 | { | ||
242 | response = String.Format("Estate already belongs to {0} ({1} {2})", account.PrincipalID, account.FirstName, account.LastName); | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | dbSettings.EstateOwner = account.PrincipalID; | ||
247 | Scene.EstateDataService.StoreEstateSettings(dbSettings); | ||
248 | response = String.Empty; | ||
249 | |||
250 | // make sure there's a log entry to document the change | ||
251 | m_log.InfoFormat("[ESTATE]: Estate Owner for {0} changed to {1} ({2} {3})", dbSettings.EstateName, | ||
252 | account.PrincipalID, account.FirstName, account.LastName); | ||
253 | |||
254 | // propagate the change | ||
255 | List<UUID> regions = Scene.GetEstateRegions(estateID); | ||
256 | UUID regionId = (regions.Count() > 0) ? regions.ElementAt(0) : UUID.Zero; | ||
257 | if (regionId != UUID.Zero) | ||
258 | { | ||
259 | ChangeDelegate change = OnEstateInfoChange; | ||
260 | |||
261 | if (change != null) | ||
262 | change(regionId); | ||
263 | } | ||
264 | |||
265 | } | ||
266 | return response; | ||
267 | } | ||
268 | |||
269 | public string SetEstateName(int estateID, string newName) | ||
270 | { | ||
271 | string response; | ||
272 | |||
273 | // get the current settings from DB | ||
274 | EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | ||
275 | |||
276 | if (dbSettings.EstateID == 0) | ||
277 | { | ||
278 | response = String.Format("No estate found with ID {0}", estateID); | ||
279 | } | ||
280 | else if (newName == dbSettings.EstateName) | ||
281 | { | ||
282 | response = String.Format("Estate {0} is already named \"{1}\"", estateID, newName); | ||
283 | } | ||
284 | else | ||
285 | { | ||
286 | List<int> estates = Scene.EstateDataService.GetEstates(newName); | ||
287 | if (estates.Count() > 0) | ||
288 | { | ||
289 | response = String.Format("An estate named \"{0}\" already exists.", newName); | ||
290 | } | ||
291 | else | ||
292 | { | ||
293 | string oldName = dbSettings.EstateName; | ||
294 | dbSettings.EstateName = newName; | ||
295 | Scene.EstateDataService.StoreEstateSettings(dbSettings); | ||
296 | response = String.Empty; | ||
297 | |||
298 | // make sure there's a log entry to document the change | ||
299 | m_log.InfoFormat("[ESTATE]: Estate {0} renamed from \"{1}\" to \"{2}\"", estateID, oldName, newName); | ||
300 | |||
301 | // propagate the change | ||
302 | List<UUID> regions = Scene.GetEstateRegions(estateID); | ||
303 | UUID regionId = (regions.Count() > 0) ? regions.ElementAt(0) : UUID.Zero; | ||
304 | if (regionId != UUID.Zero) | ||
305 | { | ||
306 | ChangeDelegate change = OnEstateInfoChange; | ||
307 | |||
308 | if (change != null) | ||
309 | change(regionId); | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | return response; | ||
314 | } | ||
315 | |||
316 | public string SetRegionEstate(RegionInfo regionInfo, int estateID) | ||
317 | { | ||
318 | string response; | ||
319 | |||
320 | if (regionInfo.EstateSettings.EstateID == estateID) | ||
321 | { | ||
322 | response = String.Format("\"{0}\" is already part of estate {1}", regionInfo.RegionName, estateID); | ||
323 | } | ||
324 | else | ||
325 | { | ||
326 | // get the current settings from DB | ||
327 | EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | ||
328 | if (dbSettings.EstateID == 0) | ||
329 | { | ||
330 | response = String.Format("No estate found with ID {0}", estateID); | ||
331 | } | ||
332 | else if (Scene.EstateDataService.LinkRegion(regionInfo.RegionID, estateID)) | ||
333 | { | ||
334 | // make sure there's a log entry to document the change | ||
335 | m_log.InfoFormat("[ESTATE]: Region {0} ({1}) moved to Estate {2} ({3}).", regionInfo.RegionID, regionInfo.RegionName, estateID, dbSettings.EstateName); | ||
336 | |||
337 | // propagate the change | ||
338 | ChangeDelegate change = OnEstateInfoChange; | ||
339 | |||
340 | if (change != null) | ||
341 | change(regionInfo.RegionID); | ||
342 | |||
343 | response = String.Empty; | ||
344 | } | ||
345 | else | ||
346 | { | ||
347 | response = String.Format("Could not move \"{0}\" to estate {1}", regionInfo.RegionName, estateID); | ||
348 | } | ||
349 | } | ||
350 | return response; | ||
351 | } | ||
352 | |||
353 | public string CreateEstate(string estateName, UUID ownerID) | ||
354 | { | ||
355 | string response; | ||
356 | if (string.IsNullOrEmpty(estateName)) | ||
357 | { | ||
358 | response = "No estate name specified."; | ||
359 | } | ||
360 | else | ||
361 | { | ||
362 | List<int> estates = Scene.EstateDataService.GetEstates(estateName); | ||
363 | if (estates.Count() > 0) | ||
364 | { | ||
365 | response = String.Format("An estate named \"{0}\" already exists.", estateName); | ||
366 | } | ||
367 | else | ||
368 | { | ||
369 | EstateSettings settings = Scene.EstateDataService.CreateNewEstate(); | ||
370 | if (settings == null) | ||
371 | response = String.Format("Unable to create estate \"{0}\" at this simulator", estateName); | ||
372 | else | ||
373 | { | ||
374 | settings.EstateOwner = ownerID; | ||
375 | settings.EstateName = estateName; | ||
376 | Scene.EstateDataService.StoreEstateSettings(settings); | ||
377 | response = String.Empty; | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | return response; | ||
382 | } | ||
383 | |||
384 | #endregion | ||
385 | |||
115 | #region Packet Data Responders | 386 | #region Packet Data Responders |
116 | 387 | ||
388 | private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice) | ||
389 | { | ||
390 | sendDetailedEstateData(remote_client, invoice); | ||
391 | sendEstateLists(remote_client, invoice); | ||
392 | } | ||
393 | |||
117 | private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice) | 394 | private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice) |
118 | { | 395 | { |
119 | uint sun = 0; | 396 | uint sun = 0; |
120 | 397 | ||
121 | if (!Scene.RegionInfo.EstateSettings.UseGlobalTime) | 398 | if (Scene.RegionInfo.EstateSettings.FixedSun) |
122 | sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800; | 399 | sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800; |
123 | UUID estateOwner; | 400 | UUID estateOwner; |
124 | estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner; | 401 | estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner; |
@@ -136,7 +413,10 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
136 | (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime, | 413 | (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime, |
137 | Scene.RegionInfo.EstateSettings.AbuseEmail, | 414 | Scene.RegionInfo.EstateSettings.AbuseEmail, |
138 | estateOwner); | 415 | estateOwner); |
416 | } | ||
139 | 417 | ||
418 | private void sendEstateLists(IClientAPI remote_client, UUID invoice) | ||
419 | { | ||
140 | remote_client.SendEstateList(invoice, | 420 | remote_client.SendEstateList(invoice, |
141 | (int)Constants.EstateAccessCodex.EstateManagers, | 421 | (int)Constants.EstateAccessCodex.EstateManagers, |
142 | Scene.RegionInfo.EstateSettings.EstateManagers, | 422 | Scene.RegionInfo.EstateSettings.EstateManagers, |
@@ -210,12 +490,6 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
210 | sendRegionInfoPacketToAll(); | 490 | sendRegionInfoPacketToAll(); |
211 | } | 491 | } |
212 | 492 | ||
213 | public void setEstateTerrainBaseTexture(int level, UUID texture) | ||
214 | { | ||
215 | setEstateTerrainBaseTexture(null, level, texture); | ||
216 | sendRegionHandshakeToAll(); | ||
217 | } | ||
218 | |||
219 | public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int level, UUID texture) | 493 | public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int level, UUID texture) |
220 | { | 494 | { |
221 | if (texture == UUID.Zero) | 495 | if (texture == UUID.Zero) |
@@ -242,11 +516,6 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
242 | sendRegionInfoPacketToAll(); | 516 | sendRegionInfoPacketToAll(); |
243 | } | 517 | } |
244 | 518 | ||
245 | public void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue) | ||
246 | { | ||
247 | setEstateTerrainTextureHeights(null, corner, lowValue, highValue); | ||
248 | } | ||
249 | |||
250 | public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue) | 519 | public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue) |
251 | { | 520 | { |
252 | switch (corner) | 521 | switch (corner) |
@@ -330,7 +599,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
330 | timeInSeconds -= 15; | 599 | timeInSeconds -= 15; |
331 | } | 600 | } |
332 | 601 | ||
333 | restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); | 602 | restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), false); |
334 | 603 | ||
335 | m_log.InfoFormat( | 604 | m_log.InfoFormat( |
336 | "User {0} requested restart of region {1} in {2} seconds", | 605 | "User {0} requested restart of region {1} in {2} seconds", |
@@ -372,13 +641,13 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
372 | { | 641 | { |
373 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | 642 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); |
374 | estateSettings.AddEstateUser(user); | 643 | estateSettings.AddEstateUser(user); |
375 | estateSettings.Save(); | 644 | Scene.EstateDataService.StoreEstateSettings(estateSettings); |
376 | } | 645 | } |
377 | } | 646 | } |
378 | } | 647 | } |
379 | 648 | ||
380 | Scene.RegionInfo.EstateSettings.AddEstateUser(user); | 649 | Scene.RegionInfo.EstateSettings.AddEstateUser(user); |
381 | Scene.RegionInfo.EstateSettings.Save(); | 650 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
382 | 651 | ||
383 | TriggerEstateInfoChange(); | 652 | TriggerEstateInfoChange(); |
384 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); | 653 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); |
@@ -405,13 +674,13 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
405 | { | 674 | { |
406 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | 675 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); |
407 | estateSettings.RemoveEstateUser(user); | 676 | estateSettings.RemoveEstateUser(user); |
408 | estateSettings.Save(); | 677 | Scene.EstateDataService.StoreEstateSettings(estateSettings); |
409 | } | 678 | } |
410 | } | 679 | } |
411 | } | 680 | } |
412 | 681 | ||
413 | Scene.RegionInfo.EstateSettings.RemoveEstateUser(user); | 682 | Scene.RegionInfo.EstateSettings.RemoveEstateUser(user); |
414 | Scene.RegionInfo.EstateSettings.Save(); | 683 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
415 | 684 | ||
416 | TriggerEstateInfoChange(); | 685 | TriggerEstateInfoChange(); |
417 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); | 686 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); |
@@ -437,13 +706,13 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
437 | { | 706 | { |
438 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | 707 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); |
439 | estateSettings.AddEstateGroup(user); | 708 | estateSettings.AddEstateGroup(user); |
440 | estateSettings.Save(); | 709 | Scene.EstateDataService.StoreEstateSettings(estateSettings); |
441 | } | 710 | } |
442 | } | 711 | } |
443 | } | 712 | } |
444 | 713 | ||
445 | Scene.RegionInfo.EstateSettings.AddEstateGroup(user); | 714 | Scene.RegionInfo.EstateSettings.AddEstateGroup(user); |
446 | Scene.RegionInfo.EstateSettings.Save(); | 715 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
447 | 716 | ||
448 | TriggerEstateInfoChange(); | 717 | TriggerEstateInfoChange(); |
449 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); | 718 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); |
@@ -469,13 +738,13 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
469 | { | 738 | { |
470 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | 739 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); |
471 | estateSettings.RemoveEstateGroup(user); | 740 | estateSettings.RemoveEstateGroup(user); |
472 | estateSettings.Save(); | 741 | Scene.EstateDataService.StoreEstateSettings(estateSettings); |
473 | } | 742 | } |
474 | } | 743 | } |
475 | } | 744 | } |
476 | 745 | ||
477 | Scene.RegionInfo.EstateSettings.RemoveEstateGroup(user); | 746 | Scene.RegionInfo.EstateSettings.RemoveEstateGroup(user); |
478 | Scene.RegionInfo.EstateSettings.Save(); | 747 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
479 | 748 | ||
480 | TriggerEstateInfoChange(); | 749 | TriggerEstateInfoChange(); |
481 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); | 750 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); |
@@ -524,7 +793,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
524 | 793 | ||
525 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | 794 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); |
526 | estateSettings.AddBan(bitem); | 795 | estateSettings.AddBan(bitem); |
527 | estateSettings.Save(); | 796 | Scene.EstateDataService.StoreEstateSettings(estateSettings); |
528 | } | 797 | } |
529 | } | 798 | } |
530 | } | 799 | } |
@@ -537,7 +806,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
537 | item.BannedHostIPMask = "0.0.0.0"; | 806 | item.BannedHostIPMask = "0.0.0.0"; |
538 | 807 | ||
539 | Scene.RegionInfo.EstateSettings.AddBan(item); | 808 | Scene.RegionInfo.EstateSettings.AddBan(item); |
540 | Scene.RegionInfo.EstateSettings.Save(); | 809 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
541 | 810 | ||
542 | TriggerEstateInfoChange(); | 811 | TriggerEstateInfoChange(); |
543 | 812 | ||
@@ -546,7 +815,11 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
546 | { | 815 | { |
547 | if (!s.IsChildAgent) | 816 | if (!s.IsChildAgent) |
548 | { | 817 | { |
549 | Scene.TeleportClientHome(user, s.ControllingClient); | 818 | if (!Scene.TeleportClientHome(user, s.ControllingClient)) |
819 | { | ||
820 | s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); | ||
821 | Scene.CloseAgent(s.UUID, false); | ||
822 | } | ||
550 | } | 823 | } |
551 | } | 824 | } |
552 | 825 | ||
@@ -555,7 +828,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
555 | { | 828 | { |
556 | remote_client.SendAlertMessage("User is already on the region ban list"); | 829 | remote_client.SendAlertMessage("User is already on the region ban list"); |
557 | } | 830 | } |
558 | //m_scene.RegionInfo.regionBanlist.Add(Manager(user); | 831 | //Scene.RegionInfo.regionBanlist.Add(Manager(user); |
559 | remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); | 832 | remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); |
560 | } | 833 | } |
561 | else | 834 | else |
@@ -596,13 +869,13 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
596 | { | 869 | { |
597 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | 870 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); |
598 | estateSettings.RemoveBan(user); | 871 | estateSettings.RemoveBan(user); |
599 | estateSettings.Save(); | 872 | Scene.EstateDataService.StoreEstateSettings(estateSettings); |
600 | } | 873 | } |
601 | } | 874 | } |
602 | } | 875 | } |
603 | 876 | ||
604 | Scene.RegionInfo.EstateSettings.RemoveBan(listitem.BannedUserID); | 877 | Scene.RegionInfo.EstateSettings.RemoveBan(listitem.BannedUserID); |
605 | Scene.RegionInfo.EstateSettings.Save(); | 878 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
606 | 879 | ||
607 | TriggerEstateInfoChange(); | 880 | TriggerEstateInfoChange(); |
608 | } | 881 | } |
@@ -611,7 +884,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
611 | remote_client.SendAlertMessage("User is not on the region ban list"); | 884 | remote_client.SendAlertMessage("User is not on the region ban list"); |
612 | } | 885 | } |
613 | 886 | ||
614 | //m_scene.RegionInfo.regionBanlist.Add(Manager(user); | 887 | //Scene.RegionInfo.regionBanlist.Add(Manager(user); |
615 | remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); | 888 | remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); |
616 | } | 889 | } |
617 | else | 890 | else |
@@ -635,13 +908,13 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
635 | { | 908 | { |
636 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | 909 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); |
637 | estateSettings.AddEstateManager(user); | 910 | estateSettings.AddEstateManager(user); |
638 | estateSettings.Save(); | 911 | Scene.EstateDataService.StoreEstateSettings(estateSettings); |
639 | } | 912 | } |
640 | } | 913 | } |
641 | } | 914 | } |
642 | 915 | ||
643 | Scene.RegionInfo.EstateSettings.AddEstateManager(user); | 916 | Scene.RegionInfo.EstateSettings.AddEstateManager(user); |
644 | Scene.RegionInfo.EstateSettings.Save(); | 917 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
645 | 918 | ||
646 | TriggerEstateInfoChange(); | 919 | TriggerEstateInfoChange(); |
647 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); | 920 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); |
@@ -667,13 +940,13 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
667 | { | 940 | { |
668 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); | 941 | estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); |
669 | estateSettings.RemoveEstateManager(user); | 942 | estateSettings.RemoveEstateManager(user); |
670 | estateSettings.Save(); | 943 | Scene.EstateDataService.StoreEstateSettings(estateSettings); |
671 | } | 944 | } |
672 | } | 945 | } |
673 | } | 946 | } |
674 | 947 | ||
675 | Scene.RegionInfo.EstateSettings.RemoveEstateManager(user); | 948 | Scene.RegionInfo.EstateSettings.RemoveEstateManager(user); |
676 | Scene.RegionInfo.EstateSettings.Save(); | 949 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
677 | 950 | ||
678 | TriggerEstateInfoChange(); | 951 | TriggerEstateInfoChange(); |
679 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); | 952 | remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); |
@@ -685,7 +958,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
685 | } | 958 | } |
686 | } | 959 | } |
687 | 960 | ||
688 | public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) | 961 | public void HandleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) |
689 | { | 962 | { |
690 | SceneObjectPart part; | 963 | SceneObjectPart part; |
691 | 964 | ||
@@ -725,7 +998,9 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
725 | default: | 998 | default: |
726 | break; | 999 | break; |
727 | } | 1000 | } |
728 | SendTelehubInfo(client); | 1001 | |
1002 | if (client != null) | ||
1003 | SendTelehubInfo(client); | ||
729 | } | 1004 | } |
730 | 1005 | ||
731 | private void SendSimulatorBlueBoxMessage( | 1006 | private void SendSimulatorBlueBoxMessage( |
@@ -777,7 +1052,11 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
777 | ScenePresence s = Scene.GetScenePresence(prey); | 1052 | ScenePresence s = Scene.GetScenePresence(prey); |
778 | if (s != null) | 1053 | if (s != null) |
779 | { | 1054 | { |
780 | Scene.TeleportClientHome(prey, s.ControllingClient); | 1055 | if (!Scene.TeleportClientHome(prey, s.ControllingClient)) |
1056 | { | ||
1057 | s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); | ||
1058 | Scene.CloseAgent(s.UUID, false); | ||
1059 | } | ||
781 | } | 1060 | } |
782 | } | 1061 | } |
783 | } | 1062 | } |
@@ -795,33 +1074,36 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
795 | // Also make sure they are actually in the region | 1074 | // Also make sure they are actually in the region |
796 | ScenePresence p; | 1075 | ScenePresence p; |
797 | if(Scene.TryGetScenePresence(client.AgentId, out p)) | 1076 | if(Scene.TryGetScenePresence(client.AgentId, out p)) |
798 | Scene.TeleportClientHome(p.UUID, p.ControllingClient); | 1077 | { |
1078 | if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient)) | ||
1079 | { | ||
1080 | p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); | ||
1081 | Scene.CloseAgent(p.UUID, false); | ||
1082 | } | ||
1083 | } | ||
799 | } | 1084 | } |
800 | }); | 1085 | }); |
801 | } | 1086 | } |
802 | 1087 | ||
803 | private void AbortTerrainXferHandler(IClientAPI remoteClient, ulong XferID) | 1088 | private void AbortTerrainXferHandler(IClientAPI remoteClient, ulong XferID) |
804 | { | 1089 | { |
805 | if (TerrainUploader != null) | 1090 | lock (this) |
806 | { | 1091 | { |
807 | lock (TerrainUploader) | 1092 | if ((TerrainUploader != null) && (XferID == TerrainUploader.XferID)) |
808 | { | 1093 | { |
809 | if (XferID == TerrainUploader.XferID) | 1094 | remoteClient.OnXferReceive -= TerrainUploader.XferReceive; |
810 | { | 1095 | remoteClient.OnAbortXfer -= AbortTerrainXferHandler; |
811 | remoteClient.OnXferReceive -= TerrainUploader.XferReceive; | 1096 | TerrainUploader.TerrainUploadDone -= HandleTerrainApplication; |
812 | remoteClient.OnAbortXfer -= AbortTerrainXferHandler; | ||
813 | TerrainUploader.TerrainUploadDone -= HandleTerrainApplication; | ||
814 | 1097 | ||
815 | TerrainUploader = null; | 1098 | TerrainUploader = null; |
816 | remoteClient.SendAlertMessage("Terrain Upload aborted by the client"); | 1099 | remoteClient.SendAlertMessage("Terrain Upload aborted by the client"); |
817 | } | ||
818 | } | 1100 | } |
819 | } | 1101 | } |
820 | |||
821 | } | 1102 | } |
1103 | |||
822 | private void HandleTerrainApplication(string filename, byte[] terrainData, IClientAPI remoteClient) | 1104 | private void HandleTerrainApplication(string filename, byte[] terrainData, IClientAPI remoteClient) |
823 | { | 1105 | { |
824 | lock (TerrainUploader) | 1106 | lock (this) |
825 | { | 1107 | { |
826 | remoteClient.OnXferReceive -= TerrainUploader.XferReceive; | 1108 | remoteClient.OnXferReceive -= TerrainUploader.XferReceive; |
827 | remoteClient.OnAbortXfer -= AbortTerrainXferHandler; | 1109 | remoteClient.OnAbortXfer -= AbortTerrainXferHandler; |
@@ -829,18 +1111,18 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
829 | 1111 | ||
830 | TerrainUploader = null; | 1112 | TerrainUploader = null; |
831 | } | 1113 | } |
1114 | |||
1115 | m_log.DebugFormat("[CLIENT]: Terrain upload from {0} to {1} complete.", remoteClient.Name, Scene.Name); | ||
832 | remoteClient.SendAlertMessage("Terrain Upload Complete. Loading...."); | 1116 | remoteClient.SendAlertMessage("Terrain Upload Complete. Loading...."); |
1117 | |||
833 | ITerrainModule terr = Scene.RequestModuleInterface<ITerrainModule>(); | 1118 | ITerrainModule terr = Scene.RequestModuleInterface<ITerrainModule>(); |
834 | 1119 | ||
835 | if (terr != null) | 1120 | if (terr != null) |
836 | { | 1121 | { |
837 | m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName); | ||
838 | |||
839 | try | 1122 | try |
840 | { | 1123 | { |
841 | MemoryStream terrainStream = new MemoryStream(terrainData); | 1124 | using (MemoryStream terrainStream = new MemoryStream(terrainData)) |
842 | terr.LoadFromStream(filename, terrainStream); | 1125 | terr.LoadFromStream(filename, terrainStream); |
843 | terrainStream.Close(); | ||
844 | 1126 | ||
845 | FileInfo x = new FileInfo(filename); | 1127 | FileInfo x = new FileInfo(filename); |
846 | remoteClient.SendAlertMessage("Your terrain was loaded as a " + x.Extension + " file. It may take a few moments to appear."); | 1128 | remoteClient.SendAlertMessage("Your terrain was loaded as a " + x.Extension + " file. It may take a few moments to appear."); |
@@ -880,25 +1162,27 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
880 | 1162 | ||
881 | private void handleUploadTerrain(IClientAPI remote_client, string clientFileName) | 1163 | private void handleUploadTerrain(IClientAPI remote_client, string clientFileName) |
882 | { | 1164 | { |
883 | if (TerrainUploader == null) | 1165 | lock (this) |
884 | { | 1166 | { |
885 | 1167 | if (TerrainUploader == null) | |
886 | TerrainUploader = new EstateTerrainXferHandler(remote_client, clientFileName); | ||
887 | lock (TerrainUploader) | ||
888 | { | 1168 | { |
1169 | m_log.DebugFormat( | ||
1170 | "[TERRAIN]: Started receiving terrain upload for region {0} from {1}", | ||
1171 | Scene.Name, remote_client.Name); | ||
1172 | |||
1173 | TerrainUploader = new EstateTerrainXferHandler(remote_client, clientFileName); | ||
889 | remote_client.OnXferReceive += TerrainUploader.XferReceive; | 1174 | remote_client.OnXferReceive += TerrainUploader.XferReceive; |
890 | remote_client.OnAbortXfer += AbortTerrainXferHandler; | 1175 | remote_client.OnAbortXfer += AbortTerrainXferHandler; |
891 | TerrainUploader.TerrainUploadDone += HandleTerrainApplication; | 1176 | TerrainUploader.TerrainUploadDone += HandleTerrainApplication; |
1177 | TerrainUploader.RequestStartXfer(remote_client); | ||
1178 | } | ||
1179 | else | ||
1180 | { | ||
1181 | remote_client.SendAlertMessage("Another Terrain Upload is in progress. Please wait your turn!"); | ||
892 | } | 1182 | } |
893 | TerrainUploader.RequestStartXfer(remote_client); | ||
894 | |||
895 | } | ||
896 | else | ||
897 | { | ||
898 | remote_client.SendAlertMessage("Another Terrain Upload is in progress. Please wait your turn!"); | ||
899 | } | 1183 | } |
900 | } | 1184 | } |
901 | 1185 | ||
902 | private void handleTerrainRequest(IClientAPI remote_client, string clientFileName) | 1186 | private void handleTerrainRequest(IClientAPI remote_client, string clientFileName) |
903 | { | 1187 | { |
904 | // Save terrain here | 1188 | // Save terrain here |
@@ -906,7 +1190,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
906 | 1190 | ||
907 | if (terr != null) | 1191 | if (terr != null) |
908 | { | 1192 | { |
909 | m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName); | 1193 | // m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName); |
910 | if (File.Exists(Util.dataDir() + "/terrain.raw")) | 1194 | if (File.Exists(Util.dataDir() + "/terrain.raw")) |
911 | { | 1195 | { |
912 | File.Delete(Util.dataDir() + "/terrain.raw"); | 1196 | File.Delete(Util.dataDir() + "/terrain.raw"); |
@@ -918,8 +1202,9 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
918 | input.Read(bdata, 0, (int)input.Length); | 1202 | input.Read(bdata, 0, (int)input.Length); |
919 | remote_client.SendAlertMessage("Terrain file written, starting download..."); | 1203 | remote_client.SendAlertMessage("Terrain file written, starting download..."); |
920 | Scene.XferManager.AddNewFile("terrain.raw", bdata); | 1204 | Scene.XferManager.AddNewFile("terrain.raw", bdata); |
921 | // Tell client about it | 1205 | |
922 | m_log.Warn("[CLIENT]: Sending Terrain to " + remote_client.Name); | 1206 | m_log.DebugFormat("[CLIENT]: Sending terrain for region {0} to {1}", Scene.Name, remote_client.Name); |
1207 | |||
923 | remote_client.SendInitiateDownload("terrain.raw", clientFileName); | 1208 | remote_client.SendInitiateDownload("terrain.raw", clientFileName); |
924 | } | 1209 | } |
925 | } | 1210 | } |
@@ -1080,11 +1365,6 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1080 | remoteClient.SendRegionHandshake(Scene.RegionInfo,args); | 1365 | remoteClient.SendRegionHandshake(Scene.RegionInfo,args); |
1081 | } | 1366 | } |
1082 | 1367 | ||
1083 | public void sendRegionHandshakeToAll() | ||
1084 | { | ||
1085 | Scene.ForEachClient(sendRegionHandshake); | ||
1086 | } | ||
1087 | |||
1088 | public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2) | 1368 | public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2) |
1089 | { | 1369 | { |
1090 | if (parms2 == 0) | 1370 | if (parms2 == 0) |
@@ -1096,6 +1376,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1096 | { | 1376 | { |
1097 | Scene.RegionInfo.EstateSettings.UseGlobalTime = false; | 1377 | Scene.RegionInfo.EstateSettings.UseGlobalTime = false; |
1098 | Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0; | 1378 | Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0; |
1379 | // Warning: FixedSun should be set to True, otherwise this sun position won't be used. | ||
1099 | } | 1380 | } |
1100 | 1381 | ||
1101 | if ((parms1 & 0x00000010) != 0) | 1382 | if ((parms1 & 0x00000010) != 0) |
@@ -1138,7 +1419,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1138 | else | 1419 | else |
1139 | Scene.RegionInfo.EstateSettings.DenyMinors = false; | 1420 | Scene.RegionInfo.EstateSettings.DenyMinors = false; |
1140 | 1421 | ||
1141 | Scene.RegionInfo.EstateSettings.Save(); | 1422 | Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); |
1142 | TriggerEstateInfoChange(); | 1423 | TriggerEstateInfoChange(); |
1143 | 1424 | ||
1144 | Scene.TriggerEstateSunUpdate(); | 1425 | Scene.TriggerEstateSunUpdate(); |
@@ -1165,11 +1446,12 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1165 | sendRegionInfoPacketToAll(); | 1446 | sendRegionInfoPacketToAll(); |
1166 | } | 1447 | } |
1167 | 1448 | ||
1168 | #endregion | 1449 | |
1450 | #endregion | ||
1169 | 1451 | ||
1170 | private void EventManager_OnNewClient(IClientAPI client) | 1452 | private void EventManager_OnNewClient(IClientAPI client) |
1171 | { | 1453 | { |
1172 | client.OnDetailedEstateDataRequest += sendDetailedEstateData; | 1454 | client.OnDetailedEstateDataRequest += clientSendDetailedEstateData; |
1173 | client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler; | 1455 | client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler; |
1174 | // client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture; | 1456 | // client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture; |
1175 | client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture; | 1457 | client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture; |
@@ -1179,7 +1461,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1179 | client.OnEstateRestartSimRequest += handleEstateRestartSimRequest; | 1461 | client.OnEstateRestartSimRequest += handleEstateRestartSimRequest; |
1180 | client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest; | 1462 | client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest; |
1181 | client.OnEstateChangeInfo += handleEstateChangeInfo; | 1463 | client.OnEstateChangeInfo += handleEstateChangeInfo; |
1182 | client.OnEstateManageTelehub += handleOnEstateManageTelehub; | 1464 | client.OnEstateManageTelehub += HandleOnEstateManageTelehub; |
1183 | client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest; | 1465 | client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest; |
1184 | client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage; | 1466 | client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage; |
1185 | client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage; | 1467 | client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage; |
@@ -1195,56 +1477,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1195 | sendRegionHandshake(client); | 1477 | sendRegionHandshake(client); |
1196 | } | 1478 | } |
1197 | 1479 | ||
1198 | public uint GetRegionFlags() | 1480 | private uint GetEstateFlags() |
1199 | { | ||
1200 | RegionFlags flags = RegionFlags.None; | ||
1201 | |||
1202 | // Fully implemented | ||
1203 | // | ||
1204 | if (Scene.RegionInfo.RegionSettings.AllowDamage) | ||
1205 | flags |= RegionFlags.AllowDamage; | ||
1206 | if (Scene.RegionInfo.RegionSettings.BlockTerraform) | ||
1207 | flags |= RegionFlags.BlockTerraform; | ||
1208 | if (!Scene.RegionInfo.RegionSettings.AllowLandResell) | ||
1209 | flags |= RegionFlags.BlockLandResell; | ||
1210 | if (Scene.RegionInfo.RegionSettings.DisableCollisions) | ||
1211 | flags |= RegionFlags.SkipCollisions; | ||
1212 | if (Scene.RegionInfo.RegionSettings.DisableScripts) | ||
1213 | flags |= RegionFlags.SkipScripts; | ||
1214 | if (Scene.RegionInfo.RegionSettings.DisablePhysics) | ||
1215 | flags |= RegionFlags.SkipPhysics; | ||
1216 | if (Scene.RegionInfo.RegionSettings.BlockFly) | ||
1217 | flags |= RegionFlags.NoFly; | ||
1218 | if (Scene.RegionInfo.RegionSettings.RestrictPushing) | ||
1219 | flags |= RegionFlags.RestrictPushObject; | ||
1220 | if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide) | ||
1221 | flags |= RegionFlags.AllowParcelChanges; | ||
1222 | if (Scene.RegionInfo.RegionSettings.BlockShowInSearch) | ||
1223 | flags |= RegionFlags.BlockParcelSearch; | ||
1224 | |||
1225 | if (Scene.RegionInfo.RegionSettings.FixedSun) | ||
1226 | flags |= RegionFlags.SunFixed; | ||
1227 | if (Scene.RegionInfo.RegionSettings.Sandbox) | ||
1228 | flags |= RegionFlags.Sandbox; | ||
1229 | if (Scene.RegionInfo.EstateSettings.AllowVoice) | ||
1230 | flags |= RegionFlags.AllowVoice; | ||
1231 | |||
1232 | // Fudge these to always on, so the menu options activate | ||
1233 | // | ||
1234 | flags |= RegionFlags.AllowLandmark; | ||
1235 | flags |= RegionFlags.AllowSetHome; | ||
1236 | |||
1237 | // TODO: SkipUpdateInterestList | ||
1238 | |||
1239 | // Omitted | ||
1240 | // | ||
1241 | // Omitted: NullLayer (what is that?) | ||
1242 | // Omitted: SkipAgentAction (what does it do?) | ||
1243 | |||
1244 | return (uint)flags; | ||
1245 | } | ||
1246 | |||
1247 | public uint GetEstateFlags() | ||
1248 | { | 1481 | { |
1249 | RegionFlags flags = RegionFlags.None; | 1482 | RegionFlags flags = RegionFlags.None; |
1250 | 1483 | ||
@@ -1273,40 +1506,18 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
1273 | flags |= RegionFlags.ResetHomeOnTeleport; | 1506 | flags |= RegionFlags.ResetHomeOnTeleport; |
1274 | if (Scene.RegionInfo.EstateSettings.TaxFree) | 1507 | if (Scene.RegionInfo.EstateSettings.TaxFree) |
1275 | flags |= RegionFlags.TaxFree; | 1508 | flags |= RegionFlags.TaxFree; |
1509 | if (Scene.RegionInfo.EstateSettings.AllowLandmark) | ||
1510 | flags |= RegionFlags.AllowLandmark; | ||
1511 | if (Scene.RegionInfo.EstateSettings.AllowParcelChanges) | ||
1512 | flags |= RegionFlags.AllowParcelChanges; | ||
1513 | if (Scene.RegionInfo.EstateSettings.AllowSetHome) | ||
1514 | flags |= RegionFlags.AllowSetHome; | ||
1276 | if (Scene.RegionInfo.EstateSettings.DenyMinors) | 1515 | if (Scene.RegionInfo.EstateSettings.DenyMinors) |
1277 | flags |= (RegionFlags)(1 << 30); | 1516 | flags |= (RegionFlags)(1 << 30); |
1278 | 1517 | ||
1279 | return (uint)flags; | 1518 | return (uint)flags; |
1280 | } | 1519 | } |
1281 | 1520 | ||
1282 | public bool IsManager(UUID avatarID) | ||
1283 | { | ||
1284 | if (avatarID == Scene.RegionInfo.EstateSettings.EstateOwner) | ||
1285 | return true; | ||
1286 | |||
1287 | List<UUID> ems = new List<UUID>(Scene.RegionInfo.EstateSettings.EstateManagers); | ||
1288 | if (ems.Contains(avatarID)) | ||
1289 | return true; | ||
1290 | |||
1291 | return false; | ||
1292 | } | ||
1293 | |||
1294 | public void TriggerRegionInfoChange() | ||
1295 | { | ||
1296 | ChangeDelegate change = OnRegionInfoChange; | ||
1297 | |||
1298 | if (change != null) | ||
1299 | change(Scene.RegionInfo.RegionID); | ||
1300 | } | ||
1301 | |||
1302 | public void TriggerEstateInfoChange() | ||
1303 | { | ||
1304 | ChangeDelegate change = OnEstateInfoChange; | ||
1305 | |||
1306 | if (change != null) | ||
1307 | change(Scene.RegionInfo.RegionID); | ||
1308 | } | ||
1309 | |||
1310 | public void TriggerEstateMessage(UUID fromID, string fromName, string message) | 1521 | public void TriggerEstateMessage(UUID fromID, string fromName, string message) |
1311 | { | 1522 | { |
1312 | MessageDelegate onmessage = OnEstateMessage; | 1523 | MessageDelegate onmessage = OnEstateMessage; |
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs b/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs index b8d8b10..2d74eaf 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs | |||
@@ -78,7 +78,10 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
78 | /// <param name="data"></param> | 78 | /// <param name="data"></param> |
79 | public void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data) | 79 | public void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data) |
80 | { | 80 | { |
81 | if (mXferID == xferID) | 81 | if (mXferID != xferID) |
82 | return; | ||
83 | |||
84 | lock (this) | ||
82 | { | 85 | { |
83 | if (m_asset.Data.Length > 1) | 86 | if (m_asset.Data.Length > 1) |
84 | { | 87 | { |
@@ -99,7 +102,6 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
99 | if ((packetID & 0x80000000) != 0) | 102 | if ((packetID & 0x80000000) != 0) |
100 | { | 103 | { |
101 | SendCompleteMessage(remoteClient); | 104 | SendCompleteMessage(remoteClient); |
102 | |||
103 | } | 105 | } |
104 | } | 106 | } |
105 | } | 107 | } |
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs new file mode 100644 index 0000000..73e706c --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs | |||
@@ -0,0 +1,218 @@ | |||
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.Reflection; | ||
31 | |||
32 | using OpenSim.Services.Interfaces; | ||
33 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
34 | using OpenSim.Server.Base; | ||
35 | using OpenSim.Framework.Servers.HttpServer; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | using log4net; | ||
41 | |||
42 | namespace OpenSim.Region.CoreModules.World.Estate | ||
43 | { | ||
44 | public class EstateConnector | ||
45 | { | ||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | protected XEstateModule m_EstateModule; | ||
49 | |||
50 | public EstateConnector(XEstateModule module) | ||
51 | { | ||
52 | m_EstateModule = module; | ||
53 | } | ||
54 | |||
55 | public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID) | ||
56 | { | ||
57 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
58 | sendData["METHOD"] = "teleport_home_one_user"; | ||
59 | |||
60 | sendData["EstateID"] = EstateID.ToString(); | ||
61 | sendData["PreyID"] = PreyID.ToString(); | ||
62 | |||
63 | SendToEstate(EstateID, sendData); | ||
64 | } | ||
65 | |||
66 | public void SendTeleportHomeAllUsers(uint EstateID) | ||
67 | { | ||
68 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
69 | sendData["METHOD"] = "teleport_home_all_users"; | ||
70 | |||
71 | sendData["EstateID"] = EstateID.ToString(); | ||
72 | |||
73 | SendToEstate(EstateID, sendData); | ||
74 | } | ||
75 | |||
76 | public bool SendUpdateCovenant(uint EstateID, UUID CovenantID) | ||
77 | { | ||
78 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
79 | sendData["METHOD"] = "update_covenant"; | ||
80 | |||
81 | sendData["CovenantID"] = CovenantID.ToString(); | ||
82 | sendData["EstateID"] = EstateID.ToString(); | ||
83 | |||
84 | // Handle local regions locally | ||
85 | // | ||
86 | foreach (Scene s in m_EstateModule.Scenes) | ||
87 | { | ||
88 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
89 | s.RegionInfo.RegionSettings.Covenant = CovenantID; | ||
90 | // s.ReloadEstateData(); | ||
91 | } | ||
92 | |||
93 | SendToEstate(EstateID, sendData); | ||
94 | |||
95 | return true; | ||
96 | } | ||
97 | |||
98 | public bool SendUpdateEstate(uint EstateID) | ||
99 | { | ||
100 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
101 | sendData["METHOD"] = "update_estate"; | ||
102 | |||
103 | sendData["EstateID"] = EstateID.ToString(); | ||
104 | |||
105 | // Handle local regions locally | ||
106 | // | ||
107 | foreach (Scene s in m_EstateModule.Scenes) | ||
108 | { | ||
109 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
110 | s.ReloadEstateData(); | ||
111 | } | ||
112 | |||
113 | SendToEstate(EstateID, sendData); | ||
114 | |||
115 | return true; | ||
116 | } | ||
117 | |||
118 | public void SendEstateMessage(uint EstateID, UUID FromID, string FromName, string Message) | ||
119 | { | ||
120 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
121 | sendData["METHOD"] = "estate_message"; | ||
122 | |||
123 | sendData["EstateID"] = EstateID.ToString(); | ||
124 | sendData["FromID"] = FromID.ToString(); | ||
125 | sendData["FromName"] = FromName; | ||
126 | sendData["Message"] = Message; | ||
127 | |||
128 | SendToEstate(EstateID, sendData); | ||
129 | } | ||
130 | |||
131 | private void SendToEstate(uint EstateID, Dictionary<string, object> sendData) | ||
132 | { | ||
133 | List<UUID> regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID); | ||
134 | |||
135 | UUID ScopeID = UUID.Zero; | ||
136 | |||
137 | // Handle local regions locally | ||
138 | // | ||
139 | lock (m_EstateModule.Scenes) | ||
140 | { | ||
141 | foreach (Scene s in m_EstateModule.Scenes) | ||
142 | { | ||
143 | if (regions.Contains(s.RegionInfo.RegionID)) | ||
144 | { | ||
145 | // All regions in one estate are in the same scope. | ||
146 | // Use that scope. | ||
147 | // | ||
148 | ScopeID = s.RegionInfo.ScopeID; | ||
149 | regions.Remove(s.RegionInfo.RegionID); | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | // Our own region should always be in the above list. | ||
155 | // In a standalone this would not be true. But then, | ||
156 | // Scope ID is not relevat there. Use first scope. | ||
157 | // | ||
158 | if (ScopeID == UUID.Zero) | ||
159 | ScopeID = m_EstateModule.Scenes[0].RegionInfo.ScopeID; | ||
160 | |||
161 | // Don't send to the same instance twice | ||
162 | // | ||
163 | List<string> done = new List<string>(); | ||
164 | |||
165 | // Send to remote regions | ||
166 | // | ||
167 | foreach (UUID regionID in regions) | ||
168 | { | ||
169 | GridRegion region = m_EstateModule.Scenes[0].GridService.GetRegionByUUID(ScopeID, regionID); | ||
170 | if (region != null) | ||
171 | { | ||
172 | string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; | ||
173 | if (done.Contains(url)) | ||
174 | continue; | ||
175 | |||
176 | Call(region, sendData); | ||
177 | done.Add(url); | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | private bool Call(GridRegion region, Dictionary<string, object> sendData) | ||
183 | { | ||
184 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
185 | // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString); | ||
186 | try | ||
187 | { | ||
188 | string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; | ||
189 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
190 | url + "/estate", | ||
191 | reqString); | ||
192 | if (reply != string.Empty) | ||
193 | { | ||
194 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
195 | |||
196 | if (replyData.ContainsKey("RESULT")) | ||
197 | { | ||
198 | if (replyData["RESULT"].ToString().ToLower() == "true") | ||
199 | return true; | ||
200 | else | ||
201 | return false; | ||
202 | } | ||
203 | else | ||
204 | m_log.DebugFormat("[XESTATE CONNECTOR]: reply data does not contain result field"); | ||
205 | |||
206 | } | ||
207 | else | ||
208 | m_log.DebugFormat("[XESTATE CONNECTOR]: received empty reply"); | ||
209 | } | ||
210 | catch (Exception e) | ||
211 | { | ||
212 | m_log.DebugFormat("[XESTATE CONNECTOR]: Exception when contacting remote sim: {0}", e.Message); | ||
213 | } | ||
214 | |||
215 | return false; | ||
216 | } | ||
217 | } | ||
218 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs new file mode 100644 index 0000000..4bb3799 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs | |||
@@ -0,0 +1,255 @@ | |||
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; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using Nwc.XmlRpc; | ||
35 | using OpenMetaverse; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Services.Interfaces; | ||
40 | using OpenSim.Server.Base; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using Mono.Addins; | ||
44 | |||
45 | namespace OpenSim.Region.CoreModules.World.Estate | ||
46 | { | ||
47 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")] | ||
48 | public class XEstateModule : ISharedRegionModule | ||
49 | { | ||
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
52 | protected List<Scene> m_Scenes = new List<Scene>(); | ||
53 | protected bool m_InInfoUpdate = false; | ||
54 | |||
55 | public bool InInfoUpdate | ||
56 | { | ||
57 | get { return m_InInfoUpdate; } | ||
58 | set { m_InInfoUpdate = value; } | ||
59 | } | ||
60 | |||
61 | public List<Scene> Scenes | ||
62 | { | ||
63 | get { return m_Scenes; } | ||
64 | } | ||
65 | |||
66 | protected EstateConnector m_EstateConnector; | ||
67 | |||
68 | public void Initialise(IConfigSource config) | ||
69 | { | ||
70 | int port = 0; | ||
71 | |||
72 | IConfig estateConfig = config.Configs["Estate"]; | ||
73 | if (estateConfig != null) | ||
74 | { | ||
75 | port = estateConfig.GetInt("Port", 0); | ||
76 | } | ||
77 | |||
78 | m_EstateConnector = new EstateConnector(this); | ||
79 | |||
80 | // Instantiate the request handler | ||
81 | IHttpServer server = MainServer.GetHttpServer((uint)port); | ||
82 | server.AddStreamHandler(new EstateRequestHandler(this)); | ||
83 | } | ||
84 | |||
85 | public void PostInitialise() | ||
86 | { | ||
87 | } | ||
88 | |||
89 | public void Close() | ||
90 | { | ||
91 | } | ||
92 | |||
93 | public void AddRegion(Scene scene) | ||
94 | { | ||
95 | lock (m_Scenes) | ||
96 | m_Scenes.Add(scene); | ||
97 | |||
98 | scene.EventManager.OnNewClient += OnNewClient; | ||
99 | } | ||
100 | |||
101 | public void RegionLoaded(Scene scene) | ||
102 | { | ||
103 | IEstateModule em = scene.RequestModuleInterface<IEstateModule>(); | ||
104 | |||
105 | em.OnRegionInfoChange += OnRegionInfoChange; | ||
106 | em.OnEstateInfoChange += OnEstateInfoChange; | ||
107 | em.OnEstateMessage += OnEstateMessage; | ||
108 | } | ||
109 | |||
110 | public void RemoveRegion(Scene scene) | ||
111 | { | ||
112 | scene.EventManager.OnNewClient -= OnNewClient; | ||
113 | |||
114 | lock (m_Scenes) | ||
115 | m_Scenes.Remove(scene); | ||
116 | } | ||
117 | |||
118 | public string Name | ||
119 | { | ||
120 | get { return "EstateModule"; } | ||
121 | } | ||
122 | |||
123 | public Type ReplaceableInterface | ||
124 | { | ||
125 | get { return null; } | ||
126 | } | ||
127 | |||
128 | private Scene FindScene(UUID RegionID) | ||
129 | { | ||
130 | foreach (Scene s in Scenes) | ||
131 | { | ||
132 | if (s.RegionInfo.RegionID == RegionID) | ||
133 | return s; | ||
134 | } | ||
135 | |||
136 | return null; | ||
137 | } | ||
138 | |||
139 | private void OnRegionInfoChange(UUID RegionID) | ||
140 | { | ||
141 | Scene s = FindScene(RegionID); | ||
142 | if (s == null) | ||
143 | return; | ||
144 | |||
145 | if (!m_InInfoUpdate) | ||
146 | m_EstateConnector.SendUpdateCovenant(s.RegionInfo.EstateSettings.EstateID, s.RegionInfo.RegionSettings.Covenant); | ||
147 | } | ||
148 | |||
149 | private void OnEstateInfoChange(UUID RegionID) | ||
150 | { | ||
151 | Scene s = FindScene(RegionID); | ||
152 | if (s == null) | ||
153 | return; | ||
154 | |||
155 | if (!m_InInfoUpdate) | ||
156 | m_EstateConnector.SendUpdateEstate(s.RegionInfo.EstateSettings.EstateID); | ||
157 | } | ||
158 | |||
159 | private void OnEstateMessage(UUID RegionID, UUID FromID, string FromName, string Message) | ||
160 | { | ||
161 | Scene senderScenes = FindScene(RegionID); | ||
162 | if (senderScenes == null) | ||
163 | return; | ||
164 | |||
165 | uint estateID = senderScenes.RegionInfo.EstateSettings.EstateID; | ||
166 | |||
167 | foreach (Scene s in Scenes) | ||
168 | { | ||
169 | if (s.RegionInfo.EstateSettings.EstateID == estateID) | ||
170 | { | ||
171 | IDialogModule dm = s.RequestModuleInterface<IDialogModule>(); | ||
172 | |||
173 | if (dm != null) | ||
174 | { | ||
175 | dm.SendNotificationToUsersInRegion(FromID, FromName, | ||
176 | Message); | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | if (!m_InInfoUpdate) | ||
181 | m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message); | ||
182 | } | ||
183 | |||
184 | private void OnNewClient(IClientAPI client) | ||
185 | { | ||
186 | client.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest; | ||
187 | client.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest; | ||
188 | |||
189 | } | ||
190 | |||
191 | private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey) | ||
192 | { | ||
193 | if (prey == UUID.Zero) | ||
194 | return; | ||
195 | |||
196 | if (!(client.Scene is Scene)) | ||
197 | return; | ||
198 | |||
199 | Scene scene = (Scene)client.Scene; | ||
200 | |||
201 | uint estateID = scene.RegionInfo.EstateSettings.EstateID; | ||
202 | |||
203 | if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) | ||
204 | return; | ||
205 | |||
206 | foreach (Scene s in Scenes) | ||
207 | { | ||
208 | if (s == scene) | ||
209 | continue; // Already handles by estate module | ||
210 | if (s.RegionInfo.EstateSettings.EstateID != estateID) | ||
211 | continue; | ||
212 | |||
213 | ScenePresence p = scene.GetScenePresence(prey); | ||
214 | if (p != null && !p.IsChildAgent) | ||
215 | { | ||
216 | p.ControllingClient.SendTeleportStart(16); | ||
217 | scene.TeleportClientHome(prey, p.ControllingClient); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | m_EstateConnector.SendTeleportHomeOneUser(estateID, prey); | ||
222 | } | ||
223 | |||
224 | private void OnEstateTeleportAllUsersHomeRequest(IClientAPI client, UUID invoice, UUID senderID) | ||
225 | { | ||
226 | if (!(client.Scene is Scene)) | ||
227 | return; | ||
228 | |||
229 | Scene scene = (Scene)client.Scene; | ||
230 | |||
231 | uint estateID = scene.RegionInfo.EstateSettings.EstateID; | ||
232 | |||
233 | if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) | ||
234 | return; | ||
235 | |||
236 | foreach (Scene s in Scenes) | ||
237 | { | ||
238 | if (s == scene) | ||
239 | continue; // Already handles by estate module | ||
240 | if (s.RegionInfo.EstateSettings.EstateID != estateID) | ||
241 | continue; | ||
242 | |||
243 | scene.ForEachScenePresence(delegate(ScenePresence p) { | ||
244 | if (p != null && !p.IsChildAgent) | ||
245 | { | ||
246 | p.ControllingClient.SendTeleportStart(16); | ||
247 | scene.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); | ||
248 | } | ||
249 | }); | ||
250 | } | ||
251 | |||
252 | m_EstateConnector.SendTeleportHomeAllUsers(estateID); | ||
253 | } | ||
254 | } | ||
255 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs new file mode 100644 index 0000000..ec5af2b --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs | |||
@@ -0,0 +1,288 @@ | |||
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.Reflection; | ||
32 | using System.Xml; | ||
33 | |||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Server.Base; | ||
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | |||
40 | using OpenMetaverse; | ||
41 | using log4net; | ||
42 | |||
43 | namespace OpenSim.Region.CoreModules.World.Estate | ||
44 | { | ||
45 | public class EstateRequestHandler : BaseStreamHandler | ||
46 | { | ||
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | protected XEstateModule m_EstateModule; | ||
50 | protected Object m_RequestLock = new Object(); | ||
51 | |||
52 | public EstateRequestHandler(XEstateModule fmodule) | ||
53 | : base("POST", "/estate") | ||
54 | { | ||
55 | m_EstateModule = fmodule; | ||
56 | } | ||
57 | |||
58 | protected override byte[] ProcessRequest(string path, Stream requestData, | ||
59 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
60 | { | ||
61 | StreamReader sr = new StreamReader(requestData); | ||
62 | string body = sr.ReadToEnd(); | ||
63 | sr.Close(); | ||
64 | body = body.Trim(); | ||
65 | |||
66 | m_log.DebugFormat("[XESTATE HANDLER]: query String: {0}", body); | ||
67 | |||
68 | try | ||
69 | { | ||
70 | lock (m_RequestLock) | ||
71 | { | ||
72 | Dictionary<string, object> request = | ||
73 | ServerUtils.ParseQueryString(body); | ||
74 | |||
75 | if (!request.ContainsKey("METHOD")) | ||
76 | return FailureResult(); | ||
77 | |||
78 | string method = request["METHOD"].ToString(); | ||
79 | request.Remove("METHOD"); | ||
80 | |||
81 | try | ||
82 | { | ||
83 | m_EstateModule.InInfoUpdate = false; | ||
84 | |||
85 | switch (method) | ||
86 | { | ||
87 | case "update_covenant": | ||
88 | return UpdateCovenant(request); | ||
89 | case "update_estate": | ||
90 | return UpdateEstate(request); | ||
91 | case "estate_message": | ||
92 | return EstateMessage(request); | ||
93 | case "teleport_home_one_user": | ||
94 | return TeleportHomeOneUser(request); | ||
95 | case "teleport_home_all_users": | ||
96 | return TeleportHomeAllUsers(request); | ||
97 | } | ||
98 | } | ||
99 | finally | ||
100 | { | ||
101 | m_EstateModule.InInfoUpdate = false; | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | catch (Exception e) | ||
106 | { | ||
107 | m_log.Debug("[XESTATE]: Exception {0}" + e.ToString()); | ||
108 | } | ||
109 | |||
110 | return FailureResult(); | ||
111 | } | ||
112 | |||
113 | byte[] TeleportHomeAllUsers(Dictionary<string, object> request) | ||
114 | { | ||
115 | UUID PreyID = UUID.Zero; | ||
116 | int EstateID = 0; | ||
117 | |||
118 | if (!request.ContainsKey("EstateID")) | ||
119 | return FailureResult(); | ||
120 | |||
121 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
122 | return FailureResult(); | ||
123 | |||
124 | foreach (Scene s in m_EstateModule.Scenes) | ||
125 | { | ||
126 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
127 | { | ||
128 | s.ForEachScenePresence(delegate(ScenePresence p) { | ||
129 | if (p != null && !p.IsChildAgent) | ||
130 | { | ||
131 | p.ControllingClient.SendTeleportStart(16); | ||
132 | s.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); | ||
133 | } | ||
134 | }); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | return SuccessResult(); | ||
139 | } | ||
140 | |||
141 | byte[] TeleportHomeOneUser(Dictionary<string, object> request) | ||
142 | { | ||
143 | UUID PreyID = UUID.Zero; | ||
144 | int EstateID = 0; | ||
145 | |||
146 | if (!request.ContainsKey("PreyID") || | ||
147 | !request.ContainsKey("EstateID")) | ||
148 | { | ||
149 | return FailureResult(); | ||
150 | } | ||
151 | |||
152 | if (!UUID.TryParse(request["PreyID"].ToString(), out PreyID)) | ||
153 | return FailureResult(); | ||
154 | |||
155 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
156 | return FailureResult(); | ||
157 | |||
158 | foreach (Scene s in m_EstateModule.Scenes) | ||
159 | { | ||
160 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
161 | { | ||
162 | ScenePresence p = s.GetScenePresence(PreyID); | ||
163 | if (p != null && !p.IsChildAgent) | ||
164 | { | ||
165 | p.ControllingClient.SendTeleportStart(16); | ||
166 | s.TeleportClientHome(PreyID, p.ControllingClient); | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | return SuccessResult(); | ||
172 | } | ||
173 | |||
174 | byte[] EstateMessage(Dictionary<string, object> request) | ||
175 | { | ||
176 | UUID FromID = UUID.Zero; | ||
177 | string FromName = String.Empty; | ||
178 | string Message = String.Empty; | ||
179 | int EstateID = 0; | ||
180 | |||
181 | if (!request.ContainsKey("FromID") || | ||
182 | !request.ContainsKey("FromName") || | ||
183 | !request.ContainsKey("Message") || | ||
184 | !request.ContainsKey("EstateID")) | ||
185 | { | ||
186 | return FailureResult(); | ||
187 | } | ||
188 | |||
189 | if (!UUID.TryParse(request["FromID"].ToString(), out FromID)) | ||
190 | return FailureResult(); | ||
191 | |||
192 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
193 | return FailureResult(); | ||
194 | |||
195 | FromName = request["FromName"].ToString(); | ||
196 | Message = request["Message"].ToString(); | ||
197 | |||
198 | foreach (Scene s in m_EstateModule.Scenes) | ||
199 | { | ||
200 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
201 | { | ||
202 | IDialogModule dm = s.RequestModuleInterface<IDialogModule>(); | ||
203 | |||
204 | if (dm != null) | ||
205 | { | ||
206 | dm.SendNotificationToUsersInRegion(FromID, FromName, | ||
207 | Message); | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | |||
212 | return SuccessResult(); | ||
213 | } | ||
214 | |||
215 | byte[] UpdateCovenant(Dictionary<string, object> request) | ||
216 | { | ||
217 | UUID CovenantID = UUID.Zero; | ||
218 | int EstateID = 0; | ||
219 | |||
220 | if (!request.ContainsKey("CovenantID") || !request.ContainsKey("EstateID")) | ||
221 | return FailureResult(); | ||
222 | |||
223 | if (!UUID.TryParse(request["CovenantID"].ToString(), out CovenantID)) | ||
224 | return FailureResult(); | ||
225 | |||
226 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
227 | return FailureResult(); | ||
228 | |||
229 | foreach (Scene s in m_EstateModule.Scenes) | ||
230 | { | ||
231 | if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) | ||
232 | s.RegionInfo.RegionSettings.Covenant = CovenantID; | ||
233 | } | ||
234 | |||
235 | return SuccessResult(); | ||
236 | } | ||
237 | |||
238 | byte[] UpdateEstate(Dictionary<string, object> request) | ||
239 | { | ||
240 | int EstateID = 0; | ||
241 | |||
242 | if (!request.ContainsKey("EstateID")) | ||
243 | return FailureResult(); | ||
244 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
245 | return FailureResult(); | ||
246 | |||
247 | foreach (Scene s in m_EstateModule.Scenes) | ||
248 | { | ||
249 | if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) | ||
250 | s.ReloadEstateData(); | ||
251 | } | ||
252 | return SuccessResult(); | ||
253 | } | ||
254 | |||
255 | private byte[] FailureResult() | ||
256 | { | ||
257 | return BoolResult(false); | ||
258 | } | ||
259 | |||
260 | private byte[] SuccessResult() | ||
261 | { | ||
262 | return BoolResult(true); | ||
263 | } | ||
264 | |||
265 | private byte[] BoolResult(bool value) | ||
266 | { | ||
267 | XmlDocument doc = new XmlDocument(); | ||
268 | |||
269 | XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, | ||
270 | "", ""); | ||
271 | |||
272 | doc.AppendChild(xmlnode); | ||
273 | |||
274 | XmlElement rootElement = doc.CreateElement("", "ServerResponse", | ||
275 | ""); | ||
276 | |||
277 | doc.AppendChild(rootElement); | ||
278 | |||
279 | XmlElement result = doc.CreateElement("", "RESULT", ""); | ||
280 | result.AppendChild(doc.CreateTextNode(value.ToString())); | ||
281 | |||
282 | rootElement.AppendChild(result); | ||
283 | |||
284 | return Util.DocToBytes(doc); | ||
285 | } | ||
286 | |||
287 | } | ||
288 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Land/DwellModule.cs b/OpenSim/Region/CoreModules/World/Land/DwellModule.cs index bd22155..70c6028 100644 --- a/OpenSim/Region/CoreModules/World/Land/DwellModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/DwellModule.cs | |||
@@ -45,17 +45,19 @@ using OpenSim.Framework.Servers.HttpServer; | |||
45 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | 45 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; |
46 | using OpenSim.Region.Framework.Interfaces; | 46 | using OpenSim.Region.Framework.Interfaces; |
47 | using OpenSim.Region.Framework.Scenes; | 47 | using OpenSim.Region.Framework.Scenes; |
48 | using OpenSim.Region.Physics.Manager; | 48 | using OpenSim.Region.PhysicsModules.SharedBase; |
49 | using OpenSim.Services.Interfaces; | 49 | using OpenSim.Services.Interfaces; |
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | 50 | using Caps = OpenSim.Framework.Capabilities.Caps; |
51 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 51 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
52 | 52 | ||
53 | namespace OpenSim.Region.CoreModules.World.Land | 53 | namespace OpenSim.Region.CoreModules.World.Land |
54 | { | 54 | { |
55 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DwellModule")] | 55 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DefaultDwellModule")] |
56 | public class DwellModule : IDwellModule, INonSharedRegionModule | 56 | public class DefaultDwellModule : IDwellModule, INonSharedRegionModule |
57 | { | 57 | { |
58 | private Scene m_scene; | 58 | private Scene m_scene; |
59 | private IConfigSource m_Config; | ||
60 | private bool m_Enabled = false; | ||
59 | 61 | ||
60 | public Type ReplaceableInterface | 62 | public Type ReplaceableInterface |
61 | { | 63 | { |
@@ -64,15 +66,27 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
64 | 66 | ||
65 | public string Name | 67 | public string Name |
66 | { | 68 | { |
67 | get { return "DwellModule"; } | 69 | get { return "DefaultDwellModule"; } |
68 | } | 70 | } |
69 | 71 | ||
70 | public void Initialise(IConfigSource source) | 72 | public void Initialise(IConfigSource source) |
71 | { | 73 | { |
74 | m_Config = source; | ||
75 | |||
76 | IConfig DwellConfig = m_Config.Configs ["Dwell"]; | ||
77 | |||
78 | if (DwellConfig == null) { | ||
79 | m_Enabled = false; | ||
80 | return; | ||
81 | } | ||
82 | m_Enabled = (DwellConfig.GetString ("DwellModule", "DefaultDwellModule") == "DefaultDwellModule"); | ||
72 | } | 83 | } |
73 | 84 | ||
74 | public void AddRegion(Scene scene) | 85 | public void AddRegion(Scene scene) |
75 | { | 86 | { |
87 | if (!m_Enabled) | ||
88 | return; | ||
89 | |||
76 | m_scene = scene; | 90 | m_scene = scene; |
77 | 91 | ||
78 | m_scene.EventManager.OnNewClient += OnNewClient; | 92 | m_scene.EventManager.OnNewClient += OnNewClient; |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs index 7fc358d..73c592d 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs | |||
@@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
95 | return null; | 95 | return null; |
96 | } | 96 | } |
97 | 97 | ||
98 | public ILandObject GetLandObject(Vector3 position) | ||
99 | { | ||
100 | return GetLandObject(position.X, position.Y); | ||
101 | } | ||
102 | |||
98 | public ILandObject GetLandObject(int x, int y) | 103 | public ILandObject GetLandObject(int x, int y) |
99 | { | 104 | { |
100 | if (m_landManagementModule != null) | 105 | if (m_landManagementModule != null) |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index bad7205..92f6c1b 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | |||
@@ -42,10 +42,9 @@ using OpenSim.Framework.Capabilities; | |||
42 | using OpenSim.Framework.Console; | 42 | using OpenSim.Framework.Console; |
43 | using OpenSim.Framework.Servers; | 43 | using OpenSim.Framework.Servers; |
44 | using OpenSim.Framework.Servers.HttpServer; | 44 | using OpenSim.Framework.Servers.HttpServer; |
45 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | ||
46 | using OpenSim.Region.Framework.Interfaces; | 45 | using OpenSim.Region.Framework.Interfaces; |
47 | using OpenSim.Region.Framework.Scenes; | 46 | using OpenSim.Region.Framework.Scenes; |
48 | using OpenSim.Region.Physics.Manager; | 47 | using OpenSim.Region.PhysicsModules.SharedBase; |
49 | using OpenSim.Services.Interfaces; | 48 | using OpenSim.Services.Interfaces; |
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | 49 | using Caps = OpenSim.Framework.Capabilities.Caps; |
51 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 50 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
@@ -65,25 +64,27 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
65 | public class LandManagementModule : INonSharedRegionModule | 64 | public class LandManagementModule : INonSharedRegionModule |
66 | { | 65 | { |
67 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
67 | private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]"; | ||
68 | |||
69 | /// <summary> | ||
70 | /// Minimum land unit size in region co-ordinates. | ||
71 | /// </summary> | ||
72 | public const int LandUnit = 4; | ||
68 | 73 | ||
69 | private static readonly string remoteParcelRequestPath = "0009/"; | 74 | private static readonly string remoteParcelRequestPath = "0009/"; |
70 | 75 | ||
71 | private LandChannel landChannel; | 76 | private LandChannel landChannel; |
72 | private Scene m_scene; | 77 | private Scene m_scene; |
73 | protected Commander m_commander = new Commander("land"); | 78 | |
74 | 79 | protected IGroupsModule m_groupManager; | |
75 | protected IUserManagement m_userManager; | 80 | protected IUserManagement m_userManager; |
76 | protected IPrimCountModule m_primCountModule; | 81 | protected IPrimCountModule m_primCountModule; |
77 | 82 | protected IDialogModule m_Dialog; | |
78 | // Minimum for parcels to work is 64m even if we don't actually use them. | ||
79 | #pragma warning disable 0429 | ||
80 | private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64; | ||
81 | #pragma warning restore 0429 | ||
82 | 83 | ||
83 | /// <value> | 84 | /// <value> |
84 | /// Local land ids at specified region co-ordinates (region size / 4) | 85 | /// Local land ids at specified region co-ordinates (region size / 4) |
85 | /// </value> | 86 | /// </value> |
86 | private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; | 87 | private int[,] m_landIDList; |
87 | 88 | ||
88 | /// <value> | 89 | /// <value> |
89 | /// Land objects keyed by local id | 90 | /// Land objects keyed by local id |
@@ -97,11 +98,17 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
97 | // caches ExtendedLandData | 98 | // caches ExtendedLandData |
98 | private Cache parcelInfoCache; | 99 | private Cache parcelInfoCache; |
99 | 100 | ||
101 | |||
100 | /// <summary> | 102 | /// <summary> |
101 | /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. | 103 | /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. |
102 | /// </summary> | 104 | /// </summary> |
103 | private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>(); | 105 | private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>(); |
104 | 106 | ||
107 | // Enables limiting parcel layer info transmission when doing simple updates | ||
108 | private bool shouldLimitParcelLayerInfoToViewDistance { get; set; } | ||
109 | // "View distance" for sending parcel layer info if asked for from a view point in the region | ||
110 | private int parcelLayerViewDistance { get; set; } | ||
111 | |||
105 | #region INonSharedRegionModule Members | 112 | #region INonSharedRegionModule Members |
106 | 113 | ||
107 | public Type ReplaceableInterface | 114 | public Type ReplaceableInterface |
@@ -111,12 +118,20 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
111 | 118 | ||
112 | public void Initialise(IConfigSource source) | 119 | public void Initialise(IConfigSource source) |
113 | { | 120 | { |
121 | shouldLimitParcelLayerInfoToViewDistance = true; | ||
122 | parcelLayerViewDistance = 128; | ||
123 | IConfig landManagementConfig = source.Configs["LandManagement"]; | ||
124 | if (landManagementConfig != null) | ||
125 | { | ||
126 | shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance); | ||
127 | parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance); | ||
128 | } | ||
114 | } | 129 | } |
115 | 130 | ||
116 | public void AddRegion(Scene scene) | 131 | public void AddRegion(Scene scene) |
117 | { | 132 | { |
118 | m_scene = scene; | 133 | m_scene = scene; |
119 | m_landIDList.Initialize(); | 134 | m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit]; |
120 | landChannel = new LandChannel(scene, this); | 135 | landChannel = new LandChannel(scene, this); |
121 | 136 | ||
122 | parcelInfoCache = new Cache(); | 137 | parcelInfoCache = new Cache(); |
@@ -139,28 +154,26 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
139 | m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; | 154 | m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; |
140 | m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan; | 155 | m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan; |
141 | m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps; | 156 | m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps; |
142 | m_scene.EventManager.OnPluginConsole += EventManagerOnPluginConsole; | ||
143 | 157 | ||
144 | lock (m_scene) | 158 | lock (m_scene) |
145 | { | 159 | { |
146 | m_scene.LandChannel = (ILandChannel)landChannel; | 160 | m_scene.LandChannel = (ILandChannel)landChannel; |
147 | } | 161 | } |
148 | 162 | ||
149 | InstallInterfaces(); | 163 | RegisterCommands(); |
150 | } | 164 | } |
151 | 165 | ||
152 | public void RegionLoaded(Scene scene) | 166 | public void RegionLoaded(Scene scene) |
153 | { | 167 | { |
154 | m_userManager = m_scene.RequestModuleInterface<IUserManagement>(); | 168 | m_userManager = m_scene.RequestModuleInterface<IUserManagement>(); |
155 | m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>(); | 169 | m_groupManager = m_scene.RequestModuleInterface<IGroupsModule>(); |
170 | m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>(); | ||
171 | m_Dialog = m_scene.RequestModuleInterface<IDialogModule>(); | ||
156 | } | 172 | } |
157 | 173 | ||
158 | public void RemoveRegion(Scene scene) | 174 | public void RemoveRegion(Scene scene) |
159 | { | 175 | { |
160 | // TODO: Also release other event manager listeners here | 176 | // TODO: Release event manager listeners here |
161 | |||
162 | m_scene.EventManager.OnPluginConsole -= EventManagerOnPluginConsole; | ||
163 | m_scene.UnregisterModuleCommander(m_commander.Name); | ||
164 | } | 177 | } |
165 | 178 | ||
166 | // private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason) | 179 | // private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason) |
@@ -168,30 +181,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
168 | // ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y); | 181 | // ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y); |
169 | // reason = "You are not allowed to enter this sim."; | 182 | // reason = "You are not allowed to enter this sim."; |
170 | // return nearestParcel != null; | 183 | // return nearestParcel != null; |
171 | // } | 184 | // } |
172 | |||
173 | /// <summary> | ||
174 | /// Processes commandline input. Do not call directly. | ||
175 | /// </summary> | ||
176 | /// <param name="args">Commandline arguments</param> | ||
177 | protected void EventManagerOnPluginConsole(string[] args) | ||
178 | { | ||
179 | if (args[0] == "land") | ||
180 | { | ||
181 | if (args.Length == 1) | ||
182 | { | ||
183 | m_commander.ProcessConsoleCommand("help", new string[0]); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | string[] tmpArgs = new string[args.Length - 2]; | ||
188 | int i; | ||
189 | for (i = 2; i < args.Length; i++) | ||
190 | tmpArgs[i - 2] = args[i]; | ||
191 | |||
192 | m_commander.ProcessConsoleCommand(args[1], tmpArgs); | ||
193 | } | ||
194 | } | ||
195 | 185 | ||
196 | void EventManagerOnNewClient(IClientAPI client) | 186 | void EventManagerOnNewClient(IClientAPI client) |
197 | { | 187 | { |
@@ -210,6 +200,10 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
210 | client.OnParcelInfoRequest += ClientOnParcelInfoRequest; | 200 | client.OnParcelInfoRequest += ClientOnParcelInfoRequest; |
211 | client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; | 201 | client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; |
212 | client.OnPreAgentUpdate += ClientOnPreAgentUpdate; | 202 | client.OnPreAgentUpdate += ClientOnPreAgentUpdate; |
203 | client.OnParcelEjectUser += ClientOnParcelEjectUser; | ||
204 | client.OnParcelFreezeUser += ClientOnParcelFreezeUser; | ||
205 | client.OnSetStartLocationRequest += ClientOnSetHome; | ||
206 | |||
213 | 207 | ||
214 | EntityBase presenceEntity; | 208 | EntityBase presenceEntity; |
215 | if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) | 209 | if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) |
@@ -293,14 +287,15 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
293 | LandData newData = data.Copy(); | 287 | LandData newData = data.Copy(); |
294 | newData.LocalID = local_id; | 288 | newData.LocalID = local_id; |
295 | 289 | ||
290 | ILandObject land; | ||
296 | lock (m_landList) | 291 | lock (m_landList) |
297 | { | 292 | { |
298 | if (m_landList.ContainsKey(local_id)) | 293 | if (m_landList.TryGetValue(local_id, out land)) |
299 | { | 294 | land.LandData = newData; |
300 | m_landList[local_id].LandData = newData; | ||
301 | m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, m_landList[local_id]); | ||
302 | } | ||
303 | } | 295 | } |
296 | |||
297 | if (land != null) | ||
298 | m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land); | ||
304 | } | 299 | } |
305 | 300 | ||
306 | public bool AllowedForcefulBans | 301 | public bool AllowedForcefulBans |
@@ -319,7 +314,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
319 | { | 314 | { |
320 | m_landList.Clear(); | 315 | m_landList.Clear(); |
321 | m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; | 316 | m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; |
322 | m_landIDList.Initialize(); | 317 | m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit]; |
323 | } | 318 | } |
324 | } | 319 | } |
325 | 320 | ||
@@ -333,7 +328,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
333 | "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); | 328 | "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); |
334 | 329 | ||
335 | ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); | 330 | ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); |
336 | fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); | 331 | fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, |
332 | (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY)); | ||
337 | fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 333 | fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; |
338 | fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); | 334 | fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); |
339 | 335 | ||
@@ -460,8 +456,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
460 | 456 | ||
461 | public void SendLandUpdate(ScenePresence avatar, bool force) | 457 | public void SendLandUpdate(ScenePresence avatar, bool force) |
462 | { | 458 | { |
463 | ILandObject over = GetLandObject((int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), | 459 | ILandObject over = GetLandObject((int)Math.Min(((int)m_scene.RegionInfo.RegionSizeX - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), |
464 | (int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); | 460 | (int)Math.Min(((int)m_scene.RegionInfo.RegionSizeY - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); |
465 | 461 | ||
466 | if (over != null) | 462 | if (over != null) |
467 | { | 463 | { |
@@ -543,16 +539,13 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
543 | /// </summary> | 539 | /// </summary> |
544 | /// <param name="avatar"></param> | 540 | /// <param name="avatar"></param> |
545 | public void EventManagerOnClientMovement(ScenePresence avatar) | 541 | public void EventManagerOnClientMovement(ScenePresence avatar) |
546 | // | ||
547 | { | 542 | { |
548 | ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); | 543 | Vector3 pos = avatar.AbsolutePosition; |
544 | ILandObject over = GetLandObject(pos.X, pos.Y); | ||
549 | if (over != null) | 545 | if (over != null) |
550 | { | 546 | { |
551 | if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT)) | 547 | if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || pos.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT)) |
552 | { | 548 | avatar.lastKnownAllowedPosition = pos; |
553 | avatar.lastKnownAllowedPosition = | ||
554 | new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z); | ||
555 | } | ||
556 | } | 549 | } |
557 | } | 550 | } |
558 | 551 | ||
@@ -611,7 +604,10 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
611 | /// <summary> | 604 | /// <summary> |
612 | /// Adds a land object to the stored list and adds them to the landIDList to what they own | 605 | /// Adds a land object to the stored list and adds them to the landIDList to what they own |
613 | /// </summary> | 606 | /// </summary> |
614 | /// <param name="new_land">The land object being added</param> | 607 | /// <param name="new_land"> |
608 | /// The land object being added. | ||
609 | /// Will return null if this overlaps with an existing parcel that has not had its bitmap adjusted. | ||
610 | /// </param> | ||
615 | public ILandObject AddLandObject(ILandObject land) | 611 | public ILandObject AddLandObject(ILandObject land) |
616 | { | 612 | { |
617 | ILandObject new_land = land.Copy(); | 613 | ILandObject new_land = land.Copy(); |
@@ -619,34 +615,76 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
619 | // Only now can we add the prim counts to the land object - we rely on the global ID which is generated | 615 | // Only now can we add the prim counts to the land object - we rely on the global ID which is generated |
620 | // as a random UUID inside LandData initialization | 616 | // as a random UUID inside LandData initialization |
621 | if (m_primCountModule != null) | 617 | if (m_primCountModule != null) |
622 | new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID); | 618 | new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID); |
623 | 619 | ||
624 | lock (m_landList) | 620 | lock (m_landList) |
625 | { | 621 | { |
626 | int newLandLocalID = ++m_lastLandLocalID; | 622 | int newLandLocalID = m_lastLandLocalID + 1; |
627 | new_land.LandData.LocalID = newLandLocalID; | 623 | new_land.LandData.LocalID = newLandLocalID; |
628 | 624 | ||
629 | bool[,] landBitmap = new_land.GetLandBitmap(); | 625 | bool[,] landBitmap = new_land.GetLandBitmap(); |
630 | for (int x = 0; x < landArrayMax; x++) | 626 | // m_log.DebugFormat("{0} AddLandObject. new_land.bitmapSize=({1},{2}). newLocalID={3}", |
627 | // LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), newLandLocalID); | ||
628 | |||
629 | if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1)) | ||
630 | { | ||
631 | // Going to variable sized regions can cause mismatches | ||
632 | m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})", | ||
633 | LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1) ); | ||
634 | } | ||
635 | else | ||
631 | { | 636 | { |
632 | for (int y = 0; y < landArrayMax; y++) | 637 | // If other land objects still believe that they occupy any parts of the same space, |
638 | // then do not allow the add to proceed. | ||
639 | for (int x = 0; x < landBitmap.GetLength(0); x++) | ||
633 | { | 640 | { |
634 | if (landBitmap[x, y]) | 641 | for (int y = 0; y < landBitmap.GetLength(1); y++) |
635 | { | 642 | { |
636 | // m_log.DebugFormat( | 643 | if (landBitmap[x, y]) |
637 | // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", | 644 | { |
638 | // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); | 645 | int lastRecordedLandId = m_landIDList[x, y]; |
639 | 646 | ||
640 | m_landIDList[x, y] = newLandLocalID; | 647 | if (lastRecordedLandId > 0) |
648 | { | ||
649 | ILandObject lastRecordedLo = m_landList[lastRecordedLandId]; | ||
650 | |||
651 | if (lastRecordedLo.LandBitmap[x, y]) | ||
652 | { | ||
653 | m_log.ErrorFormat( | ||
654 | "{0}: Cannot add parcel \"{1}\", local ID {2} at tile {3},{4} because this is still occupied by parcel \"{5}\", local ID {6} in {7}", | ||
655 | LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y, | ||
656 | lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID, m_scene.Name); | ||
657 | |||
658 | return null; | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | |||
665 | for (int x = 0; x < landBitmap.GetLength(0); x++) | ||
666 | { | ||
667 | for (int y = 0; y < landBitmap.GetLength(1); y++) | ||
668 | { | ||
669 | if (landBitmap[x, y]) | ||
670 | { | ||
671 | // m_log.DebugFormat( | ||
672 | // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", | ||
673 | // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); | ||
674 | |||
675 | m_landIDList[x, y] = newLandLocalID; | ||
676 | } | ||
641 | } | 677 | } |
642 | } | 678 | } |
643 | } | 679 | } |
644 | 680 | ||
645 | m_landList.Add(newLandLocalID, new_land); | 681 | m_landList.Add(newLandLocalID, new_land); |
682 | m_lastLandLocalID++; | ||
646 | } | 683 | } |
647 | 684 | ||
648 | new_land.ForceUpdateLandInfo(); | 685 | new_land.ForceUpdateLandInfo(); |
649 | m_scene.EventManager.TriggerLandObjectAdded(new_land); | 686 | m_scene.EventManager.TriggerLandObjectAdded(new_land); |
687 | |||
650 | return new_land; | 688 | return new_land; |
651 | } | 689 | } |
652 | 690 | ||
@@ -656,11 +694,12 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
656 | /// <param name="local_id">Land.localID of the peice of land to remove.</param> | 694 | /// <param name="local_id">Land.localID of the peice of land to remove.</param> |
657 | public void removeLandObject(int local_id) | 695 | public void removeLandObject(int local_id) |
658 | { | 696 | { |
697 | ILandObject land; | ||
659 | lock (m_landList) | 698 | lock (m_landList) |
660 | { | 699 | { |
661 | for (int x = 0; x < 64; x++) | 700 | for (int x = 0; x < m_landIDList.GetLength(0); x++) |
662 | { | 701 | { |
663 | for (int y = 0; y < 64; y++) | 702 | for (int y = 0; y < m_landIDList.GetLength(1); y++) |
664 | { | 703 | { |
665 | if (m_landIDList[x, y] == local_id) | 704 | if (m_landIDList[x, y] == local_id) |
666 | { | 705 | { |
@@ -672,9 +711,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
672 | } | 711 | } |
673 | } | 712 | } |
674 | 713 | ||
675 | m_scene.EventManager.TriggerLandObjectRemoved(m_landList[local_id].LandData.GlobalID); | 714 | land = m_landList[local_id]; |
676 | m_landList.Remove(local_id); | 715 | m_landList.Remove(local_id); |
677 | } | 716 | } |
717 | |||
718 | m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID); | ||
678 | } | 719 | } |
679 | 720 | ||
680 | /// <summary> | 721 | /// <summary> |
@@ -682,21 +723,27 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
682 | /// </summary> | 723 | /// </summary> |
683 | public void Clear(bool setupDefaultParcel) | 724 | public void Clear(bool setupDefaultParcel) |
684 | { | 725 | { |
726 | List<ILandObject> parcels; | ||
685 | lock (m_landList) | 727 | lock (m_landList) |
686 | { | 728 | { |
687 | foreach (ILandObject lo in m_landList.Values) | 729 | parcels = new List<ILandObject>(m_landList.Values); |
688 | { | 730 | } |
689 | //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID); | 731 | |
690 | m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID); | 732 | foreach (ILandObject lo in parcels) |
691 | } | 733 | { |
734 | //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID); | ||
735 | m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID); | ||
736 | } | ||
692 | 737 | ||
738 | lock (m_landList) | ||
739 | { | ||
693 | m_landList.Clear(); | 740 | m_landList.Clear(); |
694 | 741 | ||
695 | ResetSimLandObjects(); | 742 | ResetSimLandObjects(); |
696 | |||
697 | if (setupDefaultParcel) | ||
698 | CreateDefaultParcel(); | ||
699 | } | 743 | } |
744 | |||
745 | if (setupDefaultParcel) | ||
746 | CreateDefaultParcel(); | ||
700 | } | 747 | } |
701 | 748 | ||
702 | private void performFinalLandJoin(ILandObject master, ILandObject slave) | 749 | private void performFinalLandJoin(ILandObject master, ILandObject slave) |
@@ -704,9 +751,9 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
704 | bool[,] landBitmapSlave = slave.GetLandBitmap(); | 751 | bool[,] landBitmapSlave = slave.GetLandBitmap(); |
705 | lock (m_landList) | 752 | lock (m_landList) |
706 | { | 753 | { |
707 | for (int x = 0; x < 64; x++) | 754 | for (int x = 0; x < landBitmapSlave.GetLength(0); x++) |
708 | { | 755 | { |
709 | for (int y = 0; y < 64; y++) | 756 | for (int y = 0; y < landBitmapSlave.GetLength(1); y++) |
710 | { | 757 | { |
711 | if (landBitmapSlave[x, y]) | 758 | if (landBitmapSlave[x, y]) |
712 | { | 759 | { |
@@ -740,23 +787,28 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
740 | /// <returns>Land object at the point supplied</returns> | 787 | /// <returns>Land object at the point supplied</returns> |
741 | public ILandObject GetLandObject(float x_float, float y_float) | 788 | public ILandObject GetLandObject(float x_float, float y_float) |
742 | { | 789 | { |
790 | return GetLandObject((int)x_float, (int)y_float, true /* returnNullIfLandObjectNotFound */); | ||
791 | /* | ||
743 | int x; | 792 | int x; |
744 | int y; | 793 | int y; |
745 | 794 | ||
746 | if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0) | 795 | if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0) |
747 | return null; | 796 | return null; |
748 | 797 | ||
749 | try | 798 | try |
750 | { | 799 | { |
751 | x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0)); | 800 | x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit)); |
752 | y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0)); | 801 | y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit)); |
753 | } | 802 | } |
754 | catch (OverflowException) | 803 | catch (OverflowException) |
755 | { | 804 | { |
756 | return null; | 805 | return null; |
757 | } | 806 | } |
758 | 807 | ||
759 | if (x >= 64 || y >= 64 || x < 0 || y < 0) | 808 | if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit) |
809 | || y >= (m_scene.RegionInfo.RegionSizeY / landUnit) | ||
810 | || x < 0 | ||
811 | || y < 0) | ||
760 | { | 812 | { |
761 | return null; | 813 | return null; |
762 | } | 814 | } |
@@ -772,38 +824,70 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
772 | // m_log.DebugFormat( | 824 | // m_log.DebugFormat( |
773 | // "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", | 825 | // "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", |
774 | // x, y, m_scene.RegionInfo.RegionName); | 826 | // x, y, m_scene.RegionInfo.RegionName); |
775 | 827 | ||
776 | if (m_landList.ContainsKey(m_landIDList[x, y])) | 828 | try |
777 | return m_landList[m_landIDList[x, y]]; | 829 | { |
830 | if (m_landList.ContainsKey(m_landIDList[x, y])) | ||
831 | return m_landList[m_landIDList[x, y]]; | ||
832 | } | ||
833 | catch (Exception e) | ||
834 | { | ||
835 | m_log.DebugFormat("{0} GetLandObject exception. x={1}, y={2}, m_landIDList.len=({3},{4})", | ||
836 | LogHeader, x, y, m_landIDList.GetLength(0), m_landIDList.GetLength(1)); | ||
837 | } | ||
778 | 838 | ||
779 | return null; | 839 | return null; |
780 | } | 840 | } |
841 | */ | ||
781 | } | 842 | } |
782 | 843 | ||
844 | // Public entry. | ||
845 | // Throws exception if land object is not found | ||
783 | public ILandObject GetLandObject(int x, int y) | 846 | public ILandObject GetLandObject(int x, int y) |
784 | { | 847 | { |
785 | if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) | 848 | return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */); |
849 | } | ||
850 | |||
851 | /// <summary> | ||
852 | /// Given a region position, return the parcel land object for that location | ||
853 | /// </summary> | ||
854 | /// <returns> | ||
855 | /// The land object. | ||
856 | /// </returns> | ||
857 | /// <param name='x'></param> | ||
858 | /// <param name='y'></param> | ||
859 | /// <param name='returnNullIfLandObjectNotFound'> | ||
860 | /// Return null if the land object requested is not within the region's bounds. | ||
861 | /// </param> | ||
862 | private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds) | ||
863 | { | ||
864 | if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0) | ||
786 | { | 865 | { |
787 | // These exceptions here will cause a lot of complaints from the users specifically because | 866 | // These exceptions here will cause a lot of complaints from the users specifically because |
788 | // they happen every time at border crossings | 867 | // they happen every time at border crossings |
789 | throw new Exception("Error: Parcel not found at point " + x + ", " + y); | 868 | if (returnNullIfLandObjectOutsideBounds) |
790 | } | ||
791 | |||
792 | lock (m_landIDList) | ||
793 | { | ||
794 | try | ||
795 | { | ||
796 | return m_landList[m_landIDList[x / 4, y / 4]]; | ||
797 | } | ||
798 | catch (IndexOutOfRangeException) | ||
799 | { | ||
800 | // m_log.WarnFormat( | ||
801 | // "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}", | ||
802 | // x, y, m_scene.RegionInfo.RegionName); | ||
803 | |||
804 | return null; | 869 | return null; |
805 | } | 870 | else |
871 | throw new Exception( | ||
872 | String.Format("{0} GetLandObject for non-existent position. Region={1}, pos=<{2},{3}", | ||
873 | LogHeader, m_scene.RegionInfo.RegionName, x, y) | ||
874 | ); | ||
806 | } | 875 | } |
876 | |||
877 | return m_landList[m_landIDList[x / 4, y / 4]]; | ||
878 | } | ||
879 | |||
880 | // Create a 'parcel is here' bitmap for the parcel identified by the passed landID | ||
881 | private bool[,] CreateBitmapForID(int landID) | ||
882 | { | ||
883 | bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)]; | ||
884 | |||
885 | for (int xx = 0; xx < m_landIDList.GetLength(0); xx++) | ||
886 | for (int yy = 0; yy < m_landIDList.GetLength(0); yy++) | ||
887 | if (m_landIDList[xx, yy] == landID) | ||
888 | ret[xx, yy] = true; | ||
889 | |||
890 | return ret; | ||
807 | } | 891 | } |
808 | 892 | ||
809 | #endregion | 893 | #endregion |
@@ -973,8 +1057,12 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
973 | 1057 | ||
974 | //Now add the new land object | 1058 | //Now add the new land object |
975 | ILandObject result = AddLandObject(newLand); | 1059 | ILandObject result = AddLandObject(newLand); |
976 | UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData); | 1060 | |
977 | result.SendLandUpdateToAvatarsOverMe(); | 1061 | if (result != null) |
1062 | { | ||
1063 | UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData); | ||
1064 | result.SendLandUpdateToAvatarsOverMe(); | ||
1065 | } | ||
978 | } | 1066 | } |
979 | 1067 | ||
980 | /// <summary> | 1068 | /// <summary> |
@@ -1055,96 +1143,164 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1055 | 1143 | ||
1056 | #region Parcel Updating | 1144 | #region Parcel Updating |
1057 | 1145 | ||
1146 | // Send parcel layer info for the whole region | ||
1147 | public void SendParcelOverlay(IClientAPI remote_client) | ||
1148 | { | ||
1149 | SendParcelOverlay(remote_client, 0, 0, (int)Constants.MaximumRegionSize); | ||
1150 | } | ||
1151 | |||
1058 | /// <summary> | 1152 | /// <summary> |
1059 | /// Where we send the ParcelOverlay packet to the client | 1153 | /// Send the parcel overlay blocks to the client. We send the overlay packets |
1154 | /// around a location and limited by the 'parcelLayerViewDistance'. This number | ||
1155 | /// is usually 128 and the code is arranged so it sends all the parcel overlay | ||
1156 | /// information for a whole region if the region is legacy sized (256x256). If | ||
1157 | /// the region is larger, only the parcel layer information is sent around | ||
1158 | /// the point specified. This reduces the problem of parcel layer information | ||
1159 | /// blocks increasing exponentially as region size increases. | ||
1060 | /// </summary> | 1160 | /// </summary> |
1061 | /// <param name="remote_client">The object representing the client</param> | 1161 | /// <param name="remote_client">The object representing the client</param> |
1062 | public void SendParcelOverlay(IClientAPI remote_client) | 1162 | /// <param name="xPlace">X position in the region to send surrounding parcel layer info</param> |
1163 | /// <param name="yPlace">y position in the region to send surrounding parcel layer info</param> | ||
1164 | /// <param name="layerViewDistance">Distance from x,y position to send parcel layer info</param> | ||
1165 | private void SendParcelOverlay(IClientAPI remote_client, int xPlace, int yPlace, int layerViewDistance) | ||
1063 | { | 1166 | { |
1064 | const int LAND_BLOCKS_PER_PACKET = 1024; | 1167 | const int LAND_BLOCKS_PER_PACKET = 1024; |
1065 | 1168 | ||
1066 | byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; | 1169 | byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; |
1067 | int byteArrayCount = 0; | 1170 | int byteArrayCount = 0; |
1068 | int sequenceID = 0; | 1171 | int sequenceID = 0; |
1069 | int blockmeters = 4 * (int) Constants.RegionSize/(int)Constants.TerrainPatchSize; | ||
1070 | 1172 | ||
1173 | int xLow = 0; | ||
1174 | int xHigh = (int)m_scene.RegionInfo.RegionSizeX; | ||
1175 | int yLow = 0; | ||
1176 | int yHigh = (int)m_scene.RegionInfo.RegionSizeY; | ||
1071 | 1177 | ||
1072 | for (int y = 0; y < blockmeters; y++) | 1178 | if (shouldLimitParcelLayerInfoToViewDistance) |
1073 | { | 1179 | { |
1074 | for (int x = 0; x < blockmeters; x++) | 1180 | // Compute view distance around the given point |
1181 | int txLow = xPlace - layerViewDistance; | ||
1182 | int txHigh = xPlace + layerViewDistance; | ||
1183 | // If the distance is outside the region area, move the view distance to ba all in the region | ||
1184 | if (txLow < xLow) | ||
1185 | { | ||
1186 | txLow = xLow; | ||
1187 | txHigh = Math.Min(yLow + (layerViewDistance * 2), xHigh); | ||
1188 | } | ||
1189 | if (txHigh > xHigh) | ||
1075 | { | 1190 | { |
1076 | byte tempByte = 0; //This represents the byte for the current 4x4 | 1191 | txLow = Math.Max(xLow, xHigh - (layerViewDistance * 2)); |
1192 | txHigh = xHigh; | ||
1193 | } | ||
1194 | xLow = txLow; | ||
1195 | xHigh = txHigh; | ||
1077 | 1196 | ||
1078 | ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4); | 1197 | int tyLow = yPlace - layerViewDistance; |
1198 | int tyHigh = yPlace + layerViewDistance; | ||
1199 | if (tyLow < yLow) | ||
1200 | { | ||
1201 | tyLow = yLow; | ||
1202 | tyHigh = Math.Min(yLow + (layerViewDistance * 2), yHigh); | ||
1203 | } | ||
1204 | if (tyHigh > yHigh) | ||
1205 | { | ||
1206 | tyLow = Math.Max(yLow, yHigh - (layerViewDistance * 2)); | ||
1207 | tyHigh = yHigh; | ||
1208 | } | ||
1209 | yLow = tyLow; | ||
1210 | yHigh = tyHigh; | ||
1211 | } | ||
1212 | // m_log.DebugFormat("{0} SendParcelOverlay: place=<{1},{2}>, vDist={3}, xLH=<{4},{5}, yLH=<{6},{7}>", | ||
1213 | // LogHeader, xPlace, yPlace, layerViewDistance, xLow, xHigh, yLow, yHigh); | ||
1079 | 1214 | ||
1080 | if (currentParcelBlock != null) | 1215 | // Layer data is in landUnit (4m) chunks |
1216 | for (int y = yLow; y < yHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) | ||
1217 | { | ||
1218 | for (int x = xLow; x < xHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++) | ||
1219 | { | ||
1220 | byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client); | ||
1221 | byteArrayCount++; | ||
1222 | if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) | ||
1081 | { | 1223 | { |
1082 | if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) | 1224 | // m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length); |
1083 | { | 1225 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); |
1084 | //Owner Flag | 1226 | byteArrayCount = 0; |
1085 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); | 1227 | sequenceID++; |
1086 | } | 1228 | byteArray = new byte[LAND_BLOCKS_PER_PACKET]; |
1087 | else if (currentParcelBlock.LandData.SalePrice > 0 && | 1229 | } |
1088 | (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || | ||
1089 | currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) | ||
1090 | { | ||
1091 | //Sale Flag | ||
1092 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE); | ||
1093 | } | ||
1094 | else if (currentParcelBlock.LandData.OwnerID == UUID.Zero) | ||
1095 | { | ||
1096 | //Public Flag | ||
1097 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC); | ||
1098 | } | ||
1099 | else | ||
1100 | { | ||
1101 | //Other Flag | ||
1102 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER); | ||
1103 | } | ||
1104 | 1230 | ||
1105 | //Now for border control | 1231 | } |
1232 | } | ||
1106 | 1233 | ||
1107 | ILandObject westParcel = null; | 1234 | if (byteArrayCount != 0) |
1108 | ILandObject southParcel = null; | 1235 | { |
1109 | if (x > 0) | 1236 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); |
1110 | { | 1237 | // m_log.DebugFormat("{0} SendParcelOverlay, complete sending packet, bytes={1}", LogHeader, byteArray.Length); |
1111 | westParcel = GetLandObject((x - 1) * 4, y * 4); | 1238 | } |
1112 | } | 1239 | } |
1113 | if (y > 0) | ||
1114 | { | ||
1115 | southParcel = GetLandObject(x * 4, (y - 1) * 4); | ||
1116 | } | ||
1117 | 1240 | ||
1118 | if (x == 0) | 1241 | private byte BuildLayerByte(ILandObject currentParcelBlock, int x, int y, IClientAPI remote_client) |
1119 | { | 1242 | { |
1120 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); | 1243 | byte tempByte = 0; //This represents the byte for the current 4x4 |
1121 | } | ||
1122 | else if (westParcel != null && westParcel != currentParcelBlock) | ||
1123 | { | ||
1124 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); | ||
1125 | } | ||
1126 | 1244 | ||
1127 | if (y == 0) | 1245 | if (currentParcelBlock != null) |
1128 | { | 1246 | { |
1129 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); | 1247 | if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) |
1130 | } | 1248 | { |
1131 | else if (southParcel != null && southParcel != currentParcelBlock) | 1249 | //Owner Flag |
1132 | { | 1250 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); |
1133 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); | 1251 | } |
1134 | } | 1252 | else if (currentParcelBlock.LandData.SalePrice > 0 && |
1253 | (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || | ||
1254 | currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) | ||
1255 | { | ||
1256 | //Sale Flag | ||
1257 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE); | ||
1258 | } | ||
1259 | else if (currentParcelBlock.LandData.OwnerID == UUID.Zero) | ||
1260 | { | ||
1261 | //Public Flag | ||
1262 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC); | ||
1263 | } | ||
1264 | else | ||
1265 | { | ||
1266 | //Other Flag | ||
1267 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER); | ||
1268 | } | ||
1135 | 1269 | ||
1136 | byteArray[byteArrayCount] = tempByte; | 1270 | //Now for border control |
1137 | byteArrayCount++; | 1271 | |
1138 | if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) | 1272 | ILandObject westParcel = null; |
1139 | { | 1273 | ILandObject southParcel = null; |
1140 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); | 1274 | if (x > 0) |
1141 | byteArrayCount = 0; | 1275 | { |
1142 | sequenceID++; | 1276 | westParcel = GetLandObject((x - 1) * LandUnit, y * LandUnit); |
1143 | byteArray = new byte[LAND_BLOCKS_PER_PACKET]; | 1277 | } |
1144 | } | 1278 | if (y > 0) |
1145 | } | 1279 | { |
1280 | southParcel = GetLandObject(x * LandUnit, (y - 1) * LandUnit); | ||
1281 | } | ||
1282 | |||
1283 | if (x == 0) | ||
1284 | { | ||
1285 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); | ||
1286 | } | ||
1287 | else if (westParcel != null && westParcel != currentParcelBlock) | ||
1288 | { | ||
1289 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); | ||
1146 | } | 1290 | } |
1291 | |||
1292 | if (y == 0) | ||
1293 | { | ||
1294 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); | ||
1295 | } | ||
1296 | else if (southParcel != null && southParcel != currentParcelBlock) | ||
1297 | { | ||
1298 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); | ||
1299 | } | ||
1300 | |||
1147 | } | 1301 | } |
1302 | |||
1303 | return tempByte; | ||
1148 | } | 1304 | } |
1149 | 1305 | ||
1150 | public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, | 1306 | public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, |
@@ -1182,7 +1338,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1182 | temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); | 1338 | temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); |
1183 | } | 1339 | } |
1184 | 1340 | ||
1185 | SendParcelOverlay(remote_client); | 1341 | // Also send the layer data around the point of interest |
1342 | SendParcelOverlay(remote_client, (start_x + end_x) / 2, (start_y + end_y) / 2, parcelLayerViewDistance); | ||
1186 | } | 1343 | } |
1187 | 1344 | ||
1188 | public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) | 1345 | public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) |
@@ -1254,6 +1411,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1254 | 1411 | ||
1255 | m_scene.ForEachClient(SendParcelOverlay); | 1412 | m_scene.ForEachClient(SendParcelOverlay); |
1256 | land.SendLandUpdateToClient(true, remote_client); | 1413 | land.SendLandUpdateToClient(true, remote_client); |
1414 | UpdateLandObject(land.LandData.LocalID, land.LandData); | ||
1257 | } | 1415 | } |
1258 | } | 1416 | } |
1259 | } | 1417 | } |
@@ -1274,8 +1432,10 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1274 | land.LandData.GroupID = UUID.Zero; | 1432 | land.LandData.GroupID = UUID.Zero; |
1275 | land.LandData.IsGroupOwned = false; | 1433 | land.LandData.IsGroupOwned = false; |
1276 | land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); | 1434 | land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); |
1435 | |||
1277 | m_scene.ForEachClient(SendParcelOverlay); | 1436 | m_scene.ForEachClient(SendParcelOverlay); |
1278 | land.SendLandUpdateToClient(true, remote_client); | 1437 | land.SendLandUpdateToClient(true, remote_client); |
1438 | UpdateLandObject(land.LandData.LocalID, land.LandData); | ||
1279 | } | 1439 | } |
1280 | } | 1440 | } |
1281 | } | 1441 | } |
@@ -1302,6 +1462,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1302 | 1462 | ||
1303 | m_scene.ForEachClient(SendParcelOverlay); | 1463 | m_scene.ForEachClient(SendParcelOverlay); |
1304 | land.SendLandUpdateToClient(true, remote_client); | 1464 | land.SendLandUpdateToClient(true, remote_client); |
1465 | UpdateLandObject(land.LandData.LocalID, land.LandData); | ||
1305 | } | 1466 | } |
1306 | } | 1467 | } |
1307 | } | 1468 | } |
@@ -1382,19 +1543,78 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1382 | 1543 | ||
1383 | #region Land Object From Storage Functions | 1544 | #region Land Object From Storage Functions |
1384 | 1545 | ||
1385 | public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) | 1546 | private void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) |
1386 | { | 1547 | { |
1387 | // m_log.DebugFormat( | 1548 | // m_log.DebugFormat( |
1388 | // "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name); | 1549 | // "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name); |
1389 | 1550 | ||
1390 | for (int i = 0; i < data.Count; i++) | 1551 | // Prevent race conditions from any auto-creation of new parcels for varregions whilst we are still loading |
1391 | IncomingLandObjectFromStorage(data[i]); | 1552 | // the existing parcels. |
1553 | lock (m_landList) | ||
1554 | { | ||
1555 | for (int i = 0; i < data.Count; i++) | ||
1556 | IncomingLandObjectFromStorage(data[i]); | ||
1557 | |||
1558 | // Layer data is in landUnit (4m) chunks | ||
1559 | for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) | ||
1560 | { | ||
1561 | for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++) | ||
1562 | { | ||
1563 | if (m_landIDList[x, y] == 0) | ||
1564 | { | ||
1565 | if (m_landList.Count == 1) | ||
1566 | { | ||
1567 | m_log.DebugFormat( | ||
1568 | "[{0}]: Auto-extending land parcel as landID at {1},{2} is 0 and only one land parcel is present in {3}", | ||
1569 | LogHeader, x, y, m_scene.Name); | ||
1570 | |||
1571 | int onlyParcelID = 0; | ||
1572 | ILandObject onlyLandObject = null; | ||
1573 | foreach (KeyValuePair<int, ILandObject> kvp in m_landList) | ||
1574 | { | ||
1575 | onlyParcelID = kvp.Key; | ||
1576 | onlyLandObject = kvp.Value; | ||
1577 | break; | ||
1578 | } | ||
1579 | |||
1580 | // There is only one parcel. Grow it to fill all the unallocated spaces. | ||
1581 | for (int xx = 0; xx < m_landIDList.GetLength(0); xx++) | ||
1582 | for (int yy = 0; yy < m_landIDList.GetLength(1); yy++) | ||
1583 | if (m_landIDList[xx, yy] == 0) | ||
1584 | m_landIDList[xx, yy] = onlyParcelID; | ||
1585 | |||
1586 | onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID); | ||
1587 | } | ||
1588 | else if (m_landList.Count > 1) | ||
1589 | { | ||
1590 | m_log.DebugFormat( | ||
1591 | "{0}: Auto-creating land parcel as landID at {1},{2} is 0 and more than one land parcel is present in {3}", | ||
1592 | LogHeader, x, y, m_scene.Name); | ||
1593 | |||
1594 | // There are several other parcels so we must create a new one for the unassigned space | ||
1595 | ILandObject newLand = new LandObject(UUID.Zero, false, m_scene); | ||
1596 | // Claim all the unclaimed "0" ids | ||
1597 | newLand.SetLandBitmap(CreateBitmapForID(0)); | ||
1598 | newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | ||
1599 | newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); | ||
1600 | newLand = AddLandObject(newLand); | ||
1601 | } | ||
1602 | else | ||
1603 | { | ||
1604 | // We should never reach this point as the separate code path when no land data exists should have fired instead. | ||
1605 | m_log.WarnFormat( | ||
1606 | "{0}: Ignoring request to auto-create parcel in {1} as there are no other parcels present", | ||
1607 | LogHeader, m_scene.Name); | ||
1608 | } | ||
1609 | } | ||
1610 | } | ||
1611 | } | ||
1612 | } | ||
1392 | } | 1613 | } |
1393 | 1614 | ||
1394 | public void IncomingLandObjectFromStorage(LandData data) | 1615 | private void IncomingLandObjectFromStorage(LandData data) |
1395 | { | 1616 | { |
1396 | ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene); | 1617 | ILandObject new_land = new LandObject(data, m_scene); |
1397 | new_land.LandData = data.Copy(); | ||
1398 | new_land.SetLandBitmapFromByteArray(); | 1618 | new_land.SetLandBitmapFromByteArray(); |
1399 | AddLandObject(new_land); | 1619 | AddLandObject(new_land); |
1400 | } | 1620 | } |
@@ -1409,7 +1629,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1409 | m_landList.TryGetValue(localID, out selectedParcel); | 1629 | m_landList.TryGetValue(localID, out selectedParcel); |
1410 | } | 1630 | } |
1411 | 1631 | ||
1412 | if (selectedParcel == null) return; | 1632 | if (selectedParcel == null) |
1633 | return; | ||
1413 | 1634 | ||
1414 | selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); | 1635 | selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); |
1415 | } | 1636 | } |
@@ -1417,7 +1638,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1417 | { | 1638 | { |
1418 | if (returnType != 1) | 1639 | if (returnType != 1) |
1419 | { | 1640 | { |
1420 | m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown return type {0}", returnType); | 1641 | m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType); |
1421 | return; | 1642 | return; |
1422 | } | 1643 | } |
1423 | 1644 | ||
@@ -1437,14 +1658,14 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1437 | } | 1658 | } |
1438 | else | 1659 | else |
1439 | { | 1660 | { |
1440 | m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown object {0}", groupID); | 1661 | m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID); |
1441 | } | 1662 | } |
1442 | } | 1663 | } |
1443 | 1664 | ||
1444 | int num = 0; | 1665 | int num = 0; |
1445 | foreach (HashSet<SceneObjectGroup> objs in returns.Values) | 1666 | foreach (HashSet<SceneObjectGroup> objs in returns.Values) |
1446 | num += objs.Count; | 1667 | num += objs.Count; |
1447 | m_log.DebugFormat("[LAND MANAGEMENT MODULE] Returning {0} specific object(s)", num); | 1668 | m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num); |
1448 | 1669 | ||
1449 | foreach (HashSet<SceneObjectGroup> objs in returns.Values) | 1670 | foreach (HashSet<SceneObjectGroup> objs in returns.Values) |
1450 | { | 1671 | { |
@@ -1455,7 +1676,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1455 | } | 1676 | } |
1456 | else | 1677 | else |
1457 | { | 1678 | { |
1458 | m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}", | 1679 | m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}", |
1459 | objs2.Count, objs2[0].OwnerID); | 1680 | objs2.Count, objs2[0].OwnerID); |
1460 | } | 1681 | } |
1461 | } | 1682 | } |
@@ -1464,11 +1685,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1464 | 1685 | ||
1465 | public void EventManagerOnNoLandDataFromStorage() | 1686 | public void EventManagerOnNoLandDataFromStorage() |
1466 | { | 1687 | { |
1467 | lock (m_landList) | 1688 | ResetSimLandObjects(); |
1468 | { | 1689 | CreateDefaultParcel(); |
1469 | ResetSimLandObjects(); | ||
1470 | CreateDefaultParcel(); | ||
1471 | } | ||
1472 | } | 1690 | } |
1473 | 1691 | ||
1474 | #endregion | 1692 | #endregion |
@@ -1694,7 +1912,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1694 | { | 1912 | { |
1695 | // most likely still cached from building the extLandData entry | 1913 | // most likely still cached from building the extLandData entry |
1696 | uint x = 0, y = 0; | 1914 | uint x = 0, y = 0; |
1697 | Utils.LongToUInts(data.RegionHandle, out x, out y); | 1915 | Util.RegionHandleToWorldLoc(data.RegionHandle, out x, out y); |
1698 | info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); | 1916 | info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); |
1699 | } | 1917 | } |
1700 | // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. | 1918 | // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. |
@@ -1730,66 +1948,332 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1730 | UpdateLandObject(localID, land.LandData); | 1948 | UpdateLandObject(localID, land.LandData); |
1731 | } | 1949 | } |
1732 | 1950 | ||
1733 | protected void InstallInterfaces() | 1951 | Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>(); |
1952 | |||
1953 | public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target) | ||
1954 | { | ||
1955 | ScenePresence targetAvatar = null; | ||
1956 | ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar); | ||
1957 | ScenePresence parcelManager = null; | ||
1958 | ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager); | ||
1959 | System.Threading.Timer Timer; | ||
1960 | |||
1961 | if (targetAvatar.UserLevel == 0) | ||
1962 | { | ||
1963 | ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y); | ||
1964 | if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze)) | ||
1965 | return; | ||
1966 | if (flags == 0) | ||
1967 | { | ||
1968 | targetAvatar.AllowMovement = false; | ||
1969 | targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world."); | ||
1970 | parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen."); | ||
1971 | System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen); | ||
1972 | Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0); | ||
1973 | Timers.Add(targetAvatar.UUID, Timer); | ||
1974 | } | ||
1975 | else | ||
1976 | { | ||
1977 | targetAvatar.AllowMovement = true; | ||
1978 | targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you."); | ||
1979 | parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen."); | ||
1980 | Timers.TryGetValue(targetAvatar.UUID, out Timer); | ||
1981 | Timers.Remove(targetAvatar.UUID); | ||
1982 | Timer.Dispose(); | ||
1983 | } | ||
1984 | } | ||
1985 | } | ||
1986 | |||
1987 | private void OnEndParcelFrozen(object avatar) | ||
1734 | { | 1988 | { |
1735 | Command clearCommand | 1989 | ScenePresence targetAvatar = (ScenePresence)avatar; |
1736 | = new Command("clear", CommandIntentions.COMMAND_HAZARDOUS, ClearCommand, "Clears all the parcels from the region."); | 1990 | targetAvatar.AllowMovement = true; |
1737 | Command showCommand | 1991 | System.Threading.Timer Timer; |
1738 | = new Command("show", CommandIntentions.COMMAND_STATISTICAL, ShowParcelsCommand, "Shows all parcels on the region."); | 1992 | Timers.TryGetValue(targetAvatar.UUID, out Timer); |
1993 | Timers.Remove(targetAvatar.UUID); | ||
1994 | targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false); | ||
1995 | } | ||
1996 | |||
1997 | public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target) | ||
1998 | { | ||
1999 | ScenePresence targetAvatar = null; | ||
2000 | ScenePresence parcelManager = null; | ||
2001 | |||
2002 | // Must have presences | ||
2003 | if (!m_scene.TryGetScenePresence(target, out targetAvatar) || | ||
2004 | !m_scene.TryGetScenePresence(client.AgentId, out parcelManager)) | ||
2005 | return; | ||
2006 | |||
2007 | // Cannot eject estate managers or gods | ||
2008 | if (m_scene.Permissions.IsAdministrator(target)) | ||
2009 | return; | ||
2010 | |||
2011 | // Check if you even have permission to do this | ||
2012 | ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y); | ||
2013 | if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze) && | ||
2014 | !m_scene.Permissions.IsAdministrator(client.AgentId)) | ||
2015 | return; | ||
2016 | Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land); | ||
2017 | |||
2018 | targetAvatar.TeleportWithMomentum(pos, null); | ||
2019 | targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname); | ||
2020 | parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected."); | ||
1739 | 2021 | ||
1740 | m_commander.RegisterCommand("clear", clearCommand); | 2022 | if ((flags & 1) != 0) // Ban TODO: Remove magic number |
1741 | m_commander.RegisterCommand("show", showCommand); | 2023 | { |
2024 | LandAccessEntry entry = new LandAccessEntry(); | ||
2025 | entry.AgentID = targetAvatar.UUID; | ||
2026 | entry.Flags = AccessList.Ban; | ||
2027 | entry.Expires = 0; // Perm | ||
1742 | 2028 | ||
1743 | // Add this to our scene so scripts can call these functions | 2029 | land.LandData.ParcelAccessList.Add(entry); |
1744 | m_scene.RegisterModuleCommander(m_commander); | 2030 | } |
2031 | } | ||
2032 | |||
2033 | /// <summary> | ||
2034 | /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in | ||
2035 | /// </summary> | ||
2036 | /// <param name="remoteClient"></param> | ||
2037 | /// <param name="regionHandle"></param> | ||
2038 | /// <param name="position"></param> | ||
2039 | /// <param name="lookAt"></param> | ||
2040 | /// <param name="flags"></param> | ||
2041 | public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) | ||
2042 | { | ||
2043 | // Let's find the parcel in question | ||
2044 | ILandObject land = landChannel.GetLandObject(position); | ||
2045 | if (land == null || m_scene.GridUserService == null) | ||
2046 | { | ||
2047 | m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed."); | ||
2048 | return; | ||
2049 | } | ||
2050 | |||
2051 | // Gather some data | ||
2052 | ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID); | ||
2053 | SceneObjectGroup telehub = null; | ||
2054 | if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero) | ||
2055 | // Does the telehub exist in the scene? | ||
2056 | telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); | ||
2057 | |||
2058 | // Can the user set home here? | ||
2059 | if (// Required: local user; foreign users cannot set home | ||
2060 | m_scene.UserManagementModule.IsLocalGridUser(remoteClient.AgentId) && | ||
2061 | (// (a) gods and land managers can set home | ||
2062 | m_scene.Permissions.IsAdministrator(remoteClient.AgentId) || | ||
2063 | m_scene.Permissions.IsGod(remoteClient.AgentId) || | ||
2064 | // (b) land owners can set home | ||
2065 | remoteClient.AgentId == land.LandData.OwnerID || | ||
2066 | // (c) members of the land-associated group in roles that can set home | ||
2067 | ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) || | ||
2068 | // (d) parcels with telehubs can be the home of anyone | ||
2069 | (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y)))) | ||
2070 | { | ||
2071 | string userId; | ||
2072 | UUID test; | ||
2073 | if (!m_scene.UserManagementModule.GetUserUUI(remoteClient.AgentId, out userId)) | ||
2074 | { | ||
2075 | /* Do not set a home position in this grid for a HG visitor */ | ||
2076 | m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (User Lookup)"); | ||
2077 | } | ||
2078 | else if (!UUID.TryParse(userId, out test)) | ||
2079 | { | ||
2080 | m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (HG visitor)"); | ||
2081 | } | ||
2082 | else if (m_scene.GridUserService.SetHome(userId, land.RegionUUID, position, lookAt)) | ||
2083 | { | ||
2084 | // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. | ||
2085 | m_Dialog.SendAlertToUser(remoteClient, "Home position set."); | ||
2086 | } | ||
2087 | else | ||
2088 | { | ||
2089 | m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed."); | ||
2090 | } | ||
2091 | } | ||
2092 | else | ||
2093 | m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel."); | ||
2094 | } | ||
2095 | |||
2096 | protected void RegisterCommands() | ||
2097 | { | ||
2098 | ICommands commands = MainConsole.Instance.Commands; | ||
2099 | |||
2100 | commands.AddCommand( | ||
2101 | "Land", false, "land clear", | ||
2102 | "land clear", | ||
2103 | "Clear all the parcels from the region.", | ||
2104 | "Command will ask for confirmation before proceeding.", | ||
2105 | HandleClearCommand); | ||
2106 | |||
2107 | commands.AddCommand( | ||
2108 | "Land", false, "land show", | ||
2109 | "land show [<local-land-id>]", | ||
2110 | "Show information about the parcels on the region.", | ||
2111 | "If no local land ID is given, then summary information about all the parcels is shown.\n" | ||
2112 | + "If a local land ID is given then full information about that parcel is shown.", | ||
2113 | HandleShowCommand); | ||
1745 | } | 2114 | } |
1746 | 2115 | ||
1747 | protected void ClearCommand(Object[] args) | 2116 | protected void HandleClearCommand(string module, string[] args) |
1748 | { | 2117 | { |
2118 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) | ||
2119 | return; | ||
2120 | |||
1749 | string response = MainConsole.Instance.CmdPrompt( | 2121 | string response = MainConsole.Instance.CmdPrompt( |
1750 | string.Format( | 2122 | string.Format( |
1751 | "Are you sure that you want to clear all land parcels from {0} (y or n)", | 2123 | "Are you sure that you want to clear all land parcels from {0} (y or n)", m_scene.Name), |
1752 | m_scene.RegionInfo.RegionName), | ||
1753 | "n"); | 2124 | "n"); |
1754 | 2125 | ||
1755 | if (response.ToLower() == "y") | 2126 | if (response.ToLower() == "y") |
1756 | { | 2127 | { |
1757 | Clear(true); | 2128 | Clear(true); |
1758 | MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.RegionInfo.RegionName); | 2129 | MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.Name); |
1759 | } | 2130 | } |
1760 | else | 2131 | else |
1761 | { | 2132 | { |
1762 | MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.RegionInfo.RegionName); | 2133 | MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.Name); |
1763 | } | 2134 | } |
1764 | } | 2135 | } |
1765 | 2136 | ||
1766 | protected void ShowParcelsCommand(Object[] args) | 2137 | protected void HandleShowCommand(string module, string[] args) |
1767 | { | 2138 | { |
1768 | StringBuilder report = new StringBuilder(); | 2139 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) |
1769 | 2140 | return; | |
1770 | report.AppendFormat("Land information for {0}\n", m_scene.RegionInfo.RegionName); | 2141 | |
1771 | report.AppendFormat( | 2142 | StringBuilder report = new StringBuilder(); |
1772 | "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n", | 2143 | |
1773 | "Parcel Name", | 2144 | if (args.Length <= 2) |
1774 | "Local ID", | 2145 | { |
1775 | "Area", | 2146 | AppendParcelsSummaryReport(report); |
1776 | "Starts", | 2147 | } |
1777 | "Ends", | 2148 | else |
1778 | "Owner"); | 2149 | { |
2150 | int landLocalId; | ||
2151 | |||
2152 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[2], out landLocalId)) | ||
2153 | return; | ||
2154 | |||
2155 | ILandObject lo; | ||
2156 | |||
2157 | lock (m_landList) | ||
2158 | { | ||
2159 | if (!m_landList.TryGetValue(landLocalId, out lo)) | ||
2160 | { | ||
2161 | MainConsole.Instance.OutputFormat("No parcel found with local ID {0}", landLocalId); | ||
2162 | return; | ||
2163 | } | ||
2164 | } | ||
2165 | |||
2166 | AppendParcelReport(report, lo); | ||
2167 | } | ||
2168 | |||
2169 | MainConsole.Instance.Output(report.ToString()); | ||
2170 | } | ||
2171 | |||
2172 | private void AppendParcelsSummaryReport(StringBuilder report) | ||
2173 | { | ||
2174 | report.AppendFormat("Land information for {0}\n", m_scene.Name); | ||
2175 | |||
2176 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
2177 | cdt.AddColumn("Parcel Name", ConsoleDisplayUtil.ParcelNameSize); | ||
2178 | cdt.AddColumn("ID", 3); | ||
2179 | cdt.AddColumn("Area", 6); | ||
2180 | cdt.AddColumn("Starts", ConsoleDisplayUtil.VectorSize); | ||
2181 | cdt.AddColumn("Ends", ConsoleDisplayUtil.VectorSize); | ||
2182 | cdt.AddColumn("Owner", ConsoleDisplayUtil.UserNameSize); | ||
1779 | 2183 | ||
1780 | lock (m_landList) | 2184 | lock (m_landList) |
1781 | { | 2185 | { |
1782 | foreach (ILandObject lo in m_landList.Values) | 2186 | foreach (ILandObject lo in m_landList.Values) |
1783 | { | 2187 | { |
1784 | LandData ld = lo.LandData; | 2188 | LandData ld = lo.LandData; |
1785 | 2189 | string ownerName; | |
1786 | report.AppendFormat( | 2190 | if (ld.IsGroupOwned) |
1787 | "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n", | 2191 | { |
1788 | ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, m_userManager.GetUserName(ld.OwnerID)); | 2192 | GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID); |
2193 | ownerName = (rec != null) ? rec.GroupName : "Unknown Group"; | ||
2194 | } | ||
2195 | else | ||
2196 | { | ||
2197 | ownerName = m_userManager.GetUserName(ld.OwnerID); | ||
2198 | } | ||
2199 | cdt.AddRow( | ||
2200 | ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, ownerName); | ||
1789 | } | 2201 | } |
1790 | } | 2202 | } |
1791 | 2203 | ||
1792 | MainConsole.Instance.Output(report.ToString()); | 2204 | report.Append(cdt.ToString()); |
1793 | } | 2205 | } |
2206 | |||
2207 | private void AppendParcelReport(StringBuilder report, ILandObject lo) | ||
2208 | { | ||
2209 | LandData ld = lo.LandData; | ||
2210 | |||
2211 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | ||
2212 | cdl.AddRow("Parcel name", ld.Name); | ||
2213 | cdl.AddRow("Local ID", ld.LocalID); | ||
2214 | cdl.AddRow("Description", ld.Description); | ||
2215 | cdl.AddRow("Snapshot ID", ld.SnapshotID); | ||
2216 | cdl.AddRow("Area", ld.Area); | ||
2217 | cdl.AddRow("Starts", lo.StartPoint); | ||
2218 | cdl.AddRow("Ends", lo.EndPoint); | ||
2219 | cdl.AddRow("AABB Min", ld.AABBMin); | ||
2220 | cdl.AddRow("AABB Max", ld.AABBMax); | ||
2221 | string ownerName; | ||
2222 | if (ld.IsGroupOwned) | ||
2223 | { | ||
2224 | GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID); | ||
2225 | ownerName = (rec != null) ? rec.GroupName : "Unknown Group"; | ||
2226 | } | ||
2227 | else | ||
2228 | { | ||
2229 | ownerName = m_userManager.GetUserName(ld.OwnerID); | ||
2230 | } | ||
2231 | cdl.AddRow("Owner", ownerName); | ||
2232 | cdl.AddRow("Is group owned?", ld.IsGroupOwned); | ||
2233 | cdl.AddRow("GroupID", ld.GroupID); | ||
2234 | |||
2235 | cdl.AddRow("Status", ld.Status); | ||
2236 | cdl.AddRow("Flags", (ParcelFlags)ld.Flags); | ||
2237 | |||
2238 | cdl.AddRow("Landing Type", (LandingType)ld.LandingType); | ||
2239 | cdl.AddRow("User Location", ld.UserLocation); | ||
2240 | cdl.AddRow("User look at", ld.UserLookAt); | ||
2241 | |||
2242 | cdl.AddRow("Other clean time", ld.OtherCleanTime); | ||
2243 | |||
2244 | cdl.AddRow("Max Prims", lo.GetParcelMaxPrimCount()); | ||
2245 | IPrimCounts pc = lo.PrimCounts; | ||
2246 | cdl.AddRow("Owner Prims", pc.Owner); | ||
2247 | cdl.AddRow("Group Prims", pc.Group); | ||
2248 | cdl.AddRow("Other Prims", pc.Others); | ||
2249 | cdl.AddRow("Selected Prims", pc.Selected); | ||
2250 | cdl.AddRow("Total Prims", pc.Total); | ||
2251 | |||
2252 | cdl.AddRow("Music URL", ld.MusicURL); | ||
2253 | cdl.AddRow("Obscure Music", ld.ObscureMusic); | ||
2254 | |||
2255 | cdl.AddRow("Media ID", ld.MediaID); | ||
2256 | cdl.AddRow("Media Autoscale", Convert.ToBoolean(ld.MediaAutoScale)); | ||
2257 | cdl.AddRow("Media URL", ld.MediaURL); | ||
2258 | cdl.AddRow("Media Type", ld.MediaType); | ||
2259 | cdl.AddRow("Media Description", ld.MediaDescription); | ||
2260 | cdl.AddRow("Media Width", ld.MediaWidth); | ||
2261 | cdl.AddRow("Media Height", ld.MediaHeight); | ||
2262 | cdl.AddRow("Media Loop", ld.MediaLoop); | ||
2263 | cdl.AddRow("Obscure Media", ld.ObscureMedia); | ||
2264 | |||
2265 | cdl.AddRow("Parcel Category", ld.Category); | ||
2266 | |||
2267 | cdl.AddRow("Claim Date", ld.ClaimDate); | ||
2268 | cdl.AddRow("Claim Price", ld.ClaimPrice); | ||
2269 | cdl.AddRow("Pass Hours", ld.PassHours); | ||
2270 | cdl.AddRow("Pass Price", ld.PassPrice); | ||
2271 | |||
2272 | cdl.AddRow("Auction ID", ld.AuctionID); | ||
2273 | cdl.AddRow("Authorized Buyer ID", ld.AuthBuyerID); | ||
2274 | cdl.AddRow("Sale Price", ld.SalePrice); | ||
2275 | |||
2276 | cdl.AddToStringBuilder(report); | ||
2277 | } | ||
1794 | } | 2278 | } |
1795 | } | 2279 | } |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 5969d45..a0c1b9d 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs | |||
@@ -45,14 +45,12 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
45 | #region Member Variables | 45 | #region Member Variables |
46 | 46 | ||
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | #pragma warning disable 0429 | 48 | private static readonly string LogHeader = "[LAND OBJECT]"; |
49 | private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64; | ||
50 | #pragma warning restore 0429 | ||
51 | private bool[,] m_landBitmap = new bool[landArrayMax,landArrayMax]; | ||
52 | 49 | ||
53 | private int m_lastSeqId = 0; | 50 | private readonly int landUnit = 4; |
54 | 51 | ||
55 | protected LandData m_landData = new LandData(); | 52 | private int m_lastSeqId = 0; |
53 | |||
56 | protected Scene m_scene; | 54 | protected Scene m_scene; |
57 | protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); | 55 | protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); |
58 | protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>(); | 56 | protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>(); |
@@ -60,76 +58,83 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
60 | protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>(); | 58 | protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>(); |
61 | protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds | 59 | protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds |
62 | 60 | ||
63 | public bool[,] LandBitmap | 61 | public bool[,] LandBitmap { get; set; } |
64 | { | ||
65 | get { return m_landBitmap; } | ||
66 | set { m_landBitmap = value; } | ||
67 | } | ||
68 | 62 | ||
69 | #endregion | 63 | #endregion |
70 | 64 | ||
71 | public int GetPrimsFree() | 65 | public int GetPrimsFree() |
72 | { | 66 | { |
73 | m_scene.EventManager.TriggerParcelPrimCountUpdate(); | 67 | m_scene.EventManager.TriggerParcelPrimCountUpdate(); |
74 | int free = GetSimulatorMaxPrimCount() - m_landData.SimwidePrims; | 68 | int free = GetSimulatorMaxPrimCount() - LandData.SimwidePrims; |
75 | return free; | 69 | return free; |
76 | } | 70 | } |
77 | 71 | ||
78 | public LandData LandData | 72 | public LandData LandData { get; set; } |
79 | { | ||
80 | get { return m_landData; } | ||
81 | 73 | ||
82 | set { m_landData = value; } | ||
83 | } | ||
84 | |||
85 | public IPrimCounts PrimCounts { get; set; } | 74 | public IPrimCounts PrimCounts { get; set; } |
86 | 75 | ||
87 | public UUID RegionUUID | 76 | public UUID RegionUUID |
88 | { | 77 | { |
89 | get { return m_scene.RegionInfo.RegionID; } | 78 | get { return m_scene.RegionInfo.RegionID; } |
90 | } | 79 | } |
91 | 80 | ||
92 | public Vector3 StartPoint | 81 | public Vector3 StartPoint |
93 | { | 82 | { |
94 | get | 83 | get |
95 | { | 84 | { |
96 | for (int y = 0; y < landArrayMax; y++) | 85 | for (int y = 0; y < LandBitmap.GetLength(1); y++) |
97 | { | 86 | { |
98 | for (int x = 0; x < landArrayMax; x++) | 87 | for (int x = 0; x < LandBitmap.GetLength(0); x++) |
99 | { | 88 | { |
100 | if (LandBitmap[x, y]) | 89 | if (LandBitmap[x, y]) |
101 | return new Vector3(x * 4, y * 4, 0); | 90 | return new Vector3(x * landUnit, y * landUnit, 0); |
102 | } | 91 | } |
103 | } | 92 | } |
104 | 93 | ||
94 | m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>", | ||
95 | LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | ||
105 | return new Vector3(-1, -1, -1); | 96 | return new Vector3(-1, -1, -1); |
106 | } | 97 | } |
107 | } | 98 | } |
108 | 99 | ||
109 | public Vector3 EndPoint | 100 | public Vector3 EndPoint |
110 | { | 101 | { |
111 | get | 102 | get |
112 | { | 103 | { |
113 | for (int y = landArrayMax - 1; y >= 0; y--) | 104 | for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--) |
114 | { | 105 | { |
115 | for (int x = landArrayMax - 1; x >= 0; x--) | 106 | for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--) |
116 | { | 107 | { |
117 | if (LandBitmap[x, y]) | 108 | if (LandBitmap[x, y]) |
118 | { | 109 | { |
119 | return new Vector3(x * 4, y * 4, 0); | 110 | return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0); |
120 | } | 111 | } |
121 | } | 112 | } |
122 | } | 113 | } |
123 | 114 | ||
115 | m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>", | ||
116 | LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | ||
124 | return new Vector3(-1, -1, -1); | 117 | return new Vector3(-1, -1, -1); |
125 | } | 118 | } |
126 | } | 119 | } |
127 | 120 | ||
128 | #region Constructors | 121 | #region Constructors |
129 | 122 | ||
123 | public LandObject(LandData landData, Scene scene) | ||
124 | { | ||
125 | LandData = landData.Copy(); | ||
126 | m_scene = scene; | ||
127 | } | ||
128 | |||
130 | public LandObject(UUID owner_id, bool is_group_owned, Scene scene) | 129 | public LandObject(UUID owner_id, bool is_group_owned, Scene scene) |
131 | { | 130 | { |
132 | m_scene = scene; | 131 | m_scene = scene; |
132 | if (m_scene == null) | ||
133 | LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit]; | ||
134 | else | ||
135 | LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | ||
136 | |||
137 | LandData = new LandData(); | ||
133 | LandData.OwnerID = owner_id; | 138 | LandData.OwnerID = owner_id; |
134 | if (is_group_owned) | 139 | if (is_group_owned) |
135 | LandData.GroupID = owner_id; | 140 | LandData.GroupID = owner_id; |
@@ -152,9 +157,9 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
152 | /// <returns>Returns true if the piece of land contains the specified point</returns> | 157 | /// <returns>Returns true if the piece of land contains the specified point</returns> |
153 | public bool ContainsPoint(int x, int y) | 158 | public bool ContainsPoint(int x, int y) |
154 | { | 159 | { |
155 | if (x >= 0 && y >= 0 && x < Constants.RegionSize && y < Constants.RegionSize) | 160 | if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY) |
156 | { | 161 | { |
157 | return (LandBitmap[x / 4, y / 4] == true); | 162 | return LandBitmap[x / landUnit, y / landUnit]; |
158 | } | 163 | } |
159 | else | 164 | else |
160 | { | 165 | { |
@@ -164,12 +169,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
164 | 169 | ||
165 | public ILandObject Copy() | 170 | public ILandObject Copy() |
166 | { | 171 | { |
167 | ILandObject newLand = new LandObject(LandData.OwnerID, LandData.IsGroupOwned, m_scene); | 172 | ILandObject newLand = new LandObject(LandData, m_scene); |
168 | |||
169 | //Place all new variables here! | ||
170 | newLand.LandBitmap = (bool[,]) (LandBitmap.Clone()); | 173 | newLand.LandBitmap = (bool[,]) (LandBitmap.Clone()); |
171 | newLand.LandData = LandData.Copy(); | ||
172 | |||
173 | return newLand; | 174 | return newLand; |
174 | } | 175 | } |
175 | 176 | ||
@@ -194,7 +195,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
194 | else | 195 | else |
195 | { | 196 | { |
196 | // Normal Calculations | 197 | // Normal Calculations |
197 | int parcelMax = (int)(((float)LandData.Area / 65536.0f) | 198 | int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY)) |
198 | * (float)m_scene.RegionInfo.ObjectCapacity | 199 | * (float)m_scene.RegionInfo.ObjectCapacity |
199 | * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); | 200 | * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); |
200 | // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! | 201 | // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! |
@@ -211,7 +212,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
211 | else | 212 | else |
212 | { | 213 | { |
213 | //Normal Calculations | 214 | //Normal Calculations |
214 | int simMax = (int)(((float)LandData.SimwideArea / 65536.0f) | 215 | int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY)) |
215 | * (float)m_scene.RegionInfo.ObjectCapacity); | 216 | * (float)m_scene.RegionInfo.ObjectCapacity); |
216 | return simMax; | 217 | return simMax; |
217 | } | 218 | } |
@@ -224,17 +225,15 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
224 | public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) | 225 | public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) |
225 | { | 226 | { |
226 | IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); | 227 | IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); |
227 | uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); | 228 | // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); |
229 | uint regionFlags = (uint)(RegionFlags.PublicAllowed | ||
230 | | RegionFlags.AllowDirectTeleport | ||
231 | | RegionFlags.AllowParcelChanges | ||
232 | | RegionFlags.AllowVoice ); | ||
233 | |||
228 | if (estateModule != null) | 234 | if (estateModule != null) |
229 | regionFlags = estateModule.GetRegionFlags(); | 235 | regionFlags = estateModule.GetRegionFlags(); |
230 | 236 | ||
231 | // In a perfect world, this would have worked. | ||
232 | // | ||
233 | // if ((landData.Flags & (uint)ParcelFlags.AllowLandmark) != 0) | ||
234 | // regionFlags |= (uint)RegionFlags.AllowLandmark; | ||
235 | // if (landData.OwnerID == remote_client.AgentId) | ||
236 | // regionFlags |= (uint)RegionFlags.AllowSetHome; | ||
237 | |||
238 | int seq_id; | 237 | int seq_id; |
239 | if (snap_selection && (sequence_id == 0)) | 238 | if (snap_selection && (sequence_id == 0)) |
240 | { | 239 | { |
@@ -368,12 +367,14 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
368 | ParcelFlags.DenyAgeUnverified); | 367 | ParcelFlags.DenyAgeUnverified); |
369 | } | 368 | } |
370 | 369 | ||
371 | uint preserve = LandData.Flags & ~allowedDelta; | 370 | if (allowedDelta != (uint)ParcelFlags.None) |
372 | newData.Flags = preserve | (args.ParcelFlags & allowedDelta); | 371 | { |
373 | 372 | uint preserve = LandData.Flags & ~allowedDelta; | |
374 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); | 373 | newData.Flags = preserve | (args.ParcelFlags & allowedDelta); |
375 | 374 | ||
376 | SendLandUpdateToAvatarsOverMe(snap_selection); | 375 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); |
376 | SendLandUpdateToAvatarsOverMe(snap_selection); | ||
377 | } | ||
377 | } | 378 | } |
378 | 379 | ||
379 | public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area) | 380 | public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area) |
@@ -388,9 +389,16 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
388 | newData.SalePrice = 0; | 389 | newData.SalePrice = 0; |
389 | newData.AuthBuyerID = UUID.Zero; | 390 | newData.AuthBuyerID = UUID.Zero; |
390 | newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); | 391 | newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); |
392 | |||
393 | bool sellObjects = (LandData.Flags & (uint)(ParcelFlags.SellParcelObjects)) != 0 | ||
394 | && !LandData.IsGroupOwned && !groupOwned; | ||
395 | UUID previousOwner = LandData.OwnerID; | ||
396 | |||
391 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); | 397 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); |
392 | m_scene.EventManager.TriggerParcelPrimCountUpdate(); | 398 | m_scene.EventManager.TriggerParcelPrimCountUpdate(); |
393 | SendLandUpdateToAvatarsOverMe(true); | 399 | SendLandUpdateToAvatarsOverMe(true); |
400 | |||
401 | if (sellObjects) SellLandObjects(previousOwner); | ||
394 | } | 402 | } |
395 | 403 | ||
396 | public void DeedToGroup(UUID groupID) | 404 | public void DeedToGroup(UUID groupID) |
@@ -421,6 +429,19 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
421 | return false; | 429 | return false; |
422 | } | 430 | } |
423 | 431 | ||
432 | public bool CanBeOnThisLand(UUID avatar, float posHeight) | ||
433 | { | ||
434 | if (posHeight < LandChannel.BAN_LINE_SAFETY_HIEGHT && IsBannedFromLand(avatar)) | ||
435 | { | ||
436 | return false; | ||
437 | } | ||
438 | else if (IsRestrictedFromLand(avatar)) | ||
439 | { | ||
440 | return false; | ||
441 | } | ||
442 | return true; | ||
443 | } | ||
444 | |||
424 | public bool HasGroupAccess(UUID avatar) | 445 | public bool HasGroupAccess(UUID avatar) |
425 | { | 446 | { |
426 | if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup) | 447 | if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup) |
@@ -553,8 +574,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
553 | try | 574 | try |
554 | { | 575 | { |
555 | over = | 576 | over = |
556 | m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)), | 577 | m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)), |
557 | Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)Constants.RegionSize - 1))); | 578 | Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1))); |
558 | } | 579 | } |
559 | catch (Exception) | 580 | catch (Exception) |
560 | { | 581 | { |
@@ -701,15 +722,15 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
701 | /// </summary> | 722 | /// </summary> |
702 | private void UpdateAABBAndAreaValues() | 723 | private void UpdateAABBAndAreaValues() |
703 | { | 724 | { |
704 | int min_x = 64; | 725 | int min_x = 10000; |
705 | int min_y = 64; | 726 | int min_y = 10000; |
706 | int max_x = 0; | 727 | int max_x = 0; |
707 | int max_y = 0; | 728 | int max_y = 0; |
708 | int tempArea = 0; | 729 | int tempArea = 0; |
709 | int x, y; | 730 | int x, y; |
710 | for (x = 0; x < 64; x++) | 731 | for (x = 0; x < LandBitmap.GetLength(0); x++) |
711 | { | 732 | { |
712 | for (y = 0; y < 64; y++) | 733 | for (y = 0; y < LandBitmap.GetLength(1); y++) |
713 | { | 734 | { |
714 | if (LandBitmap[x, y] == true) | 735 | if (LandBitmap[x, y] == true) |
715 | { | 736 | { |
@@ -717,31 +738,31 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
717 | if (min_y > y) min_y = y; | 738 | if (min_y > y) min_y = y; |
718 | if (max_x < x) max_x = x; | 739 | if (max_x < x) max_x = x; |
719 | if (max_y < y) max_y = y; | 740 | if (max_y < y) max_y = y; |
720 | tempArea += 16; //16sqm peice of land | 741 | tempArea += landUnit * landUnit; //16sqm peice of land |
721 | } | 742 | } |
722 | } | 743 | } |
723 | } | 744 | } |
724 | int tx = min_x * 4; | 745 | int tx = min_x * landUnit; |
725 | if (tx > ((int)Constants.RegionSize - 1)) | 746 | if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1)) |
726 | tx = ((int)Constants.RegionSize - 1); | 747 | tx = ((int)m_scene.RegionInfo.RegionSizeX - 1); |
727 | int ty = min_y * 4; | 748 | int ty = min_y * landUnit; |
728 | if (ty > ((int)Constants.RegionSize - 1)) | 749 | if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1)) |
729 | ty = ((int)Constants.RegionSize - 1); | 750 | ty = ((int)m_scene.RegionInfo.RegionSizeY - 1); |
730 | 751 | ||
731 | LandData.AABBMin = | 752 | LandData.AABBMin = |
732 | new Vector3( | 753 | new Vector3( |
733 | (float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); | 754 | (float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); |
734 | 755 | ||
735 | tx = max_x * 4; | 756 | tx = max_x * landUnit; |
736 | if (tx > ((int)Constants.RegionSize - 1)) | 757 | if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1)) |
737 | tx = ((int)Constants.RegionSize - 1); | 758 | tx = ((int)m_scene.RegionInfo.RegionSizeX - 1); |
738 | ty = max_y * 4; | 759 | ty = max_y * landUnit; |
739 | if (ty > ((int)Constants.RegionSize - 1)) | 760 | if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1)) |
740 | ty = ((int)Constants.RegionSize - 1); | 761 | ty = ((int)m_scene.RegionInfo.RegionSizeY - 1); |
741 | 762 | ||
742 | LandData.AABBMax | 763 | LandData.AABBMax |
743 | = new Vector3( | 764 | = new Vector3( |
744 | (float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); | 765 | (float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); |
745 | 766 | ||
746 | LandData.Area = tempArea; | 767 | LandData.Area = tempArea; |
747 | } | 768 | } |
@@ -753,20 +774,12 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
753 | /// <summary> | 774 | /// <summary> |
754 | /// Sets the land's bitmap manually | 775 | /// Sets the land's bitmap manually |
755 | /// </summary> | 776 | /// </summary> |
756 | /// <param name="bitmap">64x64 block representing where this land is on a map</param> | 777 | /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param> |
757 | public void SetLandBitmap(bool[,] bitmap) | 778 | public void SetLandBitmap(bool[,] bitmap) |
758 | { | 779 | { |
759 | if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2) | 780 | LandBitmap = bitmap; |
760 | { | 781 | // m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); |
761 | //Throw an exception - The bitmap is not 64x64 | 782 | ForceUpdateLandInfo(); |
762 | //throw new Exception("Error: Invalid Parcel Bitmap"); | ||
763 | } | ||
764 | else | ||
765 | { | ||
766 | //Valid: Lets set it | ||
767 | LandBitmap = bitmap; | ||
768 | ForceUpdateLandInfo(); | ||
769 | } | ||
770 | } | 783 | } |
771 | 784 | ||
772 | /// <summary> | 785 | /// <summary> |
@@ -780,15 +793,19 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
780 | 793 | ||
781 | public bool[,] BasicFullRegionLandBitmap() | 794 | public bool[,] BasicFullRegionLandBitmap() |
782 | { | 795 | { |
783 | return GetSquareLandBitmap(0, 0, (int) Constants.RegionSize, (int) Constants.RegionSize); | 796 | return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY); |
784 | } | 797 | } |
785 | 798 | ||
786 | public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) | 799 | public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) |
787 | { | 800 | { |
788 | bool[,] tempBitmap = new bool[64,64]; | 801 | // Empty bitmap for the whole region |
802 | bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | ||
789 | tempBitmap.Initialize(); | 803 | tempBitmap.Initialize(); |
790 | 804 | ||
805 | // Fill the bitmap square area specified by state and end | ||
791 | tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); | 806 | tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); |
807 | // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>", | ||
808 | // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1)); | ||
792 | return tempBitmap; | 809 | return tempBitmap; |
793 | } | 810 | } |
794 | 811 | ||
@@ -805,24 +822,20 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
805 | public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, | 822 | public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, |
806 | bool set_value) | 823 | bool set_value) |
807 | { | 824 | { |
808 | if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2) | ||
809 | { | ||
810 | //Throw an exception - The bitmap is not 64x64 | ||
811 | //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()"); | ||
812 | } | ||
813 | |||
814 | int x, y; | 825 | int x, y; |
815 | for (y = 0; y < 64; y++) | 826 | for (y = 0; y < land_bitmap.GetLength(1); y++) |
816 | { | 827 | { |
817 | for (x = 0; x < 64; x++) | 828 | for (x = 0; x < land_bitmap.GetLength(0); x++) |
818 | { | 829 | { |
819 | if (x >= start_x / 4 && x < end_x / 4 | 830 | if (x >= start_x / landUnit && x < end_x / landUnit |
820 | && y >= start_y / 4 && y < end_y / 4) | 831 | && y >= start_y / landUnit && y < end_y / landUnit) |
821 | { | 832 | { |
822 | land_bitmap[x, y] = set_value; | 833 | land_bitmap[x, y] = set_value; |
823 | } | 834 | } |
824 | } | 835 | } |
825 | } | 836 | } |
837 | // m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>", | ||
838 | // LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1)); | ||
826 | return land_bitmap; | 839 | return land_bitmap; |
827 | } | 840 | } |
828 | 841 | ||
@@ -834,21 +847,21 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
834 | /// <returns></returns> | 847 | /// <returns></returns> |
835 | public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) | 848 | public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) |
836 | { | 849 | { |
837 | if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2) | 850 | if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0) |
851 | || bitmap_base.GetLength(1) != bitmap_add.GetLength(1) | ||
852 | || bitmap_add.Rank != 2 | ||
853 | || bitmap_base.Rank != 2) | ||
838 | { | 854 | { |
839 | //Throw an exception - The bitmap is not 64x64 | 855 | throw new Exception( |
840 | throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps"); | 856 | String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>", |
841 | } | 857 | LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1)) |
842 | if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2) | 858 | ); |
843 | { | ||
844 | //Throw an exception - The bitmap is not 64x64 | ||
845 | throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps"); | ||
846 | } | 859 | } |
847 | 860 | ||
848 | int x, y; | 861 | int x, y; |
849 | for (y = 0; y < 64; y++) | 862 | for (y = 0; y < bitmap_base.GetLength(1); y++) |
850 | { | 863 | { |
851 | for (x = 0; x < 64; x++) | 864 | for (x = 0; x < bitmap_add.GetLength(0); x++) |
852 | { | 865 | { |
853 | if (bitmap_add[x, y]) | 866 | if (bitmap_add[x, y]) |
854 | { | 867 | { |
@@ -865,13 +878,13 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
865 | /// <returns></returns> | 878 | /// <returns></returns> |
866 | private byte[] ConvertLandBitmapToBytes() | 879 | private byte[] ConvertLandBitmapToBytes() |
867 | { | 880 | { |
868 | byte[] tempConvertArr = new byte[512]; | 881 | byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8]; |
869 | byte tempByte = 0; | 882 | byte tempByte = 0; |
870 | int x, y, i, byteNum = 0; | 883 | int byteNum = 0; |
871 | i = 0; | 884 | int i = 0; |
872 | for (y = 0; y < 64; y++) | 885 | for (int y = 0; y < LandBitmap.GetLength(1); y++) |
873 | { | 886 | { |
874 | for (x = 0; x < 64; x++) | 887 | for (int x = 0; x < LandBitmap.GetLength(0); x++) |
875 | { | 888 | { |
876 | tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); | 889 | tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); |
877 | if (i % 8 == 0) | 890 | if (i % 8 == 0) |
@@ -883,30 +896,52 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
883 | } | 896 | } |
884 | } | 897 | } |
885 | } | 898 | } |
899 | // m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>", | ||
900 | // LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | ||
886 | return tempConvertArr; | 901 | return tempConvertArr; |
887 | } | 902 | } |
888 | 903 | ||
889 | private bool[,] ConvertBytesToLandBitmap() | 904 | private bool[,] ConvertBytesToLandBitmap() |
890 | { | 905 | { |
891 | bool[,] tempConvertMap = new bool[landArrayMax, landArrayMax]; | 906 | bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; |
892 | tempConvertMap.Initialize(); | 907 | tempConvertMap.Initialize(); |
893 | byte tempByte = 0; | 908 | byte tempByte = 0; |
894 | int x = 0, y = 0, i = 0, bitNum = 0; | 909 | // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap. |
895 | for (i = 0; i < 512; i++) | 910 | int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8); |
911 | int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit); | ||
912 | |||
913 | if (bitmapLen == 512) | ||
914 | { | ||
915 | // Legacy bitmap being passed in. Use the legacy region size | ||
916 | // and only set the lower area of the larger region. | ||
917 | xLen = (int)(Constants.RegionSize / landUnit); | ||
918 | } | ||
919 | // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen); | ||
920 | |||
921 | int x = 0, y = 0; | ||
922 | for (int i = 0; i < bitmapLen; i++) | ||
896 | { | 923 | { |
897 | tempByte = LandData.Bitmap[i]; | 924 | tempByte = LandData.Bitmap[i]; |
898 | for (bitNum = 0; bitNum < 8; bitNum++) | 925 | for (int bitNum = 0; bitNum < 8; bitNum++) |
899 | { | 926 | { |
900 | bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); | 927 | bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); |
901 | tempConvertMap[x, y] = bit; | 928 | try |
929 | { | ||
930 | tempConvertMap[x, y] = bit; | ||
931 | } | ||
932 | catch (Exception) | ||
933 | { | ||
934 | m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y); | ||
935 | } | ||
902 | x++; | 936 | x++; |
903 | if (x > 63) | 937 | if (x >= xLen) |
904 | { | 938 | { |
905 | x = 0; | 939 | x = 0; |
906 | y++; | 940 | y++; |
907 | } | 941 | } |
908 | } | 942 | } |
909 | } | 943 | } |
944 | |||
910 | return tempConvertMap; | 945 | return tempConvertMap; |
911 | } | 946 | } |
912 | 947 | ||
@@ -1043,6 +1078,43 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1043 | 1078 | ||
1044 | #endregion | 1079 | #endregion |
1045 | 1080 | ||
1081 | #region Object Sales | ||
1082 | |||
1083 | public void SellLandObjects(UUID previousOwner) | ||
1084 | { | ||
1085 | // m_log.DebugFormat( | ||
1086 | // "[LAND OBJECT]: Request to sell objects in {0} from {1}", LandData.Name, previousOwner); | ||
1087 | |||
1088 | if (LandData.IsGroupOwned) | ||
1089 | return; | ||
1090 | |||
1091 | IBuySellModule m_BuySellModule = m_scene.RequestModuleInterface<IBuySellModule>(); | ||
1092 | if (m_BuySellModule == null) | ||
1093 | { | ||
1094 | m_log.Error("[LAND OBJECT]: BuySellModule not found"); | ||
1095 | return; | ||
1096 | } | ||
1097 | |||
1098 | ScenePresence sp; | ||
1099 | if (!m_scene.TryGetScenePresence(LandData.OwnerID, out sp)) | ||
1100 | { | ||
1101 | m_log.Error("[LAND OBJECT]: New owner is not present in scene"); | ||
1102 | return; | ||
1103 | } | ||
1104 | |||
1105 | lock (primsOverMe) | ||
1106 | { | ||
1107 | foreach (SceneObjectGroup obj in primsOverMe) | ||
1108 | { | ||
1109 | if (obj.OwnerID == previousOwner && obj.GroupID == UUID.Zero && | ||
1110 | (obj.GetEffectivePermissions() & (uint)(OpenSim.Framework.PermissionMask.Transfer)) != 0) | ||
1111 | m_BuySellModule.BuyObject(sp.ControllingClient, UUID.Zero, obj.LocalId, 1, 0); | ||
1112 | } | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1116 | #endregion | ||
1117 | |||
1046 | #region Object Returning | 1118 | #region Object Returning |
1047 | 1119 | ||
1048 | public void ReturnObject(SceneObjectGroup obj) | 1120 | public void ReturnObject(SceneObjectGroup obj) |
@@ -1065,7 +1137,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1065 | { | 1137 | { |
1066 | foreach (SceneObjectGroup obj in primsOverMe) | 1138 | foreach (SceneObjectGroup obj in primsOverMe) |
1067 | { | 1139 | { |
1068 | if (obj.OwnerID == m_landData.OwnerID) | 1140 | if (obj.OwnerID == LandData.OwnerID) |
1069 | { | 1141 | { |
1070 | if (!returns.ContainsKey(obj.OwnerID)) | 1142 | if (!returns.ContainsKey(obj.OwnerID)) |
1071 | returns[obj.OwnerID] = | 1143 | returns[obj.OwnerID] = |
@@ -1074,11 +1146,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1074 | } | 1146 | } |
1075 | } | 1147 | } |
1076 | } | 1148 | } |
1077 | else if (type == (uint)ObjectReturnType.Group && m_landData.GroupID != UUID.Zero) | 1149 | else if (type == (uint)ObjectReturnType.Group && LandData.GroupID != UUID.Zero) |
1078 | { | 1150 | { |
1079 | foreach (SceneObjectGroup obj in primsOverMe) | 1151 | foreach (SceneObjectGroup obj in primsOverMe) |
1080 | { | 1152 | { |
1081 | if (obj.GroupID == m_landData.GroupID) | 1153 | if (obj.GroupID == LandData.GroupID) |
1082 | { | 1154 | { |
1083 | if (!returns.ContainsKey(obj.OwnerID)) | 1155 | if (!returns.ContainsKey(obj.OwnerID)) |
1084 | returns[obj.OwnerID] = | 1156 | returns[obj.OwnerID] = |
@@ -1091,9 +1163,9 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1091 | { | 1163 | { |
1092 | foreach (SceneObjectGroup obj in primsOverMe) | 1164 | foreach (SceneObjectGroup obj in primsOverMe) |
1093 | { | 1165 | { |
1094 | if (obj.OwnerID != m_landData.OwnerID && | 1166 | if (obj.OwnerID != LandData.OwnerID && |
1095 | (obj.GroupID != m_landData.GroupID || | 1167 | (obj.GroupID != LandData.GroupID || |
1096 | m_landData.GroupID == UUID.Zero)) | 1168 | LandData.GroupID == UUID.Zero)) |
1097 | { | 1169 | { |
1098 | if (!returns.ContainsKey(obj.OwnerID)) | 1170 | if (!returns.ContainsKey(obj.OwnerID)) |
1099 | returns[obj.OwnerID] = | 1171 | returns[obj.OwnerID] = |
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs index f9cc0cf..9b51cc8 100644 --- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs | |||
@@ -490,11 +490,14 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
490 | 490 | ||
491 | m_Scene.ForEachSOG(AddObject); | 491 | m_Scene.ForEachSOG(AddObject); |
492 | 492 | ||
493 | List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys); | 493 | lock (m_PrimCounts) |
494 | foreach (UUID k in primcountKeys) | ||
495 | { | 494 | { |
496 | if (!m_OwnerMap.ContainsKey(k)) | 495 | List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys); |
497 | m_PrimCounts.Remove(k); | 496 | foreach (UUID k in primcountKeys) |
497 | { | ||
498 | if (!m_OwnerMap.ContainsKey(k)) | ||
499 | m_PrimCounts.Remove(k); | ||
500 | } | ||
498 | } | 501 | } |
499 | 502 | ||
500 | m_Tainted = false; | 503 | m_Tainted = false; |
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs new file mode 100644 index 0000000..4ed67f3 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs | |||
@@ -0,0 +1,266 @@ | |||
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 NUnit.Framework; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework.Scenes; | ||
33 | using OpenSim.Tests.Common; | ||
34 | |||
35 | namespace OpenSim.Region.CoreModules.World.Land.Tests | ||
36 | { | ||
37 | public class LandManagementModuleTests : OpenSimTestCase | ||
38 | { | ||
39 | [Test] | ||
40 | public void TestAddLandObject() | ||
41 | { | ||
42 | TestHelpers.InMethod(); | ||
43 | // TestHelpers.EnableLogging(); | ||
44 | |||
45 | UUID userId = TestHelpers.ParseTail(0x1); | ||
46 | |||
47 | LandManagementModule lmm = new LandManagementModule(); | ||
48 | Scene scene = new SceneHelpers().SetupScene(); | ||
49 | SceneHelpers.SetupSceneModules(scene, lmm); | ||
50 | |||
51 | ILandObject lo = new LandObject(userId, false, scene); | ||
52 | lo.LandData.Name = "lo1"; | ||
53 | lo.SetLandBitmap( | ||
54 | lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); | ||
55 | lo = lmm.AddLandObject(lo); | ||
56 | |||
57 | // TODO: Should add asserts to check that land object was added properly. | ||
58 | |||
59 | // At the moment, this test just makes sure that we can't add a land object that overlaps the areas that | ||
60 | // the first still holds. | ||
61 | ILandObject lo2 = new LandObject(userId, false, scene); | ||
62 | lo2.SetLandBitmap( | ||
63 | lo2.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); | ||
64 | lo2.LandData.Name = "lo2"; | ||
65 | lo2 = lmm.AddLandObject(lo2); | ||
66 | |||
67 | { | ||
68 | ILandObject loAtCoord = lmm.GetLandObject(0, 0); | ||
69 | Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID)); | ||
70 | Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID)); | ||
71 | } | ||
72 | |||
73 | { | ||
74 | ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); | ||
75 | Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID)); | ||
76 | Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID)); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /// <summary> | ||
81 | /// Test parcels on region when no land data exists to be loaded. | ||
82 | /// </summary> | ||
83 | [Test] | ||
84 | public void TestLoadWithNoParcels() | ||
85 | { | ||
86 | TestHelpers.InMethod(); | ||
87 | // TestHelpers.EnableLogging(); | ||
88 | |||
89 | SceneHelpers sh = new SceneHelpers(); | ||
90 | LandManagementModule lmm = new LandManagementModule(); | ||
91 | Scene scene = sh.SetupScene(); | ||
92 | SceneHelpers.SetupSceneModules(scene, lmm); | ||
93 | |||
94 | scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); | ||
95 | |||
96 | ILandObject loAtCoord1 = lmm.GetLandObject(0, 0); | ||
97 | Assert.That(loAtCoord1.LandData.LocalID, Is.Not.EqualTo(0)); | ||
98 | Assert.That(loAtCoord1.LandData.GlobalID, Is.Not.EqualTo(UUID.Zero)); | ||
99 | |||
100 | ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); | ||
101 | Assert.That(loAtCoord2.LandData.LocalID, Is.EqualTo(loAtCoord1.LandData.LocalID)); | ||
102 | Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(loAtCoord1.LandData.GlobalID)); | ||
103 | } | ||
104 | |||
105 | /// <summary> | ||
106 | /// Test parcels on region when a single parcel already exists but it does not cover the whole region. | ||
107 | /// </summary> | ||
108 | [Test] | ||
109 | public void TestLoadWithSinglePartialCoveringParcel() | ||
110 | { | ||
111 | TestHelpers.InMethod(); | ||
112 | // TestHelpers.EnableLogging(); | ||
113 | |||
114 | UUID userId = TestHelpers.ParseTail(0x1); | ||
115 | |||
116 | SceneHelpers sh = new SceneHelpers(); | ||
117 | LandManagementModule lmm = new LandManagementModule(); | ||
118 | Scene scene = sh.SetupScene(); | ||
119 | SceneHelpers.SetupSceneModules(scene, lmm); | ||
120 | |||
121 | ILandObject originalLo1 = new LandObject(userId, false, scene); | ||
122 | originalLo1.LandData.Name = "lo1"; | ||
123 | originalLo1.SetLandBitmap( | ||
124 | originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2)); | ||
125 | |||
126 | sh.SimDataService.StoreLandObject(originalLo1); | ||
127 | |||
128 | scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); | ||
129 | |||
130 | ILandObject loAtCoord1 = lmm.GetLandObject(0, 0); | ||
131 | Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name)); | ||
132 | Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); | ||
133 | |||
134 | ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); | ||
135 | Assert.That(loAtCoord2.LandData.LocalID, Is.EqualTo(loAtCoord1.LandData.LocalID)); | ||
136 | Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(loAtCoord1.LandData.GlobalID)); | ||
137 | } | ||
138 | |||
139 | /// <summary> | ||
140 | /// Test parcels on region when a single parcel already exists but it does not cover the whole region. | ||
141 | /// </summary> | ||
142 | [Test] | ||
143 | public void TestLoadWithMultiplePartialCoveringParcels() | ||
144 | { | ||
145 | TestHelpers.InMethod(); | ||
146 | // TestHelpers.EnableLogging(); | ||
147 | |||
148 | UUID userId = TestHelpers.ParseTail(0x1); | ||
149 | |||
150 | SceneHelpers sh = new SceneHelpers(); | ||
151 | LandManagementModule lmm = new LandManagementModule(); | ||
152 | Scene scene = sh.SetupScene(); | ||
153 | SceneHelpers.SetupSceneModules(scene, lmm); | ||
154 | |||
155 | ILandObject originalLo1 = new LandObject(userId, false, scene); | ||
156 | originalLo1.LandData.Name = "lo1"; | ||
157 | originalLo1.SetLandBitmap( | ||
158 | originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2)); | ||
159 | |||
160 | sh.SimDataService.StoreLandObject(originalLo1); | ||
161 | |||
162 | ILandObject originalLo2 = new LandObject(userId, false, scene); | ||
163 | originalLo2.LandData.Name = "lo2"; | ||
164 | originalLo2.SetLandBitmap( | ||
165 | originalLo2.GetSquareLandBitmap( | ||
166 | 0, (int)Constants.RegionSize / 2, (int)Constants.RegionSize, ((int)Constants.RegionSize / 4) * 3)); | ||
167 | |||
168 | sh.SimDataService.StoreLandObject(originalLo2); | ||
169 | |||
170 | scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); | ||
171 | |||
172 | ILandObject loAtCoord1 = lmm.GetLandObject(0, 0); | ||
173 | Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name)); | ||
174 | Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); | ||
175 | |||
176 | ILandObject loAtCoord2 | ||
177 | = lmm.GetLandObject((int)Constants.RegionSize - 1, (((int)Constants.RegionSize / 4) * 3) - 1); | ||
178 | Assert.That(loAtCoord2.LandData.Name, Is.EqualTo(originalLo2.LandData.Name)); | ||
179 | Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID)); | ||
180 | |||
181 | ILandObject loAtCoord3 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); | ||
182 | Assert.That(loAtCoord3.LandData.LocalID, Is.Not.EqualTo(loAtCoord1.LandData.LocalID)); | ||
183 | Assert.That(loAtCoord3.LandData.LocalID, Is.Not.EqualTo(loAtCoord2.LandData.LocalID)); | ||
184 | Assert.That(loAtCoord3.LandData.GlobalID, Is.Not.EqualTo(loAtCoord1.LandData.GlobalID)); | ||
185 | Assert.That(loAtCoord3.LandData.GlobalID, Is.Not.EqualTo(loAtCoord2.LandData.GlobalID)); | ||
186 | } | ||
187 | |||
188 | /// <summary> | ||
189 | /// Test parcels on region when whole region is parcelled (which should normally always be the case). | ||
190 | /// </summary> | ||
191 | [Test] | ||
192 | public void TestLoad() | ||
193 | { | ||
194 | TestHelpers.InMethod(); | ||
195 | // TestHelpers.EnableLogging(); | ||
196 | |||
197 | UUID userId = TestHelpers.ParseTail(0x1); | ||
198 | |||
199 | SceneHelpers sh = new SceneHelpers(); | ||
200 | LandManagementModule lmm = new LandManagementModule(); | ||
201 | Scene scene = sh.SetupScene(); | ||
202 | SceneHelpers.SetupSceneModules(scene, lmm); | ||
203 | |||
204 | ILandObject originalLo1 = new LandObject(userId, false, scene); | ||
205 | originalLo1.LandData.Name = "lo1"; | ||
206 | originalLo1.SetLandBitmap( | ||
207 | originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2)); | ||
208 | |||
209 | sh.SimDataService.StoreLandObject(originalLo1); | ||
210 | |||
211 | ILandObject originalLo2 = new LandObject(userId, false, scene); | ||
212 | originalLo2.LandData.Name = "lo2"; | ||
213 | originalLo2.SetLandBitmap( | ||
214 | originalLo2.GetSquareLandBitmap(0, (int)Constants.RegionSize / 2, (int)Constants.RegionSize, (int)Constants.RegionSize)); | ||
215 | |||
216 | sh.SimDataService.StoreLandObject(originalLo2); | ||
217 | |||
218 | scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); | ||
219 | |||
220 | { | ||
221 | ILandObject loAtCoord = lmm.GetLandObject(0, 0); | ||
222 | Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo1.LandData.Name)); | ||
223 | Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); | ||
224 | } | ||
225 | |||
226 | { | ||
227 | ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); | ||
228 | Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo2.LandData.Name)); | ||
229 | Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID)); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | [Test] | ||
234 | public void TestSubdivide() | ||
235 | { | ||
236 | TestHelpers.InMethod(); | ||
237 | // TestHelpers.EnableLogging(); | ||
238 | |||
239 | UUID userId = TestHelpers.ParseTail(0x1); | ||
240 | |||
241 | LandManagementModule lmm = new LandManagementModule(); | ||
242 | Scene scene = new SceneHelpers().SetupScene(); | ||
243 | SceneHelpers.SetupSceneModules(scene, lmm); | ||
244 | |||
245 | ILandObject lo = new LandObject(userId, false, scene); | ||
246 | lo.LandData.Name = "lo1"; | ||
247 | lo.SetLandBitmap( | ||
248 | lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); | ||
249 | lo = lmm.AddLandObject(lo); | ||
250 | |||
251 | lmm.Subdivide(0, 0, LandManagementModule.LandUnit, LandManagementModule.LandUnit, userId); | ||
252 | |||
253 | { | ||
254 | ILandObject loAtCoord = lmm.GetLandObject(0, 0); | ||
255 | Assert.That(loAtCoord.LandData.LocalID, Is.Not.EqualTo(lo.LandData.LocalID)); | ||
256 | Assert.That(loAtCoord.LandData.GlobalID, Is.Not.EqualTo(lo.LandData.GlobalID)); | ||
257 | } | ||
258 | |||
259 | { | ||
260 | ILandObject loAtCoord = lmm.GetLandObject(LandManagementModule.LandUnit, LandManagementModule.LandUnit); | ||
261 | Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID)); | ||
262 | Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID)); | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs index 0945b43..949acb6 100644 --- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs +++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs | |||
@@ -36,7 +36,6 @@ using OpenSim.Framework; | |||
36 | using OpenSim.Region.Framework.Interfaces; | 36 | using OpenSim.Region.Framework.Interfaces; |
37 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
38 | using OpenSim.Tests.Common; | 38 | using OpenSim.Tests.Common; |
39 | using OpenSim.Tests.Common.Mock; | ||
40 | 39 | ||
41 | namespace OpenSim.Region.CoreModules.World.Land.Tests | 40 | namespace OpenSim.Region.CoreModules.World.Land.Tests |
42 | { | 41 | { |
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs index 8a422b0..796a15f 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs | |||
@@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
55 | public struct DrawStruct | 55 | public struct DrawStruct |
56 | { | 56 | { |
57 | public DrawRoutine dr; | 57 | public DrawRoutine dr; |
58 | public Rectangle rect; | 58 | // public Rectangle rect; |
59 | public SolidBrush brush; | 59 | public SolidBrush brush; |
60 | public face[] trns; | 60 | public face[] trns; |
61 | } | 61 | } |
@@ -77,40 +77,71 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
77 | { | 77 | { |
78 | bool drawPrimVolume = true; | 78 | bool drawPrimVolume = true; |
79 | bool textureTerrain = false; | 79 | bool textureTerrain = false; |
80 | bool generateMaptiles = true; | ||
81 | Bitmap mapbmp; | ||
80 | 82 | ||
81 | try | 83 | string[] configSections = new string[] { "Map", "Startup" }; |
82 | { | ||
83 | IConfig startupConfig = m_config.Configs["Startup"]; | ||
84 | drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume); | ||
85 | textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain); | ||
86 | } | ||
87 | catch | ||
88 | { | ||
89 | m_log.Warn("[MAPTILE]: Failed to load StartupConfig"); | ||
90 | } | ||
91 | 84 | ||
92 | if (textureTerrain) | 85 | drawPrimVolume |
93 | { | 86 | = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume); |
94 | terrainRenderer = new TexturedMapTileRenderer(); | 87 | textureTerrain |
95 | } | 88 | = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain); |
96 | else | 89 | generateMaptiles |
90 | = Util.GetConfigVarFromSections<bool>(m_config, "GenerateMaptiles", configSections, generateMaptiles); | ||
91 | |||
92 | if (generateMaptiles) | ||
97 | { | 93 | { |
98 | terrainRenderer = new ShadedMapTileRenderer(); | 94 | if (String.IsNullOrEmpty(m_scene.RegionInfo.MaptileStaticFile)) |
99 | } | 95 | { |
100 | terrainRenderer.Initialise(m_scene, m_config); | 96 | if (textureTerrain) |
97 | { | ||
98 | terrainRenderer = new TexturedMapTileRenderer(); | ||
99 | } | ||
100 | else | ||
101 | { | ||
102 | terrainRenderer = new ShadedMapTileRenderer(); | ||
103 | } | ||
104 | |||
105 | terrainRenderer.Initialise(m_scene, m_config); | ||
101 | 106 | ||
102 | Bitmap mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); | 107 | mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height, |
103 | //long t = System.Environment.TickCount; | 108 | System.Drawing.Imaging.PixelFormat.Format24bppRgb); |
104 | //for (int i = 0; i < 10; ++i) { | 109 | //long t = System.Environment.TickCount; |
105 | terrainRenderer.TerrainToBitmap(mapbmp); | 110 | //for (int i = 0; i < 10; ++i) { |
106 | //} | 111 | terrainRenderer.TerrainToBitmap(mapbmp); |
107 | //t = System.Environment.TickCount - t; | 112 | //} |
108 | //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t); | 113 | //t = System.Environment.TickCount - t; |
114 | //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t); | ||
109 | 115 | ||
116 | if (drawPrimVolume) | ||
117 | { | ||
118 | DrawObjectVolume(m_scene, mapbmp); | ||
119 | } | ||
120 | } | ||
121 | else | ||
122 | { | ||
123 | try | ||
124 | { | ||
125 | mapbmp = new Bitmap(m_scene.RegionInfo.MaptileStaticFile); | ||
126 | } | ||
127 | catch (Exception) | ||
128 | { | ||
129 | m_log.ErrorFormat( | ||
130 | "[MAPTILE]: Failed to load Static map image texture file: {0} for {1}", | ||
131 | m_scene.RegionInfo.MaptileStaticFile, m_scene.Name); | ||
132 | //mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); | ||
133 | mapbmp = null; | ||
134 | } | ||
110 | 135 | ||
111 | if (drawPrimVolume) | 136 | if (mapbmp != null) |
137 | m_log.DebugFormat( | ||
138 | "[MAPTILE]: Static map image texture file {0} found for {1}", | ||
139 | m_scene.RegionInfo.MaptileStaticFile, m_scene.Name); | ||
140 | } | ||
141 | } | ||
142 | else | ||
112 | { | 143 | { |
113 | DrawObjectVolume(m_scene, mapbmp); | 144 | mapbmp = FetchTexture(m_scene.RegionInfo.RegionSettings.TerrainImageID); |
114 | } | 145 | } |
115 | 146 | ||
116 | return mapbmp; | 147 | return mapbmp; |
@@ -121,7 +152,10 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
121 | try | 152 | try |
122 | { | 153 | { |
123 | using (Bitmap mapbmp = CreateMapTile()) | 154 | using (Bitmap mapbmp = CreateMapTile()) |
124 | return OpenJPEG.EncodeFromImage(mapbmp, true); | 155 | { |
156 | if (mapbmp != null) | ||
157 | return OpenJPEG.EncodeFromImage(mapbmp, true); | ||
158 | } | ||
125 | } | 159 | } |
126 | catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke | 160 | catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke |
127 | { | 161 | { |
@@ -139,9 +173,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
139 | { | 173 | { |
140 | m_config = source; | 174 | m_config = source; |
141 | 175 | ||
142 | IConfig startupConfig = m_config.Configs["Startup"]; | 176 | if (Util.GetConfigVarFromSections<string>( |
143 | if (startupConfig.GetString("MapImageModule", "MapImageModule") != | 177 | m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "MapImageModule") |
144 | "MapImageModule") | ||
145 | return; | 178 | return; |
146 | 179 | ||
147 | m_Enabled = true; | 180 | m_Enabled = true; |
@@ -222,342 +255,395 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
222 | // } | 255 | // } |
223 | // } | 256 | // } |
224 | 257 | ||
258 | private Bitmap FetchTexture(UUID id) | ||
259 | { | ||
260 | AssetBase asset = m_scene.AssetService.Get(id.ToString()); | ||
261 | |||
262 | if (asset != null) | ||
263 | { | ||
264 | m_log.DebugFormat("[MAPTILE]: Static map image texture {0} found for {1}", id, m_scene.Name); | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | m_log.WarnFormat("[MAPTILE]: Static map image texture {0} not found for {1}", id, m_scene.Name); | ||
269 | return null; | ||
270 | } | ||
271 | |||
272 | ManagedImage managedImage; | ||
273 | Image image; | ||
274 | |||
275 | try | ||
276 | { | ||
277 | if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image)) | ||
278 | return new Bitmap(image); | ||
279 | else | ||
280 | return null; | ||
281 | } | ||
282 | catch (DllNotFoundException) | ||
283 | { | ||
284 | m_log.ErrorFormat("[MAPTILE]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id); | ||
285 | |||
286 | } | ||
287 | catch (IndexOutOfRangeException) | ||
288 | { | ||
289 | m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id); | ||
290 | |||
291 | } | ||
292 | catch (Exception) | ||
293 | { | ||
294 | m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id); | ||
295 | |||
296 | } | ||
297 | return null; | ||
298 | |||
299 | } | ||
300 | |||
225 | private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) | 301 | private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) |
226 | { | 302 | { |
227 | int tc = 0; | 303 | int tc = 0; |
228 | double[,] hm = whichScene.Heightmap.GetDoubles(); | 304 | ITerrainChannel hm = whichScene.Heightmap; |
229 | tc = Environment.TickCount; | 305 | tc = Environment.TickCount; |
230 | m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); | 306 | m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); |
231 | EntityBase[] objs = whichScene.GetEntities(); | 307 | EntityBase[] objs = whichScene.GetEntities(); |
232 | Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>(); | ||
233 | //SortedList<float, RectangleDrawStruct> z_sort = new SortedList<float, RectangleDrawStruct>(); | ||
234 | List<float> z_sortheights = new List<float>(); | 308 | List<float> z_sortheights = new List<float>(); |
235 | List<uint> z_localIDs = new List<uint>(); | 309 | List<uint> z_localIDs = new List<uint>(); |
310 | Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>(); | ||
236 | 311 | ||
237 | lock (objs) | 312 | try |
238 | { | 313 | { |
239 | foreach (EntityBase obj in objs) | 314 | lock (objs) |
240 | { | 315 | { |
241 | // Only draw the contents of SceneObjectGroup | 316 | foreach (EntityBase obj in objs) |
242 | if (obj is SceneObjectGroup) | ||
243 | { | 317 | { |
244 | SceneObjectGroup mapdot = (SceneObjectGroup)obj; | 318 | // Only draw the contents of SceneObjectGroup |
245 | Color mapdotspot = Color.Gray; // Default color when prim color is white | 319 | if (obj is SceneObjectGroup) |
246 | |||
247 | // Loop over prim in group | ||
248 | foreach (SceneObjectPart part in mapdot.Parts) | ||
249 | { | 320 | { |
250 | if (part == null) | 321 | SceneObjectGroup mapdot = (SceneObjectGroup)obj; |
251 | continue; | 322 | Color mapdotspot = Color.Gray; // Default color when prim color is white |
252 | 323 | // Loop over prim in group | |
253 | // Draw if the object is at least 1 meter wide in any direction | 324 | foreach (SceneObjectPart part in mapdot.Parts) |
254 | if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f) | ||
255 | { | 325 | { |
256 | // Try to get the RGBA of the default texture entry.. | 326 | if (part == null) |
257 | // | 327 | continue; |
258 | try | 328 | |
329 | // Draw if the object is at least 1 meter wide in any direction | ||
330 | if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f) | ||
259 | { | 331 | { |
260 | // get the null checks out of the way | 332 | // Try to get the RGBA of the default texture entry.. |
261 | // skip the ones that break | 333 | // |
262 | if (part == null) | 334 | try |
263 | continue; | 335 | { |
336 | // get the null checks out of the way | ||
337 | // skip the ones that break | ||
338 | if (part == null) | ||
339 | continue; | ||
264 | 340 | ||
265 | if (part.Shape == null) | 341 | if (part.Shape == null) |
266 | continue; | 342 | continue; |
267 | 343 | ||
268 | if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass) | 344 | if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass) |
269 | continue; // eliminates trees from this since we don't really have a good tree representation | 345 | continue; // eliminates trees from this since we don't really have a good tree representation |
270 | // if you want tree blocks on the map comment the above line and uncomment the below line | 346 | // if you want tree blocks on the map comment the above line and uncomment the below line |
271 | //mapdotspot = Color.PaleGreen; | 347 | //mapdotspot = Color.PaleGreen; |
272 | 348 | ||
273 | Primitive.TextureEntry textureEntry = part.Shape.Textures; | 349 | Primitive.TextureEntry textureEntry = part.Shape.Textures; |
274 | 350 | ||
275 | if (textureEntry == null || textureEntry.DefaultTexture == null) | 351 | if (textureEntry == null || textureEntry.DefaultTexture == null) |
276 | continue; | 352 | continue; |
277 | 353 | ||
278 | Color4 texcolor = textureEntry.DefaultTexture.RGBA; | 354 | Color4 texcolor = textureEntry.DefaultTexture.RGBA; |
279 | 355 | ||
280 | // Not sure why some of these are null, oh well. | 356 | // Not sure why some of these are null, oh well. |
281 | 357 | ||
282 | int colorr = 255 - (int)(texcolor.R * 255f); | 358 | int colorr = 255 - (int)(texcolor.R * 255f); |
283 | int colorg = 255 - (int)(texcolor.G * 255f); | 359 | int colorg = 255 - (int)(texcolor.G * 255f); |
284 | int colorb = 255 - (int)(texcolor.B * 255f); | 360 | int colorb = 255 - (int)(texcolor.B * 255f); |
285 | 361 | ||
286 | if (!(colorr == 255 && colorg == 255 && colorb == 255)) | 362 | if (!(colorr == 255 && colorg == 255 && colorb == 255)) |
287 | { | ||
288 | //Try to set the map spot color | ||
289 | try | ||
290 | { | ||
291 | // If the color gets goofy somehow, skip it *shakes fist at Color4 | ||
292 | mapdotspot = Color.FromArgb(colorr, colorg, colorb); | ||
293 | } | ||
294 | catch (ArgumentException) | ||
295 | { | 363 | { |
364 | //Try to set the map spot color | ||
365 | try | ||
366 | { | ||
367 | // If the color gets goofy somehow, skip it *shakes fist at Color4 | ||
368 | mapdotspot = Color.FromArgb(colorr, colorg, colorb); | ||
369 | } | ||
370 | catch (ArgumentException) | ||
371 | { | ||
372 | } | ||
296 | } | 373 | } |
297 | } | 374 | } |
298 | } | 375 | catch (IndexOutOfRangeException) |
299 | catch (IndexOutOfRangeException) | 376 | { |
300 | { | 377 | // Windows Array |
301 | // Windows Array | 378 | } |
302 | } | 379 | catch (ArgumentOutOfRangeException) |
303 | catch (ArgumentOutOfRangeException) | 380 | { |
304 | { | 381 | // Mono Array |
305 | // Mono Array | 382 | } |
306 | } | ||
307 | |||
308 | Vector3 pos = part.GetWorldPosition(); | ||
309 | |||
310 | // skip prim outside of retion | ||
311 | if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f) | ||
312 | continue; | ||
313 | |||
314 | // skip prim in non-finite position | ||
315 | if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) || | ||
316 | Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y)) | ||
317 | continue; | ||
318 | |||
319 | // Figure out if object is under 256m above the height of the terrain | ||
320 | bool isBelow256AboveTerrain = false; | ||
321 | 383 | ||
322 | try | 384 | Vector3 pos = part.GetWorldPosition(); |
323 | { | ||
324 | isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f)); | ||
325 | } | ||
326 | catch (Exception) | ||
327 | { | ||
328 | } | ||
329 | 385 | ||
330 | if (isBelow256AboveTerrain) | 386 | // skip prim outside of retion |
331 | { | 387 | if (!m_scene.PositionIsInCurrentRegion(pos)) |
332 | // Translate scale by rotation so scale is represented properly when object is rotated | ||
333 | Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z); | ||
334 | Vector3 scale = new Vector3(); | ||
335 | Vector3 tScale = new Vector3(); | ||
336 | Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z); | ||
337 | |||
338 | Quaternion llrot = part.GetWorldRotation(); | ||
339 | Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z); | ||
340 | scale = lscale * rot; | ||
341 | |||
342 | // negative scales don't work in this situation | ||
343 | scale.X = Math.Abs(scale.X); | ||
344 | scale.Y = Math.Abs(scale.Y); | ||
345 | scale.Z = Math.Abs(scale.Z); | ||
346 | |||
347 | // This scaling isn't very accurate and doesn't take into account the face rotation :P | ||
348 | int mapdrawstartX = (int)(pos.X - scale.X); | ||
349 | int mapdrawstartY = (int)(pos.Y - scale.Y); | ||
350 | int mapdrawendX = (int)(pos.X + scale.X); | ||
351 | int mapdrawendY = (int)(pos.Y + scale.Y); | ||
352 | |||
353 | // If object is beyond the edge of the map, don't draw it to avoid errors | ||
354 | if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1) | ||
355 | || mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0 | ||
356 | || mapdrawendY > ((int)Constants.RegionSize - 1)) | ||
357 | continue; | 388 | continue; |
358 | 389 | ||
359 | #region obb face reconstruction part duex | 390 | // skip prim in non-finite position |
360 | Vector3[] vertexes = new Vector3[8]; | 391 | if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) || |
361 | 392 | Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y)) | |
362 | // float[] distance = new float[6]; | 393 | continue; |
363 | Vector3[] FaceA = new Vector3[6]; // vertex A for Facei | ||
364 | Vector3[] FaceB = new Vector3[6]; // vertex B for Facei | ||
365 | Vector3[] FaceC = new Vector3[6]; // vertex C for Facei | ||
366 | Vector3[] FaceD = new Vector3[6]; // vertex D for Facei | ||
367 | |||
368 | tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z); | ||
369 | scale = ((tScale * rot)); | ||
370 | vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
371 | // vertexes[0].x = pos.X + vertexes[0].x; | ||
372 | //vertexes[0].y = pos.Y + vertexes[0].y; | ||
373 | //vertexes[0].z = pos.Z + vertexes[0].z; | ||
374 | |||
375 | FaceA[0] = vertexes[0]; | ||
376 | FaceB[3] = vertexes[0]; | ||
377 | FaceA[4] = vertexes[0]; | ||
378 | |||
379 | tScale = lscale; | ||
380 | scale = ((tScale * rot)); | ||
381 | vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
382 | |||
383 | // vertexes[1].x = pos.X + vertexes[1].x; | ||
384 | // vertexes[1].y = pos.Y + vertexes[1].y; | ||
385 | //vertexes[1].z = pos.Z + vertexes[1].z; | ||
386 | |||
387 | FaceB[0] = vertexes[1]; | ||
388 | FaceA[1] = vertexes[1]; | ||
389 | FaceC[4] = vertexes[1]; | ||
390 | |||
391 | tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z); | ||
392 | scale = ((tScale * rot)); | ||
393 | |||
394 | vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
395 | |||
396 | //vertexes[2].x = pos.X + vertexes[2].x; | ||
397 | //vertexes[2].y = pos.Y + vertexes[2].y; | ||
398 | //vertexes[2].z = pos.Z + vertexes[2].z; | ||
399 | |||
400 | FaceC[0] = vertexes[2]; | ||
401 | FaceD[3] = vertexes[2]; | ||
402 | FaceC[5] = vertexes[2]; | ||
403 | |||
404 | tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z); | ||
405 | scale = ((tScale * rot)); | ||
406 | vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
407 | |||
408 | //vertexes[3].x = pos.X + vertexes[3].x; | ||
409 | // vertexes[3].y = pos.Y + vertexes[3].y; | ||
410 | // vertexes[3].z = pos.Z + vertexes[3].z; | ||
411 | |||
412 | FaceD[0] = vertexes[3]; | ||
413 | FaceC[1] = vertexes[3]; | ||
414 | FaceA[5] = vertexes[3]; | ||
415 | |||
416 | tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z); | ||
417 | scale = ((tScale * rot)); | ||
418 | vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
419 | |||
420 | // vertexes[4].x = pos.X + vertexes[4].x; | ||
421 | // vertexes[4].y = pos.Y + vertexes[4].y; | ||
422 | // vertexes[4].z = pos.Z + vertexes[4].z; | ||
423 | |||
424 | FaceB[1] = vertexes[4]; | ||
425 | FaceA[2] = vertexes[4]; | ||
426 | FaceD[4] = vertexes[4]; | ||
427 | |||
428 | tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z); | ||
429 | scale = ((tScale * rot)); | ||
430 | vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
431 | |||
432 | // vertexes[5].x = pos.X + vertexes[5].x; | ||
433 | // vertexes[5].y = pos.Y + vertexes[5].y; | ||
434 | // vertexes[5].z = pos.Z + vertexes[5].z; | ||
435 | |||
436 | FaceD[1] = vertexes[5]; | ||
437 | FaceC[2] = vertexes[5]; | ||
438 | FaceB[5] = vertexes[5]; | ||
439 | |||
440 | tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z); | ||
441 | scale = ((tScale * rot)); | ||
442 | vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
443 | 394 | ||
444 | // vertexes[6].x = pos.X + vertexes[6].x; | 395 | // Figure out if object is under 256m above the height of the terrain |
445 | // vertexes[6].y = pos.Y + vertexes[6].y; | 396 | bool isBelow256AboveTerrain = false; |
446 | // vertexes[6].z = pos.Z + vertexes[6].z; | ||
447 | 397 | ||
448 | FaceB[2] = vertexes[6]; | 398 | try |
449 | FaceA[3] = vertexes[6]; | 399 | { |
450 | FaceB[4] = vertexes[6]; | 400 | isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f)); |
401 | } | ||
402 | catch (Exception) | ||
403 | { | ||
404 | } | ||
451 | 405 | ||
452 | tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z); | 406 | if (isBelow256AboveTerrain) |
453 | scale = ((tScale * rot)); | 407 | { |
454 | vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | 408 | // Translate scale by rotation so scale is represented properly when object is rotated |
409 | Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z); | ||
410 | Vector3 scale = new Vector3(); | ||
411 | Vector3 tScale = new Vector3(); | ||
412 | Vector3 axPos = new Vector3(pos.X, pos.Y, pos.Z); | ||
413 | |||
414 | Quaternion llrot = part.GetWorldRotation(); | ||
415 | Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z); | ||
416 | scale = lscale * rot; | ||
417 | |||
418 | // negative scales don't work in this situation | ||
419 | scale.X = Math.Abs(scale.X); | ||
420 | scale.Y = Math.Abs(scale.Y); | ||
421 | scale.Z = Math.Abs(scale.Z); | ||
422 | |||
423 | // This scaling isn't very accurate and doesn't take into account the face rotation :P | ||
424 | int mapdrawstartX = (int)(pos.X - scale.X); | ||
425 | int mapdrawstartY = (int)(pos.Y - scale.Y); | ||
426 | int mapdrawendX = (int)(pos.X + scale.X); | ||
427 | int mapdrawendY = (int)(pos.Y + scale.Y); | ||
428 | |||
429 | // If object is beyond the edge of the map, don't draw it to avoid errors | ||
430 | if (mapdrawstartX < 0 | ||
431 | || mapdrawstartX > (hm.Width - 1) | ||
432 | || mapdrawendX < 0 | ||
433 | || mapdrawendX > (hm.Width - 1) | ||
434 | || mapdrawstartY < 0 | ||
435 | || mapdrawstartY > (hm.Height - 1) | ||
436 | || mapdrawendY < 0 | ||
437 | || mapdrawendY > (hm.Height - 1)) | ||
438 | continue; | ||
439 | |||
440 | #region obb face reconstruction part duex | ||
441 | Vector3[] vertexes = new Vector3[8]; | ||
442 | |||
443 | // float[] distance = new float[6]; | ||
444 | Vector3[] FaceA = new Vector3[6]; // vertex A for Facei | ||
445 | Vector3[] FaceB = new Vector3[6]; // vertex B for Facei | ||
446 | Vector3[] FaceC = new Vector3[6]; // vertex C for Facei | ||
447 | Vector3[] FaceD = new Vector3[6]; // vertex D for Facei | ||
448 | |||
449 | tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z); | ||
450 | scale = ((tScale * rot)); | ||
451 | vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
452 | // vertexes[0].x = pos.X + vertexes[0].x; | ||
453 | //vertexes[0].y = pos.Y + vertexes[0].y; | ||
454 | //vertexes[0].z = pos.Z + vertexes[0].z; | ||
455 | |||
456 | FaceA[0] = vertexes[0]; | ||
457 | FaceB[3] = vertexes[0]; | ||
458 | FaceA[4] = vertexes[0]; | ||
459 | |||
460 | tScale = lscale; | ||
461 | scale = ((tScale * rot)); | ||
462 | vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
463 | |||
464 | // vertexes[1].x = pos.X + vertexes[1].x; | ||
465 | // vertexes[1].y = pos.Y + vertexes[1].y; | ||
466 | //vertexes[1].z = pos.Z + vertexes[1].z; | ||
467 | |||
468 | FaceB[0] = vertexes[1]; | ||
469 | FaceA[1] = vertexes[1]; | ||
470 | FaceC[4] = vertexes[1]; | ||
471 | |||
472 | tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z); | ||
473 | scale = ((tScale * rot)); | ||
474 | |||
475 | vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
476 | |||
477 | //vertexes[2].x = pos.X + vertexes[2].x; | ||
478 | //vertexes[2].y = pos.Y + vertexes[2].y; | ||
479 | //vertexes[2].z = pos.Z + vertexes[2].z; | ||
480 | |||
481 | FaceC[0] = vertexes[2]; | ||
482 | FaceD[3] = vertexes[2]; | ||
483 | FaceC[5] = vertexes[2]; | ||
484 | |||
485 | tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z); | ||
486 | scale = ((tScale * rot)); | ||
487 | vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
488 | |||
489 | //vertexes[3].x = pos.X + vertexes[3].x; | ||
490 | // vertexes[3].y = pos.Y + vertexes[3].y; | ||
491 | // vertexes[3].z = pos.Z + vertexes[3].z; | ||
492 | |||
493 | FaceD[0] = vertexes[3]; | ||
494 | FaceC[1] = vertexes[3]; | ||
495 | FaceA[5] = vertexes[3]; | ||
496 | |||
497 | tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z); | ||
498 | scale = ((tScale * rot)); | ||
499 | vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
500 | |||
501 | // vertexes[4].x = pos.X + vertexes[4].x; | ||
502 | // vertexes[4].y = pos.Y + vertexes[4].y; | ||
503 | // vertexes[4].z = pos.Z + vertexes[4].z; | ||
504 | |||
505 | FaceB[1] = vertexes[4]; | ||
506 | FaceA[2] = vertexes[4]; | ||
507 | FaceD[4] = vertexes[4]; | ||
508 | |||
509 | tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z); | ||
510 | scale = ((tScale * rot)); | ||
511 | vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
512 | |||
513 | // vertexes[5].x = pos.X + vertexes[5].x; | ||
514 | // vertexes[5].y = pos.Y + vertexes[5].y; | ||
515 | // vertexes[5].z = pos.Z + vertexes[5].z; | ||
516 | |||
517 | FaceD[1] = vertexes[5]; | ||
518 | FaceC[2] = vertexes[5]; | ||
519 | FaceB[5] = vertexes[5]; | ||
520 | |||
521 | tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z); | ||
522 | scale = ((tScale * rot)); | ||
523 | vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
524 | |||
525 | // vertexes[6].x = pos.X + vertexes[6].x; | ||
526 | // vertexes[6].y = pos.Y + vertexes[6].y; | ||
527 | // vertexes[6].z = pos.Z + vertexes[6].z; | ||
528 | |||
529 | FaceB[2] = vertexes[6]; | ||
530 | FaceA[3] = vertexes[6]; | ||
531 | FaceB[4] = vertexes[6]; | ||
532 | |||
533 | tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z); | ||
534 | scale = ((tScale * rot)); | ||
535 | vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); | ||
455 | 536 | ||
456 | // vertexes[7].x = pos.X + vertexes[7].x; | 537 | // vertexes[7].x = pos.X + vertexes[7].x; |
457 | // vertexes[7].y = pos.Y + vertexes[7].y; | 538 | // vertexes[7].y = pos.Y + vertexes[7].y; |
458 | // vertexes[7].z = pos.Z + vertexes[7].z; | 539 | // vertexes[7].z = pos.Z + vertexes[7].z; |
459 | 540 | ||
460 | FaceD[2] = vertexes[7]; | 541 | FaceD[2] = vertexes[7]; |
461 | FaceC[3] = vertexes[7]; | 542 | FaceC[3] = vertexes[7]; |
462 | FaceD[5] = vertexes[7]; | 543 | FaceD[5] = vertexes[7]; |
463 | #endregion | 544 | #endregion |
464 | 545 | ||
465 | //int wy = 0; | 546 | //int wy = 0; |
466 | 547 | ||
467 | //bool breakYN = false; // If we run into an error drawing, break out of the | 548 | //bool breakYN = false; // If we run into an error drawing, break out of the |
468 | // loop so we don't lag to death on error handling | 549 | // loop so we don't lag to death on error handling |
469 | DrawStruct ds = new DrawStruct(); | 550 | DrawStruct ds = new DrawStruct(); |
470 | ds.brush = new SolidBrush(mapdotspot); | 551 | ds.brush = new SolidBrush(mapdotspot); |
471 | //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY); | 552 | //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY); |
472 | 553 | ||
473 | ds.trns = new face[FaceA.Length]; | 554 | ds.trns = new face[FaceA.Length]; |
474 | 555 | ||
475 | for (int i = 0; i < FaceA.Length; i++) | 556 | for (int i = 0; i < FaceA.Length; i++) |
476 | { | 557 | { |
477 | Point[] working = new Point[5]; | 558 | Point[] working = new Point[5]; |
478 | working[0] = project(FaceA[i], axPos); | 559 | working[0] = project(hm, FaceA[i], axPos); |
479 | working[1] = project(FaceB[i], axPos); | 560 | working[1] = project(hm, FaceB[i], axPos); |
480 | working[2] = project(FaceD[i], axPos); | 561 | working[2] = project(hm, FaceD[i], axPos); |
481 | working[3] = project(FaceC[i], axPos); | 562 | working[3] = project(hm, FaceC[i], axPos); |
482 | working[4] = project(FaceA[i], axPos); | 563 | working[4] = project(hm, FaceA[i], axPos); |
483 | 564 | ||
484 | face workingface = new face(); | 565 | face workingface = new face(); |
485 | workingface.pts = working; | 566 | workingface.pts = working; |
486 | 567 | ||
487 | ds.trns[i] = workingface; | 568 | ds.trns[i] = workingface; |
488 | } | 569 | } |
489 | 570 | ||
490 | z_sort.Add(part.LocalId, ds); | 571 | z_sort.Add(part.LocalId, ds); |
491 | z_localIDs.Add(part.LocalId); | 572 | z_localIDs.Add(part.LocalId); |
492 | z_sortheights.Add(pos.Z); | 573 | z_sortheights.Add(pos.Z); |
493 | 574 | ||
494 | //for (int wx = mapdrawstartX; wx < mapdrawendX; wx++) | 575 | // for (int wx = mapdrawstartX; wx < mapdrawendX; wx++) |
495 | //{ | 576 | // { |
496 | //for (wy = mapdrawstartY; wy < mapdrawendY; wy++) | 577 | // for (wy = mapdrawstartY; wy < mapdrawendY; wy++) |
497 | //{ | 578 | // { |
498 | //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy); | 579 | // m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy); |
499 | //try | 580 | // try |
500 | //{ | 581 | // { |
501 | // Remember, flip the y! | 582 | // // Remember, flip the y! |
502 | // mapbmp.SetPixel(wx, (255 - wy), mapdotspot); | 583 | // mapbmp.SetPixel(wx, (255 - wy), mapdotspot); |
503 | //} | 584 | // } |
504 | //catch (ArgumentException) | 585 | // catch (ArgumentException) |
505 | //{ | 586 | // { |
506 | // breakYN = true; | 587 | // breakYN = true; |
507 | //} | 588 | // } |
508 | 589 | // } | |
509 | //if (breakYN) | 590 | // if (breakYN) |
510 | // break; | 591 | // break; |
592 | // } | ||
593 | // } | ||
511 | //} | 594 | //} |
595 | } // Object is within 256m Z of terrain | ||
596 | } // object is at least a meter wide | ||
597 | } // loop over group children | ||
598 | } // entitybase is sceneobject group | ||
599 | } // foreach loop over entities | ||
512 | 600 | ||
513 | //if (breakYN) | 601 | float[] sortedZHeights = z_sortheights.ToArray(); |
514 | // break; | 602 | uint[] sortedlocalIds = z_localIDs.ToArray(); |
515 | //} | ||
516 | } // Object is within 256m Z of terrain | ||
517 | } // object is at least a meter wide | ||
518 | } // loop over group children | ||
519 | } // entitybase is sceneobject group | ||
520 | } // foreach loop over entities | ||
521 | 603 | ||
522 | float[] sortedZHeights = z_sortheights.ToArray(); | 604 | // Sort prim by Z position |
523 | uint[] sortedlocalIds = z_localIDs.ToArray(); | 605 | Array.Sort(sortedZHeights, sortedlocalIds); |
524 | 606 | ||
525 | // Sort prim by Z position | 607 | using (Graphics g = Graphics.FromImage(mapbmp)) |
526 | Array.Sort(sortedZHeights, sortedlocalIds); | ||
527 | |||
528 | Graphics g = Graphics.FromImage(mapbmp); | ||
529 | |||
530 | for (int s = 0; s < sortedZHeights.Length; s++) | ||
531 | { | ||
532 | if (z_sort.ContainsKey(sortedlocalIds[s])) | ||
533 | { | 608 | { |
534 | DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]]; | 609 | for (int s = 0; s < sortedZHeights.Length; s++) |
535 | for (int r = 0; r < rectDrawStruct.trns.Length; r++) | ||
536 | { | 610 | { |
537 | g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts); | 611 | if (z_sort.ContainsKey(sortedlocalIds[s])) |
612 | { | ||
613 | DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]]; | ||
614 | for (int r = 0; r < rectDrawStruct.trns.Length; r++) | ||
615 | { | ||
616 | g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts); | ||
617 | } | ||
618 | //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect); | ||
619 | } | ||
538 | } | 620 | } |
539 | //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect); | ||
540 | } | 621 | } |
541 | } | 622 | } // lock entities objs |
542 | 623 | ||
543 | g.Dispose(); | 624 | } |
544 | } // lock entities objs | 625 | finally |
626 | { | ||
627 | foreach (DrawStruct ds in z_sort.Values) | ||
628 | ds.brush.Dispose(); | ||
629 | } | ||
545 | 630 | ||
546 | m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms"); | 631 | m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms"); |
632 | |||
547 | return mapbmp; | 633 | return mapbmp; |
548 | } | 634 | } |
549 | 635 | ||
550 | private Point project(Vector3 point3d, Vector3 originpos) | 636 | private Point project(ITerrainChannel hm, Vector3 point3d, Vector3 originpos) |
551 | { | 637 | { |
552 | Point returnpt = new Point(); | 638 | Point returnpt = new Point(); |
553 | //originpos = point3d; | 639 | //originpos = point3d; |
554 | //int d = (int)(256f / 1.5f); | 640 | //int d = (int)(256f / 1.5f); |
555 | 641 | ||
556 | //Vector3 topos = new Vector3(0, 0, 0); | 642 | //Vector3 topos = new Vector3(0, 0, 0); |
557 | // float z = -point3d.z - topos.z; | 643 | // float z = -point3d.z - topos.z; |
558 | 644 | ||
559 | returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d); | 645 | returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d); |
560 | returnpt.Y = (int)(((int)Constants.RegionSize - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d))); | 646 | returnpt.Y = (int)((hm.Width - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d))); |
561 | 647 | ||
562 | return returnpt; | 648 | return returnpt; |
563 | } | 649 | } |
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs index 992bff3..708286c 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs | |||
@@ -31,6 +31,7 @@ using System.Reflection; | |||
31 | using log4net; | 31 | using log4net; |
32 | using Nini.Config; | 32 | using Nini.Config; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Region.Framework.Interfaces; | ||
34 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
35 | 36 | ||
36 | namespace OpenSim.Region.CoreModules.World.LegacyMap | 37 | namespace OpenSim.Region.CoreModules.World.LegacyMap |
@@ -39,8 +40,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
39 | { | 40 | { |
40 | private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); | 41 | private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); |
41 | 42 | ||
42 | private static readonly ILog m_log = | 43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
43 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly string LogHeader = "[SHADED MAPTILE RENDERER]"; |
44 | 45 | ||
45 | private Scene m_scene; | 46 | private Scene m_scene; |
46 | //private IConfigSource m_config; // not used currently | 47 | //private IConfigSource m_config; // not used currently |
@@ -53,19 +54,26 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
53 | 54 | ||
54 | public void TerrainToBitmap(Bitmap mapbmp) | 55 | public void TerrainToBitmap(Bitmap mapbmp) |
55 | { | 56 | { |
57 | m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader); | ||
56 | int tc = Environment.TickCount; | 58 | int tc = Environment.TickCount; |
57 | m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); | ||
58 | 59 | ||
59 | double[,] hm = m_scene.Heightmap.GetDoubles(); | 60 | ITerrainChannel hm = m_scene.Heightmap; |
61 | |||
62 | if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height) | ||
63 | { | ||
64 | m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>", | ||
65 | LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height); | ||
66 | } | ||
67 | |||
60 | bool ShadowDebugContinue = true; | 68 | bool ShadowDebugContinue = true; |
61 | 69 | ||
62 | bool terraincorruptedwarningsaid = false; | 70 | bool terraincorruptedwarningsaid = false; |
63 | 71 | ||
64 | float low = 255; | 72 | float low = 255; |
65 | float high = 0; | 73 | float high = 0; |
66 | for (int x = 0; x < (int)Constants.RegionSize; x++) | 74 | for (int x = 0; x < hm.Width; x++) |
67 | { | 75 | { |
68 | for (int y = 0; y < (int)Constants.RegionSize; y++) | 76 | for (int y = 0; y < hm.Height; y++) |
69 | { | 77 | { |
70 | float hmval = (float)hm[x, y]; | 78 | float hmval = (float)hm[x, y]; |
71 | if (hmval < low) | 79 | if (hmval < low) |
@@ -77,12 +85,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
77 | 85 | ||
78 | float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; | 86 | float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; |
79 | 87 | ||
80 | for (int x = 0; x < (int)Constants.RegionSize; x++) | 88 | for (int x = 0; x < hm.Width; x++) |
81 | { | 89 | { |
82 | for (int y = 0; y < (int)Constants.RegionSize; y++) | 90 | for (int y = 0; y < hm.Height; y++) |
83 | { | 91 | { |
84 | // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left | 92 | // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left |
85 | int yr = ((int)Constants.RegionSize - 1) - y; | 93 | int yr = ((int)hm.Height - 1) - y; |
86 | 94 | ||
87 | float heightvalue = (float)hm[x, y]; | 95 | float heightvalue = (float)hm[x, y]; |
88 | 96 | ||
@@ -109,12 +117,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
109 | // . | 117 | // . |
110 | // | 118 | // |
111 | // Shade the terrain for shadows | 119 | // Shade the terrain for shadows |
112 | if (x < ((int)Constants.RegionSize - 1) && yr < ((int)Constants.RegionSize - 1)) | 120 | if (x < (hm.Width - 1) && yr < (hm.Height - 1)) |
113 | { | 121 | { |
114 | float hfvalue = (float)hm[x, y]; | 122 | float hfvalue = (float)hm[x, y]; |
115 | float hfvaluecompare = 0f; | 123 | float hfvaluecompare = 0f; |
116 | 124 | ||
117 | if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize)) | 125 | if ((x + 1 < hm.Width) && (y + 1 < hm.Height)) |
118 | { | 126 | { |
119 | hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there | 127 | hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there |
120 | } | 128 | } |
@@ -179,7 +187,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
179 | 187 | ||
180 | if (ShadowDebugContinue) | 188 | if (ShadowDebugContinue) |
181 | { | 189 | { |
182 | if ((x - 1 > 0) && (yr + 1 < (int)Constants.RegionSize)) | 190 | if ((x - 1 > 0) && (yr + 1 < hm.Height)) |
183 | { | 191 | { |
184 | color = mapbmp.GetPixel(x - 1, yr + 1); | 192 | color = mapbmp.GetPixel(x - 1, yr + 1); |
185 | int r = color.R; | 193 | int r = color.R; |
@@ -199,7 +207,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
199 | { | 207 | { |
200 | if (!terraincorruptedwarningsaid) | 208 | if (!terraincorruptedwarningsaid) |
201 | { | 209 | { |
202 | m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName); | 210 | m_log.WarnFormat("[SHADED MAP TILE RENDERER]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName); |
203 | terraincorruptedwarningsaid = true; | 211 | terraincorruptedwarningsaid = true; |
204 | } | 212 | } |
205 | color = Color.Black; | 213 | color = Color.Black; |
@@ -229,16 +237,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
229 | { | 237 | { |
230 | if (!terraincorruptedwarningsaid) | 238 | if (!terraincorruptedwarningsaid) |
231 | { | 239 | { |
232 | m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName); | 240 | m_log.WarnFormat("[SHADED MAP TILE RENDERER]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName); |
233 | terraincorruptedwarningsaid = true; | 241 | terraincorruptedwarningsaid = true; |
234 | } | 242 | } |
235 | Color black = Color.Black; | 243 | Color black = Color.Black; |
236 | mapbmp.SetPixel(x, ((int)Constants.RegionSize - y) - 1, black); | 244 | mapbmp.SetPixel(x, (hm.Width - y) - 1, black); |
237 | } | 245 | } |
238 | } | 246 | } |
239 | } | 247 | } |
240 | } | 248 | } |
241 | m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); | 249 | |
250 | m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); | ||
242 | } | 251 | } |
243 | } | 252 | } |
244 | } | 253 | } |
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs index d13c2ef..9f23141 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs | |||
@@ -34,6 +34,8 @@ using Nini.Config; | |||
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenMetaverse.Imaging; | 35 | using OpenMetaverse.Imaging; |
36 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
37 | using OpenSim.Region.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
38 | 40 | ||
39 | namespace OpenSim.Region.CoreModules.World.LegacyMap | 41 | namespace OpenSim.Region.CoreModules.World.LegacyMap |
@@ -122,8 +124,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
122 | { | 124 | { |
123 | #region Constants | 125 | #region Constants |
124 | 126 | ||
125 | private static readonly ILog m_log = | 127 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
126 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 128 | private static readonly string LogHeader = "[TEXTURED MAPTILE RENDERER]"; |
127 | 129 | ||
128 | // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank"). | 130 | // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank"). |
129 | // The color-values were choosen because they "look right" (at least to me) ;-) | 131 | // The color-values were choosen because they "look right" (at least to me) ;-) |
@@ -173,7 +175,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
173 | private Bitmap fetchTexture(UUID id) | 175 | private Bitmap fetchTexture(UUID id) |
174 | { | 176 | { |
175 | AssetBase asset = m_scene.AssetService.Get(id.ToString()); | 177 | AssetBase asset = m_scene.AssetService.Get(id.ToString()); |
176 | m_log.DebugFormat("[TexturedMapTileRenderer]: Fetched texture {0}, found: {1}", id, asset != null); | 178 | m_log.DebugFormat("{0} Fetched texture {1}, found: {2}", LogHeader, id, asset != null); |
177 | if (asset == null) return null; | 179 | if (asset == null) return null; |
178 | 180 | ||
179 | ManagedImage managedImage; | 181 | ManagedImage managedImage; |
@@ -188,18 +190,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
188 | } | 190 | } |
189 | catch (DllNotFoundException) | 191 | catch (DllNotFoundException) |
190 | { | 192 | { |
191 | m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id); | 193 | m_log.ErrorFormat("{0} OpenJpeg is not installed correctly on this system. Asset Data is empty for {1}", LogHeader, id); |
192 | |||
193 | } | 194 | } |
194 | catch (IndexOutOfRangeException) | 195 | catch (IndexOutOfRangeException) |
195 | { | 196 | { |
196 | m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); | 197 | m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id); |
197 | |||
198 | } | 198 | } |
199 | catch (Exception) | 199 | catch (Exception) |
200 | { | 200 | { |
201 | m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); | 201 | m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id); |
202 | |||
203 | } | 202 | } |
204 | return null; | 203 | return null; |
205 | 204 | ||
@@ -233,10 +232,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
233 | if (textureID == UUID.Zero) return defaultColor; // not set | 232 | if (textureID == UUID.Zero) return defaultColor; // not set |
234 | if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures | 233 | if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures |
235 | 234 | ||
236 | Bitmap bmp = fetchTexture(textureID); | 235 | Color color; |
237 | Color color = bmp == null ? defaultColor : computeAverageColor(bmp); | 236 | |
238 | // store it for future reference | 237 | using (Bitmap bmp = fetchTexture(textureID)) |
239 | m_mapping[textureID] = color; | 238 | { |
239 | color = bmp == null ? defaultColor : computeAverageColor(bmp); | ||
240 | // store it for future reference | ||
241 | m_mapping[textureID] = color; | ||
242 | } | ||
240 | 243 | ||
241 | return color; | 244 | return color; |
242 | } | 245 | } |
@@ -267,8 +270,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
267 | 270 | ||
268 | // the heigthfield might have some jumps in values. Rendered land is smooth, though, | 271 | // the heigthfield might have some jumps in values. Rendered land is smooth, though, |
269 | // as a slope is rendered at that place. So average 4 neighbour values to emulate that. | 272 | // as a slope is rendered at that place. So average 4 neighbour values to emulate that. |
270 | private float getHeight(double[,] hm, int x, int y) { | 273 | private float getHeight(ITerrainChannel hm, int x, int y) { |
271 | if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1)) | 274 | if (x < (hm.Width - 1) && y < (hm.Height - 1)) |
272 | return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112); | 275 | return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112); |
273 | else | 276 | else |
274 | return (float)hm[x, y]; | 277 | return (float)hm[x, y]; |
@@ -278,7 +281,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
278 | public void TerrainToBitmap(Bitmap mapbmp) | 281 | public void TerrainToBitmap(Bitmap mapbmp) |
279 | { | 282 | { |
280 | int tc = Environment.TickCount; | 283 | int tc = Environment.TickCount; |
281 | m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); | 284 | m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader); |
285 | |||
286 | ITerrainChannel hm = m_scene.Heightmap; | ||
287 | |||
288 | if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height) | ||
289 | { | ||
290 | m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>", | ||
291 | LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height); | ||
292 | } | ||
282 | 293 | ||
283 | // These textures should be in the AssetCache anyway, as every client conneting to this | 294 | // These textures should be in the AssetCache anyway, as every client conneting to this |
284 | // region needs them. Except on start, when the map is recreated (before anyone connected), | 295 | // region needs them. Except on start, when the map is recreated (before anyone connected), |
@@ -306,19 +317,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
306 | 317 | ||
307 | float waterHeight = (float)settings.WaterHeight; | 318 | float waterHeight = (float)settings.WaterHeight; |
308 | 319 | ||
309 | double[,] hm = m_scene.Heightmap.GetDoubles(); | 320 | for (int x = 0; x < hm.Width; x++) |
310 | |||
311 | for (int x = 0; x < (int)Constants.RegionSize; x++) | ||
312 | { | 321 | { |
313 | float columnRatio = x / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation | 322 | float columnRatio = x / (hm.Width - 1); // 0 - 1, for interpolation |
314 | for (int y = 0; y < (int)Constants.RegionSize; y++) | 323 | for (int y = 0; y < hm.Height; y++) |
315 | { | 324 | { |
316 | float rowRatio = y / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation | 325 | float rowRatio = y / (hm.Height - 1); // 0 - 1, for interpolation |
317 | 326 | ||
318 | // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left | 327 | // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left |
319 | int yr = ((int)Constants.RegionSize - 1) - y; | 328 | int yr = (hm.Height - 1) - y; |
320 | 329 | ||
321 | float heightvalue = getHeight(hm, x, y); | 330 | float heightvalue = getHeight(m_scene.Heightmap, x, y); |
322 | if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue)) | 331 | if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue)) |
323 | heightvalue = 0; | 332 | heightvalue = 0; |
324 | 333 | ||
@@ -368,9 +377,9 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
368 | } | 377 | } |
369 | 378 | ||
370 | // Shade the terrain for shadows | 379 | // Shade the terrain for shadows |
371 | if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1)) | 380 | if (x < (hm.Width - 1) && y < (hm.Height - 1)) |
372 | { | 381 | { |
373 | float hfvaluecompare = getHeight(hm, x + 1, y + 1); // light from north-east => look at land height there | 382 | float hfvaluecompare = getHeight(m_scene.Heightmap, x + 1, y + 1); // light from north-east => look at land height there |
374 | if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare)) | 383 | if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare)) |
375 | hfvaluecompare = 0f; | 384 | hfvaluecompare = 0f; |
376 | 385 | ||
@@ -412,7 +421,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
412 | } | 421 | } |
413 | } | 422 | } |
414 | } | 423 | } |
415 | m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); | 424 | |
425 | m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); | ||
416 | } | 426 | } |
417 | } | 427 | } |
418 | } | 428 | } |
diff --git a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs index 4e20196..0a4e83e 100644 --- a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs +++ b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs | |||
@@ -195,19 +195,20 @@ namespace OpenSim.Region.CoreModules.World.LightShare | |||
195 | if (m_scene.RegionInfo.WindlightSettings.valid) | 195 | if (m_scene.RegionInfo.WindlightSettings.valid) |
196 | { | 196 | { |
197 | List<byte[]> param = compileWindlightSettings(wl); | 197 | List<byte[]> param = compileWindlightSettings(wl); |
198 | client.SendGenericMessage("Windlight", param); | 198 | client.SendGenericMessage("Windlight", UUID.Random(), param); |
199 | } | 199 | } |
200 | else | 200 | else |
201 | { | 201 | { |
202 | List<byte[]> param = new List<byte[]>(); | 202 | List<byte[]> param = new List<byte[]>(); |
203 | client.SendGenericMessage("WindlightReset", param); | 203 | client.SendGenericMessage("WindlightReset", UUID.Random(), param); |
204 | } | 204 | } |
205 | } | 205 | } |
206 | } | 206 | } |
207 | 207 | ||
208 | private void EventManager_OnMakeRootAgent(ScenePresence presence) | 208 | private void EventManager_OnMakeRootAgent(ScenePresence presence) |
209 | { | 209 | { |
210 | m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client"); | 210 | // m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client {0}", presence.Name); |
211 | |||
211 | SendProfileToClient(presence.ControllingClient); | 212 | SendProfileToClient(presence.ControllingClient); |
212 | } | 213 | } |
213 | 214 | ||
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs index 601e81e..46b0470 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs | |||
@@ -595,6 +595,9 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap | |||
595 | /// <returns>true if the url matches an entry on the whitelist, false otherwise</returns> | 595 | /// <returns>true if the url matches an entry on the whitelist, false otherwise</returns> |
596 | protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist) | 596 | protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist) |
597 | { | 597 | { |
598 | if (whitelist == null) | ||
599 | return false; | ||
600 | |||
598 | Uri url = new Uri(rawUrl); | 601 | Uri url = new Uri(rawUrl); |
599 | 602 | ||
600 | foreach (string origWlUrl in whitelist) | 603 | foreach (string origWlUrl in whitelist) |
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs index 03a96a4..ee57aed 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs | |||
@@ -39,7 +39,6 @@ using OpenSim.Region.CoreModules.World.Media.Moap; | |||
39 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Region.Framework.Scenes.Serialization; | 40 | using OpenSim.Region.Framework.Scenes.Serialization; |
41 | using OpenSim.Tests.Common; | 41 | using OpenSim.Tests.Common; |
42 | using OpenSim.Tests.Common.Mock; | ||
43 | 42 | ||
44 | namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests | 43 | namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests |
45 | { | 44 | { |
diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs index 1e4f0a4..2abc910 100644 --- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs | |||
@@ -38,6 +38,7 @@ using OpenSim.Region.Framework; | |||
38 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Region.Framework.Scenes.Serialization; | 40 | using OpenSim.Region.Framework.Scenes.Serialization; |
41 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
41 | 42 | ||
42 | namespace OpenSim.Region.CoreModules.World.Objects.BuySell | 43 | namespace OpenSim.Region.CoreModules.World.Objects.BuySell |
43 | { | 44 | { |
@@ -140,6 +141,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell | |||
140 | 141 | ||
141 | part.ObjectSaleType = 0; | 142 | part.ObjectSaleType = 0; |
142 | part.SalePrice = 10; | 143 | part.SalePrice = 10; |
144 | part.ClickAction = Convert.ToByte(0); | ||
143 | 145 | ||
144 | group.HasGroupChanged = true; | 146 | group.HasGroupChanged = true; |
145 | part.SendPropertiesToClient(remoteClient); | 147 | part.SendPropertiesToClient(remoteClient); |
@@ -150,14 +152,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell | |||
150 | break; | 152 | break; |
151 | 153 | ||
152 | case 2: // Sell a copy | 154 | case 2: // Sell a copy |
153 | Vector3 inventoryStoredPosition = new Vector3 | 155 | Vector3 inventoryStoredPosition = new Vector3( |
154 | (((group.AbsolutePosition.X > (int)Constants.RegionSize) | 156 | Math.Min(group.AbsolutePosition.X, m_scene.RegionInfo.RegionSizeX - 6), |
155 | ? 250 | 157 | Math.Min(group.AbsolutePosition.Y, m_scene.RegionInfo.RegionSizeY - 6), |
156 | : group.AbsolutePosition.X) | ||
157 | , | ||
158 | (group.AbsolutePosition.X > (int)Constants.RegionSize) | ||
159 | ? 250 | ||
160 | : group.AbsolutePosition.X, | ||
161 | group.AbsolutePosition.Z); | 158 | group.AbsolutePosition.Z); |
162 | 159 | ||
163 | Vector3 originalPosition = group.AbsolutePosition; | 160 | Vector3 originalPosition = group.AbsolutePosition; |
@@ -197,13 +194,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell | |||
197 | item.InvType = (int)InventoryType.Object; | 194 | item.InvType = (int)InventoryType.Object; |
198 | item.Folder = categoryID; | 195 | item.Folder = categoryID; |
199 | 196 | ||
200 | uint nextPerms=(perms & 7) << 13; | 197 | PermissionsUtil.ApplyFoldedPermissions(perms, ref perms); |
201 | if ((nextPerms & (uint)PermissionMask.Copy) == 0) | ||
202 | perms &= ~(uint)PermissionMask.Copy; | ||
203 | if ((nextPerms & (uint)PermissionMask.Transfer) == 0) | ||
204 | perms &= ~(uint)PermissionMask.Transfer; | ||
205 | if ((nextPerms & (uint)PermissionMask.Modify) == 0) | ||
206 | perms &= ~(uint)PermissionMask.Modify; | ||
207 | 198 | ||
208 | item.BasePermissions = perms & part.NextOwnerMask; | 199 | item.BasePermissions = perms & part.NextOwnerMask; |
209 | item.CurrentPermissions = perms & part.NextOwnerMask; | 200 | item.CurrentPermissions = perms & part.NextOwnerMask; |
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index 9fc2daf..e77f0aa 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs | |||
@@ -416,7 +416,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
416 | 416 | ||
417 | if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) | 417 | if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) |
418 | { | 418 | { |
419 | m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); | 419 | m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector); |
420 | return; | 420 | return; |
421 | } | 421 | } |
422 | 422 | ||
@@ -425,7 +425,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
425 | 425 | ||
426 | if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) | 426 | if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) |
427 | { | 427 | { |
428 | m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); | 428 | m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector); |
429 | return; | 429 | return; |
430 | } | 430 | } |
431 | 431 | ||
@@ -546,7 +546,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
546 | { | 546 | { |
547 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | 547 | ConsoleDisplayList cdl = new ConsoleDisplayList(); |
548 | cdl.AddRow("Name", so.Name); | 548 | cdl.AddRow("Name", so.Name); |
549 | cdl.AddRow("Descrition", so.Description); | 549 | cdl.AddRow("Description", so.Description); |
550 | cdl.AddRow("Local ID", so.LocalId); | 550 | cdl.AddRow("Local ID", so.LocalId); |
551 | cdl.AddRow("UUID", so.UUID); | 551 | cdl.AddRow("UUID", so.UUID); |
552 | cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name)); | 552 | cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name)); |
@@ -597,6 +597,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
597 | cdl.AddRow("LightFalloff", s.LightFalloff); | 597 | cdl.AddRow("LightFalloff", s.LightFalloff); |
598 | cdl.AddRow("LightIntensity", s.LightIntensity); | 598 | cdl.AddRow("LightIntensity", s.LightIntensity); |
599 | cdl.AddRow("LightRadius", s.LightRadius); | 599 | cdl.AddRow("LightRadius", s.LightRadius); |
600 | cdl.AddRow("Location (relative)", sop.RelativePosition); | ||
600 | cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); | 601 | cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); |
601 | cdl.AddRow("PathBegin", s.PathBegin); | 602 | cdl.AddRow("PathBegin", s.PathBegin); |
602 | cdl.AddRow("PathEnd", s.PathEnd); | 603 | cdl.AddRow("PathEnd", s.PathEnd); |
@@ -619,6 +620,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
619 | cdl.AddRow("ProjectionFocus", s.ProjectionFocus); | 620 | cdl.AddRow("ProjectionFocus", s.ProjectionFocus); |
620 | cdl.AddRow("ProjectionFOV", s.ProjectionFOV); | 621 | cdl.AddRow("ProjectionFOV", s.ProjectionFOV); |
621 | cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); | 622 | cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); |
623 | cdl.AddRow("Rotation (Relative)", sop.RotationOffset); | ||
624 | cdl.AddRow("Rotation (World)", sop.GetWorldRotation()); | ||
622 | cdl.AddRow("Scale", s.Scale); | 625 | cdl.AddRow("Scale", s.Scale); |
623 | cdl.AddRow( | 626 | cdl.AddRow( |
624 | "SculptData", | 627 | "SculptData", |
@@ -628,7 +631,22 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
628 | cdl.AddRow("SculptType", s.SculptType); | 631 | cdl.AddRow("SculptType", s.SculptType); |
629 | cdl.AddRow("State", s.State); | 632 | cdl.AddRow("State", s.State); |
630 | 633 | ||
631 | // TODO, unpack and display texture entries | 634 | // TODO, need to display more information about textures but in a compact format |
635 | // to stop output becoming huge. | ||
636 | for (int i = 0; i < sop.GetNumberOfSides(); i++) | ||
637 | { | ||
638 | Primitive.TextureEntryFace teFace = s.Textures.FaceTextures[i]; | ||
639 | |||
640 | UUID textureID; | ||
641 | |||
642 | if (teFace != null) | ||
643 | textureID = teFace.TextureID; | ||
644 | else | ||
645 | textureID = s.Textures.DefaultTexture.TextureID; | ||
646 | |||
647 | cdl.AddRow(string.Format("Face {0} texture ID", i), textureID); | ||
648 | } | ||
649 | |||
632 | //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures. | 650 | //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures. |
633 | } | 651 | } |
634 | 652 | ||
@@ -896,17 +914,17 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
896 | 914 | ||
897 | if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) | 915 | if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) |
898 | { | 916 | { |
899 | m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); | 917 | m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector); |
900 | endVector = Vector3.Zero; | 918 | endVector = Vector3.Zero; |
901 | 919 | ||
902 | return false; | 920 | return false; |
903 | } | 921 | } |
904 | 922 | ||
905 | string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single(); | 923 | string rawConsoleEndVector = rawComponents.Skip(2).Take(1).Single(); |
906 | 924 | ||
907 | if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) | 925 | if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) |
908 | { | 926 | { |
909 | m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); | 927 | m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector); |
910 | return false; | 928 | return false; |
911 | } | 929 | } |
912 | 930 | ||
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index ddaa227..780ec69 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
30 | using System.Reflection; | 31 | using System.Reflection; |
31 | using log4net; | 32 | using log4net; |
32 | using Nini.Config; | 33 | using Nini.Config; |
@@ -38,6 +39,7 @@ using OpenSim.Region.Framework.Scenes; | |||
38 | using OpenSim.Services.Interfaces; | 39 | using OpenSim.Services.Interfaces; |
39 | 40 | ||
40 | using Mono.Addins; | 41 | using Mono.Addins; |
42 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
41 | 43 | ||
42 | namespace OpenSim.Region.CoreModules.World.Permissions | 44 | namespace OpenSim.Region.CoreModules.World.Permissions |
43 | { | 45 | { |
@@ -156,37 +158,44 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
156 | 158 | ||
157 | public void Initialise(IConfigSource config) | 159 | public void Initialise(IConfigSource config) |
158 | { | 160 | { |
159 | IConfig myConfig = config.Configs["Startup"]; | 161 | string permissionModules = Util.GetConfigVarFromSections<string>(config, "permissionmodules", |
162 | new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule"); | ||
160 | 163 | ||
161 | string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule"); | 164 | List<string> modules = new List<string>(permissionModules.Split(',').Select(m => m.Trim())); |
162 | |||
163 | List<string> modules = new List<string>(permissionModules.Split(',')); | ||
164 | 165 | ||
165 | if (!modules.Contains("DefaultPermissionsModule")) | 166 | if (!modules.Contains("DefaultPermissionsModule")) |
166 | return; | 167 | return; |
167 | 168 | ||
168 | m_Enabled = true; | 169 | m_Enabled = true; |
169 | 170 | ||
170 | m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false); | 171 | m_allowGridGods = Util.GetConfigVarFromSections<bool>(config, "allow_grid_gods", |
171 | m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true); | 172 | new string[] { "Startup", "Permissions" }, false); |
172 | m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true); | 173 | m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(config, "serverside_object_permissions", |
173 | m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true); | 174 | new string[] { "Startup", "Permissions" }, true); |
174 | m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false); | 175 | m_propagatePermissions = Util.GetConfigVarFromSections<bool>(config, "propagate_permissions", |
175 | m_ParcelOwnerIsGod = myConfig.GetBoolean("parcel_owner_is_god", true); | 176 | new string[] { "Startup", "Permissions" }, true); |
176 | 177 | m_RegionOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_owner_is_god", | |
177 | m_SimpleBuildPermissions = myConfig.GetBoolean("simple_build_permissions", false); | 178 | new string[] { "Startup", "Permissions" }, true); |
179 | m_RegionManagerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_manager_is_god", | ||
180 | new string[] { "Startup", "Permissions" }, false); | ||
181 | m_ParcelOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "parcel_owner_is_god", | ||
182 | new string[] { "Startup", "Permissions" }, true); | ||
183 | |||
184 | m_SimpleBuildPermissions = Util.GetConfigVarFromSections<bool>(config, "simple_build_permissions", | ||
185 | new string[] { "Startup", "Permissions" }, false); | ||
178 | 186 | ||
179 | m_allowedScriptCreators | 187 | m_allowedScriptCreators |
180 | = ParseUserSetConfigSetting(myConfig, "allowed_script_creators", m_allowedScriptCreators); | 188 | = ParseUserSetConfigSetting(config, "allowed_script_creators", m_allowedScriptCreators); |
181 | m_allowedScriptEditors | 189 | m_allowedScriptEditors |
182 | = ParseUserSetConfigSetting(myConfig, "allowed_script_editors", m_allowedScriptEditors); | 190 | = ParseUserSetConfigSetting(config, "allowed_script_editors", m_allowedScriptEditors); |
183 | 191 | ||
184 | if (m_bypassPermissions) | 192 | if (m_bypassPermissions) |
185 | m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks"); | 193 | m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks"); |
186 | else | 194 | else |
187 | m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); | 195 | m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); |
188 | 196 | ||
189 | string grant = myConfig.GetString("GrantLSL", ""); | 197 | string grant = Util.GetConfigVarFromSections<string>(config, "GrantLSL", |
198 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
190 | if (grant.Length > 0) | 199 | if (grant.Length > 0) |
191 | { | 200 | { |
192 | foreach (string uuidl in grant.Split(',')) | 201 | foreach (string uuidl in grant.Split(',')) |
@@ -196,7 +205,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
196 | } | 205 | } |
197 | } | 206 | } |
198 | 207 | ||
199 | grant = myConfig.GetString("GrantCS", ""); | 208 | grant = Util.GetConfigVarFromSections<string>(config, "GrantCS", |
209 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
200 | if (grant.Length > 0) | 210 | if (grant.Length > 0) |
201 | { | 211 | { |
202 | foreach (string uuidl in grant.Split(',')) | 212 | foreach (string uuidl in grant.Split(',')) |
@@ -206,7 +216,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
206 | } | 216 | } |
207 | } | 217 | } |
208 | 218 | ||
209 | grant = myConfig.GetString("GrantVB", ""); | 219 | grant = Util.GetConfigVarFromSections<string>(config, "GrantVB", |
220 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
210 | if (grant.Length > 0) | 221 | if (grant.Length > 0) |
211 | { | 222 | { |
212 | foreach (string uuidl in grant.Split(',')) | 223 | foreach (string uuidl in grant.Split(',')) |
@@ -216,7 +227,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
216 | } | 227 | } |
217 | } | 228 | } |
218 | 229 | ||
219 | grant = myConfig.GetString("GrantJS", ""); | 230 | grant = Util.GetConfigVarFromSections<string>(config, "GrantJS", |
231 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
220 | if (grant.Length > 0) | 232 | if (grant.Length > 0) |
221 | { | 233 | { |
222 | foreach (string uuidl in grant.Split(',')) | 234 | foreach (string uuidl in grant.Split(',')) |
@@ -226,7 +238,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
226 | } | 238 | } |
227 | } | 239 | } |
228 | 240 | ||
229 | grant = myConfig.GetString("GrantYP", ""); | 241 | grant = Util.GetConfigVarFromSections<string>(config, "GrantYP", |
242 | new string[] { "Startup", "Permissions" }, string.Empty); | ||
230 | if (grant.Length > 0) | 243 | if (grant.Length > 0) |
231 | { | 244 | { |
232 | foreach (string uuidl in grant.Split(',')) | 245 | foreach (string uuidl in grant.Split(',')) |
@@ -456,7 +469,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
456 | 469 | ||
457 | return false; | 470 | return false; |
458 | } | 471 | } |
459 | 472 | ||
460 | /// <summary> | 473 | /// <summary> |
461 | /// Parse a user set configuration setting | 474 | /// Parse a user set configuration setting |
462 | /// </summary> | 475 | /// </summary> |
@@ -464,11 +477,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
464 | /// <param name="settingName"></param> | 477 | /// <param name="settingName"></param> |
465 | /// <param name="defaultValue">The default value for this attribute</param> | 478 | /// <param name="defaultValue">The default value for this attribute</param> |
466 | /// <returns>The parsed value</returns> | 479 | /// <returns>The parsed value</returns> |
467 | private static UserSet ParseUserSetConfigSetting(IConfig config, string settingName, UserSet defaultValue) | 480 | private static UserSet ParseUserSetConfigSetting(IConfigSource config, string settingName, UserSet defaultValue) |
468 | { | 481 | { |
469 | UserSet userSet = defaultValue; | 482 | UserSet userSet = defaultValue; |
470 | 483 | ||
471 | string rawSetting = config.GetString(settingName, defaultValue.ToString()); | 484 | string rawSetting = Util.GetConfigVarFromSections<string>(config, settingName, |
485 | new string[] {"Startup", "Permissions"}, defaultValue.ToString()); | ||
472 | 486 | ||
473 | // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term | 487 | // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term |
474 | // this should disappear. | 488 | // this should disappear. |
@@ -787,8 +801,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
787 | 801 | ||
788 | // Friends with benefits should be able to edit the objects too | 802 | // Friends with benefits should be able to edit the objects too |
789 | if (IsFriendWithPerms(currentUser, objectOwner)) | 803 | if (IsFriendWithPerms(currentUser, objectOwner)) |
804 | { | ||
790 | // Return immediately, so that the administrator can share objects with friends | 805 | // Return immediately, so that the administrator can share objects with friends |
791 | return true; | 806 | return true; |
807 | } | ||
792 | 808 | ||
793 | // Users should be able to edit what is over their land. | 809 | // Users should be able to edit what is over their land. |
794 | ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y); | 810 | ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y); |
@@ -887,7 +903,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
887 | return permission; | 903 | return permission; |
888 | } | 904 | } |
889 | 905 | ||
890 | protected bool GenericParcelOwnerPermission(UUID user, ILandObject parcel, ulong groupPowers) | 906 | protected bool GenericParcelOwnerPermission(UUID user, ILandObject parcel, ulong groupPowers, bool allowEstateManager) |
891 | { | 907 | { |
892 | if (parcel.LandData.OwnerID == user) | 908 | if (parcel.LandData.OwnerID == user) |
893 | { | 909 | { |
@@ -902,7 +918,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
902 | return true; | 918 | return true; |
903 | } | 919 | } |
904 | 920 | ||
905 | if (IsEstateManager(user)) | 921 | if (allowEstateManager && IsEstateManager(user)) |
906 | { | 922 | { |
907 | return true; | 923 | return true; |
908 | } | 924 | } |
@@ -929,7 +945,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
929 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); | 945 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); |
930 | if (m_bypassPermissions) return m_bypassPermissionsValue; | 946 | if (m_bypassPermissions) return m_bypassPermissionsValue; |
931 | 947 | ||
932 | return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandRelease); | 948 | return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandRelease, false); |
933 | } | 949 | } |
934 | 950 | ||
935 | private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene) | 951 | private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene) |
@@ -937,7 +953,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
937 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); | 953 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); |
938 | if (m_bypassPermissions) return m_bypassPermissionsValue; | 954 | if (m_bypassPermissions) return m_bypassPermissionsValue; |
939 | 955 | ||
940 | return GenericParcelOwnerPermission(user, parcel, 0); | 956 | return GenericParcelOwnerPermission(user, parcel, 0,true); |
941 | } | 957 | } |
942 | 958 | ||
943 | private bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene) | 959 | private bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene) |
@@ -954,7 +970,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
954 | if ((client.GetGroupPowers(parcel.LandData.GroupID) & (ulong)GroupPowers.LandDeed) == 0) | 970 | if ((client.GetGroupPowers(parcel.LandData.GroupID) & (ulong)GroupPowers.LandDeed) == 0) |
955 | return false; | 971 | return false; |
956 | 972 | ||
957 | return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDeed); | 973 | return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDeed, false); |
958 | } | 974 | } |
959 | 975 | ||
960 | private bool CanDeedObject(UUID user, UUID group, Scene scene) | 976 | private bool CanDeedObject(UUID user, UUID group, Scene scene) |
@@ -995,9 +1011,11 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
995 | return false; | 1011 | return false; |
996 | 1012 | ||
997 | if (part.OwnerID == owner) | 1013 | if (part.OwnerID == owner) |
998 | return ((part.OwnerMask & PERM_COPY) != 0); | 1014 | { |
999 | 1015 | if ((part.OwnerMask & PERM_COPY) == 0) | |
1000 | if (part.GroupID != UUID.Zero) | 1016 | return false; |
1017 | } | ||
1018 | else if (part.GroupID != UUID.Zero) | ||
1001 | { | 1019 | { |
1002 | if ((part.OwnerID == part.GroupID) && ((owner != part.LastOwnerID) || ((part.GroupMask & PERM_TRANS) == 0))) | 1020 | if ((part.OwnerID == part.GroupID) && ((owner != part.LastOwnerID) || ((part.GroupMask & PERM_TRANS) == 0))) |
1003 | return false; | 1021 | return false; |
@@ -1039,7 +1057,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1039 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); | 1057 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); |
1040 | if (m_bypassPermissions) return m_bypassPermissionsValue; | 1058 | if (m_bypassPermissions) return m_bypassPermissionsValue; |
1041 | 1059 | ||
1042 | return GenericParcelOwnerPermission(user, parcel, (ulong)p); | 1060 | return GenericParcelOwnerPermission(user, parcel, (ulong)p, false); |
1043 | } | 1061 | } |
1044 | 1062 | ||
1045 | /// <summary> | 1063 | /// <summary> |
@@ -1438,27 +1456,33 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1438 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); | 1456 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); |
1439 | if (m_bypassPermissions) return m_bypassPermissionsValue; | 1457 | if (m_bypassPermissions) return m_bypassPermissionsValue; |
1440 | 1458 | ||
1441 | bool permission = false; | 1459 | // m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name); |
1442 | |||
1443 | ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); | ||
1444 | if (land == null) return false; | ||
1445 | 1460 | ||
1446 | if ((land.LandData.Flags & ((int)ParcelFlags.CreateObjects)) == | 1461 | ILandObject parcel = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); |
1447 | (int)ParcelFlags.CreateObjects) | 1462 | if (parcel == null) |
1448 | permission = true; | 1463 | return false; |
1449 | 1464 | ||
1450 | if (IsAdministrator(owner)) | 1465 | if ((parcel.LandData.Flags & (uint)ParcelFlags.CreateObjects) != 0) |
1451 | { | 1466 | { |
1452 | permission = true; | 1467 | return true; |
1453 | } | 1468 | } |
1454 | 1469 | else if ((owner == parcel.LandData.OwnerID) || IsAdministrator(owner)) | |
1455 | // Powers are zero, because GroupPowers.AllowRez is not a precondition for rezzing objects | ||
1456 | if (GenericParcelPermission(owner, objectPosition, 0)) | ||
1457 | { | 1470 | { |
1458 | permission = true; | 1471 | return true; |
1472 | } | ||
1473 | else if (((parcel.LandData.Flags & (uint)ParcelFlags.CreateGroupObjects) != 0) | ||
1474 | && (parcel.LandData.GroupID != UUID.Zero) && IsGroupMember(parcel.LandData.GroupID, owner, 0)) | ||
1475 | { | ||
1476 | return true; | ||
1477 | } | ||
1478 | else if (parcel.LandData.GroupID != UUID.Zero && IsGroupMember(parcel.LandData.GroupID, owner, (ulong)GroupPowers.AllowRez)) | ||
1479 | { | ||
1480 | return true; | ||
1481 | } | ||
1482 | else | ||
1483 | { | ||
1484 | return false; | ||
1459 | } | 1485 | } |
1460 | |||
1461 | return permission; | ||
1462 | } | 1486 | } |
1463 | 1487 | ||
1464 | private bool CanRunConsoleCommand(UUID user, Scene requestFromScene) | 1488 | private bool CanRunConsoleCommand(UUID user, Scene requestFromScene) |
@@ -1483,7 +1507,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1483 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); | 1507 | DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); |
1484 | if (m_bypassPermissions) return m_bypassPermissionsValue; | 1508 | if (m_bypassPermissions) return m_bypassPermissionsValue; |
1485 | 1509 | ||
1486 | return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale); | 1510 | return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale, false); |
1487 | } | 1511 | } |
1488 | 1512 | ||
1489 | private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) | 1513 | private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) |
@@ -1500,6 +1524,9 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1500 | if (m_bypassPermissions) return m_bypassPermissionsValue; | 1524 | if (m_bypassPermissions) return m_bypassPermissionsValue; |
1501 | 1525 | ||
1502 | bool permission = GenericObjectPermission(userID, objectID, false); | 1526 | bool permission = GenericObjectPermission(userID, objectID, false); |
1527 | |||
1528 | SceneObjectGroup so = (SceneObjectGroup)m_scene.Entities[objectID]; | ||
1529 | |||
1503 | if (!permission) | 1530 | if (!permission) |
1504 | { | 1531 | { |
1505 | if (!m_scene.Entities.ContainsKey(objectID)) | 1532 | if (!m_scene.Entities.ContainsKey(objectID)) |
@@ -1513,31 +1540,23 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1513 | return false; | 1540 | return false; |
1514 | } | 1541 | } |
1515 | 1542 | ||
1516 | SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID]; | ||
1517 | // UUID taskOwner = null; | 1543 | // UUID taskOwner = null; |
1518 | // Added this because at this point in time it wouldn't be wise for | 1544 | // Added this because at this point in time it wouldn't be wise for |
1519 | // the administrator object permissions to take effect. | 1545 | // the administrator object permissions to take effect. |
1520 | // UUID objectOwner = task.OwnerID; | 1546 | // UUID objectOwner = task.OwnerID; |
1521 | 1547 | ||
1522 | if ((task.RootPart.EveryoneMask & PERM_COPY) != 0) | 1548 | if ((so.RootPart.EveryoneMask & PERM_COPY) != 0) |
1523 | permission = true; | 1549 | permission = true; |
1550 | } | ||
1524 | 1551 | ||
1525 | if (task.OwnerID != userID) | 1552 | if (so.OwnerID != userID) |
1526 | { | 1553 | { |
1527 | if ((task.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS)) | 1554 | if ((so.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS)) |
1528 | permission = false; | 1555 | permission = false; |
1529 | } | ||
1530 | else | ||
1531 | { | ||
1532 | if ((task.GetEffectivePermissions() & PERM_COPY) != PERM_COPY) | ||
1533 | permission = false; | ||
1534 | } | ||
1535 | } | 1556 | } |
1536 | else | 1557 | else |
1537 | { | 1558 | { |
1538 | SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID]; | 1559 | if ((so.GetEffectivePermissions() & PERM_COPY) != PERM_COPY) |
1539 | |||
1540 | if ((task.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS)) | ||
1541 | permission = false; | 1560 | permission = false; |
1542 | } | 1561 | } |
1543 | 1562 | ||
@@ -1556,10 +1575,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1556 | float X = position.X; | 1575 | float X = position.X; |
1557 | float Y = position.Y; | 1576 | float Y = position.Y; |
1558 | 1577 | ||
1559 | if (X > ((int)Constants.RegionSize - 1)) | 1578 | if (X > ((int)m_scene.RegionInfo.RegionSizeX - 1)) |
1560 | X = ((int)Constants.RegionSize - 1); | 1579 | X = ((int)m_scene.RegionInfo.RegionSizeX - 1); |
1561 | if (Y > ((int)Constants.RegionSize - 1)) | 1580 | if (Y > ((int)m_scene.RegionInfo.RegionSizeY - 1)) |
1562 | Y = ((int)Constants.RegionSize - 1); | 1581 | Y = ((int)m_scene.RegionInfo.RegionSizeY - 1); |
1563 | if (X < 0) | 1582 | if (X < 0) |
1564 | X = 0; | 1583 | X = 0; |
1565 | if (Y < 0) | 1584 | if (Y < 0) |
diff --git a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs index 7d35473..bb4dcce 100644 --- a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs | |||
@@ -81,7 +81,32 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
81 | m_console.Commands.AddCommand( | 81 | m_console.Commands.AddCommand( |
82 | "Regions", false, "show scene", | 82 | "Regions", false, "show scene", |
83 | "show scene", | 83 | "show scene", |
84 | "Show live scene information for the currently selected region.", HandleShowScene); | 84 | "Show live information for the currently selected scene (fps, prims, etc.).", HandleShowScene); |
85 | |||
86 | m_console.Commands.AddCommand( | ||
87 | "Regions", false, "show region", | ||
88 | "show region", | ||
89 | "Show control information for the currently selected region (host name, max physical prim size, etc).", | ||
90 | "A synonym for \"region get\"", | ||
91 | HandleShowRegion); | ||
92 | |||
93 | m_console.Commands.AddCommand( | ||
94 | "Regions", false, "region get", | ||
95 | "region get", | ||
96 | "Show control information for the currently selected region (host name, max physical prim size, etc).", | ||
97 | "Some parameters can be set with the \"region set\" command.\n" | ||
98 | + "Others must be changed via a viewer (usually via the region/estate dialog box).", | ||
99 | HandleShowRegion); | ||
100 | |||
101 | m_console.Commands.AddCommand( | ||
102 | "Regions", false, "region set", | ||
103 | "region set", | ||
104 | "Set control information for the currently selected region.", | ||
105 | "Currently, the following parameters can be set:\n" | ||
106 | + "agent-limit <int> - Current root agent limit. This is persisted over restart.\n" | ||
107 | + "max-agent-limit <int> - Maximum root agent limit. agent-limit cannot exceed this." | ||
108 | + " This is not persisted over restart - to set it every time you must add a MaxAgents entry to your regions file.", | ||
109 | HandleRegionSet); | ||
85 | } | 110 | } |
86 | 111 | ||
87 | public void RemoveRegion(Scene scene) | 112 | public void RemoveRegion(Scene scene) |
@@ -94,6 +119,139 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
94 | // m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); | 119 | // m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); |
95 | } | 120 | } |
96 | 121 | ||
122 | private void HandleShowRegion(string module, string[] cmd) | ||
123 | { | ||
124 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) | ||
125 | return; | ||
126 | |||
127 | RegionInfo ri = m_scene.RegionInfo; | ||
128 | RegionSettings rs = ri.RegionSettings; | ||
129 | |||
130 | StringBuilder sb = new StringBuilder(); | ||
131 | sb.AppendFormat("Region information for {0}\n", m_scene.Name); | ||
132 | |||
133 | ConsoleDisplayList dispList = new ConsoleDisplayList(); | ||
134 | dispList.AddRow("Region ID", ri.RegionID); | ||
135 | dispList.AddRow("Region handle", ri.RegionHandle); | ||
136 | dispList.AddRow("Region location", string.Format("{0},{1}", ri.RegionLocX, ri.RegionLocY)); | ||
137 | dispList.AddRow("Region size", string.Format("{0}x{1}", ri.RegionSizeX, ri.RegionSizeY)); | ||
138 | //dispList.AddRow("Region type", ri.RegionType); | ||
139 | dispList.AddRow("Maturity", rs.Maturity); | ||
140 | dispList.AddRow("Region address", ri.ServerURI); | ||
141 | dispList.AddRow("From region file", ri.RegionFile); | ||
142 | dispList.AddRow("External endpoint", ri.ExternalEndPoint); | ||
143 | dispList.AddRow("Internal endpoint", ri.InternalEndPoint); | ||
144 | dispList.AddRow("Access level", ri.AccessLevel); | ||
145 | dispList.AddRow("Agent limit", rs.AgentLimit); | ||
146 | dispList.AddRow("Max agent limit", ri.AgentCapacity); | ||
147 | dispList.AddRow("Linkset capacity", ri.LinksetCapacity <= 0 ? "not set" : ri.LinksetCapacity.ToString()); | ||
148 | dispList.AddRow("Prim capacity", ri.ObjectCapacity); | ||
149 | dispList.AddRow("Prim bonus", rs.ObjectBonus); | ||
150 | dispList.AddRow("Max prims per user", ri.MaxPrimsPerUser < 0 ? "n/a" : ri.MaxPrimsPerUser.ToString()); | ||
151 | dispList.AddRow("Clamp prim size", ri.ClampPrimSize); | ||
152 | dispList.AddRow("Non physical prim min size", ri.NonphysPrimMin <= 0 ? "not set" : string.Format("{0} m", ri.NonphysPrimMin)); | ||
153 | dispList.AddRow("Non physical prim max size", ri.NonphysPrimMax <= 0 ? "not set" : string.Format("{0} m", ri.NonphysPrimMax)); | ||
154 | dispList.AddRow("Physical prim min size", ri.PhysPrimMin <= 0 ? "not set" : string.Format("{0} m", ri.PhysPrimMin)); | ||
155 | dispList.AddRow("Physical prim max size", ri.PhysPrimMax <= 0 ? "not set" : string.Format("{0} m", ri.PhysPrimMax)); | ||
156 | |||
157 | dispList.AddRow("Allow Damage", rs.AllowDamage); | ||
158 | dispList.AddRow("Allow Land join/divide", rs.AllowLandJoinDivide); | ||
159 | dispList.AddRow("Allow land resell", rs.AllowLandResell); | ||
160 | dispList.AddRow("Block fly", rs.BlockFly); | ||
161 | dispList.AddRow("Block show in search", rs.BlockShowInSearch); | ||
162 | dispList.AddRow("Block terraform", rs.BlockTerraform); | ||
163 | dispList.AddRow("Covenant UUID", rs.Covenant); | ||
164 | dispList.AddRow("Convenant change Unix time", rs.CovenantChangedDateTime); | ||
165 | dispList.AddRow("Disable collisions", rs.DisableCollisions); | ||
166 | dispList.AddRow("Disable physics", rs.DisablePhysics); | ||
167 | dispList.AddRow("Disable scripts", rs.DisableScripts); | ||
168 | dispList.AddRow("Restrict pushing", rs.RestrictPushing); | ||
169 | dispList.AddRow("Fixed sun", rs.FixedSun); | ||
170 | dispList.AddRow("Sun position", rs.SunPosition); | ||
171 | dispList.AddRow("Sun vector", rs.SunVector); | ||
172 | dispList.AddRow("Use estate sun", rs.UseEstateSun); | ||
173 | dispList.AddRow("Telehub UUID", rs.TelehubObject); | ||
174 | dispList.AddRow("Terrain lower limit", string.Format("{0} m", rs.TerrainLowerLimit)); | ||
175 | dispList.AddRow("Terrain raise limit", string.Format("{0} m", rs.TerrainRaiseLimit)); | ||
176 | dispList.AddRow("Water height", string.Format("{0} m", rs.WaterHeight)); | ||
177 | |||
178 | dispList.AddRow("Maptile static file", ri.MaptileStaticFile); | ||
179 | dispList.AddRow("Maptile static UUID", ri.MaptileStaticUUID); | ||
180 | dispList.AddRow("Last map refresh", ri.lastMapRefresh); | ||
181 | dispList.AddRow("Last map UUID", ri.lastMapUUID); | ||
182 | |||
183 | dispList.AddToStringBuilder(sb); | ||
184 | |||
185 | MainConsole.Instance.Output(sb.ToString()); | ||
186 | } | ||
187 | |||
188 | private void HandleRegionSet(string module, string[] args) | ||
189 | { | ||
190 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) | ||
191 | return; | ||
192 | |||
193 | if (args.Length != 4) | ||
194 | { | ||
195 | MainConsole.Instance.OutputFormat("Usage: region set <param> <value>"); | ||
196 | return; | ||
197 | } | ||
198 | |||
199 | string param = args[2]; | ||
200 | string rawValue = args[3]; | ||
201 | |||
202 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) | ||
203 | return; | ||
204 | |||
205 | RegionInfo ri = m_scene.RegionInfo; | ||
206 | RegionSettings rs = ri.RegionSettings; | ||
207 | |||
208 | if (param == "agent-limit") | ||
209 | { | ||
210 | int newValue; | ||
211 | |||
212 | if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, rawValue, out newValue)) | ||
213 | return; | ||
214 | |||
215 | if (newValue > ri.AgentCapacity) | ||
216 | { | ||
217 | MainConsole.Instance.OutputFormat( | ||
218 | "Cannot set {0} to {1} in {2} as max-agent-limit is {3}", "agent-limit", | ||
219 | newValue, m_scene.Name, ri.AgentCapacity); | ||
220 | } | ||
221 | else | ||
222 | { | ||
223 | rs.AgentLimit = newValue; | ||
224 | |||
225 | MainConsole.Instance.OutputFormat( | ||
226 | "{0} set to {1} in {2}", "agent-limit", newValue, m_scene.Name); | ||
227 | } | ||
228 | |||
229 | rs.Save(); | ||
230 | } | ||
231 | else if (param == "max-agent-limit") | ||
232 | { | ||
233 | int newValue; | ||
234 | |||
235 | if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, rawValue, out newValue)) | ||
236 | return; | ||
237 | |||
238 | ri.AgentCapacity = newValue; | ||
239 | |||
240 | MainConsole.Instance.OutputFormat( | ||
241 | "{0} set to {1} in {2}", "max-agent-limit", newValue, m_scene.Name); | ||
242 | |||
243 | if (ri.AgentCapacity < rs.AgentLimit) | ||
244 | { | ||
245 | rs.AgentLimit = ri.AgentCapacity; | ||
246 | |||
247 | MainConsole.Instance.OutputFormat( | ||
248 | "Reducing {0} to {1} in {2}", "agent-limit", rs.AgentLimit, m_scene.Name); | ||
249 | } | ||
250 | |||
251 | rs.Save(); | ||
252 | } | ||
253 | } | ||
254 | |||
97 | private void HandleShowScene(string module, string[] cmd) | 255 | private void HandleShowScene(string module, string[] cmd) |
98 | { | 256 | { |
99 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) | 257 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) |
diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs index 249a40d..75a8295 100644 --- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs +++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs | |||
@@ -46,8 +46,8 @@ namespace OpenSim.Region.CoreModules.World.Region | |||
46 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")] | 46 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")] |
47 | public class RestartModule : INonSharedRegionModule, IRestartModule | 47 | public class RestartModule : INonSharedRegionModule, IRestartModule |
48 | { | 48 | { |
49 | // private static readonly ILog m_log = | 49 | private static readonly ILog m_log = |
50 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 50 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
51 | 51 | ||
52 | protected Scene m_Scene; | 52 | protected Scene m_Scene; |
53 | protected Timer m_CountdownTimer = null; | 53 | protected Timer m_CountdownTimer = null; |
@@ -203,18 +203,30 @@ namespace OpenSim.Region.CoreModules.World.Region | |||
203 | 203 | ||
204 | public void SetTimer(int intervalSeconds) | 204 | public void SetTimer(int intervalSeconds) |
205 | { | 205 | { |
206 | m_CountdownTimer = new Timer(); | 206 | if (intervalSeconds > 0) |
207 | m_CountdownTimer.AutoReset = false; | 207 | { |
208 | m_CountdownTimer.Interval = intervalSeconds * 1000; | 208 | m_CountdownTimer = new Timer(); |
209 | m_CountdownTimer.Elapsed += OnTimer; | 209 | m_CountdownTimer.AutoReset = false; |
210 | m_CountdownTimer.Start(); | 210 | m_CountdownTimer.Interval = intervalSeconds * 1000; |
211 | m_CountdownTimer.Elapsed += OnTimer; | ||
212 | m_CountdownTimer.Start(); | ||
213 | } | ||
214 | else if (m_CountdownTimer != null) | ||
215 | { | ||
216 | m_CountdownTimer.Stop(); | ||
217 | m_CountdownTimer = null; | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | m_log.WarnFormat( | ||
222 | "[RESTART MODULE]: Tried to set restart timer to {0} in {1}, which is not a valid interval", | ||
223 | intervalSeconds, m_Scene.Name); | ||
224 | } | ||
211 | } | 225 | } |
212 | 226 | ||
213 | private void OnTimer(object source, ElapsedEventArgs e) | 227 | private void OnTimer(object source, ElapsedEventArgs e) |
214 | { | 228 | { |
215 | int nextInterval = DoOneNotice(); | 229 | SetTimer(DoOneNotice()); |
216 | |||
217 | SetTimer(nextInterval); | ||
218 | } | 230 | } |
219 | 231 | ||
220 | public void AbortRestart(string message) | 232 | public void AbortRestart(string message) |
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs index 328fbf0..65f464a 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs | |||
@@ -54,13 +54,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser | |||
54 | { | 54 | { |
55 | string xmlstream = GetObjectXml(scene); | 55 | string xmlstream = GetObjectXml(scene); |
56 | 56 | ||
57 | MemoryStream stream = ReformatXmlString(xmlstream); | 57 | using (MemoryStream stream = ReformatXmlString(xmlstream)) |
58 | 58 | { | |
59 | stream.Seek(0, SeekOrigin.Begin); | 59 | stream.Seek(0, SeekOrigin.Begin); |
60 | CreateXmlFile(stream, fileName); | 60 | CreateXmlFile(stream, fileName); |
61 | 61 | ||
62 | stream.Seek(0, SeekOrigin.Begin); | 62 | stream.Seek(0, SeekOrigin.Begin); |
63 | CreateCompressedXmlFile(stream, fileName); | 63 | CreateCompressedXmlFile(stream, fileName); |
64 | } | ||
64 | } | 65 | } |
65 | 66 | ||
66 | private static MemoryStream ReformatXmlString(string xmlstream) | 67 | private static MemoryStream ReformatXmlString(string xmlstream) |
@@ -112,13 +113,16 @@ namespace OpenSim.Region.CoreModules.World.Serialiser | |||
112 | { | 113 | { |
113 | #region GZip Compressed Version | 114 | #region GZip Compressed Version |
114 | 115 | ||
115 | FileStream objectsFileCompressed = new FileStream(fileName + ".gzs", FileMode.Create); | 116 | using (FileStream objectsFileCompressed = new FileStream(fileName + ".gzs", FileMode.Create)) |
116 | MemoryStream gzipMSStream = new MemoryStream(); | 117 | using (MemoryStream gzipMSStream = new MemoryStream()) |
117 | GZipStream gzipStream = new GZipStream(gzipMSStream, CompressionMode.Compress); | 118 | { |
118 | xmlStream.WriteTo(gzipStream); | 119 | using (GZipStream gzipStream = new GZipStream(gzipMSStream, CompressionMode.Compress, true)) |
119 | gzipMSStream.WriteTo(objectsFileCompressed); | 120 | { |
120 | objectsFileCompressed.Flush(); | 121 | xmlStream.WriteTo(gzipStream); |
121 | objectsFileCompressed.Close(); | 122 | } |
123 | |||
124 | gzipMSStream.WriteTo(objectsFileCompressed); | ||
125 | } | ||
122 | 126 | ||
123 | #endregion | 127 | #endregion |
124 | } | 128 | } |
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs index bcb8e2f..a5bb1a7 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.IO; | 29 | using System.IO; |
30 | using System.Text; | ||
30 | using System.Xml; | 31 | using System.Xml; |
31 | using log4net.Config; | 32 | using log4net.Config; |
32 | using NUnit.Framework; | 33 | using NUnit.Framework; |
@@ -35,120 +36,358 @@ using OpenSim.Framework; | |||
35 | using OpenSim.Region.Framework.Scenes; | 36 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Region.Framework.Scenes.Serialization; | 37 | using OpenSim.Region.Framework.Scenes.Serialization; |
37 | using OpenSim.Tests.Common; | 38 | using OpenSim.Tests.Common; |
39 | using OpenMetaverse.StructuredData; | ||
38 | 40 | ||
39 | namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | 41 | namespace OpenSim.Region.CoreModules.World.Serialiser.Tests |
40 | { | 42 | { |
41 | [TestFixture] | 43 | [TestFixture] |
42 | public class SerialiserTests : OpenSimTestCase | 44 | public class SerialiserTests : OpenSimTestCase |
43 | { | 45 | { |
44 | private string xml = @" | 46 | private const string ObjectRootPartStubXml = |
45 | <SceneObjectGroup> | 47 | @"<SceneObjectGroup> |
46 | <RootPart> | 48 | <RootPart> |
47 | <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> | 49 | <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> |
48 | <AllowedDrop>false</AllowedDrop> | 50 | <AllowedDrop>false</AllowedDrop> |
49 | <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID> | 51 | <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID> |
50 | <FolderID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></FolderID> | 52 | <FolderID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></FolderID> |
51 | <InventorySerial>1</InventorySerial> | 53 | <InventorySerial>1</InventorySerial> |
52 | <TaskInventory /> | 54 | <TaskInventory /> |
53 | <ObjectFlags>0</ObjectFlags> | 55 | <ObjectFlags>0</ObjectFlags> |
54 | <UUID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></UUID> | 56 | <UUID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></UUID> |
55 | <LocalId>2698615125</LocalId> | 57 | <LocalId>2698615125</LocalId> |
56 | <Name>PrimMyRide</Name> | 58 | <Name>PrimMyRide</Name> |
57 | <Material>0</Material> | 59 | <Material>0</Material> |
58 | <PassTouches>false</PassTouches> | 60 | <PassTouches>false</PassTouches> |
59 | <RegionHandle>1099511628032000</RegionHandle> | 61 | <RegionHandle>1099511628032000</RegionHandle> |
60 | <ScriptAccessPin>0</ScriptAccessPin> | 62 | <ScriptAccessPin>0</ScriptAccessPin> |
61 | <GroupPosition><X>147.23</X><Y>92.698</Y><Z>22.78084</Z></GroupPosition> | 63 | <GroupPosition><X>147.23</X><Y>92.698</Y><Z>22.78084</Z></GroupPosition> |
62 | <OffsetPosition><X>0</X><Y>0</Y><Z>0</Z></OffsetPosition> | 64 | <OffsetPosition><X>0</X><Y>0</Y><Z>0</Z></OffsetPosition> |
63 | <RotationOffset><X>-4.371139E-08</X><Y>-1</Y><Z>-4.371139E-08</Z><W>0</W></RotationOffset> | 65 | <RotationOffset><X>-4.371139E-08</X><Y>-1</Y><Z>-4.371139E-08</Z><W>0</W></RotationOffset> |
64 | <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity> | 66 | <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity> |
65 | <RotationalVelocity><X>0</X><Y>0</Y><Z>0</Z></RotationalVelocity> | 67 | <RotationalVelocity><X>0</X><Y>0</Y><Z>0</Z></RotationalVelocity> |
66 | <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity> | 68 | <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity> |
67 | <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration> | 69 | <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration> |
68 | <Description /> | 70 | <Description /> |
69 | <Color /> | 71 | <Color /> |
70 | <Text /> | 72 | <Text /> |
71 | <SitName /> | 73 | <SitName /> |
72 | <TouchName /> | 74 | <TouchName /> |
73 | <LinkNum>0</LinkNum> | 75 | <LinkNum>0</LinkNum> |
74 | <ClickAction>0</ClickAction> | 76 | <ClickAction>0</ClickAction> |
75 | <Shape> | 77 | <Shape> |
76 | <ProfileCurve>1</ProfileCurve> | 78 | <ProfileCurve>1</ProfileCurve> |
77 | <TextureEntry>AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA==</TextureEntry> | 79 | <TextureEntry>AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA==</TextureEntry> |
78 | <ExtraParams>AA==</ExtraParams> | 80 | <ExtraParams>AA==</ExtraParams> |
79 | <PathBegin>0</PathBegin> | 81 | <PathBegin>0</PathBegin> |
80 | <PathCurve>16</PathCurve> | 82 | <PathCurve>16</PathCurve> |
81 | <PathEnd>0</PathEnd> | 83 | <PathEnd>0</PathEnd> |
82 | <PathRadiusOffset>0</PathRadiusOffset> | 84 | <PathRadiusOffset>0</PathRadiusOffset> |
83 | <PathRevolutions>0</PathRevolutions> | 85 | <PathRevolutions>0</PathRevolutions> |
84 | <PathScaleX>100</PathScaleX> | 86 | <PathScaleX>100</PathScaleX> |
85 | <PathScaleY>100</PathScaleY> | 87 | <PathScaleY>100</PathScaleY> |
86 | <PathShearX>0</PathShearX> | 88 | <PathShearX>0</PathShearX> |
87 | <PathShearY>0</PathShearY> | 89 | <PathShearY>0</PathShearY> |
88 | <PathSkew>0</PathSkew> | 90 | <PathSkew>0</PathSkew> |
89 | <PathTaperX>0</PathTaperX> | 91 | <PathTaperX>0</PathTaperX> |
90 | <PathTaperY>0</PathTaperY> | 92 | <PathTaperY>0</PathTaperY> |
91 | <PathTwist>0</PathTwist> | 93 | <PathTwist>0</PathTwist> |
92 | <PathTwistBegin>0</PathTwistBegin> | 94 | <PathTwistBegin>0</PathTwistBegin> |
93 | <PCode>9</PCode> | 95 | <PCode>9</PCode> |
94 | <ProfileBegin>0</ProfileBegin> | 96 | <ProfileBegin>0</ProfileBegin> |
95 | <ProfileEnd>0</ProfileEnd> | 97 | <ProfileEnd>0</ProfileEnd> |
96 | <ProfileHollow>0</ProfileHollow> | 98 | <ProfileHollow>0</ProfileHollow> |
97 | <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale> | 99 | <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale> |
98 | <State>0</State> | 100 | <State>0</State> |
99 | <ProfileShape>Square</ProfileShape> | 101 | <ProfileShape>Square</ProfileShape> |
100 | <HollowShape>Same</HollowShape> | 102 | <HollowShape>Same</HollowShape> |
101 | <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture> | 103 | <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture> |
102 | <SculptType>0</SculptType><SculptData /> | 104 | <SculptType>0</SculptType><SculptData /> |
103 | <FlexiSoftness>0</FlexiSoftness> | 105 | <FlexiSoftness>0</FlexiSoftness> |
104 | <FlexiTension>0</FlexiTension> | 106 | <FlexiTension>0</FlexiTension> |
105 | <FlexiDrag>0</FlexiDrag> | 107 | <FlexiDrag>0</FlexiDrag> |
106 | <FlexiGravity>0</FlexiGravity> | 108 | <FlexiGravity>0</FlexiGravity> |
107 | <FlexiWind>0</FlexiWind> | 109 | <FlexiWind>0</FlexiWind> |
108 | <FlexiForceX>0</FlexiForceX> | 110 | <FlexiForceX>0</FlexiForceX> |
109 | <FlexiForceY>0</FlexiForceY> | 111 | <FlexiForceY>0</FlexiForceY> |
110 | <FlexiForceZ>0</FlexiForceZ> | 112 | <FlexiForceZ>0</FlexiForceZ> |
111 | <LightColorR>0</LightColorR> | 113 | <LightColorR>0</LightColorR> |
112 | <LightColorG>0</LightColorG> | 114 | <LightColorG>0</LightColorG> |
113 | <LightColorB>0</LightColorB> | 115 | <LightColorB>0</LightColorB> |
114 | <LightColorA>1</LightColorA> | 116 | <LightColorA>1</LightColorA> |
115 | <LightRadius>0</LightRadius> | 117 | <LightRadius>0</LightRadius> |
116 | <LightCutoff>0</LightCutoff> | 118 | <LightCutoff>0</LightCutoff> |
117 | <LightFalloff>0</LightFalloff> | 119 | <LightFalloff>0</LightFalloff> |
118 | <LightIntensity>1</LightIntensity> | 120 | <LightIntensity>1</LightIntensity> |
119 | <FlexiEntry>false</FlexiEntry> | 121 | <FlexiEntry>false</FlexiEntry> |
120 | <LightEntry>false</LightEntry> | 122 | <LightEntry>false</LightEntry> |
121 | <SculptEntry>false</SculptEntry> | 123 | <SculptEntry>false</SculptEntry> |
122 | </Shape> | 124 | </Shape> |
123 | <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale> | 125 | <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale> |
124 | <UpdateFlag>0</UpdateFlag> | 126 | <UpdateFlag>0</UpdateFlag> |
125 | <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation> | 127 | <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation> |
126 | <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition> | 128 | <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition> |
127 | <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL> | 129 | <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL> |
128 | <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL> | 130 | <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL> |
129 | <ParentID>0</ParentID> | 131 | <ParentID>0</ParentID> |
130 | <CreationDate>1211330445</CreationDate> | 132 | <CreationDate>1211330445</CreationDate> |
131 | <Category>0</Category> | 133 | <Category>0</Category> |
132 | <SalePrice>0</SalePrice> | 134 | <SalePrice>0</SalePrice> |
133 | <ObjectSaleType>0</ObjectSaleType> | 135 | <ObjectSaleType>0</ObjectSaleType> |
134 | <OwnershipCost>0</OwnershipCost> | 136 | <OwnershipCost>0</OwnershipCost> |
135 | <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID> | 137 | <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID> |
136 | <OwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></OwnerID> | 138 | <OwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></OwnerID> |
137 | <LastOwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></LastOwnerID> | 139 | <LastOwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></LastOwnerID> |
138 | <BaseMask>2147483647</BaseMask> | 140 | <BaseMask>2147483647</BaseMask> |
139 | <OwnerMask>2147483647</OwnerMask> | 141 | <OwnerMask>2147483647</OwnerMask> |
140 | <GroupMask>0</GroupMask> | 142 | <GroupMask>0</GroupMask> |
141 | <EveryoneMask>0</EveryoneMask> | 143 | <EveryoneMask>0</EveryoneMask> |
142 | <NextOwnerMask>2147483647</NextOwnerMask> | 144 | <NextOwnerMask>2147483647</NextOwnerMask> |
143 | <Flags>None</Flags> | 145 | <Flags>None</Flags> |
144 | <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> | 146 | <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> |
145 | <CollisionSoundVolume>0</CollisionSoundVolume> | 147 | <CollisionSoundVolume>0</CollisionSoundVolume> |
146 | </SceneObjectPart> | 148 | <DynAttrs> |
147 | </RootPart> | 149 | <llsd> |
148 | <OtherParts /> | 150 | <map> |
149 | </SceneObjectGroup>"; | 151 | <key>MyNamespace</key> |
150 | 152 | <map> | |
151 | private string badFloatsXml = @" | 153 | <key>MyStore</key> |
154 | <map> | ||
155 | <key>the answer</key> | ||
156 | <integer>42</integer> | ||
157 | </map> | ||
158 | </map> | ||
159 | </map> | ||
160 | </llsd> | ||
161 | </DynAttrs> | ||
162 | </SceneObjectPart> | ||
163 | </RootPart>"; | ||
164 | |||
165 | private const string ObjectWithNoOtherPartsXml = ObjectRootPartStubXml + | ||
166 | @" | ||
167 | <OtherParts /> | ||
168 | </SceneObjectGroup>"; | ||
169 | |||
170 | private const string ObjectWithOtherPartsXml = ObjectRootPartStubXml + | ||
171 | @" | ||
172 | <OtherParts> | ||
173 | <Part> | ||
174 | <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> | ||
175 | <AllowedDrop>false</AllowedDrop> | ||
176 | <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID> | ||
177 | <FolderID><Guid>9958feb1-02a6-49e4-a4ce-eba6f578ee13</Guid></FolderID> | ||
178 | <InventorySerial>3</InventorySerial> | ||
179 | <UUID><Guid>9958feb1-02a6-49e4-a4ce-eba6f578ee13</Guid></UUID> | ||
180 | <LocalId>1154704500</LocalId> | ||
181 | <Name>Alien Head 1</Name> | ||
182 | <Material>3</Material> | ||
183 | <PassTouches>false</PassTouches> | ||
184 | <PassCollisions>false</PassCollisions> | ||
185 | <RegionHandle>21990232560640000</RegionHandle> | ||
186 | <ScriptAccessPin>0</ScriptAccessPin> | ||
187 | <GroupPosition><X>125.5655</X><Y>127.346</Y><Z>22.48036</Z></GroupPosition> | ||
188 | <OffsetPosition><X>-0.2171936</X><Y>0.1083984</Y><Z>0.0009994507</Z></OffsetPosition> | ||
189 | <RotationOffset><X>-0.5122106</X><Y>0.4851225</Y><Z>-0.4957454</Z><W>0.5064908</W></RotationOffset> | ||
190 | <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity> | ||
191 | <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity> | ||
192 | <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration> | ||
193 | <Description>(No Description)</Description> | ||
194 | <Color><R>0</R><G>0</G><B>0</B><A>255</A></Color> | ||
195 | <Text/> | ||
196 | <SitName/> | ||
197 | <TouchName/> | ||
198 | <LinkNum>253</LinkNum> | ||
199 | <ClickAction>0</ClickAction> | ||
200 | <Shape> | ||
201 | <ProfileCurve>5</ProfileCurve> | ||
202 | <TextureEntry>Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</TextureEntry> | ||
203 | <ExtraParams>AA==</ExtraParams> | ||
204 | <PathBegin>0</PathBegin> | ||
205 | <PathCurve>32</PathCurve> | ||
206 | <PathEnd>0</PathEnd> | ||
207 | <PathRadiusOffset>0</PathRadiusOffset> | ||
208 | <PathRevolutions>0</PathRevolutions> | ||
209 | <PathScaleX>100</PathScaleX> | ||
210 | <PathScaleY>100</PathScaleY> | ||
211 | <PathShearX>0</PathShearX> | ||
212 | <PathShearY>0</PathShearY> | ||
213 | <PathSkew>0</PathSkew> | ||
214 | <PathTaperX>0</PathTaperX> | ||
215 | <PathTaperY>0</PathTaperY> | ||
216 | <PathTwist>0</PathTwist> | ||
217 | <PathTwistBegin>0</PathTwistBegin> | ||
218 | <PCode>9</PCode> | ||
219 | <ProfileBegin>0</ProfileBegin> | ||
220 | <ProfileEnd>0</ProfileEnd> | ||
221 | <ProfileHollow>0</ProfileHollow> | ||
222 | <State>9</State> | ||
223 | <LastAttachPoint>0</LastAttachPoint> | ||
224 | <ProfileShape>HalfCircle</ProfileShape> | ||
225 | <HollowShape>Same</HollowShape> | ||
226 | <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture> | ||
227 | <SculptType>0</SculptType> | ||
228 | <FlexiSoftness>0</FlexiSoftness> | ||
229 | <FlexiTension>0</FlexiTension> | ||
230 | <FlexiDrag>0</FlexiDrag> | ||
231 | <FlexiGravity>0</FlexiGravity> | ||
232 | <FlexiWind>0</FlexiWind> | ||
233 | <FlexiForceX>0</FlexiForceX> | ||
234 | <FlexiForceY>0</FlexiForceY> | ||
235 | <FlexiForceZ>0</FlexiForceZ> | ||
236 | <LightColorR>0</LightColorR> | ||
237 | <LightColorG>0</LightColorG> | ||
238 | <LightColorB>0</LightColorB> | ||
239 | <LightColorA>1</LightColorA> | ||
240 | <LightRadius>0</LightRadius> | ||
241 | <LightCutoff>0</LightCutoff> | ||
242 | <LightFalloff>0</LightFalloff> | ||
243 | <LightIntensity>1</LightIntensity> | ||
244 | <FlexiEntry>false</FlexiEntry> | ||
245 | <LightEntry>false</LightEntry> | ||
246 | <SculptEntry>false</SculptEntry> | ||
247 | </Shape> | ||
248 | <Scale><X>0.1148195</X><Y>0.0143891</Y><Z>0.02768878</Z></Scale> | ||
249 | <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation> | ||
250 | <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition> | ||
251 | <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL> | ||
252 | <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL> | ||
253 | <ParentID>1154704499</ParentID> | ||
254 | <CreationDate>1256611042</CreationDate> | ||
255 | <Category>0</Category> | ||
256 | <SalePrice>10</SalePrice> | ||
257 | <ObjectSaleType>0</ObjectSaleType> | ||
258 | <OwnershipCost>0</OwnershipCost> | ||
259 | <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID> | ||
260 | <OwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></OwnerID> | ||
261 | <LastOwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></LastOwnerID> | ||
262 | <BaseMask>647168</BaseMask> | ||
263 | <OwnerMask>647168</OwnerMask> | ||
264 | <GroupMask>0</GroupMask> | ||
265 | <EveryoneMask>0</EveryoneMask> | ||
266 | <NextOwnerMask>581632</NextOwnerMask> | ||
267 | <Flags>None</Flags> | ||
268 | <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> | ||
269 | <CollisionSoundVolume>0</CollisionSoundVolume> | ||
270 | <AttachedPos><X>0</X><Y>0</Y><Z>0</Z></AttachedPos> | ||
271 | <TextureAnimation/> | ||
272 | <ParticleSystem/> | ||
273 | <PayPrice0>-2</PayPrice0> | ||
274 | <PayPrice1>-2</PayPrice1> | ||
275 | <PayPrice2>-2</PayPrice2> | ||
276 | <PayPrice3>-2</PayPrice3> | ||
277 | <PayPrice4>-2</PayPrice4> | ||
278 | </SceneObjectPart> | ||
279 | </Part> | ||
280 | <Part> | ||
281 | <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> | ||
282 | <AllowedDrop>false</AllowedDrop> | ||
283 | <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID> | ||
284 | <FolderID><Guid>674b6b86-f5aa-439a-8e00-0d75bc08c80a</Guid></FolderID> | ||
285 | <InventorySerial>3</InventorySerial> | ||
286 | <UUID><Guid>674b6b86-f5aa-439a-8e00-0d75bc08c80a</Guid></UUID> | ||
287 | <LocalId>1154704501</LocalId> | ||
288 | <Name>Alien Head 2</Name> | ||
289 | <Material>3</Material> | ||
290 | <PassTouches>false</PassTouches> | ||
291 | <PassCollisions>false</PassCollisions> | ||
292 | <RegionHandle>21990232560640000</RegionHandle> | ||
293 | <ScriptAccessPin>0</ScriptAccessPin> | ||
294 | <GroupPosition><X>125.5655</X><Y>127.346</Y><Z>22.48036</Z></GroupPosition> | ||
295 | <OffsetPosition><X>-0.2490997</X><Y>0.08520126</Y><Z>0.0009002686</Z></OffsetPosition> | ||
296 | <RotationOffset><X>-0.4765368</X><Y>0.5194498</Y><Z>-0.5301372</Z><W>0.4712104</W></RotationOffset> | ||
297 | <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity> | ||
298 | <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity> | ||
299 | <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration> | ||
300 | <Description>(No Description)</Description> | ||
301 | <Color><R>0</R><G>0</G><B>0</B><A>255</A></Color> | ||
302 | <Text/> | ||
303 | <SitName/> | ||
304 | <TouchName/> | ||
305 | <LinkNum>252</LinkNum> | ||
306 | <ClickAction>0</ClickAction> | ||
307 | <Shape> | ||
308 | <ProfileCurve>0</ProfileCurve> | ||
309 | <TextureEntry>Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</TextureEntry> | ||
310 | <ExtraParams>AA==</ExtraParams> | ||
311 | <PathBegin>0</PathBegin> | ||
312 | <PathCurve>32</PathCurve> | ||
313 | <PathEnd>0</PathEnd> | ||
314 | <PathRadiusOffset>0</PathRadiusOffset> | ||
315 | <PathRevolutions>0</PathRevolutions> | ||
316 | <PathScaleX>100</PathScaleX> | ||
317 | <PathScaleY>150</PathScaleY> | ||
318 | <PathShearX>0</PathShearX> | ||
319 | <PathShearY>0</PathShearY> | ||
320 | <PathSkew>0</PathSkew> | ||
321 | <PathTaperX>0</PathTaperX> | ||
322 | <PathTaperY>0</PathTaperY> | ||
323 | <PathTwist>0</PathTwist> | ||
324 | <PathTwistBegin>0</PathTwistBegin> | ||
325 | <PCode>9</PCode> | ||
326 | <ProfileBegin>0</ProfileBegin> | ||
327 | <ProfileEnd>0</ProfileEnd> | ||
328 | <ProfileHollow>0</ProfileHollow> | ||
329 | <State>9</State> | ||
330 | <LastAttachPoint>0</LastAttachPoint> | ||
331 | <ProfileShape>Circle</ProfileShape> | ||
332 | <HollowShape>Same</HollowShape> | ||
333 | <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture> | ||
334 | <SculptType>0</SculptType> | ||
335 | <FlexiSoftness>0</FlexiSoftness> | ||
336 | <FlexiTension>0</FlexiTension> | ||
337 | <FlexiDrag>0</FlexiDrag> | ||
338 | <FlexiGravity>0</FlexiGravity> | ||
339 | <FlexiWind>0</FlexiWind> | ||
340 | <FlexiForceX>0</FlexiForceX> | ||
341 | <FlexiForceY>0</FlexiForceY> | ||
342 | <FlexiForceZ>0</FlexiForceZ> | ||
343 | <LightColorR>0</LightColorR> | ||
344 | <LightColorG>0</LightColorG> | ||
345 | <LightColorB>0</LightColorB> | ||
346 | <LightColorA>1</LightColorA> | ||
347 | <LightRadius>0</LightRadius> | ||
348 | <LightCutoff>0</LightCutoff> | ||
349 | <LightFalloff>0</LightFalloff> | ||
350 | <LightIntensity>1</LightIntensity> | ||
351 | <FlexiEntry>false</FlexiEntry> | ||
352 | <LightEntry>false</LightEntry> | ||
353 | <SculptEntry>false</SculptEntry> | ||
354 | </Shape> | ||
355 | <Scale><X>0.03574385</X><Y>0.05958032</Y><Z>0.04764182</Z></Scale> | ||
356 | <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation> | ||
357 | <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition> | ||
358 | <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL> | ||
359 | <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL> | ||
360 | <ParentID>1154704499</ParentID> | ||
361 | <CreationDate>1256611042</CreationDate> | ||
362 | <Category>0</Category> | ||
363 | <SalePrice>10</SalePrice> | ||
364 | <ObjectSaleType>0</ObjectSaleType> | ||
365 | <OwnershipCost>0</OwnershipCost> | ||
366 | <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID> | ||
367 | <OwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></OwnerID> | ||
368 | <LastOwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></LastOwnerID> | ||
369 | <BaseMask>647168</BaseMask> | ||
370 | <OwnerMask>647168</OwnerMask> | ||
371 | <GroupMask>0</GroupMask> | ||
372 | <EveryoneMask>0</EveryoneMask> | ||
373 | <NextOwnerMask>581632</NextOwnerMask> | ||
374 | <Flags>None</Flags> | ||
375 | <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> | ||
376 | <CollisionSoundVolume>0</CollisionSoundVolume> | ||
377 | <AttachedPos><X>0</X><Y>0</Y><Z>0</Z></AttachedPos> | ||
378 | <TextureAnimation/> | ||
379 | <ParticleSystem/> | ||
380 | <PayPrice0>-2</PayPrice0> | ||
381 | <PayPrice1>-2</PayPrice1> | ||
382 | <PayPrice2>-2</PayPrice2> | ||
383 | <PayPrice3>-2</PayPrice3> | ||
384 | <PayPrice4>-2</PayPrice4> | ||
385 | </SceneObjectPart> | ||
386 | </Part> | ||
387 | </OtherParts> | ||
388 | </SceneObjectGroup>"; | ||
389 | |||
390 | private const string ObjectWithBadFloatsXml = @" | ||
152 | <SceneObjectGroup> | 391 | <SceneObjectGroup> |
153 | <RootPart> | 392 | <RootPart> |
154 | <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> | 393 | <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> |
@@ -255,7 +494,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
255 | <OtherParts /> | 494 | <OtherParts /> |
256 | </SceneObjectGroup>"; | 495 | </SceneObjectGroup>"; |
257 | 496 | ||
258 | private string xml2 = @" | 497 | private const string ObjectWithNoPartsXml2 = @" |
259 | <SceneObjectGroup> | 498 | <SceneObjectGroup> |
260 | <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> | 499 | <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> |
261 | <CreatorID><UUID>b46ef588-411e-4a8b-a284-d7dcfe8e74ef</UUID></CreatorID> | 500 | <CreatorID><UUID>b46ef588-411e-4a8b-a284-d7dcfe8e74ef</UUID></CreatorID> |
@@ -331,6 +570,20 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
331 | <EveryoneMask>0</EveryoneMask> | 570 | <EveryoneMask>0</EveryoneMask> |
332 | <NextOwnerMask>2147483647</NextOwnerMask> | 571 | <NextOwnerMask>2147483647</NextOwnerMask> |
333 | <Flags>None</Flags> | 572 | <Flags>None</Flags> |
573 | <DynAttrs> | ||
574 | <llsd> | ||
575 | <map> | ||
576 | <key>MyNamespace</key> | ||
577 | <map> | ||
578 | <key>MyStore</key> | ||
579 | <map> | ||
580 | <key>last words</key> | ||
581 | <string>Rosebud</string> | ||
582 | </map> | ||
583 | </map> | ||
584 | </map> | ||
585 | </llsd> | ||
586 | </DynAttrs> | ||
334 | <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar> | 587 | <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar> |
335 | </SceneObjectPart> | 588 | </SceneObjectPart> |
336 | <OtherParts /> | 589 | <OtherParts /> |
@@ -348,17 +601,58 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
348 | } | 601 | } |
349 | 602 | ||
350 | [Test] | 603 | [Test] |
351 | public void TestDeserializeXml() | 604 | public void TestDeserializeXmlObjectWithNoOtherParts() |
352 | { | 605 | { |
353 | TestHelpers.InMethod(); | 606 | TestHelpers.InMethod(); |
354 | //log4net.Config.XmlConfigurator.Configure(); | 607 | TestHelpers.EnableLogging(); |
355 | 608 | ||
356 | SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(xml); | 609 | SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithNoOtherPartsXml); |
357 | SceneObjectPart rootPart = so.RootPart; | 610 | SceneObjectPart rootPart = so.RootPart; |
358 | 611 | ||
359 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); | 612 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); |
360 | Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); | 613 | Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); |
361 | Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); | 614 | Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); |
615 | OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore"); | ||
616 | Assert.AreEqual(42, store["the answer"].AsInteger()); | ||
617 | |||
618 | // TODO: Check other properties | ||
619 | } | ||
620 | |||
621 | [Test] | ||
622 | public void TestDeserializeXmlObjectWithOtherParts() | ||
623 | { | ||
624 | TestHelpers.InMethod(); | ||
625 | TestHelpers.EnableLogging(); | ||
626 | |||
627 | SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithOtherPartsXml); | ||
628 | SceneObjectPart[] parts = so.Parts; | ||
629 | Assert.AreEqual(3, so.Parts.Length); | ||
630 | |||
631 | { | ||
632 | SceneObjectPart part = parts[0]; | ||
633 | |||
634 | Assert.That(part.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); | ||
635 | Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); | ||
636 | Assert.That(part.Name, Is.EqualTo("PrimMyRide")); | ||
637 | OSDMap store = part.DynAttrs.GetStore("MyNamespace", "MyStore"); | ||
638 | Assert.AreEqual(42, store["the answer"].AsInteger()); | ||
639 | } | ||
640 | |||
641 | { | ||
642 | SceneObjectPart part = parts[1]; | ||
643 | |||
644 | Assert.That(part.UUID, Is.EqualTo(new UUID("9958feb1-02a6-49e4-a4ce-eba6f578ee13"))); | ||
645 | Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); | ||
646 | Assert.That(part.Name, Is.EqualTo("Alien Head 1")); | ||
647 | } | ||
648 | |||
649 | { | ||
650 | SceneObjectPart part = parts[2]; | ||
651 | |||
652 | Assert.That(part.UUID, Is.EqualTo(new UUID("674b6b86-f5aa-439a-8e00-0d75bc08c80a"))); | ||
653 | Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); | ||
654 | Assert.That(part.Name, Is.EqualTo("Alien Head 2")); | ||
655 | } | ||
362 | 656 | ||
363 | // TODO: Check other properties | 657 | // TODO: Check other properties |
364 | } | 658 | } |
@@ -369,7 +663,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
369 | TestHelpers.InMethod(); | 663 | TestHelpers.InMethod(); |
370 | // log4net.Config.XmlConfigurator.Configure(); | 664 | // log4net.Config.XmlConfigurator.Configure(); |
371 | 665 | ||
372 | SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(badFloatsXml); | 666 | SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithBadFloatsXml); |
373 | SceneObjectPart rootPart = so.RootPart; | 667 | SceneObjectPart rootPart = so.RootPart; |
374 | 668 | ||
375 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); | 669 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); |
@@ -409,6 +703,15 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
409 | rp.CreatorID = rpCreatorId; | 703 | rp.CreatorID = rpCreatorId; |
410 | rp.Shape = shape; | 704 | rp.Shape = shape; |
411 | 705 | ||
706 | string daNamespace = "MyNamespace"; | ||
707 | string daStoreName = "MyStore"; | ||
708 | string daKey = "foo"; | ||
709 | string daValue = "bar"; | ||
710 | OSDMap myStore = new OSDMap(); | ||
711 | myStore.Add(daKey, daValue); | ||
712 | rp.DynAttrs = new DAMap(); | ||
713 | rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore); | ||
714 | |||
412 | SceneObjectGroup so = new SceneObjectGroup(rp); | 715 | SceneObjectGroup so = new SceneObjectGroup(rp); |
413 | 716 | ||
414 | // Need to add the object to the scene so that the request to get script state succeeds | 717 | // Need to add the object to the scene so that the request to get script state succeeds |
@@ -424,6 +727,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
424 | UUID uuid = UUID.Zero; | 727 | UUID uuid = UUID.Zero; |
425 | string name = null; | 728 | string name = null; |
426 | UUID creatorId = UUID.Zero; | 729 | UUID creatorId = UUID.Zero; |
730 | DAMap daMap = null; | ||
427 | 731 | ||
428 | while (xtr.Read() && xtr.Name != "SceneObjectPart") | 732 | while (xtr.Read() && xtr.Name != "SceneObjectPart") |
429 | { | 733 | { |
@@ -449,6 +753,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
449 | creatorId = UUID.Parse(xtr.ReadElementString("UUID")); | 753 | creatorId = UUID.Parse(xtr.ReadElementString("UUID")); |
450 | xtr.ReadEndElement(); | 754 | xtr.ReadEndElement(); |
451 | break; | 755 | break; |
756 | case "DynAttrs": | ||
757 | daMap = new DAMap(); | ||
758 | daMap.ReadXml(xtr); | ||
759 | break; | ||
452 | } | 760 | } |
453 | } | 761 | } |
454 | 762 | ||
@@ -462,6 +770,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
462 | Assert.That(uuid, Is.EqualTo(rpUuid)); | 770 | Assert.That(uuid, Is.EqualTo(rpUuid)); |
463 | Assert.That(name, Is.EqualTo(rpName)); | 771 | Assert.That(name, Is.EqualTo(rpName)); |
464 | Assert.That(creatorId, Is.EqualTo(rpCreatorId)); | 772 | Assert.That(creatorId, Is.EqualTo(rpCreatorId)); |
773 | Assert.NotNull(daMap); | ||
774 | Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString()); | ||
465 | } | 775 | } |
466 | 776 | ||
467 | [Test] | 777 | [Test] |
@@ -470,12 +780,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
470 | TestHelpers.InMethod(); | 780 | TestHelpers.InMethod(); |
471 | //log4net.Config.XmlConfigurator.Configure(); | 781 | //log4net.Config.XmlConfigurator.Configure(); |
472 | 782 | ||
473 | SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(xml2); | 783 | SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(ObjectWithNoPartsXml2); |
474 | SceneObjectPart rootPart = so.RootPart; | 784 | SceneObjectPart rootPart = so.RootPart; |
475 | 785 | ||
476 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); | 786 | Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); |
477 | Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); | 787 | Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); |
478 | Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); | 788 | Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); |
789 | OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore"); | ||
790 | Assert.AreEqual("Rosebud", store["last words"].AsString()); | ||
479 | 791 | ||
480 | // TODO: Check other properties | 792 | // TODO: Check other properties |
481 | } | 793 | } |
@@ -500,6 +812,15 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
500 | rp.CreatorID = rpCreatorId; | 812 | rp.CreatorID = rpCreatorId; |
501 | rp.Shape = shape; | 813 | rp.Shape = shape; |
502 | 814 | ||
815 | string daNamespace = "MyNamespace"; | ||
816 | string daStoreName = "MyStore"; | ||
817 | string daKey = "foo"; | ||
818 | string daValue = "bar"; | ||
819 | OSDMap myStore = new OSDMap(); | ||
820 | myStore.Add(daKey, daValue); | ||
821 | rp.DynAttrs = new DAMap(); | ||
822 | rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore); | ||
823 | |||
503 | SceneObjectGroup so = new SceneObjectGroup(rp); | 824 | SceneObjectGroup so = new SceneObjectGroup(rp); |
504 | 825 | ||
505 | // Need to add the object to the scene so that the request to get script state succeeds | 826 | // Need to add the object to the scene so that the request to get script state succeeds |
@@ -516,6 +837,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
516 | UUID uuid = UUID.Zero; | 837 | UUID uuid = UUID.Zero; |
517 | string name = null; | 838 | string name = null; |
518 | UUID creatorId = UUID.Zero; | 839 | UUID creatorId = UUID.Zero; |
840 | DAMap daMap = null; | ||
519 | 841 | ||
520 | while (xtr.Read() && xtr.Name != "SceneObjectPart") | 842 | while (xtr.Read() && xtr.Name != "SceneObjectPart") |
521 | { | 843 | { |
@@ -537,6 +859,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
537 | creatorId = UUID.Parse(xtr.ReadElementString("Guid")); | 859 | creatorId = UUID.Parse(xtr.ReadElementString("Guid")); |
538 | xtr.ReadEndElement(); | 860 | xtr.ReadEndElement(); |
539 | break; | 861 | break; |
862 | case "DynAttrs": | ||
863 | daMap = new DAMap(); | ||
864 | daMap.ReadXml(xtr); | ||
865 | break; | ||
540 | } | 866 | } |
541 | } | 867 | } |
542 | 868 | ||
@@ -549,6 +875,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests | |||
549 | Assert.That(uuid, Is.EqualTo(rpUuid)); | 875 | Assert.That(uuid, Is.EqualTo(rpUuid)); |
550 | Assert.That(name, Is.EqualTo(rpName)); | 876 | Assert.That(name, Is.EqualTo(rpName)); |
551 | Assert.That(creatorId, Is.EqualTo(rpCreatorId)); | 877 | Assert.That(creatorId, Is.EqualTo(rpCreatorId)); |
878 | Assert.NotNull(daMap); | ||
879 | Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString()); | ||
552 | } | 880 | } |
553 | } | 881 | } |
554 | } \ No newline at end of file | 882 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs index 883045a..d093224 100644 --- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs +++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs | |||
@@ -369,6 +369,15 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
369 | }); | 369 | }); |
370 | } | 370 | } |
371 | 371 | ||
372 | public void SetSoundQueueing(UUID objectID, bool shouldQueue) | ||
373 | { | ||
374 | SceneObjectPart part; | ||
375 | if (!m_scene.TryGetSceneObjectPart(objectID, out part)) | ||
376 | return; | ||
377 | |||
378 | part.SoundQueueing = shouldQueue; | ||
379 | } | ||
380 | |||
372 | #endregion | 381 | #endregion |
373 | } | 382 | } |
374 | } | 383 | } |
diff --git a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs index a321c09..d0318eb 100644 --- a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs +++ b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs | |||
@@ -68,9 +68,6 @@ namespace OpenSim.Region.CoreModules | |||
68 | // updating those region settings in GenSunPos() | 68 | // updating those region settings in GenSunPos() |
69 | private bool receivedEstateToolsSunUpdate = false; | 69 | private bool receivedEstateToolsSunUpdate = false; |
70 | 70 | ||
71 | // Configurable values | ||
72 | private string m_RegionMode = "SL"; | ||
73 | |||
74 | // Sun's position information is updated and sent to clients every m_UpdateInterval frames | 71 | // Sun's position information is updated and sent to clients every m_UpdateInterval frames |
75 | private int m_UpdateInterval = 0; | 72 | private int m_UpdateInterval = 0; |
76 | 73 | ||
@@ -90,7 +87,6 @@ namespace OpenSim.Region.CoreModules | |||
90 | // private double m_longitude = 0; | 87 | // private double m_longitude = 0; |
91 | // private double m_latitude = 0; | 88 | // private double m_latitude = 0; |
92 | // Configurable defaults Defaults close to SL | 89 | // Configurable defaults Defaults close to SL |
93 | private string d_mode = "SL"; | ||
94 | private int d_frame_mod = 100; // Every 10 seconds (actually less) | 90 | private int d_frame_mod = 100; // Every 10 seconds (actually less) |
95 | private double d_day_length = 4; // A VW day is 4 RW hours long | 91 | private double d_day_length = 4; // A VW day is 4 RW hours long |
96 | private int d_year_length = 60; // There are 60 VW days in a VW year | 92 | private int d_year_length = 60; // There are 60 VW days in a VW year |
@@ -134,12 +130,15 @@ namespace OpenSim.Region.CoreModules | |||
134 | 130 | ||
135 | private const int TICKS_PER_SECOND = 10000000; | 131 | private const int TICKS_PER_SECOND = 10000000; |
136 | 132 | ||
133 | private ulong m_CurrentTimeOffset = 0; | ||
134 | |||
137 | // Current time in elapsed seconds since Jan 1st 1970 | 135 | // Current time in elapsed seconds since Jan 1st 1970 |
138 | private ulong CurrentTime | 136 | private ulong CurrentTime |
139 | { | 137 | { |
140 | get | 138 | get |
141 | { | 139 | { |
142 | return (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND); | 140 | ulong ctime = (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND); |
141 | return ctime + m_CurrentTimeOffset; | ||
143 | } | 142 | } |
144 | } | 143 | } |
145 | 144 | ||
@@ -252,21 +251,18 @@ namespace OpenSim.Region.CoreModules | |||
252 | } | 251 | } |
253 | 252 | ||
254 | // TODO: Decouple this, so we can get rid of Linden Hour info | 253 | // TODO: Decouple this, so we can get rid of Linden Hour info |
255 | // Update Region infor with new Sun Position and Hour | 254 | // Update Region with new Sun Vector |
256 | // set estate settings for region access to sun position | 255 | // set estate settings for region access to sun position |
257 | if (receivedEstateToolsSunUpdate) | 256 | if (receivedEstateToolsSunUpdate) |
258 | { | 257 | { |
259 | m_scene.RegionInfo.RegionSettings.SunVector = Position; | 258 | m_scene.RegionInfo.RegionSettings.SunVector = Position; |
260 | m_scene.RegionInfo.RegionSettings.SunPosition = GetCurrentTimeAsLindenSunHour(); | ||
261 | } | 259 | } |
262 | } | 260 | } |
263 | 261 | ||
264 | private float GetCurrentTimeAsLindenSunHour() | 262 | private float GetCurrentTimeAsLindenSunHour() |
265 | { | 263 | { |
266 | if (m_SunFixed) | 264 | float curtime = m_SunFixed ? m_SunFixedHour : GetCurrentSunHour(); |
267 | return m_SunFixedHour + 6; | 265 | return (curtime + 6.0f) % 24.0f; |
268 | |||
269 | return GetCurrentSunHour() + 6.0f; | ||
270 | } | 266 | } |
271 | 267 | ||
272 | #region INonSharedRegion Methods | 268 | #region INonSharedRegion Methods |
@@ -292,8 +288,6 @@ namespace OpenSim.Region.CoreModules | |||
292 | try | 288 | try |
293 | { | 289 | { |
294 | // Mode: determines how the sun is handled | 290 | // Mode: determines how the sun is handled |
295 | m_RegionMode = config.Configs["Sun"].GetString("mode", d_mode); | ||
296 | // Mode: determines how the sun is handled | ||
297 | // m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude); | 291 | // m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude); |
298 | // Mode: determines how the sun is handled | 292 | // Mode: determines how the sun is handled |
299 | // m_longitude = config.Configs["Sun"].GetDouble("longitude", d_longitude); | 293 | // m_longitude = config.Configs["Sun"].GetDouble("longitude", d_longitude); |
@@ -315,7 +309,6 @@ namespace OpenSim.Region.CoreModules | |||
315 | catch (Exception e) | 309 | catch (Exception e) |
316 | { | 310 | { |
317 | m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: " + e.Message); | 311 | m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: " + e.Message); |
318 | m_RegionMode = d_mode; | ||
319 | m_YearLengthDays = d_year_length; | 312 | m_YearLengthDays = d_year_length; |
320 | m_DayLengthHours = d_day_length; | 313 | m_DayLengthHours = d_day_length; |
321 | m_HorizonShift = d_day_night; | 314 | m_HorizonShift = d_day_night; |
@@ -326,40 +319,28 @@ namespace OpenSim.Region.CoreModules | |||
326 | // m_longitude = d_longitude; | 319 | // m_longitude = d_longitude; |
327 | } | 320 | } |
328 | 321 | ||
329 | switch (m_RegionMode) | 322 | SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60); |
330 | { | 323 | SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays); |
331 | case "T1": | ||
332 | default: | ||
333 | case "SL": | ||
334 | // Time taken to complete a cycle (day and season) | ||
335 | |||
336 | SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60); | ||
337 | SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays); | ||
338 | |||
339 | // Ration of real-to-virtual time | ||
340 | 324 | ||
341 | // VWTimeRatio = 24/m_day_length; | 325 | // Ration of real-to-virtual time |
342 | 326 | ||
343 | // Speed of rotation needed to complete a cycle in the | 327 | // VWTimeRatio = 24/m_day_length; |
344 | // designated period (day and season) | ||
345 | 328 | ||
346 | SunSpeed = m_SunCycle/SecondsPerSunCycle; | 329 | // Speed of rotation needed to complete a cycle in the |
347 | SeasonSpeed = m_SeasonalCycle/SecondsPerYear; | 330 | // designated period (day and season) |
348 | 331 | ||
349 | // Horizon translation | 332 | SunSpeed = m_SunCycle/SecondsPerSunCycle; |
333 | SeasonSpeed = m_SeasonalCycle/SecondsPerYear; | ||
350 | 334 | ||
351 | HorizonShift = m_HorizonShift; // Z axis translation | 335 | // Horizon translation |
352 | // HoursToRadians = (SunCycle/24)*VWTimeRatio; | ||
353 | 336 | ||
354 | m_log.Debug("[SUN]: Mode is " + m_RegionMode); | 337 | HorizonShift = m_HorizonShift; // Z axis translation |
355 | m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days"); | 338 | // HoursToRadians = (SunCycle/24)*VWTimeRatio; |
356 | m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift); | ||
357 | m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale); | ||
358 | m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames"); | ||
359 | |||
360 | break; | ||
361 | } | ||
362 | 339 | ||
340 | m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days"); | ||
341 | m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift); | ||
342 | m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale); | ||
343 | m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames"); | ||
363 | } | 344 | } |
364 | 345 | ||
365 | public Type ReplaceableInterface | 346 | public Type ReplaceableInterface |
@@ -386,7 +367,8 @@ namespace OpenSim.Region.CoreModules | |||
386 | string sunCommand = string.Format("sun {0}", kvp.Key); | 367 | string sunCommand = string.Format("sun {0}", kvp.Key); |
387 | m_scene.AddCommand("Regions", this, sunCommand, string.Format("{0} [<value>]", sunCommand), kvp.Value, "", HandleSunConsoleCommand); | 368 | m_scene.AddCommand("Regions", this, sunCommand, string.Format("{0} [<value>]", sunCommand), kvp.Value, "", HandleSunConsoleCommand); |
388 | } | 369 | } |
389 | 370 | m_scene.AddCommand("Regions", this, "sun help", "sun help", "list parameters that can be changed", "", HandleSunConsoleCommand); | |
371 | m_scene.AddCommand("Regions", this, "sun list", "sun list", "list parameters that can be changed", "", HandleSunConsoleCommand); | ||
390 | ready = true; | 372 | ready = true; |
391 | } | 373 | } |
392 | 374 | ||
@@ -395,7 +377,7 @@ namespace OpenSim.Region.CoreModules | |||
395 | ready = false; | 377 | ready = false; |
396 | 378 | ||
397 | // Remove our hooks | 379 | // Remove our hooks |
398 | m_scene.EventManager.OnFrame -= SunUpdate; | 380 | m_scene.EventManager.OnFrame -= SunUpdate; |
399 | m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; | 381 | m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; |
400 | m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate; | 382 | m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate; |
401 | m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour; | 383 | m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour; |
@@ -420,23 +402,22 @@ namespace OpenSim.Region.CoreModules | |||
420 | 402 | ||
421 | public void SunToClient(IClientAPI client) | 403 | public void SunToClient(IClientAPI client) |
422 | { | 404 | { |
423 | if (m_RegionMode != "T1") | 405 | if (ready) |
424 | { | 406 | { |
425 | if (ready) | 407 | if (m_SunFixed) |
426 | { | 408 | { |
427 | if (m_SunFixed) | 409 | // m_log.DebugFormat("[SUN]: Fixed SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", |
428 | { | 410 | // m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); |
429 | // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); | 411 | client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); |
430 | client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); | 412 | } |
431 | } | 413 | else |
432 | else | 414 | { |
433 | { | 415 | // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", |
434 | // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); | 416 | // m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); |
435 | client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); | 417 | client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); |
436 | } | ||
437 | } | 418 | } |
438 | } | 419 | } |
439 | } | 420 | } |
440 | 421 | ||
441 | public void SunUpdate() | 422 | public void SunUpdate() |
442 | { | 423 | { |
@@ -459,26 +440,33 @@ namespace OpenSim.Region.CoreModules | |||
459 | SunToClient(avatar.ControllingClient); | 440 | SunToClient(avatar.ControllingClient); |
460 | } | 441 | } |
461 | 442 | ||
462 | /// <summary> | 443 | public void EstateToolsSunUpdate(ulong regionHandle) |
463 | /// | ||
464 | /// </summary> | ||
465 | /// <param name="regionHandle"></param> | ||
466 | /// <param name="FixedTime">Is the sun's position fixed?</param> | ||
467 | /// <param name="useEstateTime">Use the Region or Estate Sun hour?</param> | ||
468 | /// <param name="FixedSunHour">What hour of the day is the Sun Fixed at?</param> | ||
469 | public void EstateToolsSunUpdate(ulong regionHandle, bool FixedSun, bool useEstateTime, float FixedSunHour) | ||
470 | { | 444 | { |
471 | if (m_scene.RegionInfo.RegionHandle == regionHandle) | 445 | if (m_scene.RegionInfo.RegionHandle == regionHandle) |
472 | { | 446 | { |
473 | // Must limit the Sun Hour to 0 ... 24 | 447 | float sunFixedHour; |
474 | while (FixedSunHour > 24.0f) | 448 | bool fixedSun; |
475 | FixedSunHour -= 24; | ||
476 | 449 | ||
477 | while (FixedSunHour < 0) | 450 | if (m_scene.RegionInfo.RegionSettings.UseEstateSun) |
478 | FixedSunHour += 24; | 451 | { |
452 | sunFixedHour = (float)m_scene.RegionInfo.EstateSettings.SunPosition; | ||
453 | fixedSun = m_scene.RegionInfo.EstateSettings.FixedSun; | ||
454 | } | ||
455 | else | ||
456 | { | ||
457 | sunFixedHour = (float)m_scene.RegionInfo.RegionSettings.SunPosition - 6.0f; | ||
458 | fixedSun = m_scene.RegionInfo.RegionSettings.FixedSun; | ||
459 | } | ||
460 | |||
461 | // Must limit the Sun Hour to 0 ... 24 | ||
462 | while (sunFixedHour > 24.0f) | ||
463 | sunFixedHour -= 24; | ||
479 | 464 | ||
480 | m_SunFixedHour = FixedSunHour; | 465 | while (sunFixedHour < 0) |
481 | m_SunFixed = FixedSun; | 466 | sunFixedHour += 24; |
467 | |||
468 | m_SunFixedHour = sunFixedHour; | ||
469 | m_SunFixed = fixedSun; | ||
482 | 470 | ||
483 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString()); | 471 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString()); |
484 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString()); | 472 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString()); |
@@ -501,7 +489,7 @@ namespace OpenSim.Region.CoreModules | |||
501 | { | 489 | { |
502 | m_scene.ForEachRootClient(delegate(IClientAPI client) | 490 | m_scene.ForEachRootClient(delegate(IClientAPI client) |
503 | { | 491 | { |
504 | SunToClient(client); | 492 | SunToClient(client); |
505 | }); | 493 | }); |
506 | } | 494 | } |
507 | 495 | ||
@@ -526,6 +514,9 @@ namespace OpenSim.Region.CoreModules | |||
526 | case "update_interval": | 514 | case "update_interval": |
527 | return m_UpdateInterval; | 515 | return m_UpdateInterval; |
528 | 516 | ||
517 | case "current_time": | ||
518 | return GetCurrentTimeAsLindenSunHour(); | ||
519 | |||
529 | default: | 520 | default: |
530 | throw new Exception("Unknown sun parameter."); | 521 | throw new Exception("Unknown sun parameter."); |
531 | } | 522 | } |
@@ -533,7 +524,51 @@ namespace OpenSim.Region.CoreModules | |||
533 | 524 | ||
534 | public void SetSunParameter(string param, double value) | 525 | public void SetSunParameter(string param, double value) |
535 | { | 526 | { |
536 | HandleSunConsoleCommand("sun", new string[] {param, value.ToString() }); | 527 | switch (param) |
528 | { | ||
529 | case "year_length": | ||
530 | m_YearLengthDays = (int)value; | ||
531 | SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays); | ||
532 | SeasonSpeed = m_SeasonalCycle/SecondsPerYear; | ||
533 | break; | ||
534 | |||
535 | case "day_length": | ||
536 | m_DayLengthHours = value; | ||
537 | SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60); | ||
538 | SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays); | ||
539 | SunSpeed = m_SunCycle/SecondsPerSunCycle; | ||
540 | SeasonSpeed = m_SeasonalCycle/SecondsPerYear; | ||
541 | break; | ||
542 | |||
543 | case "day_night_offset": | ||
544 | m_HorizonShift = value; | ||
545 | HorizonShift = m_HorizonShift; | ||
546 | break; | ||
547 | |||
548 | case "day_time_sun_hour_scale": | ||
549 | m_DayTimeSunHourScale = value; | ||
550 | break; | ||
551 | |||
552 | case "update_interval": | ||
553 | m_UpdateInterval = (int)value; | ||
554 | break; | ||
555 | |||
556 | case "current_time": | ||
557 | value = (value + 18.0) % 24.0; | ||
558 | // set the current offset so that the effective sun time is the parameter | ||
559 | m_CurrentTimeOffset = 0; // clear this first so we use raw time | ||
560 | m_CurrentTimeOffset = (ulong)(SecondsPerSunCycle * value/ 24.0) - (CurrentTime % SecondsPerSunCycle); | ||
561 | break; | ||
562 | |||
563 | default: | ||
564 | throw new Exception("Unknown sun parameter."); | ||
565 | } | ||
566 | |||
567 | // Generate shared values | ||
568 | GenSunPos(); | ||
569 | |||
570 | // When sun settings are updated, we should update all clients with new settings. | ||
571 | SunUpdateToAllClients(); | ||
537 | } | 572 | } |
538 | 573 | ||
539 | public float GetCurrentSunHour() | 574 | public float GetCurrentSunHour() |
@@ -566,7 +601,7 @@ namespace OpenSim.Region.CoreModules | |||
566 | 601 | ||
567 | foreach (string output in ParseCmdParams(cmdparams)) | 602 | foreach (string output in ParseCmdParams(cmdparams)) |
568 | { | 603 | { |
569 | m_log.Info("[SUN] " + output); | 604 | MainConsole.Instance.Output(output); |
570 | } | 605 | } |
571 | } | 606 | } |
572 | 607 | ||
@@ -575,10 +610,11 @@ namespace OpenSim.Region.CoreModules | |||
575 | Dictionary<string, string> Params = new Dictionary<string, string>(); | 610 | Dictionary<string, string> Params = new Dictionary<string, string>(); |
576 | 611 | ||
577 | Params.Add("year_length", "number of days to a year"); | 612 | Params.Add("year_length", "number of days to a year"); |
578 | Params.Add("day_length", "number of seconds to a day"); | 613 | Params.Add("day_length", "number of hours to a day"); |
579 | Params.Add("day_night_offset", "induces a horizon shift"); | 614 | Params.Add("day_night_offset", "induces a horizon shift"); |
580 | Params.Add("update_interval", "how often to update the sun's position in frames"); | 615 | Params.Add("update_interval", "how often to update the sun's position in frames"); |
581 | Params.Add("day_time_sun_hour_scale", "scales day light vs nite hours to change day/night ratio"); | 616 | Params.Add("day_time_sun_hour_scale", "scales day light vs nite hours to change day/night ratio"); |
617 | Params.Add("current_time", "time in seconds of the simulator"); | ||
582 | 618 | ||
583 | return Params; | 619 | return Params; |
584 | } | 620 | } |
@@ -612,46 +648,15 @@ namespace OpenSim.Region.CoreModules | |||
612 | } | 648 | } |
613 | else if (args.Length == 3) | 649 | else if (args.Length == 3) |
614 | { | 650 | { |
615 | float value = 0.0f; | 651 | double value = 0.0; |
616 | if (!float.TryParse(args[2], out value)) | 652 | if (! double.TryParse(args[2], out value)) |
617 | { | 653 | { |
618 | Output.Add(String.Format("The parameter value {0} is not a valid number.", args[2])); | 654 | Output.Add(String.Format("The parameter value {0} is not a valid number.", args[2])); |
655 | return Output; | ||
619 | } | 656 | } |
620 | 657 | ||
621 | switch (args[1].ToLower()) | 658 | SetSunParameter(args[1].ToLower(), value); |
622 | { | ||
623 | case "year_length": | ||
624 | m_YearLengthDays = (int)value; | ||
625 | break; | ||
626 | |||
627 | case "day_length": | ||
628 | m_DayLengthHours = value; | ||
629 | break; | ||
630 | |||
631 | case "day_night_offset": | ||
632 | m_HorizonShift = value; | ||
633 | break; | ||
634 | |||
635 | case "day_time_sun_hour_scale": | ||
636 | m_DayTimeSunHourScale = value; | ||
637 | break; | ||
638 | |||
639 | case "update_interval": | ||
640 | m_UpdateInterval = (int)value; | ||
641 | break; | ||
642 | |||
643 | default: | ||
644 | Output.Add(String.Format("Unknown parameter {0}.", args[1])); | ||
645 | return Output; | ||
646 | } | ||
647 | |||
648 | Output.Add(String.Format("Parameter {0} set to {1}.", args[1], value.ToString())); | 659 | Output.Add(String.Format("Parameter {0} set to {1}.", args[1], value.ToString())); |
649 | |||
650 | // Generate shared values | ||
651 | GenSunPos(); | ||
652 | |||
653 | // When sun settings are updated, we should update all clients with new settings. | ||
654 | SunUpdateToAllClients(); | ||
655 | } | 660 | } |
656 | 661 | ||
657 | return Output; | 662 | return Output; |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs index 7186dd7..89087b1 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs | |||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects | |||
42 | for (y = 0; y < map.Height; y++) | 42 | for (y = 0; y < map.Height; y++) |
43 | { | 43 | { |
44 | map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; | 44 | map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; |
45 | double spherFac = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2, Constants.RegionSize / 2, 50) * 0.01; | 45 | double spherFac = TerrainUtil.SphericalFactor(x, y, map.Width / 2, map.Height / 2, 50) * 0.01; |
46 | if (map[x, y] < spherFac) | 46 | if (map[x, y] < spherFac) |
47 | { | 47 | { |
48 | map[x, y] = spherFac; | 48 | map[x, y] = spherFac; |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs index d78ade5..d5c77ec 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs | |||
@@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
67 | { | 67 | { |
68 | using (Bitmap bitmap = new Bitmap(filename)) | 68 | using (Bitmap bitmap = new Bitmap(filename)) |
69 | { | 69 | { |
70 | ITerrainChannel retval = new TerrainChannel(true); | 70 | ITerrainChannel retval = new TerrainChannel(w, h); |
71 | 71 | ||
72 | for (int x = 0; x < retval.Width; x++) | 72 | for (int x = 0; x < retval.Width; x++) |
73 | { | 73 | { |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs index 62d232e..be1fb24 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.IO; | 29 | using System.IO; |
30 | using OpenSim.Framework; | ||
30 | using OpenSim.Region.Framework.Interfaces; | 31 | using OpenSim.Region.Framework.Interfaces; |
31 | using OpenSim.Region.Framework.Scenes; | 32 | using OpenSim.Region.Framework.Scenes; |
32 | 33 | ||
@@ -73,12 +74,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
73 | public ITerrainChannel LoadFile(string filename) | 74 | public ITerrainChannel LoadFile(string filename) |
74 | { | 75 | { |
75 | FileInfo file = new FileInfo(filename); | 76 | FileInfo file = new FileInfo(filename); |
76 | FileStream s = file.Open(FileMode.Open, FileAccess.Read); | ||
77 | ITerrainChannel retval = LoadStream(s); | ||
78 | 77 | ||
79 | s.Close(); | 78 | ITerrainChannel channel; |
80 | 79 | ||
81 | return retval; | 80 | using (FileStream s = file.Open(FileMode.Open, FileAccess.Read)) |
81 | channel = LoadStream(s); | ||
82 | |||
83 | return channel; | ||
82 | } | 84 | } |
83 | 85 | ||
84 | public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight) | 86 | public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight) |
@@ -86,153 +88,159 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
86 | TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight); | 88 | TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight); |
87 | 89 | ||
88 | FileInfo file = new FileInfo(filename); | 90 | FileInfo file = new FileInfo(filename); |
89 | FileStream s = file.Open(FileMode.Open, FileAccess.Read); | ||
90 | BinaryReader bs = new BinaryReader(s); | ||
91 | 91 | ||
92 | int currFileYOffset = fileHeight - 1; | 92 | using (FileStream s = file.Open(FileMode.Open, FileAccess.Read)) |
93 | 93 | using (BinaryReader bs = new BinaryReader(s)) | |
94 | // if our region isn't on the first Y section of the areas to be landscaped, then | ||
95 | // advance to our section of the file | ||
96 | while (currFileYOffset > offsetY) | ||
97 | { | 94 | { |
98 | // read a whole strip of regions | 95 | int currFileYOffset = fileHeight - 1; |
99 | int heightsToRead = sectionHeight * (fileWidth * sectionWidth); | ||
100 | bs.ReadBytes(heightsToRead * 13); // because there are 13 fun channels | ||
101 | currFileYOffset--; | ||
102 | } | ||
103 | 96 | ||
104 | // got to the Y start offset within the file of our region | 97 | // if our region isn't on the first Y section of the areas to be landscaped, then |
105 | // so read the file bits associated with our region | 98 | // advance to our section of the file |
106 | int y; | 99 | while (currFileYOffset > offsetY) |
107 | // for each Y within our Y offset | ||
108 | for (y = sectionHeight - 1; y >= 0; y--) | ||
109 | { | ||
110 | int currFileXOffset = 0; | ||
111 | |||
112 | // if our region isn't the first X section of the areas to be landscaped, then | ||
113 | // advance the stream to the X start pos of our section in the file | ||
114 | // i.e. eat X upto where we start | ||
115 | while (currFileXOffset < offsetX) | ||
116 | { | 100 | { |
117 | bs.ReadBytes(sectionWidth * 13); | 101 | // read a whole strip of regions |
118 | currFileXOffset++; | 102 | int heightsToRead = sectionHeight * (fileWidth * sectionWidth); |
103 | bs.ReadBytes(heightsToRead * 13); // because there are 13 fun channels | ||
104 | currFileYOffset--; | ||
119 | } | 105 | } |
120 | 106 | ||
121 | // got to our X offset, so write our regions X line | 107 | // got to the Y start offset within the file of our region |
122 | int x; | 108 | // so read the file bits associated with our region |
123 | for (x = 0; x < sectionWidth; x++) | 109 | int y; |
124 | { | ||
125 | // Read a strip and continue | ||
126 | retval[x, y] = bs.ReadByte() * (bs.ReadByte() / 128.0); | ||
127 | bs.ReadBytes(11); | ||
128 | } | ||
129 | // record that we wrote it | ||
130 | currFileXOffset++; | ||
131 | 110 | ||
132 | // if our region isn't the last X section of the areas to be landscaped, then | 111 | // for each Y within our Y offset |
133 | // advance the stream to the end of this Y column | 112 | for (y = sectionHeight - 1; y >= 0; y--) |
134 | while (currFileXOffset < fileWidth) | ||
135 | { | 113 | { |
136 | // eat the next regions x line | 114 | int currFileXOffset = 0; |
137 | bs.ReadBytes(sectionWidth * 13); //The 13 channels again | 115 | |
116 | // if our region isn't the first X section of the areas to be landscaped, then | ||
117 | // advance the stream to the X start pos of our section in the file | ||
118 | // i.e. eat X upto where we start | ||
119 | while (currFileXOffset < offsetX) | ||
120 | { | ||
121 | bs.ReadBytes(sectionWidth * 13); | ||
122 | currFileXOffset++; | ||
123 | } | ||
124 | |||
125 | // got to our X offset, so write our regions X line | ||
126 | int x; | ||
127 | for (x = 0; x < sectionWidth; x++) | ||
128 | { | ||
129 | // Read a strip and continue | ||
130 | retval[x, y] = bs.ReadByte() * (bs.ReadByte() / 128.0); | ||
131 | bs.ReadBytes(11); | ||
132 | } | ||
133 | // record that we wrote it | ||
138 | currFileXOffset++; | 134 | currFileXOffset++; |
135 | |||
136 | // if our region isn't the last X section of the areas to be landscaped, then | ||
137 | // advance the stream to the end of this Y column | ||
138 | while (currFileXOffset < fileWidth) | ||
139 | { | ||
140 | // eat the next regions x line | ||
141 | bs.ReadBytes(sectionWidth * 13); //The 13 channels again | ||
142 | currFileXOffset++; | ||
143 | } | ||
139 | } | 144 | } |
140 | } | 145 | } |
141 | 146 | ||
142 | bs.Close(); | ||
143 | s.Close(); | ||
144 | |||
145 | return retval; | 147 | return retval; |
146 | } | 148 | } |
147 | 149 | ||
148 | public ITerrainChannel LoadStream(Stream s) | 150 | public ITerrainChannel LoadStream(Stream s) |
149 | { | 151 | { |
150 | TerrainChannel retval = new TerrainChannel(); | 152 | // The raw format doesn't contain any dimension information. |
153 | // Guess the square dimensions by using the length of the raw file. | ||
154 | double dimension = Math.Sqrt((double)(s.Length / 13)); | ||
155 | // Regions are always multiples of 256. | ||
156 | int trimmedDimension = (int)dimension - ((int)dimension % (int)Constants.RegionSize); | ||
157 | if (trimmedDimension < Constants.RegionSize) | ||
158 | trimmedDimension = (int)Constants.RegionSize; | ||
159 | |||
160 | TerrainChannel retval = new TerrainChannel(trimmedDimension, trimmedDimension); | ||
151 | 161 | ||
152 | BinaryReader bs = new BinaryReader(s); | 162 | using (BinaryReader bs = new BinaryReader(s)) |
153 | int y; | ||
154 | for (y = 0; y < retval.Height; y++) | ||
155 | { | 163 | { |
156 | int x; | 164 | int y; |
157 | for (x = 0; x < retval.Width; x++) | 165 | for (y = 0; y < retval.Height; y++) |
158 | { | 166 | { |
159 | retval[x, (retval.Height - 1) - y] = bs.ReadByte() * (bs.ReadByte() / 128.0); | 167 | int x; |
160 | bs.ReadBytes(11); // Advance the stream to next bytes. | 168 | for (x = 0; x < retval.Width; x++) |
169 | { | ||
170 | retval[x, (retval.Height - 1) - y] = bs.ReadByte() * (bs.ReadByte() / 128.0); | ||
171 | bs.ReadBytes(11); // Advance the stream to next bytes. | ||
172 | } | ||
161 | } | 173 | } |
162 | } | 174 | } |
163 | 175 | ||
164 | bs.Close(); | ||
165 | |||
166 | return retval; | 176 | return retval; |
167 | } | 177 | } |
168 | 178 | ||
169 | public void SaveFile(string filename, ITerrainChannel map) | 179 | public void SaveFile(string filename, ITerrainChannel map) |
170 | { | 180 | { |
171 | FileInfo file = new FileInfo(filename); | 181 | FileInfo file = new FileInfo(filename); |
172 | FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write); | ||
173 | SaveStream(s, map); | ||
174 | 182 | ||
175 | s.Close(); | 183 | using (FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write)) |
184 | SaveStream(s, map); | ||
176 | } | 185 | } |
177 | 186 | ||
178 | public void SaveStream(Stream s, ITerrainChannel map) | 187 | public void SaveStream(Stream s, ITerrainChannel map) |
179 | { | 188 | { |
180 | BinaryWriter binStream = new BinaryWriter(s); | 189 | using (BinaryWriter binStream = new BinaryWriter(s)) |
181 | |||
182 | // Output the calculated raw | ||
183 | for (int y = 0; y < map.Height; y++) | ||
184 | { | 190 | { |
185 | for (int x = 0; x < map.Width; x++) | 191 | // Output the calculated raw |
192 | for (int y = 0; y < map.Height; y++) | ||
186 | { | 193 | { |
187 | double t = map[x, (map.Height - 1) - y]; | 194 | for (int x = 0; x < map.Width; x++) |
188 | //if height is less than 0, set it to 0 as | ||
189 | //can't save -ve values in a LLRAW file | ||
190 | if (t < 0d) | ||
191 | { | 195 | { |
192 | t = 0d; | 196 | double t = map[x, (map.Height - 1) - y]; |
197 | //if height is less than 0, set it to 0 as | ||
198 | //can't save -ve values in a LLRAW file | ||
199 | if (t < 0d) | ||
200 | { | ||
201 | t = 0d; | ||
202 | } | ||
203 | |||
204 | int index = 0; | ||
205 | |||
206 | // The lookup table is pre-sorted, so we either find an exact match or | ||
207 | // the next closest (smaller) match with a binary search | ||
208 | index = Array.BinarySearch<HeightmapLookupValue>(LookupHeightTable, new HeightmapLookupValue(0, (float)t)); | ||
209 | if (index < 0) | ||
210 | index = ~index - 1; | ||
211 | |||
212 | index = LookupHeightTable[index].Index; | ||
213 | |||
214 | byte red = (byte) (index & 0xFF); | ||
215 | byte green = (byte) ((index >> 8) & 0xFF); | ||
216 | const byte blue = 20; | ||
217 | const byte alpha1 = 0; | ||
218 | const byte alpha2 = 0; | ||
219 | const byte alpha3 = 0; | ||
220 | const byte alpha4 = 0; | ||
221 | const byte alpha5 = 255; | ||
222 | const byte alpha6 = 255; | ||
223 | const byte alpha7 = 255; | ||
224 | const byte alpha8 = 255; | ||
225 | byte alpha9 = red; | ||
226 | byte alpha10 = green; | ||
227 | |||
228 | binStream.Write(red); | ||
229 | binStream.Write(green); | ||
230 | binStream.Write(blue); | ||
231 | binStream.Write(alpha1); | ||
232 | binStream.Write(alpha2); | ||
233 | binStream.Write(alpha3); | ||
234 | binStream.Write(alpha4); | ||
235 | binStream.Write(alpha5); | ||
236 | binStream.Write(alpha6); | ||
237 | binStream.Write(alpha7); | ||
238 | binStream.Write(alpha8); | ||
239 | binStream.Write(alpha9); | ||
240 | binStream.Write(alpha10); | ||
193 | } | 241 | } |
194 | |||
195 | int index = 0; | ||
196 | |||
197 | // The lookup table is pre-sorted, so we either find an exact match or | ||
198 | // the next closest (smaller) match with a binary search | ||
199 | index = Array.BinarySearch<HeightmapLookupValue>(LookupHeightTable, new HeightmapLookupValue(0, (float)t)); | ||
200 | if (index < 0) | ||
201 | index = ~index - 1; | ||
202 | |||
203 | index = LookupHeightTable[index].Index; | ||
204 | |||
205 | byte red = (byte) (index & 0xFF); | ||
206 | byte green = (byte) ((index >> 8) & 0xFF); | ||
207 | const byte blue = 20; | ||
208 | const byte alpha1 = 0; | ||
209 | const byte alpha2 = 0; | ||
210 | const byte alpha3 = 0; | ||
211 | const byte alpha4 = 0; | ||
212 | const byte alpha5 = 255; | ||
213 | const byte alpha6 = 255; | ||
214 | const byte alpha7 = 255; | ||
215 | const byte alpha8 = 255; | ||
216 | byte alpha9 = red; | ||
217 | byte alpha10 = green; | ||
218 | |||
219 | binStream.Write(red); | ||
220 | binStream.Write(green); | ||
221 | binStream.Write(blue); | ||
222 | binStream.Write(alpha1); | ||
223 | binStream.Write(alpha2); | ||
224 | binStream.Write(alpha3); | ||
225 | binStream.Write(alpha4); | ||
226 | binStream.Write(alpha5); | ||
227 | binStream.Write(alpha6); | ||
228 | binStream.Write(alpha7); | ||
229 | binStream.Write(alpha8); | ||
230 | binStream.Write(alpha9); | ||
231 | binStream.Write(alpha10); | ||
232 | } | 242 | } |
233 | } | 243 | } |
234 | |||
235 | binStream.Close(); | ||
236 | } | 244 | } |
237 | 245 | ||
238 | public string FileExtension | 246 | public string FileExtension |
@@ -259,7 +267,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
259 | public bool SupportsTileSave() | 267 | public bool SupportsTileSave() |
260 | { | 268 | { |
261 | return false; | 269 | return false; |
262 | } | 270 | } |
263 | |||
264 | } | 271 | } |
265 | } | 272 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs index 9fb7ef7..d467abb 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs | |||
@@ -25,7 +25,10 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | ||
28 | using System.IO; | 29 | using System.IO; |
30 | |||
31 | using OpenSim.Framework; | ||
29 | using OpenSim.Region.Framework.Interfaces; | 32 | using OpenSim.Region.Framework.Interfaces; |
30 | using OpenSim.Region.Framework.Scenes; | 33 | using OpenSim.Region.Framework.Scenes; |
31 | 34 | ||
@@ -116,7 +119,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
116 | 119 | ||
117 | public ITerrainChannel LoadStream(Stream s) | 120 | public ITerrainChannel LoadStream(Stream s) |
118 | { | 121 | { |
119 | TerrainChannel retval = new TerrainChannel(); | 122 | // The raw format doesn't contain any dimension information. |
123 | // Guess the square dimensions by using the length of the raw file. | ||
124 | double dimension = Math.Sqrt((double)(s.Length / 4)); | ||
125 | // Regions are always multiples of 256. | ||
126 | int trimmedDimension = (int)dimension - ((int)dimension % (int)Constants.RegionSize); | ||
127 | if (trimmedDimension < Constants.RegionSize) | ||
128 | trimmedDimension = (int)Constants.RegionSize; | ||
129 | |||
130 | TerrainChannel retval = new TerrainChannel(trimmedDimension, trimmedDimension); | ||
120 | 131 | ||
121 | BinaryReader bs = new BinaryReader(s); | 132 | BinaryReader bs = new BinaryReader(s); |
122 | int y; | 133 | int y; |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs index b5c7d33..219011e 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs | |||
@@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
65 | bool eof = false; | 65 | bool eof = false; |
66 | 66 | ||
67 | int fileXPoints = 0; | 67 | int fileXPoints = 0; |
68 | // int fileYPoints = 0; | 68 | int fileYPoints = 0; |
69 | 69 | ||
70 | // Terragen file | 70 | // Terragen file |
71 | while (eof == false) | 71 | while (eof == false) |
@@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
75 | { | 75 | { |
76 | case "SIZE": | 76 | case "SIZE": |
77 | fileXPoints = bs.ReadInt16() + 1; | 77 | fileXPoints = bs.ReadInt16() + 1; |
78 | // fileYPoints = fileXPoints; | 78 | fileYPoints = fileXPoints; |
79 | bs.ReadInt16(); | 79 | bs.ReadInt16(); |
80 | break; | 80 | break; |
81 | case "XPTS": | 81 | case "XPTS": |
@@ -83,8 +83,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
83 | bs.ReadInt16(); | 83 | bs.ReadInt16(); |
84 | break; | 84 | break; |
85 | case "YPTS": | 85 | case "YPTS": |
86 | // fileYPoints = bs.ReadInt16(); | 86 | fileYPoints = bs.ReadInt16(); |
87 | bs.ReadInt16(); | ||
88 | bs.ReadInt16(); | 87 | bs.ReadInt16(); |
89 | break; | 88 | break; |
90 | case "ALTW": | 89 | case "ALTW": |
@@ -138,7 +137,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
138 | bs.ReadInt16(); | 137 | bs.ReadInt16(); |
139 | } | 138 | } |
140 | 139 | ||
141 | |||
142 | break; | 140 | break; |
143 | default: | 141 | default: |
144 | bs.ReadInt32(); | 142 | bs.ReadInt32(); |
@@ -154,10 +152,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
154 | 152 | ||
155 | public ITerrainChannel LoadStream(Stream s) | 153 | public ITerrainChannel LoadStream(Stream s) |
156 | { | 154 | { |
157 | 155 | // Set to default size | |
158 | int w = (int)Constants.RegionSize; | 156 | int w = (int)Constants.RegionSize; |
159 | int h = (int)Constants.RegionSize; | 157 | int h = (int)Constants.RegionSize; |
160 | 158 | ||
159 | // create a dummy channel (in case data is bad) | ||
161 | TerrainChannel retval = new TerrainChannel(w, h); | 160 | TerrainChannel retval = new TerrainChannel(w, h); |
162 | 161 | ||
163 | BinaryReader bs = new BinaryReader(s); | 162 | BinaryReader bs = new BinaryReader(s); |
@@ -165,8 +164,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
165 | bool eof = false; | 164 | bool eof = false; |
166 | if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ") | 165 | if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ") |
167 | { | 166 | { |
168 | // int fileWidth = w; | ||
169 | // int fileHeight = h; | ||
170 | 167 | ||
171 | // Terragen file | 168 | // Terragen file |
172 | while (eof == false) | 169 | while (eof == false) |
@@ -175,31 +172,29 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
175 | switch (tmp) | 172 | switch (tmp) |
176 | { | 173 | { |
177 | case "SIZE": | 174 | case "SIZE": |
178 | // int sztmp = bs.ReadInt16() + 1; | 175 | w = bs.ReadInt16() + 1; |
179 | // fileWidth = sztmp; | 176 | h = w; |
180 | // fileHeight = sztmp; | ||
181 | bs.ReadInt16(); | ||
182 | bs.ReadInt16(); | 177 | bs.ReadInt16(); |
183 | break; | 178 | break; |
184 | case "XPTS": | 179 | case "XPTS": |
185 | // fileWidth = bs.ReadInt16(); | 180 | w = bs.ReadInt16(); |
186 | bs.ReadInt16(); | ||
187 | bs.ReadInt16(); | 181 | bs.ReadInt16(); |
188 | break; | 182 | break; |
189 | case "YPTS": | 183 | case "YPTS": |
190 | // fileHeight = bs.ReadInt16(); | 184 | h = bs.ReadInt16(); |
191 | bs.ReadInt16(); | ||
192 | bs.ReadInt16(); | 185 | bs.ReadInt16(); |
193 | break; | 186 | break; |
194 | case "ALTW": | 187 | case "ALTW": |
195 | eof = true; | 188 | eof = true; |
196 | Int16 heightScale = bs.ReadInt16(); | 189 | // create new channel of proper size (now that we know it) |
197 | Int16 baseHeight = bs.ReadInt16(); | 190 | retval = new TerrainChannel(w, h); |
191 | double heightScale = (double)bs.ReadInt16() / 65536.0; | ||
192 | double baseHeight = (double)bs.ReadInt16(); | ||
198 | for (int y = 0; y < h; y++) | 193 | for (int y = 0; y < h; y++) |
199 | { | 194 | { |
200 | for (int x = 0; x < w; x++) | 195 | for (int x = 0; x < w; x++) |
201 | { | 196 | { |
202 | retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0; | 197 | retval[x, y] = baseHeight + (double)bs.ReadInt16() * heightScale; |
203 | } | 198 | } |
204 | } | 199 | } |
205 | break; | 200 | break; |
@@ -209,9 +204,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
209 | } | 204 | } |
210 | } | 205 | } |
211 | } | 206 | } |
212 | |||
213 | bs.Close(); | 207 | bs.Close(); |
214 | |||
215 | return retval; | 208 | return retval; |
216 | } | 209 | } |
217 | 210 | ||
@@ -257,17 +250,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
257 | bs.Write(enc.GetBytes("TERRAGENTERRAIN ")); | 250 | bs.Write(enc.GetBytes("TERRAGENTERRAIN ")); |
258 | 251 | ||
259 | bs.Write(enc.GetBytes("SIZE")); | 252 | bs.Write(enc.GetBytes("SIZE")); |
260 | bs.Write(Convert.ToInt16(Constants.RegionSize)); | 253 | bs.Write(Convert.ToInt16(map.Width)); |
261 | bs.Write(Convert.ToInt16(0)); // necessary padding | 254 | bs.Write(Convert.ToInt16(0)); // necessary padding |
262 | 255 | ||
263 | //The XPTS and YPTS chunks are not needed for square regions | 256 | //The XPTS and YPTS chunks are not needed for square regions |
264 | //but L3DT won't load the terrain file properly without them. | 257 | //but L3DT won't load the terrain file properly without them. |
265 | bs.Write(enc.GetBytes("XPTS")); | 258 | bs.Write(enc.GetBytes("XPTS")); |
266 | bs.Write(Convert.ToInt16(Constants.RegionSize)); | 259 | bs.Write(Convert.ToInt16(map.Width)); |
267 | bs.Write(Convert.ToInt16(0)); // necessary padding | 260 | bs.Write(Convert.ToInt16(0)); // necessary padding |
268 | 261 | ||
269 | bs.Write(enc.GetBytes("YPTS")); | 262 | bs.Write(enc.GetBytes("YPTS")); |
270 | bs.Write(Convert.ToInt16(Constants.RegionSize)); | 263 | bs.Write(Convert.ToInt16(map.Height)); |
271 | bs.Write(Convert.ToInt16(0)); // necessary padding | 264 | bs.Write(Convert.ToInt16(0)); // necessary padding |
272 | 265 | ||
273 | bs.Write(enc.GetBytes("SCAL")); | 266 | bs.Write(enc.GetBytes("SCAL")); |
@@ -283,11 +276,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
283 | bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min | 276 | bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min |
284 | bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point | 277 | bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point |
285 | 278 | ||
279 | double factor = 65536.0 / horizontalScale; // avoid computing this on each iteration | ||
280 | |||
286 | for (int y = 0; y < map.Height; y++) | 281 | for (int y = 0; y < map.Height; y++) |
287 | { | 282 | { |
288 | for (int x = 0; x < map.Width; x++) | 283 | for (int x = 0; x < map.Width; x++) |
289 | { | 284 | { |
290 | float elevation = (float)((map[x,y] - baseHeight) * 65536 ) / (float)horizontalScale; // see LoadStream for inverse | 285 | float elevation = (float)((map[x,y] - baseHeight) * factor); // see LoadStream for inverse |
291 | 286 | ||
292 | // clamp rounding issues | 287 | // clamp rounding issues |
293 | if (elevation > Int16.MaxValue) | 288 | if (elevation > Int16.MaxValue) |
@@ -299,7 +294,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
299 | } | 294 | } |
300 | } | 295 | } |
301 | 296 | ||
302 | //This is only necessary for older versions of Terragen. | 297 | //This is necessary for older versions of Terragen. |
303 | bs.Write(enc.GetBytes("EOF ")); | 298 | bs.Write(enc.GetBytes("EOF ")); |
304 | 299 | ||
305 | bs.Close(); | 300 | bs.Close(); |
@@ -343,7 +338,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
343 | if (BitConverter.IsLittleEndian == false) | 338 | if (BitConverter.IsLittleEndian == false) |
344 | { | 339 | { |
345 | byte[] tmp = new byte[4]; | 340 | byte[] tmp = new byte[4]; |
346 | for (int i = 0; i < 4; i++) | 341 | for (int i = 3; i >= 0; i--) |
347 | { | 342 | { |
348 | tmp[i] = retVal[3 - i]; | 343 | tmp[i] = retVal[3 - i]; |
349 | } | 344 | } |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs index 630473e..b6c635c 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs | |||
@@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes | |||
45 | { | 45 | { |
46 | if (fillArea[x, y]) | 46 | if (fillArea[x, y]) |
47 | { | 47 | { |
48 | double noise = TerrainUtil.PerlinNoise2D((double) x / Constants.RegionSize, (double) y / Constants.RegionSize, 8, 1.0); | 48 | double noise = TerrainUtil.PerlinNoise2D((double) x / map.Width, (double) y / map.Height, 8, 1.0); |
49 | 49 | ||
50 | map[x, y] += noise * strength; | 50 | map[x, y] += noise * strength; |
51 | } | 51 | } |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs new file mode 100644 index 0000000..78a43db --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs | |||
@@ -0,0 +1,60 @@ | |||
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 OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain | ||
32 | { | ||
33 | public interface ITerrainFeature | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Creates the feature. | ||
37 | /// </summary> | ||
38 | /// <returns> | ||
39 | /// Empty string if successful, otherwise error message. | ||
40 | /// </returns> | ||
41 | /// <param name='map'> | ||
42 | /// ITerrainChannel holding terrain data. | ||
43 | /// </param> | ||
44 | /// <param name='args'> | ||
45 | /// command-line arguments from console. | ||
46 | /// </param> | ||
47 | string CreateFeature(ITerrainChannel map, string[] args); | ||
48 | |||
49 | /// <summary> | ||
50 | /// Gets a string describing the usage. | ||
51 | /// </summary> | ||
52 | /// <returns> | ||
53 | /// A string describing parameters for creating the feature. | ||
54 | /// Format is "feature-name <arg1> <arg2> ..." | ||
55 | /// </returns> | ||
56 | string GetUsage(); | ||
57 | } | ||
58 | |||
59 | } | ||
60 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs new file mode 100644 index 0000000..0e0a0e4 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs | |||
@@ -0,0 +1,77 @@ | |||
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 OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain | ||
32 | { | ||
33 | public interface ITerrainModifier | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Creates the feature. | ||
37 | /// </summary> | ||
38 | /// <returns> | ||
39 | /// Empty string if successful, otherwise error message. | ||
40 | /// </returns> | ||
41 | /// <param name='map'> | ||
42 | /// ITerrainChannel holding terrain data. | ||
43 | /// </param> | ||
44 | /// <param name='args'> | ||
45 | /// command-line arguments from console. | ||
46 | /// </param> | ||
47 | string ModifyTerrain(ITerrainChannel map, string[] args); | ||
48 | |||
49 | /// <summary> | ||
50 | /// Gets a string describing the usage. | ||
51 | /// </summary> | ||
52 | /// <returns> | ||
53 | /// A string describing parameters for creating the feature. | ||
54 | /// Format is "feature-name <arg1> <arg2> ..." | ||
55 | /// </returns> | ||
56 | string GetUsage(); | ||
57 | |||
58 | /// <summary> | ||
59 | /// Apply the appropriate operation on the specified map, at (x, y). | ||
60 | /// </summary> | ||
61 | /// <param name='map'> | ||
62 | /// Map. | ||
63 | /// </param> | ||
64 | /// <param name='data'> | ||
65 | /// Data. | ||
66 | /// </param> | ||
67 | /// <param name='x'> | ||
68 | /// X. | ||
69 | /// </param> | ||
70 | /// <param name='y'> | ||
71 | /// Y. | ||
72 | /// </param> | ||
73 | double operate(double[,] map, TerrainModifierData data, int x, int y); | ||
74 | } | ||
75 | |||
76 | } | ||
77 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs new file mode 100644 index 0000000..32f1de9 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs | |||
@@ -0,0 +1,93 @@ | |||
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 | |||
29 | using OpenSim.Region.CoreModules.World.Terrain; | ||
30 | using OpenSim.Region.Framework.Interfaces; | ||
31 | |||
32 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
33 | { | ||
34 | public class FillModifier : TerrainModifier | ||
35 | { | ||
36 | |||
37 | public FillModifier(ITerrainModule module) : base(module) | ||
38 | { | ||
39 | } | ||
40 | |||
41 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
42 | { | ||
43 | string result; | ||
44 | if (args.Length < 3) | ||
45 | { | ||
46 | result = "Usage: " + GetUsage(); | ||
47 | } | ||
48 | else | ||
49 | { | ||
50 | TerrainModifierData data; | ||
51 | result = this.parseParameters(args, out data); | ||
52 | |||
53 | // Context-specific validation | ||
54 | if (result == String.Empty) | ||
55 | { | ||
56 | if (data.shape == String.Empty) | ||
57 | { | ||
58 | data.shape = "rectangle"; | ||
59 | data.x0 = 0; | ||
60 | data.y0 = 0; | ||
61 | data.dx = map.Width; | ||
62 | data.dy = map.Height; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | // if it's all good, then do the work | ||
67 | if (result == String.Empty) | ||
68 | { | ||
69 | this.applyModification(map, data); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | return result; | ||
74 | } | ||
75 | |||
76 | public override string GetUsage() | ||
77 | { | ||
78 | string val = "fill <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]" | ||
79 | + "\nSets all points within the specified range to the specified value."; | ||
80 | return val; | ||
81 | } | ||
82 | |||
83 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
84 | { | ||
85 | double factor = this.computeBevel(data, x, y); | ||
86 | double result = data.elevation - (data.elevation - data.bevelevation) * factor; | ||
87 | return result; | ||
88 | } | ||
89 | |||
90 | } | ||
91 | |||
92 | } | ||
93 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs new file mode 100644 index 0000000..2ab4bcc --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs | |||
@@ -0,0 +1,92 @@ | |||
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 OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class LowerModifier : TerrainModifier | ||
34 | { | ||
35 | public LowerModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.shape == String.Empty) | ||
55 | { | ||
56 | data.shape = "rectangle"; | ||
57 | data.x0 = 0; | ||
58 | data.y0 = 0; | ||
59 | data.dx = map.Width; | ||
60 | data.dy = map.Height; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // if it's all good, then do the work | ||
65 | if (result == String.Empty) | ||
66 | { | ||
67 | this.applyModification(map, data); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return result; | ||
72 | } | ||
73 | |||
74 | public override string GetUsage() | ||
75 | { | ||
76 | string val = "lower <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]" | ||
77 | + "\nLowers all points within the specified range by the specified amount."; | ||
78 | return val; | ||
79 | |||
80 | } | ||
81 | |||
82 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
83 | { | ||
84 | double factor = this.computeBevel(data, x, y); | ||
85 | double result = map[x, y] - (data.elevation - (data.elevation - data.bevelevation) * factor); | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs new file mode 100644 index 0000000..0939c0a --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs | |||
@@ -0,0 +1,92 @@ | |||
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 OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class MaxModifier : TerrainModifier | ||
34 | { | ||
35 | public MaxModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.shape == String.Empty) | ||
55 | { | ||
56 | data.shape = "rectangle"; | ||
57 | data.x0 = 0; | ||
58 | data.y0 = 0; | ||
59 | data.dx = map.Width; | ||
60 | data.dy = map.Height; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // if it's all good, then do the work | ||
65 | if (result == String.Empty) | ||
66 | { | ||
67 | this.applyModification(map, data); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return result; | ||
72 | } | ||
73 | |||
74 | public override string GetUsage() | ||
75 | { | ||
76 | string val = "max <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]" | ||
77 | + "\nEnsures that all points within the specified range are no higher than the specified value."; | ||
78 | return val; | ||
79 | |||
80 | } | ||
81 | |||
82 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
83 | { | ||
84 | double factor = this.computeBevel(data, x, y); | ||
85 | double result = Math.Min(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]); | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs new file mode 100644 index 0000000..cbbccc0 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs | |||
@@ -0,0 +1,92 @@ | |||
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 OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class MinModifier : TerrainModifier | ||
34 | { | ||
35 | public MinModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.shape == String.Empty) | ||
55 | { | ||
56 | data.shape = "rectangle"; | ||
57 | data.x0 = 0; | ||
58 | data.y0 = 0; | ||
59 | data.dx = map.Width; | ||
60 | data.dy = map.Height; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // if it's all good, then do the work | ||
65 | if (result == String.Empty) | ||
66 | { | ||
67 | this.applyModification(map, data); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return result; | ||
72 | } | ||
73 | |||
74 | public override string GetUsage() | ||
75 | { | ||
76 | string val = "min <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]" | ||
77 | + "\nEnsures that all points within the specified range are no lower than the specified value."; | ||
78 | return val; | ||
79 | |||
80 | } | ||
81 | |||
82 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
83 | { | ||
84 | double factor = this.computeBevel(data, x, y); | ||
85 | double result = Math.Max(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]); | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs new file mode 100644 index 0000000..d6b95d0 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs | |||
@@ -0,0 +1,108 @@ | |||
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 OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | using OpenSim.Region.Framework.Scenes; | ||
31 | |||
32 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
33 | { | ||
34 | public class NoiseModifier : TerrainModifier | ||
35 | { | ||
36 | public NoiseModifier(ITerrainModule module) : base(module) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
41 | { | ||
42 | string result; | ||
43 | if (args.Length < 3) | ||
44 | { | ||
45 | result = "Usage: " + GetUsage(); | ||
46 | } | ||
47 | else | ||
48 | { | ||
49 | TerrainModifierData data; | ||
50 | result = this.parseParameters(args, out data); | ||
51 | |||
52 | // Context-specific validation | ||
53 | if (result == String.Empty) | ||
54 | { | ||
55 | if (data.bevel == "taper") | ||
56 | { | ||
57 | if (data.bevelevation < 0.0 || data.bevelevation > 1.0) | ||
58 | { | ||
59 | result = String.Format("Taper must be 0.0 to 1.0: {0}", data.bevelevation); | ||
60 | } | ||
61 | } | ||
62 | else | ||
63 | { | ||
64 | data.bevelevation = 1.0f; | ||
65 | } | ||
66 | |||
67 | if (data.elevation < 0.0 || data.elevation > 1.0) | ||
68 | { | ||
69 | result = String.Format("Noise strength must be 0.0 to 1.0: {0}", data.elevation); | ||
70 | } | ||
71 | |||
72 | if (data.shape == String.Empty) | ||
73 | { | ||
74 | data.shape = "rectangle"; | ||
75 | data.x0 = 0; | ||
76 | data.y0 = 0; | ||
77 | data.dx = map.Width; | ||
78 | data.dy = map.Height; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | // if it's all good, then do the work | ||
83 | if (result == String.Empty) | ||
84 | { | ||
85 | this.applyModification(map, data); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | return result; | ||
90 | } | ||
91 | |||
92 | public override string GetUsage() | ||
93 | { | ||
94 | string val = "noise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]" | ||
95 | + "\nAdds noise to all points within the specified range."; | ||
96 | return val; | ||
97 | } | ||
98 | |||
99 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
100 | { | ||
101 | double factor = this.computeBevel(data, x, y); | ||
102 | double noise = TerrainUtil.PerlinNoise2D((double)x / map.GetLength(0), (double)y / map.GetLength(1), 8, 1.0); | ||
103 | return map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor) * (noise - .5); | ||
104 | } | ||
105 | |||
106 | } | ||
107 | |||
108 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs new file mode 100644 index 0000000..35fb9d6 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs | |||
@@ -0,0 +1,92 @@ | |||
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 OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class RaiseModifier : TerrainModifier | ||
34 | { | ||
35 | public RaiseModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.shape == String.Empty) | ||
55 | { | ||
56 | data.shape = "rectangle"; | ||
57 | data.x0 = 0; | ||
58 | data.y0 = 0; | ||
59 | data.dx = map.Width; | ||
60 | data.dy = map.Height; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // if it's all good, then do the work | ||
65 | if (result == String.Empty) | ||
66 | { | ||
67 | this.applyModification(map, data); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return result; | ||
72 | } | ||
73 | |||
74 | public override string GetUsage() | ||
75 | { | ||
76 | string val = "raise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]" | ||
77 | + "\nRaises all points within the specified range by the specified amount."; | ||
78 | return val; | ||
79 | |||
80 | } | ||
81 | |||
82 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
83 | { | ||
84 | double factor = this.computeBevel(data, x, y); | ||
85 | double result = map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor); | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs new file mode 100644 index 0000000..9f8d5b2 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs | |||
@@ -0,0 +1,131 @@ | |||
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 OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class SmoothModifier : TerrainModifier | ||
34 | { | ||
35 | public SmoothModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.bevel == "taper") | ||
55 | { | ||
56 | if (data.bevelevation < 0.01 || data.bevelevation > 0.99) | ||
57 | { | ||
58 | result = String.Format("Taper must be 0.01 to 0.99: {0}", data.bevelevation); | ||
59 | } | ||
60 | } | ||
61 | else | ||
62 | { | ||
63 | data.bevelevation = 2.0f / 3.0f; | ||
64 | } | ||
65 | |||
66 | if (data.elevation < 0.0 || data.elevation > 1.0) | ||
67 | { | ||
68 | result = String.Format("Smoothing strength must be 0.0 to 1.0: {0}", data.elevation); | ||
69 | } | ||
70 | |||
71 | if (data.shape == String.Empty) | ||
72 | { | ||
73 | data.shape = "rectangle"; | ||
74 | data.x0 = 0; | ||
75 | data.y0 = 0; | ||
76 | data.dx = map.Width; | ||
77 | data.dy = map.Height; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // if it's all good, then do the work | ||
82 | if (result == String.Empty) | ||
83 | { | ||
84 | this.applyModification(map, data); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | return result; | ||
89 | } | ||
90 | |||
91 | public override string GetUsage() | ||
92 | { | ||
93 | string val = "smooth <strength> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<fraction>]" | ||
94 | + "\nSmooths all points within the specified range using a simple averaging algorithm."; | ||
95 | return val; | ||
96 | } | ||
97 | |||
98 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
99 | { | ||
100 | double[] scale = new double[3]; | ||
101 | scale[0] = data.elevation; | ||
102 | scale[1] = ((1.0 - scale[0]) * data.bevelevation) / 8.0; | ||
103 | scale[2] = ((1.0 - scale[0]) * (1.0 - data.bevelevation)) / 16.0; | ||
104 | int xMax = map.GetLength(0); | ||
105 | int yMax = map.GetLength(1); | ||
106 | double result; | ||
107 | if ((x == 0) || (y == 0) || (x == (xMax - 1)) || (y == (yMax - 1))) | ||
108 | { | ||
109 | result = map[x, y]; | ||
110 | } | ||
111 | else | ||
112 | { | ||
113 | result = 0.0; | ||
114 | for(int yPos = (y - 2); yPos < (y + 3); yPos++) | ||
115 | { | ||
116 | int yVal = (yPos <= 0) ? 0 : ((yPos < yMax) ? yPos : yMax - 1); | ||
117 | for(int xPos = (x - 2); xPos < (x + 3); xPos++) | ||
118 | { | ||
119 | int xVal = (xPos <= 0) ? 0 : ((xPos < xMax) ? xPos : xMax - 1); | ||
120 | int dist = Math.Max(Math.Abs(x - xVal), Math.Abs(y - yVal)); | ||
121 | result += map[xVal, yVal] * scale[dist]; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | return result; | ||
126 | } | ||
127 | |||
128 | } | ||
129 | |||
130 | } | ||
131 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs index 989b7d8..e7df3f8 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs | |||
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes | |||
53 | z *= z; | 53 | z *= z; |
54 | z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry)); | 54 | z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry)); |
55 | 55 | ||
56 | double noise = TerrainUtil.PerlinNoise2D(x / (double) Constants.RegionSize, y / (double) Constants.RegionSize, 8, 1.0); | 56 | double noise = TerrainUtil.PerlinNoise2D(x / (double) map.Width, y / (double) map.Height, 8, 1.0); |
57 | 57 | ||
58 | if (z > 0.0) | 58 | if (z > 0.0) |
59 | map[x, y] += noise * z * duration; | 59 | map[x, y] += noise * z * duration; |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs new file mode 100644 index 0000000..7ebd08e --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs | |||
@@ -0,0 +1,378 @@ | |||
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.Reflection; | ||
29 | using log4net; | ||
30 | |||
31 | using OpenSim.Region.Framework.Interfaces; | ||
32 | |||
33 | namespace OpenSim.Region.CoreModules.World.Terrain | ||
34 | { | ||
35 | public abstract class TerrainModifier : ITerrainModifier | ||
36 | { | ||
37 | protected ITerrainModule m_module; | ||
38 | protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
39 | |||
40 | protected TerrainModifier(ITerrainModule module) | ||
41 | { | ||
42 | m_module = module; | ||
43 | } | ||
44 | |||
45 | public abstract string ModifyTerrain(ITerrainChannel map, string[] args); | ||
46 | |||
47 | public abstract string GetUsage(); | ||
48 | |||
49 | public abstract double operate(double[,] map, TerrainModifierData data, int x, int y); | ||
50 | |||
51 | protected String parseParameters(string[] args, out TerrainModifierData data) | ||
52 | { | ||
53 | string val; | ||
54 | string arg; | ||
55 | string result; | ||
56 | data = new TerrainModifierData(); | ||
57 | data.shape = String.Empty; | ||
58 | data.bevel = String.Empty; | ||
59 | data.dx = 0; | ||
60 | data.dy = 0; | ||
61 | if (args.Length < 4) | ||
62 | { | ||
63 | result = "Usage: " + GetUsage(); | ||
64 | } | ||
65 | else | ||
66 | { | ||
67 | result = this.parseFloat(args[3], out data.elevation); | ||
68 | } | ||
69 | if (result == String.Empty) | ||
70 | { | ||
71 | int index = 3; | ||
72 | while(++index < args.Length && result == String.Empty) | ||
73 | { | ||
74 | arg = args[index]; | ||
75 | // check for shape | ||
76 | if (arg.StartsWith("-rec=") || arg.StartsWith("-ell=")) | ||
77 | { | ||
78 | if (data.shape != String.Empty) | ||
79 | { | ||
80 | result = "Only 1 '-rec' or '-ell' parameter is permitted."; | ||
81 | } | ||
82 | else | ||
83 | { | ||
84 | data.shape = arg.StartsWith("-ell=") ? "ellipse" : "rectangle"; | ||
85 | val = arg.Substring(arg.IndexOf("=") + 1); | ||
86 | string[] coords = val.Split(new char[] {','}); | ||
87 | if ((coords.Length < 3) || (coords.Length > 4)) | ||
88 | { | ||
89 | result = String.Format("Bad format for shape parameter {0}", arg); | ||
90 | } | ||
91 | else | ||
92 | { | ||
93 | result = this.parseInt(coords[0], out data.x0); | ||
94 | if (result == String.Empty) | ||
95 | { | ||
96 | result = this.parseInt(coords[1], out data.y0); | ||
97 | } | ||
98 | if (result == String.Empty) | ||
99 | { | ||
100 | result = this.parseInt(coords[2], out data.dx); | ||
101 | } | ||
102 | if (result == String.Empty) | ||
103 | { | ||
104 | if (coords.Length == 4) | ||
105 | { | ||
106 | result = this.parseInt(coords[3], out data.dy); | ||
107 | } | ||
108 | else | ||
109 | { | ||
110 | data.dy = data.dx; | ||
111 | } | ||
112 | } | ||
113 | if (result == String.Empty) | ||
114 | { | ||
115 | if ((data.dx <= 0) || (data.dy <= 0)) | ||
116 | { | ||
117 | result = "Shape sizes must be positive integers"; | ||
118 | } | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | result = String.Format("Bad value in shape parameters {0}", arg); | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | else if (arg.StartsWith("-taper=")) | ||
128 | { | ||
129 | if (data.bevel != String.Empty) | ||
130 | { | ||
131 | result = "Only 1 '-taper' parameter is permitted."; | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | data.bevel = "taper"; | ||
136 | val = arg.Substring(arg.IndexOf("=") + 1); | ||
137 | result = this.parseFloat(val, out data.bevelevation); | ||
138 | if (result != String.Empty) | ||
139 | { | ||
140 | result = String.Format("Bad format for taper parameter {0}", arg); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | result = String.Format("Unrecognized parameter {0}", arg); | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | return result; | ||
151 | } | ||
152 | |||
153 | protected string parseFloat(String s, out float f) | ||
154 | { | ||
155 | string result; | ||
156 | double d; | ||
157 | if (Double.TryParse(s, out d)) | ||
158 | { | ||
159 | try | ||
160 | { | ||
161 | f = (float)d; | ||
162 | result = String.Empty; | ||
163 | } | ||
164 | catch(InvalidCastException) | ||
165 | { | ||
166 | result = String.Format("{0} is invalid", s); | ||
167 | f = -1.0f; | ||
168 | } | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | f = -1.0f; | ||
173 | result = String.Format("{0} is invalid", s); | ||
174 | } | ||
175 | return result; | ||
176 | } | ||
177 | |||
178 | protected string parseInt(String s, out int i) | ||
179 | { | ||
180 | string result; | ||
181 | if (Int32.TryParse(s, out i)) | ||
182 | { | ||
183 | result = String.Empty; | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | result = String.Format("{0} is invalid", s); | ||
188 | } | ||
189 | return result; | ||
190 | } | ||
191 | |||
192 | protected void applyModification(ITerrainChannel map, TerrainModifierData data) | ||
193 | { | ||
194 | bool[,] mask; | ||
195 | int xMax; | ||
196 | int yMax; | ||
197 | int xMid; | ||
198 | int yMid; | ||
199 | if (data.shape == "ellipse") | ||
200 | { | ||
201 | mask = this.ellipticalMask(data.dx, data.dy); | ||
202 | xMax = mask.GetLength(0); | ||
203 | yMax = mask.GetLength(1); | ||
204 | xMid = xMax / 2 + xMax % 2; | ||
205 | yMid = yMax / 2 + yMax % 2; | ||
206 | } | ||
207 | else | ||
208 | { | ||
209 | mask = this.rectangularMask(data.dx, data.dy); | ||
210 | xMax = mask.GetLength(0); | ||
211 | yMax = mask.GetLength(1); | ||
212 | xMid = 0; | ||
213 | yMid = 0; | ||
214 | } | ||
215 | // m_log.DebugFormat("Apply {0} mask {1}x{2} @ {3},{4}", data.shape, xMax, yMax, xMid, yMid); | ||
216 | double[,] buffer = map.GetDoubles(); | ||
217 | int yDim = yMax; | ||
218 | while(--yDim >= 0) | ||
219 | { | ||
220 | int yPos = data.y0 + yDim - yMid; | ||
221 | if ((yPos >= 0) && (yPos < map.Height)) | ||
222 | { | ||
223 | int xDim = xMax; | ||
224 | while(--xDim >= 0) | ||
225 | { | ||
226 | int xPos = data.x0 + xDim - xMid; | ||
227 | if ((xPos >= 0) && (xPos < map.Width) && (mask[xDim, yDim])) | ||
228 | { | ||
229 | double endElevation = this.operate(buffer, data, xPos, yPos); | ||
230 | map[xPos, yPos] = endElevation; | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | protected double computeBevel(TerrainModifierData data, int x, int y) | ||
238 | { | ||
239 | int deltaX; | ||
240 | int deltaY; | ||
241 | int xMax; | ||
242 | int yMax; | ||
243 | double factor; | ||
244 | if (data.bevel == "taper") | ||
245 | { | ||
246 | if (data.shape == "ellipse") | ||
247 | { | ||
248 | deltaX = x - data.x0; | ||
249 | deltaY = y - data.y0; | ||
250 | xMax = data.dx; | ||
251 | yMax = data.dy; | ||
252 | factor = (double)((deltaX * deltaX) + (deltaY * deltaY)); | ||
253 | factor /= ((xMax * xMax) + (yMax * yMax)); | ||
254 | } | ||
255 | else | ||
256 | { | ||
257 | // pyramid | ||
258 | xMax = data.dx / 2 + data.dx % 2; | ||
259 | yMax = data.dy / 2 + data.dy % 2; | ||
260 | deltaX = Math.Abs(data.x0 + xMax - x); | ||
261 | deltaY = Math.Abs(data.y0 + yMax - y); | ||
262 | factor = Math.Max(((double)(deltaY) / yMax), ((double)(deltaX) / xMax)); | ||
263 | } | ||
264 | } | ||
265 | else | ||
266 | { | ||
267 | factor = 0.0; | ||
268 | } | ||
269 | return factor; | ||
270 | } | ||
271 | |||
272 | private bool[,] rectangularMask(int xSize, int ySize) | ||
273 | { | ||
274 | bool[,] mask = new bool[xSize, ySize]; | ||
275 | int yPos = ySize; | ||
276 | while(--yPos >= 0) | ||
277 | { | ||
278 | int xPos = xSize; | ||
279 | while(--xPos >= 0) | ||
280 | { | ||
281 | mask[xPos, yPos] = true; | ||
282 | } | ||
283 | } | ||
284 | return mask; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Fast ellipse-based derivative of Bresenham algorithm. | ||
289 | * https://web.archive.org/web/20120225095359/http://homepage.smc.edu/kennedy_john/belipse.pdf | ||
290 | */ | ||
291 | private bool[,] ellipticalMask(int xRadius, int yRadius) | ||
292 | { | ||
293 | long twoASquared = 2L * xRadius * xRadius; | ||
294 | long twoBSquared = 2L * yRadius * yRadius; | ||
295 | |||
296 | bool[,] mask = new bool[2 * xRadius + 1, 2 * yRadius + 1]; | ||
297 | |||
298 | long ellipseError = 0L; | ||
299 | long stoppingX = twoBSquared * xRadius; | ||
300 | long stoppingY = 0L; | ||
301 | long xChange = yRadius * yRadius * (1L - 2L * xRadius); | ||
302 | long yChange = xRadius * xRadius; | ||
303 | |||
304 | int xPos = xRadius; | ||
305 | int yPos = 0; | ||
306 | |||
307 | // first set of points | ||
308 | while(stoppingX >= stoppingY) | ||
309 | { | ||
310 | int yUpper = yRadius + yPos; | ||
311 | int yLower = yRadius - yPos; | ||
312 | // fill in the mask | ||
313 | int xNow = xPos; | ||
314 | while(xNow >= 0) | ||
315 | { | ||
316 | mask[xRadius + xNow, yUpper] = true; | ||
317 | mask[xRadius - xNow, yUpper] = true; | ||
318 | mask[xRadius + xNow, yLower] = true; | ||
319 | mask[xRadius - xNow, yLower] = true; | ||
320 | --xNow; | ||
321 | } | ||
322 | yPos++; | ||
323 | stoppingY += twoASquared; | ||
324 | ellipseError += yChange; | ||
325 | yChange += twoASquared; | ||
326 | if ((2L * ellipseError + xChange) > 0L) | ||
327 | { | ||
328 | xPos--; | ||
329 | stoppingX -= twoBSquared; | ||
330 | ellipseError += xChange; | ||
331 | xChange += twoBSquared; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | // second set of points | ||
336 | xPos = 0; | ||
337 | yPos = yRadius; | ||
338 | xChange = yRadius * yRadius; | ||
339 | yChange = xRadius * xRadius * (1L - 2L * yRadius); | ||
340 | |||
341 | ellipseError = 0L; | ||
342 | stoppingX = 0L; | ||
343 | stoppingY = twoASquared * yRadius; | ||
344 | |||
345 | while(stoppingX <= stoppingY) | ||
346 | { | ||
347 | int xUpper = xRadius + xPos; | ||
348 | int xLower = xRadius - xPos; | ||
349 | // fill in the mask | ||
350 | int yNow = yPos; | ||
351 | while(yNow >= 0) | ||
352 | { | ||
353 | mask[xUpper, yRadius + yNow] = true; | ||
354 | mask[xUpper, yRadius - yNow] = true; | ||
355 | mask[xLower, yRadius + yNow] = true; | ||
356 | mask[xLower, yRadius - yNow] = true; | ||
357 | --yNow; | ||
358 | } | ||
359 | xPos++; | ||
360 | stoppingX += twoBSquared; | ||
361 | ellipseError += xChange; | ||
362 | xChange += twoBSquared; | ||
363 | if ((2L * ellipseError + yChange) > 0L) | ||
364 | { | ||
365 | yPos--; | ||
366 | stoppingY -= twoASquared; | ||
367 | ellipseError += yChange; | ||
368 | yChange += twoASquared; | ||
369 | } | ||
370 | } | ||
371 | return mask; | ||
372 | } | ||
373 | |||
374 | |||
375 | } | ||
376 | |||
377 | } | ||
378 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs new file mode 100644 index 0000000..4e0f8d7 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs | |||
@@ -0,0 +1,17 @@ | |||
1 | using System; | ||
2 | |||
3 | namespace OpenSim.Region.CoreModules.World.Terrain | ||
4 | { | ||
5 | public struct TerrainModifierData | ||
6 | { | ||
7 | public float elevation; | ||
8 | public string shape; | ||
9 | public int x0; | ||
10 | public int y0; | ||
11 | public int dx; | ||
12 | public int dy; | ||
13 | public string bevel; | ||
14 | public float bevelevation; | ||
15 | } | ||
16 | } | ||
17 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index fd30c46..932652c 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | |||
@@ -24,19 +24,24 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | |||
28 | using System; | 27 | using System; |
29 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
30 | using System.IO; | 29 | using System.IO; |
31 | using System.Reflection; | 30 | using System.Reflection; |
32 | using System.Net; | 31 | using System.Net; |
32 | |||
33 | using log4net; | 33 | using log4net; |
34 | using Nini.Config; | 34 | using Nini.Config; |
35 | |||
35 | using OpenMetaverse; | 36 | using OpenMetaverse; |
36 | using Mono.Addins; | 37 | using Mono.Addins; |
38 | |||
39 | using OpenSim.Data; | ||
37 | using OpenSim.Framework; | 40 | using OpenSim.Framework; |
41 | using OpenSim.Framework.Console; | ||
38 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | 42 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; |
39 | using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; | 43 | using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; |
44 | using OpenSim.Region.CoreModules.World.Terrain.Modifiers; | ||
40 | using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; | 45 | using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; |
41 | using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; | 46 | using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; |
42 | using OpenSim.Region.Framework.Interfaces; | 47 | using OpenSim.Region.Framework.Interfaces; |
@@ -70,26 +75,112 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
70 | #endregion | 75 | #endregion |
71 | 76 | ||
72 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 77 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
73 | |||
74 | private readonly Commander m_commander = new Commander("terrain"); | ||
75 | 78 | ||
79 | #pragma warning disable 414 | ||
80 | private static readonly string LogHeader = "[TERRAIN MODULE]"; | ||
81 | #pragma warning restore 414 | ||
82 | |||
83 | private readonly Commander m_commander = new Commander("terrain"); | ||
76 | private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = | 84 | private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = |
77 | new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>(); | 85 | new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>(); |
78 | |||
79 | private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>(); | 86 | private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>(); |
80 | |||
81 | private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = | 87 | private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = |
82 | new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); | 88 | new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); |
83 | |||
84 | private ITerrainChannel m_channel; | ||
85 | private Dictionary<string, ITerrainEffect> m_plugineffects; | 89 | private Dictionary<string, ITerrainEffect> m_plugineffects; |
90 | private Dictionary<string, ITerrainModifier> m_modifyOperations = | ||
91 | new Dictionary<string, ITerrainModifier>(); | ||
92 | private ITerrainChannel m_channel; | ||
86 | private ITerrainChannel m_revert; | 93 | private ITerrainChannel m_revert; |
87 | private Scene m_scene; | 94 | private Scene m_scene; |
88 | private volatile bool m_tainted; | 95 | private volatile bool m_tainted; |
89 | private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); | 96 | private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); |
90 | |||
91 | private String m_InitialTerrain = "pinhead-island"; | 97 | private String m_InitialTerrain = "pinhead-island"; |
92 | 98 | ||
99 | // If true, send terrain patch updates to clients based on their view distance | ||
100 | private bool m_sendTerrainUpdatesByViewDistance = true; | ||
101 | |||
102 | // Class to keep the per client collection of terrain patches that must be sent. | ||
103 | // A patch is set to 'true' meaning it should be sent to the client. Once the | ||
104 | // patch packet is queued to the client, the bit for that patch is set to 'false'. | ||
105 | private class PatchUpdates | ||
106 | { | ||
107 | private bool[,] updated; // for each patch, whether it needs to be sent to this client | ||
108 | private int updateCount; // number of patches that need to be sent | ||
109 | public ScenePresence Presence; // a reference to the client to send to | ||
110 | public TerrainData Terrain; // reference to the underlying terrain | ||
111 | public PatchUpdates(TerrainData terrData, ScenePresence pPresence) | ||
112 | { | ||
113 | updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize]; | ||
114 | updateCount = 0; | ||
115 | Presence = pPresence; | ||
116 | Terrain = terrData; | ||
117 | // Initially, send all patches to the client | ||
118 | SetAll(true); | ||
119 | } | ||
120 | // Returns 'true' if there are any patches marked for sending | ||
121 | public bool HasUpdates() | ||
122 | { | ||
123 | return (updateCount > 0); | ||
124 | } | ||
125 | |||
126 | public void SetByXY(int x, int y, bool state) | ||
127 | { | ||
128 | this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state); | ||
129 | } | ||
130 | |||
131 | public bool GetByPatch(int patchX, int patchY) | ||
132 | { | ||
133 | return updated[patchX, patchY]; | ||
134 | } | ||
135 | |||
136 | public void SetByPatch(int patchX, int patchY, bool state) | ||
137 | { | ||
138 | bool prevState = updated[patchX, patchY]; | ||
139 | if (!prevState && state) | ||
140 | updateCount++; | ||
141 | if (prevState && !state) | ||
142 | updateCount--; | ||
143 | updated[patchX, patchY] = state; | ||
144 | } | ||
145 | |||
146 | public void SetAll(bool state) | ||
147 | { | ||
148 | updateCount = 0; | ||
149 | for(int xx = 0; xx < updated.GetLength(0); xx++) | ||
150 | for(int yy = 0; yy < updated.GetLength(1); yy++) | ||
151 | updated[xx, yy] = state; | ||
152 | if (state) | ||
153 | updateCount = updated.GetLength(0) * updated.GetLength(1); | ||
154 | } | ||
155 | // Logically OR's the terrain data's patch taint map into this client's update map. | ||
156 | public void SetAll(TerrainData terrData) | ||
157 | { | ||
158 | if (updated.GetLength(0) != (terrData.SizeX / Constants.TerrainPatchSize) | ||
159 | || updated.GetLength(1) != (terrData.SizeY / Constants.TerrainPatchSize)) | ||
160 | { | ||
161 | throw new Exception( | ||
162 | String.Format("{0} PatchUpdates.SetAll: patch array not same size as terrain. arr=<{1},{2}>, terr=<{3},{4}>", | ||
163 | LogHeader, updated.GetLength(0), updated.GetLength(1), | ||
164 | terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize) | ||
165 | ); | ||
166 | } | ||
167 | for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) | ||
168 | { | ||
169 | for(int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) | ||
170 | { | ||
171 | // Only set tainted. The patch bit may be set if the patch was to be sent later. | ||
172 | if (terrData.IsTaintedAt(xx, yy, false)) | ||
173 | { | ||
174 | this.SetByXY(xx, yy, true); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | // The flags of which terrain patches to send for each of the ScenePresence's | ||
182 | private Dictionary<UUID, PatchUpdates> m_perClientPatchUpdates = new Dictionary<UUID, PatchUpdates>(); | ||
183 | |||
93 | /// <summary> | 184 | /// <summary> |
94 | /// Human readable list of terrain file extensions that are supported. | 185 | /// Human readable list of terrain file extensions that are supported. |
95 | /// </summary> | 186 | /// </summary> |
@@ -100,8 +191,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
100 | 191 | ||
101 | #region ICommandableModule Members | 192 | #region ICommandableModule Members |
102 | 193 | ||
103 | public ICommander CommandInterface | 194 | public ICommander CommandInterface { |
104 | { | ||
105 | get { return m_commander; } | 195 | get { return m_commander; } |
106 | } | 196 | } |
107 | 197 | ||
@@ -118,7 +208,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
118 | { | 208 | { |
119 | IConfig terrainConfig = config.Configs["Terrain"]; | 209 | IConfig terrainConfig = config.Configs["Terrain"]; |
120 | if (terrainConfig != null) | 210 | if (terrainConfig != null) |
211 | { | ||
121 | m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); | 212 | m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); |
213 | m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance); | ||
214 | } | ||
122 | } | 215 | } |
123 | 216 | ||
124 | public void AddRegion(Scene scene) | 217 | public void AddRegion(Scene scene) |
@@ -126,26 +219,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
126 | m_scene = scene; | 219 | m_scene = scene; |
127 | 220 | ||
128 | // Install terrain module in the simulator | 221 | // Install terrain module in the simulator |
129 | lock (m_scene) | 222 | lock(m_scene) |
130 | { | 223 | { |
131 | if (m_scene.Heightmap == null) | 224 | if (m_scene.Heightmap == null) |
132 | { | 225 | { |
133 | m_channel = new TerrainChannel(m_InitialTerrain); | 226 | m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX, |
227 | (int)m_scene.RegionInfo.RegionSizeY, | ||
228 | (int)m_scene.RegionInfo.RegionSizeZ); | ||
134 | m_scene.Heightmap = m_channel; | 229 | m_scene.Heightmap = m_channel; |
135 | m_revert = new TerrainChannel(); | ||
136 | UpdateRevertMap(); | 230 | UpdateRevertMap(); |
137 | } | 231 | } |
138 | else | 232 | else |
139 | { | 233 | { |
140 | m_channel = m_scene.Heightmap; | 234 | m_channel = m_scene.Heightmap; |
141 | m_revert = new TerrainChannel(); | ||
142 | UpdateRevertMap(); | 235 | UpdateRevertMap(); |
143 | } | 236 | } |
144 | 237 | ||
145 | m_scene.RegisterModuleInterface<ITerrainModule>(this); | 238 | m_scene.RegisterModuleInterface<ITerrainModule>(this); |
146 | m_scene.EventManager.OnNewClient += EventManager_OnNewClient; | 239 | m_scene.EventManager.OnNewClient += EventManager_OnNewClient; |
240 | m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed; | ||
147 | m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; | 241 | m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; |
148 | m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; | 242 | m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; |
243 | m_scene.EventManager.OnFrame += EventManager_OnFrame; | ||
149 | } | 244 | } |
150 | 245 | ||
151 | InstallDefaultEffects(); | 246 | InstallDefaultEffects(); |
@@ -156,7 +251,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
156 | string supportedFilesSeparatorForTileSave = ""; | 251 | string supportedFilesSeparatorForTileSave = ""; |
157 | 252 | ||
158 | m_supportFileExtensionsForTileSave = ""; | 253 | m_supportFileExtensionsForTileSave = ""; |
159 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 254 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
160 | { | 255 | { |
161 | m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; | 256 | m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; |
162 | supportedFilesSeparator = ", "; | 257 | supportedFilesSeparator = ", "; |
@@ -179,13 +274,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
179 | 274 | ||
180 | public void RemoveRegion(Scene scene) | 275 | public void RemoveRegion(Scene scene) |
181 | { | 276 | { |
182 | lock (m_scene) | 277 | lock(m_scene) |
183 | { | 278 | { |
184 | // remove the commands | 279 | // remove the commands |
185 | m_scene.UnregisterModuleCommander(m_commander.Name); | 280 | m_scene.UnregisterModuleCommander(m_commander.Name); |
186 | // remove the event-handlers | 281 | // remove the event-handlers |
282 | m_scene.EventManager.OnFrame -= EventManager_OnFrame; | ||
187 | m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; | 283 | m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; |
188 | m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; | 284 | m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; |
285 | m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed; | ||
189 | m_scene.EventManager.OnNewClient -= EventManager_OnNewClient; | 286 | m_scene.EventManager.OnNewClient -= EventManager_OnNewClient; |
190 | // remove the interface | 287 | // remove the interface |
191 | m_scene.UnregisterModuleInterface<ITerrainModule>(this); | 288 | m_scene.UnregisterModuleInterface<ITerrainModule>(this); |
@@ -196,13 +293,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
196 | { | 293 | { |
197 | } | 294 | } |
198 | 295 | ||
199 | public Type ReplaceableInterface | 296 | public Type ReplaceableInterface { |
200 | { | ||
201 | get { return null; } | 297 | get { return null; } |
202 | } | 298 | } |
203 | 299 | ||
204 | public string Name | 300 | public string Name { |
205 | { | ||
206 | get { return "TerrainModule"; } | 301 | get { return "TerrainModule"; } |
207 | } | 302 | } |
208 | 303 | ||
@@ -221,47 +316,46 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
221 | /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> | 316 | /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> |
222 | public void LoadFromFile(string filename) | 317 | public void LoadFromFile(string filename) |
223 | { | 318 | { |
224 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 319 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
225 | { | 320 | { |
226 | if (filename.EndsWith(loader.Key)) | 321 | if (filename.EndsWith(loader.Key)) |
227 | { | 322 | { |
228 | lock (m_scene) | 323 | lock(m_scene) |
229 | { | 324 | { |
230 | try | 325 | try |
231 | { | 326 | { |
232 | ITerrainChannel channel = loader.Value.LoadFile(filename); | 327 | ITerrainChannel channel = loader.Value.LoadFile(filename); |
233 | if (channel.Width != Constants.RegionSize || channel.Height != Constants.RegionSize) | 328 | if (channel.Width != m_scene.RegionInfo.RegionSizeX || channel.Height != m_scene.RegionInfo.RegionSizeY) |
234 | { | 329 | { |
235 | // TerrainChannel expects a RegionSize x RegionSize map, currently | 330 | // TerrainChannel expects a RegionSize x RegionSize map, currently |
236 | throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}", | 331 | throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}", |
237 | Constants.RegionSize, Constants.RegionSize)); | 332 | m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY)); |
238 | } | 333 | } |
239 | m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); | 334 | m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); |
240 | m_scene.Heightmap = channel; | 335 | m_scene.Heightmap = channel; |
241 | m_channel = channel; | 336 | m_channel = channel; |
242 | UpdateRevertMap(); | 337 | UpdateRevertMap(); |
243 | } | 338 | } |
244 | catch (NotImplementedException) | 339 | catch(NotImplementedException) |
245 | { | 340 | { |
246 | m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + | 341 | m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + |
247 | " parser does not support file loading. (May be save only)"); | 342 | " parser does not support file loading. (May be save only)"); |
248 | throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); | 343 | throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); |
249 | } | 344 | } |
250 | catch (FileNotFoundException) | 345 | catch(FileNotFoundException) |
251 | { | 346 | { |
252 | m_log.Error( | 347 | m_log.Error( |
253 | "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); | 348 | "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); |
254 | throw new TerrainException( | 349 | throw new TerrainException( |
255 | String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); | 350 | String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); |
256 | } | 351 | } |
257 | catch (ArgumentException e) | 352 | catch(ArgumentException e) |
258 | { | 353 | { |
259 | m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message); | 354 | m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message); |
260 | throw new TerrainException( | 355 | throw new TerrainException( |
261 | String.Format("Unable to load heightmap: {0}", e.Message)); | 356 | String.Format("Unable to load heightmap: {0}", e.Message)); |
262 | } | 357 | } |
263 | } | 358 | } |
264 | CheckForTerrainUpdates(); | ||
265 | m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); | 359 | m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); |
266 | return; | 360 | return; |
267 | } | 361 | } |
@@ -279,7 +373,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
279 | { | 373 | { |
280 | try | 374 | try |
281 | { | 375 | { |
282 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 376 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
283 | { | 377 | { |
284 | if (filename.EndsWith(loader.Key)) | 378 | if (filename.EndsWith(loader.Key)) |
285 | { | 379 | { |
@@ -289,7 +383,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
289 | } | 383 | } |
290 | } | 384 | } |
291 | } | 385 | } |
292 | catch (IOException ioe) | 386 | catch(IOException ioe) |
293 | { | 387 | { |
294 | m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message)); | 388 | m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message)); |
295 | } | 389 | } |
@@ -309,27 +403,32 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
309 | LoadFromStream(filename, URIFetch(pathToTerrainHeightmap)); | 403 | LoadFromStream(filename, URIFetch(pathToTerrainHeightmap)); |
310 | } | 404 | } |
311 | 405 | ||
406 | public void LoadFromStream(string filename, Stream stream) | ||
407 | { | ||
408 | LoadFromStream(filename, Vector3.Zero, 0f, Vector2.Zero, stream); | ||
409 | } | ||
410 | |||
312 | /// <summary> | 411 | /// <summary> |
313 | /// Loads a terrain file from a stream and installs it in the scene. | 412 | /// Loads a terrain file from a stream and installs it in the scene. |
314 | /// </summary> | 413 | /// </summary> |
315 | /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> | 414 | /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> |
316 | /// <param name="stream"></param> | 415 | /// <param name="stream"></param> |
317 | public void LoadFromStream(string filename, Stream stream) | 416 | public void LoadFromStream(string filename, Vector3 displacement, |
417 | float radianRotation, Vector2 rotationDisplacement, Stream stream) | ||
318 | { | 418 | { |
319 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 419 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
320 | { | 420 | { |
321 | if (filename.EndsWith(loader.Key)) | 421 | if (filename.EndsWith(loader.Key)) |
322 | { | 422 | { |
323 | lock (m_scene) | 423 | lock(m_scene) |
324 | { | 424 | { |
325 | try | 425 | try |
326 | { | 426 | { |
327 | ITerrainChannel channel = loader.Value.LoadStream(stream); | 427 | ITerrainChannel channel = loader.Value.LoadStream(stream); |
328 | m_scene.Heightmap = channel; | 428 | m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); |
329 | m_channel = channel; | ||
330 | UpdateRevertMap(); | 429 | UpdateRevertMap(); |
331 | } | 430 | } |
332 | catch (NotImplementedException) | 431 | catch(NotImplementedException) |
333 | { | 432 | { |
334 | m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + | 433 | m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + |
335 | " parser does not support file loading. (May be save only)"); | 434 | " parser does not support file loading. (May be save only)"); |
@@ -337,7 +436,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
337 | } | 436 | } |
338 | } | 437 | } |
339 | 438 | ||
340 | CheckForTerrainUpdates(); | ||
341 | m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); | 439 | m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); |
342 | return; | 440 | return; |
343 | } | 441 | } |
@@ -390,7 +488,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
390 | { | 488 | { |
391 | try | 489 | try |
392 | { | 490 | { |
393 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 491 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
394 | { | 492 | { |
395 | if (filename.EndsWith(loader.Key)) | 493 | if (filename.EndsWith(loader.Key)) |
396 | { | 494 | { |
@@ -399,18 +497,56 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
399 | } | 497 | } |
400 | } | 498 | } |
401 | } | 499 | } |
402 | catch (NotImplementedException) | 500 | catch(NotImplementedException) |
403 | { | 501 | { |
404 | m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented."); | 502 | m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented."); |
405 | throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented")); | 503 | throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented")); |
406 | } | 504 | } |
407 | } | 505 | } |
408 | 506 | ||
409 | public void TaintTerrain () | 507 | // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients. |
508 | // ITerrainModule.TaintTerrain() | ||
509 | public void TaintTerrain() | ||
410 | { | 510 | { |
411 | CheckForTerrainUpdates(); | 511 | lock(m_perClientPatchUpdates) |
512 | { | ||
513 | // Set the flags for all clients so the tainted patches will be sent out | ||
514 | foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) | ||
515 | { | ||
516 | pups.SetAll(m_scene.Heightmap.GetTerrainData()); | ||
517 | } | ||
518 | } | ||
412 | } | 519 | } |
413 | 520 | ||
521 | // ITerrainModule.PushTerrain() | ||
522 | public void PushTerrain(IClientAPI pClient) | ||
523 | { | ||
524 | // If view distance based, set the modified patch bits and the frame event will send the updates | ||
525 | if (m_sendTerrainUpdatesByViewDistance) | ||
526 | { | ||
527 | ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); | ||
528 | if (presence != null) | ||
529 | { | ||
530 | lock(m_perClientPatchUpdates) | ||
531 | { | ||
532 | PatchUpdates pups; | ||
533 | if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) | ||
534 | { | ||
535 | // There is a ScenePresence without a send patch map. Create one. | ||
536 | pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence); | ||
537 | m_perClientPatchUpdates.Add(presence.UUID, pups); | ||
538 | } | ||
539 | // By setting all to modified, the next update tick will send the patches | ||
540 | pups.SetAll(true); | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | else | ||
545 | { | ||
546 | // The traditional way is to call into the protocol stack to send them all. | ||
547 | pClient.SendLayerData(new float[10]); | ||
548 | } | ||
549 | } | ||
414 | #region Plugin Loading Methods | 550 | #region Plugin Loading Methods |
415 | 551 | ||
416 | private void LoadPlugins() | 552 | private void LoadPlugins() |
@@ -418,13 +554,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
418 | m_plugineffects = new Dictionary<string, ITerrainEffect>(); | 554 | m_plugineffects = new Dictionary<string, ITerrainEffect>(); |
419 | LoadPlugins(Assembly.GetCallingAssembly()); | 555 | LoadPlugins(Assembly.GetCallingAssembly()); |
420 | string plugineffectsPath = "Terrain"; | 556 | string plugineffectsPath = "Terrain"; |
421 | 557 | ||
422 | // Load the files in the Terrain/ dir | 558 | // Load the files in the Terrain/ dir |
423 | if (!Directory.Exists(plugineffectsPath)) | 559 | if (!Directory.Exists(plugineffectsPath)) |
424 | return; | 560 | return; |
425 | 561 | ||
426 | string[] files = Directory.GetFiles(plugineffectsPath); | 562 | string[] files = Directory.GetFiles(plugineffectsPath); |
427 | foreach (string file in files) | 563 | foreach(string file in files) |
428 | { | 564 | { |
429 | m_log.Info("Loading effects in " + file); | 565 | m_log.Info("Loading effects in " + file); |
430 | try | 566 | try |
@@ -432,7 +568,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
432 | Assembly library = Assembly.LoadFrom(file); | 568 | Assembly library = Assembly.LoadFrom(file); |
433 | LoadPlugins(library); | 569 | LoadPlugins(library); |
434 | } | 570 | } |
435 | catch (BadImageFormatException) | 571 | catch(BadImageFormatException) |
436 | { | 572 | { |
437 | } | 573 | } |
438 | } | 574 | } |
@@ -440,7 +576,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
440 | 576 | ||
441 | private void LoadPlugins(Assembly library) | 577 | private void LoadPlugins(Assembly library) |
442 | { | 578 | { |
443 | foreach (Type pluginType in library.GetTypes()) | 579 | foreach(Type pluginType in library.GetTypes()) |
444 | { | 580 | { |
445 | try | 581 | try |
446 | { | 582 | { |
@@ -462,7 +598,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
462 | m_log.Info("L ... " + typeName); | 598 | m_log.Info("L ... " + typeName); |
463 | } | 599 | } |
464 | } | 600 | } |
465 | catch (AmbiguousMatchException) | 601 | catch(AmbiguousMatchException) |
466 | { | 602 | { |
467 | } | 603 | } |
468 | } | 604 | } |
@@ -470,7 +606,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
470 | 606 | ||
471 | public void InstallPlugin(string pluginName, ITerrainEffect effect) | 607 | public void InstallPlugin(string pluginName, ITerrainEffect effect) |
472 | { | 608 | { |
473 | lock (m_plugineffects) | 609 | lock(m_plugineffects) |
474 | { | 610 | { |
475 | if (!m_plugineffects.ContainsKey(pluginName)) | 611 | if (!m_plugineffects.ContainsKey(pluginName)) |
476 | { | 612 | { |
@@ -513,6 +649,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
513 | m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); | 649 | m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); |
514 | m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); | 650 | m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); |
515 | 651 | ||
652 | // Terrain Modifier operations | ||
653 | m_modifyOperations["min"] = new MinModifier(this); | ||
654 | m_modifyOperations["max"] = new MaxModifier(this); | ||
655 | m_modifyOperations["raise"] = new RaiseModifier(this); | ||
656 | m_modifyOperations["lower"] = new LowerModifier(this); | ||
657 | m_modifyOperations["fill"] = new FillModifier(this); | ||
658 | m_modifyOperations["smooth"] = new SmoothModifier(this); | ||
659 | m_modifyOperations["noise"] = new NoiseModifier(this); | ||
660 | |||
516 | // Filesystem load/save loaders | 661 | // Filesystem load/save loaders |
517 | m_loaders[".r32"] = new RAW32(); | 662 | m_loaders[".r32"] = new RAW32(); |
518 | m_loaders[".f32"] = m_loaders[".r32"]; | 663 | m_loaders[".f32"] = m_loaders[".r32"]; |
@@ -532,6 +677,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
532 | /// </summary> | 677 | /// </summary> |
533 | public void UpdateRevertMap() | 678 | public void UpdateRevertMap() |
534 | { | 679 | { |
680 | /* | ||
535 | int x; | 681 | int x; |
536 | for (x = 0; x < m_channel.Width; x++) | 682 | for (x = 0; x < m_channel.Width; x++) |
537 | { | 683 | { |
@@ -541,6 +687,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
541 | m_revert[x, y] = m_channel[x, y]; | 687 | m_revert[x, y] = m_channel[x, y]; |
542 | } | 688 | } |
543 | } | 689 | } |
690 | */ | ||
691 | m_revert = m_channel.MakeCopy(); | ||
544 | } | 692 | } |
545 | 693 | ||
546 | /// <summary> | 694 | /// <summary> |
@@ -553,22 +701,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
553 | /// <param name="fileStartY">Where to begin our slice</param> | 701 | /// <param name="fileStartY">Where to begin our slice</param> |
554 | public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) | 702 | public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) |
555 | { | 703 | { |
556 | int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX; | 704 | int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX; |
557 | int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY; | 705 | int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY; |
558 | 706 | ||
559 | if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) | 707 | if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) |
560 | { | 708 | { |
561 | // this region is included in the tile request | 709 | // this region is included in the tile request |
562 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 710 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
563 | { | 711 | { |
564 | if (filename.EndsWith(loader.Key)) | 712 | if (filename.EndsWith(loader.Key)) |
565 | { | 713 | { |
566 | lock (m_scene) | 714 | lock(m_scene) |
567 | { | 715 | { |
568 | ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, | 716 | ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, |
569 | fileWidth, fileHeight, | 717 | fileWidth, fileHeight, |
570 | (int) Constants.RegionSize, | 718 | (int)m_scene.RegionInfo.RegionSizeX, |
571 | (int) Constants.RegionSize); | 719 | (int)m_scene.RegionInfo.RegionSizeY); |
572 | m_scene.Heightmap = channel; | 720 | m_scene.Heightmap = channel; |
573 | m_channel = channel; | 721 | m_channel = channel; |
574 | UpdateRevertMap(); | 722 | UpdateRevertMap(); |
@@ -607,23 +755,23 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
607 | } | 755 | } |
608 | 756 | ||
609 | // this region is included in the tile request | 757 | // this region is included in the tile request |
610 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 758 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
611 | { | 759 | { |
612 | if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave()) | 760 | if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave()) |
613 | { | 761 | { |
614 | lock (m_scene) | 762 | lock(m_scene) |
615 | { | 763 | { |
616 | loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, | 764 | loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, |
617 | fileWidth, fileHeight, | 765 | fileWidth, fileHeight, |
618 | (int)Constants.RegionSize, | 766 | (int)m_scene.RegionInfo.RegionSizeX, |
619 | (int)Constants.RegionSize); | 767 | (int)m_scene.RegionInfo.RegionSizeY); |
620 | 768 | ||
621 | MainConsole.Instance.OutputFormat( | 769 | MainConsole.Instance.OutputFormat( |
622 | "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}", | 770 | "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}", |
623 | fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1, | 771 | fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1, |
624 | m_scene.RegionInfo.RegionName, filename); | 772 | m_scene.RegionInfo.RegionName, filename); |
625 | } | 773 | } |
626 | 774 | ||
627 | return; | 775 | return; |
628 | } | 776 | } |
629 | } | 777 | } |
@@ -634,7 +782,44 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
634 | } | 782 | } |
635 | 783 | ||
636 | /// <summary> | 784 | /// <summary> |
785 | /// Called before processing of every simulation frame. | ||
786 | /// This is used to check to see of any of the terrain is tainted and, if so, schedule | ||
787 | /// updates for all the presences. | ||
788 | /// This also checks to see if there are updates that need to be sent for each presence. | ||
789 | /// This is where the logic is to send terrain updates to clients. | ||
790 | /// </summary> | ||
791 | private void EventManager_OnFrame() | ||
792 | { | ||
793 | TerrainData terrData = m_channel.GetTerrainData(); | ||
794 | |||
795 | bool shouldTaint = false; | ||
796 | for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) | ||
797 | { | ||
798 | for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) | ||
799 | { | ||
800 | if (terrData.IsTaintedAt(x, y)) | ||
801 | { | ||
802 | // Found a patch that was modified. Push this flag into the clients. | ||
803 | SendToClients(terrData, x, y); | ||
804 | shouldTaint = true; | ||
805 | } | ||
806 | } | ||
807 | } | ||
808 | |||
809 | // This event also causes changes to be sent to the clients | ||
810 | CheckSendingPatchesToClients(); | ||
811 | |||
812 | // If things changes, generate some events | ||
813 | if (shouldTaint) | ||
814 | { | ||
815 | m_scene.EventManager.TriggerTerrainTainted(); | ||
816 | m_tainted = true; | ||
817 | } | ||
818 | } | ||
819 | |||
820 | /// <summary> | ||
637 | /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections | 821 | /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections |
822 | /// Called infrequently (like every 5 seconds or so). Best used for storing terrain. | ||
638 | /// </summary> | 823 | /// </summary> |
639 | private void EventManager_OnTerrainTick() | 824 | private void EventManager_OnTerrainTick() |
640 | { | 825 | { |
@@ -665,7 +850,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
665 | 850 | ||
666 | string[] tmpArgs = new string[args.Length - 2]; | 851 | string[] tmpArgs = new string[args.Length - 2]; |
667 | int i; | 852 | int i; |
668 | for (i = 2; i < args.Length; i++) | 853 | for(i = 2; i < args.Length; i++) |
669 | tmpArgs[i - 2] = args[i]; | 854 | tmpArgs[i - 2] = args[i]; |
670 | 855 | ||
671 | m_commander.ProcessConsoleCommand(args[1], tmpArgs); | 856 | m_commander.ProcessConsoleCommand(args[1], tmpArgs); |
@@ -683,56 +868,50 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
683 | client.OnLandUndo += client_OnLandUndo; | 868 | client.OnLandUndo += client_OnLandUndo; |
684 | client.OnUnackedTerrain += client_OnUnackedTerrain; | 869 | client.OnUnackedTerrain += client_OnUnackedTerrain; |
685 | } | 870 | } |
686 | 871 | ||
687 | /// <summary> | 872 | /// <summary> |
688 | /// Checks to see if the terrain has been modified since last check | 873 | /// Installs terrain brush hook to IClientAPI |
689 | /// but won't attempt to limit those changes to the limits specified in the estate settings | ||
690 | /// currently invoked by the command line operations in the region server only | ||
691 | /// </summary> | 874 | /// </summary> |
692 | private void CheckForTerrainUpdates() | 875 | /// <param name="client"></param> |
876 | private void EventManager_OnClientClosed(UUID client, Scene scene) | ||
693 | { | 877 | { |
694 | CheckForTerrainUpdates(false); | 878 | ScenePresence presence = scene.GetScenePresence(client); |
879 | if (presence != null) | ||
880 | { | ||
881 | presence.ControllingClient.OnModifyTerrain -= client_OnModifyTerrain; | ||
882 | presence.ControllingClient.OnBakeTerrain -= client_OnBakeTerrain; | ||
883 | presence.ControllingClient.OnLandUndo -= client_OnLandUndo; | ||
884 | presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; | ||
885 | } | ||
886 | |||
887 | lock(m_perClientPatchUpdates) | ||
888 | m_perClientPatchUpdates.Remove(client); | ||
695 | } | 889 | } |
696 | 890 | ||
697 | /// <summary> | 891 | /// <summary> |
698 | /// Checks to see if the terrain has been modified since last check. | 892 | /// Scan over changes in the terrain and limit height changes. This enforces the |
699 | /// If it has been modified, every all the terrain patches are sent to the client. | 893 | /// non-estate owner limits on rate of terrain editting. |
700 | /// If the call is asked to respect the estate settings for terrain_raise_limit and | 894 | /// Returns 'true' if any heights were limited. |
701 | /// terrain_lower_limit, it will clamp terrain updates between these values | ||
702 | /// currently invoked by client_OnModifyTerrain only and not the Commander interfaces | ||
703 | /// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param> | ||
704 | /// </summary> | 895 | /// </summary> |
705 | private void CheckForTerrainUpdates(bool respectEstateSettings) | 896 | private bool EnforceEstateLimits() |
706 | { | 897 | { |
707 | bool shouldTaint = false; | 898 | TerrainData terrData = m_channel.GetTerrainData(); |
708 | float[] serialised = m_channel.GetFloatsSerialised(); | 899 | |
709 | int x; | 900 | bool wasLimited = false; |
710 | for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize) | 901 | for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) |
711 | { | 902 | { |
712 | int y; | 903 | for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) |
713 | for (y = 0; y < m_channel.Height; y += Constants.TerrainPatchSize) | ||
714 | { | 904 | { |
715 | if (m_channel.Tainted(x, y)) | 905 | if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) |
716 | { | 906 | { |
717 | // if we should respect the estate settings then | 907 | // If we should respect the estate settings then |
718 | // fixup and height deltas that don't respect them | 908 | // fixup and height deltas that don't respect them. |
719 | if (respectEstateSettings && LimitChannelChanges(x, y)) | 909 | // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. |
720 | { | 910 | wasLimited |= LimitChannelChanges(terrData, x, y); |
721 | // this has been vetoed, so update | ||
722 | // what we are going to send to the client | ||
723 | serialised = m_channel.GetFloatsSerialised(); | ||
724 | } | ||
725 | |||
726 | SendToClients(serialised, x, y); | ||
727 | shouldTaint = true; | ||
728 | } | 911 | } |
729 | } | 912 | } |
730 | } | 913 | } |
731 | if (shouldTaint) | 914 | return wasLimited; |
732 | { | ||
733 | m_scene.EventManager.TriggerTerrainTainted(); | ||
734 | m_tainted = true; | ||
735 | } | ||
736 | } | 915 | } |
737 | 916 | ||
738 | /// <summary> | 917 | /// <summary> |
@@ -740,31 +919,30 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
740 | /// are all within the current estate limits | 919 | /// are all within the current estate limits |
741 | /// <returns>true if changes were limited, false otherwise</returns> | 920 | /// <returns>true if changes were limited, false otherwise</returns> |
742 | /// </summary> | 921 | /// </summary> |
743 | private bool LimitChannelChanges(int xStart, int yStart) | 922 | private bool LimitChannelChanges(TerrainData terrData, int xStart, int yStart) |
744 | { | 923 | { |
745 | bool changesLimited = false; | 924 | bool changesLimited = false; |
746 | double minDelta = m_scene.RegionInfo.RegionSettings.TerrainLowerLimit; | 925 | float minDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainLowerLimit; |
747 | double maxDelta = m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; | 926 | float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; |
748 | 927 | ||
749 | // loop through the height map for this patch and compare it against | 928 | // loop through the height map for this patch and compare it against |
750 | // the revert map | 929 | // the revert map |
751 | for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) | 930 | for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) |
752 | { | 931 | { |
753 | for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) | 932 | for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) |
754 | { | 933 | { |
755 | 934 | float requestedHeight = terrData[x, y]; | |
756 | double requestedHeight = m_channel[x, y]; | 935 | float bakedHeight = (float)m_revert[x, y]; |
757 | double bakedHeight = m_revert[x, y]; | 936 | float requestedDelta = requestedHeight - bakedHeight; |
758 | double requestedDelta = requestedHeight - bakedHeight; | ||
759 | 937 | ||
760 | if (requestedDelta > maxDelta) | 938 | if (requestedDelta > maxDelta) |
761 | { | 939 | { |
762 | m_channel[x, y] = bakedHeight + maxDelta; | 940 | terrData[x, y] = bakedHeight + maxDelta; |
763 | changesLimited = true; | 941 | changesLimited = true; |
764 | } | 942 | } |
765 | else if (requestedDelta < minDelta) | 943 | else if (requestedDelta < minDelta) |
766 | { | 944 | { |
767 | m_channel[x, y] = bakedHeight + minDelta; //as lower is a -ve delta | 945 | terrData[x, y] = bakedHeight + minDelta; //as lower is a -ve delta |
768 | changesLimited = true; | 946 | changesLimited = true; |
769 | } | 947 | } |
770 | } | 948 | } |
@@ -775,7 +953,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
775 | 953 | ||
776 | private void client_OnLandUndo(IClientAPI client) | 954 | private void client_OnLandUndo(IClientAPI client) |
777 | { | 955 | { |
778 | lock (m_undo) | 956 | lock(m_undo) |
779 | { | 957 | { |
780 | if (m_undo.Count > 0) | 958 | if (m_undo.Count > 0) |
781 | { | 959 | { |
@@ -792,14 +970,177 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
792 | /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param> | 970 | /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param> |
793 | /// <param name="x">The patch corner to send</param> | 971 | /// <param name="x">The patch corner to send</param> |
794 | /// <param name="y">The patch corner to send</param> | 972 | /// <param name="y">The patch corner to send</param> |
795 | private void SendToClients(float[] serialised, int x, int y) | 973 | private void SendToClients(TerrainData terrData, int x, int y) |
796 | { | 974 | { |
797 | m_scene.ForEachClient( | 975 | if (m_sendTerrainUpdatesByViewDistance) |
798 | delegate(IClientAPI controller) | 976 | { |
799 | { controller.SendLayerData( | 977 | // Add that this patch needs to be sent to the accounting for each client. |
800 | x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised); | 978 | lock(m_perClientPatchUpdates) |
979 | { | ||
980 | m_scene.ForEachScenePresence(presence => | ||
981 | { | ||
982 | PatchUpdates thisClientUpdates; | ||
983 | if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) | ||
984 | { | ||
985 | // There is a ScenePresence without a send patch map. Create one. | ||
986 | thisClientUpdates = new PatchUpdates(terrData, presence); | ||
987 | m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); | ||
988 | } | ||
989 | thisClientUpdates.SetByXY(x, y, true); | ||
801 | } | 990 | } |
802 | ); | 991 | ); |
992 | } | ||
993 | } | ||
994 | else | ||
995 | { | ||
996 | // Legacy update sending where the update is sent out as soon as noticed | ||
997 | // We know the actual terrain data that is passed is ignored so this passes a dummy heightmap. | ||
998 | //float[] heightMap = terrData.GetFloatsSerialized(); | ||
999 | float[] heightMap = new float[10]; | ||
1000 | m_scene.ForEachClient( | ||
1001 | delegate(IClientAPI controller) | ||
1002 | { | ||
1003 | controller.SendLayerData(x / Constants.TerrainPatchSize, | ||
1004 | y / Constants.TerrainPatchSize, | ||
1005 | heightMap); | ||
1006 | } | ||
1007 | ); | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | private class PatchesToSend : IComparable<PatchesToSend> | ||
1012 | { | ||
1013 | public int PatchX; | ||
1014 | public int PatchY; | ||
1015 | public float Dist; | ||
1016 | |||
1017 | public PatchesToSend(int pX, int pY, float pDist) | ||
1018 | { | ||
1019 | PatchX = pX; | ||
1020 | PatchY = pY; | ||
1021 | Dist = pDist; | ||
1022 | } | ||
1023 | |||
1024 | public int CompareTo(PatchesToSend other) | ||
1025 | { | ||
1026 | return Dist.CompareTo(other.Dist); | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | // Called each frame time to see if there are any patches to send to any of the | ||
1031 | // ScenePresences. | ||
1032 | // We know this is only called if we are doing view distance patch sending so some | ||
1033 | // tests are not made. | ||
1034 | // Loop through all the per-client info and send any patches necessary. | ||
1035 | private void CheckSendingPatchesToClients() | ||
1036 | { | ||
1037 | lock(m_perClientPatchUpdates) | ||
1038 | { | ||
1039 | foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) | ||
1040 | { | ||
1041 | if (pups.HasUpdates()) | ||
1042 | { | ||
1043 | // There is something that could be sent to this client. | ||
1044 | List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups); | ||
1045 | if (toSend.Count > 0) | ||
1046 | { | ||
1047 | // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", | ||
1048 | // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); | ||
1049 | // Sort the patches to send by the distance from the presence | ||
1050 | toSend.Sort(); | ||
1051 | /* old way that sent individual patches | ||
1052 | foreach (PatchesToSend pts in toSend) | ||
1053 | { | ||
1054 | pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); | ||
1055 | // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); | ||
1056 | } | ||
1057 | */ | ||
1058 | |||
1059 | // new way that sends all patches to the protocol so they can be sent in one block | ||
1060 | int[] xPieces = new int[toSend.Count]; | ||
1061 | int[] yPieces = new int[toSend.Count]; | ||
1062 | float[] patchPieces = new float[toSend.Count * 2]; | ||
1063 | int pieceIndex = 0; | ||
1064 | foreach(PatchesToSend pts in toSend) | ||
1065 | { | ||
1066 | patchPieces[pieceIndex++] = pts.PatchX; | ||
1067 | patchPieces[pieceIndex++] = pts.PatchY; | ||
1068 | } | ||
1069 | pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); | ||
1070 | } | ||
1071 | } | ||
1072 | } | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | // Compute a list of modified patches that are within our view distance. | ||
1077 | private List<PatchesToSend> GetModifiedPatchesInViewDistance(PatchUpdates pups) | ||
1078 | { | ||
1079 | List<PatchesToSend> ret = new List<PatchesToSend>(); | ||
1080 | |||
1081 | ScenePresence presence = pups.Presence; | ||
1082 | if (presence == null) | ||
1083 | return ret; | ||
1084 | |||
1085 | Vector3 presencePos = presence.AbsolutePosition; | ||
1086 | |||
1087 | // Before this distance check, the whole region just showed up. Adding the distance | ||
1088 | // check causes different things to happen for the current and adjacent regions. | ||
1089 | // So, to keep legacy views, if the region is legacy sized, don't do distance check. | ||
1090 | bool isLegacySizedRegion = pups.Terrain.SizeX == Constants.RegionSize && pups.Terrain.SizeY == Constants.RegionSize; | ||
1091 | bool shouldCheckViewDistance = m_sendTerrainUpdatesByViewDistance && !isLegacySizedRegion; | ||
1092 | |||
1093 | int startX = 0; | ||
1094 | int endX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize; | ||
1095 | int startY = 0; | ||
1096 | int endY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize; | ||
1097 | |||
1098 | // The following only reduces the size of area scanned for updates. Only significant for very large varregions. | ||
1099 | if (shouldCheckViewDistance) | ||
1100 | { | ||
1101 | // Compute the area of patches within our draw distance | ||
1102 | startX = (((int)(presencePos.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; | ||
1103 | startX = Math.Max(startX, 0); | ||
1104 | startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); | ||
1105 | startY = (((int)(presencePos.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; | ||
1106 | startY = Math.Max(startY, 0); | ||
1107 | startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); | ||
1108 | endX = (((int)(presencePos.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; | ||
1109 | endX = Math.Max(endX, 0); | ||
1110 | endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); | ||
1111 | endY = (((int)(presencePos.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; | ||
1112 | endY = Math.Max(endY, 0); | ||
1113 | endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); | ||
1114 | } | ||
1115 | |||
1116 | // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, cpos={4}, isChild={5}, start=<{6},{7}>, end=<{8},{9}>", | ||
1117 | // LogHeader, m_scene.RegionInfo.RegionName, | ||
1118 | // presence.DrawDistance, presencePos, presence.CameraPosition, | ||
1119 | // isLegacySizeChildRegion, | ||
1120 | // startX, startY, endX, endY); | ||
1121 | for(int x = startX; x < endX; x++) | ||
1122 | { | ||
1123 | for(int y = startY; y < endY; y++) | ||
1124 | { | ||
1125 | //Need to make sure we don't send the same ones over and over | ||
1126 | Vector3 patchPos = new Vector3(x * Constants.TerrainPatchSize, y * Constants.TerrainPatchSize, presencePos.Z); | ||
1127 | if (pups.GetByPatch(x, y)) | ||
1128 | { | ||
1129 | //Check which has less distance, camera or avatar position, both have to be done. | ||
1130 | //Its not a radius, its a diameter and we add 50 so that it doesn't look like it cuts off | ||
1131 | if (!shouldCheckViewDistance | ||
1132 | || Util.DistanceLessThan(presencePos, patchPos, presence.DrawDistance + 50) | ||
1133 | || Util.DistanceLessThan(presence.CameraPosition, patchPos, presence.DrawDistance + 50)) | ||
1134 | { | ||
1135 | //They can see it, send it to them | ||
1136 | pups.SetByPatch(x, y, false); | ||
1137 | float dist = Vector3.DistanceSquared(presencePos, patchPos); | ||
1138 | ret.Add(new PatchesToSend(x, y, dist)); | ||
1139 | } | ||
1140 | } | ||
1141 | } | ||
1142 | } | ||
1143 | return ret; | ||
803 | } | 1144 | } |
804 | 1145 | ||
805 | private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action, | 1146 | private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action, |
@@ -809,28 +1150,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
809 | bool allowed = false; | 1150 | bool allowed = false; |
810 | if (north == south && east == west) | 1151 | if (north == south && east == west) |
811 | { | 1152 | { |
812 | if (m_painteffects.ContainsKey((StandardTerrainEffects) action)) | 1153 | if (m_painteffects.ContainsKey((StandardTerrainEffects)action)) |
813 | { | 1154 | { |
814 | bool[,] allowMask = new bool[m_channel.Width,m_channel.Height]; | 1155 | bool[,] allowMask = new bool[m_channel.Width, m_channel.Height]; |
815 | allowMask.Initialize(); | 1156 | allowMask.Initialize(); |
816 | int n = size + 1; | 1157 | int n = size + 1; |
817 | if (n > 2) | 1158 | if (n > 2) |
818 | n = 4; | 1159 | n = 4; |
819 | 1160 | ||
820 | int zx = (int) (west + 0.5); | 1161 | int zx = (int)(west + 0.5); |
821 | int zy = (int) (north + 0.5); | 1162 | int zy = (int)(north + 0.5); |
822 | 1163 | ||
823 | int dx; | 1164 | int dx; |
824 | for (dx=-n; dx<=n; dx++) | 1165 | for(dx=-n; dx<=n; dx++) |
825 | { | 1166 | { |
826 | int dy; | 1167 | int dy; |
827 | for (dy=-n; dy<=n; dy++) | 1168 | for(dy=-n; dy<=n; dy++) |
828 | { | 1169 | { |
829 | int x = zx + dx; | 1170 | int x = zx + dx; |
830 | int y = zy + dy; | 1171 | int y = zy + dy; |
831 | if (x>=0 && y>=0 && x<m_channel.Width && y<m_channel.Height) | 1172 | if (x >= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height) |
832 | { | 1173 | { |
833 | if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) | 1174 | if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) |
834 | { | 1175 | { |
835 | allowMask[x, y] = true; | 1176 | allowMask[x, y] = true; |
836 | allowed = true; | 1177 | allowed = true; |
@@ -841,10 +1182,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
841 | if (allowed) | 1182 | if (allowed) |
842 | { | 1183 | { |
843 | StoreUndoState(); | 1184 | StoreUndoState(); |
844 | m_painteffects[(StandardTerrainEffects) action].PaintEffect( | 1185 | m_painteffects[(StandardTerrainEffects)action].PaintEffect( |
845 | m_channel, allowMask, west, south, height, size, seconds); | 1186 | m_channel, allowMask, west, south, height, size, seconds); |
846 | 1187 | ||
847 | CheckForTerrainUpdates(!god); //revert changes outside estate limits | 1188 | //revert changes outside estate limits |
1189 | if (!god) | ||
1190 | EnforceEstateLimits(); | ||
848 | } | 1191 | } |
849 | } | 1192 | } |
850 | else | 1193 | else |
@@ -854,22 +1197,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
854 | } | 1197 | } |
855 | else | 1198 | else |
856 | { | 1199 | { |
857 | if (m_floodeffects.ContainsKey((StandardTerrainEffects) action)) | 1200 | if (m_floodeffects.ContainsKey((StandardTerrainEffects)action)) |
858 | { | 1201 | { |
859 | bool[,] fillArea = new bool[m_channel.Width,m_channel.Height]; | 1202 | bool[,] fillArea = new bool[m_channel.Width, m_channel.Height]; |
860 | fillArea.Initialize(); | 1203 | fillArea.Initialize(); |
861 | 1204 | ||
862 | int x; | 1205 | int x; |
863 | for (x = 0; x < m_channel.Width; x++) | 1206 | for(x = 0; x < m_channel.Width; x++) |
864 | { | 1207 | { |
865 | int y; | 1208 | int y; |
866 | for (y = 0; y < m_channel.Height; y++) | 1209 | for(y = 0; y < m_channel.Height; y++) |
867 | { | 1210 | { |
868 | if (x < east && x > west) | 1211 | if (x < east && x > west) |
869 | { | 1212 | { |
870 | if (y < north && y > south) | 1213 | if (y < north && y > south) |
871 | { | 1214 | { |
872 | if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) | 1215 | if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) |
873 | { | 1216 | { |
874 | fillArea[x, y] = true; | 1217 | fillArea[x, y] = true; |
875 | allowed = true; | 1218 | allowed = true; |
@@ -882,10 +1225,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
882 | if (allowed) | 1225 | if (allowed) |
883 | { | 1226 | { |
884 | StoreUndoState(); | 1227 | StoreUndoState(); |
885 | m_floodeffects[(StandardTerrainEffects) action].FloodEffect( | 1228 | m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size); |
886 | m_channel, fillArea, size); | ||
887 | 1229 | ||
888 | CheckForTerrainUpdates(!god); //revert changes outside estate limits | 1230 | //revert changes outside estate limits |
1231 | if (!god) | ||
1232 | EnforceEstateLimits(); | ||
889 | } | 1233 | } |
890 | } | 1234 | } |
891 | else | 1235 | else |
@@ -905,16 +1249,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
905 | InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter | 1249 | InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter |
906 | } | 1250 | } |
907 | } | 1251 | } |
908 | 1252 | ||
909 | protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) | 1253 | protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) |
910 | { | 1254 | { |
911 | //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); | 1255 | //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); |
912 | client.SendLayerData(patchX, patchY, m_scene.Heightmap.GetFloatsSerialised()); | 1256 | // SendLayerData does not use the heightmap parameter. This kludge is so as to not change IClientAPI. |
1257 | float[] heightMap = new float[10]; | ||
1258 | client.SendLayerData(patchX, patchY, heightMap); | ||
913 | } | 1259 | } |
914 | 1260 | ||
915 | private void StoreUndoState() | 1261 | private void StoreUndoState() |
916 | { | 1262 | { |
917 | lock (m_undo) | 1263 | lock(m_undo) |
918 | { | 1264 | { |
919 | if (m_undo.Count > 0) | 1265 | if (m_undo.Count > 0) |
920 | { | 1266 | { |
@@ -935,23 +1281,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
935 | 1281 | ||
936 | private void InterfaceLoadFile(Object[] args) | 1282 | private void InterfaceLoadFile(Object[] args) |
937 | { | 1283 | { |
938 | LoadFromFile((string) args[0]); | 1284 | LoadFromFile((string)args[0]); |
939 | CheckForTerrainUpdates(); | ||
940 | } | 1285 | } |
941 | 1286 | ||
942 | private void InterfaceLoadTileFile(Object[] args) | 1287 | private void InterfaceLoadTileFile(Object[] args) |
943 | { | 1288 | { |
944 | LoadFromFile((string) args[0], | 1289 | LoadFromFile((string)args[0], |
945 | (int) args[1], | 1290 | (int)args[1], |
946 | (int) args[2], | 1291 | (int)args[2], |
947 | (int) args[3], | 1292 | (int)args[3], |
948 | (int) args[4]); | 1293 | (int)args[4]); |
949 | CheckForTerrainUpdates(); | ||
950 | } | 1294 | } |
951 | 1295 | ||
952 | private void InterfaceSaveFile(Object[] args) | 1296 | private void InterfaceSaveFile(Object[] args) |
953 | { | 1297 | { |
954 | SaveToFile((string) args[0]); | 1298 | SaveToFile((string)args[0]); |
955 | } | 1299 | } |
956 | 1300 | ||
957 | private void InterfaceSaveTileFile(Object[] args) | 1301 | private void InterfaceSaveTileFile(Object[] args) |
@@ -971,11 +1315,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
971 | private void InterfaceRevertTerrain(Object[] args) | 1315 | private void InterfaceRevertTerrain(Object[] args) |
972 | { | 1316 | { |
973 | int x, y; | 1317 | int x, y; |
974 | for (x = 0; x < m_channel.Width; x++) | 1318 | for(x = 0; x < m_channel.Width; x++) |
975 | for (y = 0; y < m_channel.Height; y++) | 1319 | for(y = 0; y < m_channel.Height; y++) |
976 | m_channel[x, y] = m_revert[x, y]; | 1320 | m_channel[x, y] = m_revert[x, y]; |
977 | 1321 | ||
978 | CheckForTerrainUpdates(); | ||
979 | } | 1322 | } |
980 | 1323 | ||
981 | private void InterfaceFlipTerrain(Object[] args) | 1324 | private void InterfaceFlipTerrain(Object[] args) |
@@ -984,39 +1327,36 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
984 | 1327 | ||
985 | if (direction.ToLower().StartsWith("y")) | 1328 | if (direction.ToLower().StartsWith("y")) |
986 | { | 1329 | { |
987 | for (int x = 0; x < Constants.RegionSize; x++) | 1330 | for(int x = 0; x < m_channel.Width; x++) |
988 | { | 1331 | { |
989 | for (int y = 0; y < Constants.RegionSize / 2; y++) | 1332 | for(int y = 0; y < m_channel.Height / 2; y++) |
990 | { | 1333 | { |
991 | double height = m_channel[x, y]; | 1334 | double height = m_channel[x, y]; |
992 | double flippedHeight = m_channel[x, (int)Constants.RegionSize - 1 - y]; | 1335 | double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y]; |
993 | m_channel[x, y] = flippedHeight; | 1336 | m_channel[x, y] = flippedHeight; |
994 | m_channel[x, (int)Constants.RegionSize - 1 - y] = height; | 1337 | m_channel[x, (int)m_channel.Height - 1 - y] = height; |
995 | 1338 | ||
996 | } | 1339 | } |
997 | } | 1340 | } |
998 | } | 1341 | } |
999 | else if (direction.ToLower().StartsWith("x")) | 1342 | else if (direction.ToLower().StartsWith("x")) |
1000 | { | 1343 | { |
1001 | for (int y = 0; y < Constants.RegionSize; y++) | 1344 | for(int y = 0; y < m_channel.Height; y++) |
1002 | { | 1345 | { |
1003 | for (int x = 0; x < Constants.RegionSize / 2; x++) | 1346 | for(int x = 0; x < m_channel.Width / 2; x++) |
1004 | { | 1347 | { |
1005 | double height = m_channel[x, y]; | 1348 | double height = m_channel[x, y]; |
1006 | double flippedHeight = m_channel[(int)Constants.RegionSize - 1 - x, y]; | 1349 | double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y]; |
1007 | m_channel[x, y] = flippedHeight; | 1350 | m_channel[x, y] = flippedHeight; |
1008 | m_channel[(int)Constants.RegionSize - 1 - x, y] = height; | 1351 | m_channel[(int)m_channel.Width - 1 - x, y] = height; |
1009 | 1352 | ||
1010 | } | 1353 | } |
1011 | } | 1354 | } |
1012 | } | 1355 | } |
1013 | else | 1356 | else |
1014 | { | 1357 | { |
1015 | m_log.Error("Unrecognised direction - need x or y"); | 1358 | MainConsole.Instance.OutputFormat("ERROR: Unrecognised direction {0} - need x or y", direction); |
1016 | } | 1359 | } |
1017 | |||
1018 | |||
1019 | CheckForTerrainUpdates(); | ||
1020 | } | 1360 | } |
1021 | 1361 | ||
1022 | private void InterfaceRescaleTerrain(Object[] args) | 1362 | private void InterfaceRescaleTerrain(Object[] args) |
@@ -1042,9 +1382,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1042 | int width = m_channel.Width; | 1382 | int width = m_channel.Width; |
1043 | int height = m_channel.Height; | 1383 | int height = m_channel.Height; |
1044 | 1384 | ||
1045 | for (int x = 0; x < width; x++) | 1385 | for(int x = 0; x < width; x++) |
1046 | { | 1386 | { |
1047 | for (int y = 0; y < height; y++) | 1387 | for(int y = 0; y < height; y++) |
1048 | { | 1388 | { |
1049 | double currHeight = m_channel[x, y]; | 1389 | double currHeight = m_channel[x, y]; |
1050 | if (currHeight < currMin) | 1390 | if (currHeight < currMin) |
@@ -1065,16 +1405,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1065 | //m_log.InfoFormat("Scale = {0}", scale); | 1405 | //m_log.InfoFormat("Scale = {0}", scale); |
1066 | 1406 | ||
1067 | // scale the heightmap accordingly | 1407 | // scale the heightmap accordingly |
1068 | for (int x = 0; x < width; x++) | 1408 | for(int x = 0; x < width; x++) |
1069 | { | 1409 | { |
1070 | for (int y = 0; y < height; y++) | 1410 | for(int y = 0; y < height; y++) |
1071 | { | 1411 | { |
1072 | double currHeight = m_channel[x, y] - currMin; | 1412 | double currHeight = m_channel[x, y] - currMin; |
1073 | m_channel[x, y] = desiredMin + (currHeight * scale); | 1413 | m_channel[x, y] = desiredMin + (currHeight * scale); |
1074 | } | 1414 | } |
1075 | } | 1415 | } |
1076 | 1416 | ||
1077 | CheckForTerrainUpdates(); | ||
1078 | } | 1417 | } |
1079 | 1418 | ||
1080 | } | 1419 | } |
@@ -1082,64 +1421,73 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1082 | private void InterfaceElevateTerrain(Object[] args) | 1421 | private void InterfaceElevateTerrain(Object[] args) |
1083 | { | 1422 | { |
1084 | int x, y; | 1423 | int x, y; |
1085 | for (x = 0; x < m_channel.Width; x++) | 1424 | for(x = 0; x < m_channel.Width; x++) |
1086 | for (y = 0; y < m_channel.Height; y++) | 1425 | for(y = 0; y < m_channel.Height; y++) |
1087 | m_channel[x, y] += (double) args[0]; | 1426 | m_channel[x, y] += (double)args[0]; |
1088 | CheckForTerrainUpdates(); | ||
1089 | } | 1427 | } |
1090 | 1428 | ||
1091 | private void InterfaceMultiplyTerrain(Object[] args) | 1429 | private void InterfaceMultiplyTerrain(Object[] args) |
1092 | { | 1430 | { |
1093 | int x, y; | 1431 | int x, y; |
1094 | for (x = 0; x < m_channel.Width; x++) | 1432 | for(x = 0; x < m_channel.Width; x++) |
1095 | for (y = 0; y < m_channel.Height; y++) | 1433 | for(y = 0; y < m_channel.Height; y++) |
1096 | m_channel[x, y] *= (double) args[0]; | 1434 | m_channel[x, y] *= (double)args[0]; |
1097 | CheckForTerrainUpdates(); | ||
1098 | } | 1435 | } |
1099 | 1436 | ||
1100 | private void InterfaceLowerTerrain(Object[] args) | 1437 | private void InterfaceLowerTerrain(Object[] args) |
1101 | { | 1438 | { |
1102 | int x, y; | 1439 | int x, y; |
1103 | for (x = 0; x < m_channel.Width; x++) | 1440 | for(x = 0; x < m_channel.Width; x++) |
1104 | for (y = 0; y < m_channel.Height; y++) | 1441 | for(y = 0; y < m_channel.Height; y++) |
1105 | m_channel[x, y] -= (double) args[0]; | 1442 | m_channel[x, y] -= (double)args[0]; |
1106 | CheckForTerrainUpdates(); | ||
1107 | } | 1443 | } |
1108 | 1444 | ||
1109 | private void InterfaceFillTerrain(Object[] args) | 1445 | public void InterfaceFillTerrain(Object[] args) |
1110 | { | 1446 | { |
1111 | int x, y; | 1447 | int x, y; |
1112 | 1448 | ||
1113 | for (x = 0; x < m_channel.Width; x++) | 1449 | for(x = 0; x < m_channel.Width; x++) |
1114 | for (y = 0; y < m_channel.Height; y++) | 1450 | for(y = 0; y < m_channel.Height; y++) |
1115 | m_channel[x, y] = (double) args[0]; | 1451 | m_channel[x, y] = (double)args[0]; |
1116 | CheckForTerrainUpdates(); | ||
1117 | } | 1452 | } |
1118 | 1453 | ||
1119 | private void InterfaceMinTerrain(Object[] args) | 1454 | private void InterfaceMinTerrain(Object[] args) |
1120 | { | 1455 | { |
1121 | int x, y; | 1456 | int x, y; |
1122 | for (x = 0; x < m_channel.Width; x++) | 1457 | for(x = 0; x < m_channel.Width; x++) |
1123 | { | 1458 | { |
1124 | for (y = 0; y < m_channel.Height; y++) | 1459 | for(y = 0; y < m_channel.Height; y++) |
1125 | { | 1460 | { |
1126 | m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); | 1461 | m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); |
1127 | } | 1462 | } |
1128 | } | 1463 | } |
1129 | CheckForTerrainUpdates(); | ||
1130 | } | 1464 | } |
1131 | 1465 | ||
1132 | private void InterfaceMaxTerrain(Object[] args) | 1466 | private void InterfaceMaxTerrain(Object[] args) |
1133 | { | 1467 | { |
1134 | int x, y; | 1468 | int x, y; |
1135 | for (x = 0; x < m_channel.Width; x++) | 1469 | for(x = 0; x < m_channel.Width; x++) |
1136 | { | 1470 | { |
1137 | for (y = 0; y < m_channel.Height; y++) | 1471 | for(y = 0; y < m_channel.Height; y++) |
1138 | { | 1472 | { |
1139 | m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); | 1473 | m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); |
1140 | } | 1474 | } |
1141 | } | 1475 | } |
1142 | CheckForTerrainUpdates(); | 1476 | } |
1477 | |||
1478 | private void InterfaceShow(Object[] args) | ||
1479 | { | ||
1480 | Vector2 point; | ||
1481 | |||
1482 | if (!ConsoleUtil.TryParseConsole2DVector((string)args[0], null, out point)) | ||
1483 | { | ||
1484 | Console.WriteLine("ERROR: {0} is not a valid vector", args[0]); | ||
1485 | return; | ||
1486 | } | ||
1487 | |||
1488 | double height = m_channel[(int)point.X, (int)point.Y]; | ||
1489 | |||
1490 | Console.WriteLine("Terrain height at {0} is {1}", point, height); | ||
1143 | } | 1491 | } |
1144 | 1492 | ||
1145 | private void InterfaceShowDebugStats(Object[] args) | 1493 | private void InterfaceShowDebugStats(Object[] args) |
@@ -1149,10 +1497,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1149 | double sum = 0; | 1497 | double sum = 0; |
1150 | 1498 | ||
1151 | int x; | 1499 | int x; |
1152 | for (x = 0; x < m_channel.Width; x++) | 1500 | for(x = 0; x < m_channel.Width; x++) |
1153 | { | 1501 | { |
1154 | int y; | 1502 | int y; |
1155 | for (y = 0; y < m_channel.Height; y++) | 1503 | for(y = 0; y < m_channel.Height; y++) |
1156 | { | 1504 | { |
1157 | sum += m_channel[x, y]; | 1505 | sum += m_channel[x, y]; |
1158 | if (max < m_channel[x, y]) | 1506 | if (max < m_channel[x, y]) |
@@ -1164,13 +1512,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1164 | 1512 | ||
1165 | double avg = sum / (m_channel.Height * m_channel.Width); | 1513 | double avg = sum / (m_channel.Height * m_channel.Width); |
1166 | 1514 | ||
1167 | m_log.Info("Channel " + m_channel.Width + "x" + m_channel.Height); | 1515 | MainConsole.Instance.OutputFormat("Channel {0}x{1}", m_channel.Width, m_channel.Height); |
1168 | m_log.Info("max/min/avg/sum: " + max + "/" + min + "/" + avg + "/" + sum); | 1516 | MainConsole.Instance.OutputFormat("max/min/avg/sum: {0}/{1}/{2}/{3}", max, min, avg, sum); |
1169 | } | 1517 | } |
1170 | 1518 | ||
1171 | private void InterfaceEnableExperimentalBrushes(Object[] args) | 1519 | private void InterfaceEnableExperimentalBrushes(Object[] args) |
1172 | { | 1520 | { |
1173 | if ((bool) args[0]) | 1521 | if ((bool)args[0]) |
1174 | { | 1522 | { |
1175 | m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); | 1523 | m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); |
1176 | m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); | 1524 | m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); |
@@ -1185,28 +1533,30 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1185 | private void InterfaceRunPluginEffect(Object[] args) | 1533 | private void InterfaceRunPluginEffect(Object[] args) |
1186 | { | 1534 | { |
1187 | string firstArg = (string)args[0]; | 1535 | string firstArg = (string)args[0]; |
1536 | |||
1188 | if (firstArg == "list") | 1537 | if (firstArg == "list") |
1189 | { | 1538 | { |
1190 | m_log.Info("List of loaded plugins"); | 1539 | MainConsole.Instance.Output("List of loaded plugins"); |
1191 | foreach (KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects) | 1540 | foreach(KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects) |
1192 | { | 1541 | { |
1193 | m_log.Info(kvp.Key); | 1542 | MainConsole.Instance.Output(kvp.Key); |
1194 | } | 1543 | } |
1195 | return; | 1544 | return; |
1196 | } | 1545 | } |
1546 | |||
1197 | if (firstArg == "reload") | 1547 | if (firstArg == "reload") |
1198 | { | 1548 | { |
1199 | LoadPlugins(); | 1549 | LoadPlugins(); |
1200 | return; | 1550 | return; |
1201 | } | 1551 | } |
1552 | |||
1202 | if (m_plugineffects.ContainsKey(firstArg)) | 1553 | if (m_plugineffects.ContainsKey(firstArg)) |
1203 | { | 1554 | { |
1204 | m_plugineffects[firstArg].RunEffect(m_channel); | 1555 | m_plugineffects[firstArg].RunEffect(m_channel); |
1205 | CheckForTerrainUpdates(); | ||
1206 | } | 1556 | } |
1207 | else | 1557 | else |
1208 | { | 1558 | { |
1209 | m_log.Warn("No such plugin effect loaded."); | 1559 | MainConsole.Instance.Output("WARNING: No such plugin effect {0} loaded.", firstArg); |
1210 | } | 1560 | } |
1211 | } | 1561 | } |
1212 | 1562 | ||
@@ -1295,12 +1645,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1295 | new Command("stats", CommandIntentions.COMMAND_STATISTICAL, InterfaceShowDebugStats, | 1645 | new Command("stats", CommandIntentions.COMMAND_STATISTICAL, InterfaceShowDebugStats, |
1296 | "Shows some information about the regions heightmap for debugging purposes."); | 1646 | "Shows some information about the regions heightmap for debugging purposes."); |
1297 | 1647 | ||
1648 | Command showCommand = | ||
1649 | new Command("show", CommandIntentions.COMMAND_NON_HAZARDOUS, InterfaceShow, | ||
1650 | "Shows terrain height at a given co-ordinate."); | ||
1651 | showCommand.AddArgument("point", "point in <x>,<y> format with no spaces (e.g. 45,45)", "String"); | ||
1652 | |||
1298 | Command experimentalBrushesCommand = | 1653 | Command experimentalBrushesCommand = |
1299 | new Command("newbrushes", CommandIntentions.COMMAND_HAZARDOUS, InterfaceEnableExperimentalBrushes, | 1654 | new Command("newbrushes", CommandIntentions.COMMAND_HAZARDOUS, InterfaceEnableExperimentalBrushes, |
1300 | "Enables experimental brushes which replace the standard terrain brushes. WARNING: This is a debug setting and may be removed at any time."); | 1655 | "Enables experimental brushes which replace the standard terrain brushes. WARNING: This is a debug setting and may be removed at any time."); |
1301 | experimentalBrushesCommand.AddArgument("Enabled?", "true / false - Enable new brushes", "Boolean"); | 1656 | experimentalBrushesCommand.AddArgument("Enabled?", "true / false - Enable new brushes", "Boolean"); |
1302 | 1657 | ||
1303 | //Plugins | 1658 | // Plugins |
1304 | Command pluginRunCommand = | 1659 | Command pluginRunCommand = |
1305 | new Command("effect", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRunPluginEffect, "Runs a specified plugin effect"); | 1660 | new Command("effect", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRunPluginEffect, "Runs a specified plugin effect"); |
1306 | pluginRunCommand.AddArgument("name", "The plugin effect you wish to run, or 'list' to see all plugins", "String"); | 1661 | pluginRunCommand.AddArgument("name", "The plugin effect you wish to run, or 'list' to see all plugins", "String"); |
@@ -1316,6 +1671,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1316 | m_commander.RegisterCommand("bake", bakeRegionCommand); | 1671 | m_commander.RegisterCommand("bake", bakeRegionCommand); |
1317 | m_commander.RegisterCommand("revert", revertRegionCommand); | 1672 | m_commander.RegisterCommand("revert", revertRegionCommand); |
1318 | m_commander.RegisterCommand("newbrushes", experimentalBrushesCommand); | 1673 | m_commander.RegisterCommand("newbrushes", experimentalBrushesCommand); |
1674 | m_commander.RegisterCommand("show", showCommand); | ||
1319 | m_commander.RegisterCommand("stats", showDebugStatsCommand); | 1675 | m_commander.RegisterCommand("stats", showDebugStatsCommand); |
1320 | m_commander.RegisterCommand("effect", pluginRunCommand); | 1676 | m_commander.RegisterCommand("effect", pluginRunCommand); |
1321 | m_commander.RegisterCommand("flip", flipCommand); | 1677 | m_commander.RegisterCommand("flip", flipCommand); |
@@ -1325,10 +1681,66 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1325 | 1681 | ||
1326 | // Add this to our scene so scripts can call these functions | 1682 | // Add this to our scene so scripts can call these functions |
1327 | m_scene.RegisterModuleCommander(m_commander); | 1683 | m_scene.RegisterModuleCommander(m_commander); |
1684 | |||
1685 | // Add Modify command to Scene, since Command object requires fixed-length arglists | ||
1686 | m_scene.AddCommand("Terrain", this, "terrain modify", | ||
1687 | "terrain modify <operation> <value> [<area>] [<taper>]", | ||
1688 | "Modifies the terrain as instructed." + | ||
1689 | "\nEach operation can be limited to an area of effect:" + | ||
1690 | "\n * -ell=x,y,rx[,ry] constrains the operation to an ellipse centred at x,y" + | ||
1691 | "\n * -rec=x,y,dx[,dy] constrains the operation to a rectangle based at x,y" + | ||
1692 | "\nEach operation can have its effect tapered based on distance from centre:" + | ||
1693 | "\n * elliptical operations taper as cones" + | ||
1694 | "\n * rectangular operations taper as pyramids" | ||
1695 | , | ||
1696 | ModifyCommand); | ||
1697 | |||
1328 | } | 1698 | } |
1329 | 1699 | ||
1700 | public void ModifyCommand(string module, string[] cmd) | ||
1701 | { | ||
1702 | string result; | ||
1703 | Scene scene = SceneManager.Instance.CurrentScene; | ||
1704 | if ((scene != null) && (scene != m_scene)) | ||
1705 | { | ||
1706 | result = String.Empty; | ||
1707 | } | ||
1708 | else if (cmd.Length > 2) | ||
1709 | { | ||
1710 | string operationType = cmd[2]; | ||
1330 | 1711 | ||
1331 | #endregion | 1712 | |
1713 | ITerrainModifier operation; | ||
1714 | if (!m_modifyOperations.TryGetValue(operationType, out operation)) | ||
1715 | { | ||
1716 | result = String.Format("Terrain Modify \"{0}\" not found.", operationType); | ||
1717 | } | ||
1718 | else if ((cmd.Length > 3) && (cmd[3] == "usage")) | ||
1719 | { | ||
1720 | result = "Usage: " + operation.GetUsage(); | ||
1721 | } | ||
1722 | else | ||
1723 | { | ||
1724 | result = operation.ModifyTerrain(m_channel, cmd); | ||
1725 | } | ||
1726 | |||
1727 | if (result == String.Empty) | ||
1728 | { | ||
1729 | result = "Modified terrain"; | ||
1730 | m_log.DebugFormat("Performed terrain operation {0}", operationType); | ||
1731 | } | ||
1732 | } | ||
1733 | else | ||
1734 | { | ||
1735 | result = "Usage: <operation-name> <arg1> <arg2>..."; | ||
1736 | } | ||
1737 | if (result != String.Empty) | ||
1738 | { | ||
1739 | MainConsole.Instance.Output(result); | ||
1740 | } | ||
1741 | } | ||
1742 | |||
1743 | #endregion | ||
1332 | 1744 | ||
1333 | } | 1745 | } |
1334 | } | 1746 | } |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs new file mode 100644 index 0000000..0563ad0 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs | |||
@@ -0,0 +1,75 @@ | |||
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 NUnit.Framework; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Region.CoreModules.World.Terrain; | ||
32 | using OpenSim.Region.Framework.Scenes; | ||
33 | using OpenSim.Tests.Common; | ||
34 | |||
35 | namespace OpenSim.Region.CoreModules.Terrain.Tests | ||
36 | { | ||
37 | public class TerrainModuleTests : OpenSimTestCase | ||
38 | { | ||
39 | [Test] | ||
40 | public void TestTerrainFill() | ||
41 | { | ||
42 | TestHelpers.InMethod(); | ||
43 | // TestHelpers.EnableLogging(); | ||
44 | |||
45 | //UUID userId = TestHelpers.ParseTail(0x1); | ||
46 | |||
47 | TerrainModule tm = new TerrainModule(); | ||
48 | Scene scene = new SceneHelpers().SetupScene(); | ||
49 | SceneHelpers.SetupSceneModules(scene, tm); | ||
50 | |||
51 | // Fillheight of 30 | ||
52 | { | ||
53 | double fillHeight = 30; | ||
54 | |||
55 | tm.InterfaceFillTerrain(new object[] { fillHeight }); | ||
56 | |||
57 | double height = scene.Heightmap[128, 128]; | ||
58 | |||
59 | Assert.AreEqual(fillHeight, height); | ||
60 | } | ||
61 | |||
62 | // Max fillheight of 30 | ||
63 | // According to http://wiki.secondlife.com/wiki/Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files#Notes_for_Creating_Height_Field_Maps_for_Second_Life | ||
64 | { | ||
65 | double fillHeight = 508; | ||
66 | |||
67 | tm.InterfaceFillTerrain(new object[] { fillHeight }); | ||
68 | |||
69 | double height = scene.Heightmap[128, 128]; | ||
70 | |||
71 | Assert.AreEqual(fillHeight, height); | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs index be719ea..29e80ef 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs | |||
@@ -40,10 +40,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests | |||
40 | [Test] | 40 | [Test] |
41 | public void BrushTest() | 41 | public void BrushTest() |
42 | { | 42 | { |
43 | int midRegion = (int)Constants.RegionSize / 2; | ||
44 | |||
45 | // Create a mask that covers only the left half of the region | ||
43 | bool[,] allowMask = new bool[(int)Constants.RegionSize, 256]; | 46 | bool[,] allowMask = new bool[(int)Constants.RegionSize, 256]; |
44 | int x; | 47 | int x; |
45 | int y; | 48 | int y; |
46 | for (x = 0; x < (int)((int)Constants.RegionSize * 0.5f); x++) | 49 | for (x = 0; x < midRegion; x++) |
47 | { | 50 | { |
48 | for (y = 0; y < (int)Constants.RegionSize; y++) | 51 | for (y = 0; y < (int)Constants.RegionSize; y++) |
49 | { | 52 | { |
@@ -57,13 +60,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests | |||
57 | TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); | 60 | TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); |
58 | ITerrainPaintableEffect effect = new RaiseSphere(); | 61 | ITerrainPaintableEffect effect = new RaiseSphere(); |
59 | 62 | ||
60 | effect.PaintEffect(map, allowMask, (int)Constants.RegionSize * 0.5f, (int)Constants.RegionSize * 0.5f, -1.0, 2, 0.1); | 63 | effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0); |
61 | Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (127,128)."); | 64 | Assert.That(map[127, midRegion] > 0.0, "Raise brush should raising value at this point (127,128)."); |
62 | Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (124,128)."); | 65 | Assert.That(map[125, midRegion] > 0.0, "Raise brush should raising value at this point (124,128)."); |
63 | Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (123,128)."); | 66 | Assert.That(map[120, midRegion] == 0.0, "Raise brush should not change value at this point (120,128)."); |
64 | Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (128,128)."); | 67 | Assert.That(map[128, midRegion] == 0.0, "Raise brush should not change value at this point (128,128)."); |
65 | Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (0,128)."); | 68 | Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128)."); |
66 | |||
67 | // | 69 | // |
68 | // Test LowerSphere | 70 | // Test LowerSphere |
69 | // | 71 | // |
@@ -77,13 +79,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests | |||
77 | } | 79 | } |
78 | effect = new LowerSphere(); | 80 | effect = new LowerSphere(); |
79 | 81 | ||
80 | effect.PaintEffect(map, allowMask, ((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), -1.0, 2, 6.0); | 82 | effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0); |
81 | Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128)."); | 83 | Assert.That(map[127, midRegion] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128)."); |
82 | Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128)."); | 84 | Assert.That(map[127, midRegion] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128)."); |
83 | Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] < 1.0, "Lower brush should lowering value at this point (124,128)."); | 85 | Assert.That(map[125, midRegion] < 1.0, "Lower brush should lowering value at this point (124,128)."); |
84 | Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (123,128)."); | 86 | Assert.That(map[120, midRegion] == 1.0, "Lower brush should not change value at this point (120,128)."); |
85 | Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (128,128)."); | 87 | Assert.That(map[128, midRegion] == 1.0, "Lower brush should not change value at this point (128,128)."); |
86 | Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (0,128)."); | 88 | Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128)."); |
87 | } | 89 | } |
88 | 90 | ||
89 | [Test] | 91 | [Test] |
@@ -100,10 +102,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests | |||
100 | x[0, 0] -= 1.0; | 102 | x[0, 0] -= 1.0; |
101 | Assert.That(x[0, 0] == 4.0, "Terrain addition/subtraction error."); | 103 | Assert.That(x[0, 0] == 4.0, "Terrain addition/subtraction error."); |
102 | 104 | ||
103 | x[0, 0] = Math.PI; | ||
104 | double[,] doublesExport = x.GetDoubles(); | ||
105 | Assert.That(doublesExport[0, 0] == Math.PI, "Export to double[,] array not working correctly."); | ||
106 | |||
107 | x[0, 0] = 1.0; | 105 | x[0, 0] = 1.0; |
108 | float[] floatsExport = x.GetFloatsSerialised(); | 106 | float[] floatsExport = x.GetFloatsSerialised(); |
109 | Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly."); | 107 | Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly."); |
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs index df5ac92..9534ad3 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -32,6 +32,7 @@ using System.Drawing.Imaging; | |||
32 | using log4net; | 32 | using log4net; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Region.Framework.Interfaces; | ||
35 | using OpenSim.Services.Interfaces; | 36 | using OpenSim.Services.Interfaces; |
36 | 37 | ||
37 | namespace OpenSim.Region.CoreModules.World.Warp3DMap | 38 | namespace OpenSim.Region.CoreModules.World.Warp3DMap |
@@ -66,261 +67,271 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
66 | #endregion Constants | 67 | #endregion Constants |
67 | 68 | ||
68 | private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); | 69 | private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); |
70 | private static string LogHeader = "[WARP3D TERRAIN SPLAT]"; | ||
69 | 71 | ||
70 | /// <summary> | 72 | /// <summary> |
71 | /// Builds a composited terrain texture given the region texture | 73 | /// Builds a composited terrain texture given the region texture |
72 | /// and heightmap settings | 74 | /// and heightmap settings |
73 | /// </summary> | 75 | /// </summary> |
74 | /// <param name="heightmap">Terrain heightmap</param> | 76 | /// <param name="terrain">Terrain heightmap</param> |
75 | /// <param name="regionInfo">Region information including terrain texture parameters</param> | 77 | /// <param name="regionInfo">Region information including terrain texture parameters</param> |
76 | /// <returns>A composited 256x256 RGB texture ready for rendering</returns> | 78 | /// <returns>A 256x256 square RGB texture ready for rendering</returns> |
77 | /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting | 79 | /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting |
80 | /// Note we create a 256x256 dimension texture even if the actual terrain is larger. | ||
78 | /// </remarks> | 81 | /// </remarks> |
79 | public static Bitmap Splat(float[] heightmap, UUID[] textureIDs, float[] startHeights, float[] heightRanges, Vector3d regionPosition, IAssetService assetService, bool textureTerrain) | 82 | public static Bitmap Splat(ITerrainChannel terrain, |
83 | UUID[] textureIDs, float[] startHeights, float[] heightRanges, | ||
84 | Vector3d regionPosition, IAssetService assetService, bool textureTerrain) | ||
80 | { | 85 | { |
81 | Debug.Assert(heightmap.Length == 256 * 256); | ||
82 | Debug.Assert(textureIDs.Length == 4); | 86 | Debug.Assert(textureIDs.Length == 4); |
83 | Debug.Assert(startHeights.Length == 4); | 87 | Debug.Assert(startHeights.Length == 4); |
84 | Debug.Assert(heightRanges.Length == 4); | 88 | Debug.Assert(heightRanges.Length == 4); |
85 | 89 | ||
86 | Bitmap[] detailTexture = new Bitmap[4]; | 90 | Bitmap[] detailTexture = new Bitmap[4]; |
87 | Bitmap output = null; | ||
88 | BitmapData outputData = null; | ||
89 | 91 | ||
90 | try | 92 | if (textureTerrain) |
91 | { | 93 | { |
92 | if (textureTerrain) | 94 | // Swap empty terrain textureIDs with default IDs |
95 | for (int i = 0; i < textureIDs.Length; i++) | ||
93 | { | 96 | { |
94 | // Swap empty terrain textureIDs with default IDs | 97 | if (textureIDs[i] == UUID.Zero) |
95 | for (int i = 0; i < textureIDs.Length; i++) | 98 | textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i]; |
96 | { | 99 | } |
97 | if (textureIDs[i] == UUID.Zero) | 100 | |
98 | textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i]; | 101 | #region Texture Fetching |
99 | } | 102 | |
100 | 103 | if (assetService != null) | |
101 | #region Texture Fetching | 104 | { |
102 | 105 | for (int i = 0; i < 4; i++) | |
103 | if (assetService != null) | ||
104 | { | 106 | { |
105 | for (int i = 0; i < 4; i++) | 107 | AssetBase asset; |
108 | UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]); | ||
109 | |||
110 | // Try to fetch a cached copy of the decoded/resized version of this texture | ||
111 | asset = assetService.GetCached(cacheID.ToString()); | ||
112 | if (asset != null) | ||
113 | { | ||
114 | try | ||
115 | { | ||
116 | using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data)) | ||
117 | detailTexture[i] = (Bitmap)Image.FromStream(stream); | ||
118 | } | ||
119 | catch (Exception ex) | ||
120 | { | ||
121 | m_log.Warn("Failed to decode cached terrain texture " + cacheID + | ||
122 | " (textureID: " + textureIDs[i] + "): " + ex.Message); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | if (detailTexture[i] == null) | ||
106 | { | 127 | { |
107 | AssetBase asset; | 128 | // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG |
108 | UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]); | 129 | asset = assetService.Get(textureIDs[i].ToString()); |
109 | |||
110 | // Try to fetch a cached copy of the decoded/resized version of this texture | ||
111 | asset = assetService.GetCached(cacheID.ToString()); | ||
112 | if (asset != null) | 130 | if (asset != null) |
113 | { | 131 | { |
114 | // m_log.DebugFormat( | 132 | // m_log.DebugFormat( |
115 | // "[TERRAIN SPLAT]: Got asset service cached terrain texture {0} {1}", i, asset.ID); | 133 | // "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID); |
116 | 134 | ||
117 | try | 135 | try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } |
118 | { | ||
119 | using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data)) | ||
120 | detailTexture[i] = (Bitmap)Image.FromStream(stream); | ||
121 | } | ||
122 | catch (Exception ex) | 136 | catch (Exception ex) |
123 | { | 137 | { |
124 | m_log.Warn("Failed to decode cached terrain texture " + cacheID + | 138 | m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); |
125 | " (textureID: " + textureIDs[i] + "): " + ex.Message); | ||
126 | } | 139 | } |
127 | } | 140 | } |
128 | |||
129 | if (detailTexture[i] == null) | ||
130 | { | ||
131 | // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG | ||
132 | asset = assetService.Get(textureIDs[i].ToString()); | ||
133 | if (asset != null) | ||
134 | { | ||
135 | // m_log.DebugFormat( | ||
136 | // "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID); | ||
137 | 141 | ||
138 | try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } | 142 | if (detailTexture[i] != null) |
139 | catch (Exception ex) | 143 | { |
144 | // Make sure this texture is the correct size, otherwise resize | ||
145 | if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) | ||
146 | { | ||
147 | using (Bitmap origBitmap = detailTexture[i]) | ||
140 | { | 148 | { |
141 | m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); | 149 | detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256); |
142 | } | 150 | } |
143 | } | 151 | } |
144 | 152 | ||
145 | if (detailTexture[i] != null) | 153 | // Save the decoded and resized texture to the cache |
146 | { | 154 | byte[] data; |
147 | // Make sure this texture is the correct size, otherwise resize | 155 | using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) |
148 | if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) | 156 | { |
149 | { | 157 | detailTexture[i].Save(stream, ImageFormat.Png); |
150 | using (Bitmap origBitmap = detailTexture[i]) | 158 | data = stream.ToArray(); |
151 | { | ||
152 | detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // Save the decoded and resized texture to the cache | ||
157 | byte[] data; | ||
158 | using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) | ||
159 | { | ||
160 | detailTexture[i].Save(stream, ImageFormat.Png); | ||
161 | data = stream.ToArray(); | ||
162 | } | ||
163 | |||
164 | // Cache a PNG copy of this terrain texture | ||
165 | AssetBase newAsset = new AssetBase | ||
166 | { | ||
167 | Data = data, | ||
168 | Description = "PNG", | ||
169 | Flags = AssetFlags.Collectable, | ||
170 | FullID = cacheID, | ||
171 | ID = cacheID.ToString(), | ||
172 | Local = true, | ||
173 | Name = String.Empty, | ||
174 | Temporary = true, | ||
175 | Type = (sbyte)AssetType.Unknown | ||
176 | }; | ||
177 | newAsset.Metadata.ContentType = "image/png"; | ||
178 | assetService.Store(newAsset); | ||
179 | } | 159 | } |
160 | |||
161 | // Cache a PNG copy of this terrain texture | ||
162 | AssetBase newAsset = new AssetBase | ||
163 | { | ||
164 | Data = data, | ||
165 | Description = "PNG", | ||
166 | Flags = AssetFlags.Collectable, | ||
167 | FullID = cacheID, | ||
168 | ID = cacheID.ToString(), | ||
169 | Local = true, | ||
170 | Name = String.Empty, | ||
171 | Temporary = true, | ||
172 | Type = (sbyte)AssetType.Unknown | ||
173 | }; | ||
174 | newAsset.Metadata.ContentType = "image/png"; | ||
175 | assetService.Store(newAsset); | ||
180 | } | 176 | } |
181 | } | 177 | } |
182 | } | 178 | } |
183 | |||
184 | #endregion Texture Fetching | ||
185 | } | 179 | } |
186 | 180 | ||
187 | // Fill in any missing textures with a solid color | 181 | #endregion Texture Fetching |
188 | for (int i = 0; i < 4; i++) | 182 | } |
183 | |||
184 | // Fill in any missing textures with a solid color | ||
185 | for (int i = 0; i < 4; i++) | ||
186 | { | ||
187 | if (detailTexture[i] == null) | ||
189 | { | 188 | { |
190 | if (detailTexture[i] == null) | 189 | m_log.DebugFormat("{0} Missing terrain texture for layer {1}. Filling with solid default color", |
190 | LogHeader, i); | ||
191 | // Create a solid color texture for this layer | ||
192 | detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb); | ||
193 | using (Graphics gfx = Graphics.FromImage(detailTexture[i])) | ||
191 | { | 194 | { |
192 | // m_log.DebugFormat( | 195 | using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i])) |
193 | // "[TERRAIN SPLAT]: Generating solid colour for missing texture {0}", i); | 196 | gfx.FillRectangle(brush, 0, 0, 256, 256); |
194 | |||
195 | // Create a solid color texture for this layer | ||
196 | detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb); | ||
197 | using (Graphics gfx = Graphics.FromImage(detailTexture[i])) | ||
198 | { | ||
199 | using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i])) | ||
200 | gfx.FillRectangle(brush, 0, 0, 256, 256); | ||
201 | } | ||
202 | } | 197 | } |
203 | } | 198 | } |
204 | 199 | else | |
205 | #region Layer Map | ||
206 | |||
207 | float[] layermap = new float[256 * 256]; | ||
208 | |||
209 | for (int y = 0; y < 256; y++) | ||
210 | { | 200 | { |
211 | for (int x = 0; x < 256; x++) | 201 | if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) |
212 | { | 202 | { |
213 | float height = heightmap[y * 256 + x]; | 203 | detailTexture[i] = ResizeBitmap(detailTexture[i], 256, 256); |
214 | |||
215 | float pctX = (float)x / 255f; | ||
216 | float pctY = (float)y / 255f; | ||
217 | |||
218 | // Use bilinear interpolation between the four corners of start height and | ||
219 | // height range to select the current values at this position | ||
220 | float startHeight = ImageUtils.Bilinear( | ||
221 | startHeights[0], | ||
222 | startHeights[2], | ||
223 | startHeights[1], | ||
224 | startHeights[3], | ||
225 | pctX, pctY); | ||
226 | startHeight = Utils.Clamp(startHeight, 0f, 255f); | ||
227 | |||
228 | float heightRange = ImageUtils.Bilinear( | ||
229 | heightRanges[0], | ||
230 | heightRanges[2], | ||
231 | heightRanges[1], | ||
232 | heightRanges[3], | ||
233 | pctX, pctY); | ||
234 | heightRange = Utils.Clamp(heightRange, 0f, 255f); | ||
235 | |||
236 | // Generate two frequencies of perlin noise based on our global position | ||
237 | // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting | ||
238 | Vector3 vec = new Vector3 | ||
239 | ( | ||
240 | ((float)regionPosition.X + x) * 0.20319f, | ||
241 | ((float)regionPosition.Y + y) * 0.20319f, | ||
242 | height * 0.25f | ||
243 | ); | ||
244 | |||
245 | float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f; | ||
246 | float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f; | ||
247 | float noise = (lowFreq + highFreq) * 2f; | ||
248 | |||
249 | // Combine the current height, generated noise, start height, and height range parameters, then scale all of it | ||
250 | float layer = ((height + noise - startHeight) / heightRange) * 4f; | ||
251 | if (Single.IsNaN(layer)) layer = 0f; | ||
252 | layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f); | ||
253 | } | 204 | } |
254 | } | 205 | } |
255 | 206 | } | |
256 | #endregion Layer Map | 207 | |
257 | 208 | #region Layer Map | |
258 | #region Texture Compositing | 209 | |
259 | 210 | float[,] layermap = new float[256, 256]; | |
260 | output = new Bitmap(256, 256, PixelFormat.Format24bppRgb); | 211 | |
261 | outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); | 212 | // Scale difference between actual region size and the 256 texture being created |
262 | 213 | int xFactor = terrain.Width / 256; | |
263 | unsafe | 214 | int yFactor = terrain.Height / 256; |
215 | |||
216 | // Create 'layermap' where each value is the fractional layer number to place | ||
217 | // at that point. For instance, a value of 1.345 gives the blending of | ||
218 | // layer 1 and layer 2 for that point. | ||
219 | for (int y = 0; y < 256; y++) | ||
220 | { | ||
221 | for (int x = 0; x < 256; x++) | ||
264 | { | 222 | { |
265 | // Get handles to all of the texture data arrays | 223 | float height = (float)terrain[x * xFactor, y * yFactor]; |
266 | BitmapData[] datas = new BitmapData[] | 224 | |
267 | { | 225 | float pctX = (float)x / 255f; |
268 | detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), | 226 | float pctY = (float)y / 255f; |
269 | detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), | 227 | |
270 | detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), | 228 | // Use bilinear interpolation between the four corners of start height and |
271 | detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) | 229 | // height range to select the current values at this position |
272 | }; | 230 | float startHeight = ImageUtils.Bilinear( |
273 | 231 | startHeights[0], | |
274 | int[] comps = new int[] | 232 | startHeights[2], |
275 | { | 233 | startHeights[1], |
276 | (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | 234 | startHeights[3], |
277 | (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | 235 | pctX, pctY); |
278 | (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | 236 | startHeight = Utils.Clamp(startHeight, 0f, 255f); |
279 | (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3 | 237 | |
280 | }; | 238 | float heightRange = ImageUtils.Bilinear( |
281 | 239 | heightRanges[0], | |
282 | for (int y = 0; y < 256; y++) | 240 | heightRanges[2], |
283 | { | 241 | heightRanges[1], |
284 | for (int x = 0; x < 256; x++) | 242 | heightRanges[3], |
285 | { | 243 | pctX, pctY); |
286 | float layer = layermap[y * 256 + x]; | 244 | heightRange = Utils.Clamp(heightRange, 0f, 255f); |
287 | 245 | ||
288 | // Select two textures | 246 | // Generate two frequencies of perlin noise based on our global position |
289 | int l0 = (int)Math.Floor(layer); | 247 | // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting |
290 | int l1 = Math.Min(l0 + 1, 3); | 248 | Vector3 vec = new Vector3 |
291 | 249 | ( | |
292 | byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0]; | 250 | ((float)regionPosition.X + (x * xFactor)) * 0.20319f, |
293 | byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1]; | 251 | ((float)regionPosition.Y + (y * yFactor)) * 0.20319f, |
294 | byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3; | 252 | height * 0.25f |
295 | 253 | ); | |
296 | float aB = *(ptrA + 0); | 254 | |
297 | float aG = *(ptrA + 1); | 255 | float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f; |
298 | float aR = *(ptrA + 2); | 256 | float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f; |
299 | 257 | float noise = (lowFreq + highFreq) * 2f; | |
300 | float bB = *(ptrB + 0); | 258 | |
301 | float bG = *(ptrB + 1); | 259 | // Combine the current height, generated noise, start height, and height range parameters, then scale all of it |
302 | float bR = *(ptrB + 2); | 260 | float layer = ((height + noise - startHeight) / heightRange) * 4f; |
303 | 261 | if (Single.IsNaN(layer)) | |
304 | float layerDiff = layer - l0; | 262 | layer = 0f; |
305 | 263 | layermap[x, y] = Utils.Clamp(layer, 0f, 3f); | |
306 | // Interpolate between the two selected textures | ||
307 | *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB)); | ||
308 | *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG)); | ||
309 | *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR)); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | for (int i = 0; i < 4; i++) | ||
314 | detailTexture[i].UnlockBits(datas[i]); | ||
315 | } | 264 | } |
316 | } | 265 | } |
317 | finally | 266 | |
267 | #endregion Layer Map | ||
268 | |||
269 | #region Texture Compositing | ||
270 | |||
271 | Bitmap output = new Bitmap(256, 256, PixelFormat.Format24bppRgb); | ||
272 | BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); | ||
273 | |||
274 | // Unsafe work as we lock down the source textures for quicker access and access the | ||
275 | // pixel data directly | ||
276 | unsafe | ||
318 | { | 277 | { |
319 | for (int i = 0; i < 4; i++) | 278 | // Get handles to all of the texture data arrays |
320 | if (detailTexture[i] != null) | 279 | BitmapData[] datas = new BitmapData[] |
321 | detailTexture[i].Dispose(); | 280 | { |
281 | detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), | ||
282 | detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), | ||
283 | detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), | ||
284 | detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) | ||
285 | }; | ||
286 | |||
287 | // Compute size of each pixel data (used to address into the pixel data array) | ||
288 | int[] comps = new int[] | ||
289 | { | ||
290 | (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | ||
291 | (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | ||
292 | (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | ||
293 | (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3 | ||
294 | }; | ||
295 | |||
296 | for (int y = 0; y < 256; y++) | ||
297 | { | ||
298 | for (int x = 0; x < 256; x++) | ||
299 | { | ||
300 | float layer = layermap[x, y]; | ||
301 | |||
302 | // Select two textures | ||
303 | int l0 = (int)Math.Floor(layer); | ||
304 | int l1 = Math.Min(l0 + 1, 3); | ||
305 | |||
306 | byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0]; | ||
307 | byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1]; | ||
308 | byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3; | ||
309 | |||
310 | float aB = *(ptrA + 0); | ||
311 | float aG = *(ptrA + 1); | ||
312 | float aR = *(ptrA + 2); | ||
313 | |||
314 | float bB = *(ptrB + 0); | ||
315 | float bG = *(ptrB + 1); | ||
316 | float bR = *(ptrB + 2); | ||
317 | |||
318 | float layerDiff = layer - l0; | ||
319 | |||
320 | // Interpolate between the two selected textures | ||
321 | *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB)); | ||
322 | *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG)); | ||
323 | *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR)); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | for (int i = 0; i < detailTexture.Length; i++) | ||
328 | detailTexture[i].UnlockBits(datas[i]); | ||
322 | } | 329 | } |
323 | 330 | ||
331 | for (int i = 0; i < detailTexture.Length; i++) | ||
332 | if (detailTexture[i] != null) | ||
333 | detailTexture[i].Dispose(); | ||
334 | |||
324 | output.UnlockBits(outputData); | 335 | output.UnlockBits(outputData); |
325 | 336 | ||
326 | // We generated the texture upside down, so flip it | 337 | // We generated the texture upside down, so flip it |
@@ -331,6 +342,17 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
331 | return output; | 342 | return output; |
332 | } | 343 | } |
333 | 344 | ||
345 | public static Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight) | ||
346 | { | ||
347 | m_log.DebugFormat("{0} ResizeBitmap. From <{1},{2}> to <{3},{4}>", | ||
348 | LogHeader, b.Width, b.Height, nWidth, nHeight); | ||
349 | Bitmap result = new Bitmap(nWidth, nHeight); | ||
350 | using (Graphics g = Graphics.FromImage(result)) | ||
351 | g.DrawImage(b, 0, 0, nWidth, nHeight); | ||
352 | b.Dispose(); | ||
353 | return result; | ||
354 | } | ||
355 | |||
334 | public static Bitmap SplatSimple(float[] heightmap) | 356 | public static Bitmap SplatSimple(float[] heightmap) |
335 | { | 357 | { |
336 | const float BASE_HSV_H = 93f / 360f; | 358 | const float BASE_HSV_H = 93f / 360f; |
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index 5e0dfa7..5f2534b 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs | |||
@@ -31,21 +31,25 @@ using System.Drawing; | |||
31 | using System.Drawing.Imaging; | 31 | using System.Drawing.Imaging; |
32 | using System.IO; | 32 | using System.IO; |
33 | using System.Reflection; | 33 | using System.Reflection; |
34 | |||
34 | using CSJ2K; | 35 | using CSJ2K; |
35 | using Nini.Config; | 36 | using Nini.Config; |
36 | using log4net; | 37 | using log4net; |
37 | using Rednettle.Warp3D; | 38 | using Rednettle.Warp3D; |
38 | using Mono.Addins; | 39 | using Mono.Addins; |
39 | using OpenMetaverse; | 40 | |
40 | using OpenMetaverse.Imaging; | ||
41 | using OpenMetaverse.Rendering; | ||
42 | using OpenMetaverse.StructuredData; | ||
43 | using OpenSim.Framework; | 41 | using OpenSim.Framework; |
44 | using OpenSim.Region.Framework.Interfaces; | 42 | using OpenSim.Region.Framework.Interfaces; |
45 | using OpenSim.Region.Framework.Scenes; | 43 | using OpenSim.Region.Framework.Scenes; |
46 | using OpenSim.Region.Physics.Manager; | 44 | using OpenSim.Region.PhysicsModules.SharedBase; |
47 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
48 | 46 | ||
47 | using OpenMetaverse; | ||
48 | using OpenMetaverse.Assets; | ||
49 | using OpenMetaverse.Imaging; | ||
50 | using OpenMetaverse.Rendering; | ||
51 | using OpenMetaverse.StructuredData; | ||
52 | |||
49 | using WarpRenderer = global::Warp3D.Warp3D; | 53 | using WarpRenderer = global::Warp3D.Warp3D; |
50 | 54 | ||
51 | namespace OpenSim.Region.CoreModules.World.Warp3DMap | 55 | namespace OpenSim.Region.CoreModules.World.Warp3DMap |
@@ -58,11 +62,22 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
58 | 62 | ||
59 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 63 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
60 | 64 | ||
65 | #pragma warning disable 414 | ||
66 | private static string LogHeader = "[WARP 3D IMAGE MODULE]"; | ||
67 | #pragma warning restore 414 | ||
68 | |||
61 | private Scene m_scene; | 69 | private Scene m_scene; |
62 | private IRendering m_primMesher; | 70 | private IRendering m_primMesher; |
63 | private IConfigSource m_config; | ||
64 | private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>(); | 71 | private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>(); |
65 | private bool m_useAntiAliasing = false; // TODO: Make this a config option | 72 | |
73 | private IConfigSource m_config; | ||
74 | private bool m_drawPrimVolume = true; // true if should render the prims on the tile | ||
75 | private bool m_textureTerrain = true; // true if to create terrain splatting texture | ||
76 | private bool m_texturePrims = true; // true if should texture the rendered prims | ||
77 | private float m_texturePrimSize = 48f; // size of prim before we consider texturing it | ||
78 | private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes | ||
79 | private bool m_useAntiAliasing = false; // true if to anti-alias the rendered image | ||
80 | |||
66 | private bool m_Enabled = false; | 81 | private bool m_Enabled = false; |
67 | 82 | ||
68 | #region Region Module interface | 83 | #region Region Module interface |
@@ -71,11 +86,27 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
71 | { | 86 | { |
72 | m_config = source; | 87 | m_config = source; |
73 | 88 | ||
74 | IConfig startupConfig = m_config.Configs["Startup"]; | 89 | string[] configSections = new string[] { "Map", "Startup" }; |
75 | if (startupConfig.GetString("MapImageModule", "MapImageModule") != "Warp3DImageModule") | 90 | |
91 | if (Util.GetConfigVarFromSections<string>( | ||
92 | m_config, "MapImageModule", configSections, "MapImageModule") != "Warp3DImageModule") | ||
76 | return; | 93 | return; |
77 | 94 | ||
78 | m_Enabled = true; | 95 | m_Enabled = true; |
96 | |||
97 | m_drawPrimVolume | ||
98 | = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, m_drawPrimVolume); | ||
99 | m_textureTerrain | ||
100 | = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, m_textureTerrain); | ||
101 | m_texturePrims | ||
102 | = Util.GetConfigVarFromSections<bool>(m_config, "TexturePrims", configSections, m_texturePrims); | ||
103 | m_texturePrimSize | ||
104 | = Util.GetConfigVarFromSections<float>(m_config, "TexturePrimSize", configSections, m_texturePrimSize); | ||
105 | m_renderMeshes | ||
106 | = Util.GetConfigVarFromSections<bool>(m_config, "RenderMeshes", configSections, m_renderMeshes); | ||
107 | m_useAntiAliasing | ||
108 | = Util.GetConfigVarFromSections<bool>(m_config, "UseAntiAliasing", configSections, m_useAntiAliasing); | ||
109 | |||
79 | } | 110 | } |
80 | 111 | ||
81 | public void AddRegion(Scene scene) | 112 | public void AddRegion(Scene scene) |
@@ -127,33 +158,28 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
127 | 158 | ||
128 | public Bitmap CreateMapTile() | 159 | public Bitmap CreateMapTile() |
129 | { | 160 | { |
130 | Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f); | 161 | // Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f); |
131 | Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, (int)Constants.RegionSize, (int)Constants.RegionSize, (float)Constants.RegionSize, (float)Constants.RegionSize); | 162 | // Camera above the middle of the region |
163 | Vector3 camPos = new Vector3( | ||
164 | m_scene.RegionInfo.RegionSizeX/2 - 0.5f, | ||
165 | m_scene.RegionInfo.RegionSizeY/2 - 0.5f, | ||
166 | 221.7025033688163f); | ||
167 | // Viewport viewing down onto the region | ||
168 | Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, | ||
169 | (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY, | ||
170 | (float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY ); | ||
171 | // Fill the viewport and return the image | ||
132 | return CreateMapTile(viewport, false); | 172 | return CreateMapTile(viewport, false); |
133 | } | 173 | } |
134 | 174 | ||
135 | public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures) | 175 | public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures) |
136 | { | 176 | { |
137 | Viewport viewport = new Viewport(camPos, camDir, fov, (float)Constants.RegionSize, 0.1f, width, height); | 177 | Viewport viewport = new Viewport(camPos, camDir, fov, Constants.RegionSize, 0.1f, width, height); |
138 | return CreateMapTile(viewport, useTextures); | 178 | return CreateMapTile(viewport, useTextures); |
139 | } | 179 | } |
140 | 180 | ||
141 | public Bitmap CreateMapTile(Viewport viewport, bool useTextures) | 181 | public Bitmap CreateMapTile(Viewport viewport, bool useTextures) |
142 | { | 182 | { |
143 | bool drawPrimVolume = true; | ||
144 | bool textureTerrain = true; | ||
145 | |||
146 | try | ||
147 | { | ||
148 | IConfig startupConfig = m_config.Configs["Startup"]; | ||
149 | drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume); | ||
150 | textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain); | ||
151 | } | ||
152 | catch | ||
153 | { | ||
154 | m_log.Warn("[WARP 3D IMAGE MODULE]: Failed to load StartupConfig"); | ||
155 | } | ||
156 | |||
157 | m_colors.Clear(); | 183 | m_colors.Clear(); |
158 | 184 | ||
159 | int width = viewport.Width; | 185 | int width = viewport.Width; |
@@ -166,6 +192,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
166 | } | 192 | } |
167 | 193 | ||
168 | WarpRenderer renderer = new WarpRenderer(); | 194 | WarpRenderer renderer = new WarpRenderer(); |
195 | |||
169 | renderer.CreateScene(width, height); | 196 | renderer.CreateScene(width, height); |
170 | renderer.Scene.autoCalcNormals = false; | 197 | renderer.Scene.autoCalcNormals = false; |
171 | 198 | ||
@@ -197,8 +224,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
197 | renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40)); | 224 | renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40)); |
198 | 225 | ||
199 | CreateWater(renderer); | 226 | CreateWater(renderer); |
200 | CreateTerrain(renderer, textureTerrain); | 227 | CreateTerrain(renderer, m_textureTerrain); |
201 | if (drawPrimVolume) | 228 | if (m_drawPrimVolume) |
202 | CreateAllPrims(renderer, useTextures); | 229 | CreateAllPrims(renderer, useTextures); |
203 | 230 | ||
204 | renderer.Render(); | 231 | renderer.Render(); |
@@ -214,6 +241,18 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
214 | // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory | 241 | // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory |
215 | // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating | 242 | // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating |
216 | // this map tile simply takes a lot of memory. | 243 | // this map tile simply takes a lot of memory. |
244 | foreach (var o in renderer.Scene.objectData.Values) | ||
245 | { | ||
246 | warp_Object obj = (warp_Object)o; | ||
247 | obj.vertexData = null; | ||
248 | obj.triangleData = null; | ||
249 | } | ||
250 | |||
251 | renderer.Scene.removeAllObjects(); | ||
252 | renderer = null; | ||
253 | viewport = null; | ||
254 | |||
255 | m_colors.Clear(); | ||
217 | GC.Collect(); | 256 | GC.Collect(); |
218 | m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()"); | 257 | m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()"); |
219 | 258 | ||
@@ -240,61 +279,74 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
240 | 279 | ||
241 | #region Rendering Methods | 280 | #region Rendering Methods |
242 | 281 | ||
282 | // Add a water plane to the renderer. | ||
243 | private void CreateWater(WarpRenderer renderer) | 283 | private void CreateWater(WarpRenderer renderer) |
244 | { | 284 | { |
245 | float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; | 285 | float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; |
246 | 286 | ||
247 | renderer.AddPlane("Water", 256f * 0.5f); | 287 | renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f); |
248 | renderer.Scene.sceneobject("Water").setPos(127.5f, waterHeight, 127.5f); | 288 | renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX/2 - 0.5f, |
289 | waterHeight, | ||
290 | m_scene.RegionInfo.RegionSizeY/2 - 0.5f ); | ||
249 | 291 | ||
250 | renderer.AddMaterial("WaterColor", ConvertColor(WATER_COLOR)); | 292 | warp_Material waterColorMaterial = new warp_Material(ConvertColor(WATER_COLOR)); |
251 | renderer.Scene.material("WaterColor").setReflectivity(0); // match water color with standard map module thanks lkalif | 293 | waterColorMaterial.setReflectivity(0); // match water color with standard map module thanks lkalif |
252 | renderer.Scene.material("WaterColor").setTransparency((byte)((1f - WATER_COLOR.A) * 255f)); | 294 | waterColorMaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f)); |
295 | renderer.Scene.addMaterial("WaterColor", waterColorMaterial); | ||
253 | renderer.SetObjectMaterial("Water", "WaterColor"); | 296 | renderer.SetObjectMaterial("Water", "WaterColor"); |
254 | } | 297 | } |
255 | 298 | ||
299 | // Add a terrain to the renderer. | ||
300 | // Note that we create a 'low resolution' 256x256 vertex terrain rather than trying for | ||
301 | // full resolution. This saves a lot of memory especially for very large regions. | ||
256 | private void CreateTerrain(WarpRenderer renderer, bool textureTerrain) | 302 | private void CreateTerrain(WarpRenderer renderer, bool textureTerrain) |
257 | { | 303 | { |
258 | ITerrainChannel terrain = m_scene.Heightmap; | 304 | ITerrainChannel terrain = m_scene.Heightmap; |
259 | float[] heightmap = terrain.GetFloatsSerialised(); | 305 | |
306 | // 'diff' is the difference in scale between the real region size and the size of terrain we're buiding | ||
307 | float diff = (float)m_scene.RegionInfo.RegionSizeX / 256f; | ||
260 | 308 | ||
261 | warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2); | 309 | warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2); |
262 | 310 | ||
263 | for (int y = 0; y < 256; y++) | 311 | // Create all the vertices for the terrain |
312 | for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff) | ||
264 | { | 313 | { |
265 | for (int x = 0; x < 256; x++) | 314 | for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff) |
266 | { | 315 | { |
267 | int v = y * 256 + x; | 316 | warp_Vector pos = ConvertVector(x, y, (float)terrain[(int)x, (int)y]); |
268 | float height = heightmap[v]; | 317 | obj.addVertex(new warp_Vertex(pos, |
269 | 318 | x / (float)m_scene.RegionInfo.RegionSizeX, | |
270 | warp_Vector pos = ConvertVector(new Vector3(x, y, height)); | 319 | (((float)m_scene.RegionInfo.RegionSizeY) - y) / m_scene.RegionInfo.RegionSizeY) ); |
271 | obj.addVertex(new warp_Vertex(pos, (float)x / 255f, (float)(255 - y) / 255f)); | ||
272 | } | 320 | } |
273 | } | 321 | } |
274 | 322 | ||
275 | for (int y = 0; y < 256; y++) | 323 | // Now that we have all the vertices, make another pass and create |
324 | // the normals for each of the surface triangles and | ||
325 | // create the list of triangle indices. | ||
326 | for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff) | ||
276 | { | 327 | { |
277 | for (int x = 0; x < 256; x++) | 328 | for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff) |
278 | { | 329 | { |
279 | if (x < 255 && y < 255) | 330 | float newX = x / diff; |
331 | float newY = y / diff; | ||
332 | if (newX < 255 && newY < 255) | ||
280 | { | 333 | { |
281 | int v = y * 256 + x; | 334 | int v = (int)newY * 256 + (int)newX; |
282 | 335 | ||
283 | // Normal | 336 | // Normal for a triangle made up of three adjacent vertices |
284 | Vector3 v1 = new Vector3(x, y, heightmap[y * 256 + x]); | 337 | Vector3 v1 = new Vector3(newX, newY, (float)terrain[(int)x, (int)y]); |
285 | Vector3 v2 = new Vector3(x + 1, y, heightmap[y * 256 + x + 1]); | 338 | Vector3 v2 = new Vector3(newX + 1, newY, (float)terrain[(int)(x + 1), (int)y]); |
286 | Vector3 v3 = new Vector3(x, y + 1, heightmap[(y + 1) * 256 + x]); | 339 | Vector3 v3 = new Vector3(newX, newY + 1, (float)terrain[(int)x, ((int)(y + 1))]); |
287 | warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3)); | 340 | warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3)); |
288 | norm = norm.reverse(); | 341 | norm = norm.reverse(); |
289 | obj.vertex(v).n = norm; | 342 | obj.vertex(v).n = norm; |
290 | 343 | ||
291 | // Triangle 1 | 344 | // Make two triangles for each of the squares in the grid of vertices |
292 | obj.addTriangle( | 345 | obj.addTriangle( |
293 | v, | 346 | v, |
294 | v + 1, | 347 | v + 1, |
295 | v + 256); | 348 | v + 256); |
296 | 349 | ||
297 | // Triangle 2 | ||
298 | obj.addTriangle( | 350 | obj.addTriangle( |
299 | v + 256 + 1, | 351 | v + 256 + 1, |
300 | v + 256, | 352 | v + 256, |
@@ -309,7 +361,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
309 | float[] startHeights = new float[4]; | 361 | float[] startHeights = new float[4]; |
310 | float[] heightRanges = new float[4]; | 362 | float[] heightRanges = new float[4]; |
311 | 363 | ||
312 | RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings; | 364 | OpenSim.Framework.RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings; |
313 | 365 | ||
314 | textureIDs[0] = regionInfo.TerrainTexture1; | 366 | textureIDs[0] = regionInfo.TerrainTexture1; |
315 | textureIDs[1] = regionInfo.TerrainTexture2; | 367 | textureIDs[1] = regionInfo.TerrainTexture2; |
@@ -327,14 +379,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
327 | heightRanges[3] = (float)regionInfo.Elevation2NE; | 379 | heightRanges[3] = (float)regionInfo.Elevation2NE; |
328 | 380 | ||
329 | uint globalX, globalY; | 381 | uint globalX, globalY; |
330 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY); | 382 | Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out globalX, out globalY); |
331 | 383 | ||
332 | warp_Texture texture; | 384 | warp_Texture texture; |
333 | |||
334 | using ( | 385 | using ( |
335 | Bitmap image | 386 | Bitmap image |
336 | = TerrainSplat.Splat( | 387 | = TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges, |
337 | heightmap, textureIDs, startHeights, heightRanges, | ||
338 | new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain)) | 388 | new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain)) |
339 | { | 389 | { |
340 | texture = new warp_Texture(image); | 390 | texture = new warp_Texture(image); |
@@ -355,7 +405,6 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
355 | m_scene.ForEachSOG( | 405 | m_scene.ForEachSOG( |
356 | delegate(SceneObjectGroup group) | 406 | delegate(SceneObjectGroup group) |
357 | { | 407 | { |
358 | CreatePrim(renderer, group.RootPart, useTextures); | ||
359 | foreach (SceneObjectPart child in group.Parts) | 408 | foreach (SceneObjectPart child in group.Parts) |
360 | CreatePrim(renderer, child, useTextures); | 409 | CreatePrim(renderer, child, useTextures); |
361 | } | 410 | } |
@@ -372,8 +421,48 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
372 | if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE) | 421 | if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE) |
373 | return; | 422 | return; |
374 | 423 | ||
424 | FacetedMesh renderMesh = null; | ||
375 | Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset); | 425 | Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset); |
376 | FacetedMesh renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); | 426 | |
427 | if (m_renderMeshes) | ||
428 | { | ||
429 | if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero) | ||
430 | { | ||
431 | // Try fetchinng the asset | ||
432 | byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); | ||
433 | if (sculptAsset != null) | ||
434 | { | ||
435 | // Is it a mesh? | ||
436 | if (omvPrim.Sculpt.Type == SculptType.Mesh) | ||
437 | { | ||
438 | AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | ||
439 | FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh); | ||
440 | meshAsset = null; | ||
441 | } | ||
442 | else // It's sculptie | ||
443 | { | ||
444 | IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>(); | ||
445 | if (imgDecoder != null) | ||
446 | { | ||
447 | Image sculpt = imgDecoder.DecodeToImage(sculptAsset); | ||
448 | if (sculpt != null) | ||
449 | { | ||
450 | renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, | ||
451 | DetailLevel.Medium); | ||
452 | sculpt.Dispose(); | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | } | ||
459 | |||
460 | // If not a mesh or sculptie, try the regular mesher | ||
461 | if (renderMesh == null) | ||
462 | { | ||
463 | renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); | ||
464 | } | ||
465 | |||
377 | if (renderMesh == null) | 466 | if (renderMesh == null) |
378 | return; | 467 | return; |
379 | 468 | ||
@@ -432,7 +521,11 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
432 | 521 | ||
433 | Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); | 522 | Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); |
434 | Color4 faceColor = GetFaceColor(teFace); | 523 | Color4 faceColor = GetFaceColor(teFace); |
435 | string materialName = GetOrCreateMaterial(renderer, faceColor); | 524 | string materialName = String.Empty; |
525 | if (m_texturePrims && prim.Scale.LengthSquared() > m_texturePrimSize*m_texturePrimSize) | ||
526 | materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID); | ||
527 | else | ||
528 | materialName = GetOrCreateMaterial(renderer, faceColor); | ||
436 | 529 | ||
437 | faceObj.transform(m); | 530 | faceObj.transform(m); |
438 | faceObj.setPos(primPos); | 531 | faceObj.setPos(primPos); |
@@ -521,10 +614,59 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
521 | return name; | 614 | return name; |
522 | } | 615 | } |
523 | 616 | ||
617 | public string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID) | ||
618 | { | ||
619 | string materialName = "Color-" + faceColor.ToString() + "-Texture-" + textureID.ToString(); | ||
620 | |||
621 | if (renderer.Scene.material(materialName) == null) | ||
622 | { | ||
623 | renderer.AddMaterial(materialName, ConvertColor(faceColor)); | ||
624 | if (faceColor.A < 1f) | ||
625 | { | ||
626 | renderer.Scene.material(materialName).setTransparency((byte) ((1f - faceColor.A)*255f)); | ||
627 | } | ||
628 | warp_Texture texture = GetTexture(textureID); | ||
629 | if (texture != null) | ||
630 | renderer.Scene.material(materialName).setTexture(texture); | ||
631 | } | ||
632 | |||
633 | return materialName; | ||
634 | } | ||
635 | |||
636 | private warp_Texture GetTexture(UUID id) | ||
637 | { | ||
638 | warp_Texture ret = null; | ||
639 | |||
640 | byte[] asset = m_scene.AssetService.GetData(id.ToString()); | ||
641 | |||
642 | if (asset != null) | ||
643 | { | ||
644 | IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>(); | ||
645 | |||
646 | try | ||
647 | { | ||
648 | using (Bitmap img = (Bitmap)imgDecoder.DecodeToImage(asset)) | ||
649 | ret = new warp_Texture(img); | ||
650 | } | ||
651 | catch (Exception e) | ||
652 | { | ||
653 | m_log.Warn(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0}, exception ", id), e); | ||
654 | } | ||
655 | } | ||
656 | |||
657 | return ret; | ||
658 | } | ||
659 | |||
524 | #endregion Rendering Methods | 660 | #endregion Rendering Methods |
525 | 661 | ||
526 | #region Static Helpers | 662 | #region Static Helpers |
527 | 663 | ||
664 | // Note: axis change. | ||
665 | private static warp_Vector ConvertVector(float x, float y, float z) | ||
666 | { | ||
667 | return new warp_Vector(x, z, y); | ||
668 | } | ||
669 | |||
528 | private static warp_Vector ConvertVector(Vector3 vector) | 670 | private static warp_Vector ConvertVector(Vector3 vector) |
529 | { | 671 | { |
530 | return new warp_Vector(vector.X, vector.Z, vector.Y); | 672 | return new warp_Vector(vector.X, vector.Z, vector.Y); |
diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs index 9de588c..35014f5 100644 --- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs +++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs | |||
@@ -216,13 +216,13 @@ namespace OpenSim.Region.CoreModules | |||
216 | // FIXME: If console region is root then this will be printed by every module. Currently, there is no | 216 | // FIXME: If console region is root then this will be printed by every module. Currently, there is no |
217 | // way to prevent this, short of making the entire module shared (which is complete overkill). | 217 | // way to prevent this, short of making the entire module shared (which is complete overkill). |
218 | // One possibility is to return a bool to signal whether the module has completely handled the command | 218 | // One possibility is to return a bool to signal whether the module has completely handled the command |
219 | m_log.InfoFormat("[WIND]: Please change to a specific region in order to set Sun parameters."); | 219 | MainConsole.Instance.Output("Please change to a specific region in order to set Sun parameters."); |
220 | return; | 220 | return; |
221 | } | 221 | } |
222 | 222 | ||
223 | if (m_scene.ConsoleScene() != m_scene) | 223 | if (m_scene.ConsoleScene() != m_scene) |
224 | { | 224 | { |
225 | m_log.InfoFormat("[WIND]: Console Scene is not my scene."); | 225 | MainConsole.Instance.Output("Console Scene is not my scene."); |
226 | return; | 226 | return; |
227 | } | 227 | } |
228 | } | 228 | } |
@@ -233,7 +233,9 @@ namespace OpenSim.Region.CoreModules | |||
233 | private void HandleConsoleCommand(string module, string[] cmdparams) | 233 | private void HandleConsoleCommand(string module, string[] cmdparams) |
234 | { | 234 | { |
235 | ValidateConsole(); | 235 | ValidateConsole(); |
236 | m_log.Info("[WIND] The wind command can be used to change the currently active wind model plugin and update the parameters for wind plugins."); | 236 | |
237 | MainConsole.Instance.Output( | ||
238 | "The wind command can be used to change the currently active wind model plugin and update the parameters for wind plugins."); | ||
237 | } | 239 | } |
238 | 240 | ||
239 | /// <summary> | 241 | /// <summary> |
@@ -246,7 +248,9 @@ namespace OpenSim.Region.CoreModules | |||
246 | if ((cmdparams.Length != 4) | 248 | if ((cmdparams.Length != 4) |
247 | || !cmdparams[1].Equals("base")) | 249 | || !cmdparams[1].Equals("base")) |
248 | { | 250 | { |
249 | m_log.Info("[WIND] Invalid parameters to change parameters for Wind module base, usage: wind base <parameter> <value>"); | 251 | MainConsole.Instance.Output( |
252 | "Invalid parameters to change parameters for Wind module base, usage: wind base <parameter> <value>"); | ||
253 | |||
250 | return; | 254 | return; |
251 | } | 255 | } |
252 | 256 | ||
@@ -261,7 +265,9 @@ namespace OpenSim.Region.CoreModules | |||
261 | } | 265 | } |
262 | else | 266 | else |
263 | { | 267 | { |
264 | m_log.InfoFormat("[WIND] Invalid value {0} specified for {1}", cmdparams[3], cmdparams[2]); | 268 | MainConsole.Instance.OutputFormat( |
269 | "Invalid value {0} specified for {1}", cmdparams[3], cmdparams[2]); | ||
270 | |||
265 | return; | 271 | return; |
266 | } | 272 | } |
267 | 273 | ||
@@ -271,22 +277,23 @@ namespace OpenSim.Region.CoreModules | |||
271 | 277 | ||
272 | if (desiredPlugin.Equals(m_activeWindPlugin.Name)) | 278 | if (desiredPlugin.Equals(m_activeWindPlugin.Name)) |
273 | { | 279 | { |
274 | m_log.InfoFormat("[WIND] Wind model plugin {0} is already active", cmdparams[3]); | 280 | MainConsole.Instance.OutputFormat("Wind model plugin {0} is already active", cmdparams[3]); |
281 | |||
275 | return; | 282 | return; |
276 | } | 283 | } |
277 | 284 | ||
278 | if (m_availableWindPlugins.ContainsKey(desiredPlugin)) | 285 | if (m_availableWindPlugins.ContainsKey(desiredPlugin)) |
279 | { | 286 | { |
280 | m_activeWindPlugin = m_availableWindPlugins[cmdparams[3]]; | 287 | m_activeWindPlugin = m_availableWindPlugins[cmdparams[3]]; |
281 | m_log.InfoFormat("[WIND] {0} wind model plugin now active", m_activeWindPlugin.Name); | 288 | |
289 | MainConsole.Instance.OutputFormat("{0} wind model plugin now active", m_activeWindPlugin.Name); | ||
282 | } | 290 | } |
283 | else | 291 | else |
284 | { | 292 | { |
285 | m_log.InfoFormat("[WIND] Could not find wind model plugin {0}", desiredPlugin); | 293 | MainConsole.Instance.OutputFormat("Could not find wind model plugin {0}", desiredPlugin); |
286 | } | 294 | } |
287 | break; | 295 | break; |
288 | } | 296 | } |
289 | |||
290 | } | 297 | } |
291 | 298 | ||
292 | /// <summary> | 299 | /// <summary> |
@@ -300,7 +307,7 @@ namespace OpenSim.Region.CoreModules | |||
300 | if ((cmdparams.Length != 4) | 307 | if ((cmdparams.Length != 4) |
301 | && (cmdparams.Length != 3)) | 308 | && (cmdparams.Length != 3)) |
302 | { | 309 | { |
303 | m_log.Info("[WIND] Usage: wind <plugin> <param> [value]"); | 310 | MainConsole.Instance.Output("Usage: wind <plugin> <param> [value]"); |
304 | return; | 311 | return; |
305 | } | 312 | } |
306 | 313 | ||
@@ -311,16 +318,17 @@ namespace OpenSim.Region.CoreModules | |||
311 | { | 318 | { |
312 | if (!float.TryParse(cmdparams[3], out value)) | 319 | if (!float.TryParse(cmdparams[3], out value)) |
313 | { | 320 | { |
314 | m_log.InfoFormat("[WIND] Invalid value {0}", cmdparams[3]); | 321 | MainConsole.Instance.OutputFormat("Invalid value {0}", cmdparams[3]); |
315 | } | 322 | } |
316 | 323 | ||
317 | try | 324 | try |
318 | { | 325 | { |
319 | WindParamSet(plugin, param, value); | 326 | WindParamSet(plugin, param, value); |
327 | MainConsole.Instance.OutputFormat("{0} set to {1}", param, value); | ||
320 | } | 328 | } |
321 | catch (Exception e) | 329 | catch (Exception e) |
322 | { | 330 | { |
323 | m_log.InfoFormat("[WIND] {0}", e.Message); | 331 | MainConsole.Instance.OutputFormat("{0}", e.Message); |
324 | } | 332 | } |
325 | } | 333 | } |
326 | else | 334 | else |
@@ -328,11 +336,11 @@ namespace OpenSim.Region.CoreModules | |||
328 | try | 336 | try |
329 | { | 337 | { |
330 | value = WindParamGet(plugin, param); | 338 | value = WindParamGet(plugin, param); |
331 | m_log.InfoFormat("[WIND] {0} : {1}", param, value); | 339 | MainConsole.Instance.OutputFormat("{0} : {1}", param, value); |
332 | } | 340 | } |
333 | catch (Exception e) | 341 | catch (Exception e) |
334 | { | 342 | { |
335 | m_log.InfoFormat("[WIND] {0}", e.Message); | 343 | MainConsole.Instance.OutputFormat("{0}", e.Message); |
336 | } | 344 | } |
337 | } | 345 | } |
338 | 346 | ||
@@ -366,13 +374,11 @@ namespace OpenSim.Region.CoreModules | |||
366 | { | 374 | { |
367 | IWindModelPlugin windPlugin = m_availableWindPlugins[plugin]; | 375 | IWindModelPlugin windPlugin = m_availableWindPlugins[plugin]; |
368 | windPlugin.WindParamSet(param, value); | 376 | windPlugin.WindParamSet(param, value); |
369 | m_log.InfoFormat("[WIND] {0} set to {1}", param, value); | ||
370 | } | 377 | } |
371 | else | 378 | else |
372 | { | 379 | { |
373 | throw new Exception(String.Format("Could not find plugin {0}", plugin)); | 380 | throw new Exception(String.Format("Could not find plugin {0}", plugin)); |
374 | } | 381 | } |
375 | |||
376 | } | 382 | } |
377 | 383 | ||
378 | public float WindParamGet(string plugin, string param) | 384 | public float WindParamGet(string plugin, string param) |
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index 708a9a2..d862f18 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs | |||
@@ -49,6 +49,18 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
49 | List<Scene> m_scenes = new List<Scene>(); | 49 | List<Scene> m_scenes = new List<Scene>(); |
50 | List<UUID> m_Clients; | 50 | List<UUID> m_Clients; |
51 | 51 | ||
52 | IWorldMapModule m_WorldMap; | ||
53 | IWorldMapModule WorldMap | ||
54 | { | ||
55 | get | ||
56 | { | ||
57 | if (m_WorldMap == null) | ||
58 | m_WorldMap = m_scene.RequestModuleInterface<IWorldMapModule>(); | ||
59 | return m_WorldMap; | ||
60 | } | ||
61 | |||
62 | } | ||
63 | |||
52 | #region ISharedRegionModule Members | 64 | #region ISharedRegionModule Members |
53 | public void Initialise(IConfigSource source) | 65 | public void Initialise(IConfigSource source) |
54 | { | 66 | { |
@@ -64,6 +76,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
64 | m_scenes.Add(scene); | 76 | m_scenes.Add(scene); |
65 | scene.EventManager.OnNewClient += OnNewClient; | 77 | scene.EventManager.OnNewClient += OnNewClient; |
66 | m_Clients = new List<UUID>(); | 78 | m_Clients = new List<UUID>(); |
79 | |||
67 | } | 80 | } |
68 | 81 | ||
69 | public void RemoveRegion(Scene scene) | 82 | public void RemoveRegion(Scene scene) |
@@ -129,7 +142,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
129 | private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) | 142 | private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) |
130 | { | 143 | { |
131 | List<MapBlockData> blocks = new List<MapBlockData>(); | 144 | List<MapBlockData> blocks = new List<MapBlockData>(); |
132 | MapBlockData data; | ||
133 | if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) | 145 | if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) |
134 | { | 146 | { |
135 | // final block, closing the search result | 147 | // final block, closing the search result |
@@ -143,50 +155,51 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
143 | } | 155 | } |
144 | 156 | ||
145 | 157 | ||
146 | //m_log.DebugFormat("MAP NAME=({0})", mapName); | 158 | List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); |
147 | 159 | ||
148 | // Hack to get around the fact that ll V3 now drops the port from the | ||
149 | // map name. See https://jira.secondlife.com/browse/VWR-28570 | ||
150 | // | ||
151 | // Caller, use this magic form instead: | ||
152 | // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 | ||
153 | // or url encode if possible. | ||
154 | // the hacks we do with this viewer... | ||
155 | // | ||
156 | string mapNameOrig = mapName; | 160 | string mapNameOrig = mapName; |
157 | if (mapName.Contains("|")) | 161 | if (regionInfos.Count == 0) |
158 | mapName = mapName.Replace('|', ':'); | 162 | { |
159 | if (mapName.Contains("+")) | 163 | // Hack to get around the fact that ll V3 now drops the port from the |
160 | mapName = mapName.Replace('+', ' '); | 164 | // map name. See https://jira.secondlife.com/browse/VWR-28570 |
161 | if (mapName.Contains("!")) | 165 | // |
162 | mapName = mapName.Replace('!', '/'); | 166 | // Caller, use this magic form instead: |
167 | // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 | ||
168 | // or url encode if possible. | ||
169 | // the hacks we do with this viewer... | ||
170 | // | ||
171 | if (mapName.Contains("|")) | ||
172 | mapName = mapName.Replace('|', ':'); | ||
173 | if (mapName.Contains("+")) | ||
174 | mapName = mapName.Replace('+', ' '); | ||
175 | if (mapName.Contains("!")) | ||
176 | mapName = mapName.Replace('!', '/'); | ||
177 | |||
178 | if (mapName != mapNameOrig) | ||
179 | regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); | ||
180 | } | ||
163 | 181 | ||
164 | // try to fetch from GridServer | ||
165 | List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); | ||
166 | |||
167 | m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); | 182 | m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); |
183 | |||
168 | if (regionInfos.Count > 0) | 184 | if (regionInfos.Count > 0) |
169 | { | 185 | { |
170 | foreach (GridRegion info in regionInfos) | 186 | foreach (GridRegion info in regionInfos) |
171 | { | 187 | { |
172 | data = new MapBlockData(); | 188 | if ((flags & 2) == 2) // V2 sends this |
173 | data.Agents = 0; | 189 | { |
174 | data.Access = info.Access; | 190 | List<MapBlockData> datas = WorldMap.Map2BlockFromGridRegion(info, flags); |
175 | if (flags == 2) // V2 sends this | 191 | // ugh! V2-3 is very sensitive about the result being |
176 | data.MapImageId = UUID.Zero; | 192 | // exactly the same as the requested name |
177 | else | 193 | if (regionInfos.Count == 1 && (mapName != mapNameOrig)) |
178 | data.MapImageId = info.TerrainImage; | 194 | datas.ForEach(d => d.Name = mapNameOrig); |
179 | // ugh! V2-3 is very sensitive about the result being | 195 | |
180 | // exactly the same as the requested name | 196 | blocks.AddRange(datas); |
181 | if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+")) | 197 | } |
182 | data.Name = mapNameOrig; | ||
183 | else | 198 | else |
184 | data.Name = info.RegionName; | 199 | { |
185 | data.RegionFlags = 0; // TODO not used? | 200 | MapBlockData data = WorldMap.MapBlockFromGridRegion(info, flags); |
186 | data.WaterHeight = 0; // not used | 201 | blocks.Add(data); |
187 | data.X = (ushort)(info.RegionLocX / Constants.RegionSize); | 202 | } |
188 | data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); | ||
189 | blocks.Add(data); | ||
190 | } | 203 | } |
191 | } | 204 | } |
192 | 205 | ||
@@ -204,8 +217,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
204 | { | 217 | { |
205 | if (regionInfos.Count == 0) | 218 | if (regionInfos.Count == 0) |
206 | remoteClient.SendAlertMessage("No regions found with that name."); | 219 | remoteClient.SendAlertMessage("No regions found with that name."); |
207 | else if (regionInfos.Count == 1) | 220 | // this seems unnecessary because found regions will show up in the search results |
208 | remoteClient.SendAlertMessage("Region found!"); | 221 | //else if (regionInfos.Count == 1) |
222 | // remoteClient.SendAlertMessage("Region found!"); | ||
209 | } | 223 | } |
210 | } | 224 | } |
211 | 225 | ||
@@ -214,7 +228,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
214 | // final block, closing the search result | 228 | // final block, closing the search result |
215 | MapBlockData data = new MapBlockData(); | 229 | MapBlockData data = new MapBlockData(); |
216 | data.Agents = 0; | 230 | data.Agents = 0; |
217 | data.Access = 255; | 231 | data.Access = (byte)SimAccess.NonExistent; |
218 | data.MapImageId = UUID.Zero; | 232 | data.MapImageId = UUID.Zero; |
219 | data.Name = ""; | 233 | data.Name = ""; |
220 | data.RegionFlags = 0; | 234 | data.RegionFlags = 0; |
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index e2f525c..db1187e 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | |||
@@ -59,13 +59,18 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
59 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldMapModule")] | 59 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldMapModule")] |
60 | public class WorldMapModule : INonSharedRegionModule, IWorldMapModule | 60 | public class WorldMapModule : INonSharedRegionModule, IWorldMapModule |
61 | { | 61 | { |
62 | private static readonly ILog m_log = | 62 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
63 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 63 | #pragma warning disable 414 |
64 | private static string LogHeader = "[WORLD MAP]"; | ||
65 | #pragma warning restore 414 | ||
64 | 66 | ||
65 | private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg"; | 67 | private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg"; |
66 | private static readonly UUID STOP_UUID = UUID.Random(); | 68 | private static readonly UUID STOP_UUID = UUID.Random(); |
67 | private static readonly string m_mapLayerPath = "0001/"; | 69 | private static readonly string m_mapLayerPath = "0001/"; |
68 | 70 | ||
71 | private IMapImageGenerator m_mapImageGenerator; | ||
72 | private IMapImageUploadModule m_mapImageServiceModule; | ||
73 | |||
69 | private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>(); | 74 | private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>(); |
70 | 75 | ||
71 | protected Scene m_scene; | 76 | protected Scene m_scene; |
@@ -81,19 +86,24 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
81 | private List<UUID> m_rootAgents = new List<UUID>(); | 86 | private List<UUID> m_rootAgents = new List<UUID>(); |
82 | private volatile bool threadrunning = false; | 87 | private volatile bool threadrunning = false; |
83 | 88 | ||
89 | private IServiceThrottleModule m_ServiceThrottle; | ||
90 | |||
84 | //private int CacheRegionsDistance = 256; | 91 | //private int CacheRegionsDistance = 256; |
85 | 92 | ||
86 | #region INonSharedRegionModule Members | 93 | #region INonSharedRegionModule Members |
87 | public virtual void Initialise (IConfigSource config) | 94 | public virtual void Initialise (IConfigSource config) |
88 | { | 95 | { |
89 | IConfig startupConfig = config.Configs["Startup"]; | 96 | string[] configSections = new string[] { "Map", "Startup" }; |
90 | if (startupConfig.GetString("WorldMapModule", "WorldMap") == "WorldMap") | 97 | |
98 | if (Util.GetConfigVarFromSections<string>( | ||
99 | config, "WorldMapModule", configSections, "WorldMap") == "WorldMap") | ||
91 | m_Enabled = true; | 100 | m_Enabled = true; |
92 | 101 | ||
93 | blacklistTimeout = startupConfig.GetInt("BlacklistTimeout", 10*60) * 1000; | 102 | blacklistTimeout |
103 | = Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60) * 1000; | ||
94 | } | 104 | } |
95 | 105 | ||
96 | public virtual void AddRegion (Scene scene) | 106 | public virtual void AddRegion(Scene scene) |
97 | { | 107 | { |
98 | if (!m_Enabled) | 108 | if (!m_Enabled) |
99 | return; | 109 | return; |
@@ -109,6 +119,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
109 | "export-map [<path>]", | 119 | "export-map [<path>]", |
110 | "Save an image of the world map", HandleExportWorldMapConsoleCommand); | 120 | "Save an image of the world map", HandleExportWorldMapConsoleCommand); |
111 | 121 | ||
122 | m_scene.AddCommand( | ||
123 | "Regions", this, "generate map", | ||
124 | "generate map", | ||
125 | "Generates and stores a new maptile.", HandleGenerateMapConsoleCommand); | ||
126 | |||
112 | AddHandlers(); | 127 | AddHandlers(); |
113 | } | 128 | } |
114 | } | 129 | } |
@@ -128,8 +143,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
128 | 143 | ||
129 | public virtual void RegionLoaded (Scene scene) | 144 | public virtual void RegionLoaded (Scene scene) |
130 | { | 145 | { |
131 | } | 146 | if (!m_Enabled) |
147 | return; | ||
132 | 148 | ||
149 | m_ServiceThrottle = scene.RequestModuleInterface<IServiceThrottleModule>(); | ||
150 | |||
151 | m_mapImageGenerator = m_scene.RequestModuleInterface<IMapImageGenerator>(); | ||
152 | m_mapImageServiceModule = m_scene.RequestModuleInterface<IMapImageUploadModule>(); | ||
153 | } | ||
133 | 154 | ||
134 | public virtual void Close() | 155 | public virtual void Close() |
135 | { | 156 | { |
@@ -156,7 +177,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
156 | regionimage = regionimage.Replace("-", ""); | 177 | regionimage = regionimage.Replace("-", ""); |
157 | m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage); | 178 | m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage); |
158 | 179 | ||
159 | MainServer.Instance.AddHTTPHandler(regionimage, OnHTTPGetMapImage); | 180 | MainServer.Instance.AddHTTPHandler(regionimage, |
181 | new GenericHTTPDOSProtector(OnHTTPGetMapImage, OnHTTPThrottled, new BasicDosProtectorOptions() | ||
182 | { | ||
183 | AllowXForwardedFor = false, | ||
184 | ForgetTimeSpan = TimeSpan.FromMinutes(2), | ||
185 | MaxRequestsInTimeframe = 4, | ||
186 | ReportingName = "MAPDOSPROTECTOR", | ||
187 | RequestTimeSpan = TimeSpan.FromSeconds(10), | ||
188 | ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod | ||
189 | }).Process); | ||
160 | MainServer.Instance.AddLLSDHandler( | 190 | MainServer.Instance.AddLLSDHandler( |
161 | "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest); | 191 | "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest); |
162 | 192 | ||
@@ -167,13 +197,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
167 | m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; | 197 | m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; |
168 | m_scene.EventManager.OnRegionUp += OnRegionUp; | 198 | m_scene.EventManager.OnRegionUp += OnRegionUp; |
169 | 199 | ||
170 | StartThread(new object()); | 200 | // StartThread(new object()); |
171 | } | 201 | } |
172 | 202 | ||
173 | // this has to be called with a lock on m_scene | 203 | // this has to be called with a lock on m_scene |
174 | protected virtual void RemoveHandlers() | 204 | protected virtual void RemoveHandlers() |
175 | { | 205 | { |
176 | StopThread(); | 206 | // StopThread(); |
177 | 207 | ||
178 | m_scene.EventManager.OnRegionUp -= OnRegionUp; | 208 | m_scene.EventManager.OnRegionUp -= OnRegionUp; |
179 | m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; | 209 | m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; |
@@ -259,15 +289,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
259 | { | 289 | { |
260 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; | 290 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; |
261 | 291 | ||
292 | // Get regions that are within 8 regions of here | ||
262 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 293 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
263 | (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, | 294 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 8), |
264 | (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, | 295 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 8), |
265 | (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, | 296 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 8), |
266 | (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); | 297 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 8) ); |
267 | foreach (GridRegion r in regions) | 298 | foreach (GridRegion r in regions) |
268 | { | 299 | { |
269 | MapBlockData block = new MapBlockData(); | 300 | MapBlockData block = MapBlockFromGridRegion(r, 0); |
270 | MapBlockFromGridRegion(block, r, 0); | ||
271 | mapBlocks.Add(block); | 301 | mapBlocks.Add(block); |
272 | } | 302 | } |
273 | avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); | 303 | avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); |
@@ -351,7 +381,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
351 | 381 | ||
352 | // m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread"); | 382 | // m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread"); |
353 | 383 | ||
354 | Watchdog.StartThread( | 384 | WorkManager.StartThread( |
355 | process, | 385 | process, |
356 | string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName), | 386 | string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName), |
357 | ThreadPriority.BelowNormal, | 387 | ThreadPriority.BelowNormal, |
@@ -387,24 +417,23 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
387 | } | 417 | } |
388 | uint xstart = 0; | 418 | uint xstart = 0; |
389 | uint ystart = 0; | 419 | uint ystart = 0; |
390 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); | 420 | Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); |
391 | if (itemtype == 6) // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots) | 421 | if (itemtype == (int)GridItemType.AgentLocations) |
392 | { | 422 | { |
393 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) | 423 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) |
394 | { | 424 | { |
395 | // Local Map Item Request | 425 | // Just requesting map info about the current, local region |
396 | int tc = Environment.TickCount; | 426 | int tc = Environment.TickCount; |
397 | List<mapItemReply> mapitems = new List<mapItemReply>(); | 427 | List<mapItemReply> mapitems = new List<mapItemReply>(); |
398 | mapItemReply mapitem = new mapItemReply(); | 428 | mapItemReply mapitem = new mapItemReply(); |
399 | if (m_scene.GetRootAgentCount() <= 1) | 429 | if (m_scene.GetRootAgentCount() <= 1) |
400 | { | 430 | { |
401 | mapitem = new mapItemReply(); | 431 | mapitem = new mapItemReply( |
402 | mapitem.x = (uint)(xstart + 1); | 432 | xstart + 1, |
403 | mapitem.y = (uint)(ystart + 1); | 433 | ystart + 1, |
404 | mapitem.id = UUID.Zero; | 434 | UUID.Zero, |
405 | mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()); | 435 | Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()), |
406 | mapitem.Extra = 0; | 436 | 0, 0); |
407 | mapitem.Extra2 = 0; | ||
408 | mapitems.Add(mapitem); | 437 | mapitems.Add(mapitem); |
409 | } | 438 | } |
410 | else | 439 | else |
@@ -414,13 +443,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
414 | // Don't send a green dot for yourself | 443 | // Don't send a green dot for yourself |
415 | if (sp.UUID != remoteClient.AgentId) | 444 | if (sp.UUID != remoteClient.AgentId) |
416 | { | 445 | { |
417 | mapitem = new mapItemReply(); | 446 | mapitem = new mapItemReply( |
418 | mapitem.x = (uint)(xstart + sp.AbsolutePosition.X); | 447 | xstart + (uint)sp.AbsolutePosition.X, |
419 | mapitem.y = (uint)(ystart + sp.AbsolutePosition.Y); | 448 | ystart + (uint)sp.AbsolutePosition.Y, |
420 | mapitem.id = UUID.Zero; | 449 | UUID.Zero, |
421 | mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()); | 450 | Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()), |
422 | mapitem.Extra = 1; | 451 | 1, 0); |
423 | mapitem.Extra2 = 0; | ||
424 | mapitems.Add(mapitem); | 452 | mapitems.Add(mapitem); |
425 | } | 453 | } |
426 | }); | 454 | }); |
@@ -435,7 +463,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
435 | RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); | 463 | RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); |
436 | } | 464 | } |
437 | } | 465 | } |
438 | else if (itemtype == 7) // Service 7 (MAP_ITEM_LAND_FOR_SALE) | 466 | else if (itemtype == (int)GridItemType.LandForSale) // Service 7 (MAP_ITEM_LAND_FOR_SALE) |
439 | { | 467 | { |
440 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) | 468 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) |
441 | { | 469 | { |
@@ -465,14 +493,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
465 | float x = (min.X+max.X)/2; | 493 | float x = (min.X+max.X)/2; |
466 | float y = (min.Y+max.Y)/2; | 494 | float y = (min.Y+max.Y)/2; |
467 | 495 | ||
468 | mapitem = new mapItemReply(); | 496 | mapitem = new mapItemReply( |
469 | mapitem.x = (uint)(xstart + x); | 497 | xstart + (uint)x, |
470 | mapitem.y = (uint)(ystart + y); | 498 | ystart + (uint)y, |
471 | // mapitem.z = (uint)m_scene.GetGroundHeight(x,y); | 499 | parcel.GlobalID, |
472 | mapitem.id = parcel.GlobalID; | 500 | parcel.Name, |
473 | mapitem.name = parcel.Name; | 501 | parcel.Area, |
474 | mapitem.Extra = parcel.Area; | 502 | parcel.SalePrice |
475 | mapitem.Extra2 = parcel.SalePrice; | 503 | ); |
476 | mapitems.Add(mapitem); | 504 | mapitems.Add(mapitem); |
477 | } | 505 | } |
478 | } | 506 | } |
@@ -487,7 +515,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
487 | RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); | 515 | RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); |
488 | } | 516 | } |
489 | } | 517 | } |
490 | else if (itemtype == 1) // Service 1 (MAP_ITEM_TELEHUB) | 518 | else if (itemtype == (int)GridItemType.Telehub) // Service 1 (MAP_ITEM_TELEHUB) |
491 | { | 519 | { |
492 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) | 520 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) |
493 | { | 521 | { |
@@ -497,13 +525,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
497 | SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); | 525 | SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); |
498 | if (sog != null) | 526 | if (sog != null) |
499 | { | 527 | { |
500 | mapitem = new mapItemReply(); | 528 | mapitem = new mapItemReply( |
501 | mapitem.x = (uint)(xstart + sog.AbsolutePosition.X); | 529 | xstart + (uint)sog.AbsolutePosition.X, |
502 | mapitem.y = (uint)(ystart + sog.AbsolutePosition.Y); | 530 | ystart + (uint)sog.AbsolutePosition.Y, |
503 | mapitem.id = UUID.Zero; | 531 | UUID.Zero, |
504 | mapitem.name = sog.Name; | 532 | sog.Name, |
505 | mapitem.Extra = 0; // color (not used) | 533 | 0, // color (not used) |
506 | mapitem.Extra2 = 0; // 0 = telehub / 1 = infohub | 534 | 0 // 0 = telehub / 1 = infohub |
535 | ); | ||
507 | mapitems.Add(mapitem); | 536 | mapitems.Add(mapitem); |
508 | 537 | ||
509 | remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); | 538 | remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); |
@@ -523,7 +552,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
523 | /// </summary> | 552 | /// </summary> |
524 | public void process() | 553 | public void process() |
525 | { | 554 | { |
526 | const int MAX_ASYNC_REQUESTS = 20; | 555 | //const int MAX_ASYNC_REQUESTS = 20; |
527 | try | 556 | try |
528 | { | 557 | { |
529 | while (true) | 558 | while (true) |
@@ -568,13 +597,44 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
568 | Watchdog.RemoveThread(); | 597 | Watchdog.RemoveThread(); |
569 | } | 598 | } |
570 | 599 | ||
600 | const int MAX_ASYNC_REQUESTS = 20; | ||
601 | |||
571 | /// <summary> | 602 | /// <summary> |
572 | /// Enqueues the map item request into the processing thread | 603 | /// Enqueues the map item request into the services throttle processing thread |
573 | /// </summary> | 604 | /// </summary> |
574 | /// <param name="state"></param> | 605 | /// <param name="state"></param> |
575 | public void EnqueueMapItemRequest(MapRequestState state) | 606 | public void EnqueueMapItemRequest(MapRequestState st) |
576 | { | 607 | { |
577 | requests.Enqueue(state); | 608 | |
609 | m_ServiceThrottle.Enqueue("map-item", st.regionhandle.ToString() + st.agentID.ToString(), delegate | ||
610 | { | ||
611 | if (st.agentID != UUID.Zero) | ||
612 | { | ||
613 | bool dorequest = true; | ||
614 | lock (m_rootAgents) | ||
615 | { | ||
616 | if (!m_rootAgents.Contains(st.agentID)) | ||
617 | dorequest = false; | ||
618 | } | ||
619 | |||
620 | if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) | ||
621 | { | ||
622 | if (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break | ||
623 | { | ||
624 | // AH!!! Recursive ! | ||
625 | // Put this request back in the queue and return | ||
626 | EnqueueMapItemRequest(st); | ||
627 | return; | ||
628 | } | ||
629 | |||
630 | RequestMapItemsDelegate d = RequestMapItemsAsync; | ||
631 | d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); | ||
632 | //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); | ||
633 | //RequestMapItemsCompleted(response); | ||
634 | Interlocked.Increment(ref nAsyncRequests); | ||
635 | } | ||
636 | } | ||
637 | }); | ||
578 | } | 638 | } |
579 | 639 | ||
580 | /// <summary> | 640 | /// <summary> |
@@ -622,19 +682,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
622 | { | 682 | { |
623 | OSDMap mapitem = (OSDMap)itemarray[i]; | 683 | OSDMap mapitem = (OSDMap)itemarray[i]; |
624 | mapItemReply mi = new mapItemReply(); | 684 | mapItemReply mi = new mapItemReply(); |
625 | mi.x = (uint)mapitem["X"].AsInteger(); | 685 | mi.FromOSD(mapitem); |
626 | mi.y = (uint)mapitem["Y"].AsInteger(); | ||
627 | mi.id = mapitem["ID"].AsUUID(); | ||
628 | mi.Extra = mapitem["Extra"].AsInteger(); | ||
629 | mi.Extra2 = mapitem["Extra2"].AsInteger(); | ||
630 | mi.name = mapitem["Name"].AsString(); | ||
631 | returnitems.Add(mi); | 686 | returnitems.Add(mi); |
632 | } | 687 | } |
633 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); | 688 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); |
634 | } | 689 | } |
635 | 690 | ||
636 | // Service 7 (MAP_ITEM_LAND_FOR_SALE) | 691 | // Service 7 (MAP_ITEM_LAND_FOR_SALE) |
637 | uint itemtype = 7; | 692 | uint itemtype = (uint)GridItemType.LandForSale; |
638 | 693 | ||
639 | if (response.ContainsKey(itemtype.ToString())) | 694 | if (response.ContainsKey(itemtype.ToString())) |
640 | { | 695 | { |
@@ -644,19 +699,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
644 | { | 699 | { |
645 | OSDMap mapitem = (OSDMap)itemarray[i]; | 700 | OSDMap mapitem = (OSDMap)itemarray[i]; |
646 | mapItemReply mi = new mapItemReply(); | 701 | mapItemReply mi = new mapItemReply(); |
647 | mi.x = (uint)mapitem["X"].AsInteger(); | 702 | mi.FromOSD(mapitem); |
648 | mi.y = (uint)mapitem["Y"].AsInteger(); | ||
649 | mi.id = mapitem["ID"].AsUUID(); | ||
650 | mi.Extra = mapitem["Extra"].AsInteger(); | ||
651 | mi.Extra2 = mapitem["Extra2"].AsInteger(); | ||
652 | mi.name = mapitem["Name"].AsString(); | ||
653 | returnitems.Add(mi); | 703 | returnitems.Add(mi); |
654 | } | 704 | } |
655 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); | 705 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); |
656 | } | 706 | } |
657 | 707 | ||
658 | // Service 1 (MAP_ITEM_TELEHUB) | 708 | // Service 1 (MAP_ITEM_TELEHUB) |
659 | itemtype = 1; | 709 | itemtype = (uint)GridItemType.Telehub; |
660 | 710 | ||
661 | if (response.ContainsKey(itemtype.ToString())) | 711 | if (response.ContainsKey(itemtype.ToString())) |
662 | { | 712 | { |
@@ -666,12 +716,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
666 | { | 716 | { |
667 | OSDMap mapitem = (OSDMap)itemarray[i]; | 717 | OSDMap mapitem = (OSDMap)itemarray[i]; |
668 | mapItemReply mi = new mapItemReply(); | 718 | mapItemReply mi = new mapItemReply(); |
669 | mi.x = (uint)mapitem["X"].AsInteger(); | 719 | mi.FromOSD(mapitem); |
670 | mi.y = (uint)mapitem["Y"].AsInteger(); | ||
671 | mi.id = mapitem["ID"].AsUUID(); | ||
672 | mi.Extra = mapitem["Extra"].AsInteger(); | ||
673 | mi.Extra2 = mapitem["Extra2"].AsInteger(); | ||
674 | mi.name = mapitem["Name"].AsString(); | ||
675 | returnitems.Add(mi); | 720 | returnitems.Add(mi); |
676 | } | 721 | } |
677 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); | 722 | av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); |
@@ -754,7 +799,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
754 | if (httpserver.Length == 0) | 799 | if (httpserver.Length == 0) |
755 | { | 800 | { |
756 | uint x = 0, y = 0; | 801 | uint x = 0, y = 0; |
757 | Utils.LongToUInts(regionhandle, out x, out y); | 802 | Util.RegionHandleToWorldLoc(regionhandle, out x, out y); |
758 | GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); | 803 | GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); |
759 | 804 | ||
760 | if (mreg != null) | 805 | if (mreg != null) |
@@ -861,24 +906,26 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
861 | finally | 906 | finally |
862 | { | 907 | { |
863 | if (os != null) | 908 | if (os != null) |
864 | os.Close(); | 909 | os.Dispose(); |
865 | } | 910 | } |
866 | 911 | ||
867 | string response_mapItems_reply = null; | 912 | string response_mapItems_reply = null; |
868 | { // get the response | 913 | { |
869 | StreamReader sr = null; | ||
870 | try | 914 | try |
871 | { | 915 | { |
872 | WebResponse webResponse = mapitemsrequest.GetResponse(); | 916 | using (WebResponse webResponse = mapitemsrequest.GetResponse()) |
873 | if (webResponse != null) | ||
874 | { | ||
875 | sr = new StreamReader(webResponse.GetResponseStream()); | ||
876 | response_mapItems_reply = sr.ReadToEnd().Trim(); | ||
877 | } | ||
878 | else | ||
879 | { | 917 | { |
880 | return new OSDMap(); | 918 | if (webResponse != null) |
881 | } | 919 | { |
920 | using (Stream s = webResponse.GetResponseStream()) | ||
921 | using (StreamReader sr = new StreamReader(s)) | ||
922 | response_mapItems_reply = sr.ReadToEnd().Trim(); | ||
923 | } | ||
924 | else | ||
925 | { | ||
926 | return new OSDMap(); | ||
927 | } | ||
928 | } | ||
882 | } | 929 | } |
883 | catch (WebException) | 930 | catch (WebException) |
884 | { | 931 | { |
@@ -905,11 +952,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
905 | 952 | ||
906 | return responseMap; | 953 | return responseMap; |
907 | } | 954 | } |
908 | finally | ||
909 | { | ||
910 | if (sr != null) | ||
911 | sr.Close(); | ||
912 | } | ||
913 | 955 | ||
914 | OSD rezResponse = null; | 956 | OSD rezResponse = null; |
915 | try | 957 | try |
@@ -923,6 +965,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
923 | { | 965 | { |
924 | m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message); | 966 | m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message); |
925 | responseMap["connect"] = OSD.FromBoolean(false); | 967 | responseMap["connect"] = OSD.FromBoolean(false); |
968 | |||
926 | lock (m_blacklistedregions) | 969 | lock (m_blacklistedregions) |
927 | { | 970 | { |
928 | if (!m_blacklistedregions.ContainsKey(regionhandle)) | 971 | if (!m_blacklistedregions.ContainsKey(regionhandle)) |
@@ -955,7 +998,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
955 | /// <param name="maxY"></param> | 998 | /// <param name="maxY"></param> |
956 | public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) | 999 | public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) |
957 | { | 1000 | { |
958 | //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); | ||
959 | if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible | 1001 | if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible |
960 | { | 1002 | { |
961 | List<MapBlockData> response = new List<MapBlockData>(); | 1003 | List<MapBlockData> response = new List<MapBlockData>(); |
@@ -964,22 +1006,24 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
964 | // on an unloaded square. | 1006 | // on an unloaded square. |
965 | // But make sure: Look whether the one we requested is in there | 1007 | // But make sure: Look whether the one we requested is in there |
966 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 1008 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
967 | minX * (int)Constants.RegionSize, | 1009 | (int)Util.RegionToWorldLoc((uint)minX), (int)Util.RegionToWorldLoc((uint)maxX), |
968 | maxX * (int)Constants.RegionSize, | 1010 | (int)Util.RegionToWorldLoc((uint)minY), (int)Util.RegionToWorldLoc((uint)maxY) ); |
969 | minY * (int)Constants.RegionSize, | ||
970 | maxY * (int)Constants.RegionSize); | ||
971 | 1011 | ||
1012 | m_log.DebugFormat("[WORLD MAP MODULE] RequestMapBlocks min=<{0},{1}>, max=<{2},{3}>, flag={4}, cntFound={5}", | ||
1013 | minX, minY, maxX, maxY, flag.ToString("X"), regions.Count); | ||
972 | if (regions != null) | 1014 | if (regions != null) |
973 | { | 1015 | { |
974 | foreach (GridRegion r in regions) | 1016 | foreach (GridRegion r in regions) |
975 | { | 1017 | { |
976 | if ((r.RegionLocX == minX * (int)Constants.RegionSize) && | 1018 | if (r.RegionLocX == Util.RegionToWorldLoc((uint)minX) |
977 | (r.RegionLocY == minY * (int)Constants.RegionSize)) | 1019 | && r.RegionLocY == Util.RegionToWorldLoc((uint)minY) ) |
978 | { | 1020 | { |
979 | // found it => add it to response | 1021 | // found it => add it to response |
980 | MapBlockData block = new MapBlockData(); | 1022 | // Version 2 viewers can handle the larger regions |
981 | MapBlockFromGridRegion(block, r, flag); | 1023 | if ((flag & 2) == 2) |
982 | response.Add(block); | 1024 | response.AddRange(Map2BlockFromGridRegion(r, flag)); |
1025 | else | ||
1026 | response.Add(MapBlockFromGridRegion(r, flag)); | ||
983 | break; | 1027 | break; |
984 | } | 1028 | } |
985 | } | 1029 | } |
@@ -991,7 +1035,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
991 | MapBlockData block = new MapBlockData(); | 1035 | MapBlockData block = new MapBlockData(); |
992 | block.X = (ushort)minX; | 1036 | block.X = (ushort)minX; |
993 | block.Y = (ushort)minY; | 1037 | block.Y = (ushort)minY; |
994 | block.Access = 254; // means 'simulator is offline' | 1038 | block.Access = (byte)SimAccess.Down; // means 'simulator is offline' |
1039 | // block.Access = (byte)SimAccess.NonExistent; | ||
995 | response.Add(block); | 1040 | response.Add(block); |
996 | } | 1041 | } |
997 | // The lower 16 bits are an unsigned int16 | 1042 | // The lower 16 bits are an unsigned int16 |
@@ -1008,39 +1053,94 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1008 | { | 1053 | { |
1009 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); | 1054 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); |
1010 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 1055 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
1011 | (minX - 4) * (int)Constants.RegionSize, | 1056 | (int)Util.RegionToWorldLoc((uint)(minX - 4)), (int)Util.RegionToWorldLoc((uint)(maxX + 4)), |
1012 | (maxX + 4) * (int)Constants.RegionSize, | 1057 | (int)Util.RegionToWorldLoc((uint)(minY - 4)), (int)Util.RegionToWorldLoc((uint)(maxY + 4)) ); |
1013 | (minY - 4) * (int)Constants.RegionSize, | 1058 | //m_log.DebugFormat("{0} GetAndSendBlocks. min=<{1},{2}>, max=<{3},{4}>, cntFound={5}", |
1014 | (maxY + 4) * (int)Constants.RegionSize); | 1059 | // LogHeader, minX, minY, maxX, maxY, regions.Count); |
1015 | foreach (GridRegion r in regions) | 1060 | foreach (GridRegion r in regions) |
1016 | { | 1061 | { |
1017 | MapBlockData block = new MapBlockData(); | 1062 | // Version 2 viewers can handle the larger regions |
1018 | MapBlockFromGridRegion(block, r, flag); | 1063 | if ((flag & 2) == 2) |
1019 | mapBlocks.Add(block); | 1064 | mapBlocks.AddRange(Map2BlockFromGridRegion(r, flag)); |
1065 | else | ||
1066 | mapBlocks.Add(MapBlockFromGridRegion(r, flag)); | ||
1020 | } | 1067 | } |
1021 | remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); | 1068 | remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); |
1022 | 1069 | ||
1023 | return mapBlocks; | 1070 | return mapBlocks; |
1024 | } | 1071 | } |
1025 | 1072 | ||
1026 | protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) | 1073 | // Fill a passed MapBlockData from a GridRegion |
1074 | public MapBlockData MapBlockFromGridRegion(GridRegion r, uint flag) | ||
1027 | { | 1075 | { |
1076 | MapBlockData block = new MapBlockData(); | ||
1077 | |||
1028 | block.Access = r.Access; | 1078 | block.Access = r.Access; |
1029 | switch (flag & 0xffff) | 1079 | switch (flag & 0xffff) |
1030 | { | 1080 | { |
1031 | case 0: | 1081 | case 0: |
1032 | block.MapImageId = r.TerrainImage; | 1082 | block.MapImageId = r.TerrainImage; |
1033 | break; | 1083 | break; |
1034 | case 2: | 1084 | case 2: |
1035 | block.MapImageId = r.ParcelImage; | 1085 | block.MapImageId = r.ParcelImage; |
1036 | break; | 1086 | break; |
1037 | default: | 1087 | default: |
1038 | block.MapImageId = UUID.Zero; | 1088 | block.MapImageId = UUID.Zero; |
1039 | break; | 1089 | break; |
1040 | } | 1090 | } |
1041 | block.Name = r.RegionName; | 1091 | block.Name = r.RegionName; |
1042 | block.X = (ushort)(r.RegionLocX / Constants.RegionSize); | 1092 | block.X = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocX); |
1043 | block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); | 1093 | block.Y = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocY); |
1094 | block.SizeX = (ushort) r.RegionSizeX; | ||
1095 | block.SizeY = (ushort) r.RegionSizeY; | ||
1096 | |||
1097 | return block; | ||
1098 | } | ||
1099 | |||
1100 | public List<MapBlockData> Map2BlockFromGridRegion(GridRegion r, uint flag) | ||
1101 | { | ||
1102 | List<MapBlockData> blocks = new List<MapBlockData>(); | ||
1103 | MapBlockData block = new MapBlockData(); | ||
1104 | if (r == null) | ||
1105 | { | ||
1106 | block.Access = (byte)SimAccess.Down; | ||
1107 | block.MapImageId = UUID.Zero; | ||
1108 | blocks.Add(block); | ||
1109 | } | ||
1110 | else | ||
1111 | { | ||
1112 | block.Access = r.Access; | ||
1113 | switch (flag & 0xffff) | ||
1114 | { | ||
1115 | case 0: | ||
1116 | block.MapImageId = r.TerrainImage; | ||
1117 | break; | ||
1118 | case 2: | ||
1119 | block.MapImageId = r.ParcelImage; | ||
1120 | break; | ||
1121 | default: | ||
1122 | block.MapImageId = UUID.Zero; | ||
1123 | break; | ||
1124 | } | ||
1125 | block.Name = r.RegionName; | ||
1126 | block.X = (ushort)(r.RegionLocX / Constants.RegionSize); | ||
1127 | block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); | ||
1128 | block.SizeX = (ushort)r.RegionSizeX; | ||
1129 | block.SizeY = (ushort)r.RegionSizeY; | ||
1130 | blocks.Add(block); | ||
1131 | } | ||
1132 | return blocks; | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | public Hashtable OnHTTPThrottled(Hashtable keysvals) | ||
1137 | { | ||
1138 | Hashtable reply = new Hashtable(); | ||
1139 | int statuscode = 500; | ||
1140 | reply["str_response_string"] = ""; | ||
1141 | reply["int_response_code"] = statuscode; | ||
1142 | reply["content_type"] = "text/plain"; | ||
1143 | return reply; | ||
1044 | } | 1144 | } |
1045 | 1145 | ||
1046 | public Hashtable OnHTTPGetMapImage(Hashtable keysvals) | 1146 | public Hashtable OnHTTPGetMapImage(Hashtable keysvals) |
@@ -1052,7 +1152,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1052 | 1152 | ||
1053 | if (myMapImageJPEG.Length == 0) | 1153 | if (myMapImageJPEG.Length == 0) |
1054 | { | 1154 | { |
1055 | MemoryStream imgstream = new MemoryStream(); | 1155 | MemoryStream imgstream = null; |
1056 | Bitmap mapTexture = new Bitmap(1,1); | 1156 | Bitmap mapTexture = new Bitmap(1,1); |
1057 | ManagedImage managedImage; | 1157 | ManagedImage managedImage; |
1058 | Image image = (Image)mapTexture; | 1158 | Image image = (Image)mapTexture; |
@@ -1099,10 +1199,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1099 | image.Dispose(); | 1199 | image.Dispose(); |
1100 | 1200 | ||
1101 | if (imgstream != null) | 1201 | if (imgstream != null) |
1102 | { | ||
1103 | imgstream.Close(); | ||
1104 | imgstream.Dispose(); | 1202 | imgstream.Dispose(); |
1105 | } | ||
1106 | } | 1203 | } |
1107 | } | 1204 | } |
1108 | else | 1205 | else |
@@ -1161,17 +1258,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1161 | 1258 | ||
1162 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); | 1259 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); |
1163 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 1260 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
1164 | (int)(m_scene.RegionInfo.RegionLocX - 9) * (int)Constants.RegionSize, | 1261 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 9), |
1165 | (int)(m_scene.RegionInfo.RegionLocX + 9) * (int)Constants.RegionSize, | 1262 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 9), |
1166 | (int)(m_scene.RegionInfo.RegionLocY - 9) * (int)Constants.RegionSize, | 1263 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 9), |
1167 | (int)(m_scene.RegionInfo.RegionLocY + 9) * (int)Constants.RegionSize); | 1264 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 9)); |
1168 | List<AssetBase> textures = new List<AssetBase>(); | 1265 | List<AssetBase> textures = new List<AssetBase>(); |
1169 | List<Image> bitImages = new List<Image>(); | 1266 | List<Image> bitImages = new List<Image>(); |
1170 | 1267 | ||
1171 | foreach (GridRegion r in regions) | 1268 | foreach (GridRegion r in regions) |
1172 | { | 1269 | { |
1173 | MapBlockData mapBlock = new MapBlockData(); | 1270 | MapBlockData mapBlock = MapBlockFromGridRegion(r, 0); |
1174 | MapBlockFromGridRegion(mapBlock, r, 0); | ||
1175 | AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); | 1271 | AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); |
1176 | 1272 | ||
1177 | if (texAsset != null) | 1273 | if (texAsset != null) |
@@ -1217,12 +1313,34 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1217 | m_scene.RegionInfo.RegionName, exportPath); | 1313 | m_scene.RegionInfo.RegionName, exportPath); |
1218 | } | 1314 | } |
1219 | 1315 | ||
1316 | public void HandleGenerateMapConsoleCommand(string module, string[] cmdparams) | ||
1317 | { | ||
1318 | Scene consoleScene = m_scene.ConsoleScene(); | ||
1319 | |||
1320 | if (consoleScene != null && consoleScene != m_scene) | ||
1321 | return; | ||
1322 | |||
1323 | if (m_mapImageGenerator == null) | ||
1324 | { | ||
1325 | Console.WriteLine("No map image generator available for {0}", m_scene.Name); | ||
1326 | return; | ||
1327 | } | ||
1328 | |||
1329 | using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile()) | ||
1330 | { | ||
1331 | GenerateMaptile(mapbmp); | ||
1332 | m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp); | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1220 | public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint) | 1336 | public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint) |
1221 | { | 1337 | { |
1222 | uint xstart = 0; | 1338 | uint xstart = 0; |
1223 | uint ystart = 0; | 1339 | uint ystart = 0; |
1224 | 1340 | ||
1225 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart); | 1341 | Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle,out xstart,out ystart); |
1342 | // m_log.DebugFormat("{0} HandleRemoteMapItemRequest. loc=<{1},{2}>", | ||
1343 | // LogHeader, Util.WorldToRegionLoc(xstart), Util.WorldToRegionLoc(ystart)); | ||
1226 | 1344 | ||
1227 | // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots) | 1345 | // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots) |
1228 | 1346 | ||
@@ -1337,20 +1455,35 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1337 | 1455 | ||
1338 | public void GenerateMaptile() | 1456 | public void GenerateMaptile() |
1339 | { | 1457 | { |
1340 | // Cannot create a map for a nonexistant heightmap | 1458 | // Cannot create a map for a nonexistent heightmap |
1341 | if (m_scene.Heightmap == null) | 1459 | if (m_scene.Heightmap == null) |
1342 | return; | 1460 | return; |
1343 | 1461 | ||
1344 | //create a texture asset of the terrain | 1462 | m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.Name); |
1345 | IMapImageGenerator terrain = m_scene.RequestModuleInterface<IMapImageGenerator>(); | 1463 | |
1346 | if (terrain == null) | 1464 | using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile()) |
1347 | return; | 1465 | { |
1466 | // V1 (This Module) | ||
1467 | GenerateMaptile(mapbmp); | ||
1468 | |||
1469 | // v2/3 (MapImageServiceModule) | ||
1470 | m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp); | ||
1471 | } | ||
1472 | } | ||
1348 | 1473 | ||
1349 | m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName); | 1474 | private void GenerateMaptile(Bitmap mapbmp) |
1475 | { | ||
1476 | byte[] data; | ||
1350 | 1477 | ||
1351 | byte[] data = terrain.WriteJpeg2000Image(); | 1478 | try |
1352 | if (data == null) | 1479 | { |
1480 | data = OpenJPEG.EncodeFromImage(mapbmp, true); | ||
1481 | } | ||
1482 | catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke | ||
1483 | { | ||
1484 | m_log.Error("[WORLD MAP]: Failed generating terrain map: " + e); | ||
1353 | return; | 1485 | return; |
1486 | } | ||
1354 | 1487 | ||
1355 | byte[] overlay = GenerateOverlay(); | 1488 | byte[] overlay = GenerateOverlay(); |
1356 | 1489 | ||
@@ -1448,62 +1581,80 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1448 | 1581 | ||
1449 | private Byte[] GenerateOverlay() | 1582 | private Byte[] GenerateOverlay() |
1450 | { | 1583 | { |
1451 | Bitmap overlay = new Bitmap(256, 256); | 1584 | // These need to be ints for bitmap generation |
1585 | int regionSizeX = (int)m_scene.RegionInfo.RegionSizeX; | ||
1586 | int regionSizeY = (int)m_scene.RegionInfo.RegionSizeY; | ||
1452 | 1587 | ||
1453 | bool[,] saleBitmap = new bool[64, 64]; | 1588 | int landTileSize = LandManagementModule.LandUnit; |
1454 | for (int x = 0 ; x < 64 ; x++) | 1589 | int regionLandTilesX = regionSizeX / landTileSize; |
1455 | { | 1590 | int regionLandTilesY = regionSizeY / landTileSize; |
1456 | for (int y = 0 ; y < 64 ; y++) | ||
1457 | saleBitmap[x, y] = false; | ||
1458 | } | ||
1459 | 1591 | ||
1460 | bool landForSale = false; | 1592 | using (Bitmap overlay = new Bitmap(regionSizeX, regionSizeY)) |
1593 | { | ||
1594 | bool[,] saleBitmap = new bool[regionLandTilesX, regionLandTilesY]; | ||
1595 | for (int x = 0; x < regionLandTilesX; x++) | ||
1596 | { | ||
1597 | for (int y = 0; y < regionLandTilesY; y++) | ||
1598 | saleBitmap[x, y] = false; | ||
1599 | } | ||
1461 | 1600 | ||
1462 | List<ILandObject> parcels = m_scene.LandChannel.AllParcels(); | 1601 | bool landForSale = false; |
1463 | 1602 | ||
1464 | Color background = Color.FromArgb(0, 0, 0, 0); | 1603 | List<ILandObject> parcels = m_scene.LandChannel.AllParcels(); |
1465 | SolidBrush transparent = new SolidBrush(background); | ||
1466 | Graphics g = Graphics.FromImage(overlay); | ||
1467 | g.FillRectangle(transparent, 0, 0, 256, 256); | ||
1468 | 1604 | ||
1469 | SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)); | 1605 | Color background = Color.FromArgb(0, 0, 0, 0); |
1470 | 1606 | ||
1471 | foreach (ILandObject land in parcels) | 1607 | using (Graphics g = Graphics.FromImage(overlay)) |
1472 | { | ||
1473 | // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags); | ||
1474 | if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0) | ||
1475 | { | 1608 | { |
1476 | landForSale = true; | 1609 | using (SolidBrush transparent = new SolidBrush(background)) |
1610 | g.FillRectangle(transparent, 0, 0, regionSizeX, regionSizeY); | ||
1477 | 1611 | ||
1478 | saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap()); | 1612 | foreach (ILandObject land in parcels) |
1479 | } | 1613 | { |
1480 | } | 1614 | // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags); |
1615 | if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0) | ||
1616 | { | ||
1617 | landForSale = true; | ||
1481 | 1618 | ||
1482 | if (!landForSale) | 1619 | saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap()); |
1483 | { | 1620 | } |
1484 | m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName); | 1621 | } |
1485 | return null; | 1622 | |
1486 | } | 1623 | if (!landForSale) |
1624 | { | ||
1625 | m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName); | ||
1626 | return null; | ||
1627 | } | ||
1487 | 1628 | ||
1488 | m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName); | 1629 | m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName); |
1489 | 1630 | ||
1490 | for (int x = 0 ; x < 64 ; x++) | 1631 | using (SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9))) |
1491 | { | 1632 | { |
1492 | for (int y = 0 ; y < 64 ; y++) | 1633 | for (int x = 0 ; x < regionLandTilesX ; x++) |
1634 | { | ||
1635 | for (int y = 0 ; y < regionLandTilesY ; y++) | ||
1636 | { | ||
1637 | if (saleBitmap[x, y]) | ||
1638 | g.FillRectangle( | ||
1639 | yellow, x * landTileSize, | ||
1640 | regionSizeX - landTileSize - (y * landTileSize), | ||
1641 | landTileSize, | ||
1642 | landTileSize); | ||
1643 | } | ||
1644 | } | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | try | ||
1493 | { | 1649 | { |
1494 | if (saleBitmap[x, y]) | 1650 | return OpenJPEG.EncodeFromImage(overlay, true); |
1495 | g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4); | 1651 | } |
1652 | catch (Exception e) | ||
1653 | { | ||
1654 | m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString()); | ||
1496 | } | 1655 | } |
1497 | } | 1656 | } |
1498 | 1657 | ||
1499 | try | ||
1500 | { | ||
1501 | return OpenJPEG.EncodeFromImage(overlay, true); | ||
1502 | } | ||
1503 | catch (Exception e) | ||
1504 | { | ||
1505 | m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString()); | ||
1506 | } | ||
1507 | return null; | 1658 | return null; |
1508 | } | 1659 | } |
1509 | } | 1660 | } |