diff --git a/OpenSim/Framework/RegionSettings.cs b/OpenSim/Framework/RegionSettings.cs index db8c53ef95..a895c40cc1 100644 --- a/OpenSim/Framework/RegionSettings.cs +++ b/OpenSim/Framework/RegionSettings.cs @@ -482,21 +482,14 @@ namespace OpenSim.Framework set { m_LoadedCreationID = value; } } - // Connected Telehub object - private UUID m_TelehubObject = UUID.Zero; - public UUID TelehubObject - { - get - { - return m_TelehubObject; - } - set - { - m_TelehubObject = value; - } - } + /// + /// Connected Telehub object + /// + public UUID TelehubObject { get; set; } - // Our Connected Telehub's SpawnPoints + /// + /// Our connected Telehub's SpawnPoints + /// public List l_SpawnPoints = new List(); // Add a SpawnPoint diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index cb73e8f762..92491050b3 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -39,8 +39,32 @@ namespace OpenSim.Framework { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Asset types used only in OpenSim. + /// To avoid clashing with the code numbers used in Second Life, use only negative numbers here. + /// + public enum OpenSimAssetType : sbyte + { + Material = -2 + } + + #region SL / file extension / content-type conversions + /// + /// Returns the Enum entry corresponding to the given code, regardless of whether it belongs + /// to the AssetType or OpenSimAssetType enums. + /// + public static object AssetTypeFromCode(sbyte assetType) + { + if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType)) + return (OpenMetaverse.AssetType)assetType; + else if (Enum.IsDefined(typeof(OpenSimAssetType), assetType)) + return (OpenSimAssetType)assetType; + else + return OpenMetaverse.AssetType.Unknown; + } + private class TypeMapping { private sbyte assetType; @@ -56,12 +80,7 @@ namespace OpenSim.Framework public object AssetType { - get { - if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType)) - return (OpenMetaverse.AssetType)assetType; - else - return OpenMetaverse.AssetType.Unknown; - } + get { return AssetTypeFromCode(assetType); } } public InventoryType InventoryType @@ -102,6 +121,11 @@ namespace OpenSim.Framework : this((sbyte)assetType, inventoryType, contentType, null, extension) { } + + public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension) + : this((sbyte)assetType, inventoryType, contentType, null, extension) + { + } } /// @@ -142,7 +166,9 @@ namespace OpenSim.Framework new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"), new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), - new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm") + new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"), + + new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material") }; private static Dictionary asset2Content; diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs index 0c12787882..73ebfae234 100644 --- a/OpenSim/Framework/Serialization/ArchiveConstants.cs +++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.Text; using OpenMetaverse; +using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; namespace OpenSim.Framework.Serialization { @@ -128,6 +129,7 @@ namespace OpenSim.Framework.Serialization ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[(sbyte)OpenSimAssetType.Material] = ASSET_EXTENSION_SEPARATOR + "material.xml"; // Not sure if we'll ever see this EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart; @@ -152,6 +154,7 @@ namespace OpenSim.Framework.Serialization EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "material.xml"] = (sbyte)OpenSimAssetType.Material; } public static string CreateOarLandDataPath(LandData ld) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 202cc625a2..51433cbbc3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -162,6 +162,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC private int m_maxRTO = 60000; + /// + /// This is the percentage of the udp texture queue to add to the task queue since + /// textures are now generally handled through http. + /// + private double m_cannibalrate = 0.0; + private ClientInfo m_info = new ClientInfo(); /// @@ -201,6 +207,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Create an array of token buckets for this clients different throttle categories m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; + m_cannibalrate = rates.CannibalizeTextureRate; + for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { ThrottleOutPacketType type = (ThrottleOutPacketType)i; @@ -349,6 +357,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP texture = Math.Max(texture, LLUDPServer.MTU); asset = Math.Max(asset, LLUDPServer.MTU); + // Since most textures are now delivered through http, make it possible + // to cannibalize some of the bw from the texture throttle to use for + // the task queue (e.g. object updates) + task = task + (int)(m_cannibalrate * texture); + texture = (int)((1 - m_cannibalrate) * texture); + //int total = resend + land + wind + cloud + task + texture + asset; //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", // AgentID, resend, land, wind, cloud, task, texture, asset, total); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index c9aac0ba09..e5bae6ee6c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs @@ -59,6 +59,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Flag used to enable adaptive throttles public bool AdaptiveThrottlesEnabled; + /// Amount of the texture throttle to steal for the task throttle + public double CannibalizeTextureRate; + /// /// Default constructor /// @@ -80,6 +83,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP Total = throttleConfig.GetInt("client_throttle_max_bps", 0); AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); + + CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); + CannibalizeTextureRate = Util.Clamp(CannibalizeTextureRate,0.0, 0.9); } catch (Exception) { } } diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 6a5f8f397e..b270de9c89 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -771,7 +771,7 @@ namespace OpenSim.Region.CoreModules.Asset UuidGatherer gatherer = new UuidGatherer(m_AssetService); HashSet uniqueUuids = new HashSet(); - Dictionary assets = new Dictionary(); + Dictionary assets = new Dictionary(); foreach (Scene s in m_Scenes) { @@ -794,7 +794,7 @@ namespace OpenSim.Region.CoreModules.Asset else if (storeUncached) { AssetBase cachedAsset = m_AssetService.Get(assetID.ToString()); - if (cachedAsset == null && assets[assetID] != AssetType.Unknown) + if (cachedAsset == null && assets[assetID] != (sbyte)AssetType.Unknown) m_log.DebugFormat( "[FLOTSAM ASSET CACHE]: Could not find asset {0}, type {1} referenced by object {2} at {3} in scene {4} when pre-caching all scene assets", assetID, assets[assetID], e.Name, e.AbsolutePosition, s.Name); diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index 4ec8ae7aa7..429271916f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -78,7 +78,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// Used to collect the uuids of the assets that we need to save into the archive /// - protected Dictionary m_assetUuids = new Dictionary(); + protected Dictionary m_assetUuids = new Dictionary(); /// /// Used to collect the uuids of the users that we need to save into the archive @@ -187,7 +187,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // Don't chase down link asset items as they actually point to their target item IDs rather than an asset if (SaveAssets && itemAssetType != AssetType.Link && itemAssetType != AssetType.LinkFolder) - m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, m_assetUuids); + m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (sbyte)inventoryItem.AssetType, m_assetUuids); } /// diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 04a0db6b47..09b19757ee 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -182,11 +182,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); - Dictionary ids = new Dictionary(); + Dictionary ids = new Dictionary(); HGUuidGatherer uuidGatherer = new HGUuidGatherer(Scene.AssetService, url); uuidGatherer.GatherAssetUuids(so, ids); - foreach (KeyValuePair kvp in ids) + foreach (KeyValuePair kvp in ids) uuidGatherer.FetchAsset(kvp.Key); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index b7a4d1ac1c..d4fb1baf48 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs @@ -260,9 +260,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // The act of gathering UUIDs downloads some assets from the remote server // but not all... - Dictionary ids = new Dictionary(); + Dictionary ids = new Dictionary(); HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); - uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); + uuidGatherer.GatherAssetUuids(assetID, meta.Type, ids); m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count); bool success = true; foreach (UUID uuid in ids.Keys) @@ -286,9 +286,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); if (asset != null) { - Dictionary ids = new Dictionary(); + Dictionary ids = new Dictionary(); HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty); - uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); + uuidGatherer.GatherAssetUuids(asset.FullID, asset.Type, ids); bool success = false; foreach (UUID uuid in ids.Keys) { diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index 9f39aa2673..cd95ee9784 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs @@ -178,7 +178,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Archive the regions - Dictionary assetUuids = new Dictionary(); + Dictionary assetUuids = new Dictionary(); scenesGroup.ForEachScene(delegate(Scene scene) { @@ -216,7 +216,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver } } - private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary assetUuids) + private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary assetUuids) { m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); @@ -276,16 +276,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver RegionSettings regionSettings = scene.RegionInfo.RegionSettings; if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) - assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture; + assetUuids[regionSettings.TerrainTexture1] = (sbyte)AssetType.Texture; if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) - assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture; + assetUuids[regionSettings.TerrainTexture2] = (sbyte)AssetType.Texture; if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) - assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture; + assetUuids[regionSettings.TerrainTexture3] = (sbyte)AssetType.Texture; if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) - assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture; + assetUuids[regionSettings.TerrainTexture4] = (sbyte)AssetType.Texture; Save(scene, sceneObjects, regionDir); } diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index 96000234ff..2d0da61145 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs @@ -81,7 +81,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// uuids to request /// - protected IDictionary m_uuids; + protected IDictionary m_uuids; /// /// Callback used when all the assets requested have been received. @@ -115,7 +115,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver protected Dictionary m_options; protected internal AssetsRequest( - AssetsArchiver assetsArchiver, IDictionary uuids, + AssetsArchiver assetsArchiver, IDictionary uuids, IAssetService assetService, IUserAccountService userService, UUID scope, Dictionary options, AssetsRequestCallback assetsRequestCallback) @@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_requestCallbackTimer.Enabled = true; - foreach (KeyValuePair kvp in m_uuids) + foreach (KeyValuePair kvp in m_uuids) { // m_log.DebugFormat("[ARCHIVER]: Requesting asset {0}", kvp.Key); @@ -235,9 +235,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown) { - AssetType type = (AssetType)assetType; - m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, type); - fetchedAsset.Type = (sbyte)type; + m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, SLUtil.AssetTypeFromCode((sbyte)assetType)); + fetchedAsset.Type = (sbyte)assetType; } AssetRequestCallback(fetchedAssetID, this, fetchedAsset); diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs index 173b603fe5..1659493981 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs @@ -60,7 +60,7 @@ namespace OpenSim.Region.CoreModules.World.Estate public void Initialise() { - m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName); +// m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName); m_module.Scene.AddCommand("Regions", m_module, "set terrain texture", "set terrain texture [] []", diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 17387da751..3bd7b4a218 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -702,7 +702,7 @@ namespace OpenSim.Region.CoreModules.World.Estate } } - public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) + public void HandleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) { SceneObjectPart part; @@ -742,7 +742,9 @@ namespace OpenSim.Region.CoreModules.World.Estate default: break; } - SendTelehubInfo(client); + + if (client != null) + SendTelehubInfo(client); } private void SendSimulatorBlueBoxMessage( @@ -1214,7 +1216,7 @@ namespace OpenSim.Region.CoreModules.World.Estate client.OnEstateRestartSimRequest += handleEstateRestartSimRequest; client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest; client.OnEstateChangeInfo += handleEstateChangeInfo; - client.OnEstateManageTelehub += handleOnEstateManageTelehub; + client.OnEstateManageTelehub += HandleOnEstateManageTelehub; client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest; client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage; client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage; diff --git a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs index b67312e0b4..1a897219df 100644 --- a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs @@ -51,10 +51,17 @@ namespace OpenSim.Region.Framework.Interfaces UUID = 5 } + public struct JsonStoreStats + { + public int StoreCount; + } + public delegate void TakeValueCallback(string s); public interface IJsonStoreModule { + JsonStoreStats GetStoreStats(); + bool AttachObjectStore(UUID objectID); bool CreateStore(string value, ref UUID result); bool DestroyStore(UUID storeID); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index aee621f533..2f666c032c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3930,32 +3930,52 @@ namespace OpenSim.Region.Framework.Scenes } } +// m_log.DebugFormat( +// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}", +// RegionInfo.RegionSettings.TelehubObject, acd.Name, Name); + // Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && RegionInfo.EstateSettings.AllowDirectTeleport == false && !viahome && !godlike) { SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject); - // Can have multiple SpawnPoints - List spawnpoints = RegionInfo.RegionSettings.SpawnPoints(); - if (spawnpoints.Count > 1) + + if (telehub != null) { - // We have multiple SpawnPoints, Route the agent to a random or sequential one - if (SpawnPointRouting == "random") - acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); + // Can have multiple SpawnPoints + List spawnpoints = RegionInfo.RegionSettings.SpawnPoints(); + if (spawnpoints.Count > 1) + { + // We have multiple SpawnPoints, Route the agent to a random or sequential one + if (SpawnPointRouting == "random") + acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( + telehub.AbsolutePosition, + telehub.GroupRotation + ); + else + acd.startpos = spawnpoints[SpawnPoint()].GetLocation( + telehub.AbsolutePosition, + telehub.GroupRotation + ); + } + else if (spawnpoints.Count == 1) + { + // We have a single SpawnPoint and will route the agent to it + acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); + } else - acd.startpos = spawnpoints[SpawnPoint()].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); + { + m_log.DebugFormat( + "[SCENE]: No spawnpoints defined for telehub {0} for {1} in {2}. Continuing.", + RegionInfo.RegionSettings.TelehubObject, acd.Name, Name); + } } else { - // We have a single SpawnPoint and will route the agent to it - acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); + m_log.DebugFormat( + "[SCENE]: No telehub {0} found to direct {1} in {2}. Continuing.", + RegionInfo.RegionSettings.TelehubObject, acd.Name, Name); } return true; diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs new file mode 100644 index 0000000000..9a97acc176 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs @@ -0,0 +1,119 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.World.Estate; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Scene telehub tests + /// + /// + /// TODO: Tests which run through normal functionality. Currently, the only test is one that checks behaviour + /// in the case of an error condition + /// + [TestFixture] + public class SceneTelehubTests : OpenSimTestCase + { + /// + /// Test for desired behaviour when a telehub has no spawn points + /// + [Test] + public void TestNoTelehubSpawnPoints() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + EstateManagementModule emm = new EstateManagementModule(); + + SceneHelpers sh = new SceneHelpers(); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, emm); + + UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1); + + SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner); + + emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId); + scene.RegionInfo.EstateSettings.AllowDirectTeleport = false; + + // Must still be possible to successfully log in + UUID loggingInUserId = TestHelpers.ParseTail(0x2); + + UserAccount ua + = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password"); + + SceneHelpers.AddScenePresence(scene, ua); + + Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null); + } + + /// + /// Test for desired behaviour when the scene object nominated as a telehub object does not exist. + /// + [Test] + public void TestNoTelehubSceneObject() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + EstateManagementModule emm = new EstateManagementModule(); + + SceneHelpers sh = new SceneHelpers(); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, emm); + + UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1); + + SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner); + SceneObjectGroup spawnPointSo = SceneHelpers.AddSceneObject(scene, "spawnpointObject", telehubSceneObjectOwner); + + emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId); + emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "spawnpoint add", spawnPointSo.LocalId); + scene.RegionInfo.EstateSettings.AllowDirectTeleport = false; + + scene.DeleteSceneObject(telehubSo, false); + + // Must still be possible to successfully log in + UUID loggingInUserId = TestHelpers.ParseTail(0x2); + + UserAccount ua + = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password"); + + SceneHelpers.AddScenePresence(scene, ua); + + Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs index dd27294372..1e59e3f764 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs @@ -62,8 +62,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests = AssetHelpers.CreateAsset(corruptAssetUuid, AssetType.Notecard, "CORRUPT ASSET", UUID.Zero); m_assetService.Store(corruptAsset); - IDictionary foundAssetUuids = new Dictionary(); - m_uuidGatherer.GatherAssetUuids(corruptAssetUuid, AssetType.Object, foundAssetUuids); + IDictionary foundAssetUuids = new Dictionary(); + m_uuidGatherer.GatherAssetUuids(corruptAssetUuid, (sbyte)AssetType.Object, foundAssetUuids); // We count the uuid as gathered even if the asset itself is corrupt. Assert.That(foundAssetUuids.Count, Is.EqualTo(1)); @@ -78,9 +78,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestHelpers.InMethod(); UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); - IDictionary foundAssetUuids = new Dictionary(); + IDictionary foundAssetUuids = new Dictionary(); - m_uuidGatherer.GatherAssetUuids(missingAssetUuid, AssetType.Object, foundAssetUuids); + m_uuidGatherer.GatherAssetUuids(missingAssetUuid, (sbyte)AssetType.Object, foundAssetUuids); // We count the uuid as gathered even if the asset itself is missing. Assert.That(foundAssetUuids.Count, Is.EqualTo(1)); @@ -103,8 +103,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests AssetBase ncAsset = AssetHelpers.CreateNotecardAsset(ncAssetId, soAssetId.ToString()); m_assetService.Store(ncAsset); - IDictionary foundAssetUuids = new Dictionary(); - m_uuidGatherer.GatherAssetUuids(ncAssetId, AssetType.Notecard, foundAssetUuids); + IDictionary foundAssetUuids = new Dictionary(); + m_uuidGatherer.GatherAssetUuids(ncAssetId, (sbyte)AssetType.Notecard, foundAssetUuids); // We count the uuid as gathered even if the asset itself is corrupt. Assert.That(foundAssetUuids.Count, Is.EqualTo(2)); diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 3e074b9cfc..75a51b5e68 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -38,6 +38,7 @@ using OpenMetaverse.StructuredData; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Services.Interfaces; +using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; namespace OpenSim.Region.Framework.Scenes { @@ -83,7 +84,7 @@ namespace OpenSim.Region.Framework.Scenes /// The uuid of the asset for which to gather referenced assets /// The type of the asset for the uuid given /// The assets gathered - public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary assetUuids) + public void GatherAssetUuids(UUID assetUuid, sbyte assetType, IDictionary assetUuids) { // avoid infinite loops if (assetUuids.ContainsKey(assetUuid)) @@ -93,23 +94,27 @@ namespace OpenSim.Region.Framework.Scenes { assetUuids[assetUuid] = assetType; - if (AssetType.Bodypart == assetType || AssetType.Clothing == assetType) + if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) { GetWearableAssetUuids(assetUuid, assetUuids); } - else if (AssetType.Gesture == assetType) + else if ((sbyte)AssetType.Gesture == assetType) { GetGestureAssetUuids(assetUuid, assetUuids); } - else if (AssetType.Notecard == assetType) + else if ((sbyte)AssetType.Notecard == assetType) { GetTextEmbeddedAssetUuids(assetUuid, assetUuids); } - else if (AssetType.LSLText == assetType) + else if ((sbyte)AssetType.LSLText == assetType) { GetTextEmbeddedAssetUuids(assetUuid, assetUuids); } - else if (AssetType.Object == assetType) + else if ((sbyte)OpenSimAssetType.Material == assetType) + { + GetMaterialAssetUuids(assetUuid, assetUuids); + } + else if ((sbyte)AssetType.Object == assetType) { GetSceneObjectAssetUuids(assetUuid, assetUuids); } @@ -136,7 +141,7 @@ namespace OpenSim.Region.Framework.Scenes /// A dictionary which is populated with the asset UUIDs gathered and the type of that asset. /// For assets where the type is not clear (e.g. UUIDs extracted from LSL and notecards), the type is Unknown. /// - public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary assetUuids) + public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary assetUuids) { // m_log.DebugFormat( // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); @@ -156,7 +161,7 @@ namespace OpenSim.Region.Framework.Scenes { // Get the prim's default texture. This will be used for faces which don't have their own texture if (textureEntry.DefaultTexture != null) - assetUuids[textureEntry.DefaultTexture.TextureID] = AssetType.Texture; + assetUuids[textureEntry.DefaultTexture.TextureID] = (sbyte)AssetType.Texture; if (textureEntry.FaceTextures != null) { @@ -164,20 +169,20 @@ namespace OpenSim.Region.Framework.Scenes foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures) { if (texture != null) - assetUuids[texture.TextureID] = AssetType.Texture; + assetUuids[texture.TextureID] = (sbyte)AssetType.Texture; } } } // If the prim is a sculpt then preserve this information too if (part.Shape.SculptTexture != UUID.Zero) - assetUuids[part.Shape.SculptTexture] = AssetType.Texture; + assetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture; if (part.Shape.ProjectionTextureUUID != UUID.Zero) - assetUuids[part.Shape.ProjectionTextureUUID] = AssetType.Texture; + assetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture; if (part.CollisionSound != UUID.Zero) - assetUuids[part.CollisionSound] = AssetType.Sound; + assetUuids[part.CollisionSound] = (sbyte)AssetType.Sound; if (part.ParticleSystem.Length > 0) { @@ -185,7 +190,7 @@ namespace OpenSim.Region.Framework.Scenes { Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); if (ps.Texture != UUID.Zero) - assetUuids[ps.Texture] = AssetType.Texture; + assetUuids[ps.Texture] = (sbyte)AssetType.Texture; } catch (Exception e) { @@ -205,7 +210,7 @@ namespace OpenSim.Region.Framework.Scenes // tii.Name, tii.Type, part.Name, part.UUID); if (!assetUuids.ContainsKey(tii.AssetID)) - GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); + GatherAssetUuids(tii.AssetID, (sbyte)tii.Type, assetUuids); } // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed @@ -214,7 +219,9 @@ namespace OpenSim.Region.Framework.Scenes // Scene.EventManager is present. // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); - GatherMaterialsUuids(part, assetUuids); + + // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs + GatherMaterialsUuids(part, assetUuids); } catch (Exception e) { @@ -225,7 +232,7 @@ namespace OpenSim.Region.Framework.Scenes } } } - + // /// // /// The callback made when we request the asset for an object from the asset service. // /// @@ -241,10 +248,12 @@ namespace OpenSim.Region.Framework.Scenes /// /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps + /// stored in legacy format in part.DynAttrs /// /// /// - public void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) + //public void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) + public void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) { // scan thru the dynAttrs map of this part for any textures used as materials OSD osdMaterials = null; @@ -280,7 +289,7 @@ namespace OpenSim.Region.Framework.Scenes UUID normalMapId = mat["NormMap"].AsUUID(); if (normalMapId != UUID.Zero) { - assetUuids[normalMapId] = AssetType.Texture; + assetUuids[normalMapId] = (sbyte)AssetType.Texture; //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); } } @@ -289,7 +298,7 @@ namespace OpenSim.Region.Framework.Scenes UUID specularMapId = mat["SpecMap"].AsUUID(); if (specularMapId != UUID.Zero) { - assetUuids[specularMapId] = AssetType.Texture; + assetUuids[specularMapId] = (sbyte)AssetType.Texture; //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); } } @@ -344,7 +353,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// Dictionary in which to record the references - private void GetTextEmbeddedAssetUuids(UUID embeddingAssetId, IDictionary assetUuids) + private void GetTextEmbeddedAssetUuids(UUID embeddingAssetId, IDictionary assetUuids) { // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId); @@ -364,7 +373,7 @@ namespace OpenSim.Region.Framework.Scenes // Embedded asset references (if not false positives) could be for many types of asset, so we will // label these as unknown. - assetUuids[uuid] = AssetType.Unknown; + assetUuids[uuid] = (sbyte)AssetType.Unknown; } } } @@ -374,7 +383,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// Dictionary in which to record the references - private void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary assetUuids) + private void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary assetUuids) { AssetBase assetBase = GetAsset(wearableAssetUuid); @@ -389,7 +398,7 @@ namespace OpenSim.Region.Framework.Scenes foreach (UUID uuid in wearableAsset.Textures.Values) { - assetUuids[uuid] = AssetType.Texture; + assetUuids[uuid] = (sbyte)AssetType.Texture; } } } @@ -401,7 +410,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - private void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary assetUuids) + private void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary assetUuids) { AssetBase objectAsset = GetAsset(sceneObjectUuid); @@ -430,7 +439,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - private void GetGestureAssetUuids(UUID gestureUuid, IDictionary assetUuids) + private void GetGestureAssetUuids(UUID gestureUuid, IDictionary assetUuids) { AssetBase assetBase = GetAsset(gestureUuid); if (null == assetBase) @@ -464,9 +473,29 @@ namespace OpenSim.Region.Framework.Scenes // If it can be parsed as a UUID, it is an asset ID UUID uuid; if (UUID.TryParse(id, out uuid)) - assetUuids[uuid] = AssetType.Animation; + assetUuids[uuid] = (sbyte)AssetType.Animation; } } + + /// + /// Get the asset uuid's referenced in a material. + /// + private void GetMaterialAssetUuids(UUID materialUuid, IDictionary assetUuids) + { + AssetBase assetBase = GetAsset(materialUuid); + if (null == assetBase) + return; + + OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(assetBase.Data); + + UUID normMap = mat["NormMap"].AsUUID(); + if (normMap != UUID.Zero) + assetUuids[normMap] = (sbyte)AssetType.Texture; + + UUID specMap = mat["SpecMap"].AsUUID(); + if (specMap != UUID.Zero) + assetUuids[specMap] = (sbyte)AssetType.Texture; + } } public class HGUuidGatherer : UuidGatherer diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs deleted file mode 100644 index d8f5563624..0000000000 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Security.Cryptography; // for computing md5 hash -using log4net; -using Mono.Addins; -using Nini.Config; - -using OpenMetaverse; -using OpenMetaverse.StructuredData; - -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -using Ionic.Zlib; - -// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already -// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans -// the available DLLs -//[assembly: Addin("MaterialsDemoModule", "1.0")] -//[assembly: AddinDependency("OpenSim", "0.5")] - -namespace OpenSim.Region.OptionalModules.MaterialsDemoModule -{ - /// - /// - // # # ## ##### # # # # # #### - // # # # # # # ## # # ## # # # - // # # # # # # # # # # # # # # - // # ## # ###### ##### # # # # # # # # ### - // ## ## # # # # # ## # # ## # # - // # # # # # # # # # # # #### - // - // THIS MODULE IS FOR EXPERIMENTAL USE ONLY AND MAY CAUSE REGION OR ASSET CORRUPTION! - // - ////////////// WARNING ////////////////////////////////////////////////////////////////// - /// This is an *Experimental* module for developing support for materials-capable viewers - /// This module should NOT be used in a production environment! It may cause data corruption and - /// viewer crashes. It should be only used to evaluate implementations of materials. - /// - /// Materials are persisted via SceneObjectPart.dynattrs. This is a relatively new feature - /// of OpenSimulator and is not field proven at the time this module was written. Persistence - /// may fail or become corrupt and this could cause viewer crashes due to erroneous materials - /// data being sent to viewers. Materials descriptions might survive IAR, OAR, or other means - /// of archiving however the texture resources used by these materials probably will not as they - /// may not be adequately referenced to ensure proper archiving. - /// - /// - /// - /// To enable this module, add this string at the bottom of OpenSim.ini: - /// [MaterialsDemoModule] - /// - /// - /// - - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")] - public class MaterialsDemoModule : INonSharedRegionModule - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public string Name { get { return "MaterialsDemoModule"; } } - - public Type ReplaceableInterface { get { return null; } } - - private Scene m_scene = null; - private bool m_enabled = false; - - public Dictionary m_knownMaterials = new Dictionary(); - - public void Initialise(IConfigSource source) - { - m_enabled = (source.Configs["MaterialsDemoModule"] != null); - if (!m_enabled) - return; - - m_log.DebugFormat("[MaterialsDemoModule]: INITIALIZED MODULE"); - } - - public void Close() - { - if (!m_enabled) - return; - - m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); - } - - public void AddRegion(Scene scene) - { - if (!m_enabled) - return; - - m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); - - m_scene = scene; - m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; - m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; -// m_scene.EventManager.OnGatherUuids += GatherMaterialsUuids; - } - - void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) - { - foreach (var part in obj.Parts) - if (part != null) - GetStoredMaterialsForPart(part); - } - - void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) - { - string capsBase = "/CAPS/" + caps.CapsObjectPath; - - IRequestHandler renderMaterialsPostHandler - = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); - caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); - - // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET - // and POST handlers, (at least at the time this was originally written), so we first set up a POST - // handler normally and then add a GET handler via MainServer - - IRequestHandler renderMaterialsGetHandler - = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap, "RenderMaterials", null); - MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); - - // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well - IRequestHandler renderMaterialsPutHandler - = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); - MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); - } - - public void RemoveRegion(Scene scene) - { - if (!m_enabled) - return; - - m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; - m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; -// m_scene.EventManager.OnGatherUuids -= GatherMaterialsUuids; - - m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); - } - - public void RegionLoaded(Scene scene) - { - } - - OSDMap GetMaterial(UUID id) - { - OSDMap map = null; - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(id)) - { - map = new OSDMap(); - map["ID"] = OSD.FromBinary(id.GetBytes()); - map["Material"] = m_knownMaterials[id]; - } - } - return map; - } - - void GetStoredMaterialsForPart(SceneObjectPart part) - { - OSD OSMaterials = null; - OSDArray matsArr = null; - - if (part.DynAttrs == null) - { - m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); - } - - lock (part.DynAttrs) - { - if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) - { - OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); - - if (materialsStore == null) - return; - - materialsStore.TryGetValue("Materials", out OSMaterials); - } - - if (OSMaterials != null && OSMaterials is OSDArray) - matsArr = OSMaterials as OSDArray; - else - return; - } - - m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); - - if (matsArr == null) - { - m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); - return; - } - - foreach (OSD elemOsd in matsArr) - { - if (elemOsd != null && elemOsd is OSDMap) - { - OSDMap matMap = elemOsd as OSDMap; - if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) - { - try - { - lock (m_knownMaterials) - m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material: " + e.ToString()); - } - } - } - } - } - - void StoreMaterialsForPart(SceneObjectPart part) - { - try - { - if (part == null || part.Shape == null) - return; - - Dictionary mats = new Dictionary(); - - Primitive.TextureEntry te = part.Shape.Textures; - - if (te.DefaultTexture != null) - { - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) - mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; - } - } - - if (te.FaceTextures != null) - { - foreach (var face in te.FaceTextures) - { - if (face != null) - { - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(face.MaterialID)) - mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; - } - } - } - } - if (mats.Count == 0) - return; - - OSDArray matsArr = new OSDArray(); - foreach (KeyValuePair kvp in mats) - { - OSDMap matOsd = new OSDMap(); - matOsd["ID"] = OSD.FromUUID(kvp.Key); - matOsd["Material"] = kvp.Value; - matsArr.Add(matOsd); - } - - OSDMap OSMaterials = new OSDMap(); - OSMaterials["Materials"] = matsArr; - - lock (part.DynAttrs) - part.DynAttrs.SetStore("OpenSim", "Materials", OSMaterials); - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart(): " + e.ToString()); - } - } - - public string RenderMaterialsPostCap(string request, string path, - string param, IOSHttpRequest httpRequest, - IOSHttpResponse httpResponse) - { - m_log.Debug("[MaterialsDemoModule]: POST cap handler"); - - OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); - OSDMap resp = new OSDMap(); - - OSDMap materialsFromViewer = null; - - OSDArray respArr = new OSDArray(); - - if (req.ContainsKey("Zipped")) - { - OSD osd = null; - - byte[] inBytes = req["Zipped"].AsBinary(); - - try - { - osd = ZDecompressBytesToOsd(inBytes); - - if (osd != null) - { - if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries - { - foreach (OSD elem in (OSDArray)osd) - { - - try - { - UUID id = new UUID(elem.AsBinary(), 0); - - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(id)) - { - m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); - OSDMap matMap = new OSDMap(); - matMap["ID"] = OSD.FromBinary(id.GetBytes()); - - matMap["Material"] = m_knownMaterials[id]; - respArr.Add(matMap); - } - else - m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); - } - } - catch (Exception e) - { - // report something here? - continue; - } - } - } - else if (osd is OSDMap) // reqest to assign a material - { - materialsFromViewer = osd as OSDMap; - - if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) - { - OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; - if (matsOsd is OSDArray) - { - OSDArray matsArr = matsOsd as OSDArray; - - try - { - foreach (OSDMap matsMap in matsArr) - { - m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); - - uint matLocalID = 0; - try { matLocalID = matsMap["ID"].AsUInteger(); } - catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } - m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString()); - - - OSDMap mat = null; - try { mat = matsMap["Material"] as OSDMap; } - catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } - m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); - - UUID id = HashOsd(mat); - lock (m_knownMaterials) - m_knownMaterials[id] = mat; - - - var sop = m_scene.GetSceneObjectPart(matLocalID); - if (sop == null) - m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); - else - { - var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); - - if (te == null) - { - m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString()); - } - else - { - int face = -1; - - if (matsMap.ContainsKey("Face")) - { - face = matsMap["Face"].AsInteger(); - if (te.FaceTextures == null) // && face == 0) - { - if (te.DefaultTexture == null) - m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); - else - te.DefaultTexture.MaterialID = id; - } - else - { - if (te.FaceTextures.Length >= face - 1) - { - if (te.FaceTextures[face] == null) - te.DefaultTexture.MaterialID = id; - else - te.FaceTextures[face].MaterialID = id; - } - } - } - else - { - if (te.DefaultTexture != null) - te.DefaultTexture.MaterialID = id; - } - - m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString()); - - //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually - - if (sop.ParentGroup != null) - { - sop.Shape.TextureEntry = te.GetBytes(); - sop.TriggerScriptChangedEvent(Changed.TEXTURE); - sop.UpdateFlag = UpdateRequired.FULL; - sop.ParentGroup.HasGroupChanged = true; - - sop.ScheduleFullUpdate(); - - StoreMaterialsForPart(sop); - } - } - } - } - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message); - } - } - } - } - } - - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload: " + e.Message); - //return ""; - } - m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); - } - - - resp["Zipped"] = ZCompressOSD(respArr, false); - string response = OSDParser.SerializeLLSDXmlString(resp); - - //m_log.Debug("[MaterialsDemoModule]: cap request: " + request); - m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); - m_log.Debug("[MaterialsDemoModule]: cap response: " + response); - return response; - } - - - public string RenderMaterialsGetCap(string request, string path, - string param, IOSHttpRequest httpRequest, - IOSHttpResponse httpResponse) - { - m_log.Debug("[MaterialsDemoModule]: GET cap handler"); - - OSDMap resp = new OSDMap(); - int matsCount = 0; - OSDArray allOsd = new OSDArray(); - - lock (m_knownMaterials) - { - foreach (KeyValuePair kvp in m_knownMaterials) - { - OSDMap matMap = new OSDMap(); - - matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); - matMap["Material"] = kvp.Value; - allOsd.Add(matMap); - matsCount++; - } - } - - resp["Zipped"] = ZCompressOSD(allOsd, false); - m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); - - return OSDParser.SerializeLLSDXmlString(resp); - } - - static string ZippedOsdBytesToString(byte[] bytes) - { - try - { - return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes)); - } - catch (Exception e) - { - return "ZippedOsdBytesToString caught an exception: " + e.ToString(); - } - } - - /// - /// computes a UUID by hashing a OSD object - /// - /// - /// - private static UUID HashOsd(OSD osd) - { - using (var md5 = MD5.Create()) - using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false))) - return new UUID(md5.ComputeHash(ms), 0); - } - - public static OSD ZCompressOSD(OSD inOsd, bool useHeader) - { - OSD osd = null; - - using (MemoryStream msSinkCompressed = new MemoryStream()) - { - using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, - Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) - { - CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut); - zOut.Close(); - } - - msSinkCompressed.Seek(0L, SeekOrigin.Begin); - osd = OSD.FromBinary( msSinkCompressed.ToArray()); - } - - return osd; - } - - - public static OSD ZDecompressBytesToOsd(byte[] input) - { - OSD osd = null; - - using (MemoryStream msSinkUnCompressed = new MemoryStream()) - { - using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) - { - CopyStream(new MemoryStream(input), zOut); - zOut.Close(); - } - msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); - osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); - } - - return osd; - } - - static void CopyStream(System.IO.Stream input, System.IO.Stream output) - { - byte[] buffer = new byte[2048]; - int len; - while ((len = input.Read(buffer, 0, 2048)) > 0) - { - output.Write(buffer, 0, len); - } - - output.Flush(); - } - - // FIXME: This code is currently still in UuidGatherer since we cannot use Scene.EventManager as some - // calls to the gatherer are done for objects with no scene. -// /// -// /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps -// /// -// /// -// /// -// private void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) -// { -// // scan thru the dynAttrs map of this part for any textures used as materials -// OSD osdMaterials = null; -// -// lock (part.DynAttrs) -// { -// if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) -// { -// OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); -// if (materialsStore == null) -// return; -// -// materialsStore.TryGetValue("Materials", out osdMaterials); -// } -// -// if (osdMaterials != null) -// { -// //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); -// -// if (osdMaterials is OSDArray) -// { -// OSDArray matsArr = osdMaterials as OSDArray; -// foreach (OSDMap matMap in matsArr) -// { -// try -// { -// if (matMap.ContainsKey("Material")) -// { -// OSDMap mat = matMap["Material"] as OSDMap; -// if (mat.ContainsKey("NormMap")) -// { -// UUID normalMapId = mat["NormMap"].AsUUID(); -// if (normalMapId != UUID.Zero) -// { -// assetUuids[normalMapId] = AssetType.Texture; -// //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); -// } -// } -// if (mat.ContainsKey("SpecMap")) -// { -// UUID specularMapId = mat["SpecMap"].AsUUID(); -// if (specularMapId != UUID.Zero) -// { -// assetUuids[specularMapId] = AssetType.Texture; -// //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); -// } -// } -// } -// -// } -// catch (Exception e) -// { -// m_log.Warn("[MaterialsDemoModule]: exception getting materials: " + e.Message); -// } -// } -// } -// } -// } -// } - } -} \ No newline at end of file diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs new file mode 100644 index 0000000000..afb788b8ae --- /dev/null +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -0,0 +1,590 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Security.Cryptography; // for computing md5 hash +using log4net; +using Mono.Addins; +using Nini.Config; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; + +using Ionic.Zlib; + +// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already +// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans +// the available DLLs +//[assembly: Addin("MaterialsModule", "1.0")] +//[assembly: AddinDependency("OpenSim", "0.5")] + +namespace OpenSim.Region.OptionalModules.Materials +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsModule")] + public class MaterialsModule : INonSharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public string Name { get { return "MaterialsModule"; } } + + public Type ReplaceableInterface { get { return null; } } + + private Scene m_scene = null; + private bool m_enabled = false; + + public Dictionary m_regionMaterials = new Dictionary(); + + public void Initialise(IConfigSource source) + { + IConfig config = source.Configs["Materials"]; + if (config == null) + return; + + m_enabled = config.GetBoolean("enable_materials", true); + if (!m_enabled) + return; + + m_log.DebugFormat("[Materials]: Initialized"); + } + + public void Close() + { + if (!m_enabled) + return; + } + + public void AddRegion(Scene scene) + { + if (!m_enabled) + return; + + m_scene = scene; + m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; + m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; + } + + private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) + { + foreach (var part in obj.Parts) + if (part != null) + GetStoredMaterialsInPart(part); + } + + private void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) + { + string capsBase = "/CAPS/" + caps.CapsObjectPath; + + IRequestHandler renderMaterialsPostHandler + = new RestStreamHandler("POST", capsBase + "/", + (request, path, param, httpRequest, httpResponse) + => RenderMaterialsPostCap(request, agentID), + "RenderMaterials", null); + caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); + + // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET + // and POST handlers, (at least at the time this was originally written), so we first set up a POST + // handler normally and then add a GET handler via MainServer + + IRequestHandler renderMaterialsGetHandler + = new RestStreamHandler("GET", capsBase + "/", + (request, path, param, httpRequest, httpResponse) + => RenderMaterialsGetCap(request), + "RenderMaterials", null); + MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); + + // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well + IRequestHandler renderMaterialsPutHandler + = new RestStreamHandler("PUT", capsBase + "/", + (request, path, param, httpRequest, httpResponse) + => RenderMaterialsPostCap(request, agentID), + "RenderMaterials", null); + MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); + } + + public void RemoveRegion(Scene scene) + { + if (!m_enabled) + return; + + m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; + m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; + } + + public void RegionLoaded(Scene scene) + { + } + + /// + /// Finds any legacy materials stored in DynAttrs that may exist for this part and add them to 'm_regionMaterials'. + /// + /// + private void GetLegacyStoredMaterialsInPart(SceneObjectPart part) + { + if (part.DynAttrs == null) + return; + + OSD OSMaterials = null; + OSDArray matsArr = null; + + lock (part.DynAttrs) + { + if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) + { + OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + + if (materialsStore == null) + return; + + materialsStore.TryGetValue("Materials", out OSMaterials); + } + + if (OSMaterials != null && OSMaterials is OSDArray) + matsArr = OSMaterials as OSDArray; + else + return; + } + + if (matsArr == null) + return; + + foreach (OSD elemOsd in matsArr) + { + if (elemOsd != null && elemOsd is OSDMap) + { + OSDMap matMap = elemOsd as OSDMap; + if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) + { + try + { + lock (m_regionMaterials) + m_regionMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; + } + catch (Exception e) + { + m_log.Warn("[Materials]: exception decoding persisted legacy material: " + e.ToString()); + } + } + } + } + } + + /// + /// Find the materials used in the SOP, and add them to 'm_regionMaterials'. + /// + private void GetStoredMaterialsInPart(SceneObjectPart part) + { + if (part.Shape == null) + return; + + var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); + if (te == null) + return; + + GetLegacyStoredMaterialsInPart(part); + + GetStoredMaterialInFace(part, te.DefaultTexture); + + foreach (Primitive.TextureEntryFace face in te.FaceTextures) + { + if (face != null) + GetStoredMaterialInFace(part, face); + } + } + + /// + /// Find the materials used in one Face, and add them to 'm_regionMaterials'. + /// + private void GetStoredMaterialInFace(SceneObjectPart part, Primitive.TextureEntryFace face) + { + UUID id = face.MaterialID; + if (id == UUID.Zero) + return; + + lock (m_regionMaterials) + { + if (m_regionMaterials.ContainsKey(id)) + return; + + byte[] data = m_scene.AssetService.GetData(id.ToString()); + if (data == null) + { + m_log.WarnFormat("[Materials]: Prim \"{0}\" ({1}) contains unknown material ID {2}", part.Name, part.UUID, id); + return; + } + + OSDMap mat; + try + { + mat = (OSDMap)OSDParser.DeserializeLLSDXml(data); + } + catch (Exception e) + { + m_log.WarnFormat("[Materials]: cannot decode material asset {0}: {1}", id, e.Message); + return; + } + + m_regionMaterials[id] = mat; + } + } + + public string RenderMaterialsPostCap(string request, UUID agentID) + { + OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); + OSDMap resp = new OSDMap(); + + OSDMap materialsFromViewer = null; + + OSDArray respArr = new OSDArray(); + + if (req.ContainsKey("Zipped")) + { + OSD osd = null; + + byte[] inBytes = req["Zipped"].AsBinary(); + + try + { + osd = ZDecompressBytesToOsd(inBytes); + + if (osd != null) + { + if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries + { + foreach (OSD elem in (OSDArray)osd) + { + try + { + UUID id = new UUID(elem.AsBinary(), 0); + + lock (m_regionMaterials) + { + if (m_regionMaterials.ContainsKey(id)) + { + OSDMap matMap = new OSDMap(); + matMap["ID"] = OSD.FromBinary(id.GetBytes()); + matMap["Material"] = m_regionMaterials[id]; + respArr.Add(matMap); + } + else + { + m_log.Warn("[Materials]: request for unknown material ID: " + id.ToString()); + + // Theoretically we could try to load the material from the assets service, + // but that shouldn't be necessary because the viewer should only request + // materials that exist in a prim on the region, and all of these materials + // are already stored in m_regionMaterials. + } + } + } + catch (Exception e) + { + m_log.Error("Error getting materials in response to viewer request", e); + continue; + } + } + } + else if (osd is OSDMap) // request to assign a material + { + materialsFromViewer = osd as OSDMap; + + if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) + { + OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; + if (matsOsd is OSDArray) + { + OSDArray matsArr = matsOsd as OSDArray; + + try + { + foreach (OSDMap matsMap in matsArr) + { + uint primLocalID = 0; + try { + primLocalID = matsMap["ID"].AsUInteger(); + } + catch (Exception e) { + m_log.Warn("[Materials]: cannot decode \"ID\" from matsMap: " + e.Message); + continue; + } + + OSDMap mat = null; + try + { + mat = matsMap["Material"] as OSDMap; + } + catch (Exception e) + { + m_log.Warn("[Materials]: cannot decode \"Material\" from matsMap: " + e.Message); + continue; + } + + SceneObjectPart sop = m_scene.GetSceneObjectPart(primLocalID); + if (sop == null) + { + m_log.WarnFormat("[Materials]: SOP not found for localId: {0}", primLocalID.ToString()); + continue; + } + + if (!m_scene.Permissions.CanEditObject(sop.UUID, agentID)) + { + m_log.WarnFormat("User {0} can't edit object {1} {2}", agentID, sop.Name, sop.UUID); + continue; + } + + Primitive.TextureEntry te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); + if (te == null) + { + m_log.WarnFormat("[Materials]: Error in TextureEntry for SOP {0} {1}", sop.Name, sop.UUID); + continue; + } + + + UUID id; + if (mat == null) + { + // This happens then the user removes a material from a prim + id = UUID.Zero; + } + else + { + id = StoreMaterialAsAsset(agentID, mat, sop); + } + + + int face = -1; + + if (matsMap.ContainsKey("Face")) + { + face = matsMap["Face"].AsInteger(); + Primitive.TextureEntryFace faceEntry = te.CreateFace((uint)face); + faceEntry.MaterialID = id; + } + else + { + if (te.DefaultTexture == null) + m_log.WarnFormat("[Materials]: TextureEntry.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID); + else + te.DefaultTexture.MaterialID = id; + } + + //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id); + + // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually + sop.Shape.TextureEntry = te.GetBytes(); + + if (sop.ParentGroup != null) + { + sop.TriggerScriptChangedEvent(Changed.TEXTURE); + sop.UpdateFlag = UpdateRequired.FULL; + sop.ParentGroup.HasGroupChanged = true; + sop.ScheduleFullUpdate(); + } + } + } + catch (Exception e) + { + m_log.Warn("[Materials]: exception processing received material ", e); + } + } + } + } + } + + } + catch (Exception e) + { + m_log.Warn("[Materials]: exception decoding zipped CAP payload ", e); + //return ""; + } + } + + + resp["Zipped"] = ZCompressOSD(respArr, false); + string response = OSDParser.SerializeLLSDXmlString(resp); + + //m_log.Debug("[Materials]: cap request: " + request); + //m_log.Debug("[Materials]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); + //m_log.Debug("[Materials]: cap response: " + response); + return response; + } + + private UUID StoreMaterialAsAsset(UUID agentID, OSDMap mat, SceneObjectPart sop) + { + UUID id; + // Material UUID = hash of the material's data. + // This makes materials deduplicate across the entire grid (but isn't otherwise required). + byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); + using (var md5 = MD5.Create()) + id = new UUID(md5.ComputeHash(data), 0); + + lock (m_regionMaterials) + { + if (!m_regionMaterials.ContainsKey(id)) + { + m_regionMaterials[id] = mat; + + // This asset might exist already, but it's ok to try to store it again + string name = "Material " + ChooseMaterialName(mat, sop); + name = name.Substring(0, Math.Min(64, name.Length)).Trim(); + AssetBase asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, agentID.ToString()); + asset.Data = data; + m_scene.AssetService.Store(asset); + } + } + return id; + } + + /// + /// Use heuristics to choose a good name for the material. + /// + private string ChooseMaterialName(OSDMap mat, SceneObjectPart sop) + { + UUID normMap = mat["NormMap"].AsUUID(); + if (normMap != UUID.Zero) + { + AssetBase asset = m_scene.AssetService.GetCached(normMap.ToString()); + if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals("From IAR")) + return asset.Name; + } + + UUID specMap = mat["SpecMap"].AsUUID(); + if (specMap != UUID.Zero) + { + AssetBase asset = m_scene.AssetService.GetCached(specMap.ToString()); + if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals("From IAR")) + return asset.Name; + } + + if (sop.Name != "Primitive") + return sop.Name; + + if ((sop.ParentGroup != null) && (sop.ParentGroup.Name != "Primitive")) + return sop.ParentGroup.Name; + + return ""; + } + + + public string RenderMaterialsGetCap(string request) + { + OSDMap resp = new OSDMap(); + int matsCount = 0; + OSDArray allOsd = new OSDArray(); + + lock (m_regionMaterials) + { + foreach (KeyValuePair kvp in m_regionMaterials) + { + OSDMap matMap = new OSDMap(); + + matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); + matMap["Material"] = kvp.Value; + allOsd.Add(matMap); + matsCount++; + } + } + + resp["Zipped"] = ZCompressOSD(allOsd, false); + + return OSDParser.SerializeLLSDXmlString(resp); + } + + private static string ZippedOsdBytesToString(byte[] bytes) + { + try + { + return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes)); + } + catch (Exception e) + { + return "ZippedOsdBytesToString caught an exception: " + e.ToString(); + } + } + + /// + /// computes a UUID by hashing a OSD object + /// + /// + /// + private static UUID HashOsd(OSD osd) + { + byte[] data = OSDParser.SerializeLLSDBinary(osd, false); + using (var md5 = MD5.Create()) + return new UUID(md5.ComputeHash(data), 0); + } + + public static OSD ZCompressOSD(OSD inOsd, bool useHeader) + { + OSD osd = null; + + byte[] data = OSDParser.SerializeLLSDBinary(inOsd, useHeader); + + using (MemoryStream msSinkCompressed = new MemoryStream()) + { + using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, + Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + zOut.Write(data, 0, data.Length); + } + + msSinkCompressed.Seek(0L, SeekOrigin.Begin); + osd = OSD.FromBinary(msSinkCompressed.ToArray()); + } + + return osd; + } + + + public static OSD ZDecompressBytesToOsd(byte[] input) + { + OSD osd = null; + + using (MemoryStream msSinkUnCompressed = new MemoryStream()) + { + using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) + { + zOut.Write(input, 0, input.Length); + } + + msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); + osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); + } + + return osd; + } + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs new file mode 100644 index 0000000000..d4b19ddd91 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs @@ -0,0 +1,195 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Mono.Addins; + +using System; +using System.Reflection; +using System.Threading; +using System.Text; +using System.Net; +using System.Net.Sockets; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace OpenSim.Region.OptionalModules.Scripting.JsonStore +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreCommandsModule")] + + public class JsonStoreCommandsModule : INonSharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfig m_config = null; + private bool m_enabled = false; + + private Scene m_scene = null; + //private IJsonStoreModule m_store; + private JsonStoreModule m_store; + +#region Region Module interface + + // ----------------------------------------------------------------- + /// + /// Name of this shared module is it's class name + /// + // ----------------------------------------------------------------- + public string Name + { + get { return this.GetType().Name; } + } + + // ----------------------------------------------------------------- + /// + /// Initialise this shared module + /// + /// this region is getting initialised + /// nini config, we are not using this + // ----------------------------------------------------------------- + public void Initialise(IConfigSource config) + { + try + { + if ((m_config = config.Configs["JsonStore"]) == null) + { + // There is no configuration, the module is disabled + // m_log.InfoFormat("[JsonStore] no configuration info"); + return; + } + + m_enabled = m_config.GetBoolean("Enabled", m_enabled); + } + catch (Exception e) + { + m_log.Error("[JsonStore]: initialization error: {0}", e); + return; + } + + if (m_enabled) + m_log.DebugFormat("[JsonStore]: module is enabled"); + } + + // ----------------------------------------------------------------- + /// + /// everything is loaded, perform post load configuration + /// + // ----------------------------------------------------------------- + public void PostInitialise() + { + } + + // ----------------------------------------------------------------- + /// + /// Nothing to do on close + /// + // ----------------------------------------------------------------- + public void Close() + { + } + + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public void AddRegion(Scene scene) + { + if (m_enabled) + { + m_scene = scene; + + } + } + + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public void RemoveRegion(Scene scene) + { + // need to remove all references to the scene in the subscription + // list to enable full garbage collection of the scene object + } + + // ----------------------------------------------------------------- + /// + /// Called when all modules have been added for a region. This is + /// where we hook up events + /// + // ----------------------------------------------------------------- + public void RegionLoaded(Scene scene) + { + if (m_enabled) + { + m_scene = scene; + + m_store = (JsonStoreModule) m_scene.RequestModuleInterface(); + if (m_store == null) + { + m_log.ErrorFormat("[JsonStoreCommands]: JsonModule interface not defined"); + m_enabled = false; + return; + } + + scene.AddCommand("JsonStore", this, "jsonstore stats", "jsonstore stats", + "Display statistics about the state of the JsonStore module", "", + CmdStats); + } + } + + /// ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public Type ReplaceableInterface + { + get { return null; } + } + +#endregion + +#region Commands + + private void CmdStats(string module, string[] cmd) + { + if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) + return; + + JsonStoreStats stats = m_store.GetStoreStats(); + MainConsole.Instance.OutputFormat("{0}\t{1}",m_scene.RegionInfo.RegionName,stats.StoreCount); + } + +#endregion + + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs index 5fbfcc583a..b502a55508 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs @@ -42,7 +42,6 @@ using OpenSim.Region.Framework.Scenes; using System.Collections.Generic; using System.Text.RegularExpressions; - namespace OpenSim.Region.OptionalModules.Scripting.JsonStore { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreModule")] @@ -60,6 +59,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore private Scene m_scene = null; private Dictionary m_JsonValueStore; + private UUID m_sharedStore; #region Region Module interface @@ -140,6 +140,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore m_sharedStore = UUID.Zero; m_JsonValueStore = new Dictionary(); m_JsonValueStore.Add(m_sharedStore,new JsonStore("")); + + scene.EventManager.OnObjectBeingRemovedFromScene += EventManagerOnObjectBeingRemovedFromScene; } } @@ -149,6 +151,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public void RemoveRegion(Scene scene) { + scene.EventManager.OnObjectBeingRemovedFromScene -= EventManagerOnObjectBeingRemovedFromScene; + // need to remove all references to the scene in the subscription // list to enable full garbage collection of the scene object } @@ -161,7 +165,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public void RegionLoaded(Scene scene) { - if (m_enabled) {} + if (m_enabled) + { + } } /// ----------------------------------------------------------------- @@ -175,8 +181,39 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore #endregion +#region SceneEvents + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public void EventManagerOnObjectBeingRemovedFromScene(SceneObjectGroup obj) + { + obj.ForEachPart(delegate(SceneObjectPart sop) { DestroyStore(sop.UUID); } ); + } + +#endregion + #region ScriptInvocationInteface + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public JsonStoreStats GetStoreStats() + { + JsonStoreStats stats; + + lock (m_JsonValueStore) + { + stats.StoreCount = m_JsonValueStore.Count; + } + + return stats; + } + // ----------------------------------------------------------------- /// /// diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs index 1bb5aee796..9fbfb66b8e 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs @@ -59,7 +59,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore private IScriptModuleComms m_comms; private IJsonStoreModule m_store; - + + private Dictionary> m_scriptStores = new Dictionary>(); + #region Region Module interface // ----------------------------------------------------------------- @@ -126,6 +128,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public void AddRegion(Scene scene) { + scene.EventManager.OnScriptReset += HandleScriptReset; + scene.EventManager.OnRemoveScript += HandleScriptReset; } // ----------------------------------------------------------------- @@ -134,10 +138,32 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public void RemoveRegion(Scene scene) { + scene.EventManager.OnScriptReset -= HandleScriptReset; + scene.EventManager.OnRemoveScript -= HandleScriptReset; + // need to remove all references to the scene in the subscription // list to enable full garbage collection of the scene object } + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + private void HandleScriptReset(uint localID, UUID itemID) + { + HashSet stores; + + lock (m_scriptStores) + { + if (! m_scriptStores.TryGetValue(itemID, out stores)) + return; + m_scriptStores.Remove(itemID); + } + + foreach (UUID id in stores) + m_store.DestroyStore(id); + } + // ----------------------------------------------------------------- /// /// Called when all modules have been added for a region. This is @@ -250,6 +276,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore if (! m_store.CreateStore(value, ref uuid)) GenerateRuntimeError("Failed to create Json store"); + lock (m_scriptStores) + { + if (! m_scriptStores.ContainsKey(scriptID)) + m_scriptStores[scriptID] = new HashSet(); + + m_scriptStores[scriptID].Add(uuid); + } return uuid; } @@ -261,6 +294,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore [ScriptInvocation] public int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID) { + lock(m_scriptStores) + { + if (m_scriptStores.ContainsKey(scriptID)) + m_scriptStores[scriptID].Remove(storeID); + } + return m_store.DestroyStore(storeID) ? 1 : 0; } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 937010285f..a4247e303a 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -788,11 +788,6 @@ namespace OpenSim.Tests.Common.Mock { OnRegionHandShakeReply(this); } - - if (OnCompleteMovementToRegion != null) - { - OnCompleteMovementToRegion(this, true); - } } public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) diff --git a/OpenSim/Tests/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs index a684d72e7f..6bf23f8e67 100644 --- a/OpenSim/Tests/Common/TestHelpers.cs +++ b/OpenSim/Tests/Common/TestHelpers.cs @@ -117,8 +117,6 @@ namespace OpenSim.Tests.Common /// Parse a UUID stem into a full UUID. /// /// - /// Yes, this is completely inconsistent with ParseTail but this is probably a better way to do it, - /// UUIDs are conceptually not hexadecmial numbers. /// The fragment will come at the start of the UUID. The rest will be 0s /// /// @@ -143,5 +141,24 @@ namespace OpenSim.Tests.Common { return new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", tail)); } + + /// + /// Parse a UUID tail section into a full UUID. + /// + /// + /// The fragment will come at the end of the UUID. The rest will be 0s + /// + /// + /// + /// A UUID fragment that will be parsed into a full UUID. Therefore, it can only contain + /// cahracters which are valid in a UUID, except for "-" which is currently only allowed if a full UUID is + /// given as the 'fragment'. + /// + public static UUID ParseTail(string stem) + { + string rawUuid = stem.PadLeft(32, '0'); + + return UUID.Parse(rawUuid); + } } } diff --git a/bin/OpenMetaverse.StructuredData.XML b/bin/OpenMetaverse.StructuredData.XML index 789ad5b811..3999d9977d 100644 --- a/bin/OpenMetaverse.StructuredData.XML +++ b/bin/OpenMetaverse.StructuredData.XML @@ -4,123 +4,6 @@ OpenMetaverse.StructuredData - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Uses reflection to create an SDMap from all of the SD - serializable types in an object - - Class or struct containing serializable types - An SDMap holding the serialized values from the - container object - - - - Uses reflection to deserialize member variables in an object from - an SDMap - - Reference to an object to fill with deserialized - values - Serialized values to put in the target - object - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -345,5 +228,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Uses reflection to create an SDMap from all of the SD + serializable types in an object + + Class or struct containing serializable types + An SDMap holding the serialized values from the + container object + + + + Uses reflection to deserialize member variables in an object from + an SDMap + + Reference to an object to fill with deserialized + values + Serialized values to put in the target + object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/OpenMetaverse.StructuredData.dll b/bin/OpenMetaverse.StructuredData.dll index d980531e18..ed613e710f 100755 Binary files a/bin/OpenMetaverse.StructuredData.dll and b/bin/OpenMetaverse.StructuredData.dll differ diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index d422c3395c..b6927581aa 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -703,6 +703,12 @@ ; enable_windlight = false +[Materials] + ;# {enable_materials} {} {Enable Materials support?} {true false} true + ;; This enables the use of Materials. + ; enable_materials = true + + [DataSnapshot] ;# {index_sims} {} {Enable data snapshotting (search)?} {true false} false ;; The following set of configs pertains to search. diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index d80f5bae2e..df94239801 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -548,6 +548,16 @@ ; ;TextureSendLimit = 20 + ; CannibalizeTextureRate allows bandwidth to be moved from the + ; UDP texture throttle to the task throttle. Since most viewers + ; use HTTP textures, this provides a means of using what is largely + ; unused bandwidth in the total throttle. The value is the proportion + ; of the texture rate to move to the task queue. It must be between + ; 0.0 (none of the bandwidth is cannibalized) and 0.9 (90% of the + ; bandwidth is grabbed) + ; + ; CannibalizeTextureRate = 0.5 + ; Quash and remove any light properties from attachments not on the ; hands. This allows flashlights and lanterns to function, but kills ; silly vanity "Facelights" dead. Sorry, head mounted miner's lamps