diff --git a/OpenSim/Framework/ColliderData.cs b/OpenSim/Framework/ColliderData.cs new file mode 100644 index 0000000000..075a4e0c63 --- /dev/null +++ b/OpenSim/Framework/ColliderData.cs @@ -0,0 +1,54 @@ +/* + * 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 OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using libsecondlife; +using System.Collections.Generic; + +namespace OpenSim.Framework +{ + public class DetectedObject + { + public DetectedObject() { } + public LLUUID groupUUID = LLUUID.Zero; + public LLUUID ownerUUID = LLUUID.Zero; + public LLUUID keyUUID = LLUUID.Zero; + public LLVector3 posVector = LLVector3.Zero; + public LLQuaternion rotQuat = LLQuaternion.Identity; + public LLVector3 velVector = LLVector3.Zero; + public string nameStr = String.Empty; + public int colliderType = 0; + } + + public class ColliderArgs : EventArgs + { + public ColliderArgs() { } + public List Colliders = new List(); + + } +} diff --git a/OpenSim/Region/Environment/Scenes/EventManager.cs b/OpenSim/Region/Environment/Scenes/EventManager.cs index eee4e4ad3c..5c750e42a3 100644 --- a/OpenSim/Region/Environment/Scenes/EventManager.cs +++ b/OpenSim/Region/Environment/Scenes/EventManager.cs @@ -158,9 +158,17 @@ namespace OpenSim.Region.Environment.Scenes public event ScriptAtTargetEvent OnScriptAtTargetEvent; public delegate void ScriptNotAtTargetEvent(uint localID); - + public event ScriptNotAtTargetEvent OnScriptNotAtTargetEvent; + public delegate void ScriptColliding(uint localID, ColliderArgs colliders); + + public event ScriptColliding OnScriptColliderStart; + public event ScriptColliding OnScriptColliding; + public event ScriptColliding OnScriptCollidingEnd; + + + public delegate void OnMakeChildAgentDelegate(ScenePresence presence); public event OnMakeChildAgentDelegate OnMakeChildAgent; @@ -293,6 +301,8 @@ namespace OpenSim.Region.Environment.Scenes } } + + public delegate void MoneyTransferEvent(Object sender, MoneyTransferArgs e); public delegate void LandBuy(Object sender, LandBuyArgs e); @@ -357,6 +367,11 @@ namespace OpenSim.Region.Environment.Scenes private ScriptTimerEvent handlerScriptTimerEvent = null; private EstateToolsTimeUpdate handlerEstateToolsTimeUpdate = null; + private ScriptColliding handlerCollidingStart = null; + private ScriptColliding handlerColliding = null; + private ScriptColliding handlerCollidingEnd = null; + + private SunLindenHour handlerSunGetLindenHour = null; public void TriggerOnScriptChangedEvent(uint localID, uint change) @@ -838,5 +853,26 @@ namespace OpenSim.Region.Environment.Scenes } return 6; } + + public void TriggerScriptCollidingStart(uint localId, ColliderArgs colliders) + { + handlerCollidingStart = OnScriptColliderStart; + if (handlerCollidingStart != null) + handlerCollidingStart(localId, colliders); + } + public void TriggerScriptColliding(uint localId, ColliderArgs colliders) + { + + handlerColliding = OnScriptColliding; + if (handlerColliding != null) + handlerColliding(localId, colliders); + } + public void TriggerScriptCollidingEnd(uint localId, ColliderArgs colliders) + { + handlerCollidingEnd = OnScriptCollidingEnd; + if (handlerCollidingEnd != null) + handlerCollidingEnd(localId, colliders); + } + } } diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index ce7497d5f5..532d003e39 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs @@ -113,6 +113,8 @@ namespace OpenSim.Region.Environment.Scenes public Int32 CreationDate; public uint ParentID = 0; + private List m_lastColliders = new List(); + private PhysicsVector m_lastRotationalVelocity = PhysicsVector.Zero; private Vector3 m_sitTargetPosition = new Vector3(0, 0, 0); private Quaternion m_sitTargetOrientation = new Quaternion(0, 0, 0, 1); @@ -2807,21 +2809,181 @@ namespace OpenSim.Region.Environment.Scenes } public void PhysicsCollision(EventArgs e) { - return; + //return; - // - //if (e == null) - //{ - // return; - //} - //CollisionEventUpdate a = (CollisionEventUpdate)e; - //Dictionary collissionswith = a.m_objCollisionList; - //foreach (uint localid in collissionswith.Keys) - //{ - // m_log.Debug("[OBJECT]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString()); - //} + // single threaded here + if (e == null) + { + return; + } + + CollisionEventUpdate a = (CollisionEventUpdate)e; + Dictionary collissionswith = a.m_objCollisionList; + List thisHitColliders = new List(); + List endedColliders = new List(); + List startedColliders = new List(); + + // calculate things that started colliding this time + // and build up list of colliders this time + foreach (uint localid in collissionswith.Keys) + { + if (localid != 0) + { + thisHitColliders.Add(localid); + if (!m_lastColliders.Contains(localid)) + { + startedColliders.Add(localid); + } + + + //m_log.Debug("[OBJECT]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString()); + } + } + + // calculate things that ended colliding + foreach (uint localID in m_lastColliders) + { + if (!thisHitColliders.Contains(localID)) + { + endedColliders.Add(localID); + } + } + // remove things that ended colliding from the last colliders list + foreach (uint localID in endedColliders) + { + m_lastColliders.Remove(localID); + } + + //add the items that started colliding this time to the last colliders list. + foreach (uint localID in startedColliders) + { + m_lastColliders.Add(localID); + } + // do event notification + if (startedColliders.Count > 0) + { + ColliderArgs StartCollidingMessage = new ColliderArgs(); + List colliding = new List(); + foreach (uint localId in startedColliders) + { + // always running this check because if the user deletes the object it would return a null reference. + if (m_parentGroup == null) + return; + if (m_parentGroup.Scene == null) + return; + SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId); + if (obj != null) + { + DetectedObject detobj = new DetectedObject(); + detobj.keyUUID = obj.UUID; + detobj.nameStr = obj.Name; + detobj.ownerUUID = obj.OwnerID; + detobj.posVector = obj.AbsolutePosition; + detobj.rotQuat = obj.GetWorldRotation(); + detobj.velVector = obj.Velocity; + detobj.colliderType = 0; + detobj.groupUUID = obj.GroupID; + colliding.Add(detobj); + } + } + if (colliding.Count > 0) + { + StartCollidingMessage.Colliders = colliding; + // always running this check because if the user deletes the object it would return a null reference. + if (m_parentGroup == null) + return; + if (m_parentGroup.Scene == null) + return; + m_parentGroup.Scene.EventManager.TriggerScriptCollidingStart(LocalId, StartCollidingMessage); + } + + } + if (m_lastColliders.Count > 0) + { + ColliderArgs CollidingMessage = new ColliderArgs(); + List colliding = new List(); + foreach (uint localId in m_lastColliders) + { + // always running this check because if the user deletes the object it would return a null reference. + if (localId == 0) + continue; + + if (m_parentGroup == null) + return; + if (m_parentGroup.Scene == null) + return; + SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId); + if (obj != null) + { + DetectedObject detobj = new DetectedObject(); + detobj.keyUUID = obj.UUID; + detobj.nameStr = obj.Name; + detobj.ownerUUID = obj.OwnerID; + detobj.posVector = obj.AbsolutePosition; + detobj.rotQuat = obj.GetWorldRotation(); + detobj.velVector = obj.Velocity; + detobj.colliderType = 0; + detobj.groupUUID = obj.GroupID; + colliding.Add(detobj); + } + } + if (colliding.Count > 0) + { + CollidingMessage.Colliders = colliding; + // always running this check because if the user deletes the object it would return a null reference. + if (m_parentGroup == null) + return; + if (m_parentGroup.Scene == null) + return; + m_parentGroup.Scene.EventManager.TriggerScriptCollidingStart(LocalId, CollidingMessage); + } + + } + if (endedColliders.Count > 0) + { + ColliderArgs EndCollidingMessage = new ColliderArgs(); + List colliding = new List(); + foreach (uint localId in endedColliders) + { + if (localId == 0) + continue; + + // always running this check because if the user deletes the object it would return a null reference. + if (m_parentGroup == null) + return; + if (m_parentGroup.Scene == null) + return; + SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId); + if (obj != null) + { + DetectedObject detobj = new DetectedObject(); + detobj.keyUUID = obj.UUID; + detobj.nameStr = obj.Name; + detobj.ownerUUID = obj.OwnerID; + detobj.posVector = obj.AbsolutePosition; + detobj.rotQuat = obj.GetWorldRotation(); + detobj.velVector = obj.Velocity; + detobj.colliderType = 0; + detobj.groupUUID = obj.GroupID; + colliding.Add(detobj); + } + } + if (colliding.Count > 0) + { + EndCollidingMessage.Colliders = colliding; + // always running this check because if the user deletes the object it would return a null reference. + if (m_parentGroup == null) + return; + if (m_parentGroup.Scene == null) + return; + m_parentGroup.Scene.EventManager.TriggerScriptCollidingStart(LocalId, EndCollidingMessage); + } + + } } + + public void SetDieAtEdge(bool p) { if (m_parentGroup == null) diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs index 663ac0ca5f..4c58e360ac 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs @@ -562,6 +562,25 @@ namespace OpenSim.Region.ScriptEngine.Common return resolveName(SensedUUID); } } + else + { + ScriptManager sm; + IScript script = null; + + if ((sm = m_ScriptEngine.m_ScriptManager) != null) + { + if (sm.Scripts.ContainsKey(m_localID)) + { + if ((script = sm.GetScript(m_localID, m_itemID)) != null) + { + if (script.llDetectParams._bool.Length > number && script.llDetectParams._bool[number]) + { + return script.llDetectParams._string[number]; + } + } + } + } + } return String.Empty; } @@ -587,9 +606,12 @@ namespace OpenSim.Region.ScriptEngine.Common { if ((script = sm.GetScript(m_localID, m_itemID)) != null) { - if (script.llDetectParams._key[0]) + if (script.llDetectParams._bool.Length > number && script.llDetectParams._bool[number]) { - return new LLUUID(script.llDetectParams._key[0]); + LLUUID returnUUID = LLUUID.Zero; + Helpers.TryParse(script.llDetectParams._key[number], out returnUUID); + + return returnUUID; } } } @@ -614,6 +636,35 @@ namespace OpenSim.Region.ScriptEngine.Common return SensedObject; } } + else + { + ScriptManager sm; + IScript script = null; + + if ((sm = m_ScriptEngine.m_ScriptManager) != null) + { + if (sm.Scripts.ContainsKey(m_localID)) + { + if ((script = sm.GetScript(m_localID, m_itemID)) != null) + { + if (script.llDetectParams._key[number]) + { + EntityBase SensedObject = null; + LLUUID SensedUUID = LLUUID.Zero; + Helpers.TryParse(script.llDetectParams._key.ToString(), out SensedUUID); + if (SensedUUID == LLUUID.Zero) + return null; + lock (World.Entities) + { + World.Entities.TryGetValue(SensedUUID, out SensedObject); + } + return SensedObject; + + } + } + } + } + } return null; } diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs index 5ef4a6bedf..ae84f65170 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs @@ -26,9 +26,12 @@ */ using System; +using System.Collections.Generic; using libsecondlife; using OpenSim.Framework; using OpenSim.Region.Environment.Modules.Avatar.Currency.SampleMoney; +using OpenSim.Region.Environment; +using OpenSim.Region; using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Environment.Interfaces; @@ -74,6 +77,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase myScriptEngine.World.EventManager.OnScriptAtTargetEvent += at_target; myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target; myScriptEngine.World.EventManager.OnScriptControlEvent += control; + myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start; + myScriptEngine.World.EventManager.OnScriptColliding += collision; + myScriptEngine.World.EventManager.OnScriptCollidingEnd += collision_end; // TODO: HOOK ALL EVENTS UP TO SERVER! IMoneyModule money=myScriptEngine.World.RequestModuleInterface(); @@ -171,19 +177,82 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch_end", EventQueueManager.llDetectNull, new object[] { new LSL_Types.LSLInteger(1) }); } - public void collision_start(uint localID, LLUUID itemID) + public void collision_start(uint localID, ColliderArgs col) { - myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_start", EventQueueManager.llDetectNull, new object[] { new LSL_Types.LSLInteger(1) }); + EventQueueManager.Queue_llDetectParams_Struct detstruct = new EventQueueManager.Queue_llDetectParams_Struct(); + detstruct._string = new string[col.Colliders.Count]; + detstruct._Quaternion = new LSL_Types.Quaternion[col.Colliders.Count]; + detstruct._int = new int[col.Colliders.Count]; + detstruct._key = new LSL_Types.key[col.Colliders.Count]; + detstruct._Vector3 = new LSL_Types.Vector3[col.Colliders.Count]; + detstruct._Vector32 = new LSL_Types.Vector3[col.Colliders.Count]; + detstruct._bool = new bool[col.Colliders.Count]; + + int i = 0; + foreach (DetectedObject detobj in col.Colliders) + { + detstruct._key[i] = new LSL_Types.key(detobj.keyUUID.ToString()); + detstruct._Quaternion[i] = new LSL_Types.Quaternion(detobj.rotQuat.X, detobj.rotQuat.Y, detobj.rotQuat.Z, detobj.rotQuat.W); + detstruct._string[i] = detobj.nameStr; + detstruct._int[i] = detobj.colliderType; + detstruct._Vector3[i] = new LSL_Types.Vector3(detobj.posVector.X, detobj.posVector.Y, detobj.posVector.Z); + detstruct._Vector32[i] = new LSL_Types.Vector3(detobj.velVector.X, detobj.velVector.Y, detobj.velVector.Z); + detstruct._bool[i] = true; // Apparently the script engine uses this to see if this is a valid entry... + i++; + } + + myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "collision_start", detstruct, new object[] { new LSL_Types.LSLInteger(col.Colliders.Count) }); } - public void collision(uint localID, LLUUID itemID) + public void collision(uint localID, ColliderArgs col) { - myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision", EventQueueManager.llDetectNull, new object[] { new LSL_Types.LSLInteger(1) }); + EventQueueManager.Queue_llDetectParams_Struct detstruct = new EventQueueManager.Queue_llDetectParams_Struct(); + detstruct._string = new string[col.Colliders.Count]; + detstruct._Quaternion = new LSL_Types.Quaternion[col.Colliders.Count]; + detstruct._int = new int[col.Colliders.Count]; + detstruct._key = new LSL_Types.key[col.Colliders.Count]; + detstruct._Vector3 = new LSL_Types.Vector3[col.Colliders.Count]; + detstruct._Vector32 = new LSL_Types.Vector3[col.Colliders.Count]; + detstruct._bool = new bool[col.Colliders.Count]; + + int i = 0; + foreach (DetectedObject detobj in col.Colliders) + { + detstruct._key[i] = new LSL_Types.key(detobj.keyUUID.ToString()); + detstruct._Quaternion[i] = new LSL_Types.Quaternion(detobj.rotQuat.X, detobj.rotQuat.Y, detobj.rotQuat.Z, detobj.rotQuat.W); + detstruct._string[i] = detobj.nameStr; + detstruct._int[i] = detobj.colliderType; + detstruct._Vector3[i] = new LSL_Types.Vector3(detobj.posVector.X, detobj.posVector.Y, detobj.posVector.Z); + detstruct._Vector32[i] = new LSL_Types.Vector3(detobj.velVector.X, detobj.velVector.Y, detobj.velVector.Z); + detstruct._bool[i] = true; // Apparently the script engine uses this to see if this is a valid entry... i++; + } + myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "collision", detstruct, new object[] { new LSL_Types.LSLInteger(col.Colliders.Count) }); } - public void collision_end(uint localID, LLUUID itemID) + public void collision_end(uint localID, ColliderArgs col) { - myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_end", EventQueueManager.llDetectNull, new object[] { new LSL_Types.LSLInteger(1) }); + EventQueueManager.Queue_llDetectParams_Struct detstruct = new EventQueueManager.Queue_llDetectParams_Struct(); + detstruct._string = new string[col.Colliders.Count]; + detstruct._Quaternion = new LSL_Types.Quaternion[col.Colliders.Count]; + detstruct._int = new int[col.Colliders.Count]; + detstruct._key = new LSL_Types.key[col.Colliders.Count]; + detstruct._Vector3 = new LSL_Types.Vector3[col.Colliders.Count]; + detstruct._Vector32 = new LSL_Types.Vector3[col.Colliders.Count]; + detstruct._bool = new bool[col.Colliders.Count]; + + int i = 0; + foreach (DetectedObject detobj in col.Colliders) + { + detstruct._key[i] = new LSL_Types.key(detobj.keyUUID.ToString()); + detstruct._Quaternion[i] = new LSL_Types.Quaternion(detobj.rotQuat.X, detobj.rotQuat.Y, detobj.rotQuat.Z, detobj.rotQuat.W); + detstruct._string[i] = detobj.nameStr; + detstruct._int[i] = detobj.colliderType; + detstruct._Vector3[i] = new LSL_Types.Vector3(detobj.posVector.X, detobj.posVector.Y, detobj.posVector.Z); + detstruct._Vector32[i] = new LSL_Types.Vector3(detobj.velVector.X, detobj.velVector.Y, detobj.velVector.Z); + detstruct._bool[i] = true; // Apparently the script engine uses this to see if this is a valid entry... + i++; + } + myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "collision_end", EventQueueManager.llDetectNull, new object[] { new LSL_Types.LSLInteger(col.Colliders.Count) }); } public void land_collision_start(uint localID, LLUUID itemID) @@ -191,9 +260,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_start", EventQueueManager.llDetectNull); } - public void land_collision(uint localID, LLUUID itemID) + public void land_collision(uint localID, ColliderArgs col) { - myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision", EventQueueManager.llDetectNull); + myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "land_collision", EventQueueManager.llDetectNull); } public void land_collision_end(uint localID, LLUUID itemID) diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs index 7cbbd4f7d9..c6eebf1cc9 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs @@ -155,7 +155,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase // should be fixed to something better :) public LSL_Types.key[] _key; public LSL_Types.Quaternion[] _Quaternion; - public LSL_Types.Vector3[] _Vector3; + public LSL_Types.Vector3[] _Vector3; // Pos + public LSL_Types.Vector3[] _Vector32; // Vel public bool[] _bool; public int[] _int; public string[] _string; diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptServerInterfaces.cs b/OpenSim/Region/ScriptEngine/Common/ScriptServerInterfaces.cs index be42539d73..59f828ddf0 100644 --- a/OpenSim/Region/ScriptEngine/Common/ScriptServerInterfaces.cs +++ b/OpenSim/Region/ScriptEngine/Common/ScriptServerInterfaces.cs @@ -31,6 +31,7 @@ using OpenSim.Framework; using OpenSim.Region.Environment.Scenes; using OpenSim.Region.ScriptEngine.Common.ScriptEngineBase; + namespace OpenSim.Region.ScriptEngine.Common { public class ScriptServerInterfaces @@ -43,11 +44,11 @@ namespace OpenSim.Region.ScriptEngine.Common void state_exit(uint localID); void touch(uint localID, LLUUID itemID); void touch_end(uint localID, LLUUID itemID); - void collision_start(uint localID, LLUUID itemID); - void collision(uint localID, LLUUID itemID); - void collision_end(uint localID, LLUUID itemID); + void collision_start(uint localID, ColliderArgs col); + void collision(uint localID, ColliderArgs col); + void collision_end(uint localID, ColliderArgs col); void land_collision_start(uint localID, LLUUID itemID); - void land_collision(uint localID, LLUUID itemID); + void land_collision(uint localID, ColliderArgs col); void land_collision_end(uint localID, LLUUID itemID); void timer(uint localID, LLUUID itemID); void listen(uint localID, LLUUID itemID);