* Many llSensor() improvements, though sensoring isn't perfect yet * thanks idb!0.6.0-stable
parent
60b86e1e62
commit
4e3bc9a63e
|
@ -45,10 +45,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
m_CmdManager = CmdManager;
|
m_CmdManager = CmdManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<uint, Dictionary<UUID, LSL_Types.list>> SenseEvents =
|
|
||||||
new Dictionary<uint, Dictionary<UUID, LSL_Types.list>>();
|
|
||||||
private Object SenseLock = new Object();
|
private Object SenseLock = new Object();
|
||||||
|
|
||||||
|
private const int AGENT = 1;
|
||||||
|
private const int ACTIVE = 2;
|
||||||
|
private const int PASSIVE = 4;
|
||||||
|
private const int SCRIPTED = 8;
|
||||||
|
|
||||||
|
private double maximumRange = 96.0;
|
||||||
|
private int maximumToReturn = 16;
|
||||||
|
|
||||||
//
|
//
|
||||||
// SenseRepeater and Sensors
|
// SenseRepeater and Sensors
|
||||||
//
|
//
|
||||||
|
@ -87,7 +93,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
ts.name = name;
|
ts.name = name;
|
||||||
ts.keyID = keyID;
|
ts.keyID = keyID;
|
||||||
ts.type = type;
|
ts.type = type;
|
||||||
ts.range = range;
|
if (range > maximumRange)
|
||||||
|
ts.range = maximumRange;
|
||||||
|
else
|
||||||
|
ts.range = range;
|
||||||
ts.arc = arc;
|
ts.arc = arc;
|
||||||
ts.host = host;
|
ts.host = host;
|
||||||
|
|
||||||
|
@ -150,7 +159,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
ts.name = name;
|
ts.name = name;
|
||||||
ts.keyID = keyID;
|
ts.keyID = keyID;
|
||||||
ts.type = type;
|
ts.type = type;
|
||||||
ts.range = range;
|
if (range > maximumRange)
|
||||||
|
ts.range = maximumRange;
|
||||||
|
else
|
||||||
|
ts.range = range;
|
||||||
ts.arc = arc;
|
ts.arc = arc;
|
||||||
ts.host = host;
|
ts.host = host;
|
||||||
SensorSweep(ts);
|
SensorSweep(ts);
|
||||||
|
@ -158,13 +170,101 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
|
|
||||||
private void SensorSweep(SenseRepeatClass ts)
|
private void SensorSweep(SenseRepeatClass ts)
|
||||||
{
|
{
|
||||||
SceneObjectPart SensePoint = ts.host;
|
if (ts.host == null)
|
||||||
|
|
||||||
if (SensePoint == null)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LSL_Types.list SensedObjects = new LSL_Types.list();
|
||||||
|
|
||||||
|
// Is the sensor type is AGENT and not SCRIPTED then include agents
|
||||||
|
if ((ts.type & AGENT) != 0 && (ts.type & SCRIPTED) == 0)
|
||||||
|
{
|
||||||
|
doAgentSensor(ts, SensedObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If SCRIPTED or PASSIVE or ACTIVE check objects
|
||||||
|
if ((ts.type & SCRIPTED) != 0 || (ts.type & PASSIVE) != 0 || (ts.type & ACTIVE) != 0)
|
||||||
|
{
|
||||||
|
doObjectSensor(ts, SensedObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (SenseLock)
|
||||||
|
{
|
||||||
|
if (SensedObjects.Length == 0)
|
||||||
|
{
|
||||||
|
// send a "no_sensor"
|
||||||
|
// Add it to queue
|
||||||
|
m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
|
||||||
|
new EventParams("no_sensor", new Object[0],
|
||||||
|
new DetectParams[0]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the sort is stride = 2 and ascending to get everything ordered by distance
|
||||||
|
SensedObjects = SensedObjects.Sort(2, 1);
|
||||||
|
int count = SensedObjects.Length;
|
||||||
|
int idx;
|
||||||
|
List<DetectParams> detected = new List<DetectParams>();
|
||||||
|
for (idx = 0; idx < count; idx++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DetectParams detect = new DetectParams();
|
||||||
|
detect.Key = (UUID)(SensedObjects.Data[(idx * 2) + 1]);
|
||||||
|
detect.Populate(m_CmdManager.m_ScriptEngine.World);
|
||||||
|
detected.Add(detect);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Ignore errors, the object has been deleted or the avatar has gone and
|
||||||
|
// there was a problem in detect.Populate so nothing added to the list
|
||||||
|
}
|
||||||
|
if (detected.Count == maximumToReturn)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detected.Count == 0)
|
||||||
|
{
|
||||||
|
// To get here with zero in the list there must have been some sort of problem
|
||||||
|
// like the object being deleted or the avatar leaving to have caused some
|
||||||
|
// difficulty during the Populate above so fire a no_sensor event
|
||||||
|
m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
|
||||||
|
new EventParams("no_sensor", new Object[0],
|
||||||
|
new DetectParams[0]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
|
||||||
|
new EventParams("sensor",
|
||||||
|
new Object[] {new LSL_Types.LSLInteger(detected.Count) },
|
||||||
|
detected.ToArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doObjectSensor(SenseRepeatClass ts, LSL_Types.list SensedObjects)
|
||||||
|
{
|
||||||
|
List<EntityBase> Entities;
|
||||||
|
|
||||||
|
// If this is an object sense by key try to get it directly
|
||||||
|
// rather than getting a list to scan through
|
||||||
|
if (ts.keyID != UUID.Zero)
|
||||||
|
{
|
||||||
|
EntityBase e = null;
|
||||||
|
m_CmdManager.m_ScriptEngine.World.Entities.TryGetValue(ts.keyID, out e);
|
||||||
|
if (e == null)
|
||||||
|
return;
|
||||||
|
Entities = new List<EntityBase>();
|
||||||
|
Entities.Add(e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Entities = m_CmdManager.m_ScriptEngine.World.GetEntities();
|
||||||
|
}
|
||||||
|
SceneObjectPart SensePoint = ts.host;
|
||||||
|
|
||||||
Vector3 sensorPos = SensePoint.AbsolutePosition;
|
Vector3 sensorPos = SensePoint.AbsolutePosition;
|
||||||
Vector3 regionPos = new Vector3(m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocX * Constants.RegionSize, m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
|
Vector3 regionPos = new Vector3(m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocX * Constants.RegionSize, m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
|
||||||
Vector3 fromRegionPos = sensorPos + regionPos;
|
Vector3 fromRegionPos = sensorPos + regionPos;
|
||||||
|
@ -174,37 +274,55 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
|
LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
|
||||||
double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
|
double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
|
||||||
|
|
||||||
// Here we should do some smart culling ...
|
Vector3 ZeroVector = new Vector3(0, 0, 0);
|
||||||
// math seems quicker than strings so try that first
|
|
||||||
LSL_Types.list SensedObjects = new LSL_Types.list();
|
|
||||||
LSL_Types.Vector3 ZeroVector = new LSL_Types.Vector3(0, 0, 0);
|
|
||||||
|
|
||||||
foreach (EntityBase ent in m_CmdManager.m_ScriptEngine.World.Entities.Values)
|
bool nameSearch = (ts.name != null && ts.name != "");
|
||||||
|
SceneObjectGroup group;
|
||||||
|
|
||||||
|
foreach (EntityBase ent in Entities)
|
||||||
{
|
{
|
||||||
|
bool keep = true;
|
||||||
|
|
||||||
|
if (nameSearch && ent.Name != ts.name) // Wrong name and it is a named search
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ent.IsDeleted) // taken so long to do this it has gone from the scene
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(ent is SceneObjectGroup)) // dont bother if it is a pesky avatar
|
||||||
|
continue;
|
||||||
|
|
||||||
Vector3 toRegionPos = ent.AbsolutePosition + regionPos;
|
Vector3 toRegionPos = ent.AbsolutePosition + regionPos;
|
||||||
double dis = Math.Abs((double)Util.GetDistanceTo(toRegionPos, fromRegionPos));
|
double dis = Math.Abs((double)Util.GetDistanceTo(toRegionPos, fromRegionPos));
|
||||||
if (dis <= ts.range)
|
if (keep && dis <= ts.range && ts.host.UUID != ent.UUID)
|
||||||
{
|
{
|
||||||
// In Range, is it the right Type ?
|
// In Range and not the object containing the script, is it the right Type ?
|
||||||
int objtype = 0;
|
int objtype = 0;
|
||||||
|
|
||||||
if (m_CmdManager.m_ScriptEngine.World.GetScenePresence(ent.UUID) != null) objtype |= 0x01; // actor
|
SceneObjectPart part = ((SceneObjectGroup)ent).RootPart;
|
||||||
if (ent.Velocity.Equals(ZeroVector))
|
if (part.AttachmentPoint != 0) // Attached so ignore
|
||||||
objtype |= 0x04; // passive non-moving
|
continue;
|
||||||
else
|
|
||||||
objtype |= 0x02; // active moving
|
|
||||||
|
|
||||||
SceneObjectPart part = m_CmdManager.m_ScriptEngine.World.GetSceneObjectPart(ent.UUID);
|
if (part.ContainsScripts())
|
||||||
|
|
||||||
if (part != null && part.ContainsScripts()) objtype |= 0x08; // Scripted. It COULD have one hidden ...
|
|
||||||
|
|
||||||
if (((ts.type & objtype) != 0) || ((ts.type & objtype) == ts.type))
|
|
||||||
{
|
{
|
||||||
// docs claim AGENT|ACTIVE should find agent objects OR active objects
|
objtype |= ACTIVE | SCRIPTED; // Scripted and active. It COULD have one hidden ...
|
||||||
// so the bitwise AND with object type should be non-zero
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ent.Velocity.Equals(ZeroVector))
|
||||||
|
{
|
||||||
|
objtype |= PASSIVE; // Passive non-moving
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
objtype |= ACTIVE; // moving so active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If any of the objects attributes match any in the requested scan type
|
||||||
|
if (((ts.type & objtype) != 0))
|
||||||
|
{
|
||||||
// Right type too, what about the other params , key and name ?
|
// Right type too, what about the other params , key and name ?
|
||||||
bool keep = true;
|
|
||||||
if (ts.arc < Math.PI)
|
if (ts.arc < Math.PI)
|
||||||
{
|
{
|
||||||
// not omni-directional. Can you see it ?
|
// not omni-directional. Can you see it ?
|
||||||
|
@ -230,67 +348,118 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
if (ang_obj > ts.arc) keep = false;
|
if (ang_obj > ts.arc) keep = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keep && (ts.keyID != UUID.Zero) && (ts.keyID != ent.UUID))
|
if (keep == true)
|
||||||
{
|
{
|
||||||
keep = false;
|
// add distance for sorting purposes later
|
||||||
|
SensedObjects.Add(new LSL_Types.LSLFloat(dis));
|
||||||
|
SensedObjects.Add(ent.UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keep && (ts.name.Length > 0))
|
|
||||||
{
|
|
||||||
if (ts.name != ent.Name)
|
|
||||||
{
|
|
||||||
keep = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keep == true) SensedObjects.Add(ent.UUID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lock (SenseLock)
|
private void doAgentSensor(SenseRepeatClass ts, LSL_Types.list SensedObjects)
|
||||||
|
{
|
||||||
|
List<ScenePresence> Presences;
|
||||||
|
|
||||||
|
// If this is an avatar sense by key try to get them directly
|
||||||
|
// rather than getting a list to scan through
|
||||||
|
if (ts.keyID != UUID.Zero)
|
||||||
{
|
{
|
||||||
// Create object if it doesn't exist
|
ScenePresence p = m_CmdManager.m_ScriptEngine.World.GetScenePresence(ts.keyID);
|
||||||
if (SenseEvents.ContainsKey(ts.localID) == false)
|
if (p == null)
|
||||||
{
|
return;
|
||||||
SenseEvents.Add(ts.localID, new Dictionary<UUID, LSL_Types.list>());
|
Presences = new List<ScenePresence>();
|
||||||
}
|
Presences.Add(p);
|
||||||
// clear if previous traces exist
|
}
|
||||||
Dictionary<UUID, LSL_Types.list> Obj;
|
else
|
||||||
SenseEvents.TryGetValue(ts.localID, out Obj);
|
{
|
||||||
if (Obj.ContainsKey(ts.itemID) == true)
|
Presences = m_CmdManager.m_ScriptEngine.World.GetScenePresences();
|
||||||
Obj.Remove(ts.itemID);
|
}
|
||||||
|
|
||||||
// note list may be zero length
|
// If nobody about quit fast
|
||||||
Obj.Add(ts.itemID, SensedObjects);
|
if (Presences.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (SensedObjects.Length == 0)
|
SceneObjectPart SensePoint = ts.host;
|
||||||
{
|
|
||||||
// send a "no_sensor"
|
|
||||||
// Add it to queue
|
|
||||||
m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
|
|
||||||
new EventParams("no_sensor", new Object[0],
|
|
||||||
new DetectParams[0]));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DetectParams[] detect =
|
|
||||||
new DetectParams[SensedObjects.Length];
|
|
||||||
|
|
||||||
int idx;
|
Vector3 sensorPos = SensePoint.AbsolutePosition;
|
||||||
for (idx = 0; idx < SensedObjects.Length; idx++)
|
Vector3 regionPos = new Vector3(m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocX * Constants.RegionSize, m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
|
||||||
|
Vector3 fromRegionPos = sensorPos + regionPos;
|
||||||
|
|
||||||
|
Quaternion q = SensePoint.RotationOffset;
|
||||||
|
LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
|
||||||
|
LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
|
||||||
|
double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
|
||||||
|
|
||||||
|
bool attached = (SensePoint.AttachmentPoint != 0);
|
||||||
|
bool nameSearch = (ts.name != null && ts.name != "");
|
||||||
|
|
||||||
|
foreach (ScenePresence presence in Presences)
|
||||||
|
{
|
||||||
|
bool keep = true;
|
||||||
|
|
||||||
|
if (presence.IsDeleted)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (presence.IsChildAgent)
|
||||||
|
keep = false;
|
||||||
|
|
||||||
|
Vector3 toRegionPos = presence.AbsolutePosition + regionPos;
|
||||||
|
double dis = Math.Abs(Util.GetDistanceTo(toRegionPos, fromRegionPos));
|
||||||
|
|
||||||
|
// are they in range
|
||||||
|
if (keep && dis <= ts.range)
|
||||||
|
{
|
||||||
|
// if the object the script is in is attached and the avatar is the owner
|
||||||
|
// then this one is not wanted
|
||||||
|
if (attached && presence.UUID == SensePoint.OwnerID)
|
||||||
|
keep = false;
|
||||||
|
|
||||||
|
// check the name if needed
|
||||||
|
if (keep && nameSearch && ts.name != presence.Name)
|
||||||
|
keep = false;
|
||||||
|
|
||||||
|
// Are they in the required angle of view
|
||||||
|
if (keep && ts.arc < Math.PI)
|
||||||
{
|
{
|
||||||
detect[idx] = new DetectParams();
|
// not omni-directional. Can you see it ?
|
||||||
detect[idx].Key=(UUID)(SensedObjects.Data[idx]);
|
// vec forward_dir = llRot2Fwd(llGetRot())
|
||||||
detect[idx].Populate(m_CmdManager.m_ScriptEngine.World);
|
// vec obj_dir = toRegionPos-fromRegionPos
|
||||||
|
// dot=dot(forward_dir,obj_dir)
|
||||||
|
// mag_fwd = mag(forward_dir)
|
||||||
|
// mag_obj = mag(obj_dir)
|
||||||
|
// ang = acos(dot /(mag_fwd*mag_obj))
|
||||||
|
double ang_obj = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Vector3 diff = toRegionPos - fromRegionPos;
|
||||||
|
LSL_Types.Vector3 obj_dir = new LSL_Types.Vector3(diff.X, diff.Y, diff.Z);
|
||||||
|
double dot = LSL_Types.Vector3.Dot(forward_dir, obj_dir);
|
||||||
|
double mag_obj = LSL_Types.Vector3.Mag(obj_dir);
|
||||||
|
ang_obj = Math.Acos(dot / (mag_fwd * mag_obj));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
if (ang_obj > ts.arc) keep = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
|
|
||||||
new EventParams("sensor",
|
|
||||||
new Object[] {
|
|
||||||
new LSL_Types.LSLInteger(SensedObjects.Length) },
|
|
||||||
detect));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not report gods, not even minor ones
|
||||||
|
if (keep && presence.GodLevel > 0.0)
|
||||||
|
keep = false;
|
||||||
|
|
||||||
|
if (keep) // add to list with distance
|
||||||
|
{
|
||||||
|
SensedObjects.Add(new LSL_Types.LSLFloat(dis));
|
||||||
|
SensedObjects.Add(presence.UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a search by name and we have just found it then no more to do
|
||||||
|
if (nameSearch && ts.name == presence.Name)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue