diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index bc6f6f99a9..241fef3866 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -30,6 +30,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; +using System.Threading; using log4net; using Nini.Config; using OpenMetaverse; @@ -68,6 +69,7 @@ namespace OpenSim.Framework.Capabilities private IHttpServer m_httpListener; private UUID m_agentID; private string m_regionName; + private ManualResetEvent m_capsActive = new ManualResetEvent(false); public UUID AgentID { @@ -171,5 +173,16 @@ namespace OpenSim.Framework.Capabilities } } } + + public void Activate() + { + m_capsActive.Set(); + } + + public bool WaitForActivation() + { + // Wait for 30s. If that elapses, return false and run without caps + return m_capsActive.WaitOne(30000); + } } } diff --git a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs index 9a6ca8640a..11a269882b 100644 --- a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs +++ b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs @@ -435,4 +435,4 @@ namespace OpenSim.Capabilities.Handlers return llsdItem; } } -} \ No newline at end of file +} diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 01b9299035..d5a4f46d12 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -1339,7 +1339,7 @@ namespace OpenSim.Data.MySQL prim.Density = (float)(double)row["Density"]; prim.GravityModifier = (float)(double)row["GravityModifier"]; prim.Friction = (float)(double)row["Friction"]; - prim.Bounciness = (float)(double)row["Restitution"]; + prim.Restitution = (float)(double)row["Restitution"]; SOPVehicle vehicle = null; @@ -1725,7 +1725,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("Density", (double)prim.Density); cmd.Parameters.AddWithValue("GravityModifier", (double)prim.GravityModifier); cmd.Parameters.AddWithValue("Friction", (double)prim.Friction); - cmd.Parameters.AddWithValue("Restitution", (double)prim.Bounciness); + cmd.Parameters.AddWithValue("Restitution", (double)prim.Restitution); if (prim.VehicleParams != null) cmd.Parameters.AddWithValue("Vehicle", prim.VehicleParams.ToXml2()); diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 041fb94ff1..ba6d87dac2 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -497,8 +497,6 @@ namespace OpenSim.Framework /// public List GetAttachments() { - - lock (m_attachments) { List alist = new List(); @@ -508,7 +506,8 @@ namespace OpenSim.Framework alist.Add(new AvatarAttachment(attach)); } return alist; - } } + } + } internal void AppendAttachment(AvatarAttachment attach) { diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e76a37b9a1..48f3f8b0d2 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2097,4 +2097,112 @@ namespace OpenSim.Framework } #endregion } + + public class DoubleQueue where T:class + { + private Queue m_lowQueue = new Queue(); + private Queue m_highQueue = new Queue(); + + private object m_syncRoot = new object(); + private Semaphore m_s = new Semaphore(0, 1); + + public DoubleQueue() + { + } + + public virtual int Count + { + get { return m_highQueue.Count + m_lowQueue.Count; } + } + + public virtual void Enqueue(T data) + { + Enqueue(m_lowQueue, data); + } + + public virtual void EnqueueLow(T data) + { + Enqueue(m_lowQueue, data); + } + + public virtual void EnqueueHigh(T data) + { + Enqueue(m_highQueue, data); + } + + private void Enqueue(Queue q, T data) + { + lock (m_syncRoot) + { + m_lowQueue.Enqueue(data); + m_s.WaitOne(0); + m_s.Release(); + } + } + + public virtual T Dequeue() + { + return Dequeue(Timeout.Infinite); + } + + public virtual T Dequeue(int tmo) + { + return Dequeue(TimeSpan.FromMilliseconds(tmo)); + } + + public virtual T Dequeue(TimeSpan wait) + { + T res = null; + + if (!Dequeue(wait, ref res)) + return null; + + return res; + } + + public bool Dequeue(int timeout, ref T res) + { + return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); + } + + public bool Dequeue(TimeSpan wait, ref T res) + { + if (!m_s.WaitOne(wait)) + return false; + + lock (m_syncRoot) + { + if (m_highQueue.Count > 0) + res = m_highQueue.Dequeue(); + else + res = m_lowQueue.Dequeue(); + + if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) + return true; + + try + { + m_s.Release(); + } + catch + { + } + + return true; + } + } + + public virtual void Clear() + { + + lock (m_syncRoot) + { + // Make sure sem count is 0 + m_s.WaitOne(0); + + m_lowQueue.Clear(); + m_highQueue.Clear(); + } + } + } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index b06788b199..248eab61d9 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -343,6 +343,9 @@ namespace OpenSim.Region.ClientStack.Linden m_log.DebugFormat( "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); + if (!m_HostCapsObj.WaitForActivation()) + return string.Empty; + if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) { m_log.WarnFormat( @@ -1317,7 +1320,7 @@ namespace OpenSim.Region.ClientStack.Linden object_data["PhysicsShapeType"] = obj.PhysicsShapeType; object_data["Density"] = obj.Density; object_data["Friction"] = obj.Friction; - object_data["Restitution"] = obj.Bounciness; + object_data["Restitution"] = obj.Restitution; object_data["GravityMultiplier"] = obj.GravityModifier; resp[uuid.ToString()] = object_data; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 986a665dad..f6e501de11 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -467,8 +467,8 @@ namespace OpenSim.Region.ClientStack.Linden responsedata["content_type"] = "text/plain"; responsedata["keepalive"] = false; responsedata["reusecontext"] = false; - responsedata["str_response_string"] = "Upstream error: "; - responsedata["error_status_text"] = "Upstream error:"; + responsedata["str_response_string"] = ""; + responsedata["error_status_text"] = ""; responsedata["http_protocol_version"] = "HTTP/1.0"; return responsedata; } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index 191bccf812..6ef8815026 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs @@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.Linden // private static readonly ILog m_log = // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest; + private Scene m_scene; /// @@ -94,6 +96,8 @@ namespace OpenSim.Region.ClientStack.Linden { m_scene = s; m_scene.EventManager.OnRegisterCaps += RegisterCaps; + + m_scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene s) @@ -156,7 +160,7 @@ namespace OpenSim.Region.ClientStack.Linden IRequestHandler reqHandler = new RestHTTPHandler( "GET", "/CAPS/" + UUID.Random(), - HandleSimulatorFeaturesRequest, "SimulatorFeatures", agentID.ToString()); + x => { return HandleSimulatorFeaturesRequest(x, agentID); }, "SimulatorFeatures", agentID.ToString()); caps.RegisterHandler("SimulatorFeatures", reqHandler); } @@ -185,18 +189,33 @@ namespace OpenSim.Region.ClientStack.Linden return new OSDMap(m_features); } - private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod) + private OSDMap DeepCopy() + { + // This isn't the cheapest way of doing this but the rate + // of occurrence is low (on sim entry only) and it's a sure + // way to get a true deep copy. + OSD copy = OSDParser.DeserializeLLSDXml(OSDParser.SerializeLLSDXmlString(m_features)); + + return (OSDMap)copy; + } + + private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod, UUID agentID) { // m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); + OSDMap copy = DeepCopy(); + + SimulatorFeaturesRequestDelegate handlerOnSimulatorFeaturesRequest = OnSimulatorFeaturesRequest; + if (handlerOnSimulatorFeaturesRequest != null) + handlerOnSimulatorFeaturesRequest(agentID, ref copy); + //Send back data Hashtable responsedata = new Hashtable(); responsedata["int_response_code"] = 200; responsedata["content_type"] = "text/plain"; responsedata["keepalive"] = false; - lock (m_features) - responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(m_features); + responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(copy); return responsedata; } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs index 6bed95f369..eca576dd76 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs @@ -190,8 +190,15 @@ namespace OpenSim.Region.ClientStack.Linden { if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) { - cacheItems[i].TextureID = - textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID; + Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; + if (face == null) + { + textureEntry.CreateFace(cacheItems[i].TextureIndex); + textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = + AppearanceManager.DEFAULT_AVATAR_TEXTURE; + continue; + } + cacheItems[i].TextureID =face.TextureID; if (m_scene.AssetService != null) cacheItems[i].TextureAsset = m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); @@ -213,8 +220,16 @@ namespace OpenSim.Region.ClientStack.Linden { if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) { + Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; + if (face == null) + { + textureEntry.CreateFace(cacheItems[i].TextureIndex); + textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = + AppearanceManager.DEFAULT_AVATAR_TEXTURE; + continue; + } cacheItems[i].TextureID = - textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID; + face.TextureID; } else { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 04cd4748af..707cc93472 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -39,10 +39,13 @@ using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Framework.Capabilities; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; using OpenSim.Capabilities.Handlers; using OpenSim.Framework.Monitoring; +using OpenMetaverse; +using OpenMetaverse.StructuredData; namespace OpenSim.Region.ClientStack.Linden { @@ -52,11 +55,13 @@ namespace OpenSim.Region.ClientStack.Linden [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] public class WebFetchInvDescModule : INonSharedRegionModule { - struct aPollRequest + class aPollRequest { public PollServiceInventoryEventArgs thepoll; public UUID reqID; public Hashtable request; + public ScenePresence presence; + public List folders; } private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -71,8 +76,8 @@ namespace OpenSim.Region.ClientStack.Linden private Dictionary m_capsDict = new Dictionary(); private static Thread[] m_workerThreads = null; - private static OpenMetaverse.BlockingQueue m_queue = - new OpenMetaverse.BlockingQueue(); + private static DoubleQueue m_queue = + new DoubleQueue(); #region ISharedRegionModule Members @@ -143,12 +148,18 @@ namespace OpenSim.Region.ClientStack.Linden private class PollServiceInventoryEventArgs : PollServiceEventArgs { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private Dictionary responses = new Dictionary(); - public PollServiceInventoryEventArgs(UUID pId) : + private Scene m_scene; + + public PollServiceInventoryEventArgs(Scene scene, UUID pId) : base(null, null, null, null, pId, int.MaxValue) { + m_scene = scene; + HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; GetEvents = (x, y) => { @@ -167,12 +178,68 @@ namespace OpenSim.Region.ClientStack.Linden Request = (x, y) => { + ScenePresence sp = m_scene.GetScenePresence(Id); + if (sp == null) + { + m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id); + return; + } + aPollRequest reqinfo = new aPollRequest(); reqinfo.thepoll = this; reqinfo.reqID = x; reqinfo.request = y; + reqinfo.presence = sp; + reqinfo.folders = new List(); - m_queue.Enqueue(reqinfo); + // Decode the request here + string request = y["body"].ToString(); + + request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); + + request = request.Replace("fetch_folders0", "fetch_folders0"); + request = request.Replace("fetch_folders1", "fetch_folders1"); + + Hashtable hash = new Hashtable(); + try + { + hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); + } + catch (LLSD.LLSDParseException e) + { + m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace); + m_log.Error("Request: " + request); + return; + } + catch (System.Xml.XmlException) + { + m_log.ErrorFormat("[INVENTORY]: XML Format error"); + } + + ArrayList foldersrequested = (ArrayList)hash["folders"]; + + bool highPriority = false; + + for (int i = 0; i < foldersrequested.Count; i++) + { + Hashtable inventoryhash = (Hashtable)foldersrequested[i]; + string folder = inventoryhash["folder_id"].ToString(); + UUID folderID; + if (UUID.TryParse(folder, out folderID)) + { + if (!reqinfo.folders.Contains(folderID)) + { + if (sp.COF != UUID.Zero && sp.COF == folderID) + highPriority = true; + reqinfo.folders.Add(folderID); + } + } + } + + if (highPriority) + m_queue.EnqueueHigh(reqinfo); + else + m_queue.EnqueueLow(reqinfo); }; NoEvents = (x, y) => @@ -208,7 +275,7 @@ namespace OpenSim.Region.ClientStack.Linden response["reusecontext"] = false; response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest( - requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); + requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); lock (responses) responses[requestID] = response; @@ -220,7 +287,7 @@ namespace OpenSim.Region.ClientStack.Linden string capUrl = "/CAPS/" + UUID.Random() + "/"; // Register this as a poll service - PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(agentID); + PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); args.Type = PollServiceEventArgs.EventType.Inventory; MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index fd82db703b..03888287fe 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -2654,7 +2654,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte physshapetype = part.PhysicsShapeType; float density = part.Density; float friction = part.Friction; - float bounce = part.Bounciness; + float bounce = part.Restitution; float gravmod = part.GravityModifier; eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); @@ -3893,6 +3893,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP part.Shape.LightEntry = false; } } + + if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) + { + // Ensure that mesh has at least 8 valid faces + part.Shape.ProfileBegin = 12500; + part.Shape.ProfileEnd = 0; + part.Shape.ProfileHollow = 27500; + } } ++updatesThisCall; @@ -4952,6 +4960,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset; rotation = part.RotationOffset * presence.Rotation; } + angularVelocity = Vector3.Zero; + } + else + { + angularVelocity = presence.AngularVelocity; + rotation = presence.Rotation; } attachPoint = 0; @@ -4963,9 +4977,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // in that direction, even though we don't model this on the server. Implementing this in the future // may improve movement smoothness. // acceleration = new Vector3(1, 0, 0); - - angularVelocity = Vector3.Zero; - + if (sendTexture) textureEntry = presence.Appearance.Texture.GetBytes(); else diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index da1ccb3eab..df763968b0 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1903,112 +1903,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } } - - internal class DoubleQueue where T:class - { - private Queue m_lowQueue = new Queue(); - private Queue m_highQueue = new Queue(); - - private object m_syncRoot = new object(); - private Semaphore m_s = new Semaphore(0, 1); - - public DoubleQueue() - { - } - - public virtual int Count - { - get { return m_highQueue.Count + m_lowQueue.Count; } - } - - public virtual void Enqueue(T data) - { - Enqueue(m_lowQueue, data); - } - - public virtual void EnqueueLow(T data) - { - Enqueue(m_lowQueue, data); - } - - public virtual void EnqueueHigh(T data) - { - Enqueue(m_highQueue, data); - } - - private void Enqueue(Queue q, T data) - { - lock (m_syncRoot) - { - m_lowQueue.Enqueue(data); - m_s.WaitOne(0); - m_s.Release(); - } - } - - public virtual T Dequeue() - { - return Dequeue(Timeout.Infinite); - } - - public virtual T Dequeue(int tmo) - { - return Dequeue(TimeSpan.FromMilliseconds(tmo)); - } - - public virtual T Dequeue(TimeSpan wait) - { - T res = null; - - if (!Dequeue(wait, ref res)) - return null; - - return res; - } - - public bool Dequeue(int timeout, ref T res) - { - return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); - } - - public bool Dequeue(TimeSpan wait, ref T res) - { - if (!m_s.WaitOne(wait)) - return false; - - lock (m_syncRoot) - { - if (m_highQueue.Count > 0) - res = m_highQueue.Dequeue(); - else - res = m_lowQueue.Dequeue(); - - if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) - return true; - - try - { - m_s.Release(); - } - catch - { - } - - return true; - } - } - - public virtual void Clear() - { - - lock (m_syncRoot) - { - // Make sure sem count is 0 - m_s.WaitOne(0); - - m_lowQueue.Clear(); - m_highQueue.Clear(); - } - } - } } diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs index 0aa46931fb..e13f479a96 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs @@ -260,10 +260,10 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction { CompleteTaskItemUpdate(m_updateTaskItemData); } -// else if (m_storeLocal) -// { -// m_Scene.AssetService.Store(m_asset); -// } + else if (m_asset.Local) + { + m_Scene.AssetService.Store(m_asset); + } } m_log.DebugFormat( @@ -339,7 +339,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction // to avoid a race condition when the appearance module retrieves the item to set the asset id in // the AvatarAppearance structure. item.AssetID = m_asset.FullID; - m_Scene.InventoryService.UpdateItem(item); + if (item.AssetID != UUID.Zero) + m_Scene.InventoryService.UpdateItem(item); if (m_uploadState == UploadState.Complete) { @@ -390,6 +391,11 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction // m_asset.FullID, item.Name, ourClient.Name); m_Scene.AssetService.Store(m_asset); + if (m_asset.FullID != UUID.Zero) + { + item.AssetID = m_asset.FullID; + m_Scene.InventoryService.UpdateItem(item); + } m_transactions.RemoveXferUploader(m_transactionID); } diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index a0f1e8c560..ec388f40cc 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -369,7 +369,7 @@ namespace OpenSim.Region.CoreModules.Asset AssetBase asset = null; string filename = GetFileName(id); - if (File.Exists(filename)) + while (File.Exists(filename)) { FileStream stream = null; try @@ -380,6 +380,8 @@ namespace OpenSim.Region.CoreModules.Asset asset = (AssetBase)bformatter.Deserialize(stream); m_DiskHits++; + + break; } catch (System.Runtime.Serialization.SerializationException e) { @@ -392,12 +394,24 @@ namespace OpenSim.Region.CoreModules.Asset // {different version of AssetBase} -- we should attempt to // delete it and re-cache File.Delete(filename); + + break; + } + catch (IOException e) + { + // This is a sharing violation: File exists but can't be opened because it's + // being written + Thread.Sleep(100); + + continue; } catch (Exception e) { m_log.ErrorFormat( "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", filename, id, e.Message, e.StackTrace); + + break; } finally { diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index acd156e855..7cc5092594 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -236,9 +236,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // If we're an NPC then skip all the item checks and manipulations since we don't have an // inventory right now. if (sp.PresenceType == PresenceType.Npc) - RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null); + RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null, true); else - RezSingleAttachmentFromInventory(sp, attach.ItemID, p, d); + RezSingleAttachmentFromInventory(sp, attach.ItemID, p | (uint)0x80, d); } catch (Exception e) { @@ -284,12 +284,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments sp.ClearAttachments(); } - public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) + public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp, bool append) { if (!Enabled) return false; - if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp)) + if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp, append)) { m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID); return true; @@ -298,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return false; } - private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) + private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp, bool append) { lock (sp.AttachmentsSyncLock) { @@ -326,10 +326,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments Vector3 attachPos = group.AbsolutePosition; - // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should - // be removed when that functionality is implemented in opensim - attachmentPt &= 0x7f; - // If the attachment point isn't the same as the one previously used // set it's offset position = 0 so that it appears on the attachment point // and not in a weird location somewhere unknown. @@ -375,7 +371,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments group.AbsolutePosition = attachPos; if (sp.PresenceType != PresenceType.Npc) - UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp); + UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append); AttachToAgent(sp, group, attachmentPt, attachPos, silent); } @@ -383,21 +379,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return true; } - private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp) + private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp, bool append) { - // Remove any previous attachments List attachments = sp.GetAttachments(attachmentPt); - // At the moment we can only deal with a single attachment - if (attachments.Count != 0) + // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones + while (attachments.Count >= 5) { if (attachments[0].FromItemID != UUID.Zero) DetachSingleAttachmentToInvInternal(sp, attachments[0]); - // Error logging commented because UUID.Zero now means temp attachment -// else -// m_log.WarnFormat( -// "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!", -// attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name); + attachments.RemoveAt(0); + } + + // If we're not appending, remove the rest as well + if (attachments.Count != 0 && !append) + { + foreach (SceneObjectGroup g in attachments) + { + if (g.FromItemID != UUID.Zero) + DetachSingleAttachmentToInvInternal(sp, g); + } } // Add the new attachment to inventory if we don't already have it. @@ -407,7 +408,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (newAttachmentItemID == UUID.Zero) newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID; - ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); + ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group, append); } } @@ -425,8 +426,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", // (AttachmentPoint)AttachmentPt, itemID, sp.Name); - // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should - // be removed when that functionality is implemented in opensim + bool append = (AttachmentPt & 0x80) != 0; AttachmentPt &= 0x7f; // Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such). @@ -455,7 +455,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return null; } - return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc); + return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc, append); } public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List> rezlist) @@ -847,7 +847,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( - IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc) + IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc, bool append) { if (m_invAccessModule == null) return null; @@ -885,7 +885,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // This will throw if the attachment fails try { - AttachObjectInternal(sp, objatt, attachmentPt, false, false, false); + AttachObjectInternal(sp, objatt, attachmentPt, false, false, false, append); } catch (Exception e) { @@ -936,7 +936,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// /// - private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) + private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att, bool append) { // m_log.DebugFormat( // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", @@ -959,7 +959,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (item == null) return; - bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); + int attFlag = append ? 0x80 : 0; + bool changed = sp.Appearance.SetAttachment((int)AttachmentPt | attFlag, itemID, item.AssetID); if (changed && m_scene.AvatarFactory != null) { // m_log.DebugFormat( @@ -1043,12 +1044,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return; } - // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should - // be removed when that functionality is implemented in opensim + bool append = (AttachmentPt & 0x80) != 0; AttachmentPt &= 0x7f; // Calls attach with a Zero position - if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true, false)) + if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true, false, append)) { // m_log.Debug( // "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 4e9d3f9e57..545aedaa20 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -197,7 +197,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); m_numberOfAttachEventsFired = 0; - scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false); + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false, false); // Check status on scene presence Assert.That(sp.HasAttachments(), Is.True); @@ -254,7 +254,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests sp2.AbsolutePosition = new Vector3(0, 0, 0); sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); - scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false); + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false, false); Assert.That(sp.HasAttachments(), Is.False); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 7ec28605c1..1adff7e6aa 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -674,26 +674,70 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) { IInventoryService invService = m_scene.InventoryService; - + bool resetwearable = false; if (invService.GetRootFolder(userID) != null) { for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) { for (int j = 0; j < appearance.Wearables[i].Count; j++) { + // Check if the default wearables are not set if (appearance.Wearables[i][j].ItemID == UUID.Zero) - continue; + { + switch ((WearableType) i) + { + case WearableType.Eyes: + case WearableType.Hair: + case WearableType.Shape: + case WearableType.Skin: + //case WearableType.Underpants: + TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); + resetwearable = true; + m_log.Warn("[AVFACTORY]: UUID.Zero Wearables, passing fake values."); + resetwearable = true; + break; - // Ignore ruth's assets + } + continue; + } + + // Ignore ruth's assets except for the body parts! missing body parts fail avatar appearance on V1 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) - continue; + { + switch ((WearableType)i) + { + case WearableType.Eyes: + case WearableType.Hair: + case WearableType.Shape: + case WearableType.Skin: + //case WearableType.Underpants: + TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); + + m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i); + resetwearable = true; + break; + } + continue; + } + InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); baseItem = invService.GetItem(baseItem); if (baseItem != null) { appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID); + int unmodifiedWearableIndexForClosure = i; + m_scene.AssetService.Get(baseItem.AssetID.ToString(), this, + delegate(string x, object y, AssetBase z) + { + if (z == null) + { + TryAndRepairBrokenWearable( + (WearableType)unmodifiedWearableIndexForClosure, invService, + userID, appearance); + } + }); } else { @@ -701,17 +745,236 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", appearance.Wearables[i][j].ItemID, (WearableType)i); - appearance.Wearables[i].RemoveItem(appearance.Wearables[i][j].ItemID); + TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); + resetwearable = true; + } } } + + // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... + if (appearance.Wearables[(int) WearableType.Eyes] == null) + { + m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes)); + + TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance); + resetwearable = true; + } + else + { + if (appearance.Wearables[(int) WearableType.Eyes][0].ItemID == UUID.Zero) + { + m_log.WarnFormat("[AVFACTORY]: Eyes are UUID.Zero are broken, {0} {1}", + appearance.Wearables[(int) WearableType.Eyes][0].ItemID, + appearance.Wearables[(int) WearableType.Eyes][0].AssetID); + TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance); + resetwearable = true; + + } + + } + // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... + if (appearance.Wearables[(int)WearableType.Shape] == null) + { + m_log.WarnFormat("[AVFACTORY]: {0} shape is Null, passing existing values.", (WearableType.Shape)); + + TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance); + resetwearable = true; + } + else + { + if (appearance.Wearables[(int)WearableType.Shape][0].ItemID == UUID.Zero) + { + m_log.WarnFormat("[AVFACTORY]: Shape is UUID.Zero and broken, {0} {1}", + appearance.Wearables[(int)WearableType.Shape][0].ItemID, + appearance.Wearables[(int)WearableType.Shape][0].AssetID); + TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance); + resetwearable = true; + + } + + } + // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... + if (appearance.Wearables[(int)WearableType.Hair] == null) + { + m_log.WarnFormat("[AVFACTORY]: {0} Hair is Null, passing existing values.", (WearableType.Hair)); + + TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance); + resetwearable = true; + } + else + { + if (appearance.Wearables[(int)WearableType.Hair][0].ItemID == UUID.Zero) + { + m_log.WarnFormat("[AVFACTORY]: Hair is UUID.Zero and broken, {0} {1}", + appearance.Wearables[(int)WearableType.Hair][0].ItemID, + appearance.Wearables[(int)WearableType.Hair][0].AssetID); + TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance); + resetwearable = true; + + } + + } + // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... + if (appearance.Wearables[(int)WearableType.Skin] == null) + { + m_log.WarnFormat("[AVFACTORY]: {0} Skin is Null, passing existing values.", (WearableType.Skin)); + + TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance); + resetwearable = true; + } + else + { + if (appearance.Wearables[(int)WearableType.Skin][0].ItemID == UUID.Zero) + { + m_log.WarnFormat("[AVFACTORY]: Skin is UUID.Zero and broken, {0} {1}", + appearance.Wearables[(int)WearableType.Skin][0].ItemID, + appearance.Wearables[(int)WearableType.Skin][0].AssetID); + TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance); + resetwearable = true; + + } + + } + if (resetwearable) + { + ScenePresence presence = null; + if (m_scene.TryGetScenePresence(userID, out presence)) + { + presence.ControllingClient.SendWearables(presence.Appearance.Wearables, + presence.Appearance.Serial++); + } + } + } else { m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); } } + private void TryAndRepairBrokenWearable(WearableType type, IInventoryService invService, UUID userID,AvatarAppearance appearance) + { + UUID defaultwearable = GetDefaultItem(type); + if (defaultwearable != UUID.Zero) + { + UUID newInvItem = UUID.Random(); + InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID) + { + AssetID = + defaultwearable, + AssetType + = + (int) + AssetType + .Bodypart, + CreatorId + = + userID + .ToString + (), + //InvType = (int)InventoryType.Wearable, + Description + = + "Failed Wearable Replacement", + Folder = + invService + .GetFolderForType + (userID, + AssetType + .Bodypart) + .ID, + Flags = (uint) type, + Name = Enum.GetName(typeof (WearableType), type), + BasePermissions = (uint) PermissionMask.Copy, + CurrentPermissions = (uint) PermissionMask.Copy, + EveryOnePermissions = (uint) PermissionMask.Copy, + GroupPermissions = (uint) PermissionMask.Copy, + NextPermissions = (uint) PermissionMask.Copy + }; + invService.AddItem(itembase); + UUID LinkInvItem = UUID.Random(); + itembase = new InventoryItemBase(LinkInvItem, userID) + { + AssetID = + newInvItem, + AssetType + = + (int) + AssetType + .Link, + CreatorId + = + userID + .ToString + (), + InvType = (int) InventoryType.Wearable, + + Description + = + "Failed Wearable Replacement", + Folder = + invService + .GetFolderForType + (userID, + AssetType + .CurrentOutfitFolder) + .ID, + Flags = (uint) type, + Name = Enum.GetName(typeof (WearableType), type), + BasePermissions = (uint) PermissionMask.Copy, + CurrentPermissions = (uint) PermissionMask.Copy, + EveryOnePermissions = (uint) PermissionMask.Copy, + GroupPermissions = (uint) PermissionMask.Copy, + NextPermissions = (uint) PermissionMask.Copy + }; + invService.AddItem(itembase); + appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type)); + ScenePresence presence = null; + if (m_scene.TryGetScenePresence(userID, out presence)) + { + m_scene.SendInventoryUpdate(presence.ControllingClient, + invService.GetFolderForType(userID, + AssetType + .CurrentOutfitFolder), + false, true); + } + } + } + private UUID GetDefaultItem(WearableType wearable) + { + // These are ruth + UUID ret = UUID.Zero; + switch (wearable) + { + case WearableType.Eyes: + ret = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7"); + break; + case WearableType.Hair: + ret = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66"); + break; + case WearableType.Pants: + ret = new UUID("00000000-38f9-1111-024e-222222111120"); + break; + case WearableType.Shape: + ret = new UUID("66c41e39-38f9-f75a-024e-585989bfab73"); + break; + case WearableType.Shirt: + ret = new UUID("00000000-38f9-1111-024e-222222111110"); + break; + case WearableType.Skin: + ret = new UUID("77c41e39-38f9-f75a-024e-585989bbabbb"); + break; + case WearableType.Undershirt: + ret = new UUID("16499ebb-3208-ec27-2def-481881728f47"); + break; + case WearableType.Underpants: + ret = new UUID("4ac2e9c7-3671-d229-316a-67717730841d"); + break; + } + + return ret; + } #endregion #region Client Event Handlers diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index 7f30e5a35a..2eb9bfb7c1 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.Framework /// /// Each agent has its own capabilities handler. /// - protected Dictionary m_capsObjects = new Dictionary(); + protected Dictionary m_capsObjects = new Dictionary(); protected Dictionary capsPaths = new Dictionary(); protected Dictionary> childrenSeeds @@ -100,7 +100,7 @@ namespace OpenSim.Region.CoreModules.Framework get { return null; } } - public void CreateCaps(UUID agentId) + public void CreateCaps(UUID agentId, uint circuitCode) { int flags = m_scene.GetUserFlags(agentId); if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags)) @@ -108,9 +108,9 @@ namespace OpenSim.Region.CoreModules.Framework String capsObjectPath = GetCapsPath(agentId); - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - Caps oldCaps = m_capsObjects[agentId]; + Caps oldCaps = m_capsObjects[circuitCode]; m_log.DebugFormat( "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", @@ -125,12 +125,12 @@ namespace OpenSim.Region.CoreModules.Framework (MainServer.Instance == null) ? 0: MainServer.Instance.Port, capsObjectPath, agentId, m_scene.RegionInfo.RegionName); - m_capsObjects[agentId] = caps; + m_capsObjects[circuitCode] = caps; m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); } - public void RemoveCaps(UUID agentId) + public void RemoveCaps(UUID agentId, uint circuitCode) { if (childrenSeeds.ContainsKey(agentId)) { @@ -139,11 +139,11 @@ namespace OpenSim.Region.CoreModules.Framework lock (m_capsObjects) { - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - m_capsObjects[agentId].DeregisterHandlers(); - m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[agentId]); - m_capsObjects.Remove(agentId); + m_capsObjects[circuitCode].DeregisterHandlers(); + m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[circuitCode]); + m_capsObjects.Remove(circuitCode); } else { @@ -154,19 +154,30 @@ namespace OpenSim.Region.CoreModules.Framework } } - public Caps GetCapsForUser(UUID agentId) + public Caps GetCapsForUser(uint circuitCode) { lock (m_capsObjects) { - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - return m_capsObjects[agentId]; + return m_capsObjects[circuitCode]; } } return null; } + public void ActivateCaps(uint circuitCode) + { + lock (m_capsObjects) + { + if (m_capsObjects.ContainsKey(circuitCode)) + { + m_capsObjects[circuitCode].Activate(); + } + } + } + public void SetAgentCapsSeeds(AgentCircuitData agent) { capsPaths[agent.AgentID] = agent.CapsPath; @@ -237,9 +248,9 @@ namespace OpenSim.Region.CoreModules.Framework StringBuilder caps = new StringBuilder(); caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); - foreach (KeyValuePair kvp in m_capsObjects) + foreach (KeyValuePair kvp in m_capsObjects) { - caps.AppendFormat("** User {0}:\n", kvp.Key); + caps.AppendFormat("** Circuit {0}:\n", kvp.Key); for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); ) { diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index cb09047ad8..ac4d93d790 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -150,7 +150,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { client.OnTeleportHomeRequest += TriggerTeleportHome; client.OnTeleportLandmarkRequest += RequestTeleportLandmark; - client.OnTeleportCancel += TeleportCancel; } public virtual void Close() {} @@ -995,11 +994,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return neighbourRegion; } - private void TeleportCancel(IClientAPI remoteClient) - { - m_entityTransferStateMachine.ResetFromTransit(remoteClient.AgentId); - } - public bool Cross(ScenePresence agent, bool isFlying) { uint x; diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index da59eabff1..24e925e42e 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -50,6 +50,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public string url; public UUID urlcode; public Dictionary requests; + public bool isSsl; } public class RequestData @@ -184,6 +185,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp urlData.engine = engine; urlData.url = url; urlData.urlcode = urlcode; + urlData.isSsl = false; urlData.requests = new Dictionary(); m_UrlMap[url] = urlData; @@ -229,6 +231,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp urlData.engine = engine; urlData.url = url; urlData.urlcode = urlcode; + urlData.isSsl = true; urlData.requests = new Dictionary(); @@ -394,7 +397,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp private void RemoveUrl(UrlData data) { - m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); + if (data.isSsl) + m_HttpsServer.RemoveHTTPHandler("", "/lslhttps/"+data.urlcode.ToString()+"/"); + else + m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); } private Hashtable NoEvents(UUID requestID, UUID sessionID) diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs index f6e1d393a8..f697c242c8 100644 --- a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs @@ -262,6 +262,8 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms return "modInvokeR"; else if (sid.ReturnType == typeof(object[])) return "modInvokeL"; + else if (sid.ReturnType == typeof(void)) + return "modInvokeN"; m_log.WarnFormat("[MODULE COMMANDS] failed to find match for {0} with return type {1}",fname,sid.ReturnType.Name); } diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index d781eae887..eaaf7a3b40 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -84,7 +84,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// true if the object was successfully attached, false otherwise - bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool temp); + bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool temp, bool append); /// /// Rez an attachment from user inventory and change inventory status to match. diff --git a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs index 522c82d40f..30d404e020 100644 --- a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs @@ -40,19 +40,19 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - void CreateCaps(UUID agentId); + void CreateCaps(UUID agentId, uint circuitCode); /// /// Remove the caps handler for a given agent. /// /// - void RemoveCaps(UUID agentId); + void RemoveCaps(UUID agentId, uint circuitCode); /// /// Will return null if the agent doesn't have a caps handler registered /// /// - Caps GetCapsForUser(UUID agentId); + Caps GetCapsForUser(uint circuitCode); void SetAgentCapsSeeds(AgentCircuitData agent); @@ -65,5 +65,7 @@ namespace OpenSim.Region.Framework.Interfaces void DropChildSeed(UUID agentID, ulong handle); string GetCapsPath(UUID agentId); + + void ActivateCaps(uint circuitCode); } } diff --git a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs index 8cef14e932..6effcc1d5c 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs @@ -26,18 +26,22 @@ */ using System; +using OpenMetaverse; using OpenMetaverse.StructuredData; namespace OpenSim.Region.Framework.Interfaces { + public delegate void SimulatorFeaturesRequestDelegate(UUID agentID, ref OSDMap features); + /// /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability. /// public interface ISimulatorFeaturesModule { + event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest; void AddFeature(string name, OSD value); bool RemoveFeature(string name); bool TryGetFeature(string name, out OSD value); OSDMap GetFeatures(); } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index 5cfba39452..b102e48861 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -22,6 +22,115 @@ using log4net; namespace OpenSim.Region.Framework.Scenes { + public class KeyframeTimer + { + private static Dictionarym_timers = + new Dictionary(); + + private Timer m_timer; + private Dictionary m_motions = new Dictionary(); + private object m_lockObject = new object(); + private object m_timerLock = new object(); + private const double m_tickDuration = 50.0; + private Scene m_scene; + + public double TickDuration + { + get { return m_tickDuration; } + } + + public KeyframeTimer(Scene scene) + { + m_timer = new Timer(); + m_timer.Interval = TickDuration; + m_timer.AutoReset = true; + m_timer.Elapsed += OnTimer; + + m_scene = scene; + + m_timer.Start(); + } + + private void OnTimer(object sender, ElapsedEventArgs ea) + { + if (!Monitor.TryEnter(m_timerLock)) + return; + + try + { + List motions; + + lock (m_lockObject) + { + motions = new List(m_motions.Keys); + } + + foreach (KeyframeMotion m in motions) + { + try + { + m.OnTimer(TickDuration); + } + catch (Exception inner) + { + // Don't stop processing + } + } + } + catch (Exception e) + { + // Keep running no matter what + } + finally + { + Monitor.Exit(m_timerLock); + } + } + + public static void Add(KeyframeMotion motion) + { + KeyframeTimer timer; + + if (motion.Scene == null) + return; + + lock (m_timers) + { + if (!m_timers.TryGetValue(motion.Scene, out timer)) + { + timer = new KeyframeTimer(motion.Scene); + m_timers[motion.Scene] = timer; + } + } + + lock (timer.m_lockObject) + { + timer.m_motions[motion] = null; + } + } + + public static void Remove(KeyframeMotion motion) + { + KeyframeTimer timer; + + if (motion.Scene == null) + return; + + lock (m_timers) + { + if (!m_timers.TryGetValue(motion.Scene, out timer)) + { + return; + } + } + + lock (timer.m_lockObject) + { + timer.m_motions.Remove(motion); + } + } + } + [Serializable] public class KeyframeMotion { @@ -63,18 +172,6 @@ namespace OpenSim.Region.Framework.Scenes private Keyframe[] m_keyframes; - [NonSerialized()] - protected Timer m_timer = null; - - // timer lock - [NonSerialized()] - private object m_onTimerLock; - - // timer overrun detect - // prevents overlap or timer events threads frozen on the lock - [NonSerialized()] - private bool m_inOnTimer; - // skip timer events. //timer.stop doesn't assure there aren't event threads still being fired [NonSerialized()] @@ -97,12 +194,21 @@ namespace OpenSim.Region.Framework.Scenes private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation; private bool m_running = false; + [NonSerialized()] private bool m_selected = false; private int m_iterations = 0; - private const double timerInterval = 50.0; + private int m_skipLoops = 0; + + [NonSerialized()] + private Scene m_scene; + + public Scene Scene + { + get { return m_scene; } + } public DataFormat Data { @@ -139,31 +245,16 @@ namespace OpenSim.Region.Framework.Scenes private void StartTimer() { - if (m_timer == null) - return; + KeyframeTimer.Add(this); m_timerStopped = false; - m_timer.Start(); } private void StopTimer() { - if (m_timer == null || m_timerStopped) - return; m_timerStopped = true; - m_timer.Stop(); + KeyframeTimer.Remove(this); } - private void RemoveTimer() - { - if (m_timer == null) - return; - m_timerStopped = true; - m_timer.Stop(); - m_timer.Elapsed -= OnTimer; - m_timer = null; - } - - public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) { KeyframeMotion newMotion = null; @@ -177,12 +268,15 @@ namespace OpenSim.Region.Framework.Scenes newMotion.m_group = grp; - if (grp != null && grp.IsSelected) - newMotion.m_selected = true; + if (grp != null) + { + newMotion.m_scene = grp.Scene; + if (grp.IsSelected) + newMotion.m_selected = true; + } - newMotion.m_onTimerLock = new object(); newMotion.m_timerStopped = false; - newMotion.m_inOnTimer = false; + newMotion.m_running = true; newMotion.m_isCrossing = false; newMotion.m_waitingCrossing = false; } @@ -196,37 +290,36 @@ namespace OpenSim.Region.Framework.Scenes public void UpdateSceneObject(SceneObjectGroup grp) { -// lock (m_onTimerLock) + m_isCrossing = false; + m_waitingCrossing = false; + StopTimer(); + + if (grp == null) + return; + + m_group = grp; + m_scene = grp.Scene; + + Vector3 grppos = grp.AbsolutePosition; + Vector3 offset = grppos - m_serializedPosition; + // avoid doing it more than once + // current this will happen draging a prim to other region + m_serializedPosition = grppos; + + m_basePosition += offset; + m_currentFrame.Position += offset; + + m_nextPosition += offset; + + for (int i = 0; i < m_frames.Count; i++) { - m_isCrossing = false; - m_waitingCrossing = false; - StopTimer(); - - if (grp == null) - return; - - m_group = grp; - Vector3 grppos = grp.AbsolutePosition; - Vector3 offset = grppos - m_serializedPosition; - // avoid doing it more than once - // current this will happen draging a prim to other region - m_serializedPosition = grppos; - - m_basePosition += offset; - m_currentFrame.Position += offset; - - m_nextPosition += offset; - - for (int i = 0; i < m_frames.Count; i++) - { - Keyframe k = m_frames[i]; - k.Position += offset; - m_frames[i]=k; - } - - if (m_running) - Start(); + Keyframe k = m_frames[i]; + k.Position += offset; + m_frames[i]=k; } + + if (m_running) + Start(); } public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data) @@ -239,11 +332,10 @@ namespace OpenSim.Region.Framework.Scenes { m_basePosition = grp.AbsolutePosition; m_baseRotation = grp.GroupRotation; + m_scene = grp.Scene; } - m_onTimerLock = new object(); m_timerStopped = true; - m_inOnTimer = false; m_isCrossing = false; m_waitingCrossing = false; } @@ -260,6 +352,7 @@ namespace OpenSim.Region.Framework.Scenes KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data); newmotion.m_group = newgrp; + newmotion.m_scene = newgrp.Scene; if (m_keyframes != null) { @@ -296,7 +389,7 @@ namespace OpenSim.Region.Framework.Scenes public void Delete() { m_running = false; - RemoveTimer(); + StopTimer(); m_isCrossing = false; m_waitingCrossing = false; m_frames.Clear(); @@ -309,27 +402,13 @@ namespace OpenSim.Region.Framework.Scenes m_waitingCrossing = false; if (m_keyframes != null && m_group != null && m_keyframes.Length > 0) { - if (m_timer == null) - { - m_timer = new Timer(); - m_timer.Interval = timerInterval; - m_timer.AutoReset = true; - m_timer.Elapsed += OnTimer; - } - else - { - StopTimer(); - m_timer.Interval = timerInterval; - } - - m_inOnTimer = false; StartTimer(); m_running = true; } else { m_running = false; - RemoveTimer(); + StopTimer(); } } @@ -339,7 +418,7 @@ namespace OpenSim.Region.Framework.Scenes m_isCrossing = false; m_waitingCrossing = false; - RemoveTimer(); + StopTimer(); m_basePosition = m_group.AbsolutePosition; m_baseRotation = m_group.GroupRotation; @@ -354,7 +433,7 @@ namespace OpenSim.Region.Framework.Scenes public void Pause() { m_running = false; - RemoveTimer(); + StopTimer(); m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.AngularVelocity = Vector3.Zero; @@ -377,15 +456,11 @@ namespace OpenSim.Region.Framework.Scenes int start = 0; int end = m_keyframes.Length; -// if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1) -// end = m_keyframes.Length - 1; if (direction < 0) { start = m_keyframes.Length - 1; end = -1; -// if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1) -// end = 0; } for (int i = start; i != end ; i += direction) @@ -463,189 +538,172 @@ namespace OpenSim.Region.Framework.Scenes } } - protected void OnTimer(object sender, ElapsedEventArgs e) + public void OnTimer(double tickDuration) { - if (m_timerStopped) // trap events still in air even after a timer.stop - return; - - if (m_inOnTimer) // don't let overruns to happen + if (m_skipLoops > 0) { - m_log.Warn("[KeyFrame]: timer overrun"); + m_skipLoops--; return; } + if (m_timerStopped) // trap events still in air even after a timer.stop + return; + if (m_group == null) return; - lock (m_onTimerLock) + bool update = false; + + if (m_selected) { - - m_inOnTimer = true; - - bool update = false; - - try + if (m_group.RootPart.Velocity != Vector3.Zero) { - if (m_selected) - { - if (m_group.RootPart.Velocity != Vector3.Zero) - { - m_group.RootPart.Velocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); -// m_group.RootPart.ScheduleTerseUpdate(); + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); - } - m_inOnTimer = false; - return; + } + return; + } + + if (m_isCrossing) + { + // if crossing and timer running then cross failed + // wait some time then + // retry to set the position that evtually caused the outbound + // if still outside region this will call startCrossing below + m_isCrossing = false; + m_group.AbsolutePosition = m_nextPosition; + if (!m_isCrossing) + { + StopTimer(); + StartTimer(); + } + return; + } + + if (m_frames.Count == 0) + { + GetNextList(); + + if (m_frames.Count == 0) + { + Stop(); + Scene scene = m_group.Scene; + + IScriptModule[] scriptModules = scene.RequestModuleInterfaces(); + foreach (IScriptModule m in scriptModules) + { + if (m == null) + continue; + m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]); } - if (m_isCrossing) + return; + } + + m_currentFrame = m_frames[0]; + m_currentFrame.TimeMS += (int)tickDuration; + + //force a update on a keyframe transition + update = true; + } + + m_currentFrame.TimeMS -= (int)tickDuration; + + // Do the frame processing + double steps = (double)m_currentFrame.TimeMS / tickDuration; + + if (steps <= 0.0) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.RootPart.AngularVelocity = Vector3.Zero; + + m_nextPosition = (Vector3)m_currentFrame.Position; + m_group.AbsolutePosition = m_nextPosition; + + // we are sending imediate updates, no doing force a extra terseUpdate + // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); + + m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; + m_frames.RemoveAt(0); + if (m_frames.Count > 0) + m_currentFrame = m_frames[0]; + + update = true; + } + else + { + float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; + + Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; + Vector3 motionThisFrame = v / (float)steps; + v = v * 1000 / m_currentFrame.TimeMS; + + if (Vector3.Mag(motionThisFrame) >= 0.05f) + { + // m_group.AbsolutePosition += motionThisFrame; + m_nextPosition = m_group.AbsolutePosition + motionThisFrame; + m_group.AbsolutePosition = m_nextPosition; + + m_group.RootPart.Velocity = v; + update = true; + } + + if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) + { + Quaternion current = m_group.GroupRotation; + + Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); + step.Normalize(); +/* use simpler change detection +* float angle = 0; + + float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; + float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; + float aa_bb = aa * bb; + + if (aa_bb == 0) { - // if crossing and timer running then cross failed - // wait some time then - // retry to set the position that evtually caused the outbound - // if still outside region this will call startCrossing below - m_isCrossing = false; - m_group.AbsolutePosition = m_nextPosition; - if (!m_isCrossing) - { - StopTimer(); - m_timer.Interval = timerInterval; - StartTimer(); - } - m_inOnTimer = false; - return; - } - - if (m_frames.Count == 0) - { - GetNextList(); - - if (m_frames.Count == 0) - { - Stop(); - m_inOnTimer = false; - return; - } - - m_currentFrame = m_frames[0]; - m_currentFrame.TimeMS += (int)timerInterval; - - //force a update on a keyframe transition - update = true; - } - - m_currentFrame.TimeMS -= (int)timerInterval; - - // Do the frame processing - double steps = (double)m_currentFrame.TimeMS / timerInterval; - - if (steps <= 0.0) - { - m_group.RootPart.Velocity = Vector3.Zero; - m_group.RootPart.AngularVelocity = Vector3.Zero; - - m_nextPosition = (Vector3)m_currentFrame.Position; - m_group.AbsolutePosition = m_nextPosition; - - // we are sending imediate updates, no doing force a extra terseUpdate -// m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); - - m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; - m_frames.RemoveAt(0); - if (m_frames.Count > 0) - m_currentFrame = m_frames[0]; - - update = true; + angle = 0; } else { - float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; + float ab = current.X * step.X + + current.Y * step.Y + + current.Z * step.Z + + current.W * step.W; + float q = (ab * ab) / aa_bb; - Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; - Vector3 motionThisFrame = v / (float)steps; - v = v * 1000 / m_currentFrame.TimeMS; - - if (Vector3.Mag(motionThisFrame) >= 0.05f) + if (q > 1.0f) { - // m_group.AbsolutePosition += motionThisFrame; - m_nextPosition = m_group.AbsolutePosition + motionThisFrame; - m_group.AbsolutePosition = m_nextPosition; - - m_group.RootPart.Velocity = v; - update = true; + angle = 0; } - - if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) + else { - Quaternion current = m_group.GroupRotation; - - Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); - step.Normalize(); -/* use simpler change detection - * float angle = 0; - - float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; - float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; - float aa_bb = aa * bb; - - if (aa_bb == 0) - { - angle = 0; - } - else - { - float ab = current.X * step.X + - current.Y * step.Y + - current.Z * step.Z + - current.W * step.W; - float q = (ab * ab) / aa_bb; - - if (q > 1.0f) - { - angle = 0; - } - else - { - angle = (float)Math.Acos(2 * q - 1); - } - } - - if (angle > 0.01f) - */ - if(Math.Abs(step.X - current.X) > 0.001f - || Math.Abs(step.Y - current.Y) > 0.001f - || Math.Abs(step.Z - current.Z) > 0.001f) - // assuming w is a dependente var - - { -// m_group.UpdateGroupRotationR(step); - m_group.RootPart.RotationOffset = step; - - //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); - update = true; - } + angle = (float)Math.Acos(2 * q - 1); } } - if (update) - m_group.SendGroupRootTerseUpdate(); -// m_group.RootPart.ScheduleTerseUpdate(); + if (angle > 0.01f) +*/ + if(Math.Abs(step.X - current.X) > 0.001f + || Math.Abs(step.Y - current.Y) > 0.001f + || Math.Abs(step.Z - current.Z) > 0.001f) + // assuming w is a dependente var + { +// m_group.UpdateGroupRotationR(step); + m_group.RootPart.RotationOffset = step; + //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); + update = true; + } } - catch ( Exception ex) - { - // still happening sometimes - // lets try to see where - m_log.Warn("[KeyFrame]: timer overrun" + ex.Message); - } + } - finally - { - // make sure we do not let this frozen - m_inOnTimer = false; - } + if (update) + { + m_group.SendGroupRootTerseUpdate(); } } @@ -677,7 +735,7 @@ namespace OpenSim.Region.Framework.Scenes m_isCrossing = true; m_waitingCrossing = true; -// to remove / retune to smoth crossings + // to remove / retune to smoth crossings if (m_group.RootPart.Velocity != Vector3.Zero) { m_group.RootPart.Velocity = Vector3.Zero; @@ -696,9 +754,10 @@ namespace OpenSim.Region.Framework.Scenes m_group.SendGroupRootTerseUpdate(); // m_group.RootPart.ScheduleTerseUpdate(); - if (m_running && m_timer != null) + if (m_running) { - m_timer.Interval = 60000; + StopTimer(); + m_skipLoops = 1200; // 60 seconds StartTimer(); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index c9d1205484..4130029b33 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -401,17 +401,17 @@ namespace OpenSim.Region.Framework.Scenes if (item.Owner != remoteClient.AgentId) return; - if (UUID.Zero == transactionID) - { - item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255); - item.Name = itemUpd.Name; - item.Description = itemUpd.Description; + item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255); + item.Name = itemUpd.Name; + item.Description = itemUpd.Description; // m_log.DebugFormat( // "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}", // itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags, // item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions); + if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid + { if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions)) item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner; item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions; @@ -446,7 +446,8 @@ namespace OpenSim.Region.Framework.Scenes InventoryService.UpdateItem(item); } - else + + if (UUID.Zero != transactionID) { if (AgentTransactionsModule != null) { diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e3bc8c7b36..2e64819920 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2769,8 +2769,6 @@ namespace OpenSim.Region.Framework.Scenes if (newPosition != Vector3.Zero) newObject.RootPart.GroupPosition = newPosition; - if (newObject.RootPart.KeyframeMotion != null) - newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject); if (!AddSceneObject(newObject)) { @@ -2798,6 +2796,9 @@ namespace OpenSim.Region.Framework.Scenes // before we restart the scripts, or else some functions won't work. newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); newObject.ResumeScripts(); + + if (newObject.RootPart.KeyframeMotion != null) + newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject); } // Do this as late as possible so that listeners have full access to the incoming object @@ -2865,7 +2866,7 @@ namespace OpenSim.Region.Framework.Scenes RootPrim.RemFlag(PrimFlags.TemporaryOnRez); if (AttachmentsModule != null) - AttachmentsModule.AttachObject(sp, grp, 0, false, false, false); + AttachmentsModule.AttachObject(sp, grp, 0, false, false, false, true); } else { @@ -2970,6 +2971,13 @@ namespace OpenSim.Region.Framework.Scenes SubscribeToClientEvents(client); sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); + InventoryFolderBase cof = InventoryService.GetFolderForType(client.AgentId, (AssetType)46); + if (cof == null) + sp.COF = UUID.Zero; + else + sp.COF = cof.ID; + + m_log.DebugFormat("[SCENE]: COF for {0} is {1}", client.AgentId, sp.COF); m_eventManager.TriggerOnNewPresence(sp); sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; @@ -3615,7 +3623,7 @@ namespace OpenSim.Region.Framework.Scenes // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI if (closeChildAgents && CapsModule != null) - CapsModule.RemoveCaps(agentID); + CapsModule.RemoveCaps(agentID, avatar.ControllingClient.CircuitCode); // // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever // // this method is doing is HORRIBLE!!! @@ -3846,20 +3854,36 @@ namespace OpenSim.Region.Framework.Scenes return false; } - ScenePresence sp = GetScenePresence(agent.AgentID); - if (sp != null && !sp.IsChildAgent) + // If we have noo presence here or if that presence is a zombie root + // presence that will be kicled, we need a new CAPS object. + if (sp == null || (sp != null && !sp.IsChildAgent)) { - // We have a zombie from a crashed session. - // Or the same user is trying to be root twice here, won't work. - // Kill it. - m_log.WarnFormat( - "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", - sp.Name, sp.UUID, RegionInfo.RegionName); + if (CapsModule != null) + { + lock (agent) + { + CapsModule.SetAgentCapsSeeds(agent); + CapsModule.CreateCaps(agent.AgentID, agent.circuitcode); + } + } + } - sp.ControllingClient.Close(true, true); - sp = null; + if (sp != null) + { + if (!sp.IsChildAgent) + { + // We have a zombie from a crashed session. + // Or the same user is trying to be root twice here, won't work. + // Kill it. + m_log.WarnFormat( + "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", + sp.Name, sp.UUID, RegionInfo.RegionName); + + sp.ControllingClient.Close(true, true); + sp = null; + } } lock (agent) @@ -3900,7 +3924,9 @@ namespace OpenSim.Region.Framework.Scenes if (vialogin || (!m_seeIntoBannedRegion)) { if (!AuthorizeUser(agent, out reason)) + { return false; + } } } catch (Exception e) @@ -3915,11 +3941,6 @@ namespace OpenSim.Region.Framework.Scenes RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, agent.AgentID, agent.circuitcode); - if (CapsModule != null) - { - CapsModule.SetAgentCapsSeeds(agent); - CapsModule.CreateCaps(agent.AgentID); - } } else { @@ -3945,6 +3966,11 @@ namespace OpenSim.Region.Framework.Scenes agent.teleportFlags = teleportFlags; m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); + if (CapsModule != null) + { + CapsModule.ActivateCaps(agent.circuitcode); + } + if (vialogin) { // CleanDroppedAttachments(); @@ -5122,7 +5148,7 @@ namespace OpenSim.Region.Framework.Scenes { if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) { - if (grp.RootPart.Expires <= DateTime.Now) + if (grp.GetSittingAvatarsCount() == 0 && grp.RootPart.Expires <= DateTime.Now) DeleteSceneObject(grp, false); } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 8528edc616..20a662683e 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1689,6 +1689,10 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup != null) ParentGroup.HasGroupChanged = true; + + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Density = Density; } } @@ -1708,6 +1712,9 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup != null) ParentGroup.HasGroupChanged = true; + PhysicsActor pa = PhysActor; + if (pa != null) + pa.GravModifier = GravityModifier; } } @@ -1726,10 +1733,14 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup != null) ParentGroup.HasGroupChanged = true; + + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Friction = Friction; } } - public float Bounciness + public float Restitution { get { return m_bounce; } set @@ -1744,6 +1755,10 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup != null) ParentGroup.HasGroupChanged = true; + + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Restitution = Restitution; } } @@ -4493,8 +4508,8 @@ namespace OpenSim.Region.Framework.Scenes GravityModifier = physdata.GravitationModifier; if(Friction != physdata.Friction) Friction = physdata.Friction; - if(Bounciness != physdata.Bounce) - Bounciness = physdata.Bounce; + if(Restitution != physdata.Bounce) + Restitution = physdata.Bounce; } /// /// Update the flags on this prim. This covers properties such as phantom, physics and temporary. @@ -4657,6 +4672,11 @@ namespace OpenSim.Region.Framework.Scenes pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info pa.SetMaterial(Material); + pa.Density = Density; + pa.GravModifier = GravityModifier; + pa.Friction = Friction; + pa.Restitution = Restitution; + if (VolumeDetectActive) // change if not the default only pa.SetVolumeDetect(1); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index a9195f72fe..230cb23b96 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -204,6 +204,11 @@ namespace OpenSim.Region.Framework.Scenes private const int LAND_VELOCITYMAG_MAX = 12; + private const float FLY_ROLL_MAX_RADIANS = 1.1f; + + private const float FLY_ROLL_RADIANS_PER_UPDATE = 0.06f; + private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f; + private float m_health = 100f; protected ulong crossingFromRegion; @@ -438,6 +443,8 @@ namespace OpenSim.Region.Framework.Scenes get { return (IClientCore)ControllingClient; } } + public UUID COF { get; set; } + // public Vector3 ParentPosition { get; set; } /// @@ -606,6 +613,14 @@ namespace OpenSim.Region.Framework.Scenes } } + // Used for limited viewer 'fake' user rotations. + private Vector3 m_AngularVelocity = Vector3.Zero; + + public Vector3 AngularVelocity + { + get { return m_AngularVelocity; } + } + public bool IsChildAgent { get; set; } public bool IsLoggingIn { get; set; } @@ -736,6 +751,8 @@ namespace OpenSim.Region.Framework.Scenes #endregion + + #region Constructor(s) public ScenePresence( @@ -1225,6 +1242,85 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.StopFlying(this); } + /// + /// Applies a roll accumulator to the avatar's angular velocity for the avatar fly roll effect. + /// + /// Postive or negative roll amount in radians + private void ApplyFlyingRoll(float amount, bool PressingUp, bool PressingDown) + { + + float rollAmount = Util.Clamp(m_AngularVelocity.Z + amount, -FLY_ROLL_MAX_RADIANS, FLY_ROLL_MAX_RADIANS); + m_AngularVelocity.Z = rollAmount; + + // APPLY EXTRA consideration for flying up and flying down during this time. + // if we're turning left + if (amount > 0) + { + + // If we're at the max roll and pressing up, we want to swing BACK a bit + // Automatically adds noise + if (PressingUp) + { + if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS - 0.04f) + m_AngularVelocity.Z -= 0.9f; + } + // If we're at the max roll and pressing down, we want to swing MORE a bit + if (PressingDown) + { + if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS && m_AngularVelocity.Z < FLY_ROLL_MAX_RADIANS + 0.6f) + m_AngularVelocity.Z += 0.6f; + } + } + else // we're turning right. + { + // If we're at the max roll and pressing up, we want to swing BACK a bit + // Automatically adds noise + if (PressingUp) + { + if (m_AngularVelocity.Z <= (-FLY_ROLL_MAX_RADIANS)) + m_AngularVelocity.Z += 0.6f; + } + // If we're at the max roll and pressing down, we want to swing MORE a bit + if (PressingDown) + { + if (m_AngularVelocity.Z >= -FLY_ROLL_MAX_RADIANS - 0.6f) + m_AngularVelocity.Z -= 0.6f; + } + } + } + + /// + /// incrementally sets roll amount to zero + /// + /// Positive roll amount in radians + /// + private float CalculateFlyingRollResetToZero(float amount) + { + const float rollMinRadians = 0f; + + if (m_AngularVelocity.Z > 0) + { + + float leftOverToMin = m_AngularVelocity.Z - rollMinRadians; + if (amount > leftOverToMin) + return -leftOverToMin; + else + return -amount; + + } + else + { + + float leftOverToMin = -m_AngularVelocity.Z - rollMinRadians; + if (amount > leftOverToMin) + return leftOverToMin; + else + return amount; + } + } + + + // neighbouring regions we have enabled a child agent in // holds the seed cap for the child agent in that region private Dictionary m_knownChildRegions = new Dictionary(); @@ -1430,17 +1526,42 @@ namespace OpenSim.Region.Framework.Scenes m_doingCamRayCast = false; if (hitYN && localid != LocalId) { - CameraConstraintActive = true; - pNormal.X = (float)Math.Round(pNormal.X, 2); - pNormal.Y = (float)Math.Round(pNormal.Y, 2); - pNormal.Z = (float)Math.Round(pNormal.Z, 2); - pNormal.Normalize(); - collisionPoint.X = (float)Math.Round(collisionPoint.X, 1); - collisionPoint.Y = (float)Math.Round(collisionPoint.Y, 1); - collisionPoint.Z = (float)Math.Round(collisionPoint.Z, 1); + SceneObjectGroup group = m_scene.GetGroupByPrim(localid); + bool IsPrim = group != null; + if (IsPrim) + { + SceneObjectPart part = group.GetPart(localid); + if (part != null && !part.VolumeDetectActive) + { + CameraConstraintActive = true; + pNormal.X = (float) Math.Round(pNormal.X, 2); + pNormal.Y = (float) Math.Round(pNormal.Y, 2); + pNormal.Z = (float) Math.Round(pNormal.Z, 2); + pNormal.Normalize(); + collisionPoint.X = (float) Math.Round(collisionPoint.X, 1); + collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1); + collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1); - Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z, Vector3.Dot(collisionPoint, pNormal)); - UpdateCameraCollisionPlane(plane); + Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z, + Vector3.Dot(collisionPoint, pNormal)); + UpdateCameraCollisionPlane(plane); + } + } + else + { + CameraConstraintActive = true; + pNormal.X = (float) Math.Round(pNormal.X, 2); + pNormal.Y = (float) Math.Round(pNormal.Y, 2); + pNormal.Z = (float) Math.Round(pNormal.Z, 2); + pNormal.Normalize(); + collisionPoint.X = (float) Math.Round(collisionPoint.X, 1); + collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1); + collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1); + + Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z, + Vector3.Dot(collisionPoint, pNormal)); + UpdateCameraCollisionPlane(plane); + } } else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) @@ -1741,6 +1862,33 @@ namespace OpenSim.Region.Framework.Scenes bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); + + //m_log.Debug("[CONTROL]: " +flags); + // Applies a satisfying roll effect to the avatar when flying. + if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0) && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)) + { + + ApplyFlyingRoll(FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0)); + + + } + else if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0) && + ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)) + { + ApplyFlyingRoll(-FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0)); + + + } + else + { + if (m_AngularVelocity.Z != 0) + m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); + + } + + + + if (Flying && IsColliding && controlland) { // nesting this check because LengthSquared() is expensive and we don't diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 123c158e2c..2984782bf1 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -633,7 +633,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessBounce(SceneObjectPart obj, XmlTextReader reader) { - obj.Bounciness = reader.ReadElementContentAsFloat("Bounce", String.Empty); + obj.Restitution = reader.ReadElementContentAsFloat("Bounce", String.Empty); } private static void ProcessGravityModifier(SceneObjectPart obj, XmlTextReader reader) @@ -1363,8 +1363,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("Density", sop.Density.ToString().ToLower()); if (sop.Friction != 0.6f) writer.WriteElementString("Friction", sop.Friction.ToString().ToLower()); - if (sop.Bounciness != 0.5f) - writer.WriteElementString("Bounce", sop.Bounciness.ToString().ToLower()); + if (sop.Restitution != 0.5f) + writer.WriteElementString("Bounce", sop.Restitution.ToString().ToLower()); if (sop.GravityModifier != 1.0f) writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower()); WriteVector(writer, "CameraEyeOffset", sop.GetCameraEyeOffset()); diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs index 17971e3a58..0b28edd909 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs @@ -183,7 +183,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments hostPart.ParentGroup.RootPart.ScheduleFullUpdate(); } - return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true, true) ? 1 : 0; + return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true, true, true) ? 1 : 0; } } } diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 9338130400..dcb2c91b8d 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -274,7 +274,7 @@ namespace OpenSim.Region.Physics.Manager public virtual float Density { get; set; } public virtual float GravModifier { get; set; } public virtual float Friction { get; set; } - public virtual float Bounce { get; set; } + public virtual float Restitution { get; set; } /// /// Position of this actor. diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs index f7e4c1cca1..bea34d42b5 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs @@ -1014,8 +1014,8 @@ namespace OpenSim.Region.Physics.OdePlugin offset.Y += contact.pos.Y; offset.Z += contact.pos.Z; - _position = offset; - return false; + //_position = offset; + //return false; } offset.X = contact.pos.X - _position.X; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 53c6e5cf20..7be64ebdbd 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -3332,7 +3332,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; if (attachmentsModule != null) - return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, false); + return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, false, true); else return false; } @@ -4724,7 +4724,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID av = new UUID(); if (!UUID.TryParse(agent,out av)) { - //LSLError("First parameter to llDialog needs to be a key"); return; } @@ -7222,20 +7221,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } if (buttons.Length > 12) { - LSLError("No more than 12 buttons can be shown"); - return; + ShoutError("button list too long, must be 12 or fewer entries"); } - string[] buts = new string[buttons.Length]; - for (int i = 0; i < buttons.Length; i++) + int length = buttons.Length; + if (length > 12) + length = 12; + + string[] buts = new string[length]; + for (int i = 0; i < length; i++) { if (buttons.Data[i].ToString() == String.Empty) { - LSLError("button label cannot be blank"); + ShoutError("button label cannot be blank"); return; } if (buttons.Data[i].ToString().Length > 24) { - llWhisper(ScriptBaseClass.DEBUG_CHANNEL, "button label cannot be longer than 24 characters"); + ShoutError("button label cannot be longer than 24 characters"); return; } buts[i] = buttons.Data[i].ToString(); @@ -7843,7 +7845,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api physdata.PhysShapeType = (PhysShapeType)part.PhysicsShapeType; physdata.Density = part.Density; physdata.Friction = part.Friction; - physdata.Bounce = part.Bounciness; + physdata.Bounce = part.Restitution; physdata.GravitationModifier = part.GravityModifier; if ((material_bits & (int)ScriptBaseClass.DENSITY) != 0) @@ -8236,7 +8238,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ExtraPhysicsData physdata = new ExtraPhysicsData(); physdata.Density = part.Density; - physdata.Bounce = part.Bounciness; + physdata.Bounce = part.Restitution; physdata.GravitationModifier = part.GravityModifier; physdata.PhysShapeType = (PhysShapeType)shape_type; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 8f348332b6..ee89f9d21a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -123,7 +123,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void modInvokeN(string fname, params object[] parms) { Type returntype = m_comms.LookupReturnType(fname); - if (returntype != typeof(string)) + if (returntype != typeof(void)) MODError(String.Format("return type mismatch for {0}",fname)); modInvoke(fname,parms); @@ -264,6 +264,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (result != null) return result; + Type returntype = m_comms.LookupReturnType(fname); + if (returntype == typeof(void)) + return null; + MODError(String.Format("Invocation of {0} failed; null return value",fname)); } catch (Exception e) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 7c2f8edbca..8aac33f4cc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -1619,7 +1619,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - public Object osParseJSONNew(string JSON) + private Object osParseJSONNew(string JSON) { CheckThreatLevel(ThreatLevel.None, "osParseJSONNew"); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index c447d1f6e3..8aa12497ae 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -259,7 +259,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces string osGetScriptEngineName(); string osGetSimulatorVersion(); - Object osParseJSONNew(string JSON); Hashtable osParseJSON(string JSON); void osMessageObject(key objectUUID,string message); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index afa9ae0431..95dff180e2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -430,11 +430,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osParseJSON(JSON); } - public Object osParseJSONNew(string JSON) - { - return m_OSSL_Functions.osParseJSONNew(JSON); - } - public void osMessageObject(key objectUUID,string message) { m_OSSL_Functions.osMessageObject(objectUUID,message); diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index c9c4753195..c6393ed554 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -512,7 +512,7 @@ namespace OpenSim.Region.ScriptEngine.Shared else if (o is LSL_Types.LSLFloat) size += 8; else if (o is LSL_Types.LSLString) - size += ((LSL_Types.LSLString)o).m_string.Length; + size += ((LSL_Types.LSLString)o).m_string == null ? 0 : ((LSL_Types.LSLString)o).m_string.Length; else if (o is LSL_Types.key) size += ((LSL_Types.key)o).value.Length; else if (o is LSL_Types.Vector3) diff --git a/OpenSim/Services/Interfaces/IAvatarService.cs b/OpenSim/Services/Interfaces/IAvatarService.cs index c0130f139b..3663a7a896 100644 --- a/OpenSim/Services/Interfaces/IAvatarService.cs +++ b/OpenSim/Services/Interfaces/IAvatarService.cs @@ -180,11 +180,18 @@ namespace OpenSim.Services.Interfaces // Attachments List attachments = appearance.GetAttachments(); + Dictionary> atts = new Dictionary>(); foreach (AvatarAttachment attach in attachments) { if (attach.ItemID != UUID.Zero) - Data["_ap_" + attach.AttachPoint] = attach.ItemID.ToString(); + { + if (!atts.ContainsKey(attach.AttachPoint)) + atts[attach.AttachPoint] = new List(); + atts[attach.AttachPoint].Add(attach.ItemID.ToString()); + } } + foreach (KeyValuePair> kvp in atts) + Data["_ap_" + kvp.Key] = string.Join(",", kvp.Value.ToArray()); } public AvatarAppearance ToAvatarAppearance() @@ -320,10 +327,16 @@ namespace OpenSim.Services.Interfaces if (!Int32.TryParse(pointStr, out point)) continue; - UUID uuid = UUID.Zero; - UUID.TryParse(_kvp.Value, out uuid); + List idList = new List(_kvp.Value.Split(new char[] {','})); - appearance.SetAttachment(point, uuid, UUID.Zero); + appearance.SetAttachment(point, UUID.Zero, UUID.Zero); + foreach (string id in idList) + { + UUID uuid = UUID.Zero; + UUID.TryParse(id, out uuid); + + appearance.SetAttachment(point | 0x80, uuid, UUID.Zero); + } } if (appearance.Wearables[AvatarWearable.BODY].Count == 0) diff --git a/prebuild.xml b/prebuild.xml index dc00d40dc6..90450cff72 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1597,9 +1597,10 @@ + - +