diff options
author | Justin Clarke Casey | 2008-10-09 22:41:07 +0000 |
---|---|---|
committer | Justin Clarke Casey | 2008-10-09 22:41:07 +0000 |
commit | 4e3bc9a63ebf9eb292eccca7b104b6914fe7de5a (patch) | |
tree | bd950d0052c787a59b9309567f260b3858adcf52 /OpenSim | |
parent | - Fix the build for monodevelop, too. If that breaks the build on Windows, (diff) | |
download | opensim-SC-4e3bc9a63ebf9eb292eccca7b104b6914fe7de5a.zip opensim-SC-4e3bc9a63ebf9eb292eccca7b104b6914fe7de5a.tar.gz opensim-SC-4e3bc9a63ebf9eb292eccca7b104b6914fe7de5a.tar.bz2 opensim-SC-4e3bc9a63ebf9eb292eccca7b104b6914fe7de5a.tar.xz |
* Apply http://opensimulator.org/mantis/view.php?id=2373
* Many llSensor() improvements, though sensoring isn't perfect yet
* thanks idb!
Diffstat (limited to 'OpenSim')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs | 315 |
1 files changed, 242 insertions, 73 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index c4240d8..68c7392 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs | |||
@@ -45,10 +45,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
45 | m_CmdManager = CmdManager; | 45 | m_CmdManager = CmdManager; |
46 | } | 46 | } |
47 | 47 | ||
48 | public Dictionary<uint, Dictionary<UUID, LSL_Types.list>> SenseEvents = | ||
49 | new Dictionary<uint, Dictionary<UUID, LSL_Types.list>>(); | ||
50 | private Object SenseLock = new Object(); | 48 | private Object SenseLock = new Object(); |
51 | 49 | ||
50 | private const int AGENT = 1; | ||
51 | private const int ACTIVE = 2; | ||
52 | private const int PASSIVE = 4; | ||
53 | private const int SCRIPTED = 8; | ||
54 | |||
55 | private double maximumRange = 96.0; | ||
56 | private int maximumToReturn = 16; | ||
57 | |||
52 | // | 58 | // |
53 | // SenseRepeater and Sensors | 59 | // SenseRepeater and Sensors |
54 | // | 60 | // |
@@ -87,7 +93,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
87 | ts.name = name; | 93 | ts.name = name; |
88 | ts.keyID = keyID; | 94 | ts.keyID = keyID; |
89 | ts.type = type; | 95 | ts.type = type; |
90 | ts.range = range; | 96 | if (range > maximumRange) |
97 | ts.range = maximumRange; | ||
98 | else | ||
99 | ts.range = range; | ||
91 | ts.arc = arc; | 100 | ts.arc = arc; |
92 | ts.host = host; | 101 | ts.host = host; |
93 | 102 | ||
@@ -150,7 +159,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
150 | ts.name = name; | 159 | ts.name = name; |
151 | ts.keyID = keyID; | 160 | ts.keyID = keyID; |
152 | ts.type = type; | 161 | ts.type = type; |
153 | ts.range = range; | 162 | if (range > maximumRange) |
163 | ts.range = maximumRange; | ||
164 | else | ||
165 | ts.range = range; | ||
154 | ts.arc = arc; | 166 | ts.arc = arc; |
155 | ts.host = host; | 167 | ts.host = host; |
156 | SensorSweep(ts); | 168 | SensorSweep(ts); |
@@ -158,13 +170,101 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
158 | 170 | ||
159 | private void SensorSweep(SenseRepeatClass ts) | 171 | private void SensorSweep(SenseRepeatClass ts) |
160 | { | 172 | { |
161 | SceneObjectPart SensePoint = ts.host; | 173 | if (ts.host == null) |
162 | |||
163 | if (SensePoint == null) | ||
164 | { | 174 | { |
165 | return; | 175 | return; |
166 | } | 176 | } |
167 | 177 | ||
178 | LSL_Types.list SensedObjects = new LSL_Types.list(); | ||
179 | |||
180 | // Is the sensor type is AGENT and not SCRIPTED then include agents | ||
181 | if ((ts.type & AGENT) != 0 && (ts.type & SCRIPTED) == 0) | ||
182 | { | ||
183 | doAgentSensor(ts, SensedObjects); | ||
184 | } | ||
185 | |||
186 | // If SCRIPTED or PASSIVE or ACTIVE check objects | ||
187 | if ((ts.type & SCRIPTED) != 0 || (ts.type & PASSIVE) != 0 || (ts.type & ACTIVE) != 0) | ||
188 | { | ||
189 | doObjectSensor(ts, SensedObjects); | ||
190 | } | ||
191 | |||
192 | lock (SenseLock) | ||
193 | { | ||
194 | if (SensedObjects.Length == 0) | ||
195 | { | ||
196 | // send a "no_sensor" | ||
197 | // Add it to queue | ||
198 | m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, | ||
199 | new EventParams("no_sensor", new Object[0], | ||
200 | new DetectParams[0])); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // the sort is stride = 2 and ascending to get everything ordered by distance | ||
205 | SensedObjects = SensedObjects.Sort(2, 1); | ||
206 | int count = SensedObjects.Length; | ||
207 | int idx; | ||
208 | List<DetectParams> detected = new List<DetectParams>(); | ||
209 | for (idx = 0; idx < count; idx++) | ||
210 | { | ||
211 | try | ||
212 | { | ||
213 | DetectParams detect = new DetectParams(); | ||
214 | detect.Key = (UUID)(SensedObjects.Data[(idx * 2) + 1]); | ||
215 | detect.Populate(m_CmdManager.m_ScriptEngine.World); | ||
216 | detected.Add(detect); | ||
217 | } | ||
218 | catch (Exception) | ||
219 | { | ||
220 | // Ignore errors, the object has been deleted or the avatar has gone and | ||
221 | // there was a problem in detect.Populate so nothing added to the list | ||
222 | } | ||
223 | if (detected.Count == maximumToReturn) | ||
224 | break; | ||
225 | } | ||
226 | |||
227 | if (detected.Count == 0) | ||
228 | { | ||
229 | // To get here with zero in the list there must have been some sort of problem | ||
230 | // like the object being deleted or the avatar leaving to have caused some | ||
231 | // difficulty during the Populate above so fire a no_sensor event | ||
232 | m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, | ||
233 | new EventParams("no_sensor", new Object[0], | ||
234 | new DetectParams[0])); | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, | ||
239 | new EventParams("sensor", | ||
240 | new Object[] {new LSL_Types.LSLInteger(detected.Count) }, | ||
241 | detected.ToArray())); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | private void doObjectSensor(SenseRepeatClass ts, LSL_Types.list SensedObjects) | ||
248 | { | ||
249 | List<EntityBase> Entities; | ||
250 | |||
251 | // If this is an object sense by key try to get it directly | ||
252 | // rather than getting a list to scan through | ||
253 | if (ts.keyID != UUID.Zero) | ||
254 | { | ||
255 | EntityBase e = null; | ||
256 | m_CmdManager.m_ScriptEngine.World.Entities.TryGetValue(ts.keyID, out e); | ||
257 | if (e == null) | ||
258 | return; | ||
259 | Entities = new List<EntityBase>(); | ||
260 | Entities.Add(e); | ||
261 | } | ||
262 | else | ||
263 | { | ||
264 | Entities = m_CmdManager.m_ScriptEngine.World.GetEntities(); | ||
265 | } | ||
266 | SceneObjectPart SensePoint = ts.host; | ||
267 | |||
168 | Vector3 sensorPos = SensePoint.AbsolutePosition; | 268 | Vector3 sensorPos = SensePoint.AbsolutePosition; |
169 | Vector3 regionPos = new Vector3(m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocX * Constants.RegionSize, m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocY * Constants.RegionSize, 0); | 269 | Vector3 regionPos = new Vector3(m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocX * Constants.RegionSize, m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocY * Constants.RegionSize, 0); |
170 | Vector3 fromRegionPos = sensorPos + regionPos; | 270 | Vector3 fromRegionPos = sensorPos + regionPos; |
@@ -174,37 +274,55 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
174 | LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); | 274 | LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); |
175 | double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); | 275 | double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); |
176 | 276 | ||
177 | // Here we should do some smart culling ... | 277 | Vector3 ZeroVector = new Vector3(0, 0, 0); |
178 | // math seems quicker than strings so try that first | 278 | |
179 | LSL_Types.list SensedObjects = new LSL_Types.list(); | 279 | bool nameSearch = (ts.name != null && ts.name != ""); |
180 | LSL_Types.Vector3 ZeroVector = new LSL_Types.Vector3(0, 0, 0); | 280 | SceneObjectGroup group; |
181 | 281 | ||
182 | foreach (EntityBase ent in m_CmdManager.m_ScriptEngine.World.Entities.Values) | 282 | foreach (EntityBase ent in Entities) |
183 | { | 283 | { |
284 | bool keep = true; | ||
285 | |||
286 | if (nameSearch && ent.Name != ts.name) // Wrong name and it is a named search | ||
287 | continue; | ||
288 | |||
289 | if (ent.IsDeleted) // taken so long to do this it has gone from the scene | ||
290 | continue; | ||
291 | |||
292 | if (!(ent is SceneObjectGroup)) // dont bother if it is a pesky avatar | ||
293 | continue; | ||
294 | |||
184 | Vector3 toRegionPos = ent.AbsolutePosition + regionPos; | 295 | Vector3 toRegionPos = ent.AbsolutePosition + regionPos; |
185 | double dis = Math.Abs((double)Util.GetDistanceTo(toRegionPos, fromRegionPos)); | 296 | double dis = Math.Abs((double)Util.GetDistanceTo(toRegionPos, fromRegionPos)); |
186 | if (dis <= ts.range) | 297 | if (keep && dis <= ts.range && ts.host.UUID != ent.UUID) |
187 | { | 298 | { |
188 | // In Range, is it the right Type ? | 299 | // In Range and not the object containing the script, is it the right Type ? |
189 | int objtype = 0; | 300 | int objtype = 0; |
190 | 301 | ||
191 | if (m_CmdManager.m_ScriptEngine.World.GetScenePresence(ent.UUID) != null) objtype |= 0x01; // actor | 302 | SceneObjectPart part = ((SceneObjectGroup)ent).RootPart; |
192 | if (ent.Velocity.Equals(ZeroVector)) | 303 | if (part.AttachmentPoint != 0) // Attached so ignore |
193 | objtype |= 0x04; // passive non-moving | 304 | continue; |
194 | else | ||
195 | objtype |= 0x02; // active moving | ||
196 | |||
197 | SceneObjectPart part = m_CmdManager.m_ScriptEngine.World.GetSceneObjectPart(ent.UUID); | ||
198 | 305 | ||
199 | if (part != null && part.ContainsScripts()) objtype |= 0x08; // Scripted. It COULD have one hidden ... | 306 | if (part.ContainsScripts()) |
200 | 307 | { | |
201 | if (((ts.type & objtype) != 0) || ((ts.type & objtype) == ts.type)) | 308 | objtype |= ACTIVE | SCRIPTED; // Scripted and active. It COULD have one hidden ... |
309 | } | ||
310 | else | ||
202 | { | 311 | { |
203 | // docs claim AGENT|ACTIVE should find agent objects OR active objects | 312 | if (ent.Velocity.Equals(ZeroVector)) |
204 | // so the bitwise AND with object type should be non-zero | 313 | { |
314 | objtype |= PASSIVE; // Passive non-moving | ||
315 | } | ||
316 | else | ||
317 | { | ||
318 | objtype |= ACTIVE; // moving so active | ||
319 | } | ||
320 | } | ||
205 | 321 | ||
322 | // If any of the objects attributes match any in the requested scan type | ||
323 | if (((ts.type & objtype) != 0)) | ||
324 | { | ||
206 | // Right type too, what about the other params , key and name ? | 325 | // Right type too, what about the other params , key and name ? |
207 | bool keep = true; | ||
208 | if (ts.arc < Math.PI) | 326 | if (ts.arc < Math.PI) |
209 | { | 327 | { |
210 | // not omni-directional. Can you see it ? | 328 | // not omni-directional. Can you see it ? |
@@ -230,67 +348,118 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
230 | if (ang_obj > ts.arc) keep = false; | 348 | if (ang_obj > ts.arc) keep = false; |
231 | } | 349 | } |
232 | 350 | ||
233 | if (keep && (ts.keyID != UUID.Zero) && (ts.keyID != ent.UUID)) | 351 | if (keep == true) |
234 | { | 352 | { |
235 | keep = false; | 353 | // add distance for sorting purposes later |
354 | SensedObjects.Add(new LSL_Types.LSLFloat(dis)); | ||
355 | SensedObjects.Add(ent.UUID); | ||
236 | } | 356 | } |
237 | |||
238 | if (keep && (ts.name.Length > 0)) | ||
239 | { | ||
240 | if (ts.name != ent.Name) | ||
241 | { | ||
242 | keep = false; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | if (keep == true) SensedObjects.Add(ent.UUID); | ||
247 | } | 357 | } |
248 | } | 358 | } |
249 | } | 359 | } |
360 | } | ||
250 | 361 | ||
251 | lock (SenseLock) | 362 | private void doAgentSensor(SenseRepeatClass ts, LSL_Types.list SensedObjects) |
363 | { | ||
364 | List<ScenePresence> Presences; | ||
365 | |||
366 | // If this is an avatar sense by key try to get them directly | ||
367 | // rather than getting a list to scan through | ||
368 | if (ts.keyID != UUID.Zero) | ||
252 | { | 369 | { |
253 | // Create object if it doesn't exist | 370 | ScenePresence p = m_CmdManager.m_ScriptEngine.World.GetScenePresence(ts.keyID); |
254 | if (SenseEvents.ContainsKey(ts.localID) == false) | 371 | if (p == null) |
255 | { | 372 | return; |
256 | SenseEvents.Add(ts.localID, new Dictionary<UUID, LSL_Types.list>()); | 373 | Presences = new List<ScenePresence>(); |
257 | } | 374 | Presences.Add(p); |
258 | // clear if previous traces exist | 375 | } |
259 | Dictionary<UUID, LSL_Types.list> Obj; | 376 | else |
260 | SenseEvents.TryGetValue(ts.localID, out Obj); | 377 | { |
261 | if (Obj.ContainsKey(ts.itemID) == true) | 378 | Presences = m_CmdManager.m_ScriptEngine.World.GetScenePresences(); |
262 | Obj.Remove(ts.itemID); | 379 | } |
263 | 380 | ||
264 | // note list may be zero length | 381 | // If nobody about quit fast |
265 | Obj.Add(ts.itemID, SensedObjects); | 382 | if (Presences.Count == 0) |
383 | return; | ||
266 | 384 | ||
267 | if (SensedObjects.Length == 0) | 385 | SceneObjectPart SensePoint = ts.host; |
268 | { | 386 | |
269 | // send a "no_sensor" | 387 | Vector3 sensorPos = SensePoint.AbsolutePosition; |
270 | // Add it to queue | 388 | Vector3 regionPos = new Vector3(m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocX * Constants.RegionSize, m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocY * Constants.RegionSize, 0); |
271 | m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, | 389 | Vector3 fromRegionPos = sensorPos + regionPos; |
272 | new EventParams("no_sensor", new Object[0], | 390 | |
273 | new DetectParams[0])); | 391 | Quaternion q = SensePoint.RotationOffset; |
274 | } | 392 | LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); |
275 | else | 393 | LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); |
394 | double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); | ||
395 | |||
396 | bool attached = (SensePoint.AttachmentPoint != 0); | ||
397 | bool nameSearch = (ts.name != null && ts.name != ""); | ||
398 | |||
399 | foreach (ScenePresence presence in Presences) | ||
400 | { | ||
401 | bool keep = true; | ||
402 | |||
403 | if (presence.IsDeleted) | ||
404 | continue; | ||
405 | |||
406 | if (presence.IsChildAgent) | ||
407 | keep = false; | ||
408 | |||
409 | Vector3 toRegionPos = presence.AbsolutePosition + regionPos; | ||
410 | double dis = Math.Abs(Util.GetDistanceTo(toRegionPos, fromRegionPos)); | ||
411 | |||
412 | // are they in range | ||
413 | if (keep && dis <= ts.range) | ||
276 | { | 414 | { |
277 | DetectParams[] detect = | 415 | // if the object the script is in is attached and the avatar is the owner |
278 | new DetectParams[SensedObjects.Length]; | 416 | // then this one is not wanted |
417 | if (attached && presence.UUID == SensePoint.OwnerID) | ||
418 | keep = false; | ||
279 | 419 | ||
280 | int idx; | 420 | // check the name if needed |
281 | for (idx = 0; idx < SensedObjects.Length; idx++) | 421 | if (keep && nameSearch && ts.name != presence.Name) |
422 | keep = false; | ||
423 | |||
424 | // Are they in the required angle of view | ||
425 | if (keep && ts.arc < Math.PI) | ||
282 | { | 426 | { |
283 | detect[idx] = new DetectParams(); | 427 | // not omni-directional. Can you see it ? |
284 | detect[idx].Key=(UUID)(SensedObjects.Data[idx]); | 428 | // vec forward_dir = llRot2Fwd(llGetRot()) |
285 | detect[idx].Populate(m_CmdManager.m_ScriptEngine.World); | 429 | // vec obj_dir = toRegionPos-fromRegionPos |
430 | // dot=dot(forward_dir,obj_dir) | ||
431 | // mag_fwd = mag(forward_dir) | ||
432 | // mag_obj = mag(obj_dir) | ||
433 | // ang = acos(dot /(mag_fwd*mag_obj)) | ||
434 | double ang_obj = 0; | ||
435 | try | ||
436 | { | ||
437 | Vector3 diff = toRegionPos - fromRegionPos; | ||
438 | LSL_Types.Vector3 obj_dir = new LSL_Types.Vector3(diff.X, diff.Y, diff.Z); | ||
439 | double dot = LSL_Types.Vector3.Dot(forward_dir, obj_dir); | ||
440 | double mag_obj = LSL_Types.Vector3.Mag(obj_dir); | ||
441 | ang_obj = Math.Acos(dot / (mag_fwd * mag_obj)); | ||
442 | } | ||
443 | catch | ||
444 | { | ||
445 | } | ||
446 | if (ang_obj > ts.arc) keep = false; | ||
286 | } | 447 | } |
448 | } | ||
287 | 449 | ||
288 | m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, | 450 | // Do not report gods, not even minor ones |
289 | new EventParams("sensor", | 451 | if (keep && presence.GodLevel > 0.0) |
290 | new Object[] { | 452 | keep = false; |
291 | new LSL_Types.LSLInteger(SensedObjects.Length) }, | 453 | |
292 | detect)); | 454 | if (keep) // add to list with distance |
455 | { | ||
456 | SensedObjects.Add(new LSL_Types.LSLFloat(dis)); | ||
457 | SensedObjects.Add(presence.UUID); | ||
293 | } | 458 | } |
459 | |||
460 | // If this is a search by name and we have just found it then no more to do | ||
461 | if (nameSearch && ts.name == presence.Name) | ||
462 | return; | ||
294 | } | 463 | } |
295 | } | 464 | } |
296 | 465 | ||