diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs index 72018e46e0..6f517b6f87 100644 --- a/OpenSim/Framework/Communications/RestClient.cs +++ b/OpenSim/Framework/Communications/RestClient.cs @@ -90,7 +90,7 @@ namespace OpenSim.Framework.Communications private byte[] _readbuf; /// - /// MemoryStream representing the resultiong resource + /// MemoryStream representing the resulting resource /// private Stream _resource; @@ -352,42 +352,46 @@ namespace OpenSim.Framework.Communications m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri); // IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); + try { - _response = (HttpWebResponse) _request.GetResponse(); + using (_response = (HttpWebResponse) _request.GetResponse()) + { + using (Stream src = _response.GetResponseStream()) + { + int length = src.Read(_readbuf, 0, BufferSize); + while (length > 0) + { + _resource.Write(_readbuf, 0, length); + length = src.Read(_readbuf, 0, BufferSize); + } + + // TODO! Implement timeout, without killing the server + // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted + //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); + + // _allDone.WaitOne(); + } + } } catch (WebException e) { - HttpWebResponse errorResponse = e.Response as HttpWebResponse; - if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode) + using (HttpWebResponse errorResponse = e.Response as HttpWebResponse) { - // This is often benign. E.g., requesting a missing asset will return 404. - m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString()); - } - else - { - m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e); + if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode) + { + // This is often benign. E.g., requesting a missing asset will return 404. + m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString()); + } + else + { + m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e); + } } return null; } - Stream src = _response.GetResponseStream(); - int length = src.Read(_readbuf, 0, BufferSize); - while (length > 0) - { - _resource.Write(_readbuf, 0, length); - length = src.Read(_readbuf, 0, BufferSize); - } - - - // TODO! Implement timeout, without killing the server - // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted - //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - -// _allDone.WaitOne(); - if (_response != null) - _response.Close(); if (_asyncException != null) throw _asyncException; @@ -515,4 +519,4 @@ namespace OpenSim.Framework.Communications #endregion Async Invocation } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/ISceneObject.cs b/OpenSim/Framework/ISceneObject.cs index afac9b84f2..754b77b4a2 100644 --- a/OpenSim/Framework/ISceneObject.cs +++ b/OpenSim/Framework/ISceneObject.cs @@ -32,6 +32,8 @@ namespace OpenSim.Framework { public interface ISceneObject { + string Name { get; } + UUID UUID { get; } /// diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index fe9a17d264..6564b4d22f 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -256,20 +256,7 @@ namespace OpenSim.Region.CoreModules.Asset // If the file is already cached, don't cache it, just touch it so access time is updated if (File.Exists(filename)) { - // We don't really want to know about sharing - // violations here. If the file is locked, then - // the other thread has updated the time for us. - try - { - lock (m_CurrentlyWriting) - { - if (!m_CurrentlyWriting.Contains(filename)) - File.SetLastAccessTime(filename, DateTime.Now); - } - } - catch - { - } + UpdateFileLastAccessTime(filename); } else { @@ -328,6 +315,24 @@ namespace OpenSim.Region.CoreModules.Asset } } + /// + /// Updates the cached file with the current time. + /// + /// Filename. + /// true, if the update was successful, false otherwise. + private bool UpdateFileLastAccessTime(string filename) + { + try + { + File.SetLastAccessTime(filename, DateTime.Now); + return true; + } + catch + { + return false; + } + } + /// /// Try to get an asset from the in-memory cache. /// @@ -771,8 +776,8 @@ namespace OpenSim.Region.CoreModules.Asset { UuidGatherer gatherer = new UuidGatherer(m_AssetService); - HashSet uniqueUuids = new HashSet(); - Dictionary assets = new Dictionary(); + Dictionary assetIdsToCheck = new Dictionary(); + Dictionary assetsFound = new Dictionary(); foreach (Scene s in m_Scenes) { @@ -780,34 +785,40 @@ namespace OpenSim.Region.CoreModules.Asset s.ForEachSOG(delegate(SceneObjectGroup e) { - gatherer.GatherAssetUuids(e, assets); + gatherer.GatherAssetUuids(e, assetIdsToCheck); - foreach (UUID assetID in assets.Keys) + foreach (UUID assetID in assetIdsToCheck.Keys) { - uniqueUuids.Add(assetID); - - string filename = GetFileName(assetID.ToString()); - - if (File.Exists(filename)) + if (!assetsFound.ContainsKey(assetID)) { - File.SetLastAccessTime(filename, DateTime.Now); + string filename = GetFileName(assetID.ToString()); + + if (File.Exists(filename)) + { + UpdateFileLastAccessTime(filename); + } + else if (storeUncached) + { + AssetBase cachedAsset = m_AssetService.Get(assetID.ToString()); + if (cachedAsset == null && assetIdsToCheck[assetID] != (sbyte)AssetType.Unknown) + assetsFound[assetID] = false; + else + assetsFound[assetID] = true; + } } - else if (storeUncached) + else if (!assetsFound[assetID]) { - AssetBase cachedAsset = m_AssetService.Get(assetID.ToString()); - if (cachedAsset == null && assets[assetID] != (sbyte)AssetType.Unknown) - m_log.DebugFormat( + 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); + assetID, assetIdsToCheck[assetID], e.Name, e.AbsolutePosition, s.Name); } } - assets.Clear(); + assetIdsToCheck.Clear(); }); } - - return uniqueUuids.Count; + return assetsFound.Count; } /// diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index a3368fbb1c..4af4ddb32c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -255,6 +255,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void CopyAttachments(AgentData ad, IScenePresence sp) { +// m_log.DebugFormat("[ATTACHMENTS MODULE]: Copying attachment data into {0} in {1}", sp.Name, m_scene.Name); + if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0) { lock (sp.AttachmentsSyncLock) @@ -265,6 +267,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { ((SceneObjectGroup)so).LocalId = 0; ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule(); + +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Copying script state with {0} bytes for object {1} for {2} in {3}", +// ad.AttachmentObjectStates[i].Length, so.Name, sp.Name, m_scene.Name); + so.SetState(ad.AttachmentObjectStates[i++], m_scene); m_scene.IncomingCreateObject(Vector3.Zero, so); } @@ -334,11 +341,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (!Enabled) return; - if (DebugLevel > 0) - m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); - List attachments = sp.GetAttachments(); + if (DebugLevel > 0) + m_log.DebugFormat( + "[ATTACHMENTS MODULE]: Saving for {0} attachments for {1} in {2}", + attachments.Count, sp.Name, m_scene.Name); + if (attachments.Count <= 0) return; @@ -352,6 +361,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from // scripts performing attachment operations at the same time. Getting object states stops the scripts. scriptStates[so] = PrepareScriptInstanceForSave(so, false); + +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: For object {0} for {1} in {2} got saved state {3}", +// so.Name, sp.Name, m_scene.Name, scriptStates[so]); } lock (sp.AttachmentsSyncLock) @@ -819,8 +832,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { if (DebugLevel > 0) m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", - so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); + "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} at pt {2} pos {3} {4} in {5}", + so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos, m_scene.Name); // Remove from database and parcel prim count m_scene.DeleteFromStorage(so.UUID); diff --git a/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs index 5e35135c5f..7d2cad67c3 100644 --- a/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs @@ -103,48 +103,51 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures return null; int size = 0; - RestClient rc = new RestClient(m_URL); - List ret = new List(); - rc.AddResourcePath("bakes"); - rc.AddResourcePath(id.ToString()); - rc.RequestMethod = "GET"; - - try + using (RestClient rc = new RestClient(m_URL)) { - Stream s = rc.Request(m_Auth); - XmlTextReader sr = new XmlTextReader(s); + List ret = new List(); + rc.AddResourcePath("bakes"); + rc.AddResourcePath(id.ToString()); - sr.ReadStartElement("BakedAppearance"); - while (sr.LocalName == "BakedTexture") + rc.RequestMethod = "GET"; + + try { - string sTextureIndex = sr.GetAttribute("TextureIndex"); - int lTextureIndex = Convert.ToInt32(sTextureIndex); - string sCacheId = sr.GetAttribute("CacheId"); - UUID lCacheId = UUID.Zero; - if (!(UUID.TryParse(sCacheId, out lCacheId))) + Stream s = rc.Request(m_Auth); + + using (XmlTextReader sr = new XmlTextReader(s)) { - // ?? Nothing here + sr.ReadStartElement("BakedAppearance"); + while (sr.LocalName == "BakedTexture") + { + string sTextureIndex = sr.GetAttribute("TextureIndex"); + int lTextureIndex = Convert.ToInt32(sTextureIndex); + string sCacheId = sr.GetAttribute("CacheId"); + UUID lCacheId = UUID.Zero; + if (!(UUID.TryParse(sCacheId, out lCacheId))) + { + // ?? Nothing here + } + + ++size; + + sr.ReadStartElement("BakedTexture"); + AssetBase a = (AssetBase)m_serializer.Deserialize(sr); + ret.Add(new WearableCacheItem() { CacheId = lCacheId, TextureIndex = (uint)lTextureIndex, TextureAsset = a, TextureID = a.FullID }); + + sr.ReadEndElement(); + } + + m_log.DebugFormat("[XBakes]: read {0} textures for user {1}", ret.Count, id); } - ++size; - - sr.ReadStartElement("BakedTexture"); - AssetBase a = (AssetBase)m_serializer.Deserialize(sr); - ret.Add(new WearableCacheItem() { CacheId = lCacheId, TextureIndex = (uint)lTextureIndex, TextureAsset = a, TextureID = a.FullID }); - - sr.ReadEndElement(); + return ret.ToArray(); + } + catch (XmlException) + { + return null; } - m_log.DebugFormat("[XBakes]: read {0} textures for user {1}", ret.Count, id); - sr.Close(); - s.Close(); - - - return ret.ToArray(); - } - catch (XmlException) - { - return null; } } @@ -153,27 +156,32 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures if (m_URL == String.Empty) return; - MemoryStream bakeStream = new MemoryStream(); - XmlTextWriter bakeWriter = new XmlTextWriter(bakeStream, null); + MemoryStream reqStream; - bakeWriter.WriteStartElement(String.Empty, "BakedAppearance", String.Empty); - - for (int i = 0; i < data.Length; i++) + using (MemoryStream bakeStream = new MemoryStream()) + using (XmlTextWriter bakeWriter = new XmlTextWriter(bakeStream, null)) { - if (data[i] != null) + bakeWriter.WriteStartElement(String.Empty, "BakedAppearance", String.Empty); + + for (int i = 0; i < data.Length; i++) { - bakeWriter.WriteStartElement(String.Empty, "BakedTexture", String.Empty); - bakeWriter.WriteAttributeString(String.Empty, "TextureIndex", String.Empty, data[i].TextureIndex.ToString()); - bakeWriter.WriteAttributeString(String.Empty, "CacheId", String.Empty, data[i].CacheId.ToString()); - if (data[i].TextureAsset != null) - m_serializer.Serialize(bakeWriter, data[i].TextureAsset); + if (data[i] != null) + { + bakeWriter.WriteStartElement(String.Empty, "BakedTexture", String.Empty); + bakeWriter.WriteAttributeString(String.Empty, "TextureIndex", String.Empty, data[i].TextureIndex.ToString()); + bakeWriter.WriteAttributeString(String.Empty, "CacheId", String.Empty, data[i].CacheId.ToString()); + if (data[i].TextureAsset != null) + m_serializer.Serialize(bakeWriter, data[i].TextureAsset); - bakeWriter.WriteEndElement(); + bakeWriter.WriteEndElement(); + } } - } - bakeWriter.WriteEndElement(); - bakeWriter.Flush(); + bakeWriter.WriteEndElement(); + bakeWriter.Flush(); + + reqStream = new MemoryStream(bakeStream.ToArray()); + } RestClient rc = new RestClient(m_URL); rc.AddResourcePath("bakes"); @@ -181,7 +189,6 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures rc.RequestMethod = "POST"; - MemoryStream reqStream = new MemoryStream(bakeStream.ToArray()); Util.FireAndForget( delegate { @@ -191,4 +198,4 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures ); } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 97267c1cd7..2ddb599af4 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -604,8 +604,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}", // so.Name, so.AttachedAvatar, url); - IteratingHGUuidGatherer uuidGatherer = new IteratingHGUuidGatherer(Scene.AssetService, url); - uuidGatherer.RecordAssetUuids(so); + IDictionary ids = new Dictionary(); + IteratingHGUuidGatherer uuidGatherer + = new IteratingHGUuidGatherer(Scene.AssetService, url, ids); + uuidGatherer.AddForInspection(so); while (!uuidGatherer.Complete) { @@ -632,8 +634,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } - IDictionary ids = uuidGatherer.GetGatheredUuids(); - // m_log.DebugFormat( // "[HG ENTITY TRANSFER]: Fetching {0} assets for attachment {1} for HG user {2} with asset service {3}", // ids.Count, so.Name, so.OwnerID, url); diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 9bf788545e..647943062e 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -680,6 +680,21 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement "Show the bindings between user UUIDs and user names", String.Empty, HandleShowUsers); + + MainConsole.Instance.Commands.AddCommand("Users", true, + "reset user cache", + "reset user cache", + "reset user cache to allow changed settings to be applied", + String.Empty, + HandleResetUserCache); + } + + private void HandleResetUserCache(string module, string[] cmd) + { + lock(m_UserCache) + { + m_UserCache.Clear(); + } } private void HandleShowUser(string module, string[] cmd) diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs index 601e81e587..46b0470600 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 /// true if the url matches an entry on the whitelist, false otherwise protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist) { + if (whitelist == null) + return false; + Uri url = new Uri(rawUrl); foreach (string origWlUrl in whitelist) diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs index d5dcdddf6a..478833ea70 100644 --- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs @@ -122,6 +122,17 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Check if the caller has permission to manipulate the given NPC. /// + /// + /// A caller has permission if + /// * An NPC exists with the given npcID. + /// * The caller UUID given is UUID.Zero. + /// * The avatar is unowned (owner is UUID.Zero). + /// * The avatar is owned and the owner and callerID match. + /// * The avatar is owned and the callerID matches its agentID. + /// + /// + /// + /// true if they do, false if they don't. /// /// /// diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f7c12d6f99..21d47aa15a 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -823,7 +823,6 @@ namespace OpenSim.Region.Framework.Scenes m_sceneGridService = sceneGridService; m_SimulationDataService = simDataService; m_EstateDataService = estateDataService; - m_regionHandle = RegionInfo.RegionHandle; m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); m_asyncSceneObjectDeleter.Enabled = true; @@ -2042,11 +2041,11 @@ namespace OpenSim.Region.Framework.Scenes GridRegion region = new GridRegion(RegionInfo); string error = GridService.RegisterRegion(RegionInfo.ScopeID, region); - m_log.DebugFormat("{0} RegisterRegionWithGrid. name={1},id={2},loc=<{3},{4}>,size=<{5},{6}>", - LogHeader, m_regionName, - RegionInfo.RegionID, - RegionInfo.RegionLocX, RegionInfo.RegionLocY, - RegionInfo.RegionSizeX, RegionInfo.RegionSizeY); +// m_log.DebugFormat("[SCENE]: RegisterRegionWithGrid. name={0},id={1},loc=<{2},{3}>,size=<{4},{5}>", +// m_regionName, +// RegionInfo.RegionID, +// RegionInfo.RegionLocX, RegionInfo.RegionLocY, +// RegionInfo.RegionSizeX, RegionInfo.RegionSizeY); if (error != String.Empty) throw new Exception(error); diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index aaddce6050..6f172e7611 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs @@ -145,10 +145,6 @@ namespace OpenSim.Region.Framework.Scenes get { return 1.0f; } } - protected ulong m_regionHandle; - protected string m_regionName; - protected RegionInfo m_regInfo; - public ITerrainChannel Heightmap; /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 93dfd005d2..0414f893c3 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1228,45 +1228,27 @@ namespace OpenSim.Region.Framework.Scenes m_scene.SwapRootAgentCount(false); - // The initial login scene presence is already root when it gets here - // and it has already rezzed the attachments and started their scripts. - // We do the following only for non-login agents, because their scripts - // haven't started yet. - if (PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags)) + if (Scene.AttachmentsModule != null) { - // Viewers which have a current outfit folder will actually rez their own attachments. However, - // viewers without (e.g. v1 viewers) will not, so we still need to make this call. - if (Scene.AttachmentsModule != null) + // The initial login scene presence is already root when it gets here + // and it has already rezzed the attachments and started their scripts. + // We do the following only for non-login agents, because their scripts + // haven't started yet. + if (PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags)) { + // Viewers which have a current outfit folder will actually rez their own attachments. However, + // viewers without (e.g. v1 viewers) will not, so we still need to make this call. WorkManager.RunJob( "RezAttachments", o => Scene.AttachmentsModule.RezAttachments(this), null, string.Format("Rez attachments for {0} in {1}", Name, Scene.Name)); } - } - else - { - // We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT - // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently - // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are - // not transporting the required data. - // - // We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of - // the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here - // which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status. - // - // FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts(). - // But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing - // is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the - // script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine. - List attachments = GetAttachments(); - - if (attachments.Count > 0) + else { WorkManager.RunJob( - "StartAttachmentScripts", - o => RestartAttachmentScripts(attachments), + "StartAttachmentScripts", + o => RestartAttachmentScripts(), null, string.Format("Start attachment scripts for {0} in {1}", Name, Scene.Name), true); @@ -1292,10 +1274,25 @@ namespace OpenSim.Region.Framework.Scenes return true; } - private void RestartAttachmentScripts(List attachments) + private void RestartAttachmentScripts() { + // We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT + // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently + // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are + // not transporting the required data. + // + // We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of + // the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here + // which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status. + // + // FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts(). + // But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing + // is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the + // script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine. + List attachments = GetAttachments(); + m_log.DebugFormat( - "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); + "[SCENE PRESENCE]: Restarting scripts in {0} attachments for {1} in {2}", attachments.Count, Name, Scene.Name); // Resume scripts foreach (SceneObjectGroup sog in attachments) diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 2450cdbb84..2c5353fc6b 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -648,6 +648,15 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// Gather uuids for a given entity. + /// + /// + /// This does a deep inspection of the entity to retrieve all the assets it uses (whether as textures, as scripts + /// contained in inventory, as scripts contained in objects contained in another object's inventory, etc. Assets + /// are only retrieved when they are necessary to carry out the inspection (i.e. a serialized object needs to be + /// retrieved to work out which assets it references). + /// public class IteratingUuidGatherer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -678,21 +687,31 @@ namespace OpenSim.Region.Framework.Scenes protected Queue m_assetUuidsToInspect; - public IteratingUuidGatherer(IAssetService assetService) + /// + /// Initializes a new instance of the class. + /// + /// + /// Asset service. + /// + /// + /// Gathered UUIDs will be collected in this dictinaory. + /// It can be pre-populated if you want to stop the gatherer from analyzing assets that have already been fetched and inspected. + /// + public IteratingUuidGatherer(IAssetService assetService, IDictionary collector) { m_assetService = assetService; - m_gatheredAssetUuids = new Dictionary(); + m_gatheredAssetUuids = collector; // FIXME: Not efficient for searching, can improve. m_assetUuidsToInspect = new Queue(); } - public IDictionary GetGatheredUuids() - { - return new Dictionary(m_gatheredAssetUuids); - } - - public bool AddAssetUuidToInspect(UUID uuid) + /// + /// Adds the asset uuid for inspection during the gathering process. + /// + /// true, if for inspection was added, false otherwise. + /// UUID. + public bool AddForInspection(UUID uuid) { if (m_assetUuidsToInspect.Contains(uuid)) return false; @@ -701,6 +720,107 @@ namespace OpenSim.Region.Framework.Scenes return true; } + + /// + /// Gather all the asset uuids associated with a given object. + /// + /// + /// This includes both those directly associated with + /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained + /// within this object). + /// + /// The scene object for which to gather assets + public void AddForInspection(SceneObjectGroup sceneObject) + { + // m_log.DebugFormat( + // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); + + SceneObjectPart[] parts = sceneObject.Parts; + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + + // m_log.DebugFormat( + // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); + + try + { + Primitive.TextureEntry textureEntry = part.Shape.Textures; + if (textureEntry != null) + { + // Get the prim's default texture. This will be used for faces which don't have their own texture + if (textureEntry.DefaultTexture != null) + RecordTextureEntryAssetUuids(textureEntry.DefaultTexture); + + if (textureEntry.FaceTextures != null) + { + // Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture) + foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures) + { + if (texture != null) + RecordTextureEntryAssetUuids(texture); + } + } + } + + // If the prim is a sculpt then preserve this information too + if (part.Shape.SculptTexture != UUID.Zero) + m_gatheredAssetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture; + + if (part.Shape.ProjectionTextureUUID != UUID.Zero) + m_gatheredAssetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture; + + if (part.CollisionSound != UUID.Zero) + m_gatheredAssetUuids[part.CollisionSound] = (sbyte)AssetType.Sound; + + if (part.ParticleSystem.Length > 0) + { + try + { + Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); + if (ps.Texture != UUID.Zero) + m_gatheredAssetUuids[ps.Texture] = (sbyte)AssetType.Texture; + } + catch (Exception) + { + m_log.WarnFormat( + "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.", + part.Name, part.UUID, sceneObject.Name, sceneObject.UUID); + } + } + + TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); + + // Now analyze this prim's inventory items to preserve all the uuids that they reference + foreach (TaskInventoryItem tii in taskDictionary.Values) + { + // m_log.DebugFormat( + // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", + // tii.Name, tii.Type, part.Name, part.UUID); + + if (!m_gatheredAssetUuids.ContainsKey(tii.AssetID)) + AddForInspection(tii.AssetID, (sbyte)tii.Type); + } + + // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed + // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and + // inventory transfer. There needs to be a way for a module to register a method without assuming a + // Scene.EventManager is present. + // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); + + + // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs + RecordMaterialsUuids(part); + } + catch (Exception e) + { + m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e); + m_log.DebugFormat( + "[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)", + part.Shape.TextureEntry.Length); + } + } + } /// /// Gathers the next set of assets returned by the next uuid to get from the asset service. @@ -790,7 +910,7 @@ namespace OpenSim.Region.Framework.Scenes } } - private void RecordAssetUuids(UUID assetUuid, sbyte assetType) + private void AddForInspection(UUID assetUuid, sbyte assetType) { // Here, we want to collect uuids which require further asset fetches but mark the others as gathered try @@ -799,27 +919,27 @@ namespace OpenSim.Region.Framework.Scenes if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) { - AddAssetUuidToInspect(assetUuid); + AddForInspection(assetUuid); } else if ((sbyte)AssetType.Gesture == assetType) { - AddAssetUuidToInspect(assetUuid); + AddForInspection(assetUuid); } else if ((sbyte)AssetType.Notecard == assetType) { - AddAssetUuidToInspect(assetUuid); + AddForInspection(assetUuid); } else if ((sbyte)AssetType.LSLText == assetType) { - AddAssetUuidToInspect(assetUuid); + AddForInspection(assetUuid); } else if ((sbyte)OpenSimAssetType.Material == assetType) { - AddAssetUuidToInspect(assetUuid); + AddForInspection(assetUuid); } else if ((sbyte)AssetType.Object == assetType) { - AddAssetUuidToInspect(assetUuid); + AddForInspection(assetUuid); } } catch (Exception) @@ -831,107 +951,6 @@ namespace OpenSim.Region.Framework.Scenes } } - /// - /// Gather all the asset uuids associated with a given object. - /// - /// - /// This includes both those directly associated with - /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained - /// within this object). - /// - /// The scene object for which to gather assets - public void RecordAssetUuids(SceneObjectGroup sceneObject) - { - // m_log.DebugFormat( - // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); - - SceneObjectPart[] parts = sceneObject.Parts; - for (int i = 0; i < parts.Length; i++) - { - SceneObjectPart part = parts[i]; - - // m_log.DebugFormat( - // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); - - try - { - Primitive.TextureEntry textureEntry = part.Shape.Textures; - if (textureEntry != null) - { - // Get the prim's default texture. This will be used for faces which don't have their own texture - if (textureEntry.DefaultTexture != null) - RecordTextureEntryAssetUuids(textureEntry.DefaultTexture); - - if (textureEntry.FaceTextures != null) - { - // Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture) - foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures) - { - if (texture != null) - RecordTextureEntryAssetUuids(texture); - } - } - } - - // If the prim is a sculpt then preserve this information too - if (part.Shape.SculptTexture != UUID.Zero) - m_gatheredAssetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture; - - if (part.Shape.ProjectionTextureUUID != UUID.Zero) - m_gatheredAssetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture; - - if (part.CollisionSound != UUID.Zero) - m_gatheredAssetUuids[part.CollisionSound] = (sbyte)AssetType.Sound; - - if (part.ParticleSystem.Length > 0) - { - try - { - Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); - if (ps.Texture != UUID.Zero) - m_gatheredAssetUuids[ps.Texture] = (sbyte)AssetType.Texture; - } - catch (Exception) - { - m_log.WarnFormat( - "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.", - part.Name, part.UUID, sceneObject.Name, sceneObject.UUID); - } - } - - TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); - - // Now analyze this prim's inventory items to preserve all the uuids that they reference - foreach (TaskInventoryItem tii in taskDictionary.Values) - { - // m_log.DebugFormat( - // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", - // tii.Name, tii.Type, part.Name, part.UUID); - - if (!m_gatheredAssetUuids.ContainsKey(tii.AssetID)) - RecordAssetUuids(tii.AssetID, (sbyte)tii.Type); - } - - // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed - // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and - // inventory transfer. There needs to be a way for a module to register a method without assuming a - // Scene.EventManager is present. - // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); - - - // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs - RecordMaterialsUuids(part); - } - catch (Exception e) - { - m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e); - m_log.DebugFormat( - "[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)", - part.Shape.TextureEntry.Length); - } - } - } - /// /// Collect all the asset uuids found in one face of a Texture Entry. /// @@ -940,7 +959,7 @@ namespace OpenSim.Region.Framework.Scenes m_gatheredAssetUuids[texture.TextureID] = (sbyte)AssetType.Texture; if (texture.MaterialID != UUID.Zero) - AddAssetUuidToInspect(texture.MaterialID); + AddForInspection(texture.MaterialID); } /// @@ -948,7 +967,7 @@ namespace OpenSim.Region.Framework.Scenes /// stored in legacy format in part.DynAttrs /// /// - public void RecordMaterialsUuids(SceneObjectPart part) + private void RecordMaterialsUuids(SceneObjectPart part) { // scan thru the dynAttrs map of this part for any textures used as materials OSD osdMaterials = null; @@ -1039,7 +1058,7 @@ namespace OpenSim.Region.Framework.Scenes UUID uuid = new UUID(uuidMatch.Value); // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid); - AddAssetUuidToInspect(uuid); + AddForInspection(uuid); } } @@ -1074,14 +1093,14 @@ namespace OpenSim.Region.Framework.Scenes if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) { foreach (SceneObjectGroup sog in coa.Objects) - RecordAssetUuids(sog); + AddForInspection(sog); } else { SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); if (null != sog) - RecordAssetUuids(sog); + AddForInspection(sog); } } @@ -1147,8 +1166,8 @@ namespace OpenSim.Region.Framework.Scenes protected string m_assetServerURL; - public IteratingHGUuidGatherer(IAssetService assetService, string assetServerURL) - : base(assetService) + public IteratingHGUuidGatherer(IAssetService assetService, string assetServerURL, IDictionary collector) + : base(assetService, collector) { m_assetServerURL = assetServerURL; if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("=")) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 95e59ab38e..b834619d2c 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -441,13 +441,20 @@ namespace OpenSim.Region.OptionalModules.World.NPC /// /// Check if the caller has permission to manipulate the given NPC. /// + /// + /// A caller has permission if + /// * The caller UUID given is UUID.Zero. + /// * The avatar is unowned (owner is UUID.Zero). + /// * The avatar is owned and the owner and callerID match. + /// * The avatar is owned and the callerID matches its agentID. + /// /// /// /// true if they do, false if they don't. private bool CheckPermissions(NPCAvatar av, UUID callerID) { return callerID == UUID.Zero || av.OwnerID == UUID.Zero || - av.OwnerID == callerID; + av.OwnerID == callerID || av.AgentId == callerID; } } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index b9a217b649..1097efb856 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -222,7 +222,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces void SetVars(Dictionary vars); DetectParams GetDetectParams(int idx); UUID GetDetectID(int idx); - void SaveState(string assembly); + void SaveState(); void DestroyScriptInstance(); IScriptApi GetApi(string name); diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 9379f8fe74..de5f92df4a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -663,9 +663,8 @@ namespace SecondLife try { - FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read); - fs.Read(data, 0, data.Length); - fs.Close(); + using (FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read)) + fs.Read(data, 0, data.Length); } catch (Exception) { @@ -680,9 +679,8 @@ namespace SecondLife Byte[] buf = Encoding.ASCII.GetBytes(filetext); - FileStream sfs = File.Create(assembly + ".text"); - sfs.Write(buf, 0, buf.Length); - sfs.Close(); + using (FileStream sfs = File.Create(assembly + ".text")) + sfs.Write(buf, 0, buf.Length); return assembly; } @@ -775,7 +773,6 @@ namespace SecondLife return message; } - private static void WriteMapFile(string filename, Dictionary, KeyValuePair> linemap) { string mapstring = String.Empty; @@ -787,40 +784,42 @@ namespace SecondLife } Byte[] mapbytes = Encoding.ASCII.GetBytes(mapstring); - FileStream mfs = File.Create(filename); - mfs.Write(mapbytes, 0, mapbytes.Length); - mfs.Close(); - } + using (FileStream mfs = File.Create(filename)) + mfs.Write(mapbytes, 0, mapbytes.Length); + } private static Dictionary, KeyValuePair> ReadMapFile(string filename) { Dictionary, KeyValuePair> linemap; try { - StreamReader r = File.OpenText(filename); - linemap = new Dictionary, KeyValuePair>(); - - string line; - while ((line = r.ReadLine()) != null) + using (StreamReader r = File.OpenText(filename)) { - String[] parts = line.Split(new Char[] { ',' }); - int kk = System.Convert.ToInt32(parts[0]); - int kv = System.Convert.ToInt32(parts[1]); - int vk = System.Convert.ToInt32(parts[2]); - int vv = System.Convert.ToInt32(parts[3]); + linemap = new Dictionary, KeyValuePair>(); - KeyValuePair k = new KeyValuePair(kk, kv); - KeyValuePair v = new KeyValuePair(vk, vv); + string line; + while ((line = r.ReadLine()) != null) + { + String[] parts = line.Split(new Char[] { ',' }); + int kk = System.Convert.ToInt32(parts[0]); + int kv = System.Convert.ToInt32(parts[1]); + int vk = System.Convert.ToInt32(parts[2]); + int vv = System.Convert.ToInt32(parts[3]); - linemap[k] = v; + KeyValuePair k = new KeyValuePair(kk, kv); + KeyValuePair v = new KeyValuePair(vk, vv); + + linemap[k] = v; + } } } catch { linemap = new Dictionary, KeyValuePair>(); } + return linemap; } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 9da2168585..b983be93b6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -71,7 +71,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance private bool m_TimerQueued; private DateTime m_EventStart; private bool m_InEvent; - private string m_Assembly; + private string m_assemblyPath; + private string m_dataPath; private string m_CurrentEvent = String.Empty; private bool m_InSelfDelete; private int m_MaxScriptQueue; @@ -244,12 +245,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance /// /// /// + /// + /// Path for all script associated data (state, etc.). In a multi-region set up + /// with all scripts loading into the same AppDomain this may not be the same place as the DLL itself. + /// /// /// false if load failed, true if suceeded - public bool Load(AppDomain dom, Assembly scriptAssembly, StateSource stateSource) + public bool Load(AppDomain dom, Assembly scriptAssembly, string dataPath, StateSource stateSource) { - //m_Assembly = scriptAssembly.CodeBase; - m_Assembly = scriptAssembly.Location; + m_assemblyPath = scriptAssembly.Location; + m_dataPath = dataPath; m_stateSource = stateSource; try @@ -270,14 +275,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance constructorParams = null; } -// m_log.DebugFormat( -// "[SCRIP -// scriptType.FullName, m_Assembly, Engine.World.Name); - if (dom != System.AppDomain.CurrentDomain) m_Script = (IScript)dom.CreateInstanceAndUnwrap( - Path.GetFileNameWithoutExtension(m_Assembly), + Path.GetFileNameWithoutExtension(m_assemblyPath), scriptType.FullName, false, BindingFlags.Default, @@ -305,7 +306,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}", - ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, m_Assembly, e.Message, e.StackTrace); + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, scriptAssembly.Location, e.Message, e.StackTrace); return false; } @@ -340,10 +341,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_SaveState = true; - string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), ItemID.ToString() + ".state"); + string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state"); if (File.Exists(savedState)) { +// m_log.DebugFormat( +// "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}", +// ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); + string xml = String.Empty; try @@ -385,12 +390,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_startedFromSavedState = true; } } - else - { - m_log.WarnFormat( - "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", - ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); - } +// else +// { +// m_log.WarnFormat( +// "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", +// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); +// } } catch (Exception e) { @@ -401,11 +406,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } // else // { -// ScenePresence presence = Engine.World.GetScenePresence(part.OwnerID); - -// if (presence != null && (!postOnRez)) -// presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); - +// m_log.DebugFormat( +// "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}", +// ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); // } return true; @@ -498,8 +501,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public void RemoveState() { - string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), - ItemID.ToString() + ".state"); + string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state"); + +// m_log.DebugFormat( +// "[SCRIPT INSTANCE]: Deleting state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}.", +// savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name); try { @@ -822,8 +828,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (Engine.World.PipeEventsForScript(LocalID) || data.EventName == "control") // Don't freeze avies! { - // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", - // PrimName, ScriptName, data.EventName, State); +// m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", +// PrimName, ScriptName, data.EventName, State); try { @@ -849,7 +855,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // This will be the very first event we deliver // (state_entry) in default state // - SaveState(m_Assembly); + SaveState(); m_SaveState = false; } @@ -1043,7 +1049,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance return m_DetectParams[idx].Key; } - public void SaveState(string assembly) + public void SaveState() { // If we're currently in an event, just tell it to save upon return // @@ -1065,10 +1071,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { try { - FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")); - Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); - fs.Write(buf, 0, buf.Length); - fs.Close(); + using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state"))) + { + Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); + fs.Write(buf, 0, buf.Length); + } } catch(Exception) { @@ -1148,7 +1155,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public string GetAssemblyName() { - return m_Assembly; + return m_assemblyPath; } public string GetXMLState() diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs index fe15157af5..878e571617 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs @@ -40,10 +40,10 @@ using OpenSim.Tests.Common; namespace OpenSim.Region.ScriptEngine.XEngine.Tests { /// - /// XEngine tests. + /// Basic XEngine tests. /// [TestFixture] - public class XEngineTest : OpenSimTestCase + public class XEngineBasicTests : OpenSimTestCase { private TestScene m_scene; private XEngine m_xEngine; diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs new file mode 100644 index 0000000000..587695fc1a --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs @@ -0,0 +1,195 @@ +/* + * 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.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.XEngine.Tests +{ + /// + /// XEngine tests connected with crossing scripts between regions. + /// + [TestFixture] + public class XEngineCrossingTests : OpenSimTestCase + { + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [TestFixtureTearDown] + public void TearDown() + { + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression + // tests really shouldn't). + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + /// + /// Test script state preservation when a script crosses between regions on the same simulator. + /// + [Test] + public void TestScriptCrossOnSameSimulator() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + int sceneObjectIdTail = 0x2; + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + XEngine xEngineA = new XEngine(); + XEngine xEngineB = new XEngine(); + xEngineA.DebugLevel = 1; + xEngineB.DebugLevel = 1; + + IConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = configSource.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + + // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call + // to AssemblyResolver.OnAssemblyResolve fails. + xEngineConfig.Set("AppDomainLoading", "false"); + + IConfig modulesConfig = configSource.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000, configSource); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999, configSource); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, configSource, lscm); + SceneHelpers.SetupSceneModules(sceneA, configSource, etmA, xEngineA); + SceneHelpers.SetupSceneModules(sceneB, configSource, etmB, xEngineB); + sceneA.StartScripts(); + sceneB.StartScripts(); + + SceneObjectGroup soSceneA = SceneHelpers.AddSceneObject(sceneA, 1, userId, "so1-", sceneObjectIdTail); + soSceneA.AbsolutePosition = new Vector3(128, 10, 20); + + // CREATE SCRIPT TODO + InventoryItemBase scriptItemSceneA = new InventoryItemBase(); + // itemTemplate.ID = itemId; + scriptItemSceneA.Name = "script1"; + scriptItemSceneA.Folder = soSceneA.UUID; + scriptItemSceneA.InvType = (int)InventoryType.LSL; + + AutoResetEvent chatEvent = new AutoResetEvent(false); + OSChatMessage messageReceived = null; + sceneA.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); }; + + sceneA.RezNewScript(userId, scriptItemSceneA, +@"integer c = 0; + +default +{ + state_entry() + { + llSay(0, ""Script running""); + } + + changed(integer change) + { + llSay(0, ""Changed""); + } + + touch_start(integer n) + { + c = c + 1; + llSay(0, (string)c); + } +}"); + + chatEvent.WaitOne(60000); + + Assert.That(messageReceived, Is.Not.Null, "No chat message received."); + Assert.That(messageReceived.Message, Is.EqualTo("Script running")); + + { + // XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead. + DetectParams[] det = new DetectParams[1]; + det[0] = new DetectParams(); + det[0].Key = userId; + det[0].Populate(sceneA); + + EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det); + + xEngineA.PostObjectEvent(soSceneA.LocalId, ep); + chatEvent.WaitOne(60000); + + Assert.That(messageReceived.Message, Is.EqualTo("1")); + } + + sceneB.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); }; + + // Cross with a negative value + soSceneA.AbsolutePosition = new Vector3(128, -10, 20); + + chatEvent.WaitOne(60000); + Assert.That(messageReceived.Message, Is.EqualTo("Changed")); + + // TEST sending event to moved prim and output + { + SceneObjectGroup soSceneB = sceneB.GetSceneObjectGroup(soSceneA.Name); + TaskInventoryItem scriptItemSceneB = soSceneB.RootPart.Inventory.GetInventoryItem(scriptItemSceneA.Name); + + // XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead. + DetectParams[] det = new DetectParams[1]; + det[0] = new DetectParams(); + det[0].Key = userId; + det[0].Populate(sceneB); + + EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det); + + xEngineB.PostObjectEvent(soSceneB.LocalId, ep); + chatEvent.WaitOne(60000); + + Assert.That(messageReceived.Message, Is.EqualTo("2")); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index a4113d66a9..906c6ee298 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -70,7 +70,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine /// /// If DebugLevel >= 1, then we log every time that a script is started. /// -// public int DebugLevel { get; set; } + public int DebugLevel { get; set; } private SmartThreadPool m_ThreadPool; private int m_MaxScriptQueue; @@ -101,7 +101,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine private bool m_InitialStartup = true; private int m_ScriptFailCount; // Number of script fails since compile queue was last empty private string m_ScriptErrorMessage; - private Dictionary m_uniqueScripts = new Dictionary(); private bool m_AppDomainLoading; private Dictionary m_ScriptErrors = new Dictionary(); @@ -403,12 +402,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine + "Level >= 2, log event invocations.\n", HandleDebugScriptLogCommand); -// MainConsole.Instance.Commands.AddCommand( -// "Debug", false, "debug xengine", "debug xengine []", -// "Turn on detailed xengine debugging.", -// "If level <= 0, then no extra logging is done.\n" -// + "If level >= 1, then we log every time that a script is started.", -// HandleDebugLevelCommand); + MainConsole.Instance.Commands.AddCommand( + "Debug", false, "debug xengine log", "debug xengine log []", + "Turn on detailed xengine debugging.", + "If level <= 0, then no extra logging is done.\n" + + "If level >= 1, then we log every time that a script is started.", + HandleDebugLevelCommand); } private void HandleDebugScriptLogCommand(string module, string[] args) @@ -451,26 +450,26 @@ namespace OpenSim.Region.ScriptEngine.XEngine /// /// /// -// private void HandleDebugLevelCommand(string module, string[] args) -// { -// if (args.Length == 3) -// { -// int newDebug; -// if (int.TryParse(args[2], out newDebug)) -// { -// DebugLevel = newDebug; -// MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug); -// } -// } -// else if (args.Length == 2) -// { -// MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); -// } -// else -// { -// MainConsole.Instance.Output("Usage: debug xengine 0..1"); -// } -// } + private void HandleDebugLevelCommand(string module, string[] args) + { + if (args.Length <= 4) + { + int newDebug; + if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, args[3], out newDebug)) + { + DebugLevel = newDebug; + MainConsole.Instance.OutputFormat("Debug level set to {0} in XEngine for region {1}", newDebug, m_Scene.Name); + } + } + else if (args.Length == 3) + { + MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); + } + else + { + MainConsole.Instance.Output("Usage: debug xengine log "); + } + } /// /// Parse the raw item id into a script instance from the command params if it's present. @@ -570,7 +569,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine } sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded); - sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads); @@ -716,22 +714,17 @@ namespace OpenSim.Region.ScriptEngine.XEngine { // Force a final state save // - if (m_Assemblies.ContainsKey(instance.AssetID)) + try { - string assembly = m_Assemblies[instance.AssetID]; - - try - { - instance.SaveState(assembly); - } - catch (Exception e) - { - m_log.Error( - string.Format( - "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ", - instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name) - , e); - } + instance.SaveState(); + } + catch (Exception e) + { + m_log.Error( + string.Format( + "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ", + instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name) + , e); } // Clear the event queue and abort the instance thread @@ -840,18 +833,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine foreach (IScriptInstance i in instances) { - string assembly = String.Empty; - - lock (m_Scripts) - { - if (!m_Assemblies.ContainsKey(i.AssetID)) - continue; - assembly = m_Assemblies[i.AssetID]; - } - try { - i.SaveState(assembly); + i.SaveState(); } catch (Exception e) { @@ -1001,12 +985,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (engine != ScriptEngineName) return; - // If we've seen this exact script text before, use that reference instead - if (m_uniqueScripts.ContainsKey(script)) - script = m_uniqueScripts[script]; - else - m_uniqueScripts[script] = script; - Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; if (stateSource == (int)StateSource.ScriptedRez) @@ -1020,11 +998,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine } else { - m_CompileQueue.Enqueue(parms); lock (m_CompileDict) - { m_CompileDict[itemID] = 0; - } + + // This must occur after the m_CompileDict so that an existing compile thread cannot hit the check + // in DoOnRezScript() before m_CompileDict has been updated. + m_CompileQueue.Enqueue(parms); // m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID); @@ -1100,7 +1079,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine // due to a race condition // lock (m_CompileQueue) + { m_CurrentCompile = null; + + // This is to avoid a situation where the m_CompileQueue while loop above could complete but + // OnRezScript() place a new script on the queue and check m_CurrentCompile = null before we hit + // this section. + if (m_CompileQueue.Count > 0) + m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null); + } } return null; @@ -1148,10 +1135,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine return false; } - m_log.DebugFormat( - "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", - part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, - part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); + if (DebugLevel > 0) + m_log.DebugFormat( + "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", + part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, + part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); UUID assetID = item.AssetID; @@ -1170,7 +1158,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine lock (m_AddingAssemblies) { m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assemblyPath, out linemap); - + +// m_log.DebugFormat( +// "[XENGINE]: Found assembly path {0} onrez {1} in {2}", +// assemblyPath, item.ItemID, World.Name); + if (!m_AddingAssemblies.ContainsKey(assemblyPath)) { m_AddingAssemblies[assemblyPath] = 1; } else { @@ -1348,14 +1340,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine // simulator session if the script halt strategy has been changed. Instead, we'll continue with // the existing DLL and the new one will be used in the next simulator session. if (recompile) + { + m_log.DebugFormat( + "[XEngine]: Recompiling script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5} to switch it to {6} termination. Will be active on next restart.", + part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, + part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.Name, + m_coopTermination ? "co-op" : "abort"); + m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, true, out assemblyPath, out linemap); + } instance = new ScriptInstance(this, part, item, startParam, postOnRez, m_MaxScriptQueue); - if (!instance.Load(m_AppDomains[appDomain], scriptAssembly, stateSource)) + if (!instance.Load( + m_AppDomains[appDomain], scriptAssembly, + Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource)) return false; // if (DebugLevel >= 1) @@ -1586,7 +1588,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine IScriptInstance instance = (ScriptInstance) parms; - //m_log.DebugFormat("[XEngine]: Processing event for {0}", instance); +// m_log.DebugFormat("[XEngine]: Processing event for {0}", instance); return instance.EventProcessor(); } @@ -2155,7 +2157,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine catch (IOException ex) { // if there already exists a file at that location, it may be locked. - m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message); + m_log.Error( + string.Format("[XEngine]: Linemap file {0} could not be written. Exception ", mappath), ex); } } } @@ -2181,6 +2184,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message); } +// m_log.DebugFormat( +// "[XEngine]: Wrote state for script item with ID {0} at {1} in {2}", itemID, statepath, m_Scene.Name); + return true; } diff --git a/OpenSim/Server/Handlers/BakedTextures/XBakes.cs b/OpenSim/Server/Handlers/BakedTextures/XBakes.cs index d1b2e124d8..4e554336ae 100644 --- a/OpenSim/Server/Handlers/BakedTextures/XBakes.cs +++ b/OpenSim/Server/Handlers/BakedTextures/XBakes.cs @@ -107,11 +107,9 @@ namespace OpenSim.Server.Handlers.BakedTextures File.Delete(diskFile); byte[] data = utf8encoding.GetBytes(sdata); - FileStream fs = File.Create(diskFile); - fs.Write(data, 0, data.Length); - - fs.Close(); + using (FileStream fs = File.Create(diskFile)) + fs.Write(data, 0, data.Length); } private void HandleDeleteBakes(string module, string[] args) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index e8a545cf10..29723d8329 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -317,8 +317,10 @@ namespace OpenSim.Services.GridService m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e); } - m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3} with flags {4}", - regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY, + m_log.DebugFormat + ("[GRID SERVICE]: Region {0} ({1}, {2}x{3}) registered at {4},{5} with flags {6}", + regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionSizeX, regionInfos.RegionSizeY, + regionInfos.RegionCoordX, regionInfos.RegionCoordY, (OpenSim.Framework.RegionFlags)flags); return String.Empty; diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs index ec6118b3f6..4705445675 100644 --- a/OpenSim/Services/UserAccountService/UserAccountService.cs +++ b/OpenSim/Services/UserAccountService/UserAccountService.cs @@ -98,7 +98,12 @@ namespace OpenSim.Services.UserAccountService MainConsole.Instance.Commands.AddCommand("Users", false, "reset user password", "reset user password [ [ []]]", - "Reset a user password", HandleResetUserPassword); + "Reset a user password", HandleResetUserPassword); + + MainConsole.Instance.Commands.AddCommand("Users", false, + "reset user email", + "reset user email [ [ []]]", + "Reset a user email address", HandleResetUserEmail); MainConsole.Instance.Commands.AddCommand("Users", false, "set user level", @@ -420,6 +425,43 @@ namespace OpenSim.Services.UserAccountService MainConsole.Instance.OutputFormat("Password reset for user {0} {1}", firstName, lastName); } + protected void HandleResetUserEmail(string module, string[] cmdparams) + { + string firstName; + string lastName; + string newEmail; + + if (cmdparams.Length < 4) + firstName = MainConsole.Instance.CmdPrompt("First name"); + else firstName = cmdparams[3]; + + if (cmdparams.Length < 5) + lastName = MainConsole.Instance.CmdPrompt("Last name"); + else lastName = cmdparams[4]; + + if (cmdparams.Length < 6) + newEmail = MainConsole.Instance.PasswdPrompt("New Email"); + else newEmail = cmdparams[5]; + + UserAccount account = GetUserAccount(UUID.Zero, firstName, lastName); + if (account == null) + { + MainConsole.Instance.OutputFormat("No such user as {0} {1}", firstName, lastName); + return; + } + + bool success = false; + + account.Email = newEmail; + + success = StoreUserAccount(account); + if (!success) + MainConsole.Instance.OutputFormat("Unable to set Email for account {0} {1}.", firstName, lastName); + else + MainConsole.Instance.OutputFormat("User Email set for user {0} {1} to {2}", firstName, lastName, account.Email); + } + + protected void HandleSetUserLevel(string module, string[] cmdparams) { string firstName; diff --git a/bin/OpenMetaverse.dll b/bin/OpenMetaverse.dll index f1f5ed66a3..97aaba45ed 100755 Binary files a/bin/OpenMetaverse.dll and b/bin/OpenMetaverse.dll differ diff --git a/bin/OpenSim.exe.config b/bin/OpenSim.exe.config index 31f1064068..e19a47a4a4 100755 --- a/bin/OpenSim.exe.config +++ b/bin/OpenSim.exe.config @@ -57,11 +57,6 @@ - - - - - diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 9a6371b3af..4d4ebde14f 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -208,6 +208,10 @@ [InventoryService] LocalServiceModule = "OpenSim.Services.InventoryService.dll:XInventoryService" + ; Will calls to purge folders (empty trash) and immediately delete/update items or folders (not move to trash first) succeed? + ; If this is set to false then some other arrangement must be made to perform these operations if necessary. + AllowDelete = true + ; * This is the new style grid service. ; * "Realm" is the table that is used for user lookup. diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 0ce16ba47f..a7b39a36aa 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -179,6 +179,10 @@ [InventoryService] LocalServiceModule = "OpenSim.Services.InventoryService.dll:XInventoryService" + ; Will calls to purge folders (empty trash) and immediately delete/update items or folders (not move to trash first) succeed? + ; If this is set to false then some other arrangement must be made to perform these operations if necessary. + AllowDelete = true + ; * This is the new style grid service. ; * "Realm" is the table that is used for user lookup. diff --git a/prebuild.xml b/prebuild.xml index 90997cf1b4..a9a7cfcf73 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2926,7 +2926,6 @@ -