diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index c5d7c47856..3db30d8647 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -1403,7 +1403,10 @@ namespace OpenSim.Data.MySQL prim.Sound = DBGuid.FromDB(row["LoopedSound"].ToString()); prim.SoundGain = (float)(double)row["LoopedSoundGain"]; - prim.SoundFlags = 1; // If it's persisted at all, it's looped + if (prim.Sound != UUID.Zero) + prim.SoundFlags = 1; // If it's persisted at all, it's looped + else + prim.SoundFlags = 0; if (!(row["TextureAnimation"] is DBNull)) prim.TextureAnimation = (byte[])row["TextureAnimation"]; diff --git a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs index 569cc806a0..99ceb914e9 100755 --- a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs +++ b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs @@ -1742,7 +1742,10 @@ namespace OpenSim.Data.PGSQL prim.Sound = new UUID((Guid)primRow["LoopedSound"]); prim.SoundGain = Convert.ToSingle(primRow["LoopedSoundGain"]); - prim.SoundFlags = 1; // If it's persisted at all, it's looped + if (prim.Sound != UUID.Zero) + prim.SoundFlags = 1; // If it's persisted at all, it's looped + else + prim.SoundFlags = 0; if (!(primRow["TextureAnimation"] is DBNull)) prim.TextureAnimation = (Byte[])primRow["TextureAnimation"]; diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index e02ac7df2c..1403a8f8e5 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -1742,7 +1742,10 @@ namespace OpenSim.Data.SQLite prim.Sound = new UUID(row["LoopedSound"].ToString()); prim.SoundGain = Convert.ToSingle(row["LoopedSoundGain"]); - prim.SoundFlags = 1; // If it's persisted at all, it's looped + if (prim.Sound != UUID.Zero) + prim.SoundFlags = 1; // If it's persisted at all, it's looped + else + prim.SoundFlags = 0; if (!row.IsNull("TextureAnimation")) prim.TextureAnimation = Convert.FromBase64String(row["TextureAnimation"].ToString()); diff --git a/OpenSim/Framework/ClientManager.cs b/OpenSim/Framework/ClientManager.cs index 45c54e4989..1508c7f505 100644 --- a/OpenSim/Framework/ClientManager.cs +++ b/OpenSim/Framework/ClientManager.cs @@ -51,7 +51,14 @@ namespace OpenSim.Framework private object m_syncRoot = new object(); /// Number of clients in the collection - public int Count { get { return m_dict1.Count; } } + public int Count + { + get + { + lock (m_syncRoot) + return m_dict1.Count; + } + } /// /// Default constructor @@ -60,7 +67,7 @@ namespace OpenSim.Framework { m_dict1 = new Dictionary(); m_dict2 = new Dictionary(); - m_array = new IClientAPI[0]; + m_array = null; } /// @@ -74,17 +81,9 @@ namespace OpenSim.Framework { lock (m_syncRoot) { - // allow self healing -// if (m_dict1.ContainsKey(value.AgentId) || m_dict2.ContainsKey(value.RemoteEndPoint)) -// return false; - m_dict1[value.AgentId] = value; m_dict2[value.RemoteEndPoint] = value; - - // dict1 is the master - IClientAPI[] newArray = new IClientAPI[m_dict1.Count]; - m_dict1.Values.CopyTo(newArray, 0); - m_array = newArray; + m_array = null; } return true; @@ -105,10 +104,7 @@ namespace OpenSim.Framework { m_dict1.Remove(key); m_dict2.Remove(value.RemoteEndPoint); - - IClientAPI[] newArray = new IClientAPI[m_dict1.Count]; - m_dict1.Values.CopyTo(newArray, 0); - m_array = newArray; + m_array = null; return true; } } @@ -124,7 +120,7 @@ namespace OpenSim.Framework { m_dict1.Clear(); m_dict2.Clear(); - m_array = new IClientAPI[0]; + m_array = null; } } @@ -135,7 +131,8 @@ namespace OpenSim.Framework /// True if the UUID was found in the collection, otherwise false public bool ContainsKey(UUID key) { - return m_dict1.ContainsKey(key); + lock (m_syncRoot) + return m_dict1.ContainsKey(key); } /// @@ -145,7 +142,8 @@ namespace OpenSim.Framework /// True if the endpoint was found in the collection, otherwise false public bool ContainsKey(IPEndPoint key) { - return m_dict2.ContainsKey(key); + lock (m_syncRoot) + return m_dict2.ContainsKey(key); } /// @@ -156,8 +154,12 @@ namespace OpenSim.Framework /// True if the lookup succeeded, otherwise false public bool TryGetValue(UUID key, out IClientAPI value) { - try { return m_dict1.TryGetValue(key, out value); } - catch (Exception) + try + { + lock (m_syncRoot) + return m_dict1.TryGetValue(key, out value); + } + catch { value = null; return false; @@ -172,8 +174,12 @@ namespace OpenSim.Framework /// True if the lookup succeeded, otherwise false public bool TryGetValue(IPEndPoint key, out IClientAPI value) { - try { return m_dict2.TryGetValue(key, out value); } - catch (Exception) + try + { + lock (m_syncRoot) + return m_dict2.TryGetValue(key, out value); + } + catch { value = null; return false; @@ -187,7 +193,20 @@ namespace OpenSim.Framework /// Action to perform on each element public void ForEach(Action action) { - IClientAPI[] localArray = m_array; + IClientAPI[] localArray; + lock (m_syncRoot) + { + if (m_array == null) + { + if (m_dict1.Count == 0) + return; + + m_array = new IClientAPI[m_dict1.Count]; + m_dict1.Values.CopyTo(m_array, 0); + } + localArray = m_array; + } + for (int i = 0; i < localArray.Length; i++) action(localArray[i]); } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 307dbf3917..d63136e332 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -390,7 +390,7 @@ namespace OpenSim.Framework IClientAPI remoteClient, UUID invoice, UUID senderID, bool scripted, bool collisionEvents, bool physics); public delegate void EstateTeleportOneUserHomeRequest( - IClientAPI remoteClient, UUID invoice, UUID senderID, UUID prey); + IClientAPI remoteClient, UUID invoice, UUID senderID, UUID prey, bool kill); public delegate void EstateTeleportAllUsersHomeRequest(IClientAPI remoteClient, UUID invoice, UUID senderID); @@ -671,7 +671,6 @@ namespace OpenSim.Framework Particles = 1 << 19, ExtraData = 1 << 20, Sound = 1 << 21, - Joint = 1 << 22, TerseUpdate = Position | Rotation | Velocity | Acceleration | AngularVelocity, FullUpdate = 0x00ffffff, diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs old mode 100644 new mode 100755 index b9ac155401..14e21a2167 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -230,25 +230,25 @@ namespace OpenSim.Framework.Servers.HttpServer PollServiceHttpRequest req; while (m_running) { - req = null; - if(!m_requests.TryTake(out req, 4500) || req == null) - { - Watchdog.UpdateThread(); - continue; - } - - Watchdog.UpdateThread(); - try { - if(!req.HttpContext.CanSend()) + req = null; + if (!m_requests.TryTake(out req, 4500) || req == null) + { + Watchdog.UpdateThread(); + continue; + } + + Watchdog.UpdateThread(); + + if (!req.HttpContext.CanSend()) { req.PollServiceArgs.Drop(req.RequestID, req.PollServiceArgs.Id); byContextDequeue(req); continue; } - if(req.HttpContext.IsSending()) + if (req.HttpContext.IsSending()) { if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) { @@ -256,7 +256,7 @@ namespace OpenSim.Framework.Servers.HttpServer byContextDequeue(req); } else - ReQueueEvent(req); + ReQueueEvent(req); continue; } @@ -290,7 +290,7 @@ namespace OpenSim.Framework.Servers.HttpServer { nreq.DoHTTPGruntWork(nreq.PollServiceArgs.NoEvents(nreq.RequestID, nreq.PollServiceArgs.Id)); } - catch (ObjectDisposedException) {} + catch (ObjectDisposedException) { } finally { byContextDequeue(nreq); @@ -305,6 +305,12 @@ namespace OpenSim.Framework.Servers.HttpServer } } } + catch (ThreadAbortException) + { + Thread.ResetAbort(); + // Shouldn't set this to 'false', the normal shutdown should cause things to exit + // m_running = false; + } catch (Exception e) { m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs index 5604628d95..1a2d5d1e5f 100644 --- a/OpenSim/Framework/TerrainData.cs +++ b/OpenSim/Framework/TerrainData.cs @@ -212,7 +212,6 @@ namespace OpenSim.Framework return heights; } - // TerrainData.GetDoubles public double[,] GetDoubles() { double[,] ret = new double[SizeX, SizeY]; diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 52f9aeab2b..f66a98736d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2437,34 +2437,6 @@ namespace OpenSim.Framework #region FireAndForget Threading Pattern - /// - /// Created to work around a limitation in Mono with nested delegates - /// - private sealed class FireAndForgetWrapper - { - private static object syncRoot = new Object(); - - public void FireAndForget(System.Threading.WaitCallback callback) - { - callback.BeginInvoke(null, EndFireAndForget, callback); - } - - public void FireAndForget(System.Threading.WaitCallback callback, object obj) - { - callback.BeginInvoke(obj, EndFireAndForget, callback); - } - - private static void EndFireAndForget(IAsyncResult ar) - { - System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; - - try { callback.EndInvoke(ar); } - catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } - - ar.AsyncWaitHandle.Close(); - } - } - public static void InitThreadPool(int minThreads, int maxThreads) { if (maxThreads < 2) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs old mode 100644 new mode 100755 index 9187979903..c071bd1847 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs @@ -59,7 +59,7 @@ namespace OpenSim.Region.ClientStack.Linden private string m_GetTextureURL; private string m_GetMeshURL; private string m_GetMesh2URL; -// private string m_GetAssetURL; + private string m_GetAssetURL; class APollRequest { @@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.Linden private Dictionary m_capsDictTexture = new Dictionary(); private Dictionary m_capsDictGetMesh = new Dictionary(); private Dictionary m_capsDictGetMesh2 = new Dictionary(); - //private Dictionary m_capsDictGetAsset = new Dictionary(); + private Dictionary m_capsDictGetAsset = new Dictionary(); #region Region Module interfaceBase Members @@ -113,11 +113,11 @@ namespace OpenSim.Region.ClientStack.Linden m_GetMesh2URL = config.GetString("Cap_GetMesh2", string.Empty); if (m_GetMesh2URL != string.Empty) m_Enabled = true; -/* + m_GetAssetURL = config.GetString("Cap_GetAsset", string.Empty); if (m_GetAssetURL != string.Empty) m_Enabled = true; -*/ + } public void AddRegion(Scene pScene) @@ -204,19 +204,26 @@ namespace OpenSim.Region.ClientStack.Linden private static void DoAssetRequests() { - while (m_NumberScenes > 0) + try { - APollRequest poolreq; - if(m_queue.TryTake(out poolreq, 4500)) + while (m_NumberScenes > 0) { - if (m_NumberScenes <= 0) - break; + APollRequest poolreq; + if (m_queue.TryTake(out poolreq, 4500)) + { + if (m_NumberScenes <= 0) + break; + Watchdog.UpdateThread(); + if (poolreq.reqID != UUID.Zero) + poolreq.thepoll.Process(poolreq); + poolreq = null; + } Watchdog.UpdateThread(); - if (poolreq.reqID != UUID.Zero) - poolreq.thepoll.Process(poolreq); - poolreq = null; } - Watchdog.UpdateThread(); + } + catch (ThreadAbortException) + { + Thread.ResetAbort(); } } @@ -441,7 +448,6 @@ namespace OpenSim.Region.ClientStack.Linden else if (m_GetMesh2URL != string.Empty) caps.RegisterHandler("GetMesh2", m_GetMesh2URL); -/* we can't support this cap. Current viewers connect to the wrong regions. //ViewerAsset if (m_GetAssetURL == "localhost") { @@ -459,7 +465,7 @@ namespace OpenSim.Region.ClientStack.Linden } else if (m_GetAssetURL != string.Empty) caps.RegisterHandler("ViewerAsset", m_GetMesh2URL); -*/ + } private void DeregisterCaps(UUID agentID, Caps caps) @@ -480,13 +486,12 @@ namespace OpenSim.Region.ClientStack.Linden MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); m_capsDictGetMesh2.Remove(agentID); } -/* + if (m_capsDictGetAsset.TryGetValue(agentID, out capUrl)) { MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); m_capsDictGetAsset.Remove(agentID); } -*/ } } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs old mode 100644 new mode 100755 index 41d70a3ab9..9a01567064 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -395,17 +395,26 @@ namespace OpenSim.Region.ClientStack.Linden private static void DoInventoryRequests() { - while (true) + bool running = true; + while (running) { - APollRequest poolreq; - if (m_queue.TryTake(out poolreq, 4500)) + try { + APollRequest poolreq; + if (m_queue.TryTake(out poolreq, 4500)) + { + Watchdog.UpdateThread(); + if (poolreq.thepoll != null) + poolreq.thepoll.Process(poolreq); + poolreq = null; + } Watchdog.UpdateThread(); - if (poolreq.thepoll != null) - poolreq.thepoll.Process(poolreq); - poolreq = null; } - Watchdog.UpdateThread(); + catch (ThreadAbortException) + { + Thread.ResetAbort(); + running = false; + } } } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index b7d5a80dfd..ac041f500b 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -1257,6 +1257,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP SendLayerTopRight(x1 + 1, y1, x2, y2 - 1); } + static private readonly byte[] TerrainPacketHeader = new byte[] { + Helpers.MSG_RELIABLE, // zero code is not as spec + 0, 0, 0, 0, // sequence number + 0, // extra + 11, // ID (high frequency) + }; + + private const int END_OF_PATCHES = 97; + private const int STRIDE = 264; + public void SendLayerData(int[] map) { if(map == null) @@ -1264,9 +1274,75 @@ namespace OpenSim.Region.ClientStack.LindenUDP try { - List packets = OpenSimTerrainCompressor.CreateLayerDataPackets(m_scene.Heightmap.GetTerrainData(), map); - foreach (LayerDataPacket pkt in packets) - OutPacket(pkt, ThrottleOutPacketType.Land); + TerrainData terrData = m_scene.Heightmap.GetTerrainData(); + byte landPacketType = (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) ? + (byte)TerrainPatch.LayerType.LandExtended : (byte)TerrainPatch.LayerType.Land; + + int numberPatchs = map.Length / 2; + + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + Buffer.BlockCopy(TerrainPacketHeader, 0, data, 0, 7); + + data[7] = landPacketType; + //data[8] and data[9] == datablock size to fill later + + data[10] = 0; // BitPack needs this on reused packets + + // start data + BitPack bitpack = new BitPack(data, 10); + bitpack.PackBits(STRIDE, 16); + bitpack.PackBitsFromByte(16); + bitpack.PackBitsFromByte(landPacketType); + + int s; + int datasize = 0; + for (int i = 0; i < numberPatchs; i++) + { + s = 2 * i; + OpenSimTerrainCompressor.CreatePatchFromTerrainData(bitpack, terrData, map[s], map[s + 1]); + if (bitpack.BytePos > 950 && i != numberPatchs - 1) + { + //finish this packet + bitpack.PackBitsFromByte(END_OF_PATCHES); + + // fix the datablock lenght + datasize = bitpack.BytePos - 9; + data[8] = (byte)datasize; + data[9] = (byte)(datasize >> 8); + + buf.DataLength = bitpack.BytePos + 1; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land, null, false, false); + + // start another + buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + data = buf.Data; + + Buffer.BlockCopy(TerrainPacketHeader, 0, data, 0, 7); + + data[7] = landPacketType; + //data[8] and data[9] == datablock size to fill later + + data[10] = 0; // BitPack needs this + // start data + bitpack = new BitPack(data, 10); + + bitpack.PackBits(STRIDE, 16); + bitpack.PackBitsFromByte(16); + bitpack.PackBitsFromByte(landPacketType); + } + } + + bitpack.PackBitsFromByte(END_OF_PATCHES); + + datasize = bitpack.BytePos - 9; + data[8] = (byte)datasize; + data[9] = (byte)(datasize >> 8); + + buf.DataLength = bitpack.BytePos + 1; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land, null, false, false); + } catch (Exception e) { @@ -1677,8 +1753,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendKillObject(List localIDs) { - // foreach (uint id in localIDs) - // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); + // foreach (uint id in localIDs) + // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); // remove pending entities to reduce looping chances. lock (m_entityProps.SyncRoot) @@ -1702,10 +1778,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if(++nsent >= 200) { - kill.Header.Reliable = true; - kill.Header.Zerocoded = true; OutPacket(kill, ThrottleOutPacketType.Task); - perpacket = localIDs.Count - i - 1; if(perpacket == 0) break; @@ -1720,8 +1793,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP if(nsent != 0) { - kill.Header.Reliable = true; - kill.Header.Zerocoded = true; OutPacket(kill, ThrottleOutPacketType.Task); } } @@ -3832,32 +3903,136 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(avp, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); } +/* public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) { // m_log.DebugFormat("[LLCLIENTVIEW]: Sending animations for {0} to {1}", sourceAgentId, Name); AvatarAnimationPacket ani = (AvatarAnimationPacket)PacketPool.Instance.GetPacket(PacketType.AvatarAnimation); // TODO: don't create new blocks if recycling an old packet - ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[animations.Length]; ani.Sender = new AvatarAnimationPacket.SenderBlock(); ani.Sender.ID = sourceAgentId; ani.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length]; ani.PhysicalAvatarEventList = new AvatarAnimationPacket.PhysicalAvatarEventListBlock[0]; - for (int i = 0; i < animations.Length; ++i) + //self animations + if (sourceAgentId == AgentId) { - ani.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock(); - ani.AnimationList[i].AnimID = animations[i]; - ani.AnimationList[i].AnimSequenceID = seqs[i]; + List withobjects = new List(animations.Length); + List noobjects = new List(animations.Length); + for(int i = 0; i < animations.Length; ++i) + { + if(objectIDs[i] == sourceAgentId || objectIDs[i] == UUID.Zero) + noobjects.Add(i); + else + withobjects.Add(i); + } - ani.AnimationSourceList[i] = new AvatarAnimationPacket.AnimationSourceListBlock(); - if (objectIDs[i].Equals(sourceAgentId)) - ani.AnimationSourceList[i].ObjectID = UUID.Zero; - else - ani.AnimationSourceList[i].ObjectID = objectIDs[i]; + ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[withobjects.Count]; + int k = 0; + foreach (int i in withobjects) + { + ani.AnimationList[k] = new AvatarAnimationPacket.AnimationListBlock(); + ani.AnimationList[k].AnimID = animations[i]; + ani.AnimationList[k].AnimSequenceID = seqs[i]; + ani.AnimationSourceList[k] = new AvatarAnimationPacket.AnimationSourceListBlock(); + ani.AnimationSourceList[k].ObjectID = objectIDs[i]; + k++; + } + foreach (int i in noobjects) + { + ani.AnimationList[k] = new AvatarAnimationPacket.AnimationListBlock(); + ani.AnimationList[k].AnimID = animations[i]; + ani.AnimationList[k].AnimSequenceID = seqs[i]; + k++; + } } + else + { + ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[0]; + for (int i = 0; i < animations.Length; ++i) + { + ani.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock(); + ani.AnimationList[i].AnimID = animations[i]; + ani.AnimationList[i].AnimSequenceID = seqs[i]; + } + } + OutPacket(ani, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); } +*/ + + static private readonly byte[] AvatarAnimationHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 20 // ID (high frequency) + }; + + public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) + { + // m_log.DebugFormat("[LLCLIENTVIEW]: Sending animations for {0} to {1}", sourceAgentId, Name); + + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + //setup header + Buffer.BlockCopy(AvatarAnimationHeader, 0, data, 0, 7); + //agent block + sourceAgentId.ToBytes(data, 7); + + // animations count + data[23] = (byte)animations.Length; + + int pos = 24; + + //self animations + if (sourceAgentId == AgentId) + { + List withobjects = new List(animations.Length); + List noobjects = new List(animations.Length); + for (int i = 0; i < animations.Length; ++i) + { + if (objectIDs[i] == sourceAgentId || objectIDs[i] == UUID.Zero) + noobjects.Add(i); + else + withobjects.Add(i); + } + + // first the ones with corresponding objects + foreach (int i in withobjects) + { + animations[i].ToBytes(data, pos); pos += 16; + Utils.IntToBytesSafepos(seqs[i], data, pos); pos += 4; + } + // then the rest + foreach (int i in noobjects) + { + animations[i].ToBytes(data, pos); pos += 16; + Utils.IntToBytesSafepos(seqs[i], data, pos); pos += 4; + } + // object ids block + data[pos++] = (byte)withobjects.Count; + foreach (int i in withobjects) + { + objectIDs[i].ToBytes(data, pos); pos += 16; + } + } + else + { + for(int i = 0; i < animations.Length; ++i) + { + animations[i].ToBytes(data, pos); pos += 16; + Utils.IntToBytesSafepos(seqs[i], data, pos); pos += 4; + } + data[pos++] = 0; // no object ids + } + + data[pos++] = 0; // no physical avatar events + + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority, + null, false, false); + } public void SendObjectAnimations(UUID[] animations, int[] seqs, UUID senderId) { @@ -3889,36 +4064,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public void SendEntityFullUpdateImmediate(ISceneEntity ent) { -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}", -// avatar.Name, avatar.UUID, Name, AgentId); - - if (ent == null) + if (ent == null || (!(ent is ScenePresence) && !(ent is SceneObjectPart))) return; - ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); - objupdate.Header.Zerocoded = true; + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(objectUpdateHeader, 0, buf.Data, 0, 7); - objupdate.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); - objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; + LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); + zc.Position = 7; - if(ent is ScenePresence) + zc.AddUInt64(m_scene.RegionInfo.RegionHandle); + zc.AddUInt16(Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f)); + + zc.AddByte(1); // block count + + ThrottleOutPacketType ptype = ThrottleOutPacketType.Task; + if (ent is ScenePresence) { - ScenePresence presence = ent as ScenePresence; - objupdate.RegionData.RegionHandle = presence.RegionHandle; - objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); - } - else if(ent is SceneObjectPart) - { - SceneObjectPart part = ent as SceneObjectPart; - objupdate.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - objupdate.ObjectData[0] = CreatePrimUpdateBlock(part, (ScenePresence)SceneAgent); + CreateAvatarUpdateBlock(ent as ScenePresence, zc); + ptype |= ThrottleOutPacketType.HighPriority; } + else + CreatePrimUpdateBlock(ent as SceneObjectPart, (ScenePresence)SceneAgent, zc); - OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); - - // We need to record the avatar local id since the root prim of an attachment points to this. -// m_attachmentsSent.Add(avatar.LocalId); + buf.DataLength = zc.Finish(); + m_udpServer.SendUDPPacket(m_udpClient, buf, ptype , null, false, false); } public void SendEntityTerseUpdateImmediate(ISceneEntity ent) @@ -4089,6 +4259,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP ResendPrimUpdate(update); } + static private readonly byte[] objectUpdateHeader = new byte[] { + Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED, + 0, 0, 0, 0, // sequence number + 0, // extra + 12 // ID (high frequency) + }; + + static private readonly byte[] terseUpdateHeader = new byte[] { + Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED, // zero code is not as spec + 0, 0, 0, 0, // sequence number + 0, // extra + 15 // ID (high frequency) + }; + private void ProcessEntityUpdates(int maxUpdatesBytes) { if (!IsActive) @@ -4098,14 +4282,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (mysp == null) return; - List objectUpdateBlocks = null; - List compressedUpdateBlocks = null; - List terseUpdateBlocks = null; - List terseAgentUpdateBlocks = null; + // List compressedUpdateBlocks = null; List objectUpdates = null; - List compressedUpdates = null; + // List compressedUpdates = null; List terseUpdates = null; - List terseAgentUpdates = null; List ObjectAnimationUpdates = null; // Check to see if this is a flush @@ -4120,10 +4300,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP float cullingrange = 64.0f; Vector3 mypos = Vector3.Zero; - bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance; + //bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance; + bool orderedDequeue = false; // temporary off HashSet GroupsNeedFullUpdate = new HashSet(); + if (doCulling) { cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance + 16f; @@ -4179,7 +4361,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP } if (grp.IsAttachment) - { // Someone else's HUD, why are we getting these? + { + // animated attachments are nasty if not supported by viewer + if(!m_SupportObjectAnimations && grp.RootPart.Shape.MeshFlagEntry) + continue; + + // Someone else's HUD, why are we getting these? if (grp.OwnerID != AgentId && grp.HasPrivateAttachmentPoint) continue; @@ -4273,7 +4460,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if(ObjectAnimationUpdates == null) ObjectAnimationUpdates = new List(); ObjectAnimationUpdates.Add(sop); - maxUpdatesBytes -= 32 * sop.Animations.Count + 16; + maxUpdatesBytes -= 20 * sop.Animations.Count + 24; } } } @@ -4304,7 +4491,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP PrimUpdateFlags.Velocity | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity | - PrimUpdateFlags.CollisionPlane + PrimUpdateFlags.CollisionPlane | + PrimUpdateFlags.Textures ); #endregion UpdateFlags to packet type conversion @@ -4326,48 +4514,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP if ((updateFlags & canNotUseImprovedMask) == 0) { - ImprovedTerseObjectUpdatePacket.ObjectDataBlock ablock = - CreateImprovedTerseBlock(update.Entity); + if (terseUpdates == null) + { + terseUpdates = new List(); + maxUpdatesBytes -= 18; + } + terseUpdates.Add(update); if (update.Entity is ScenePresence) - { - // ALL presence updates go into a special list - if (terseAgentUpdateBlocks == null) - { - terseAgentUpdateBlocks = new List(); - terseAgentUpdates = new List(); - } - terseAgentUpdateBlocks.Add(ablock); - terseAgentUpdates.Add(update); - } + maxUpdatesBytes -= 63; // no texture entry else { - // Everything else goes here - if (terseUpdateBlocks == null) - { - terseUpdateBlocks = new List(); - terseUpdates = new List(); - } - terseUpdateBlocks.Add(ablock); - terseUpdates.Add(update); + if ((updateFlags & PrimUpdateFlags.Textures) == 0) + maxUpdatesBytes -= 47; + else + maxUpdatesBytes -= 150; // aprox } - maxUpdatesBytes -= ablock.Length; } else { - ObjectUpdatePacket.ObjectDataBlock ablock; if (update.Entity is ScenePresence) - ablock = CreateAvatarUpdateBlock((ScenePresence)update.Entity); + maxUpdatesBytes -= 150; // crude estimation else - ablock = CreatePrimUpdateBlock((SceneObjectPart)update.Entity, mysp); - if(objectUpdateBlocks == null) + maxUpdatesBytes -= 300; + + if(objectUpdates == null) { - objectUpdateBlocks = new List(); objectUpdates = new List(); + maxUpdatesBytes -= 18; } - objectUpdateBlocks.Add(ablock); objectUpdates.Add(update); - maxUpdatesBytes -= ablock.Length; } #endregion Block Construction @@ -4382,29 +4558,87 @@ namespace OpenSim.Region.ClientStack.LindenUDP timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); - if (terseAgentUpdateBlocks != null) + if(objectUpdates != null) { - ImprovedTerseObjectUpdatePacket packet - = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = terseAgentUpdateBlocks.ToArray(); - terseAgentUpdateBlocks.Clear(); + int blocks = objectUpdates.Count; + List tau = new List(30); - OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates, oPacket); }); - } - - if (objectUpdateBlocks != null) - { - ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = objectUpdateBlocks.ToArray(); - objectUpdateBlocks.Clear(); - - OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates, oPacket); }); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(objectUpdateHeader, 0, buf.Data, 0, 7); + + LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); + zc.Position = 7; + + zc.AddUInt64(m_scene.RegionInfo.RegionHandle); + zc.AddUInt16(Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f)); + + zc.AddByte(1); // tmp block count + + int countposition = zc.Position - 1; + + int lastpos = 0; + int lastzc = 0; + + int count = 0; + foreach (EntityUpdate eu in objectUpdates) + { + lastpos = zc.Position; + lastzc = zc.ZeroCount; + if (eu.Entity is ScenePresence) + CreateAvatarUpdateBlock((ScenePresence)eu.Entity, zc); + else + CreatePrimUpdateBlock((SceneObjectPart)eu.Entity, mysp, zc); + if (zc.Position < LLUDPServer.MAXPAYLOAD) + { + tau.Add(eu); + ++count; + --blocks; + } + else if (blocks > 0) + { + // we need more packets + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, countposition); // start is the same + + buf.Data[countposition] = (byte)count; + // get pending zeros at cut point + if(lastzc > 0) + { + buf.Data[lastpos++] = 0; + buf.Data[lastpos++] = (byte)lastzc; + } + buf.DataLength = lastpos; + + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + + buf = newbuf; + zc.Data = buf.Data; + zc.ZeroCount = 0; + zc.Position = countposition + 1; + // im lazy now, just do last again + if (eu.Entity is ScenePresence) + CreateAvatarUpdateBlock((ScenePresence)eu.Entity, zc); + else + CreatePrimUpdateBlock((SceneObjectPart)eu.Entity, mysp, zc); + + tau = new List(30); + tau.Add(eu); + count = 1; + --blocks; + } + } + + if (count > 0) + { + buf.Data[countposition] = (byte)count; + buf.DataLength = zc.Finish(); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + } } +/* if (compressedUpdateBlocks != null) { ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); @@ -4415,20 +4649,68 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates, oPacket); }); } - - if (terseUpdateBlocks != null) +*/ + if (terseUpdates != null) { - ImprovedTerseObjectUpdatePacket packet = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( - PacketType.ImprovedTerseObjectUpdate); - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = terseUpdateBlocks.ToArray(); - terseUpdateBlocks.Clear(); + int blocks = terseUpdates.Count; + List tau = new List(30); - OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates, oPacket); }); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + + //setup header and regioninfo block + Buffer.BlockCopy(terseUpdateHeader, 0, buf.Data, 0, 7); + Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, buf.Data, 7); + Utils.UInt16ToBytes(timeDilation, buf.Data, 15); + int pos = 18; + int lastpos = 0; + + int count = 0; + foreach (EntityUpdate eu in terseUpdates) + { + lastpos = pos; + CreateImprovedTerseBlock(eu.Entity, buf.Data, ref pos, (eu.Flags & PrimUpdateFlags.Textures) != 0); + if (pos < LLUDPServer.MAXPAYLOAD) + { + tau.Add(eu); + ++count; + --blocks; + } + else if (blocks > 0) + { + // we need more packets + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, 17); // start is the same + // copy what we done in excess + int extralen = pos - lastpos; + if(extralen > 0) + Buffer.BlockCopy(buf.Data, lastpos, newbuf.Data, 18, extralen); + + pos = 18 + extralen; + + buf.Data[17] = (byte)count; + buf.DataLength = lastpos; + // zero encode is not as spec + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, true); + + tau = new List(30); + tau.Add(eu); + count = 1; + --blocks; + buf = newbuf; + } + } + + if (count > 0) + { + buf.Data[17] = (byte)count; + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, true); + } } - if(ObjectAnimationUpdates != null) + if (ObjectAnimationUpdates != null) { foreach (SceneObjectPart sop in ObjectAnimationUpdates) { @@ -4445,13 +4727,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP UUID[] ids = null; int[] seqs = null; int count = sop.GetAnimations(out ids, out seqs); - if(count < 0) - continue; ObjectAnimationPacket ani = (ObjectAnimationPacket)PacketPool.Instance.GetPacket(PacketType.ObjectAnimation); ani.Sender = new ObjectAnimationPacket.SenderBlock(); ani.Sender.ID = sop.UUID; - ani.AnimationList = new ObjectAnimationPacket.AnimationListBlock[sop.Animations.Count]; + ani.AnimationList = new ObjectAnimationPacket.AnimationListBlock[count]; for(int i = 0; i< count; i++) { @@ -4642,9 +4922,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // These are used to implement an adaptive backoff in the number // of updates converted to packets. Since we don't want packets // to sit in the queue with old data, only convert enough updates - // to packets that can be sent in 200ms. -// private Int32 m_LastQueueFill = 0; -// private Int32 m_maxUpdates = 0; + // to packets that can be sent in 30ms. void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) { @@ -5645,9 +5923,144 @@ namespace OpenSim.Region.ClientStack.LindenUDP return block; } + protected void CreateImprovedTerseBlock(ISceneEntity entity, byte[] data, ref int pos, bool includeTexture) + { + #region ScenePresence/SOP Handling + + bool avatar = (entity is ScenePresence); + uint localID = entity.LocalId; + uint attachPoint; + Vector4 collisionPlane; + Vector3 position, velocity, acceleration, angularVelocity; + Quaternion rotation; + byte datasize; + byte[] te = null; + + if (avatar) + { + ScenePresence presence = (ScenePresence)entity; + + position = presence.OffsetPosition; + velocity = presence.Velocity; + acceleration = Vector3.Zero; + rotation = presence.Rotation; + // tpvs can only see rotations around Z in some cases + if (!presence.Flying && !presence.IsSatOnObject) + { + rotation.X = 0f; + rotation.Y = 0f; + } + rotation.Normalize(); + angularVelocity = presence.AngularVelocity; + + // m_log.DebugFormat( + // "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name); + + attachPoint = presence.State; + collisionPlane = presence.CollisionPlane; + + datasize = 60; + } + else + { + SceneObjectPart part = (SceneObjectPart)entity; + + attachPoint = part.ParentGroup.AttachmentPoint; + attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16)); + // m_log.DebugFormat( + // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", + // attachPoint, part.Name, part.LocalId, Name); + + collisionPlane = Vector4.Zero; + position = part.RelativePosition; + velocity = part.Velocity; + acceleration = part.Acceleration; + angularVelocity = part.AngularVelocity; + rotation = part.RotationOffset; + + datasize = 44; + if(includeTexture) + te = part.Shape.TextureEntry; + } + + #endregion ScenePresence/SOP Handling + //object block size + data[pos++] = datasize; + + // LocalID + Utils.UIntToBytes(localID, data, pos); + pos += 4; + + data[pos++] = (byte)attachPoint; + + // Avatar/CollisionPlane + if (avatar) + { + data[pos++] = 1; + + if (collisionPlane == Vector4.Zero) + collisionPlane = Vector4.UnitW; + //m_log.DebugFormat("CollisionPlane: {0}",collisionPlane); + collisionPlane.ToBytes(data, pos); + pos += 16; + } + else + { + data[pos++] = 0; + } + + // Position + position.ToBytes(data, pos); + pos += 12; + + // Velocity + ClampVectorForUint(ref velocity, 128f); + Utils.FloatToUInt16Bytes(velocity.X, 128.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(velocity.Y, 128.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(velocity.Z, 128.0f, data, pos); pos += 2; + + // Acceleration + ClampVectorForUint(ref acceleration, 64f); + Utils.FloatToUInt16Bytes(acceleration.X, 64.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(acceleration.Y, 64.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(acceleration.Z, 64.0f, data, pos); pos += 2; + + // Rotation + Utils.FloatToUInt16Bytes(rotation.X, 1.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(rotation.Y, 1.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(rotation.Z, 1.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(rotation.W, 1.0f, data, pos); pos += 2; + + // Angular Velocity + ClampVectorForUint(ref angularVelocity, 64f); + Utils.FloatToUInt16Bytes(angularVelocity.X, 64.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(angularVelocity.Y, 64.0f, data, pos); pos += 2; + Utils.FloatToUInt16Bytes(angularVelocity.Z, 64.0f, data, pos); pos += 2; + + // texture entry block size + if(te == null) + { + data[pos++] = 0; + data[pos++] = 0; + } + else + { + int len = te.Length & 0x7fff; + int totlen = len + 4; + data[pos++] = (byte)totlen; + data[pos++] = (byte)(totlen >> 8); + data[pos++] = (byte)len; // wtf ??? + data[pos++] = (byte)(len >> 8); + data[pos++] = 0; + data[pos++] = 0; + Buffer.BlockCopy(te, 0, data, pos, len); + pos += len; + } + // total size 63 or 47 + (texture size + 4) + } + protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) { - Vector3 offsetPosition = data.OffsetPosition; Quaternion rotation = data.Rotation; // tpvs can only see rotations around Z in some cases if(!data.Flying && !data.IsSatOnObject) @@ -5657,27 +6070,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP } rotation.Normalize(); - uint parentID = data.ParentID; - // m_log.DebugFormat( // "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name); byte[] objectData = new byte[76]; - Vector3 velocity = new Vector3(0, 0, 0); - Vector3 acceleration = new Vector3(0, 0, 0); + //Vector3 velocity = Vector3.Zero; + Vector3 acceleration = Vector3.Zero; + Vector3 angularvelocity = Vector3.Zero; data.CollisionPlane.ToBytes(objectData, 0); - offsetPosition.ToBytes(objectData, 16); - velocity.ToBytes(objectData, 28); + data.OffsetPosition.ToBytes(objectData, 16); + data.Velocity.ToBytes(objectData, 28); acceleration.ToBytes(objectData, 40); rotation.ToBytes(objectData, 52); - data.AngularVelocity.ToBytes(objectData, 64); + angularvelocity.ToBytes(objectData, 64); ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); update.Data = Utils.EmptyBytes; - update.ExtraParams = new byte[1]; + update.ExtraParams = Utils.EmptyBytes; update.FullID = data.UUID; update.ID = data.LocalId; update.Material = (byte)Material.Flesh; @@ -5714,7 +6126,158 @@ namespace OpenSim.Region.ClientStack.LindenUDP return update; } -// protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID) + protected void CreateAvatarUpdateBlock(ScenePresence data, byte[] dest, ref int pos) + { + Quaternion rotation = data.Rotation; + // tpvs can only see rotations around Z in some cases + if (!data.Flying && !data.IsSatOnObject) + { + rotation.X = 0f; + rotation.Y = 0f; + } + rotation.Normalize(); + + //Vector3 velocity = Vector3.Zero; + //Vector3 acceleration = Vector3.Zero; + //Vector3 angularvelocity = Vector3.Zero; + + Utils.UIntToBytesSafepos(data.LocalId, dest, pos); pos += 4; + dest[pos++] = 0; // state + data.UUID.ToBytes(dest, pos); pos += 16; + Utils.UIntToBytesSafepos(0 , dest, pos); pos += 4; // crc + dest[pos++] = (byte)PCode.Avatar; + dest[pos++] = (byte)Material.Flesh; + dest[pos++] = 0; // clickaction + data.Appearance.AvatarSize.ToBytes(dest, pos); pos += 12; + + // objectdata block + dest[pos++] = 76; + data.CollisionPlane.ToBytes(dest, pos); pos += 16; + data.OffsetPosition.ToBytes(dest, pos); pos += 12; + data.Velocity.ToBytes(dest, pos); pos += 12; + + //acceleration.ToBytes(dest, pos); pos += 12; + Array.Clear(dest, pos, 12); pos += 12; + + rotation.ToBytes(dest, pos); pos += 12; + + //angularvelocity.ToBytes(dest, pos); pos += 12; + Array.Clear(dest, pos, 12); pos += 12; + + SceneObjectPart parentPart = data.ParentPart; + if (parentPart != null) + { + Utils.UIntToBytesSafepos(parentPart.ParentGroup.LocalId, dest, pos); + pos += 4; + } + else + { +// Utils.UIntToBytesSafepos(0, dest, pos); +// pos += 4; + dest[pos++] = 0; + dest[pos++] = 0; + dest[pos++] = 0; + dest[pos++] = 0; + } + + //Utils.UIntToBytesSafepos(0, dest, pos); pos += 4; //update flags + dest[pos++] = 0; + dest[pos++] = 0; + dest[pos++] = 0; + dest[pos++] = 0; + + //pbs + dest[pos++] = 16; + dest[pos++] = 1; + //Utils.UInt16ToBytes(0, dest, pos); pos += 2; + //Utils.UInt16ToBytes(0, dest, pos); pos += 2; + dest[pos++] = 0; + dest[pos++] = 0; + dest[pos++] = 0; + dest[pos++] = 0; + + dest[pos++] = 100; + dest[pos++] = 100; + + // rest of pbs is 0 (15), texture entry (2) and texture anim (1) + const int pbszeros = 15 + 2 + 1; + Array.Clear(dest, pos, pbszeros); pos += pbszeros; + + //NameValue + byte[] nv = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + + data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); + int len = nv.Length; + dest[pos++] = (byte)len; + dest[pos++] = (byte)(len >> 8); + Buffer.BlockCopy(nv, 0, dest, pos, len); pos += len; + + // data(2), text(1), text color(4), media url(1), PBblock(1), ExtramParams(1), + // sound id(16), sound owner(16) gain (4), flags (1), radius (4) + // jointtype(1) joint pivot(12) joint offset(12) + const int lastzeros = 2 + 1 + 4 + 1 + 1 + 1 + 16 + 16 + 4 + 1 + 4 + 1 + 12 + 12; + Array.Clear(dest, pos, lastzeros); pos += lastzeros; + } + + protected void CreateAvatarUpdateBlock(ScenePresence data, LLUDPZeroEncoder zc) + { + Quaternion rotation = data.Rotation; + // tpvs can only see rotations around Z in some cases + if (!data.Flying && !data.IsSatOnObject) + { + rotation.X = 0f; + rotation.Y = 0f; + } + rotation.Normalize(); + + zc.AddUInt(data.LocalId); + zc.AddByte(0); + zc.AddUUID(data.UUID); + zc.AddZeros(4); // crc unused + zc.AddByte((byte)PCode.Avatar); + zc.AddByte((byte)Material.Flesh); + zc.AddByte(0); // clickaction + zc.AddVector3(data.Appearance.AvatarSize); + + // objectdata block + zc.AddByte(76); // fixed avatar block size + zc.AddVector4(data.CollisionPlane); + zc.AddVector3(data.OffsetPosition); + zc.AddVector3(data.Velocity); + //zc.AddVector3(acceleration); + zc.AddZeros(12); + zc.AddNormQuat(rotation); + //zc.AddVector3(angularvelocity); + zc.AddZeros(12); + + SceneObjectPart parentPart = data.ParentPart; + if (parentPart != null) + zc.AddUInt(parentPart.ParentGroup.LocalId); + else + zc.AddZeros(4); + + zc.AddZeros(4); //update flags + + //pbs volume data 23 + //texture entry 2 + //texture anim (1) + const int pbszeros = 23 + 2 + 1; + zc.AddZeros(pbszeros); + + //NameValue + byte[] nv = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + + data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); + int len = nv.Length; + zc.AddByte((byte)len); + zc.AddByte((byte)(len >> 8)); + zc.AddBytes(nv, len); + + // data(2), text(1), text color(4), media url(1), PBblock(1), ExtramParams(1), + // sound id(16), sound owner(16) gain (4), flags (1), radius (4) + // jointtype(1) joint pivot(12) joint offset(12) + const int lastzeros = 2 + 1 + 4 + 1 + 1 + 1 + 16 + 16 + 4 + 1 + 4 + 1 + 12 + 12; + zc.AddZeros(lastzeros); + } + protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart part, ScenePresence sp) { byte[] objectData = new byte[60]; @@ -5737,32 +6300,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP //update.JointPivot = Vector3.Zero; //update.JointType = 0; update.Material = part.Material; -/* - if (data.ParentGroup.IsAttachment) - { - update.NameValue - = Util.StringToBytes256( - string.Format("AttachItemID STRING RW SV {0}", data.ParentGroup.FromItemID)); - - update.State = (byte)((data.ParentGroup.AttachmentPoint % 16) * 16 + (data.ParentGroup.AttachmentPoint / 16)); - -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending NameValue {0} for {1} {2} to {3}", -// Util.UTF8.GetString(update.NameValue), data.Name, data.LocalId, Name); -// -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}", -// update.State, data.Name, data.LocalId, Name); - } - else - { - update.NameValue = Utils.EmptyBytes; - - // The root part state is the canonical state for all parts of the object. The other part states in the - // case for attachments may contain conflicting values that can end up crashing the viewer. - update.State = data.ParentGroup.RootPart.Shape.State; - } -*/ if (part.ParentGroup.IsAttachment) { @@ -5858,15 +6395,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion PrimFlags - if (part.Sound != UUID.Zero || part.SoundFlags != 0) + bool hassound = part.Sound != UUID.Zero || part.SoundFlags != 0; + if (hassound) { update.Sound = part.Sound; - update.OwnerID = part.OwnerID; update.Gain = (float)part.SoundGain; update.Radius = (float)part.SoundRadius; update.Flags = part.SoundFlags; } + if(hassound || update.PSBlock.Length > 1) + update.OwnerID = part.OwnerID; + switch ((PCode)part.Shape.PCode) { case PCode.Grass: @@ -5882,6 +6422,308 @@ namespace OpenSim.Region.ClientStack.LindenUDP return update; } + protected void CreatePrimUpdateBlock(SceneObjectPart part, ScenePresence sp, LLUDPZeroEncoder zc) + { + // prepare data + + #region PrimFlags + // prim/update flags + PrimFlags primflags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp); + // Don't send the CreateSelected flag to everyone + primflags &= ~PrimFlags.CreateSelected; + if (sp.UUID == part.OwnerID) + { + if (part.CreateSelected) + { + // Only send this flag once, then unset it + primflags |= PrimFlags.CreateSelected; + part.CreateSelected = false; + } + } + #endregion PrimFlags + + // data block + byte[] data = null; + byte state = part.Shape.State; + PCode pcode = (PCode)part.Shape.PCode; + + //vegetation is special so just do it inline + if(pcode == PCode.Grass || pcode == PCode.Tree || pcode == PCode.NewTree) + { + zc.AddUInt(part.LocalId); + zc.AddByte(state); // state + zc.AddUUID(part.UUID); + zc.AddZeros(4); // crc unused + zc.AddByte((byte)pcode); + // material 1 + // clickaction 1 + zc.AddZeros(2); + zc.AddVector3(part.Shape.Scale); + + // objectdata block + zc.AddByte(60); // fixed object block size + zc.AddVector3(part.RelativePosition); + if (pcode == PCode.Grass) + zc.AddZeros(48); + else + { + zc.AddZeros(24); + Quaternion rot = part.RotationOffset; + rot.Normalize(); + zc.AddNormQuat(rot); + zc.AddZeros(12); + } + + zc.AddUInt(part.ParentID); + zc.AddUInt((uint)primflags); //update flags + + /* + if (pcode == PCode.Grass) + { + //pbs volume data 23 + //texture entry 2 + //texture anim 1 + //name value 2 + // data 1 + // text 5 + // media url 1 + // particle system 1 + // Extraparams 1 + // sound id 16 + // ownwer 16 + // sound gain 4 + // sound flags 1 + // sound radius 4 + // jointtype 1 + // joint pivot 12 + // joint offset 12 + zc.AddZeros(23 + 2 + 1 + 2 + 1 + 5 + 1 + 1 + 1 + 16 + 16 + 4 + 1 + 4 + 1 + 12 + 12); + return; + } + */ + + //pbs volume data 23 + //texture entry 2 + //texture anim 1 + //name value 2 + zc.AddZeros(23 + 2 + 1 + 2); + + //data: the tree type + zc.AddByte(1); + zc.AddZeros(1); + zc.AddByte(state); + + // text 5 + // media url 1 + // particle system 1 + // Extraparams 1 + // sound id 16 + // ownwer 16 + // sound gain 4 + // sound flags 1 + // sound radius 4 + // jointtype 1 + // joint pivot 12 + // joint offset 12 + zc.AddZeros(5 + 1 + 1 + 1 + 16 + 16 + 4 + 1 + 4 + 1 + 12 + 12); + + return; + } + + //NameValue and state + byte[] nv = null; + + if (part.ParentGroup.IsAttachment) + { + if (part.IsRoot) + nv = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID); + + int st = (int)part.ParentGroup.AttachmentPoint; + state = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ; + } + + // filter out mesh faces hack + ushort profileBegin = part.Shape.ProfileBegin; + ushort profileHollow = part.Shape.ProfileHollow; + byte profileCurve = part.Shape.ProfileCurve; + byte pathScaleY = part.Shape.PathScaleY; + + if (part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack + { + profileCurve = (byte)(part.Shape.ProfileCurve & 0x0f); + // fix old values that confused viewers + if (profileBegin == 1) + profileBegin = 9375; + if (profileHollow == 1) + profileHollow = 27500; + // fix torus hole size Y that also confuse some viewers + if (profileCurve == (byte)ProfileShape.Circle && pathScaleY < 150) + pathScaleY = 150; + } + + // do encode the things + zc.AddUInt(part.LocalId); + zc.AddByte(state); // state + zc.AddUUID(part.UUID); + zc.AddZeros(4); // crc unused + zc.AddByte((byte)pcode); + zc.AddByte(part.Material); + zc.AddByte(part.ClickAction); // clickaction + zc.AddVector3(part.Shape.Scale); + + // objectdata block + zc.AddByte(60); // fixed object block size + zc.AddVector3(part.RelativePosition); + zc.AddVector3(part.Velocity); + zc.AddVector3(part.Acceleration); + Quaternion rotation = part.RotationOffset; + rotation.Normalize(); + zc.AddNormQuat(rotation); + zc.AddVector3(part.AngularVelocity); + + zc.AddUInt(part.ParentID); + zc.AddUInt((uint)primflags); //update flags + + //pbs + zc.AddByte(part.Shape.PathCurve); + zc.AddByte(profileCurve); + zc.AddUInt16(part.Shape.PathBegin); + zc.AddUInt16(part.Shape.PathEnd); + zc.AddByte(part.Shape.PathScaleX); + zc.AddByte(pathScaleY); + zc.AddByte(part.Shape.PathShearX); + zc.AddByte(part.Shape.PathShearY); + zc.AddByte((byte)part.Shape.PathTwist); + zc.AddByte((byte)part.Shape.PathTwistBegin); + zc.AddByte((byte)part.Shape.PathRadiusOffset); + zc.AddByte((byte)part.Shape.PathTaperX); + zc.AddByte((byte)part.Shape.PathTaperY); + zc.AddByte(part.Shape.PathRevolutions); + zc.AddByte((byte)part.Shape.PathSkew); + zc.AddUInt16(profileBegin); + zc.AddUInt16(part.Shape.ProfileEnd); + zc.AddUInt16(profileHollow); + + // texture + byte[] tentry = part.Shape.TextureEntry; + if (tentry == null) + zc.AddZeros(2); + else + { + int len = tentry.Length; + zc.AddByte((byte)len); + zc.AddByte((byte)(len >> 8)); + zc.AddBytes(tentry, len); + } + + // texture animation + byte[] tanim = part.TextureAnimation; + if (tanim == null) + zc.AddZeros(1); + else + { + int len = tanim.Length; + zc.AddByte((byte)len); + zc.AddBytes(tanim, len); + } + + //NameValue + if(nv == null) + zc.AddZeros(2); + else + { + int len = nv.Length; + zc.AddByte((byte)len); + zc.AddByte((byte)(len >> 8)); + zc.AddBytes(nv, len); + } + + // data + if (data == null) + zc.AddZeros(2); + else + { + int len = data.Length; + zc.AddByte((byte)len); + zc.AddByte((byte)(len >> 8)); + zc.AddBytes(data, len); + } + + //text + if (part.Text == null || part.Text.Length == 0) + zc.AddZeros(5); + else + { + byte[] tbuf = Util.StringToBytes(part.Text, 254); + int len = tbuf.Length; + zc.AddByte((byte)len); + zc.AddBytes(tbuf, len); + + //textcolor + byte[] tc = part.GetTextColor().GetBytes(false); + zc.AddBytes(tc, 4); + } + + //media url + if (part.MediaUrl == null || part.MediaUrl.Length == 0) + zc.AddZeros(1); + else + { + byte[] tbuf = Util.StringToBytes(part.MediaUrl, 255); + int len = tbuf.Length; + zc.AddByte((byte)len); + zc.AddBytes(tbuf, len); + } + + bool hasps = false; + //particle system + byte[] ps = part.ParticleSystem; + if (ps == null || ps.Length < 1) + zc.AddZeros(1); + else + { + int len = ps.Length; + zc.AddByte((byte)len); + zc.AddBytes(ps, len); + hasps = true; + } + + //Extraparams + byte[] ep = part.Shape.ExtraParams; + if (ep == null || ep.Length < 2) + zc.AddZeros(1); + else + { + int len = ep.Length; + zc.AddByte((byte)len); + zc.AddBytes(ep, len); + } + + bool hassound = part.Sound != UUID.Zero || part.SoundFlags != 0; + if (hassound) + zc.AddUUID(part.Sound); + else + zc.AddZeros(16); + + if (hassound || hasps) + zc.AddUUID(part.OwnerID); + else + zc.AddZeros(16); + + if (hassound) + { + zc.AddFloat((float)part.SoundGain); + zc.AddByte(part.SoundFlags); + zc.AddFloat((float)part.SoundRadius); + } + else + zc.AddZeros(9); + + // jointtype(1) joint pivot(12) joint offset(12) + const int lastzeros = 1 + 12 + 12; + zc.AddZeros(lastzeros); + } + protected ObjectUpdateCompressedPacket.ObjectDataBlock CreateCompressedUpdateBlock(SceneObjectPart part, PrimUpdateFlags updateFlags) { // TODO: Implement this @@ -10047,7 +10889,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP UUID.TryParse(Utils.BytesToString(messagePacket.ParamList[1].Parameter), out Prey); - OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey); + OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey, false); } return true; case "teleporthomeallusers": @@ -10195,7 +11037,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP UUID.TryParse(Utils.BytesToString(messagePacket.ParamList[0].Parameter), out Prey); - OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey); + OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey, true); } return true; @@ -12560,14 +13402,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// provide your own method. protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) { - -/* this is causing packet loss for some reason - if(!m_udpClient.IsConnected) - { - PacketPool.Instance.ReturnPacket(packet); - return; - } -*/ if (m_outPacketsToDrop != null) { if (m_outPacketsToDrop.Contains(packet.Type.ToString())) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 439621ae4e..2981337b2d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -120,7 +120,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Circuit code that this client is connected on public readonly uint CircuitCode; /// Sequence numbers of packets we've received (for duplicate checking) - public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); + public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(256); /// Packets we have sent that need to be ACKed by the client public UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); @@ -210,12 +210,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - /// - /// This is the percentage of the udp texture queue to add to the task queue since - /// textures are now generally handled through http. - /// - private double m_cannibalrate = 0.0; - private ClientInfo m_info = new ClientInfo(); /// @@ -257,8 +251,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Create an array of token buckets for this clients different throttle categories m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; - m_cannibalrate = rates.CannibalizeTextureRate; - m_burst = rates.Total * rates.BrustTime; for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) @@ -449,12 +441,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP asset = Math.Max(asset, LLUDPServer.MTU); */ - // Since most textures are now delivered through http, make it possible - // to cannibalize some of the bw from the texture throttle to use for - // the task queue (e.g. object updates) - task = task + (int)(m_cannibalrate * texture); - texture = (int)((1 - m_cannibalrate) * texture); - int total = resend + land + wind + cloud + task + texture + asset; float m_burst = total * m_burstTime; @@ -575,22 +561,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP { DoubleLocklessQueue queue = m_packetOutboxes[category]; - if (m_deliverPackets == false) + if (forceQueue || m_deliverPackets == false) { queue.Enqueue(packet, highPriority); return true; } - TokenBucket bucket = m_throttleCategories[category]; - - // Don't send this packet if queue is not empty + // need to enqueue if queue is not empty if (queue.Count > 0 || m_nextPackets[category] != null) { queue.Enqueue(packet, highPriority); return true; } - if (!forceQueue && bucket.CheckTokens(packet.Buffer.DataLength)) + // check bandwidth + TokenBucket bucket = m_throttleCategories[category]; + if (bucket.CheckTokens(packet.Buffer.DataLength)) { // enough tokens so it can be sent imediatly by caller bucket.RemoveTokens(packet.Buffer.DataLength); @@ -608,7 +594,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // We don't have a token bucket for this category, so it will not be queued return false; } - } /// @@ -650,6 +635,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP // leaving a dequeued packet still waiting to be sent out. Try to // send it again OutgoingPacket nextPacket = m_nextPackets[i]; + if(nextPacket.Buffer == null) + { + if (m_packetOutboxes[i].Count < 5) + emptyCategories |= CategoryToFlag(i); + continue; + } if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) { // Send the packet @@ -681,21 +672,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out - if (bucket.RemoveTokens(packet.Buffer.DataLength)) + if(packet.Buffer == null) { - // Send the packet - m_udpServer.SendPacketFinal(packet); - packetSent = true; - + // packet canceled elsewhere (by a ack for example) if (queue.Count < 5) emptyCategories |= CategoryToFlag(i); } else { - // Save the dequeued packet for the next iteration - m_nextPackets[i] = packet; - } + if (bucket.RemoveTokens(packet.Buffer.DataLength)) + { + // Send the packet + m_udpServer.SendPacketFinal(packet); + packetSent = true; + if (queue.Count < 5) + emptyCategories |= CategoryToFlag(i); + } + else + { + // Save the dequeued packet for the next iteration + m_nextPackets[i] = packet; + } + } } else { @@ -803,8 +802,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - - /// /// Fires the OnQueueEmpty callback and sets the minimum time that it /// can be called again @@ -843,6 +840,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP return 0; } + public void FreeUDPBuffer(UDPPacketBuffer buf) + { + m_udpServer.FreeUDPBuffer(buf); + } + /// /// Converts a integer to a /// flag value @@ -853,34 +855,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ThrottleOutPacketType category = (ThrottleOutPacketType)i; - /* - * Land = 1, - /// Wind data - Wind = 2, - /// Cloud data - Cloud = 3, - /// Any packets that do not fit into the other throttles - Task = 4, - /// Texture assets - Texture = 5, - /// Non-texture assets - Asset = 6, - */ - switch (category) { case ThrottleOutPacketType.Land: - return ThrottleOutPacketTypeFlags.Land; + return ThrottleOutPacketTypeFlags.Land; // Terrain data case ThrottleOutPacketType.Wind: - return ThrottleOutPacketTypeFlags.Wind; + return ThrottleOutPacketTypeFlags.Wind; // Wind data case ThrottleOutPacketType.Cloud: - return ThrottleOutPacketTypeFlags.Cloud; + return ThrottleOutPacketTypeFlags.Cloud; // Cloud data case ThrottleOutPacketType.Task: - return ThrottleOutPacketTypeFlags.Task; + return ThrottleOutPacketTypeFlags.Task; // Object updates and everything not on the other categories case ThrottleOutPacketType.Texture: - return ThrottleOutPacketTypeFlags.Texture; + return ThrottleOutPacketTypeFlags.Texture; // Textures data (also impacts http texture and mesh by default) case ThrottleOutPacketType.Asset: - return ThrottleOutPacketTypeFlags.Asset; + return ThrottleOutPacketTypeFlags.Asset; // Non-texture Assets data default: return 0; } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs old mode 100644 new mode 100755 index 35d29a5adb..2300800f57 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -256,6 +256,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Maximum transmission unit, or UDP packet size, for the LLUDP protocol public const int MTU = 1400; + public const int MAXPAYLOAD = 1250; /// Number of forced client logouts due to no receipt of packets before timeout. public int ClientLogoutsDueToNoReceives { get; protected set; } @@ -274,10 +275,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// The measured resolution of Environment.TickCount public readonly float TickCountResolution; - /// Number of prim updates to put on the queue each time the - /// OnQueueEmpty event is triggered for updates - public readonly int PrimUpdatesPerCallback; - /// Number of texture packets to put on the queue each time the /// OnQueueEmpty event is triggered for textures public readonly int TextureSendLimit; @@ -344,18 +341,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected ExpiringCache> m_pendingCache = new ExpiringCache>(); - protected Pool m_incomingPacketPool; - - /// - /// Stat for number of packets in the main pool awaiting use. - /// - protected Stat m_poolCountStat; - - /// - /// Stat for number of packets in the inbound packet pool awaiting use. - /// - protected Stat m_incomingPacketPoolStat; - protected int m_defaultRTO = 0; protected int m_maxRTO = 0; protected int m_ackTimeout = 0; @@ -452,7 +437,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); - PrimUpdatesPerCallback = config.GetInt("PrimUpdatesPerCallback", 100); TextureSendLimit = config.GetInt("TextureSendLimit", 20); m_defaultRTO = config.GetInt("DefaultRTO", 0); @@ -463,7 +447,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - PrimUpdatesPerCallback = 100; TextureSendLimit = 20; m_ackTimeout = 1000 * 60; // 1 minute m_pausedAckTimeout = 1000 * 300; // 5 minutes @@ -498,7 +481,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // if (usePools) // EnablePools(); - base.DisablePools(); } public void Start() @@ -554,83 +536,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OqrEngine.Stop(); } - public override bool EnablePools() - { - if (!UsePools) - { - base.EnablePools(); - - m_incomingPacketPool = new Pool(() => new IncomingPacket(), 500); - - return true; - } - - return false; - } - - public override bool DisablePools() - { - if (UsePools) - { - base.DisablePools(); - - StatsManager.DeregisterStat(m_incomingPacketPoolStat); - - // We won't null out the pool to avoid a race condition with code that may be in the middle of using it. - - return true; - } - - return false; - } - - /// - /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene - /// stats. - /// - protected internal void EnablePoolStats() - { - m_poolCountStat - = new Stat( - "UDPPacketBufferPoolCount", - "Objects within the UDPPacketBuffer pool", - "The number of objects currently stored within the UDPPacketBuffer pool", - "", - "clientstack", - Scene.Name, - StatType.Pull, - stat => stat.Value = Pool.Count, - StatVerbosity.Debug); - - StatsManager.RegisterStat(m_poolCountStat); - - m_incomingPacketPoolStat - = new Stat( - "IncomingPacketPoolCount", - "Objects within incoming packet pool", - "The number of objects currently stored within the incoming packet pool", - "", - "clientstack", - Scene.Name, - StatType.Pull, - stat => stat.Value = m_incomingPacketPool.Count, - StatVerbosity.Debug); - - StatsManager.RegisterStat(m_incomingPacketPoolStat); - } - - /// - /// Disables pool stats. - /// - protected internal void DisablePoolStats() - { - StatsManager.DeregisterStat(m_poolCountStat); - m_poolCountStat = null; - - StatsManager.DeregisterStat(m_incomingPacketPoolStat); - m_incomingPacketPoolStat = null; - } - /// /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. /// @@ -658,8 +563,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name), "INCOMING PACKET ASYNC HANDLING ENGINE"); */ - OqrEngine - = new JobEngine( + OqrEngine = new JobEngine( string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name), "OUTGOING QUEUE REFILL ENGINE"); @@ -769,15 +673,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP stat => stat.Value = OqrEngine.JobsWaiting, StatVerbosity.Debug)); - // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by - // scene name - if (UsePools) - EnablePoolStats(); - + StatsManager.RegisterStat( + new Stat( + "UDPBuffersPoolCount", + "Buffers in the UDP buffers pool", + "The number of buffers currently stored within the UDP buffers pool", + "", + "clientstack", + Scene.Name, + StatType.Pull, + stat => stat.Value = m_udpBuffersPoolPtr + 1, + StatVerbosity.Debug)); LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this); commands.Register(); - } public bool HandlesRegion(Location x) @@ -939,9 +848,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here // to accomodate for both common scenarios and provide ample room for ACK appending in both - int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; + //int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; - UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); + //UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); + UDPPacketBuffer buffer = GetNewUDPBuffer(udpClient.RemoteEndPoint); // Zerocode if needed if (doZerocode) @@ -971,7 +881,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // If the packet data wasn't already copied during zerocoding, copy it now if (doCopy) { - if (dataLength <= buffer.Data.Length) + //if (dataLength <= buffer.Data.Length) + if (dataLength <= LLUDPServer.MTU) { Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } @@ -979,7 +890,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length); - buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, dataLength); + // buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, dataLength); + buffer = GetNewUDPBuffer(udpClient.RemoteEndPoint); Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } } @@ -1017,6 +929,89 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Queue or Send } + public unsafe UDPPacketBuffer ZeroEncode(UDPPacketBuffer input) + { + UDPPacketBuffer zb = GetNewUDPBuffer(null); + int srclen = input.DataLength; + byte[] src = input.Data; + byte[] dest = zb.Data; + + int zerolen = 6; + byte zerocount = 0; + + for (int i = zerolen; i < srclen; i++) + { + if (src[i] == 0x00) + { + zerocount++; + if (zerocount == 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = 0xff; + zerocount++; + } + } + else + { + if (zerocount != 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = zerocount; + zerocount = 0; + } + + dest[zerolen++] = src[i]; + } + } + + if (zerocount != 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = zerocount; + } + + if(zerolen >= srclen) + { + FreeUDPBuffer(zb); + + src[0] &= unchecked((byte)~Helpers.MSG_ZEROCODED); + return input; + } + + Buffer.BlockCopy(src, 0, dest, 0, 6); + + zb.RemoteEndPoint = input.RemoteEndPoint; + zb.DataLength = zerolen; + + FreeUDPBuffer(input); + + return zb; + } + + public void SendUDPPacket( + LLUDPClient udpClient, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method, bool forcequeue, bool zerocode) + { + bool highPriority = false; + + if(zerocode) + buffer = ZeroEncode(buffer); + + if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0) + { + category = (ThrottleOutPacketType)((int)category & 127); + highPriority = true; + } + + OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); + + // If we were not provided a method for handling unacked, use the UDPServer default method + if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0) + outgoingPacket.UnackedMethod = ((method == null) ? delegate (OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); + + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forcequeue, highPriority)) + SendPacketFinal(outgoingPacket); + } + public void SendAcks(LLUDPClient udpClient) { uint ack; @@ -1066,7 +1061,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { LLUDPClient udpClient = client.UDPClient; - if (!udpClient.IsConnected) + if (!client.IsActive || !udpClient.IsConnected) return; // Disconnect an agent if no packets are received for some time @@ -1136,14 +1131,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP internal void SendPacketFinal(OutgoingPacket outgoingPacket) { UDPPacketBuffer buffer = outgoingPacket.Buffer; + if(buffer == null) // canceled packet + return; + LLUDPClient udpClient = outgoingPacket.Client; + if (!udpClient.IsConnected) + return; + byte flags = buffer.Data[0]; bool isResend = (flags & Helpers.MSG_RESENT) != 0; bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; bool isZerocoded = (flags & Helpers.MSG_ZEROCODED) != 0; - LLUDPClient udpClient = outgoingPacket.Client; - - if (!udpClient.IsConnected) - return; int dataLength = buffer.DataLength; @@ -1154,7 +1151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // no more ACKs to append int ackCount = 0; uint ack; - while (dataLength + 5 < buffer.Data.Length && ackCount < 256 && udpClient.PendingAcks.Dequeue(out ack)) + while (dataLength + 5 < MTU && ackCount < 256 && udpClient.PendingAcks.Dequeue(out ack)) { Utils.UIntToBytesBig(ack, buffer.Data, dataLength); dataLength += 4; @@ -1168,22 +1165,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Set the appended ACKs flag on this packet buffer.Data[0] = (byte)(buffer.Data[0] | Helpers.MSG_APPENDED_ACKS); } + buffer.DataLength = dataLength; } - buffer.DataLength = dataLength; - if (!isResend) { // Not a resend, assign a new sequence number uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence); Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); outgoingPacket.SequenceNumber = sequenceNumber; - - if (isReliable) - { - // Add this packet to the list of ACK responses we are waiting on from the server - udpClient.NeedAcks.Add(outgoingPacket); - } } else { @@ -1196,9 +1186,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP PacketsSentCount++; SyncSend(buffer); + // Keep track of when this packet was sent out (right now) outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; + if (outgoingPacket.UnackedMethod == null) + FreeUDPBuffer(buffer); + else if(!isResend) + { + // Add this packet to the list of ACK responses we are waiting on from the server + udpClient.NeedAcks.Add(outgoingPacket); + } + if (udpClient.DebugDataOutLevel > 0) m_log.DebugFormat( "[LLUDPSERVER]: Sending packet #{0} (rel: {1}, res: {2}) to {3} from {4}", @@ -1240,7 +1239,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); RecordMalformedInboundPacket(endPoint); - + FreeUDPBuffer(buffer); return; // Drop undersized packet } @@ -1260,21 +1259,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); RecordMalformedInboundPacket(endPoint); - + FreeUDPBuffer(buffer); return; // Malformed header } try { -// packet = Packet.BuildPacket(buffer.Data, ref packetEnd, -// // Only allocate a buffer for zerodecoding if the packet is zerocoded -// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); + // get a buffer for zero decode using the udp buffers pool + UDPPacketBuffer zerodecodebufferholder = null; + byte[] zerodecodebuffer = null; + // only if needed + if (((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0)) + { + zerodecodebufferholder = GetNewUDPBuffer(null); + zerodecodebuffer = zerodecodebufferholder.Data; + } + + packet = Packet.BuildPacket(buffer.Data, ref packetEnd, zerodecodebuffer); // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all // bytes are copied out). - packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd, - // Only allocate a buffer for zerodecoding if the packet is zerocoded - ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); + // packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd, zerodecodebuffer); + if(zerodecodebufferholder != null) + FreeUDPBuffer(zerodecodebufferholder); } catch (Exception e) { @@ -1292,7 +1299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } RecordMalformedInboundPacket(endPoint); - + FreeUDPBuffer(buffer); return; } @@ -1311,17 +1318,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP lock (m_pendingCache) { if (m_pendingCache.Contains(endPoint)) + { + FreeUDPBuffer(buffer); return; + } m_pendingCache.AddOrUpdate(endPoint, new Queue(), 60); } - // We need to copy the endpoint so that it doesn't get changed when another thread reuses the - // buffer. - object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; - - Util.FireAndForget(HandleUseCircuitCode, array); - + Util.FireAndForget(HandleUseCircuitCode, new object[] { endPoint, packet }); + FreeUDPBuffer(buffer); return; } } @@ -1336,24 +1342,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP queue.Enqueue(buffer); return; } - -/* - else if (packet.Type == PacketType.CompleteAgentMovement) - { - // Send ack straight away to let the viewer know that we got it. - SendAckImmediate(endPoint, packet.Header.Sequence); - - // We need to copy the endpoint so that it doesn't get changed when another thread reuses the - // buffer. - object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; - - Util.FireAndForget(HandleCompleteMovementIntoRegion, array); - - return; - } - */ } + FreeUDPBuffer(buffer); + // Determine which agent this packet came from if (client == null || !(client is LLClientView)) { @@ -1471,10 +1463,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); #endregion BinaryStats - -//AgentUpdate removed from here - - #region Ping Check Handling if (packet.Type == PacketType.StartPingCheck) @@ -1506,17 +1494,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP IncomingPacket incomingPacket; - // Inbox insertion - if (UsePools) - { - incomingPacket = m_incomingPacketPool.GetObject(); - incomingPacket.Client = (LLClientView)client; - incomingPacket.Packet = packet; - } - else - { - incomingPacket = new IncomingPacket((LLClientView)client, packet); - } + incomingPacket = new IncomingPacket((LLClientView)client, packet); // if (incomingPacket.Packet.Type == PacketType.AgentUpdate || // incomingPacket.Packet.Type == PacketType.ChatFromViewer) @@ -1525,7 +1503,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // else // packetInbox.Enqueue(incomingPacket); packetInbox.Add(incomingPacket); - } #region BinaryStats @@ -1685,7 +1662,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); return; - } m_pendingCache.Remove(endPoint); } @@ -1881,13 +1857,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte[] packetData = ack.ToBytes(); int length = packetData.Length; - UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length); + UDPPacketBuffer buffer = GetNewUDPBuffer(remoteEndpoint); buffer.DataLength = length; Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); // AsyncBeginSend(buffer); SyncSend(buffer); + FreeUDPBuffer(buffer); } protected bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) @@ -1982,21 +1959,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP Scene.ThreadAlive(1); try { - packetInbox.TryTake(out incomingPacket, 250); + packetInbox.TryTake(out incomingPacket, 4500); if (incomingPacket != null && IsRunningInbound) { ProcessInPacket(incomingPacket); - - if (UsePools) - { - incomingPacket.Client = null; - m_incomingPacketPool.ReturnObject(incomingPacket); - } incomingPacket = null; } } - catch(Exception ex) + catch (ThreadAbortException) + { + Thread.ResetAbort(); + } + catch (Exception ex) { m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); } @@ -2025,7 +2000,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { Scene.ThreadAlive(2); - try { m_packetSent = false; @@ -2080,7 +2054,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else if (!m_packetSent) // Thread.Sleep((int)TickCountResolution); outch this is bad on linux - Thread.Sleep(15); // match the 16ms of windows7, dont ask 16 or win may decide to do 32ms. + Thread.Sleep(15); // match the 16ms of windows, dont ask 16 or win may decide to do 32ms. Watchdog.UpdateThread(); } @@ -2104,14 +2078,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (udpClient.IsConnected) { - if (m_resendUnacked) + if (client.IsActive && m_resendUnacked) HandleUnacked(llClient); - if (m_sendAcks) - SendAcks(udpClient); + if (client.IsActive) + { + if (m_sendAcks) + SendAcks(udpClient); - if (m_sendPing) - SendPing(udpClient); + if (m_sendPing) + SendPing(udpClient); + } // Dequeue any outgoing packets that are within the throttle limits if (udpClient.DequeueOutgoing()) @@ -2124,7 +2101,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.Error( string.Format("[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex); } - client = null; } #region Emergency Monitoring diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs index 012a57d969..a4d7eb924e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs @@ -777,41 +777,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpServer.StopOutbound(); } - private void HandlePoolCommand(string module, string[] args) - { - if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) - return; - - if (args.Length != 4) - { - MainConsole.Instance.Output("Usage: debug lludp pool "); - return; - } - - string enabled = args[3]; - - if (enabled == "on") - { - if (m_udpServer.EnablePools()) - { - m_udpServer.EnablePoolStats(); - MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_udpServer.Scene.Name); - } - } - else if (enabled == "off") - { - if (m_udpServer.DisablePools()) - { - m_udpServer.DisablePoolStats(); - MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_udpServer.Scene.Name); - } - } - else - { - MainConsole.Instance.Output("Usage: debug lludp pool "); - } - } - private void HandleAgentUpdateCommand(string module, string[] args) { if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) @@ -834,8 +799,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP MainConsole.Instance.OutputFormat( "OUT LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningOutbound ? "enabled" : "disabled"); - MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_udpServer.Scene.Name, m_udpServer.UsePools ? "on" : "off"); - MainConsole.Instance.OutputFormat( "Packet debug level for new clients is {0}", m_udpServer.DefaultClientPacketDebugLevel); } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPZeroEncoder.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPZeroEncoder.cs new file mode 100644 index 0000000000..8ed2cf12cd --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPZeroEncoder.cs @@ -0,0 +1,279 @@ +/* + * 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 OpenSim.Framework; +using Nini.Config; +using OpenMetaverse; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public sealed class LLUDPZeroEncoder + { + private byte[] m_tmp = new byte[16]; + private byte[] m_dest; + private int zerocount; + private int pos; + + public LLUDPZeroEncoder() + { + } + + public LLUDPZeroEncoder(byte[] data) + { + m_dest = data; + zerocount = 0; + } + + public byte[] Data + { + get + { + return m_dest; + } + set + { + m_dest = value; + } + } + + public int ZeroCount + { + get + { + return zerocount; + } + set + { + zerocount = value; + } + } + + public int Position + { + get + { + return pos; + } + set + { + pos = value; + } + } + + public unsafe void AddZeros(int len) + { + zerocount += len; + while (zerocount > 255) + { + m_dest[pos++] = 0x00; + m_dest[pos++] = 0xff; + zerocount -= 256; + } + } + + public unsafe int Finish() + { + if(zerocount > 0) + { + m_dest[pos++] = 0x00; + m_dest[pos++] = (byte)zerocount; + } + return pos; + } + + public unsafe void AddBytes(byte[] src, int srclen) + { + for (int i = 0; i < srclen; ++i) + { + if (src[i] == 0x00) + { + zerocount++; + if (zerocount == 0) + { + m_dest[pos++] = 0x00; + m_dest[pos++] = 0xff; + zerocount++; + } + } + else + { + if (zerocount != 0) + { + m_dest[pos++] = 0x00; + m_dest[pos++] = (byte)zerocount; + zerocount = 0; + } + + m_dest[pos++] = src[i]; + } + } + } + + public unsafe void AddByte(byte v) + { + if (v == 0x00) + { + zerocount++; + if (zerocount == 0) + { + m_dest[pos++] = 0x00; + m_dest[pos++] = 0xff; + zerocount++; + } + } + else + { + if (zerocount != 0) + { + m_dest[pos++] = 0x00; + m_dest[pos++] = (byte)zerocount; + zerocount = 0; + } + + m_dest[pos++] = v; + } + } + + public void AddInt16(short v) + { + if (v == 0) + AddZeros(2); + else + { + Utils.Int16ToBytes(v, m_tmp, 0); + AddBytes(m_tmp, 2); + } + } + + public void AddUInt16(ushort v) + { + if (v == 0) + AddZeros(2); + else + { + Utils.UInt16ToBytes(v, m_tmp, 0); + AddBytes(m_tmp, 2); + } + } + + public void AddInt(int v) + { + if (v == 0) + AddZeros(4); + else + { + Utils.IntToBytesSafepos(v, m_tmp, 0); + AddBytes(m_tmp, 4); + } + } + + public unsafe void AddUInt(uint v) + { + if (v == 0) + AddZeros(4); + else + { + Utils.UIntToBytesSafepos(v, m_tmp, 0); + AddBytes(m_tmp, 4); + } + } + + public void AddFloatToUInt16(float v, float range) + { + Utils.FloatToUInt16Bytes(v, range, m_tmp, 0); + AddBytes(m_tmp, 2); + } + + public void AddFloat(float v) + { + if (v == 0f) + AddZeros(4); + else + { + Utils.FloatToBytesSafepos(v, m_tmp, 0); + AddBytes(m_tmp, 4); + } + } + + public void AddInt64(long v) + { + if (v == 0) + AddZeros(8); + else + { + Utils.Int64ToBytesSafepos(v, m_tmp, 0); + AddBytes(m_tmp, 8); + } + } + + public void AddUInt64(ulong v) + { + if (v == 0) + AddZeros(8); + else + { + Utils.UInt64ToBytesSafepos(v, m_tmp, 0); + AddBytes(m_tmp, 8); + } + } + + public void AddVector3(Vector3 v) + { + if (v == Vector3.Zero) + AddZeros(12); + else + { + v.ToBytes(m_tmp, 0); + AddBytes(m_tmp, 12); + } + } + + public void AddVector4(Vector4 v) + { + if (v == Vector4.Zero) + AddZeros(16); + else + { + v.ToBytes(m_tmp, 0); + AddBytes(m_tmp, 16); + } + } + + public void AddNormQuat(Quaternion v) + { + v.ToBytes(m_tmp, 0); + AddBytes(m_tmp, 12); + } + + public void AddUUID(UUID v) + { + v.ToBytes(m_tmp, 0); + AddBytes(m_tmp, 16); + } + } +} diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index f362b06f0a..49aca3c18e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Concurrent; using System.Net; using System.Net.Sockets; using System.Threading; @@ -57,15 +58,9 @@ namespace OpenMetaverse /// UDP socket, used in either client or server mode private Socket m_udpSocket; - /// - /// Are we to use object pool(s) to reduce memory churn when receiving data? - /// - public bool UsePools { get; protected set; } - - /// - /// Pool to use for handling data. May be null if UsePools = false; - /// - protected OpenSim.Framework.Pool Pool { get; private set; } + public static Object m_udpBuffersPoolLock = new Object(); + public static UDPPacketBuffer[] m_udpBuffersPool = new UDPPacketBuffer[1000]; + public static int m_udpBuffersPoolPtr = -1; /// Returns true if the server is currently listening for inbound packets, otherwise false public bool IsRunningInbound { get; private set; } @@ -186,6 +181,37 @@ namespace OpenMetaverse if(m_udpSocket !=null) try { m_udpSocket.Close(); } catch { } } + + public UDPPacketBuffer GetNewUDPBuffer(IPEndPoint remoteEndpoint) + { + lock (m_udpBuffersPoolLock) + { + if (m_udpBuffersPoolPtr >= 0) + { + UDPPacketBuffer buf = m_udpBuffersPool[m_udpBuffersPoolPtr]; + m_udpBuffersPool[m_udpBuffersPoolPtr] = null; + m_udpBuffersPoolPtr--; + buf.RemoteEndPoint = remoteEndpoint; + return buf; + } + } + return new UDPPacketBuffer(remoteEndpoint); + } + + public void FreeUDPBuffer(UDPPacketBuffer buf) + { + lock (m_udpBuffersPoolLock) + { + if (m_udpBuffersPoolPtr < 999) + { + buf.RemoteEndPoint = null; + buf.DataLength = 0; + m_udpBuffersPoolPtr++; + m_udpBuffersPool[m_udpBuffersPoolPtr] = buf; + } + } + } + /// /// Start inbound UDP packet handling. /// @@ -202,6 +228,7 @@ namespace OpenMetaverse /// manner (not throwing an exception when the remote side resets the /// connection). This call is ignored on Mono where the flag is not /// necessary + public virtual void StartInbound(int recvBufferSize) { if (!IsRunningInbound) @@ -306,101 +333,55 @@ namespace OpenMetaverse IsRunningOutbound = false; } - public virtual bool EnablePools() - { - if (!UsePools) - { - Pool = new Pool(() => new UDPPacketBuffer(), 500); - - UsePools = true; - - return true; - } - - return false; - } - - public virtual bool DisablePools() - { - if (UsePools) - { - UsePools = false; - - // We won't null out the pool to avoid a race condition with code that may be in the middle of using it. - - return true; - } - - return false; - } - private void AsyncBeginReceive() { - UDPPacketBuffer buf; + if (!IsRunningInbound) + return; - // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other - // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux. - // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation. -// if (UsePools) -// buf = Pool.GetObject(); -// else - buf = new UDPPacketBuffer(); - - if (IsRunningInbound) + UDPPacketBuffer buf = GetNewUDPBuffer(new IPEndPoint(IPAddress.Any, 0)); // we need a fresh one here, for now at least + try { - try + // kick off an async read + m_udpSocket.BeginReceiveFrom( + buf.Data, + 0, + buf.Data.Length, + SocketFlags.None, + ref buf.RemoteEndPoint, + AsyncEndReceive, + buf); + } + catch (SocketException e) + { + if (e.SocketErrorCode == SocketError.ConnectionReset) { - // kick off an async read - m_udpSocket.BeginReceiveFrom( - //wrappedBuffer.Instance.Data, - buf.Data, - 0, - UDPPacketBuffer.BUFFER_SIZE, - SocketFlags.None, - ref buf.RemoteEndPoint, - AsyncEndReceive, - //wrappedBuffer); - buf); - } - catch (SocketException e) - { - if (e.SocketErrorCode == SocketError.ConnectionReset) + m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort); + bool salvaged = false; + while (!salvaged) { - m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort); - bool salvaged = false; - while (!salvaged) + try { - try - { - m_udpSocket.BeginReceiveFrom( - //wrappedBuffer.Instance.Data, - buf.Data, - 0, - UDPPacketBuffer.BUFFER_SIZE, - SocketFlags.None, - ref buf.RemoteEndPoint, - AsyncEndReceive, - //wrappedBuffer); - buf); - salvaged = true; - } - catch (SocketException) { } - catch (ObjectDisposedException) { return; } + m_udpSocket.BeginReceiveFrom( + buf.Data, + 0, + buf.Data.Length, + SocketFlags.None, + ref buf.RemoteEndPoint, + AsyncEndReceive, + buf); + salvaged = true; } - - m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); + catch (SocketException) { } + catch (ObjectDisposedException) { return; } } + + m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); } - catch (ObjectDisposedException e) - { - m_log.Error( - string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); - } - catch (Exception e) - { - m_log.Error( - string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); - } + } + catch (Exception e) + { + m_log.Error( + string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); } } @@ -453,11 +434,6 @@ namespace OpenMetaverse UdpReceives, se.ErrorCode), se); } - catch (ObjectDisposedException e) - { - m_log.Error( - string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); - } catch (Exception e) { m_log.Error( @@ -465,14 +441,12 @@ namespace OpenMetaverse } finally { -// if (UsePools) -// Pool.ReturnObject(buffer); - AsyncBeginReceive(); } } } +/* not in use public void AsyncBeginSend(UDPPacketBuffer buf) { // if (IsRunningOutbound) @@ -511,9 +485,11 @@ namespace OpenMetaverse catch (SocketException) { } catch (ObjectDisposedException) { } } - +*/ public void SyncSend(UDPPacketBuffer buf) { + if(buf.RemoteEndPoint == null) + return; // already expired try { m_udpSocket.SendTo( @@ -527,7 +503,7 @@ namespace OpenMetaverse } catch (SocketException e) { - m_log.Warn("[UDPBASE]: sync send SocketException {0} " + e.Message); + m_log.WarnFormat("[UDPBASE]: sync send SocketException {0} {1}", buf.RemoteEndPoint, e.Message); } catch (ObjectDisposedException) { } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index f8ec97ae83..3277638697 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs @@ -66,9 +66,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public Int64 MinimumAdaptiveThrottleRate; - /// Amount of the texture throttle to steal for the task throttle - public double CannibalizeTextureRate; - public int ClientMaxRate; public float BrustTime; @@ -104,12 +101,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); AdaptiveThrottlesEnabled = false; MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000); - - // http textures do use udp bandwidth setting -// CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); -// CannibalizeTextureRate = Util.Clamp(CannibalizeTextureRate,0.0, 0.9); - CannibalizeTextureRate = 0f; - } catch (Exception) { } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs index 76f4c6f86e..1f978e13c3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs @@ -189,8 +189,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Process all the pending adds OutgoingPacket pendingAdd; while (m_pendingAdds.TryDequeue(out pendingAdd)) + { if (pendingAdd != null) m_packets[pendingAdd.SequenceNumber] = pendingAdd; + } // Process all the pending removes, including updating statistics and round-trip times PendingAck pendingAcknowledgement; @@ -204,13 +206,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_packets.Remove(pendingAcknowledgement.SequenceNumber); + // Update stats + Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); + + ackedPacket.Client.FreeUDPBuffer(ackedPacket.Buffer); + ackedPacket.Buffer = null; + // As with other network applications, assume that an acknowledged packet is an // indication that the network can handle a little more load, speed up the transmission ackedPacket.Client.FlowThrottle.AcknowledgePackets(1); - // Update stats - Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); - if (!pendingAcknowledgement.FromResend) { // Calculate the round-trip time for this packet and its ACK @@ -244,6 +249,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Update stats Interlocked.Add(ref removedPacket.Client.UnackedBytes, -removedPacket.Buffer.DataLength); + + removedPacket.Client.FreeUDPBuffer(removedPacket.Buffer); + removedPacket.Buffer = null; } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index d36d770152..5205576246 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -953,13 +953,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return; } - // Saving attachments for NPCs messes them up for the real owner! - INPCModule module = m_scene.RequestModuleInterface(); - if (module != null) - { - if (module.IsNPC(sp.UUID, m_scene)) - return; - } + if(sp.IsNPC) + return; if (grp.HasGroupChanged) { diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs index 4e1958a9c4..10bc6aa188 100644 --- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs @@ -77,7 +77,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule } scene.EventManager.OnAvatarKilled += KillAvatar; - scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel; } public void RemoveRegion(Scene scene) @@ -86,7 +85,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule m_scenel.Remove(scene.RegionInfo.RegionHandle); scene.EventManager.OnAvatarKilled -= KillAvatar; - scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; } public void RegionLoaded(Scene scene) @@ -177,31 +175,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule deadAvatar.setHealthWithUpdate(100.0f); deadAvatar.Scene.TeleportClientHome(deadAvatar.UUID, deadAvatar.ControllingClient); } - - private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) - { - try - { - ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); - if (obj == null) - return; - if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0 - || avatar.Scene.RegionInfo.RegionSettings.AllowDamage) - { - avatar.Invulnerable = false; - } - else - { - avatar.Invulnerable = true; - if (avatar.Health < 100.0f) - { - avatar.setHealthWithUpdate(100.0f); - } - } - } - catch (Exception) - { - } - } } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index d6c65a1e3f..69c1e4edce 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -526,16 +526,23 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess item.AssetType = (int)AssetType.Object; item.AssetID = asset.FullID; - if (DeRezAction.SaveToExistingUserInventoryItem == action) + if (action == DeRezAction.SaveToExistingUserInventoryItem) { m_Scene.InventoryService.UpdateItem(item); } else { - AddPermissions(item, objlist[0], objlist, remoteClient); + bool isowner = remoteClient != null && item.Owner == remoteClient.AgentId; + if(action == DeRezAction.Return) + AddPermissions(item, objlist[0], objlist, null); + else if(action == DeRezAction.Delete && !isowner) + AddPermissions(item, objlist[0], objlist, null); + else + AddPermissions(item, objlist[0], objlist, remoteClient); + m_Scene.AddInventoryItem(item); - if (remoteClient != null && item.Owner == remoteClient.AgentId) + if (isowner) { remoteClient.SendInventoryItemCreateUpdate(item, 0); } @@ -1010,7 +1017,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); rootPart.ParentGroup.ResumeScripts(); - group.ScheduleGroupForFullUpdate(); + group.ScheduleGroupForFullAnimUpdate(); } else m_Scene.AddNewSceneObject(group, true, false); diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index c3f6d6b2df..83d91c40b5 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Collections.Concurrent; using System.IO; using System.Net; using System.Net.Mail; @@ -94,18 +95,31 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private object HttpListLock = new object(); - private int httpTimeout = 30000; + private object m_httpListLock = new object(); + private int m_httpTimeout = 30000; private string m_name = "HttpScriptRequests"; private OutboundUrlFilter m_outboundUrlFilter; private string m_proxyurl = ""; private string m_proxyexcepts = ""; + private float m_primPerSec = 1.0f; + private float m_primBurst = 3.0f; + private float m_primOwnerPerSec = 25.0f; + private float m_primOwnerBurst = 5.0f; + + private struct ThrottleData + { + public double lastTime; + public float count; + } + // private Dictionary m_pendingRequests; - private Scene m_scene; - // private Queue rpcQueue = new Queue(); + private ConcurrentQueue m_CompletedRequests; + private ConcurrentDictionary m_RequestsThrottle; + private ConcurrentDictionary m_OwnerRequestsThrottle; + public static SmartThreadPool ThreadPool = null; public HttpRequestModule() @@ -119,10 +133,77 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest return UUID.Zero; } + public bool CheckThrottle(uint localID, UUID ownerID) + { + ThrottleData th; + double now = Util.GetTimeStamp(); + bool ret; + + if (m_RequestsThrottle.TryGetValue(localID, out th)) + { + double delta = now - th.lastTime; + th.lastTime = now; + + float add = (float)(m_primPerSec * delta); + th.count += add; + if (th.count > m_primBurst) + th.count = m_primBurst; + + ret = th.count > 0; + if (ret) + th.count--; + } + else + { + th = new ThrottleData() + { + lastTime = now, + count = m_primBurst - 1 + }; + ret = true; + } + m_RequestsThrottle[localID] = th; + + if(!ret) + return false; + + if (m_OwnerRequestsThrottle.TryGetValue(ownerID, out th)) + { + double delta = now - th.lastTime; + th.lastTime = now; + + float add = (float)(m_primOwnerPerSec * delta); + th.count += add; + if (th.count > m_primOwnerBurst) + th.count = m_primOwnerBurst; + + ret = th.count > 0; + if (ret) + th.count--; + } + else + { + th = new ThrottleData() + { + lastTime = now, + count = m_primOwnerBurst - 1 + }; + } + m_OwnerRequestsThrottle[ownerID] = th; + + return ret; + } + public UUID StartHttpRequest( uint localID, UUID itemID, string url, List parameters, Dictionary headers, string body, out HttpInitialRequestStatus status) { + if (!CheckAllowed(new Uri(url))) + { + status = HttpInitialRequestStatus.DISALLOWED_BY_FILTER; + return UUID.Zero; + } + UUID reqID = UUID.Random(); HttpRequestClass htc = new HttpRequestClass(); @@ -207,7 +288,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest htc.ItemID = itemID; htc.Url = url; htc.ReqID = reqID; - htc.HttpTimeout = httpTimeout; + htc.HttpTimeout = m_httpTimeout; htc.OutboundBody = body; htc.ResponseHeaders = headers; htc.proxyurl = m_proxyurl; @@ -216,16 +297,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest // Same number as default HttpWebRequest.MaximumAutomaticRedirections htc.MaxRedirects = 50; - if (StartHttpRequest(htc)) - { - status = HttpInitialRequestStatus.OK; - return htc.ReqID; - } - else - { - status = HttpInitialRequestStatus.DISALLOWED_BY_FILTER; - return UUID.Zero; - } + lock (m_httpListLock) + m_pendingRequests.Add(reqID, htc); + + htc.Process(); + status = HttpInitialRequestStatus.OK; + return reqID; } /// @@ -237,34 +314,21 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest return m_outboundUrlFilter.CheckAllowed(url); } - public bool StartHttpRequest(HttpRequestClass req) - { - if (!CheckAllowed(new Uri(req.Url))) - return false; - - lock (HttpListLock) - { - m_pendingRequests.Add(req.ReqID, req); - } - - req.Process(); - - return true; - } - public void StopHttpRequest(uint m_localID, UUID m_itemID) { - if (m_pendingRequests != null) + List toremove = new List(); + lock (m_httpListLock) { - lock (HttpListLock) + foreach (HttpRequestClass tmpReq in m_pendingRequests.Values) { - HttpRequestClass tmpReq; - if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq)) + if(tmpReq.ItemID == m_itemID) { tmpReq.Stop(); - m_pendingRequests.Remove(m_itemID); + toremove.Add(tmpReq.ReqID); } } + foreach(UUID id in toremove) + m_pendingRequests.Remove(id); } } @@ -276,37 +340,35 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest * finished. I thought about setting up a queue for this, but * it will need some refactoring and this works 'enough' right now */ + public void GotCompletedRequest(HttpRequestClass req) + { + lock (m_httpListLock) + { + if (req.Removed) + return; + m_pendingRequests.Remove(req.ReqID); + m_CompletedRequests.Enqueue(req); + } + } public IServiceRequest GetNextCompletedRequest() { - lock (HttpListLock) - { - foreach (UUID luid in m_pendingRequests.Keys) - { - HttpRequestClass tmpReq; + HttpRequestClass req; + if(m_CompletedRequests.TryDequeue(out req)) + return req; - if (m_pendingRequests.TryGetValue(luid, out tmpReq)) - { - if (tmpReq.Finished) - { - return tmpReq; - } - } - } - } return null; } - public void RemoveCompletedRequest(UUID id) + public void RemoveCompletedRequest(UUID reqId) { - lock (HttpListLock) + lock (m_httpListLock) { HttpRequestClass tmpReq; - if (m_pendingRequests.TryGetValue(id, out tmpReq)) + if (m_pendingRequests.TryGetValue(reqId, out tmpReq)) { tmpReq.Stop(); - tmpReq = null; - m_pendingRequests.Remove(id); + m_pendingRequests.Remove(reqId); } } } @@ -322,17 +384,28 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest HttpRequestClass.HttpBodyMaxLenMAX = config.Configs["Network"].GetInt("HttpBodyMaxLenMAX", 16384); - m_outboundUrlFilter = new OutboundUrlFilter("Script HTTP request module", config); - int maxThreads = 15; - IConfig httpConfig = config.Configs["HttpRequestModule"]; + int maxThreads = 8; + IConfig httpConfig = config.Configs["ScriptsHttpRequestModule"]; if (httpConfig != null) { maxThreads = httpConfig.GetInt("MaxPoolThreads", maxThreads); + m_primBurst = httpConfig.GetFloat("PrimRequestsBurst", m_primBurst); + m_primPerSec = httpConfig.GetFloat("PrimRequestsPerSec", m_primPerSec); + m_primOwnerBurst = httpConfig.GetFloat("PrimOwnerRequestsBurst", m_primOwnerBurst); + m_primOwnerPerSec = httpConfig.GetFloat("PrimOwnerRequestsPerSec", m_primOwnerPerSec); + m_httpTimeout = httpConfig.GetInt("RequestsTimeOut", m_httpTimeout); + if(m_httpTimeout > 60000) + m_httpTimeout = 60000; + else if(m_httpTimeout < 200) + m_httpTimeout = 200; } m_pendingRequests = new Dictionary(); + m_CompletedRequests = new ConcurrentQueue(); + m_RequestsThrottle = new ConcurrentDictionary(); + m_OwnerRequestsThrottle = new ConcurrentDictionary(); // First instance sets this up for all sims if (ThreadPool == null) @@ -352,16 +425,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public void AddRegion(Scene scene) { - m_scene = scene; - - m_scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface(this); - if (scene == m_scene) - m_scene = null; } public void PostInitialise() @@ -406,11 +475,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest /// public HttpRequestModule RequestModule { get; set; } - private bool _finished; - public bool Finished - { - get { return _finished; } - } + public bool Finished { get; private set;} + public bool Removed{ get; set;} public static int HttpBodyMaxLenMAX = 16384; @@ -427,19 +493,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public bool HttpPragmaNoCache = true; // Request info - private UUID _itemID; - public UUID ItemID - { - get { return _itemID; } - set { _itemID = value; } - } - private uint _localID; - public uint LocalID - { - get { return _localID; } - set { _localID = value; } - } - public DateTime Next; + public UUID ReqID { get; set; } + public UUID ItemID { get; set;} + public uint LocalID { get; set;} + public string proxyurl; public string proxyexcepts; @@ -454,12 +511,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public int MaxRedirects { get; set; } public string OutboundBody; - private UUID _reqID; - public UUID ReqID - { - get { return _reqID; } - set { _reqID = value; } - } + public HttpWebRequest Request; public string ResponseBody; public List ResponseMetadata; @@ -469,10 +521,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public void Process() { - _finished = false; - - lock (HttpRequestModule.ThreadPool) - WorkItem = HttpRequestModule.ThreadPool.QueueWorkItem(new WorkItemCallback(StpSendWrapper), null); + WorkItem = HttpRequestModule.ThreadPool.QueueWorkItem(new WorkItemCallback(StpSendWrapper), null); } private object StpSendWrapper(object o) @@ -521,6 +570,9 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public void SendRequest() { + if(Removed) + return; + HttpWebResponse response = null; Stream resStream = null; byte[] buf = new byte[HttpBodyMaxLenMAX + 16]; @@ -534,6 +586,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest Request.AllowAutoRedirect = false; Request.KeepAlive = false; + Request.Timeout = HttpTimeout; //This works around some buggy HTTP Servers like Lighttpd Request.ServicePoint.Expect100Continue = false; @@ -593,7 +646,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest bstream.Write(data, 0, data.Length); } - Request.Timeout = HttpTimeout; try { // execute the request @@ -672,7 +724,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest if (response != null) response.Close(); - // We need to resubmit if ( (Status == (int)HttpStatusCode.MovedPermanently @@ -684,7 +735,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { Status = (int)OSHttpStatusCode.ClientErrorJoker; ResponseBody = "Number of redirects exceeded max redirects"; - _finished = true; + WorkItem = null; + RequestModule.GotCompletedRequest(this); } else { @@ -694,13 +746,15 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { Status = (int)OSHttpStatusCode.ClientErrorJoker; ResponseBody = "HTTP redirect code but no location header"; - _finished = true; + WorkItem = null; + RequestModule.GotCompletedRequest(this); } else if (!RequestModule.CheckAllowed(new Uri(location))) { Status = (int)OSHttpStatusCode.ClientErrorJoker; ResponseBody = "URL from HTTP redirect blocked: " + location; - _finished = true; + WorkItem = null; + RequestModule.GotCompletedRequest(this); } else { @@ -717,9 +771,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest } else { - _finished = true; + WorkItem = null; if (ResponseBody == null) ResponseBody = String.Empty; + RequestModule.GotCompletedRequest(this); } } } @@ -728,10 +783,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { try { + Removed = true; + if(WorkItem == null) + return; + if (!WorkItem.Cancel()) - { WorkItem.Cancel(true); - } } catch (Exception) { diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 2e801e35b4..ac28ceeac0 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -1204,28 +1204,33 @@ namespace OpenSim.Region.CoreModules.World.Estate } } - private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey) + private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey, bool kick) { + if (prey == UUID.Zero) + return; + EstateTeleportOneUserHomeRequest evOverride = OnEstateTeleportOneUserHomeRequest; if(evOverride != null) { - evOverride(remover_client, invoice, senderID, prey); + evOverride(remover_client, invoice, senderID, prey, kick); return; } if (!Scene.Permissions.CanIssueEstateCommand(remover_client.AgentId, false)) return; - if (prey != UUID.Zero) + ScenePresence s = Scene.GetScenePresence(prey); + if (s != null && !s.IsDeleted && !s.IsInTransit) { - ScenePresence s = Scene.GetScenePresence(prey); - if (s != null && !s.IsDeleted && !s.IsInTransit) + if (kick) { - if (!Scene.TeleportClientHome(prey, s.ControllingClient)) - { - s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); - Scene.CloseAgent(s.UUID, false); - } + s.ControllingClient.Kick("You have been kicked"); + Scene.CloseAgent(s.UUID, false); + } + else if (!Scene.TeleportClientHome(prey, s.ControllingClient)) + { + s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed "); + Scene.CloseAgent(s.UUID, false); } } } diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs index f4a174a7a7..c8b9032c36 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs @@ -204,7 +204,7 @@ namespace OpenSim.Region.CoreModules.World.Estate m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message); } - private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey) + private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey, bool kick) { if (prey == UUID.Zero) return; @@ -227,8 +227,20 @@ namespace OpenSim.Region.CoreModules.World.Estate ScenePresence p = scene.GetScenePresence(prey); if (p != null && !p.IsChildAgent && !p.IsDeleted && !p.IsInTransit) { - p.ControllingClient.SendTeleportStart(16); - scene.TeleportClientHome(prey, client); + if (kick) + { + p.ControllingClient.Kick("You have been kicked out"); + s.CloseAgent(p.UUID, false); + } + else + { + p.ControllingClient.SendTeleportStart(16); + if (!s.TeleportClientHome(prey, client)) + { + p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed"); + s.CloseAgent(p.UUID, false); + } + } return; } } @@ -259,6 +271,11 @@ namespace OpenSim.Region.CoreModules.World.Estate { p.ControllingClient.SendTeleportStart(16); scene.TeleportClientHome(p.ControllingClient.AgentId, client); + if (!s.TeleportClientHome(p.ControllingClient.AgentId, client)) + { + p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); + s.CloseAgent(p.UUID, false); + } } }); } diff --git a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs index 978c248610..2c75844fea 100644 --- a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs +++ b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs @@ -87,5 +87,6 @@ namespace OpenSim.Region.Framework.Interfaces void StopHttpRequest(uint m_localID, UUID m_itemID); IServiceRequest GetNextCompletedRequest(); void RemoveCompletedRequest(UUID id); + bool CheckThrottle(uint localID, UUID onerID); } } diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index 7509686bbb..eae6d6f44c 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs @@ -94,19 +94,15 @@ namespace OpenSim.Region.Framework.Scenes m_inventoryDeletes.Enqueue(dtis); } - if (Enabled) - lock (m_inventoryTicker) - m_inventoryTicker.Start(); - - // Visually remove it, even if it isnt really gone yet. This means that if we crash before the object - // has gone to inventory, it will reappear in the region again on restart instead of being lost. - // This is not ideal since the object will still be available for manipulation when it should be, but it's - // better than losing the object for now. if (permissionToDelete) { foreach (SceneObjectGroup g in objectGroups) g.DeleteGroupFromScene(false); } + + if (Enabled) + lock (m_inventoryTicker) + m_inventoryTicker.Start(); } private void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e) diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index f76f8828d0..edc8886fbf 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -539,7 +539,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// public event ScriptChangedEvent OnScriptChangedEvent; - public delegate void ScriptChangedEvent(uint localID, uint change); + public delegate void ScriptChangedEvent(uint localID, uint change, object data); public delegate void ScriptControlEvent(UUID item, UUID avatarID, uint held, uint changed); @@ -1185,7 +1185,7 @@ namespace OpenSim.Region.Framework.Scenes } } - public void TriggerOnScriptChangedEvent(uint localID, uint change) + public void TriggerOnScriptChangedEvent(uint localID, uint change, object parameter = null) { ScriptChangedEvent handlerScriptChangedEvent = OnScriptChangedEvent; if (handlerScriptChangedEvent != null) @@ -1194,7 +1194,7 @@ namespace OpenSim.Region.Framework.Scenes { try { - d(localID, change); + d(localID, change, parameter); } catch (Exception e) { diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index e6e035402f..debcad373d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -2110,7 +2110,7 @@ namespace OpenSim.Region.Framework.Scenes // build a list of eligible objects List deleteIDs = new List(); List deleteGroups = new List(); - List takeGroups = new List(); + List takeCopyGroups = new List(); List takeDeleteGroups = new List(); ScenePresence sp = null; @@ -2119,11 +2119,10 @@ namespace OpenSim.Region.Framework.Scenes else if(action != DeRezAction.Return) return; // only Return can be called without a client - // Start with true for both, then remove the flags if objects - // that we can't derez are part of the selection - bool permissionToTake = true; - bool permissionToTakeCopy = true; - bool permissionToDelete = true; + // this is not as 0.8x code + // 0.8x did refuse all operation is not allowed on all objects + // this will do it on allowed objects + // current viewers only ask if all allowed foreach (uint localID in localIDs) { @@ -2136,8 +2135,8 @@ namespace OpenSim.Region.Framework.Scenes continue; } - // Already deleted by someone else - if (part.ParentGroup.IsDeleted) + SceneObjectGroup grp = part.ParentGroup; + if (grp == null || grp.IsDeleted) { //Client still thinks the object exists, kill it deleteIDs.Add(localID); @@ -2145,132 +2144,105 @@ namespace OpenSim.Region.Framework.Scenes } // Can't delete child prims - if (part != part.ParentGroup.RootPart) + if (part != grp.RootPart) continue; - SceneObjectGroup grp = part.ParentGroup; if (grp.IsAttachment) - continue; + { + if(!sp.IsGod || action != DeRezAction.Return || action != DeRezAction.Delete) + continue; + // this may break the attachment, but its a security action + // viewers don't allow it anyways + } // If child prims have invalid perms, fix them grp.AdjustChildPrimPermissions(false); - if (remoteClient == null) + switch (action) { - // Autoreturn has a null client. Nothing else does. So - // allow only returns - if (action != DeRezAction.Return) + case DeRezAction.SaveToExistingUserInventoryItem: { - m_log.WarnFormat( - "[AGENT INVENTORY]: Ignoring attempt to {0} {1} {2} without a client", - action, grp.Name, grp.UUID); - return; + if (Permissions.CanTakeCopyObject(grp, sp)) + takeCopyGroups.Add(grp); + break; } - permissionToTakeCopy = false; - } - else - { - if (action == DeRezAction.TakeCopy) + case DeRezAction.TakeCopy: { - if (!Permissions.CanTakeCopyObject(grp, sp)) - permissionToTakeCopy = false; - } - else - { - permissionToTakeCopy = false; - } - if (!Permissions.CanTakeObject(grp, sp)) - permissionToTake = false; - - if (!Permissions.CanDeleteObject(grp, remoteClient)) - permissionToDelete = false; - } - - // Handle god perms - if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) - { - permissionToTake = true; - permissionToTakeCopy = true; - permissionToDelete = true; - } - - // If we're re-saving, we don't even want to delete - if (action == DeRezAction.SaveToExistingUserInventoryItem) - permissionToDelete = false; - - // if we want to take a copy, we also don't want to delete - // Note: after this point, the permissionToTakeCopy flag - // becomes irrelevant. It already includes the permissionToTake - // permission and after excluding no copy items here, we can - // just use that. - if (action == DeRezAction.TakeCopy) - { - // If we don't have permission, stop right here - if (!permissionToTakeCopy) - { - remoteClient.SendAlertMessage("You don't have permission to take the object"); - return; + if (Permissions.CanTakeCopyObject(grp, sp)) + takeCopyGroups.Add(grp); + break; } - permissionToTake = true; - // Don't delete - permissionToDelete = false; - } - - if (action == DeRezAction.Return) - { - if (remoteClient != null) + case DeRezAction.Take: { - if (Permissions.CanReturnObjects( - null, - remoteClient, - new List() {grp})) + if (Permissions.CanTakeObject(grp, sp)) + takeDeleteGroups.Add(grp); + break; + } + + case DeRezAction.GodTakeCopy: + { + if((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) + takeCopyGroups.Add(grp); + break; + } + + case DeRezAction.Delete: + { + if (Permissions.CanDeleteObject(grp, remoteClient)) { - permissionToTake = true; - permissionToDelete = true; - if(AddToReturns) - AddReturn(grp.OwnerID == grp.GroupID ? grp.LastOwnerID : grp.OwnerID, grp.Name, grp.AbsolutePosition, - "parcel owner return"); + if(m_useTrashOnDelete || (sp.IsGod && grp.OwnerID != sp.UUID)) + takeDeleteGroups.Add(grp); + else + deleteGroups.Add(grp); } + break; } - else // Auto return passes through here with null agent - { - permissionToTake = true; - permissionToDelete = true; - } - } - if (permissionToDelete) - { - if (permissionToTake) - takeDeleteGroups.Add(grp); - else - deleteGroups.Add(grp); - deleteIDs.Add(grp.LocalId); + case DeRezAction.Return: + { + if (remoteClient != null) + { + if (Permissions.CanReturnObjects( null, remoteClient, new List() {grp})) + { + takeDeleteGroups.Add(grp); + if (AddToReturns) + AddReturn(grp.OwnerID == grp.GroupID ? grp.LastOwnerID : grp.OwnerID, grp.Name, grp.AbsolutePosition, + "parcel owner return"); + } + } + else // Auto return passes through here with null agent + { + takeDeleteGroups.Add(grp); + } + break; + } + + default: + break; } - else if(permissionToTake) - takeGroups.Add(grp); } - SendKillObject(deleteIDs); + if(deleteIDs.Count > 0) + SendKillObject(deleteIDs); if (takeDeleteGroups.Count > 0) { - m_asyncSceneObjectDeleter.DeleteToInventory( - action, destinationID, takeDeleteGroups, remoteClient, - true); + m_asyncSceneObjectDeleter.DeleteToInventory(action, destinationID, takeDeleteGroups, + remoteClient, true); } - if (takeGroups.Count > 0) + + if (takeCopyGroups.Count > 0) { - m_asyncSceneObjectDeleter.DeleteToInventory( - action, destinationID, takeGroups, remoteClient, - false); + m_asyncSceneObjectDeleter.DeleteToInventory(action, destinationID, takeCopyGroups, + remoteClient, false); } + if (deleteGroups.Count > 0) { foreach (SceneObjectGroup g in deleteGroups) - DeleteSceneObject(g, true); + DeleteSceneObject(g, false); } } diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index b526fe936b..ea037beb30 100755 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1913,9 +1913,8 @@ namespace OpenSim.Region.Framework.Scenes { if (parentGroup.OwnerID == child.OwnerID) { - parentGroup.LinkToGroup(child); - child.DetachFromBackup(); + parentGroup.LinkToGroup(child); // this is here so physics gets updated! // Don't remove! Bad juju! Stay away! or fix physics! @@ -1943,7 +1942,6 @@ namespace OpenSim.Region.Framework.Scenes */ parentGroup.AdjustChildPrimPermissions(false); parentGroup.HasGroupChanged = true; - parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true); parentGroup.ScheduleGroupForFullAnimUpdate(); Monitor.Exit(m_linkLock); } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index bf217a5f3c..8899e96dba 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -154,7 +154,7 @@ namespace OpenSim.Region.Framework.Scenes // We're adding this to a prim we don't own. Force // owner change taskItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; - + taskItem.LastOwnerID = item.Owner; } else { diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index a23ebbfa46..312ce26e4a 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -3242,8 +3242,6 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup.Scene.GetNumberOfClients() == 0) return; - ParentGroup.QueueForUpdateCheck(); - bool isfull = false; if (ParentGroup.IsAttachment) { @@ -3254,6 +3252,8 @@ namespace OpenSim.Region.Framework.Scenes lock (UpdateFlagLock) UpdateFlag |= update; + ParentGroup.QueueForUpdateCheck(); + ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, isfull); } @@ -4439,10 +4439,10 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectSerializer.SOPToXml2(xmlWriter, this, new Dictionary()); } - public void TriggerScriptChangedEvent(Changed val) + public void TriggerScriptChangedEvent(Changed val, object data = null) { if (ParentGroup != null && ParentGroup.Scene != null) - ParentGroup.Scene.EventManager.TriggerOnScriptChangedEvent(LocalId, (uint)val); + ParentGroup.Scene.EventManager.TriggerOnScriptChangedEvent(LocalId, (uint)val, data); } public void TrimPermissions() @@ -5130,11 +5130,10 @@ namespace OpenSim.Region.Framework.Scenes if (changeFlags == 0) return; - m_shape.TextureEntry = newTex.GetBytes(); + m_shape.TextureEntry = newTex.GetBytes(9); TriggerScriptChangedEvent(changeFlags); ParentGroup.HasGroupChanged = true; - ScheduleFullUpdate(); - + ScheduleUpdate(PrimUpdateFlags.Textures); } /// @@ -5160,10 +5159,10 @@ namespace OpenSim.Region.Framework.Scenes if (changeFlags == 0) return; - m_shape.TextureEntry = newTex.GetBytes(); + m_shape.TextureEntry = newTex.GetBytes(9); TriggerScriptChangedEvent(changeFlags); ParentGroup.HasGroupChanged = true; - ScheduleFullUpdate(); + ScheduleUpdate(PrimUpdateFlags.Textures); } internal void UpdatePhysicsSubscribedEvents() @@ -5575,20 +5574,26 @@ namespace OpenSim.Region.Framework.Scenes // handle osVolumeDetect public void ScriptSetVolumeDetect(bool makeVolumeDetect) { + if(ParentGroup.IsDeleted) + return; + if(_parentID == 0) { - // if root prim do it via SOG + // if root prim do it is like llVolumeDetect ParentGroup.ScriptSetVolumeDetect(makeVolumeDetect); return; } - bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0); - bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0); - bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0); + if(ParentGroup.IsVolumeDetect) + return; // entire linkset is phantom already + + bool wasUsingPhysics = ParentGroup.UsesPhysics; + bool wasTemporary = ParentGroup.IsTemporary; + bool wasPhantom = ParentGroup.IsPhantom; if(PhysActor != null) PhysActor.Building = true; - UpdatePrimFlags(wasUsingPhysics,wasTemporary,wasPhantom,makeVolumeDetect,false); + UpdatePrimFlags(wasUsingPhysics, wasTemporary, wasPhantom, makeVolumeDetect, false); } protected static int m_animationSequenceNumber = (int)(Util.GetTimeStampTicks() & 0x5fffafL); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 4934b8327c..a0f895933f 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -815,10 +815,10 @@ namespace OpenSim.Region.Framework.Scenes m_items.LockItemsForWrite(true); m_items.Add(item.ItemID, item); m_items.LockItemsForWrite(false); - if (allowedDrop) - m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); - else - m_part.TriggerScriptChangedEvent(Changed.INVENTORY); + if (allowedDrop) + m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP, item.ItemID); + else + m_part.TriggerScriptChangedEvent(Changed.INVENTORY); m_part.AggregateInnerPerms(); m_inventorySerial++; diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index cfb1be4f98..1c5d23d9b4 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -507,7 +507,19 @@ namespace OpenSim.Region.Framework.Scenes /// /// Physical scene representation of this Avatar. /// - public PhysicsActor PhysicsActor { get; private set; } + + PhysicsActor m_physActor; + public PhysicsActor PhysicsActor + { + get + { + return m_physActor; + } + private set + { + m_physActor = value; + } + } /// /// Record user movement inputs. @@ -523,7 +535,12 @@ namespace OpenSim.Region.Framework.Scenes public bool Invulnerable { - set { m_invulnerable = value; } + set + { + m_invulnerable = value; + if(value && Health != 100.0f) + Health = 100.0f; + } get { return m_invulnerable; } } @@ -1636,15 +1653,15 @@ namespace OpenSim.Region.Framework.Scenes /// public void RemoveFromPhysicalScene() { - if (PhysicsActor != null) + PhysicsActor pa = Interlocked.Exchange(ref m_physActor, null); + if (pa != null) { // PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; - PhysicsActor.OnOutOfBounds -= OutOfBoundsCall; - PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; - PhysicsActor.UnSubscribeEvents(); - m_scene.PhysicsScene.RemoveAvatar(PhysicsActor); - PhysicsActor = null; + pa.OnOutOfBounds -= OutOfBoundsCall; + pa.OnCollisionUpdate -= PhysicsCollisionUpdate; + pa.UnSubscribeEvents(); + m_scene.PhysicsScene.RemoveAvatar(pa); } // else // { @@ -2537,7 +2554,7 @@ namespace OpenSim.Region.Framework.Scenes m_pos.X = 127f; m_pos.Y = 127f; m_pos.Z = 127f; - m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903"); + m_log.Error("[AVATAR]: NonFinite Avatar on lastFiniteposition also. Reset Position. Mantis this please. Error #9999903"); } if(isphysical) @@ -5007,16 +5024,17 @@ namespace OpenSim.Region.Framework.Scenes PhysicsScene scene = m_scene.PhysicsScene; Vector3 pVec = AbsolutePosition; - PhysicsActor = scene.AddAvatar( + PhysicsActor pa = scene.AddAvatar( LocalId, Firstname + "." + Lastname, pVec, Appearance.AvatarBoxSize,Appearance.AvatarFeetOffset, isFlying); - PhysicsActor.Orientation = m_bodyRot; + pa.Orientation = m_bodyRot; //PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; - PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; - PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong - PhysicsActor.SubscribeEvents(100); - PhysicsActor.LocalID = LocalId; - PhysicsActor.SetAlwaysRun = m_setAlwaysRun; + pa.OnCollisionUpdate += PhysicsCollisionUpdate; + pa.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong + pa.SubscribeEvents(100); + pa.LocalID = LocalId; + pa.SetAlwaysRun = m_setAlwaysRun; + PhysicsActor = pa; } private void OutOfBoundsCall(Vector3 pos) diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs index a60381afb7..020c7bed99 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs @@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return iout; } +/* // new using terrain data and patchs indexes public static List CreateLayerDataPackets(TerrainData terrData, int[] map) { @@ -213,6 +214,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return ret; } +*/ public static void CreatePatchFromTerrainData(BitPack output, TerrainData terrData, int patchX, int patchY) { diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 516f9eb4bd..822439fb5e 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -323,7 +323,7 @@ namespace OpenSim.Region.OptionalModules.Materials } if(facechanged) - part.Shape.TextureEntry = te.GetBytes(); + part.Shape.TextureEntry = te.GetBytes(9); if(facechanged || partchanged) { @@ -632,7 +632,7 @@ namespace OpenSim.Region.OptionalModules.Materials faceEntry.MaterialID = id; //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id); // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually - sop.Shape.TextureEntry = te.GetBytes(); + sop.Shape.TextureEntry = te.GetBytes(9); } if(oldid != UUID.Zero) diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs index 40c6b983b0..4e9216db30 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs @@ -47,9 +47,9 @@ public class BSActorAvatarMove : BSActor // The amount the step up is applying. Used to smooth stair walking. float m_lastStepUp; - // There are times the velocity is set but we don't want to inforce stationary until the - // real velocity drops. - bool m_waitingForLowVelocityForStationary = false; + // There are times the velocity or force is set but we don't want to inforce + // stationary until some tick in the future and the real velocity drops. + int m_waitingForLowVelocityForStationary = 0; public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) @@ -114,14 +114,18 @@ public class BSActorAvatarMove : BSActor m_velocityMotor.Enabled = true; m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,SetVelocityAndTarget,vel={1}, targ={2}", m_controllingPrim.LocalID, vel, targ); - m_waitingForLowVelocityForStationary = false; + m_waitingForLowVelocityForStationary = 0; } }); } public void SuppressStationayCheckUntilLowVelocity() { - m_waitingForLowVelocityForStationary = true; + m_waitingForLowVelocityForStationary = 1; + } + public void SuppressStationayCheckUntilLowVelocity(int waitTicks) + { + m_waitingForLowVelocityForStationary = waitTicks; } // If a movement motor has not been created, create one and start the movement @@ -143,7 +147,7 @@ public class BSActorAvatarMove : BSActor m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty; m_walkingUpStairs = 0; - m_waitingForLowVelocityForStationary = false; + m_waitingForLowVelocityForStationary = 0; } } @@ -194,15 +198,17 @@ public class BSActorAvatarMove : BSActor // if colliding with something stationary and we're not doing volume detect . if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect) { - if (m_waitingForLowVelocityForStationary) + if (m_waitingForLowVelocityForStationary-- <= 0) { // if waiting for velocity to drop and it has finally dropped, we can be stationary + // m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,waitingForLowVelocity {1}", + // m_controllingPrim.LocalID, m_waitingForLowVelocityForStationary); if (m_controllingPrim.RawVelocity.LengthSquared() < BSParam.AvatarStopZeroThresholdSquared) { - m_waitingForLowVelocityForStationary = false; + m_waitingForLowVelocityForStationary = 0; } } - if (!m_waitingForLowVelocityForStationary) + if (m_waitingForLowVelocityForStationary <= 0) { m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); m_controllingPrim.IsStationary = true; diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs old mode 100644 new mode 100755 index 2ca7dbc498..f971e59166 --- a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs @@ -701,7 +701,7 @@ public sealed class BSCharacter : BSPhysObject } if (m_moveActor != null) { - m_moveActor.SuppressStationayCheckUntilLowVelocity(); + m_moveActor.SuppressStationayCheckUntilLowVelocity(BSParam.AvatarAddForceFrames); } }); } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs index 495f752e46..d80b050de6 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs @@ -149,6 +149,7 @@ public static class BSParam public static float AvatarHeightHighFudge { get; private set; } public static float AvatarFlyingGroundMargin { get; private set; } public static float AvatarFlyingGroundUpForce { get; private set; } + public static int AvatarAddForceFrames { get; private set; } public static float AvatarTerminalVelocity { get; private set; } public static float AvatarContactProcessingThreshold { get; private set; } public static float AvatarAddForcePushFactor { get; private set; } @@ -634,6 +635,8 @@ public static class BSParam 5f ), new ParameterDefn("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin", 2.0f ), + new ParameterDefn("AvatarAddForceFrames", "Frames to allow AddForce to apply before checking for stationary", + 10 ), new ParameterDefn("AvatarTerminalVelocity", "Terminal Velocity of falling avatar", -54.0f ), new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs old mode 100644 new mode 100755 index 3120d04038..a6a2dd890e --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -221,7 +221,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// private static void CmdHandlerThreadLoop() { - while (true) + bool running = true; + while (running) { try { @@ -230,7 +231,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api DoOneCmdHandlerPass(); Watchdog.UpdateThread(); } - catch ( System.Threading.ThreadAbortException) { } + catch ( System.Threading.ThreadAbortException) + { + Thread.ResetAbort(); + running = false; + } catch (Exception e) { m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 943141cba3..ab3562f35b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1936,45 +1936,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return; - Primitive.TextureEntry tex = part.Shape.Textures; - int nsides = GetNumberOfSides(part); - Color4 texcolor; - - if (face >= 0 && face < nsides) - { - texcolor = tex.CreateFace((uint)face).RGBA; - texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f); - texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f); - texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f); - tex.FaceTextures[face].RGBA = texcolor; - part.UpdateTextureEntry(tex); - return; - } - else if (face == ScriptBaseClass.ALL_SIDES) - { - for (uint i = 0; i < nsides; i++) - { - if (tex.FaceTextures[i] != null) - { - texcolor = tex.FaceTextures[i].RGBA; - texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f); - texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f); - texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f); - tex.FaceTextures[i].RGBA = texcolor; - } - texcolor = tex.DefaultTexture.RGBA; - texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f); - texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f); - texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f); - tex.DefaultTexture.RGBA = texcolor; - } - part.UpdateTextureEntry(tex); - return; - } - - if (face == ScriptBaseClass.ALL_SIDES) - face = SceneObjectPart.ALL_SIDES; - m_host.SetFaceColorAlpha(face, color, null); } @@ -3577,7 +3538,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void doObjectRez(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param, bool atRoot) { m_host.AddScriptLPS(1); - if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s)) + if (string.IsNullOrEmpty(inventory) || Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s)) return; float dist = (float)llVecDist(llGetPos(), pos); @@ -10653,7 +10614,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return false; texface.MaterialID = id; - part.Shape.TextureEntry = tex.GetBytes(); + part.Shape.TextureEntry = tex.GetBytes(9); m_materialsModule.RemoveMaterial(oldid); return true; } @@ -10710,7 +10671,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return false; texface.MaterialID = id; - part.Shape.TextureEntry = tex.GetBytes(); + part.Shape.TextureEntry = tex.GetBytes(9); m_materialsModule.RemoveMaterial(oldid); return true; } @@ -10777,7 +10738,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return false; texface.MaterialID = id; - part.Shape.TextureEntry = tex.GetBytes(); + part.Shape.TextureEntry = tex.GetBytes(9); m_materialsModule.RemoveMaterial(oldid); return true; } @@ -13945,14 +13906,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Key llHTTPRequest(string url, LSL_List parameters, string body) { - // Partial implementation: support for parameter flags needed - // see http://wiki.secondlife.com/wiki/LlHTTPRequest - // parameter flags support are implemented in ScriptsHttpRequests.cs - // in StartHttpRequest - m_host.AddScriptLPS(1); - IHttpRequestModule httpScriptMod = - m_ScriptEngine.World.RequestModuleInterface(); + IHttpRequestModule httpScriptMod = m_ScriptEngine.World.RequestModuleInterface(); + if(httpScriptMod == null) + return ""; + + if(!httpScriptMod.CheckThrottle(m_host.LocalId, m_host.OwnerID)) + return UUID.Zero.ToString(); + List param = new List(); bool ok; Int32 flag; @@ -14123,8 +14084,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } HttpInitialRequestStatus status; - UUID reqID - = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body, out status); + UUID reqID = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body, out status); if (status == HttpInitialRequestStatus.DISALLOWED_BY_FILTER) Error("llHttpRequest", string.Format("Request to {0} disallowed by filter", url)); @@ -14132,7 +14092,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (reqID != UUID.Zero) return reqID.ToString(); else - return null; + return ""; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 9d5f67014c..dabd399b0a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3629,7 +3629,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar"); - World.ForEachRootScenePresence(delegate(ScenePresence sp) + World.ForEachRootScenePresence(delegate (ScenePresence sp) { if (sp.Firstname == FirstName && sp.Lastname == SurName) { @@ -3643,18 +3643,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api }); } - public LSL_Float osGetHealth(string avatar) + public void osKickAvatar(LSL_Key agentKey, string alert) + { + CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar"); + + UUID id; + if (!UUID.TryParse(agentKey, out id) || id == UUID.Zero) + return; + + ScenePresence sp = World.GetScenePresence(id); + if(sp == null) + return; + + // kick client... + if (alert != null) + sp.ControllingClient.Kick(alert); + + // ...and close on our side + sp.Scene.CloseAgent(id, false); + } + + public LSL_Float osGetHealth(LSL_Key agentKey) { CheckThreatLevel(ThreatLevel.None, "osGetHealth"); LSL_Float health = new LSL_Float(-1); - ScenePresence presence = World.GetScenePresence(new UUID(avatar)); + + UUID id; + if (!UUID.TryParse(agentKey, out id) || id == UUID.Zero) + return health; + + ScenePresence presence = World.GetScenePresence(id); if (presence != null) health = presence.Health; return health; } - public void osCauseDamage(string avatar, double damage) + public void osCauseDamage(LSL_Key avatar, LSL_Float damage) { CheckThreatLevel(ThreatLevel.High, "osCauseDamage"); @@ -3683,7 +3708,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - public void osCauseHealing(string avatar, double healing) + public void osCauseHealing(LSL_Key avatar, LSL_Float healing) { CheckThreatLevel(ThreatLevel.High, "osCauseHealing"); @@ -3704,7 +3729,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api presence.setHealthWithUpdate(health); } - public void osSetHealth(string avatar, double health) + public void osSetHealth(LSL_Key avatar, LSL_Float health) { CheckThreatLevel(ThreatLevel.High, "osSetHealth"); @@ -3722,7 +3747,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - public void osSetHealRate(string avatar, double healrate) + public void osSetHealRate(LSL_Key avatar, LSL_Float healrate) { CheckThreatLevel(ThreatLevel.High, "osSetHealRate"); @@ -3737,7 +3762,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api presence.HealRate = (float)healrate; } - public LSL_Float osGetHealRate(string avatar) + public LSL_Float osGetHealRate(LSL_Key avatar) { CheckThreatLevel(ThreatLevel.None, "osGetHealRate"); @@ -3864,29 +3889,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return date.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ"); } - /// - /// Get the description from an inventory item - /// - /// - /// Item description - public LSL_String osGetInventoryDesc(string item) - { - CheckThreatLevel(); - - lock (m_host.TaskInventory) - { - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == item) - { - return inv.Value.Description.ToString(); - } - } - } - - return String.Empty; - } - /// /// Invite user to the group this object is set to /// @@ -4849,8 +4851,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return Math.Atan2(mcross, dot); } - -//******* link sound public void osAdjustSoundVolume(LSL_Integer linknum, LSL_Float volume) { m_host.AddScriptLPS(1); @@ -5381,5 +5381,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 1; } + public LSL_Key osGetInventoryLastOwner(LSL_String itemNameorid) + { + m_host.AddScriptLPS(1); + + TaskInventoryItem item = null; + UUID itemID; + if (UUID.TryParse(itemNameorid, out itemID)) + item = m_host.Inventory.GetInventoryItem(itemID); + else + item = m_host.Inventory.GetInventoryItem(itemNameorid); + + if (item == null) + return UUID.Zero.ToString(); + + UUID id = item.LastOwnerID; + if(id == UUID.Zero) + id= item.OwnerID; + return id.ToString(); + } + + public LSL_String osGetInventoryName(LSL_Key itemId) + { + m_host.AddScriptLPS(1); + + TaskInventoryItem item = null; + UUID itemID; + if (UUID.TryParse(itemId, out itemID)) + item = m_host.Inventory.GetInventoryItem(itemID); + + if (item == null) + return String.Empty; + + return item.Name; + } + + public LSL_String osGetInventoryDesc(LSL_String itemNameorid) + { + m_host.AddScriptLPS(1); + + TaskInventoryItem item = null; + UUID itemID; + if (UUID.TryParse(itemNameorid, out itemID)) + item = m_host.Inventory.GetInventoryItem(itemID); + else + item = m_host.Inventory.GetInventoryItem(itemNameorid); + + if (item == null) + return String.Empty; + + return item.Description; + } + + public LSL_Key osGetLastChangedEventKey() + { + m_host.AddScriptLPS(1); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, 0); + if (detectedParams == null) + return String.Empty; + return detectedParams.Key.ToString(); + } } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/HttpRequest.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/HttpRequest.cs index 629b14bbb2..166f2d9814 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/HttpRequest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/HttpRequest.cs @@ -48,14 +48,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins if (m_CmdManager.m_ScriptEngine.World == null) return; - IHttpRequestModule iHttpReq = - m_CmdManager.m_ScriptEngine.World.RequestModuleInterface(); - - HttpRequestClass httpInfo = null; - - if (iHttpReq != null) - httpInfo = (HttpRequestClass)iHttpReq.GetNextCompletedRequest(); + IHttpRequestModule iHttpReq = m_CmdManager.m_ScriptEngine.World.RequestModuleInterface(); + if(iHttpReq == null) + return; + HttpRequestClass httpInfo = (HttpRequestClass)iHttpReq.GetNextCompletedRequest(); while (httpInfo != null) { //m_log.Debug("[AsyncLSL]:" + httpInfo.response_body + httpInfo.status); @@ -67,8 +64,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // implemented here yet anyway. Should be fixed if/when maxsize // is supported - iHttpReq.RemoveCompletedRequest(httpInfo.ReqID); - object[] resobj = new object[] { new LSL_Types.LSLString(httpInfo.ReqID.ToString()), diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 12e8103b3d..49b3f74e8c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -379,15 +379,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces int osGetSimulatorMemory(); int osGetSimulatorMemoryKB(); - void osKickAvatar(string FirstName,string SurName,string alert); + void osKickAvatar(string FirstName, string SurName, string alert); + void osKickAvatar(LSL_Key agentId, string alert); void osSetSpeed(string UUID, LSL_Float SpeedModifier); void osSetOwnerSpeed(LSL_Float SpeedModifier); - LSL_Float osGetHealth(string avatar); - void osCauseHealing(string avatar, double healing); - void osSetHealth(string avatar, double health); - void osSetHealRate(string avatar, double health); - LSL_Float osGetHealRate(string avatar); - void osCauseDamage(string avatar, double damage); + LSL_Float osGetHealth(key agentId); + void osCauseHealing(key agentId, LSL_Float healing); + void osSetHealth(key agentId, LSL_Float health); + void osSetHealRate(key agentId, LSL_Float health); + LSL_Float osGetHealRate(key agentId); + void osCauseDamage(key avatar, LSL_Float damage); void osForceOtherSit(string avatar); void osForceOtherSit(string avatar, string target); LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules); @@ -400,8 +401,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String osUnixTimeToTimestamp(LSL_Integer time); - LSL_String osGetInventoryDesc(string item); - LSL_Integer osInviteToGroup(LSL_Key agentId); LSL_Integer osEjectFromGroup(LSL_Key agentId); @@ -546,5 +545,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Integer osApproxEquals(vector va, vector vb, LSL_Float margin); LSL_Integer osApproxEquals(rotation ra, rotation rb); LSL_Integer osApproxEquals(rotation ra, rotation rb, LSL_Float margin); + LSL_Key osGetInventoryLastOwner(LSL_String itemNameOrId); + LSL_String osGetInventoryName(LSL_Key itemId); + LSL_String osGetInventoryDesc(LSL_String itemNameOrId); + LSL_Key osGetLastChangedEventKey(); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 49f46b7b4c..8b70128e71 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -35,7 +35,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public partial class ScriptBaseClass { // SCRIPTS CONSTANTS - public static readonly LSLInteger OS_APIVERSION = 2; + public static readonly LSLInteger OS_APIVERSION = 3; public static readonly LSLInteger TRUE = 1; public static readonly LSLInteger FALSE = 0; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index 94df1eaa76..fb491e4923 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -965,11 +965,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osGetSimulatorMemoryKB(); } - public void osKickAvatar(string FirstName,string SurName,string alert) + public void osKickAvatar(string FirstName, string SurName, string alert) { m_OSSL_Functions.osKickAvatar(FirstName, SurName, alert); } + public void osKickAvatar(LSL_Key agentId, string alert) + { + m_OSSL_Functions.osKickAvatar(agentId, alert); + } + public void osSetSpeed(string UUID, LSL_Float SpeedModifier) { m_OSSL_Functions.osSetSpeed(UUID, SpeedModifier); @@ -980,32 +985,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osSetOwnerSpeed(SpeedModifier); } - public LSL_Float osGetHealth(string avatar) + public LSL_Float osGetHealth(key avatar) { return m_OSSL_Functions.osGetHealth(avatar); } - public void osCauseDamage(string avatar, double damage) + public void osCauseDamage(key avatar, LSL_Float damage) { m_OSSL_Functions.osCauseDamage(avatar, damage); } - public void osCauseHealing(string avatar, double healing) + public void osCauseHealing(key avatar, LSL_Float healing) { m_OSSL_Functions.osCauseHealing(avatar, healing); } - public void osSetHealth(string avatar, double health) + public void osSetHealth(key avatar, LSL_Float health) { m_OSSL_Functions.osSetHealth(avatar, health); } - public void osSetHealRate(string avatar, double health) + public void osSetHealRate(key avatar, LSL_Float health) { m_OSSL_Functions.osSetHealRate(avatar, health); } - public LSL_Float osGetHealRate(string avatar) + public LSL_Float osGetHealRate(key avatar) { return m_OSSL_Functions.osGetHealRate(avatar); } @@ -1055,11 +1060,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osUnixTimeToTimestamp(time); } - public LSL_String osGetInventoryDesc(string item) - { - return m_OSSL_Functions.osGetInventoryDesc(item); - } - public LSL_Integer osInviteToGroup(LSL_Key agentId) { return m_OSSL_Functions.osInviteToGroup(agentId); @@ -1361,5 +1361,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osApproxEquals(ra, rb, margin); } + + public LSL_Key osGetInventoryLastOwner(LSL_String itemNameOrId) + { + return m_OSSL_Functions.osGetInventoryLastOwner(itemNameOrId); + } + + public LSL_String osGetInventoryName(LSL_Key itemId) + { + return m_OSSL_Functions.osGetInventoryName(itemId); + } + + public LSL_String osGetInventoryDesc(LSL_String itemNameOrId) + { + return m_OSSL_Functions.osGetInventoryDesc(itemNameOrId); + } + + public LSL_Key osGetLastChangedEventKey() + { + return m_OSSL_Functions.osGetLastChangedEventKey(); + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 019a0d9986..351fca9bed 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -699,7 +699,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // If min event delay is set then ignore any events untill the time has expired // This currently only allows 1 event of any type in the given time period. // This may need extending to allow for a time for each individual event type. - if (m_eventDelayTicks != 0) + if (m_eventDelayTicks != 0 && + data.EventName != "state" && data.EventName != "state_entry" && data.EventName != "state_exit" + && data.EventName != "run_time_permissions" && data.EventName != "http_request" && data.EventName != "link_message") { if (DateTime.Now.Ticks < m_nextEventTimeTicks) return; diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs index b7fc161e61..50a95a90ee 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs @@ -215,12 +215,25 @@ namespace OpenSim.Region.ScriptEngine.XEngine det)); } - public void changed(uint localID, uint change) + public void changed(uint localID, uint change, object parameter) { // Add to queue for all scripts in localID, Object pass change. - myScriptEngine.PostObjectEvent(localID, new EventParams( - "changed",new object[] { new LSL_Types.LSLInteger(change) }, + if(parameter == null) + { + myScriptEngine.PostObjectEvent(localID, new EventParams( + "changed", new object[] { new LSL_Types.LSLInteger(change) }, new DetectParams[0])); + return; + } + if (parameter is UUID) + { + DetectParams det = new DetectParams(); + det.Key = (UUID)parameter; + myScriptEngine.PostObjectEvent(localID, new EventParams( + "changed", new object[] { new LSL_Types.LSLInteger(change) }, + new DetectParams[] { det })); + return; + } } // state_entry: not processed here diff --git a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs index c00e8d4dda..3539fa13b9 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs @@ -88,10 +88,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine path_update = 40, - // XMRE specific - region_cross = 63, - // marks highest numbered event, ie, number of columns in seht. - Size = 64 + Size = 41 } } diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs b/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs index 017b294d6b..6acc293869 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs @@ -930,12 +930,15 @@ namespace OpenSim.Region.ScriptEngine.Yengine public void SetMinEventDelay(UUID itemID, double delay) { + XMRInstance instance = GetInstance(itemID); + if (instance != null) + instance.MinEventDelay = delay; } public int GetStartParameter(UUID itemID) { XMRInstance instance = GetInstance(itemID); - if(instance == null) + if (instance == null) return 0; return instance.StartParam; } diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMREvents.cs b/OpenSim/Region/ScriptEngine/YEngine/XMREvents.cs index 5a8b2a39aa..65a8aed88b 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMREvents.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMREvents.cs @@ -182,13 +182,26 @@ namespace OpenSim.Region.ScriptEngine.Yengine new DetectParams[] { det })); } - public void changed(uint localID, uint change) + public void changed(uint localID, uint change, object parameter) { int ch = (int)change; // Add to queue for all scripts in localID, Object pass change. - this.PostObjectEvent(localID, new EventParams( + if(parameter == null) + { + PostObjectEvent(localID, new EventParams( "changed", new object[] { ch }, zeroDetectParams)); + return; + } + if ( parameter is UUID) + { + DetectParams det = new DetectParams(); + det.Key = (UUID)parameter; + PostObjectEvent(localID, new EventParams( + "changed", new object[] { ch }, + new DetectParams[] { det })); + return; + } } // state_entry: not processed here diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs index 6fe11d8113..7fc97e9c1a 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs @@ -422,9 +422,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine object[] saveEHArgs = this.ehArgs; ScriptEventCode saveEventCode = this.eventCode; - this.m_DetectParams = evt.DetectParams; - this.ehArgs = evt.Params; - this.eventCode = evc; + m_DetectParams = evt.DetectParams; + ehArgs = evt.Params; + eventCode = evc; try { @@ -432,9 +432,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine } finally { - this.m_DetectParams = saveDetParams; - this.ehArgs = saveEHArgs; - this.eventCode = saveEventCode; + m_DetectParams = saveDetParams; + ehArgs = saveEHArgs; + eventCode = saveEventCode; } // Keep waiting until we find a returnable event or timeout. diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstCapture.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstCapture.cs index 9bb894de2c..5798638623 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstCapture.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstCapture.cs @@ -115,6 +115,15 @@ namespace OpenSim.Region.ScriptEngine.Yengine m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true); + if (m_minEventDelay != 0.0) + { + XmlElement minEventDelayN = doc.CreateElement("", "mEvtDly", ""); + minEventDelayN.AppendChild(doc.CreateTextNode(m_minEventDelay.ToString())); + scriptStateN.AppendChild(minEventDelayN); + m_RunOnePhase = "GetExecutionState D"; + CheckRunLockInvariants(true); + } + // More misc data. XmlNode permissionsN = doc.CreateElement("", "Permissions", ""); scriptStateN.AppendChild(permissionsN); diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstCtor.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstCtor.cs index b140453b83..7e13ae4962 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstCtor.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstCtor.cs @@ -527,6 +527,11 @@ namespace OpenSim.Region.ScriptEngine.Yengine XmlElement doGblInitN = (XmlElement)scriptStateN.SelectSingleNode("DoGblInit"); doGblInit = bool.Parse(doGblInitN.InnerText); + double minEventDelay = 0.0; + XmlElement minEventDelayN = (XmlElement)scriptStateN.SelectSingleNode("mEvtDly"); + if(minEventDelayN != null) + minEventDelay = Double.Parse(minEventDelayN.InnerText); + // get values used by stuff like llDetectedGrab, etc. DetectParams[] detParams = RestoreDetectParams(scriptStateN.SelectSingleNode("DetectArray")); @@ -576,6 +581,8 @@ namespace OpenSim.Region.ScriptEngine.Yengine AsyncCommandManager.CreateFromData(m_Engine, m_LocalID, m_ItemID, m_Part.UUID, pluginData); + + MinEventDelay = minEventDelay; } private void processXstate(XmlDocument doc) @@ -919,6 +926,8 @@ namespace OpenSim.Region.ScriptEngine.Yengine AsyncCommandManager.CreateFromData(m_Engine, m_LocalID, m_ItemID, m_Part.UUID, pluginData); + + MinEventDelay = minEventDelay; } private static void getvarNames(Dictionary s, Dictionary d) diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs index 3c0040c84a..def06b27c5 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs @@ -215,5 +215,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine // It's born ready, but will be reset when the detach is posted. // It will then be set again on suspend/completion private ManualResetEvent m_DetachReady = new ManualResetEvent(true); + + // llmineventdelay support + double m_minEventDelay = 0.0; + double m_nextEventTime = 0.0; } } diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs index 0af3d37c3a..12feb7b428 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs @@ -298,6 +298,24 @@ namespace OpenSim.Region.ScriptEngine.Yengine } } + public double MinEventDelay + { + get + { + return m_minEventDelay; + } + set + { + if (value > 0.001) + m_minEventDelay = value; + else + m_minEventDelay = 0.0; + + m_nextEventTime = 0.0; // reset it + } + } + + public SceneObjectPart SceneObject { get diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs index 6c969dc697..1b735e33de 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs @@ -63,8 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine */ public void PostEvent(EventParams evt) { - ScriptEventCode evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), - evt.EventName); + ScriptEventCode evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName); // Put event on end of event queue. bool startIt = false; @@ -86,6 +85,47 @@ namespace OpenSim.Region.ScriptEngine.Yengine if(!m_Running && !construct) return; + if(m_minEventDelay != 0) + { + switch (evc) + { + // ignore some events by time set by llMinEventDelay + case ScriptEventCode.collision: + case ScriptEventCode.land_collision: + case ScriptEventCode.listen: + case ScriptEventCode.not_at_target: + case ScriptEventCode.not_at_rot_target: + case ScriptEventCode.no_sensor: + case ScriptEventCode.sensor: + case ScriptEventCode.timer: + case ScriptEventCode.touch: + { + double now = Util.GetTimeStamp(); + if (now < m_nextEventTime) + return; + m_nextEventTime = now + m_minEventDelay; + break; + } + case ScriptEventCode.changed: + { + const int canignore = ~(CHANGED_SCALE | CHANGED_POSITION); + int change = (int)evt.Params[0]; + if(change == 0) // what? + return; + if((change & canignore) == 0) + { + double now = Util.GetTimeStamp(); + if (now < m_nextEventTime) + return; + m_nextEventTime = now + m_minEventDelay; + } + break; + } + default: + break; + } + } + // Only so many of each event type allowed to queue. if((uint)evc < (uint)m_EventCounts.Length) { @@ -124,10 +164,8 @@ namespace OpenSim.Region.ScriptEngine.Yengine for(lln2 = m_EventQueue.First; lln2 != null; lln2 = lln2.Next) { EventParams evt2 = lln2.Value; - ScriptEventCode evc2 = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), - evt2.EventName); - if((evc2 != ScriptEventCode.state_entry) && - (evc2 != ScriptEventCode.attach)) + ScriptEventCode evc2 = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt2.EventName); + if((evc2 != ScriptEventCode.state_entry) && (evc2 != ScriptEventCode.attach)) break; } if(lln2 == null) diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 0438673ce3..22748cc1f7 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -757,6 +757,14 @@ namespace OpenSim.Services.LLLoginService } } } + + //find a exact match + foreach(GridRegion r in regions) + { + if(string.Equals(regionName, r.RegionName, StringComparison.InvariantCultureIgnoreCase)) + return r; + } + // else, whatever return regions[0]; } else diff --git a/bin/OpenMetaverse.dll b/bin/OpenMetaverse.dll index b7ddd0bd18..02edd6c1d3 100755 Binary files a/bin/OpenMetaverse.dll and b/bin/OpenMetaverse.dll differ diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 3a80dbedd9..cede84d25b 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -661,6 +661,25 @@ ; many simultaneous requests, default is 30 and is currently applied only to assets ;MaxRequestConcurrency = 30 +[ScriptsHttpRequestModule] + ; options for llHttpRequest + + ; max number of concurrent connections per instance (all scenes), default 8 + ; MaxPoolThreads = 8 + + ; max requests per second for all scripts on a prim, default 1 + ;PrimRequestsPerSec = 1.0 + ; initial unthrottled burst for all scripts on a prim, default 3 + ;PrimRequestsBurst = 3.0 + + ; max requests per second for the objects owner (per instance), default 25 + ;PrimOwnerRequestsPerSec = 25.0 + ; initial unthrottled burst for the objects owner (per instance), default 5 + ;PrimOwnerRequestsBurst = 5.0 + + ; requests timeout in miliseconds, range 200 to 60000, default 30000 + ;RequestsTimeOut = 30000 + [AccessControl] ; Viewer-based access control. |-separated list of allowed viewers. ; AllowedClients = "" @@ -728,17 +747,6 @@ ;texture_default = 18500 ;asset_default = 10500 - ; Configures how ObjectUpdates are aggregated. These numbers - ; do not literally mean how many updates will be put in each - ; packet that goes over the wire, as packets are - ; automatically split on a 1400 byte boundary. These control - ; the balance between responsiveness of interest list updates - ; and total throughput. Higher numbers will ensure more full- - ; sized packets and faster sending of data, but more delay in - ; updating interest lists - ; - ;PrimUpdatesPerCallback = 100 - ; TextureSendLimit determines how many packets will be put on ; the outgoing queue each cycle. Like the settings above, this ; is a balance between responsiveness to priority updates and @@ -748,16 +756,6 @@ ; ;TextureSendLimit = 20 - ; CannibalizeTextureRate allows bandwidth to be moved from the - ; UDP texture throttle to the task throttle. Since most viewers - ; use HTTP textures, this provides a means of using what is largely - ; unused bandwidth in the total throttle. The value is the proportion - ; of the texture rate to move to the task queue. It must be between - ; 0.0 (none of the bandwidth is cannibalized) and 0.9 (90% of the - ; bandwidth is grabbed) - ; - ; CannibalizeTextureRate = 0.5 - ; Quash and remove any light properties from attachments not on the ; hands. This allows flashlights and lanterns to function, but kills ; silly vanity "Facelights" dead. Sorry, head mounted miner's lamps @@ -802,6 +800,7 @@ Cap_GetTexture = "localhost" Cap_GetMesh = "localhost" Cap_GetMesh2 = "localhost" + ; Cap_GetAsset = "localhost" DO not ucoment this line. Some popular viewers still dont do it right for opensim. Here to easy testing Cap_GetObjectCost = "" Cap_GetObjectPhysicsData = "" Cap_GroupProposalBallot = "" diff --git a/bin/ScriptSyntax.xml b/bin/ScriptSyntax.xml index 862a66df93..8f2f6002f9 100644 --- a/bin/ScriptSyntax.xml +++ b/bin/ScriptSyntax.xml @@ -1,4 +1,4 @@ -a0b4b514-3c14-6b98-ca98-e18a79e9792f +20392e48-fad2-094e-bc5b-cda003a1e940 llsd-lsl-syntax-version2 controls @@ -1513,7 +1513,7 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f OS_APIVERSION typeinteger - value2 + value3 OS_ATTACH_MSG_ALL typeinteger @@ -6114,17 +6114,8 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returninteger arguments - vatypevector - vbtypevector - margintypefloat - - - osApproxEquals - - returninteger - arguments - vatypevector - vbtypevector + atypefloat + btypefloat osApproxEquals @@ -6140,8 +6131,17 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returninteger arguments - atypefloat - btypefloat + ratyperotation + rbtyperotation + + + osApproxEquals + + returninteger + arguments + vatypevector + vbtypevector + margintypefloat osApproxEquals @@ -6157,8 +6157,8 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returninteger arguments - ratyperotation - rbtyperotation + vatypevector + vbtypevector osAvatarName2Key @@ -6186,14 +6186,14 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f osCauseDamage arguments - avatartypestring + avatartypekey damagetypefloat osCauseHealing arguments - avatartypestring + agentIdtypekey healingtypefloat @@ -6284,8 +6284,6 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returnstring arguments drawListtypestring - startXtypeinteger - startYtypeinteger endXtypeinteger endYtypeinteger @@ -6295,6 +6293,8 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returnstring arguments drawListtypestring + startXtypeinteger + startYtypeinteger endXtypeinteger endYtypeinteger @@ -6539,14 +6539,14 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returnfloat arguments - avatartypestring + agentIdtypekey osGetHealth returnfloat arguments - avatartypestring + agentIdtypekey osGetInertiaData @@ -6558,9 +6558,28 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returnstring arguments - itemtypestring + itemNameOrIdtypestring + osGetInventoryLastOwner + + returnkey + arguments + itemNameOrIdtypestring + + + osGetInventoryName + + returnstring + arguments + itemIdtypekey + + + osGetLastChangedEventKey + + returnkey + arguments + osGetLinkNumber returninteger @@ -6735,6 +6754,13 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f alerttypestring + osKickAvatar + + arguments + agentIdtypekey + alerttypestring + + osLoadedCreationDate returnstring @@ -6839,7 +6865,6 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f nametypestring positiontypevector notecardtypestring - optionstypeinteger osNpcCreate @@ -6850,6 +6875,7 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f nametypestring positiontypevector notecardtypestring + optionstypeinteger osNpcGetOwner @@ -7089,7 +7115,6 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returninteger arguments secondstypefloat - msgtypestring osRegionRestart @@ -7097,6 +7122,7 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f returninteger arguments secondstypefloat + msgtypestring osReplaceString @@ -7199,14 +7225,14 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f osSetHealRate arguments - avatartypestring + agentIdtypekey healthtypefloat osSetHealth arguments - avatartypestring + agentIdtypekey healthtypefloat @@ -7432,6 +7458,8 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f arguments srctypestring valuetypestring + starttypeinteger + counttypeinteger ignorecasetypeinteger @@ -7441,8 +7469,6 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f arguments srctypestring valuetypestring - starttypeinteger - counttypeinteger ignorecasetypeinteger @@ -7525,15 +7551,6 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f osTeleportAgent - - arguments - agenttypestring - regionNametypestring - positiontypevector - lookattypevector - - - osTeleportAgent arguments agenttypestring @@ -7551,6 +7568,15 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f lookattypevector + osTeleportAgent + + arguments + agenttypestring + regionNametypestring + positiontypevector + lookattypevector + + osTeleportObject returninteger @@ -7564,8 +7590,6 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f osTeleportOwner arguments - regionXtypeinteger - regionYtypeinteger positiontypevector lookattypevector @@ -7581,6 +7605,8 @@ a0b4b514-3c14-6b98-ca98-e18a79e9792f osTeleportOwner arguments + regionXtypeinteger + regionYtypeinteger positiontypevector lookattypevector diff --git a/bin/config-include/osslEnable.ini b/bin/config-include/osslEnable.ini index a96459ae82..f127b1fe3c 100644 --- a/bin/config-include/osslEnable.ini +++ b/bin/config-include/osslEnable.ini @@ -155,7 +155,6 @@ Allow_osForceDropAttachmentAt = ${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER Allow_osGetLinkPrimitiveParams = ${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER Allow_osGetPhysicsEngineType = true - Allow_osGetPrimitiveParams = ${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER Allow_osGetRegionMapTexture = ${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER Allow_osGetScriptEngineName = true Allow_osGetSimulatorVersion = true @@ -185,7 +184,6 @@ Allow_osParcelSubdivide = ESTATE_MANAGER,ESTATE_OWNER Allow_osRegionRestart = ESTATE_MANAGER,ESTATE_OWNER Allow_osRegionNotice = ESTATE_MANAGER,ESTATE_OWNER - Allow_osSetPrimitiveParams = false Allow_osSetProjectionParams = ${OSSL|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER Allow_osSetRegionWaterHeight = ESTATE_MANAGER,ESTATE_OWNER Allow_osSetStateEvents = false ; deprecated @@ -250,6 +248,7 @@ ; Allow_osGetLinkNumber = true ; Allow_osGetMapTexture = true ; Allow_osGetPhysicsEngineName = true +; Allow_osGetPrimitiveParams = true ; Allow_osGetRegionSize = true ; Allow_osGetSunParam = true ; Allow_osGetTerrainHeight = true @@ -275,6 +274,7 @@ ; Allow_osSetPenCap = true ; Allow_osSetPenColor = true ; Allow_osSetPenSize = true +; Allow_osSetPrimitiveParams = true ; Allow_osSetSoundRadius = true ; Allow_osStopSound = true ; Allow_osStringSubString = true