SensorRepeat.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using libsecondlife;
  30. using OpenSim.Framework;
  31. using OpenSim.Region.Environment.Scenes;
  32. using OpenSim.Region.ScriptEngine.XEngine.Script;
  33. namespace OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins
  34. {
  35. public class SensorRepeat
  36. {
  37. public AsyncCommandManager m_CmdManager;
  38. public SensorRepeat(AsyncCommandManager CmdManager)
  39. {
  40. m_CmdManager = CmdManager;
  41. }
  42. public Dictionary<uint, Dictionary<LLUUID, LSL_Types.list>> SenseEvents =
  43. new Dictionary<uint, Dictionary<LLUUID, LSL_Types.list>>();
  44. private Object SenseLock = new Object();
  45. //
  46. // SenseRepeater and Sensors
  47. //
  48. private class SenseRepeatClass
  49. {
  50. public uint localID;
  51. public LLUUID itemID;
  52. public double interval;
  53. public DateTime next;
  54. public string name;
  55. public LLUUID keyID;
  56. public int type;
  57. public double range;
  58. public double arc;
  59. public SceneObjectPart host;
  60. }
  61. private List<SenseRepeatClass> SenseRepeaters = new List<SenseRepeatClass>();
  62. private object SenseRepeatListLock = new object();
  63. public void SetSenseRepeatEvent(uint m_localID, LLUUID m_itemID,
  64. string name, LLUUID keyID, int type, double range, double arc, double sec, SceneObjectPart host)
  65. {
  66. Console.WriteLine("SetSensorEvent");
  67. // Always remove first, in case this is a re-set
  68. UnSetSenseRepeaterEvents(m_localID, m_itemID);
  69. if (sec == 0) // Disabling timer
  70. return;
  71. // Add to timer
  72. SenseRepeatClass ts = new SenseRepeatClass();
  73. ts.localID = m_localID;
  74. ts.itemID = m_itemID;
  75. ts.interval = sec;
  76. ts.name = name;
  77. ts.keyID = keyID;
  78. ts.type = type;
  79. ts.range = range;
  80. ts.arc = arc;
  81. ts.host = host;
  82. ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
  83. lock (SenseRepeatListLock)
  84. {
  85. SenseRepeaters.Add(ts);
  86. }
  87. }
  88. public void UnSetSenseRepeaterEvents(uint m_localID, LLUUID m_itemID)
  89. {
  90. // Remove from timer
  91. lock (SenseRepeatListLock)
  92. {
  93. List<SenseRepeatClass> NewSensors = new List<SenseRepeatClass>();
  94. foreach (SenseRepeatClass ts in SenseRepeaters)
  95. {
  96. if (ts.localID != m_localID && ts.itemID != m_itemID)
  97. {
  98. NewSensors.Add(ts);
  99. }
  100. }
  101. SenseRepeaters.Clear();
  102. SenseRepeaters = NewSensors;
  103. }
  104. }
  105. public void CheckSenseRepeaterEvents()
  106. {
  107. // Nothing to do here?
  108. if (SenseRepeaters.Count == 0)
  109. return;
  110. lock (SenseRepeatListLock)
  111. {
  112. // Go through all timers
  113. foreach (SenseRepeatClass ts in SenseRepeaters)
  114. {
  115. // Time has passed?
  116. if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
  117. {
  118. SensorSweep(ts);
  119. // set next interval
  120. ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
  121. }
  122. }
  123. } // lock
  124. }
  125. public void SenseOnce(uint m_localID, LLUUID m_itemID,
  126. string name, LLUUID keyID, int type,
  127. double range, double arc, SceneObjectPart host)
  128. {
  129. // Add to timer
  130. SenseRepeatClass ts = new SenseRepeatClass();
  131. ts.localID = m_localID;
  132. ts.itemID = m_itemID;
  133. ts.interval = 0;
  134. ts.name = name;
  135. ts.keyID = keyID;
  136. ts.type = type;
  137. ts.range = range;
  138. ts.arc = arc;
  139. ts.host = host;
  140. SensorSweep(ts);
  141. }
  142. public LSL_Types.list GetSensorList(uint m_localID, LLUUID m_itemID)
  143. {
  144. lock (SenseLock)
  145. {
  146. Dictionary<LLUUID, LSL_Types.list> Obj = null;
  147. if (!SenseEvents.TryGetValue(m_localID, out Obj))
  148. {
  149. m_CmdManager.m_ScriptEngine.Log.Info("[AsyncLSL]: GetSensorList missing localID: " + m_localID);
  150. return null;
  151. }
  152. lock (Obj)
  153. {
  154. // Get script
  155. LSL_Types.list SenseList = null;
  156. if (!Obj.TryGetValue(m_itemID, out SenseList))
  157. {
  158. m_CmdManager.m_ScriptEngine.Log.Info("[AsyncLSL]: GetSensorList missing itemID: " + m_itemID);
  159. return null;
  160. }
  161. return SenseList;
  162. }
  163. }
  164. }
  165. private void SensorSweep(SenseRepeatClass ts)
  166. {
  167. //m_ScriptEngine.Log.Info("[AsyncLSL]:Enter SensorSweep");
  168. SceneObjectPart SensePoint = ts.host;
  169. if (SensePoint == null)
  170. {
  171. //m_ScriptEngine.Log.Info("[AsyncLSL]: Enter SensorSweep (SensePoint == null) for "+ts.itemID.ToString());
  172. return;
  173. }
  174. //m_ScriptEngine.Log.Info("[AsyncLSL]: Enter SensorSweep Scan");
  175. LLVector3 sensorPos = SensePoint.AbsolutePosition;
  176. LLVector3 regionPos = new LLVector3(m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocX * Constants.RegionSize, m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
  177. LLVector3 fromRegionPos = sensorPos + regionPos;
  178. LLQuaternion q = SensePoint.RotationOffset;
  179. LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
  180. LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
  181. double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
  182. // Here we should do some smart culling ...
  183. // math seems quicker than strings so try that first
  184. LSL_Types.list SensedObjects = new LSL_Types.list();
  185. LSL_Types.Vector3 ZeroVector = new LSL_Types.Vector3(0, 0, 0);
  186. foreach (EntityBase ent in m_CmdManager.m_ScriptEngine.World.Entities.Values)
  187. {
  188. LLVector3 toRegionPos = ent.AbsolutePosition + regionPos;
  189. double dis = Math.Abs((double)Util.GetDistanceTo(toRegionPos, fromRegionPos));
  190. if (dis <= ts.range)
  191. {
  192. // In Range, is it the right Type ?
  193. int objtype = 0;
  194. if (m_CmdManager.m_ScriptEngine.World.GetScenePresence(ent.UUID) != null) objtype |= 0x01; // actor
  195. if (ent.Velocity.Equals(ZeroVector))
  196. objtype |= 0x04; // passive non-moving
  197. else
  198. objtype |= 0x02; // active moving
  199. if (ent is IScript) objtype |= 0x08; // Scripted. It COULD have one hidden ...
  200. if (((ts.type & objtype) != 0) || ((ts.type & objtype) == ts.type))
  201. {
  202. // docs claim AGENT|ACTIVE should find agent objects OR active objects
  203. // so the bitwise AND with object type should be non-zero
  204. // Right type too, what about the other params , key and name ?
  205. bool keep = true;
  206. if (ts.arc < Math.PI)
  207. {
  208. // not omni-directional. Can you see it ?
  209. // vec forward_dir = llRot2Fwd(llGetRot())
  210. // vec obj_dir = toRegionPos-fromRegionPos
  211. // dot=dot(forward_dir,obj_dir)
  212. // mag_fwd = mag(forward_dir)
  213. // mag_obj = mag(obj_dir)
  214. // ang = acos(dot /(mag_fwd*mag_obj))
  215. double ang_obj = 0;
  216. try
  217. {
  218. LLVector3 diff = toRegionPos - fromRegionPos;
  219. LSL_Types.Vector3 obj_dir = new LSL_Types.Vector3(diff.X, diff.Y, diff.Z);
  220. double dot = LSL_Types.Vector3.Dot(forward_dir, obj_dir);
  221. double mag_obj = LSL_Types.Vector3.Mag(obj_dir);
  222. ang_obj = Math.Acos(dot / (mag_fwd * mag_obj));
  223. }
  224. catch
  225. {
  226. }
  227. if (ang_obj > ts.arc) keep = false;
  228. }
  229. if (keep && (ts.keyID != LLUUID.Zero) && (ts.keyID != ent.UUID))
  230. {
  231. keep = false;
  232. }
  233. if (keep && (ts.name.Length > 0))
  234. {
  235. string avatarname=null;
  236. string objectname=null;
  237. string entname =ent.Name;
  238. // try avatar username surname
  239. UserProfileData profile = m_CmdManager.m_ScriptEngine.World.CommsManager.UserService.GetUserProfile(ent.UUID);
  240. if (profile != null)
  241. {
  242. avatarname = profile.FirstName + " " + profile.SurName;
  243. }
  244. // try an scene object
  245. SceneObjectPart SOP = m_CmdManager.m_ScriptEngine.World.GetSceneObjectPart(ent.UUID);
  246. if (SOP != null)
  247. {
  248. objectname = SOP.Name;
  249. }
  250. if ((ts.name != entname) && (ts.name != avatarname) && (ts.name != objectname))
  251. {
  252. keep = false;
  253. }
  254. }
  255. if (keep == true) SensedObjects.Add(ent.UUID);
  256. }
  257. }
  258. }
  259. //m_ScriptEngine.Log.Info("[AsyncLSL]: Enter SensorSweep SenseLock");
  260. lock (SenseLock)
  261. {
  262. // Create object if it doesn't exist
  263. if (SenseEvents.ContainsKey(ts.localID) == false)
  264. {
  265. SenseEvents.Add(ts.localID, new Dictionary<LLUUID, LSL_Types.list>());
  266. }
  267. // clear if previous traces exist
  268. Dictionary<LLUUID, LSL_Types.list> Obj;
  269. SenseEvents.TryGetValue(ts.localID, out Obj);
  270. if (Obj.ContainsKey(ts.itemID) == true)
  271. Obj.Remove(ts.itemID);
  272. // note list may be zero length
  273. Obj.Add(ts.itemID, SensedObjects);
  274. if (SensedObjects.Length == 0)
  275. {
  276. // send a "no_sensor"
  277. // Add it to queue
  278. m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
  279. new XEventParams("no_sensor", new Object[0],
  280. new XDetectParams[0]));
  281. }
  282. else
  283. {
  284. XDetectParams[] detect =
  285. new XDetectParams[SensedObjects.Length];
  286. int idx;
  287. for(idx = 0 ; idx < SensedObjects.Length; idx++)
  288. {
  289. detect[idx].Key=(LLUUID)(SensedObjects.Data[idx]);
  290. }
  291. m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
  292. new XEventParams("sensor",
  293. new Object[] {
  294. new LSL_Types.LSLInteger(SensedObjects.Length) },
  295. detect));
  296. }
  297. }
  298. }
  299. public Object[] GetSerializationData(LLUUID itemID)
  300. {
  301. List<Object> data = new List<Object>();
  302. foreach (SenseRepeatClass ts in SenseRepeaters)
  303. {
  304. if(ts.itemID == itemID)
  305. {
  306. data.Add(ts.interval);
  307. data.Add(ts.name);
  308. data.Add(ts.keyID);
  309. data.Add(ts.type);
  310. data.Add(ts.range);
  311. data.Add(ts.arc);
  312. }
  313. }
  314. return data.ToArray();
  315. }
  316. public void CreateFromData(uint localID, LLUUID itemID, LLUUID objectID,
  317. Object[] data)
  318. {
  319. SceneObjectPart part =
  320. m_CmdManager.m_ScriptEngine.World.GetSceneObjectPart(
  321. objectID);
  322. if(part == null)
  323. return;
  324. int idx=0;
  325. while(idx < data.Length)
  326. {
  327. SenseRepeatClass ts = new SenseRepeatClass();
  328. ts.localID = localID;
  329. ts.itemID = itemID;
  330. ts.interval = (double)data[idx];
  331. ts.name = (string)data[idx+1];
  332. ts.keyID = (LLUUID)data[idx+2];
  333. ts.type = (int)data[idx+3];
  334. ts.range = (double)data[idx+4];
  335. ts.arc = (double)data[idx+5];
  336. ts.host = part;
  337. ts.next =
  338. DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
  339. SenseRepeaters.Add(ts);
  340. idx += 6;
  341. }
  342. }
  343. }
  344. }