PageRenderTime 115ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 2ms

/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs

https://bitbucket.org/KyanhaLLC/opensim
C# | 11784 lines | 8932 code | 1681 blank | 1171 comment | 1937 complexity | cd8c1e05459df14cd225b18da69481df MD5 | raw file
Possible License(s): Unlicense, MIT, BSD-3-Clause
  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 OpenSimulator 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;
  29. using System.Collections.Generic;
  30. using System.Runtime.Remoting.Lifetime;
  31. using System.Text;
  32. using System.Threading;
  33. using System.Text.RegularExpressions;
  34. using Nini.Config;
  35. using log4net;
  36. using OpenMetaverse;
  37. using OpenMetaverse.Packets;
  38. using OpenSim;
  39. using OpenSim.Framework;
  40. using OpenSim.Region.CoreModules;
  41. using OpenSim.Region.CoreModules.World.Land;
  42. using OpenSim.Region.CoreModules.World.Terrain;
  43. using OpenSim.Region.Framework.Interfaces;
  44. using OpenSim.Region.Framework.Scenes;
  45. using OpenSim.Region.Framework.Scenes.Animation;
  46. using OpenSim.Region.Framework.Scenes.Scripting;
  47. using OpenSim.Region.Physics.Manager;
  48. using OpenSim.Region.ScriptEngine.Shared;
  49. using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
  50. using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
  51. using OpenSim.Region.ScriptEngine.Interfaces;
  52. using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
  53. using OpenSim.Services.Interfaces;
  54. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  55. using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
  56. using PrimType = OpenSim.Region.Framework.Scenes.PrimType;
  57. using AssetLandmark = OpenSim.Framework.AssetLandmark;
  58. using RegionFlags = OpenSim.Framework.RegionFlags;
  59. using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
  60. using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
  61. using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  62. using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
  63. using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
  64. using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  65. using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
  66. using System.Reflection;
  67. namespace OpenSim.Region.ScriptEngine.Shared.Api
  68. {
  69. // MUST be a ref type
  70. public class UserInfoCacheEntry
  71. {
  72. public int time;
  73. public UserAccount account;
  74. public PresenceInfo pinfo;
  75. }
  76. /// <summary>
  77. /// Contains all LSL ll-functions. This class will be in Default AppDomain.
  78. /// </summary>
  79. public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
  80. {
  81. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  82. protected IScriptEngine m_ScriptEngine;
  83. protected SceneObjectPart m_host;
  84. /// <summary>
  85. /// Used for script sleeps when we are using co-operative script termination.
  86. /// </summary>
  87. /// <remarks>null if co-operative script termination is not active</remarks>
  88. WaitHandle m_coopSleepHandle;
  89. /// <summary>
  90. /// The item that hosts this script
  91. /// </summary>
  92. protected TaskInventoryItem m_item;
  93. protected bool throwErrorOnNotImplemented = true;
  94. protected AsyncCommandManager AsyncCommands = null;
  95. protected float m_ScriptDelayFactor = 1.0f;
  96. protected float m_ScriptDistanceFactor = 1.0f;
  97. protected float m_MinTimerInterval = 0.5f;
  98. protected float m_recoilScaleFactor = 0.0f;
  99. protected DateTime m_timer = DateTime.Now;
  100. protected bool m_waitingForScriptAnswer = false;
  101. protected bool m_automaticLinkPermission = false;
  102. protected IMessageTransferModule m_TransferModule = null;
  103. protected int m_notecardLineReadCharsMax = 255;
  104. protected int m_scriptConsoleChannel = 0;
  105. protected bool m_scriptConsoleChannelEnabled = false;
  106. protected IUrlModule m_UrlModule = null;
  107. protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache = new Dictionary<UUID, UserInfoCacheEntry>();
  108. protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp.
  109. protected ISoundModule m_SoundModule = null;
  110. public void Initialize(
  111. IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle)
  112. {
  113. m_ScriptEngine = scriptEngine;
  114. m_host = host;
  115. m_item = item;
  116. m_coopSleepHandle = coopSleepHandle;
  117. LoadConfig();
  118. m_TransferModule =
  119. m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>();
  120. m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>();
  121. m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>();
  122. AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
  123. }
  124. /// <summary>
  125. /// Load configuration items that affect script, object and run-time behavior. */
  126. /// </summary>
  127. private void LoadConfig()
  128. {
  129. m_ScriptDelayFactor =
  130. m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f);
  131. m_ScriptDistanceFactor =
  132. m_ScriptEngine.Config.GetFloat("ScriptDistanceLimitFactor", 1.0f);
  133. m_MinTimerInterval =
  134. m_ScriptEngine.Config.GetFloat("MinTimerInterval", 0.5f);
  135. m_automaticLinkPermission =
  136. m_ScriptEngine.Config.GetBoolean("AutomaticLinkPermission", false);
  137. m_notecardLineReadCharsMax =
  138. m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255);
  139. if (m_notecardLineReadCharsMax > 65535)
  140. m_notecardLineReadCharsMax = 65535;
  141. // load limits for particular subsystems.
  142. IConfig SMTPConfig;
  143. if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) {
  144. // there's an smtp config, so load in the snooze time.
  145. EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME);
  146. }
  147. // Rezzing an object with a velocity can create recoil. This feature seems to have been
  148. // removed from recent versions of SL. The code computes recoil (vel*mass) and scales
  149. // it by this factor. May be zero to turn off recoil all together.
  150. m_recoilScaleFactor = m_ScriptEngine.Config.GetFloat("RecoilScaleFactor", m_recoilScaleFactor);
  151. }
  152. public override Object InitializeLifetimeService()
  153. {
  154. ILease lease = (ILease)base.InitializeLifetimeService();
  155. if (lease.CurrentState == LeaseState.Initial)
  156. {
  157. lease.InitialLeaseTime = TimeSpan.FromMinutes(0);
  158. // lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
  159. // lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
  160. }
  161. return lease;
  162. }
  163. protected virtual void ScriptSleep(int delay)
  164. {
  165. delay = (int)((float)delay * m_ScriptDelayFactor);
  166. if (delay == 0)
  167. return;
  168. Sleep(delay);
  169. }
  170. protected virtual void Sleep(int delay)
  171. {
  172. if (m_coopSleepHandle == null)
  173. System.Threading.Thread.Sleep(delay);
  174. else
  175. CheckForCoopTermination(delay);
  176. }
  177. /// <summary>
  178. /// Check for co-operative termination.
  179. /// </summary>
  180. /// <param name='delay'>If called with 0, then just the check is performed with no wait.</param>
  181. protected virtual void CheckForCoopTermination(int delay)
  182. {
  183. if (m_coopSleepHandle.WaitOne(delay))
  184. throw new ScriptCoopStopException();
  185. }
  186. public Scene World
  187. {
  188. get { return m_ScriptEngine.World; }
  189. }
  190. public void state(string newState)
  191. {
  192. m_ScriptEngine.SetState(m_item.ItemID, newState);
  193. }
  194. /// <summary>
  195. /// Reset the named script. The script must be present
  196. /// in the same prim.
  197. /// </summary>
  198. public void llResetScript()
  199. {
  200. m_host.AddScriptLPS(1);
  201. // We need to tell the URL module, if we hav one, to release
  202. // the allocated URLs
  203. if (m_UrlModule != null)
  204. m_UrlModule.ScriptRemoved(m_item.ItemID);
  205. m_ScriptEngine.ApiResetScript(m_item.ItemID);
  206. }
  207. public void llResetOtherScript(string name)
  208. {
  209. UUID item;
  210. m_host.AddScriptLPS(1);
  211. if ((item = GetScriptByName(name)) != UUID.Zero)
  212. m_ScriptEngine.ResetScript(item);
  213. else
  214. ShoutError("llResetOtherScript: script "+name+" not found");
  215. }
  216. public LSL_Integer llGetScriptState(string name)
  217. {
  218. UUID item;
  219. m_host.AddScriptLPS(1);
  220. if ((item = GetScriptByName(name)) != UUID.Zero)
  221. {
  222. return m_ScriptEngine.GetScriptState(item) ?1:0;
  223. }
  224. ShoutError("llGetScriptState: script "+name+" not found");
  225. // If we didn't find it, then it's safe to
  226. // assume it is not running.
  227. return 0;
  228. }
  229. public void llSetScriptState(string name, int run)
  230. {
  231. UUID item;
  232. m_host.AddScriptLPS(1);
  233. // These functions are supposed to be robust,
  234. // so get the state one step at a time.
  235. if ((item = GetScriptByName(name)) != UUID.Zero)
  236. {
  237. m_ScriptEngine.SetScriptState(item, run == 0 ? false : true);
  238. }
  239. else
  240. {
  241. ShoutError("llSetScriptState: script "+name+" not found");
  242. }
  243. }
  244. public List<SceneObjectPart> GetLinkParts(int linkType)
  245. {
  246. return GetLinkParts(m_host, linkType);
  247. }
  248. public static List<SceneObjectPart> GetLinkParts(SceneObjectPart part, int linkType)
  249. {
  250. List<SceneObjectPart> ret = new List<SceneObjectPart>();
  251. ret.Add(part);
  252. switch (linkType)
  253. {
  254. case ScriptBaseClass.LINK_SET:
  255. return new List<SceneObjectPart>(part.ParentGroup.Parts);
  256. case ScriptBaseClass.LINK_ROOT:
  257. ret = new List<SceneObjectPart>();
  258. ret.Add(part.ParentGroup.RootPart);
  259. return ret;
  260. case ScriptBaseClass.LINK_ALL_OTHERS:
  261. ret = new List<SceneObjectPart>(part.ParentGroup.Parts);
  262. if (ret.Contains(part))
  263. ret.Remove(part);
  264. return ret;
  265. case ScriptBaseClass.LINK_ALL_CHILDREN:
  266. ret = new List<SceneObjectPart>(part.ParentGroup.Parts);
  267. if (ret.Contains(part.ParentGroup.RootPart))
  268. ret.Remove(part.ParentGroup.RootPart);
  269. return ret;
  270. case ScriptBaseClass.LINK_THIS:
  271. return ret;
  272. default:
  273. if (linkType < 0)
  274. return new List<SceneObjectPart>();
  275. SceneObjectPart target = part.ParentGroup.GetLinkNumPart(linkType);
  276. if (target == null)
  277. return new List<SceneObjectPart>();
  278. ret = new List<SceneObjectPart>();
  279. ret.Add(target);
  280. return ret;
  281. }
  282. }
  283. //These are the implementations of the various ll-functions used by the LSL scripts.
  284. public LSL_Float llSin(double f)
  285. {
  286. m_host.AddScriptLPS(1);
  287. return (double)Math.Sin(f);
  288. }
  289. public LSL_Float llCos(double f)
  290. {
  291. m_host.AddScriptLPS(1);
  292. return (double)Math.Cos(f);
  293. }
  294. public LSL_Float llTan(double f)
  295. {
  296. m_host.AddScriptLPS(1);
  297. return (double)Math.Tan(f);
  298. }
  299. public LSL_Float llAtan2(double x, double y)
  300. {
  301. m_host.AddScriptLPS(1);
  302. return (double)Math.Atan2(x, y);
  303. }
  304. public LSL_Float llSqrt(double f)
  305. {
  306. m_host.AddScriptLPS(1);
  307. return (double)Math.Sqrt(f);
  308. }
  309. public LSL_Float llPow(double fbase, double fexponent)
  310. {
  311. m_host.AddScriptLPS(1);
  312. return (double)Math.Pow(fbase, fexponent);
  313. }
  314. public LSL_Integer llAbs(int i)
  315. {
  316. // changed to replicate LSL behaviour whereby minimum int value is returned untouched.
  317. m_host.AddScriptLPS(1);
  318. if (i == Int32.MinValue)
  319. return i;
  320. else
  321. return (int)Math.Abs(i);
  322. }
  323. public LSL_Float llFabs(double f)
  324. {
  325. m_host.AddScriptLPS(1);
  326. return (double)Math.Abs(f);
  327. }
  328. public LSL_Float llFrand(double mag)
  329. {
  330. m_host.AddScriptLPS(1);
  331. lock (Util.RandomClass)
  332. {
  333. return Util.RandomClass.NextDouble() * mag;
  334. }
  335. }
  336. public LSL_Integer llFloor(double f)
  337. {
  338. m_host.AddScriptLPS(1);
  339. return (int)Math.Floor(f);
  340. }
  341. public LSL_Integer llCeil(double f)
  342. {
  343. m_host.AddScriptLPS(1);
  344. return (int)Math.Ceiling(f);
  345. }
  346. // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
  347. public LSL_Integer llRound(double f)
  348. {
  349. m_host.AddScriptLPS(1);
  350. return (int)Math.Round(f, MidpointRounding.AwayFromZero);
  351. }
  352. //This next group are vector operations involving squaring and square root. ckrinke
  353. public LSL_Float llVecMag(LSL_Vector v)
  354. {
  355. m_host.AddScriptLPS(1);
  356. return LSL_Vector.Mag(v);
  357. }
  358. public LSL_Vector llVecNorm(LSL_Vector v)
  359. {
  360. m_host.AddScriptLPS(1);
  361. return LSL_Vector.Norm(v);
  362. }
  363. private double VecDist(LSL_Vector a, LSL_Vector b)
  364. {
  365. double dx = a.x - b.x;
  366. double dy = a.y - b.y;
  367. double dz = a.z - b.z;
  368. return Math.Sqrt(dx * dx + dy * dy + dz * dz);
  369. }
  370. public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b)
  371. {
  372. m_host.AddScriptLPS(1);
  373. return VecDist(a, b);
  374. }
  375. //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
  376. /// <summary>
  377. /// Convert an LSL rotation to a Euler vector.
  378. /// </summary>
  379. /// <remarks>
  380. /// Using algorithm based off http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/quat_2_euler_paper_ver2-1.pdf
  381. /// to avoid issues with singularity and rounding with Y rotation of +/- PI/2
  382. /// </remarks>
  383. /// <param name="r"></param>
  384. /// <returns></returns>
  385. public LSL_Vector llRot2Euler(LSL_Rotation r)
  386. {
  387. m_host.AddScriptLPS(1);
  388. LSL_Vector v = new LSL_Vector(0.0, 0.0, 1.0) * r; // Z axis unit vector unaffected by Z rotation component of r.
  389. double m = LSL_Vector.Mag(v); // Just in case v isn't normalized, need magnitude for Asin() operation later.
  390. if (m == 0.0) return new LSL_Vector();
  391. double x = Math.Atan2(-v.y, v.z);
  392. double sin = v.x / m;
  393. if (sin < -0.999999 || sin > 0.999999) x = 0.0; // Force X rotation to 0 at the singularities.
  394. double y = Math.Asin(sin);
  395. // Rotate X axis unit vector by r and unwind the X and Y rotations leaving only the Z rotation
  396. v = new LSL_Vector(1.0, 0.0, 0.0) * ((r * new LSL_Rotation(Math.Sin(-x / 2.0), 0.0, 0.0, Math.Cos(-x / 2.0))) * new LSL_Rotation(0.0, Math.Sin(-y / 2.0), 0.0, Math.Cos(-y / 2.0)));
  397. double z = Math.Atan2(v.y, v.x);
  398. return new LSL_Vector(x, y, z);
  399. }
  400. /* From wiki:
  401. The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes
  402. in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation,
  403. a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting
  404. vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis.
  405. */
  406. /* How we arrived at this llEuler2Rot
  407. *
  408. * Experiment in SL to determine conventions:
  409. * llEuler2Rot(<PI,0,0>)=<1,0,0,0>
  410. * llEuler2Rot(<0,PI,0>)=<0,1,0,0>
  411. * llEuler2Rot(<0,0,PI>)=<0,0,1,0>
  412. *
  413. * Important facts about Quaternions
  414. * - multiplication is non-commutative (a*b != b*a)
  415. * - http://en.wikipedia.org/wiki/Quaternion#Basis_multiplication
  416. *
  417. * Above SL experiment gives (c1,c2,c3,s1,s2,s3 as defined in our llEuler2Rot):
  418. * Qx = c1+i*s1
  419. * Qy = c2+j*s2;
  420. * Qz = c3+k*s3;
  421. *
  422. * Rotations applied in order (from above) Z, Y, X
  423. * Q = (Qz * Qy) * Qx
  424. * ((c1+i*s1)*(c2+j*s2))*(c3+k*s3)
  425. * (c1*c2+i*s1*c2+j*c1*s2+ij*s1*s2)*(c3+k*s3)
  426. * (c1*c2+i*s1*c2+j*c1*s2+k*s1*s2)*(c3+k*s3)
  427. * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3+ik*s1*c2*s3+jk*c1*s2*s3+kk*s1*s2*s3
  428. * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3 -j*s1*c2*s3 +i*c1*s2*s3 -s1*s2*s3
  429. * regroup: x=i*(s1*c2*c3+c1*s2*s3)
  430. * y=j*(c1*s2*c3-s1*c2*s3)
  431. * z=k*(s1*s2*c3+c1*c2*s3)
  432. * s= c1*c2*c3-s1*s2*s3
  433. *
  434. * This implementation agrees with the functions found here:
  435. * http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions
  436. * And with the results in SL.
  437. *
  438. * It's also possible to calculate llEuler2Rot by direct multiplication of
  439. * the Qz, Qy, and Qx vectors (as above - and done in the "accurate" function
  440. * from the wiki).
  441. * Apparently in some cases this is better from a numerical precision perspective?
  442. */
  443. public LSL_Rotation llEuler2Rot(LSL_Vector v)
  444. {
  445. m_host.AddScriptLPS(1);
  446. double x,y,z,s;
  447. double c1 = Math.Cos(v.x * 0.5);
  448. double c2 = Math.Cos(v.y * 0.5);
  449. double c3 = Math.Cos(v.z * 0.5);
  450. double s1 = Math.Sin(v.x * 0.5);
  451. double s2 = Math.Sin(v.y * 0.5);
  452. double s3 = Math.Sin(v.z * 0.5);
  453. x = s1 * c2 * c3 + c1 * s2 * s3;
  454. y = c1 * s2 * c3 - s1 * c2 * s3;
  455. z = s1 * s2 * c3 + c1 * c2 * s3;
  456. s = c1 * c2 * c3 - s1 * s2 * s3;
  457. return new LSL_Rotation(x, y, z, s);
  458. }
  459. public LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up)
  460. {
  461. m_host.AddScriptLPS(1);
  462. double s;
  463. double tr = fwd.x + left.y + up.z + 1.0;
  464. if (tr >= 1.0)
  465. {
  466. s = 0.5 / Math.Sqrt(tr);
  467. return new LSL_Rotation(
  468. (left.z - up.y) * s,
  469. (up.x - fwd.z) * s,
  470. (fwd.y - left.x) * s,
  471. 0.25 / s);
  472. }
  473. else
  474. {
  475. double max = (left.y > up.z) ? left.y : up.z;
  476. if (max < fwd.x)
  477. {
  478. s = Math.Sqrt(fwd.x - (left.y + up.z) + 1.0);
  479. double x = s * 0.5;
  480. s = 0.5 / s;
  481. return new LSL_Rotation(
  482. x,
  483. (fwd.y + left.x) * s,
  484. (up.x + fwd.z) * s,
  485. (left.z - up.y) * s);
  486. }
  487. else if (max == left.y)
  488. {
  489. s = Math.Sqrt(left.y - (up.z + fwd.x) + 1.0);
  490. double y = s * 0.5;
  491. s = 0.5 / s;
  492. return new LSL_Rotation(
  493. (fwd.y + left.x) * s,
  494. y,
  495. (left.z + up.y) * s,
  496. (up.x - fwd.z) * s);
  497. }
  498. else
  499. {
  500. s = Math.Sqrt(up.z - (fwd.x + left.y) + 1.0);
  501. double z = s * 0.5;
  502. s = 0.5 / s;
  503. return new LSL_Rotation(
  504. (up.x + fwd.z) * s,
  505. (left.z + up.y) * s,
  506. z,
  507. (fwd.y - left.x) * s);
  508. }
  509. }
  510. }
  511. public LSL_Vector llRot2Fwd(LSL_Rotation r)
  512. {
  513. m_host.AddScriptLPS(1);
  514. double x, y, z, m;
  515. m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
  516. // m is always greater than zero
  517. // if m is not equal to 1 then Rotation needs to be normalized
  518. if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
  519. {
  520. m = 1.0 / Math.Sqrt(m);
  521. r.x *= m;
  522. r.y *= m;
  523. r.z *= m;
  524. r.s *= m;
  525. }
  526. // Fast Algebric Calculations instead of Vectors & Quaternions Product
  527. x = r.x * r.x - r.y * r.y - r.z * r.z + r.s * r.s;
  528. y = 2 * (r.x * r.y + r.z * r.s);
  529. z = 2 * (r.x * r.z - r.y * r.s);
  530. return (new LSL_Vector(x, y, z));
  531. }
  532. public LSL_Vector llRot2Left(LSL_Rotation r)
  533. {
  534. m_host.AddScriptLPS(1);
  535. double x, y, z, m;
  536. m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
  537. // m is always greater than zero
  538. // if m is not equal to 1 then Rotation needs to be normalized
  539. if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
  540. {
  541. m = 1.0 / Math.Sqrt(m);
  542. r.x *= m;
  543. r.y *= m;
  544. r.z *= m;
  545. r.s *= m;
  546. }
  547. // Fast Algebric Calculations instead of Vectors & Quaternions Product
  548. x = 2 * (r.x * r.y - r.z * r.s);
  549. y = -r.x * r.x + r.y * r.y - r.z * r.z + r.s * r.s;
  550. z = 2 * (r.x * r.s + r.y * r.z);
  551. return (new LSL_Vector(x, y, z));
  552. }
  553. public LSL_Vector llRot2Up(LSL_Rotation r)
  554. {
  555. m_host.AddScriptLPS(1);
  556. double x, y, z, m;
  557. m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
  558. // m is always greater than zero
  559. // if m is not equal to 1 then Rotation needs to be normalized
  560. if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
  561. {
  562. m = 1.0 / Math.Sqrt(m);
  563. r.x *= m;
  564. r.y *= m;
  565. r.z *= m;
  566. r.s *= m;
  567. }
  568. // Fast Algebric Calculations instead of Vectors & Quaternions Product
  569. x = 2 * (r.x * r.z + r.y * r.s);
  570. y = 2 * (-r.x * r.s + r.y * r.z);
  571. z = -r.x * r.x - r.y * r.y + r.z * r.z + r.s * r.s;
  572. return (new LSL_Vector(x, y, z));
  573. }
  574. public LSL_Rotation llRotBetween(LSL_Vector a, LSL_Vector b)
  575. {
  576. //A and B should both be normalized
  577. m_host.AddScriptLPS(1);
  578. LSL_Rotation rotBetween;
  579. // Check for zero vectors. If either is zero, return zero rotation. Otherwise,
  580. // continue calculation.
  581. if (a == new LSL_Vector(0.0f, 0.0f, 0.0f) || b == new LSL_Vector(0.0f, 0.0f, 0.0f))
  582. {
  583. rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
  584. }
  585. else
  586. {
  587. a = LSL_Vector.Norm(a);
  588. b = LSL_Vector.Norm(b);
  589. double dotProduct = LSL_Vector.Dot(a, b);
  590. // There are two degenerate cases possible. These are for vectors 180 or
  591. // 0 degrees apart. These have to be detected and handled individually.
  592. //
  593. // Check for vectors 180 degrees apart.
  594. // A dot product of -1 would mean the angle between vectors is 180 degrees.
  595. if (dotProduct < -0.9999999f)
  596. {
  597. // First assume X axis is orthogonal to the vectors.
  598. LSL_Vector orthoVector = new LSL_Vector(1.0f, 0.0f, 0.0f);
  599. orthoVector = orthoVector - a * (a.x / LSL_Vector.Dot(a, a));
  600. // Check for near zero vector. A very small non-zero number here will create
  601. // a rotation in an undesired direction.
  602. if (LSL_Vector.Mag(orthoVector) > 0.0001)
  603. {
  604. rotBetween = new LSL_Rotation(orthoVector.x, orthoVector.y, orthoVector.z, 0.0f);
  605. }
  606. // If the magnitude of the vector was near zero, then assume the X axis is not
  607. // orthogonal and use the Z axis instead.
  608. else
  609. {
  610. // Set 180 z rotation.
  611. rotBetween = new LSL_Rotation(0.0f, 0.0f, 1.0f, 0.0f);
  612. }
  613. }
  614. // Check for parallel vectors.
  615. // A dot product of 1 would mean the angle between vectors is 0 degrees.
  616. else if (dotProduct > 0.9999999f)
  617. {
  618. // Set zero rotation.
  619. rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
  620. }
  621. else
  622. {
  623. // All special checks have been performed so get the axis of rotation.
  624. LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
  625. // Quarternion s value is the length of the unit vector + dot product.
  626. double qs = 1.0 + dotProduct;
  627. rotBetween = new LSL_Rotation(crossProduct.x, crossProduct.y, crossProduct.z, qs);
  628. // Normalize the rotation.
  629. double mag = LSL_Rotation.Mag(rotBetween);
  630. // We shouldn't have to worry about a divide by zero here. The qs value will be
  631. // non-zero because we already know if we're here, then the dotProduct is not -1 so
  632. // qs will not be zero. Also, we've already handled the input vectors being zero so the
  633. // crossProduct vector should also not be zero.
  634. rotBetween.x = rotBetween.x / mag;
  635. rotBetween.y = rotBetween.y / mag;
  636. rotBetween.z = rotBetween.z / mag;
  637. rotBetween.s = rotBetween.s / mag;
  638. // Check for undefined values and set zero rotation if any found. This code might not actually be required
  639. // any longer since zero vectors are checked for at the top.
  640. if (Double.IsNaN(rotBetween.x) || Double.IsNaN(rotBetween.y) || Double.IsNaN(rotBetween.z) || Double.IsNaN(rotBetween.s))
  641. {
  642. rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
  643. }
  644. }
  645. }
  646. return rotBetween;
  647. }
  648. public void llWhisper(int channelID, string text)
  649. {
  650. m_host.AddScriptLPS(1);
  651. if (text.Length > 1023)
  652. text = text.Substring(0, 1023);
  653. World.SimChat(Utils.StringToBytes(text),
  654. ChatTypeEnum.Whisper, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
  655. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  656. if (wComm != null)
  657. wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text);
  658. }
  659. public void llSay(int channelID, string text)
  660. {
  661. m_host.AddScriptLPS(1);
  662. if (m_scriptConsoleChannelEnabled && (channelID == m_scriptConsoleChannel))
  663. {
  664. Console.WriteLine(text);
  665. }
  666. else
  667. {
  668. if (text.Length > 1023)
  669. text = text.Substring(0, 1023);
  670. World.SimChat(Utils.StringToBytes(text),
  671. ChatTypeEnum.Say, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
  672. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  673. if (wComm != null)
  674. wComm.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, text);
  675. }
  676. }
  677. public void llShout(int channelID, string text)
  678. {
  679. m_host.AddScriptLPS(1);
  680. if (text.Length > 1023)
  681. text = text.Substring(0, 1023);
  682. World.SimChat(Utils.StringToBytes(text),
  683. ChatTypeEnum.Shout, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true);
  684. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  685. if (wComm != null)
  686. wComm.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, text);
  687. }
  688. public void llRegionSay(int channelID, string text)
  689. {
  690. if (channelID == 0)
  691. {
  692. LSLError("Cannot use llRegionSay() on channel 0");
  693. return;
  694. }
  695. if (text.Length > 1023)
  696. text = text.Substring(0, 1023);
  697. m_host.AddScriptLPS(1);
  698. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  699. if (wComm != null)
  700. wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
  701. }
  702. public void llRegionSayTo(string target, int channel, string msg)
  703. {
  704. if (msg.Length > 1023)
  705. msg = msg.Substring(0, 1023);
  706. m_host.AddScriptLPS(1);
  707. if (channel == ScriptBaseClass.DEBUG_CHANNEL)
  708. {
  709. return;
  710. }
  711. UUID TargetID;
  712. UUID.TryParse(target, out TargetID);
  713. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  714. if (wComm != null)
  715. wComm.DeliverMessageTo(TargetID, channel, m_host.AbsolutePosition, m_host.Name, m_host.UUID, msg);
  716. }
  717. public LSL_Integer llListen(int channelID, string name, string ID, string msg)
  718. {
  719. m_host.AddScriptLPS(1);
  720. UUID keyID;
  721. UUID.TryParse(ID, out keyID);
  722. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  723. if (wComm != null)
  724. return wComm.Listen(m_host.LocalId, m_item.ItemID, m_host.UUID, channelID, name, keyID, msg);
  725. else
  726. return -1;
  727. }
  728. public void llListenControl(int number, int active)
  729. {
  730. m_host.AddScriptLPS(1);
  731. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  732. if (wComm != null)
  733. wComm.ListenControl(m_item.ItemID, number, active);
  734. }
  735. public void llListenRemove(int number)
  736. {
  737. m_host.AddScriptLPS(1);
  738. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  739. if (wComm != null)
  740. wComm.ListenRemove(m_item.ItemID, number);
  741. }
  742. public void llSensor(string name, string id, int type, double range, double arc)
  743. {
  744. m_host.AddScriptLPS(1);
  745. UUID keyID = UUID.Zero;
  746. UUID.TryParse(id, out keyID);
  747. AsyncCommands.SensorRepeatPlugin.SenseOnce(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, m_host);
  748. }
  749. public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
  750. {
  751. m_host.AddScriptLPS(1);
  752. UUID keyID = UUID.Zero;
  753. UUID.TryParse(id, out keyID);
  754. AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, rate, m_host);
  755. }
  756. public void llSensorRemove()
  757. {
  758. m_host.AddScriptLPS(1);
  759. AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_host.LocalId, m_item.ItemID);
  760. }
  761. public string resolveName(UUID objecUUID)
  762. {
  763. // try avatar username surname
  764. UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, objecUUID);
  765. if (account != null)
  766. {
  767. string avatarname = account.Name;
  768. return avatarname;
  769. }
  770. // try an scene object
  771. SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
  772. if (SOP != null)
  773. {
  774. string objectname = SOP.Name;
  775. return objectname;
  776. }
  777. EntityBase SensedObject;
  778. World.Entities.TryGetValue(objecUUID, out SensedObject);
  779. if (SensedObject == null)
  780. {
  781. IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
  782. if (groups != null)
  783. {
  784. GroupRecord gr = groups.GetGroupRecord(objecUUID);
  785. if (gr != null)
  786. return gr.GroupName;
  787. }
  788. return String.Empty;
  789. }
  790. return SensedObject.Name;
  791. }
  792. public LSL_String llDetectedName(int number)
  793. {
  794. m_host.AddScriptLPS(1);
  795. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  796. if (detectedParams == null)
  797. return String.Empty;
  798. return detectedParams.Name;
  799. }
  800. public LSL_String llDetectedKey(int number)
  801. {
  802. m_host.AddScriptLPS(1);
  803. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  804. if (detectedParams == null)
  805. return String.Empty;
  806. return detectedParams.Key.ToString();
  807. }
  808. public LSL_String llDetectedOwner(int number)
  809. {
  810. m_host.AddScriptLPS(1);
  811. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  812. if (detectedParams == null)
  813. return String.Empty;
  814. return detectedParams.Owner.ToString();
  815. }
  816. public LSL_Integer llDetectedType(int number)
  817. {
  818. m_host.AddScriptLPS(1);
  819. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  820. if (detectedParams == null)
  821. return 0;
  822. return new LSL_Integer(detectedParams.Type);
  823. }
  824. public LSL_Vector llDetectedPos(int number)
  825. {
  826. m_host.AddScriptLPS(1);
  827. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  828. if (detectedParams == null)
  829. return new LSL_Vector();
  830. return detectedParams.Position;
  831. }
  832. public LSL_Vector llDetectedVel(int number)
  833. {
  834. m_host.AddScriptLPS(1);
  835. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  836. if (detectedParams == null)
  837. return new LSL_Vector();
  838. return detectedParams.Velocity;
  839. }
  840. public LSL_Vector llDetectedGrab(int number)
  841. {
  842. m_host.AddScriptLPS(1);
  843. DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  844. if (parms == null)
  845. return new LSL_Vector(0, 0, 0);
  846. return parms.OffsetPos;
  847. }
  848. public LSL_Rotation llDetectedRot(int number)
  849. {
  850. m_host.AddScriptLPS(1);
  851. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  852. if (detectedParams == null)
  853. return new LSL_Rotation();
  854. return detectedParams.Rotation;
  855. }
  856. public LSL_Integer llDetectedGroup(int number)
  857. {
  858. m_host.AddScriptLPS(1);
  859. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  860. if (detectedParams == null)
  861. return new LSL_Integer(0);
  862. if (m_host.GroupID == detectedParams.Group)
  863. return new LSL_Integer(1);
  864. return new LSL_Integer(0);
  865. }
  866. public LSL_Integer llDetectedLinkNumber(int number)
  867. {
  868. m_host.AddScriptLPS(1);
  869. DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  870. if (parms == null)
  871. return new LSL_Integer(0);
  872. return new LSL_Integer(parms.LinkNum);
  873. }
  874. /// <summary>
  875. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchBinormal for details
  876. /// </summary>
  877. public LSL_Vector llDetectedTouchBinormal(int index)
  878. {
  879. m_host.AddScriptLPS(1);
  880. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  881. if (detectedParams == null)
  882. return new LSL_Vector();
  883. return detectedParams.TouchBinormal;
  884. }
  885. /// <summary>
  886. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchFace for details
  887. /// </summary>
  888. public LSL_Integer llDetectedTouchFace(int index)
  889. {
  890. m_host.AddScriptLPS(1);
  891. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  892. if (detectedParams == null)
  893. return new LSL_Integer(-1);
  894. return new LSL_Integer(detectedParams.TouchFace);
  895. }
  896. /// <summary>
  897. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchNormal for details
  898. /// </summary>
  899. public LSL_Vector llDetectedTouchNormal(int index)
  900. {
  901. m_host.AddScriptLPS(1);
  902. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  903. if (detectedParams == null)
  904. return new LSL_Vector();
  905. return detectedParams.TouchNormal;
  906. }
  907. /// <summary>
  908. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchPos for details
  909. /// </summary>
  910. public LSL_Vector llDetectedTouchPos(int index)
  911. {
  912. m_host.AddScriptLPS(1);
  913. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  914. if (detectedParams == null)
  915. return new LSL_Vector();
  916. return detectedParams.TouchPos;
  917. }
  918. /// <summary>
  919. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchST for details
  920. /// </summary>
  921. public LSL_Vector llDetectedTouchST(int index)
  922. {
  923. m_host.AddScriptLPS(1);
  924. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  925. if (detectedParams == null)
  926. return new LSL_Vector(-1.0, -1.0, 0.0);
  927. return detectedParams.TouchST;
  928. }
  929. /// <summary>
  930. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchUV for details
  931. /// </summary>
  932. public LSL_Vector llDetectedTouchUV(int index)
  933. {
  934. m_host.AddScriptLPS(1);
  935. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  936. if (detectedParams == null)
  937. return new LSL_Vector(-1.0, -1.0, 0.0);
  938. return detectedParams.TouchUV;
  939. }
  940. public virtual void llDie()
  941. {
  942. m_host.AddScriptLPS(1);
  943. throw new SelfDeleteException();
  944. }
  945. public LSL_Float llGround(LSL_Vector offset)
  946. {
  947. m_host.AddScriptLPS(1);
  948. Vector3 pos = m_host.GetWorldPosition() + (Vector3)offset;
  949. //Get the slope normal. This gives us the equation of the plane tangent to the slope.
  950. LSL_Vector vsn = llGroundNormal(offset);
  951. // Clamp to valid position
  952. if (pos.X < 0)
  953. pos.X = 0;
  954. else if (pos.X >= World.Heightmap.Width)
  955. pos.X = World.Heightmap.Width - 1;
  956. if (pos.Y < 0)
  957. pos.Y = 0;
  958. else if (pos.Y >= World.Heightmap.Height)
  959. pos.Y = World.Heightmap.Height - 1;
  960. //Get the height for the integer coordinates from the Heightmap
  961. float baseheight = (float)World.Heightmap[(int)pos.X, (int)pos.Y];
  962. //Calculate the difference between the actual coordinates and the integer coordinates
  963. float xdiff = pos.X - (float)((int)pos.X);
  964. float ydiff = pos.Y - (float)((int)pos.Y);
  965. //Use the equation of the tangent plane to adjust the height to account for slope
  966. return (((vsn.x * xdiff) + (vsn.y * ydiff)) / (-1 * vsn.z)) + baseheight;
  967. }
  968. public LSL_Float llCloud(LSL_Vector offset)
  969. {
  970. m_host.AddScriptLPS(1);
  971. float cloudCover = 0f;
  972. ICloudModule module = World.RequestModuleInterface<ICloudModule>();
  973. if (module != null)
  974. {
  975. Vector3 pos = m_host.GetWorldPosition();
  976. int x = (int)(pos.X + offset.x);
  977. int y = (int)(pos.Y + offset.y);
  978. cloudCover = module.CloudCover(x, y, 0);
  979. }
  980. return cloudCover;
  981. }
  982. public LSL_Vector llWind(LSL_Vector offset)
  983. {
  984. m_host.AddScriptLPS(1);
  985. LSL_Vector wind = new LSL_Vector(0, 0, 0);
  986. IWindModule module = World.RequestModuleInterface<IWindModule>();
  987. if (module != null)
  988. {
  989. Vector3 pos = m_host.GetWorldPosition();
  990. int x = (int)(pos.X + offset.x);
  991. int y = (int)(pos.Y + offset.y);
  992. Vector3 windSpeed = module.WindSpeed(x, y, 0);
  993. wind.x = windSpeed.X;
  994. wind.y = windSpeed.Y;
  995. }
  996. return wind;
  997. }
  998. public void llSetStatus(int status, int value)
  999. {
  1000. m_host.AddScriptLPS(1);
  1001. int statusrotationaxis = 0;
  1002. if ((status & ScriptBaseClass.STATUS_PHYSICS) == ScriptBaseClass.STATUS_PHYSICS)
  1003. {
  1004. if (value != 0)
  1005. {
  1006. SceneObjectGroup group = m_host.ParentGroup;
  1007. bool allow = true;
  1008. foreach (SceneObjectPart part in group.Parts)
  1009. {
  1010. if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys)
  1011. {
  1012. allow = false;
  1013. break;
  1014. }
  1015. }
  1016. if (!allow)
  1017. return;
  1018. m_host.ScriptSetPhysicsStatus(true);
  1019. }
  1020. else
  1021. {
  1022. m_host.ScriptSetPhysicsStatus(false);
  1023. }
  1024. }
  1025. if ((status & ScriptBaseClass.STATUS_PHANTOM) == ScriptBaseClass.STATUS_PHANTOM)
  1026. {
  1027. m_host.ParentGroup.ScriptSetPhantomStatus(value != 0);
  1028. }
  1029. if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) == ScriptBaseClass.STATUS_CAST_SHADOWS)
  1030. {
  1031. m_host.AddFlag(PrimFlags.CastShadows);
  1032. }
  1033. if ((status & ScriptBaseClass.STATUS_ROTATE_X) == ScriptBaseClass.STATUS_ROTATE_X)
  1034. {
  1035. statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_X;
  1036. }
  1037. if ((status & ScriptBaseClass.STATUS_ROTATE_Y) == ScriptBaseClass.STATUS_ROTATE_Y)
  1038. {
  1039. statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Y;
  1040. }
  1041. if ((status & ScriptBaseClass.STATUS_ROTATE_Z) == ScriptBaseClass.STATUS_ROTATE_Z)
  1042. {
  1043. statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Z;
  1044. }
  1045. if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB) == ScriptBaseClass.STATUS_BLOCK_GRAB)
  1046. {
  1047. if (value != 0)
  1048. m_host.SetBlockGrab(true);
  1049. else
  1050. m_host.SetBlockGrab(false);
  1051. }
  1052. if ((status & ScriptBaseClass.STATUS_DIE_AT_EDGE) == ScriptBaseClass.STATUS_DIE_AT_EDGE)
  1053. {
  1054. if (value != 0)
  1055. m_host.SetDieAtEdge(true);
  1056. else
  1057. m_host.SetDieAtEdge(false);
  1058. }
  1059. if ((status & ScriptBaseClass.STATUS_RETURN_AT_EDGE) == ScriptBaseClass.STATUS_RETURN_AT_EDGE)
  1060. {
  1061. if (value != 0)
  1062. m_host.SetReturnAtEdge(true);
  1063. else
  1064. m_host.SetReturnAtEdge(false);
  1065. }
  1066. if ((status & ScriptBaseClass.STATUS_SANDBOX) == ScriptBaseClass.STATUS_SANDBOX)
  1067. {
  1068. if (value != 0)
  1069. m_host.SetStatusSandbox(true);
  1070. else
  1071. m_host.SetStatusSandbox(false);
  1072. }
  1073. if (statusrotationaxis != 0)
  1074. {
  1075. m_host.SetAxisRotation(statusrotationaxis, value);
  1076. }
  1077. }
  1078. private bool IsPhysical()
  1079. {
  1080. return ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) == (uint)PrimFlags.Physics);
  1081. }
  1082. public LSL_Integer llGetStatus(int status)
  1083. {
  1084. m_host.AddScriptLPS(1);
  1085. // m_log.Debug(m_host.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
  1086. switch (status)
  1087. {
  1088. case ScriptBaseClass.STATUS_PHYSICS:
  1089. return IsPhysical() ? 1 : 0;
  1090. case ScriptBaseClass.STATUS_PHANTOM:
  1091. if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == (uint)PrimFlags.Phantom)
  1092. {
  1093. return 1;
  1094. }
  1095. return 0;
  1096. case ScriptBaseClass.STATUS_CAST_SHADOWS:
  1097. if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.CastShadows) == (uint)PrimFlags.CastShadows)
  1098. {
  1099. return 1;
  1100. }
  1101. return 0;
  1102. case ScriptBaseClass.STATUS_BLOCK_GRAB:
  1103. if (m_host.GetBlockGrab())
  1104. return 1;
  1105. else
  1106. return 0;
  1107. case ScriptBaseClass.STATUS_DIE_AT_EDGE:
  1108. if (m_host.GetDieAtEdge())
  1109. return 1;
  1110. else
  1111. return 0;
  1112. case ScriptBaseClass.STATUS_RETURN_AT_EDGE:
  1113. if (m_host.GetReturnAtEdge())
  1114. return 1;
  1115. else
  1116. return 0;
  1117. case ScriptBaseClass.STATUS_ROTATE_X:
  1118. // if (m_host.GetAxisRotation(2) != 0)
  1119. if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
  1120. return 1;
  1121. else
  1122. return 0;
  1123. case ScriptBaseClass.STATUS_ROTATE_Y:
  1124. if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
  1125. return 1;
  1126. else
  1127. return 0;
  1128. case ScriptBaseClass.STATUS_ROTATE_Z:
  1129. if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
  1130. return 1;
  1131. else
  1132. return 0;
  1133. case ScriptBaseClass.STATUS_SANDBOX:
  1134. if (m_host.GetStatusSandbox())
  1135. return 1;
  1136. else
  1137. return 0;
  1138. }
  1139. return 0;
  1140. }
  1141. public void llSetScale(LSL_Vector scale)
  1142. {
  1143. m_host.AddScriptLPS(1);
  1144. SetScale(m_host, scale);
  1145. }
  1146. protected void SetScale(SceneObjectPart part, LSL_Vector scale)
  1147. {
  1148. // TODO: this needs to trigger a persistance save as well
  1149. if (part == null || part.ParentGroup.IsDeleted)
  1150. return;
  1151. // First we need to check whether or not we need to clamp the size of a physics-enabled prim
  1152. PhysicsActor pa = part.ParentGroup.RootPart.PhysActor;
  1153. if (pa != null && pa.IsPhysical)
  1154. {
  1155. scale.x = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.x));
  1156. scale.y = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.y));
  1157. scale.z = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.z));
  1158. }
  1159. else
  1160. {
  1161. // If not physical, then we clamp the scale to the non-physical min/max
  1162. scale.x = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.x));
  1163. scale.y = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.y));
  1164. scale.z = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.z));
  1165. }
  1166. Vector3 tmp = part.Scale;
  1167. tmp.X = (float)scale.x;
  1168. tmp.Y = (float)scale.y;
  1169. tmp.Z = (float)scale.z;
  1170. part.Scale = tmp;
  1171. part.SendFullUpdateToAllClients();
  1172. }
  1173. public LSL_Vector llGetScale()
  1174. {
  1175. m_host.AddScriptLPS(1);
  1176. return new LSL_Vector(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
  1177. }
  1178. public void llSetClickAction(int action)
  1179. {
  1180. m_host.AddScriptLPS(1);
  1181. m_host.ClickAction = (byte)action;
  1182. m_host.ParentGroup.HasGroupChanged = true;
  1183. m_host.ScheduleFullUpdate();
  1184. return;
  1185. }
  1186. public void llSetColor(LSL_Vector color, int face)
  1187. {
  1188. m_host.AddScriptLPS(1);
  1189. if (face == ScriptBaseClass.ALL_SIDES)
  1190. face = SceneObjectPart.ALL_SIDES;
  1191. m_host.SetFaceColorAlpha(face, color, null);
  1192. }
  1193. public void SetTexGen(SceneObjectPart part, int face,int style)
  1194. {
  1195. Primitive.TextureEntry tex = part.Shape.Textures;
  1196. MappingType textype;
  1197. textype = MappingType.Default;
  1198. if (style == (int)ScriptBaseClass.PRIM_TEXGEN_PLANAR)
  1199. textype = MappingType.Planar;
  1200. if (face >= 0 && face < GetNumberOfSides(part))
  1201. {
  1202. tex.CreateFace((uint) face);
  1203. tex.FaceTextures[face].TexMapType = textype;
  1204. part.UpdateTextureEntry(tex.GetBytes());
  1205. return;
  1206. }
  1207. else if (face == ScriptBaseClass.ALL_SIDES)
  1208. {
  1209. for (uint i = 0; i < GetNumberOfSides(part); i++)
  1210. {
  1211. if (tex.FaceTextures[i] != null)
  1212. {
  1213. tex.FaceTextures[i].TexMapType = textype;
  1214. }
  1215. tex.DefaultTexture.TexMapType = textype;
  1216. }
  1217. part.UpdateTextureEntry(tex.GetBytes());
  1218. return;
  1219. }
  1220. }
  1221. public void SetGlow(SceneObjectPart part, int face, float glow)
  1222. {
  1223. Primitive.TextureEntry tex = part.Shape.Textures;
  1224. if (face >= 0 && face < GetNumberOfSides(part))
  1225. {
  1226. tex.CreateFace((uint) face);
  1227. tex.FaceTextures[face].Glow = glow;
  1228. part.UpdateTextureEntry(tex.GetBytes());
  1229. return;
  1230. }
  1231. else if (face == ScriptBaseClass.ALL_SIDES)
  1232. {
  1233. for (uint i = 0; i < GetNumberOfSides(part); i++)
  1234. {
  1235. if (tex.FaceTextures[i] != null)
  1236. {
  1237. tex.FaceTextures[i].Glow = glow;
  1238. }
  1239. tex.DefaultTexture.Glow = glow;
  1240. }
  1241. part.UpdateTextureEntry(tex.GetBytes());
  1242. return;
  1243. }
  1244. }
  1245. public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
  1246. {
  1247. Shininess sval = new Shininess();
  1248. switch (shiny)
  1249. {
  1250. case 0:
  1251. sval = Shininess.None;
  1252. break;
  1253. case 1:
  1254. sval = Shininess.Low;
  1255. break;
  1256. case 2:
  1257. sval = Shininess.Medium;
  1258. break;
  1259. case 3:
  1260. sval = Shininess.High;
  1261. break;
  1262. default:
  1263. sval = Shininess.None;
  1264. break;
  1265. }
  1266. Primitive.TextureEntry tex = part.Shape.Textures;
  1267. if (face >= 0 && face < GetNumberOfSides(part))
  1268. {
  1269. tex.CreateFace((uint) face);
  1270. tex.FaceTextures[face].Shiny = sval;
  1271. tex.FaceTextures[face].Bump = bump;
  1272. part.UpdateTextureEntry(tex.GetBytes());
  1273. return;
  1274. }
  1275. else if (face == ScriptBaseClass.ALL_SIDES)
  1276. {
  1277. for (uint i = 0; i < GetNumberOfSides(part); i++)
  1278. {
  1279. if (tex.FaceTextures[i] != null)
  1280. {
  1281. tex.FaceTextures[i].Shiny = sval;
  1282. tex.FaceTextures[i].Bump = bump;;
  1283. }
  1284. tex.DefaultTexture.Shiny = sval;
  1285. tex.DefaultTexture.Bump = bump;
  1286. }
  1287. part.UpdateTextureEntry(tex.GetBytes());
  1288. return;
  1289. }
  1290. }
  1291. public void SetFullBright(SceneObjectPart part, int face, bool bright)
  1292. {
  1293. Primitive.TextureEntry tex = part.Shape.Textures;
  1294. if (face >= 0 && face < GetNumberOfSides(part))
  1295. {
  1296. tex.CreateFace((uint) face);
  1297. tex.FaceTextures[face].Fullbright = bright;
  1298. part.UpdateTextureEntry(tex.GetBytes());
  1299. return;
  1300. }
  1301. else if (face == ScriptBaseClass.ALL_SIDES)
  1302. {
  1303. for (uint i = 0; i < GetNumberOfSides(part); i++)
  1304. {
  1305. if (tex.FaceTextures[i] != null)
  1306. {
  1307. tex.FaceTextures[i].Fullbright = bright;
  1308. }
  1309. }
  1310. tex.DefaultTexture.Fullbright = bright;
  1311. part.UpdateTextureEntry(tex.GetBytes());
  1312. return;
  1313. }
  1314. }
  1315. public LSL_Float llGetAlpha(int face)
  1316. {
  1317. m_host.AddScriptLPS(1);
  1318. return GetAlpha(m_host, face);
  1319. }
  1320. protected LSL_Float GetAlpha(SceneObjectPart part, int face)
  1321. {
  1322. Primitive.TextureEntry tex = part.Shape.Textures;
  1323. if (face == ScriptBaseClass.ALL_SIDES)
  1324. {
  1325. int i;
  1326. double sum = 0.0;
  1327. for (i = 0 ; i < GetNumberOfSides(part); i++)
  1328. sum += (double)tex.GetFace((uint)i).RGBA.A;
  1329. return sum;
  1330. }
  1331. if (face >= 0 && face < GetNumberOfSides(part))
  1332. {
  1333. return (double)tex.GetFace((uint)face).RGBA.A;
  1334. }
  1335. return 0.0;
  1336. }
  1337. public void llSetAlpha(double alpha, int face)
  1338. {
  1339. m_host.AddScriptLPS(1);
  1340. SetAlpha(m_host, alpha, face);
  1341. }
  1342. public void llSetLinkAlpha(int linknumber, double alpha, int face)
  1343. {
  1344. m_host.AddScriptLPS(1);
  1345. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  1346. foreach (SceneObjectPart part in parts)
  1347. SetAlpha(part, alpha, face);
  1348. }
  1349. protected void SetAlpha(SceneObjectPart part, double alpha, int face)
  1350. {
  1351. Primitive.TextureEntry tex = part.Shape.Textures;
  1352. Color4 texcolor;
  1353. if (face >= 0 && face < GetNumberOfSides(part))
  1354. {
  1355. texcolor = tex.CreateFace((uint)face).RGBA;
  1356. texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
  1357. tex.FaceTextures[face].RGBA = texcolor;
  1358. part.UpdateTextureEntry(tex.GetBytes());
  1359. return;
  1360. }
  1361. else if (face == ScriptBaseClass.ALL_SIDES)
  1362. {
  1363. for (int i = 0; i < GetNumberOfSides(part); i++)
  1364. {
  1365. if (tex.FaceTextures[i] != null)
  1366. {
  1367. texcolor = tex.FaceTextures[i].RGBA;
  1368. texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
  1369. tex.FaceTextures[i].RGBA = texcolor;
  1370. }
  1371. }
  1372. // In some cases, the default texture can be null, eg when every face
  1373. // has a unique texture
  1374. if (tex.DefaultTexture != null)
  1375. {
  1376. texcolor = tex.DefaultTexture.RGBA;
  1377. texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
  1378. tex.DefaultTexture.RGBA = texcolor;
  1379. }
  1380. part.UpdateTextureEntry(tex.GetBytes());
  1381. return;
  1382. }
  1383. }
  1384. /// <summary>
  1385. /// Set flexi parameters of a part.
  1386. ///
  1387. /// FIXME: Much of this code should probably be within the part itself.
  1388. /// </summary>
  1389. /// <param name="part"></param>
  1390. /// <param name="flexi"></param>
  1391. /// <param name="softness"></param>
  1392. /// <param name="gravity"></param>
  1393. /// <param name="friction"></param>
  1394. /// <param name="wind"></param>
  1395. /// <param name="tension"></param>
  1396. /// <param name="Force"></param>
  1397. protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
  1398. float wind, float tension, LSL_Vector Force)
  1399. {
  1400. if (part == null)
  1401. return;
  1402. if (flexi)
  1403. {
  1404. part.Shape.FlexiEntry = true; // this setting flexi true isn't working, but the below parameters do
  1405. // work once the prim is already flexi
  1406. part.Shape.FlexiSoftness = softness;
  1407. part.Shape.FlexiGravity = gravity;
  1408. part.Shape.FlexiDrag = friction;
  1409. part.Shape.FlexiWind = wind;
  1410. part.Shape.FlexiTension = tension;
  1411. part.Shape.FlexiForceX = (float)Force.x;
  1412. part.Shape.FlexiForceY = (float)Force.y;
  1413. part.Shape.FlexiForceZ = (float)Force.z;
  1414. part.Shape.PathCurve = (byte)Extrusion.Flexible;
  1415. }
  1416. else
  1417. {
  1418. // Other values not set, they do not seem to be sent to the viewer
  1419. // Setting PathCurve appears to be what actually toggles the check box and turns Flexi on and off
  1420. part.Shape.PathCurve = (byte)Extrusion.Straight;
  1421. part.Shape.FlexiEntry = false;
  1422. }
  1423. part.ParentGroup.HasGroupChanged = true;
  1424. part.ScheduleFullUpdate();
  1425. }
  1426. /// <summary>
  1427. /// Set a light point on a part
  1428. /// </summary>
  1429. /// FIXME: Much of this code should probably be in SceneObjectGroup
  1430. ///
  1431. /// <param name="part"></param>
  1432. /// <param name="light"></param>
  1433. /// <param name="color"></param>
  1434. /// <param name="intensity"></param>
  1435. /// <param name="radius"></param>
  1436. /// <param name="falloff"></param>
  1437. protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
  1438. {
  1439. if (part == null)
  1440. return;
  1441. if (light)
  1442. {
  1443. part.Shape.LightEntry = true;
  1444. part.Shape.LightColorR = Util.Clip((float)color.x, 0.0f, 1.0f);
  1445. part.Shape.LightColorG = Util.Clip((float)color.y, 0.0f, 1.0f);
  1446. part.Shape.LightColorB = Util.Clip((float)color.z, 0.0f, 1.0f);
  1447. part.Shape.LightIntensity = intensity;
  1448. part.Shape.LightRadius = radius;
  1449. part.Shape.LightFalloff = falloff;
  1450. }
  1451. else
  1452. {
  1453. part.Shape.LightEntry = false;
  1454. }
  1455. part.ParentGroup.HasGroupChanged = true;
  1456. part.ScheduleFullUpdate();
  1457. }
  1458. public LSL_Vector llGetColor(int face)
  1459. {
  1460. m_host.AddScriptLPS(1);
  1461. return GetColor(m_host, face);
  1462. }
  1463. protected LSL_Vector GetColor(SceneObjectPart part, int face)
  1464. {
  1465. Primitive.TextureEntry tex = part.Shape.Textures;
  1466. Color4 texcolor;
  1467. LSL_Vector rgb = new LSL_Vector();
  1468. if (face == ScriptBaseClass.ALL_SIDES)
  1469. {
  1470. int i;
  1471. for (i = 0 ; i < GetNumberOfSides(part); i++)
  1472. {
  1473. texcolor = tex.GetFace((uint)i).RGBA;
  1474. rgb.x += texcolor.R;
  1475. rgb.y += texcolor.G;
  1476. rgb.z += texcolor.B;
  1477. }
  1478. rgb.x /= (float)GetNumberOfSides(part);
  1479. rgb.y /= (float)GetNumberOfSides(part);
  1480. rgb.z /= (float)GetNumberOfSides(part);
  1481. return rgb;
  1482. }
  1483. if (face >= 0 && face < GetNumberOfSides(part))
  1484. {
  1485. texcolor = tex.GetFace((uint)face).RGBA;
  1486. rgb.x = texcolor.R;
  1487. rgb.y = texcolor.G;
  1488. rgb.z = texcolor.B;
  1489. return rgb;
  1490. }
  1491. else
  1492. {
  1493. return new LSL_Vector();
  1494. }
  1495. }
  1496. public void llSetTexture(string texture, int face)
  1497. {
  1498. m_host.AddScriptLPS(1);
  1499. SetTexture(m_host, texture, face);
  1500. ScriptSleep(200);
  1501. }
  1502. public void llSetLinkTexture(int linknumber, string texture, int face)
  1503. {
  1504. m_host.AddScriptLPS(1);
  1505. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  1506. foreach (SceneObjectPart part in parts)
  1507. SetTexture(part, texture, face);
  1508. ScriptSleep(200);
  1509. }
  1510. protected void SetTexture(SceneObjectPart part, string texture, int face)
  1511. {
  1512. UUID textureID = new UUID();
  1513. textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture);
  1514. if (textureID == UUID.Zero)
  1515. {
  1516. if (!UUID.TryParse(texture, out textureID))
  1517. return;
  1518. }
  1519. Primitive.TextureEntry tex = part.Shape.Textures;
  1520. if (face >= 0 && face < GetNumberOfSides(part))
  1521. {
  1522. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  1523. texface.TextureID = textureID;
  1524. tex.FaceTextures[face] = texface;
  1525. part.UpdateTextureEntry(tex.GetBytes());
  1526. return;
  1527. }
  1528. else if (face == ScriptBaseClass.ALL_SIDES)
  1529. {
  1530. for (uint i = 0; i < GetNumberOfSides(part); i++)
  1531. {
  1532. if (tex.FaceTextures[i] != null)
  1533. {
  1534. tex.FaceTextures[i].TextureID = textureID;
  1535. }
  1536. }
  1537. tex.DefaultTexture.TextureID = textureID;
  1538. part.UpdateTextureEntry(tex.GetBytes());
  1539. return;
  1540. }
  1541. }
  1542. public void llScaleTexture(double u, double v, int face)
  1543. {
  1544. m_host.AddScriptLPS(1);
  1545. ScaleTexture(m_host, u, v, face);
  1546. ScriptSleep(200);
  1547. }
  1548. protected void ScaleTexture(SceneObjectPart part, double u, double v, int face)
  1549. {
  1550. Primitive.TextureEntry tex = part.Shape.Textures;
  1551. if (face >= 0 && face < GetNumberOfSides(part))
  1552. {
  1553. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  1554. texface.RepeatU = (float)u;
  1555. texface.RepeatV = (float)v;
  1556. tex.FaceTextures[face] = texface;
  1557. part.UpdateTextureEntry(tex.GetBytes());
  1558. return;
  1559. }
  1560. if (face == ScriptBaseClass.ALL_SIDES)
  1561. {
  1562. for (int i = 0; i < GetNumberOfSides(part); i++)
  1563. {
  1564. if (tex.FaceTextures[i] != null)
  1565. {
  1566. tex.FaceTextures[i].RepeatU = (float)u;
  1567. tex.FaceTextures[i].RepeatV = (float)v;
  1568. }
  1569. }
  1570. tex.DefaultTexture.RepeatU = (float)u;
  1571. tex.DefaultTexture.RepeatV = (float)v;
  1572. part.UpdateTextureEntry(tex.GetBytes());
  1573. return;
  1574. }
  1575. }
  1576. public void llOffsetTexture(double u, double v, int face)
  1577. {
  1578. m_host.AddScriptLPS(1);
  1579. OffsetTexture(m_host, u, v, face);
  1580. ScriptSleep(200);
  1581. }
  1582. protected void OffsetTexture(SceneObjectPart part, double u, double v, int face)
  1583. {
  1584. Primitive.TextureEntry tex = part.Shape.Textures;
  1585. if (face >= 0 && face < GetNumberOfSides(part))
  1586. {
  1587. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  1588. texface.OffsetU = (float)u;
  1589. texface.OffsetV = (float)v;
  1590. tex.FaceTextures[face] = texface;
  1591. part.UpdateTextureEntry(tex.GetBytes());
  1592. return;
  1593. }
  1594. if (face == ScriptBaseClass.ALL_SIDES)
  1595. {
  1596. for (int i = 0; i < GetNumberOfSides(part); i++)
  1597. {
  1598. if (tex.FaceTextures[i] != null)
  1599. {
  1600. tex.FaceTextures[i].OffsetU = (float)u;
  1601. tex.FaceTextures[i].OffsetV = (float)v;
  1602. }
  1603. }
  1604. tex.DefaultTexture.OffsetU = (float)u;
  1605. tex.DefaultTexture.OffsetV = (float)v;
  1606. part.UpdateTextureEntry(tex.GetBytes());
  1607. return;
  1608. }
  1609. }
  1610. public void llRotateTexture(double rotation, int face)
  1611. {
  1612. m_host.AddScriptLPS(1);
  1613. RotateTexture(m_host, rotation, face);
  1614. ScriptSleep(200);
  1615. }
  1616. protected void RotateTexture(SceneObjectPart part, double rotation, int face)
  1617. {
  1618. Primitive.TextureEntry tex = part.Shape.Textures;
  1619. if (face >= 0 && face < GetNumberOfSides(part))
  1620. {
  1621. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  1622. texface.Rotation = (float)rotation;
  1623. tex.FaceTextures[face] = texface;
  1624. part.UpdateTextureEntry(tex.GetBytes());
  1625. return;
  1626. }
  1627. if (face == ScriptBaseClass.ALL_SIDES)
  1628. {
  1629. for (int i = 0; i < GetNumberOfSides(part); i++)
  1630. {
  1631. if (tex.FaceTextures[i] != null)
  1632. {
  1633. tex.FaceTextures[i].Rotation = (float)rotation;
  1634. }
  1635. }
  1636. tex.DefaultTexture.Rotation = (float)rotation;
  1637. part.UpdateTextureEntry(tex.GetBytes());
  1638. return;
  1639. }
  1640. }
  1641. public LSL_String llGetTexture(int face)
  1642. {
  1643. m_host.AddScriptLPS(1);
  1644. return GetTexture(m_host, face);
  1645. }
  1646. protected LSL_String GetTexture(SceneObjectPart part, int face)
  1647. {
  1648. Primitive.TextureEntry tex = part.Shape.Textures;
  1649. if (face == ScriptBaseClass.ALL_SIDES)
  1650. {
  1651. face = 0;
  1652. }
  1653. if (face >= 0 && face < GetNumberOfSides(part))
  1654. {
  1655. Primitive.TextureEntryFace texface;
  1656. texface = tex.GetFace((uint)face);
  1657. string texture = texface.TextureID.ToString();
  1658. lock (part.TaskInventory)
  1659. {
  1660. foreach (KeyValuePair<UUID, TaskInventoryItem> inv in part.TaskInventory)
  1661. {
  1662. if (inv.Value.AssetID == texface.TextureID)
  1663. {
  1664. texture = inv.Value.Name.ToString();
  1665. break;
  1666. }
  1667. }
  1668. }
  1669. return texture;
  1670. }
  1671. else
  1672. {
  1673. return UUID.Zero.ToString();
  1674. }
  1675. }
  1676. public void llSetPos(LSL_Vector pos)
  1677. {
  1678. m_host.AddScriptLPS(1);
  1679. SetPos(m_host, pos, true);
  1680. ScriptSleep(200);
  1681. }
  1682. /// <summary>
  1683. /// Tries to move the entire object so that the root prim is within 0.1m of position. http://wiki.secondlife.com/wiki/LlSetRegionPos
  1684. /// Documentation indicates that the use of x/y coordinates up to 10 meters outside the bounds of a region will work but do not specify what happens if there is no adjacent region for the object to move into.
  1685. /// Uses the RegionSize constant here rather than hard-coding 266.0 to alert any developer modifying OpenSim to support variable-sized regions that this method will need tweaking.
  1686. /// </summary>
  1687. /// <param name="pos"></param>
  1688. /// <returns>1 if successful, 0 otherwise.</returns>
  1689. public LSL_Integer llSetRegionPos(LSL_Vector pos)
  1690. {
  1691. m_host.AddScriptLPS(1);
  1692. // BEGIN WORKAROUND
  1693. // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND.
  1694. //
  1695. // This workaround is to prevent silent failure of this function.
  1696. // According to the specification on the SL Wiki, providing a position outside of the
  1697. if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize)
  1698. {
  1699. return 0;
  1700. }
  1701. // END WORK AROUND
  1702. else if ( // this is not part of the workaround if-block because it's not related to the workaround.
  1703. IsPhysical() ||
  1704. m_host.ParentGroup.IsAttachment || // return FALSE if attachment
  1705. (
  1706. pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region.
  1707. pos.x > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a east-adjacent region.
  1708. pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region.
  1709. pos.y > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a north-adjacent region.
  1710. pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m
  1711. )
  1712. )
  1713. {
  1714. return 0;
  1715. }
  1716. // if we reach this point, then the object is not physical, it's not an attachment, and the destination is within the valid range.
  1717. // this could possibly be done in the above else-if block, but we're doing the check here to keep the code easier to read.
  1718. Vector3 objectPos = m_host.ParentGroup.RootPart.AbsolutePosition;
  1719. LandData here = World.GetLandData(objectPos);
  1720. LandData there = World.GetLandData(pos);
  1721. // we're only checking prim limits if it's moving to a different parcel under the assumption that if the object got onto the parcel without exceeding the prim limits.
  1722. bool sameParcel = here.GlobalID == there.GlobalID;
  1723. if (!sameParcel && !World.Permissions.CanRezObject(
  1724. m_host.ParentGroup.PrimCount, m_host.ParentGroup.OwnerID, pos))
  1725. {
  1726. return 0;
  1727. }
  1728. SetPos(m_host.ParentGroup.RootPart, pos, false);
  1729. return VecDist(pos, llGetRootPosition()) <= 0.1 ? 1 : 0;
  1730. }
  1731. // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
  1732. // note linked setpos is capped "differently"
  1733. private LSL_Vector SetPosAdjust(LSL_Vector start, LSL_Vector end)
  1734. {
  1735. if (llVecDist(start, end) > 10.0f * m_ScriptDistanceFactor)
  1736. return start + m_ScriptDistanceFactor * 10.0f * llVecNorm(end - start);
  1737. else
  1738. return end;
  1739. }
  1740. protected LSL_Vector GetSetPosTarget(SceneObjectPart part, LSL_Vector targetPos, LSL_Vector fromPos)
  1741. {
  1742. if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
  1743. return fromPos;
  1744. // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
  1745. float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
  1746. bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
  1747. if (part.ParentGroup.RootPart == part)
  1748. {
  1749. if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
  1750. targetPos.z = ground;
  1751. }
  1752. LSL_Vector real_vec = SetPosAdjust(fromPos, targetPos);
  1753. return real_vec;
  1754. }
  1755. /// <summary>
  1756. /// set object position, optionally capping the distance.
  1757. /// </summary>
  1758. /// <param name="part"></param>
  1759. /// <param name="targetPos"></param>
  1760. /// <param name="adjust">if TRUE, will cap the distance to 10m.</param>
  1761. protected void SetPos(SceneObjectPart part, LSL_Vector targetPos, bool adjust)
  1762. {
  1763. // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
  1764. LSL_Vector currentPos = GetPartLocalPos(part);
  1765. float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
  1766. bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
  1767. if (part.ParentGroup.RootPart == part)
  1768. {
  1769. if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
  1770. targetPos.z = ground;
  1771. SceneObjectGroup parent = part.ParentGroup;
  1772. parent.UpdateGroupPosition(!adjust ? targetPos :
  1773. SetPosAdjust(currentPos, targetPos));
  1774. }
  1775. else
  1776. {
  1777. part.OffsetPosition = !adjust ? targetPos :
  1778. SetPosAdjust(currentPos, targetPos);
  1779. SceneObjectGroup parent = part.ParentGroup;
  1780. parent.HasGroupChanged = true;
  1781. parent.ScheduleGroupForTerseUpdate();
  1782. }
  1783. }
  1784. public LSL_Vector llGetPos()
  1785. {
  1786. m_host.AddScriptLPS(1);
  1787. return m_host.GetWorldPosition();
  1788. }
  1789. public LSL_Vector llGetLocalPos()
  1790. {
  1791. m_host.AddScriptLPS(1);
  1792. return GetPartLocalPos(m_host);
  1793. }
  1794. protected LSL_Vector GetPartLocalPos(SceneObjectPart part)
  1795. {
  1796. m_host.AddScriptLPS(1);
  1797. Vector3 pos;
  1798. if (!part.IsRoot)
  1799. {
  1800. pos = part.OffsetPosition;
  1801. }
  1802. else
  1803. {
  1804. if (part.ParentGroup.IsAttachment)
  1805. {
  1806. pos = part.AttachedPos;
  1807. }
  1808. else
  1809. {
  1810. pos = part.AbsolutePosition;
  1811. }
  1812. }
  1813. // m_log.DebugFormat("[LSL API]: Returning {0} in GetPartLocalPos()", pos);
  1814. return new LSL_Vector(pos);
  1815. }
  1816. public void llSetRot(LSL_Rotation rot)
  1817. {
  1818. m_host.AddScriptLPS(1);
  1819. // try to let this work as in SL...
  1820. if (m_host.ParentID == 0)
  1821. {
  1822. // special case: If we are root, rotate complete SOG to new rotation
  1823. SetRot(m_host, rot);
  1824. }
  1825. else
  1826. {
  1827. // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
  1828. SceneObjectPart rootPart = m_host.ParentGroup.RootPart;
  1829. if (rootPart != null) // better safe than sorry
  1830. {
  1831. SetRot(m_host, rootPart.RotationOffset * (Quaternion)rot);
  1832. }
  1833. }
  1834. ScriptSleep(200);
  1835. }
  1836. public void llSetLocalRot(LSL_Rotation rot)
  1837. {
  1838. m_host.AddScriptLPS(1);
  1839. SetRot(m_host, rot);
  1840. ScriptSleep(200);
  1841. }
  1842. protected void SetRot(SceneObjectPart part, Quaternion rot)
  1843. {
  1844. part.UpdateRotation(rot);
  1845. // Update rotation does not move the object in the physics scene if it's a linkset.
  1846. //KF: Do NOT use this next line if using ODE physics engine. This need a switch based on .ini Phys Engine type
  1847. // part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
  1848. // So, after thinking about this for a bit, the issue with the part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition line
  1849. // is it isn't compatible with vehicles because it causes the vehicle body to have to be broken down and rebuilt
  1850. // It's perfectly okay when the object is not an active physical body though.
  1851. // So, part.ParentGroup.ResetChildPrimPhysicsPositions(); does the thing that Kitto is warning against
  1852. // but only if the object is not physial and active. This is important for rotating doors.
  1853. // without the absoluteposition = absoluteposition happening, the doors do not move in the physics
  1854. // scene
  1855. PhysicsActor pa = part.PhysActor;
  1856. if (pa != null && !pa.IsPhysical)
  1857. {
  1858. part.ParentGroup.ResetChildPrimPhysicsPositions();
  1859. }
  1860. }
  1861. /// <summary>
  1862. /// See http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
  1863. /// </summary>
  1864. public LSL_Rotation llGetRot()
  1865. {
  1866. // unlinked or root prim then use llRootRotation
  1867. // see llRootRotaion for references.
  1868. if (m_host.LinkNum == 0 || m_host.LinkNum == 1)
  1869. {
  1870. return llGetRootRotation();
  1871. }
  1872. m_host.AddScriptLPS(1);
  1873. Quaternion q = m_host.GetWorldRotation();
  1874. return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
  1875. }
  1876. private LSL_Rotation GetPartRot(SceneObjectPart part)
  1877. {
  1878. Quaternion q;
  1879. if (part.LinkNum == 0 || part.LinkNum == 1) // unlinked or root prim
  1880. {
  1881. if (part.ParentGroup.AttachmentPoint != 0)
  1882. {
  1883. ScenePresence avatar = World.GetScenePresence(part.ParentGroup.AttachedAvatar);
  1884. if (avatar != null)
  1885. {
  1886. if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
  1887. q = avatar.CameraRotation; // Mouselook
  1888. else
  1889. q = avatar.Rotation; // Currently infrequently updated so may be inaccurate
  1890. }
  1891. else
  1892. q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
  1893. }
  1894. else
  1895. q = part.ParentGroup.GroupRotation; // just the group rotation
  1896. return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
  1897. }
  1898. q = part.GetWorldRotation();
  1899. return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
  1900. }
  1901. public LSL_Rotation llGetLocalRot()
  1902. {
  1903. m_host.AddScriptLPS(1);
  1904. return new LSL_Rotation(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W);
  1905. }
  1906. public void llSetForce(LSL_Vector force, int local)
  1907. {
  1908. m_host.AddScriptLPS(1);
  1909. if (!m_host.ParentGroup.IsDeleted)
  1910. {
  1911. if (local != 0)
  1912. force *= llGetRot();
  1913. m_host.ParentGroup.RootPart.SetForce(force);
  1914. }
  1915. }
  1916. public LSL_Vector llGetForce()
  1917. {
  1918. LSL_Vector force = new LSL_Vector(0.0, 0.0, 0.0);
  1919. m_host.AddScriptLPS(1);
  1920. if (!m_host.ParentGroup.IsDeleted)
  1921. {
  1922. force = m_host.ParentGroup.RootPart.GetForce();
  1923. }
  1924. return force;
  1925. }
  1926. public LSL_Integer llTarget(LSL_Vector position, double range)
  1927. {
  1928. m_host.AddScriptLPS(1);
  1929. return m_host.ParentGroup.registerTargetWaypoint(position,
  1930. (float)range);
  1931. }
  1932. public void llTargetRemove(int number)
  1933. {
  1934. m_host.AddScriptLPS(1);
  1935. m_host.ParentGroup.unregisterTargetWaypoint(number);
  1936. }
  1937. public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
  1938. {
  1939. m_host.AddScriptLPS(1);
  1940. return m_host.ParentGroup.registerRotTargetWaypoint(rot, (float)error);
  1941. }
  1942. public void llRotTargetRemove(int number)
  1943. {
  1944. m_host.AddScriptLPS(1);
  1945. m_host.ParentGroup.unregisterRotTargetWaypoint(number);
  1946. }
  1947. public void llMoveToTarget(LSL_Vector target, double tau)
  1948. {
  1949. m_host.AddScriptLPS(1);
  1950. m_host.MoveToTarget(target, (float)tau);
  1951. }
  1952. public void llStopMoveToTarget()
  1953. {
  1954. m_host.AddScriptLPS(1);
  1955. m_host.StopMoveToTarget();
  1956. }
  1957. public void llApplyImpulse(LSL_Vector force, int local)
  1958. {
  1959. m_host.AddScriptLPS(1);
  1960. //No energy force yet
  1961. Vector3 v = force;
  1962. if (v.Length() > 20000.0f)
  1963. {
  1964. v.Normalize();
  1965. v = v * 20000.0f;
  1966. }
  1967. m_host.ApplyImpulse(v, local != 0);
  1968. }
  1969. public void llApplyRotationalImpulse(LSL_Vector force, int local)
  1970. {
  1971. m_host.AddScriptLPS(1);
  1972. m_host.ApplyAngularImpulse(force, local != 0);
  1973. }
  1974. public void llSetTorque(LSL_Vector torque, int local)
  1975. {
  1976. m_host.AddScriptLPS(1);
  1977. m_host.SetAngularImpulse(torque, local != 0);
  1978. }
  1979. public LSL_Vector llGetTorque()
  1980. {
  1981. m_host.AddScriptLPS(1);
  1982. Vector3 torque = m_host.ParentGroup.GetTorque();
  1983. return new LSL_Vector(torque.X,torque.Y,torque.Z);
  1984. }
  1985. public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
  1986. {
  1987. m_host.AddScriptLPS(1);
  1988. llSetForce(force, local);
  1989. llSetTorque(torque, local);
  1990. }
  1991. public LSL_Vector llGetVel()
  1992. {
  1993. m_host.AddScriptLPS(1);
  1994. Vector3 vel;
  1995. if (m_host.ParentGroup.IsAttachment)
  1996. {
  1997. ScenePresence avatar = m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
  1998. vel = avatar.Velocity;
  1999. }
  2000. else
  2001. {
  2002. vel = m_host.Velocity;
  2003. }
  2004. return new LSL_Vector(vel.X, vel.Y, vel.Z);
  2005. }
  2006. public LSL_Vector llGetAccel()
  2007. {
  2008. m_host.AddScriptLPS(1);
  2009. return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
  2010. }
  2011. public LSL_Vector llGetOmega()
  2012. {
  2013. m_host.AddScriptLPS(1);
  2014. return new LSL_Vector(m_host.AngularVelocity.X, m_host.AngularVelocity.Y, m_host.AngularVelocity.Z);
  2015. }
  2016. public LSL_Float llGetTimeOfDay()
  2017. {
  2018. m_host.AddScriptLPS(1);
  2019. return (double)((DateTime.Now.TimeOfDay.TotalMilliseconds / 1000) % (3600 * 4));
  2020. }
  2021. public LSL_Float llGetWallclock()
  2022. {
  2023. m_host.AddScriptLPS(1);
  2024. return DateTime.Now.TimeOfDay.TotalSeconds;
  2025. }
  2026. public LSL_Float llGetTime()
  2027. {
  2028. m_host.AddScriptLPS(1);
  2029. TimeSpan ScriptTime = DateTime.Now - m_timer;
  2030. return (double)(ScriptTime.TotalMilliseconds / 1000);
  2031. }
  2032. public void llResetTime()
  2033. {
  2034. m_host.AddScriptLPS(1);
  2035. m_timer = DateTime.Now;
  2036. }
  2037. public LSL_Float llGetAndResetTime()
  2038. {
  2039. m_host.AddScriptLPS(1);
  2040. TimeSpan ScriptTime = DateTime.Now - m_timer;
  2041. m_timer = DateTime.Now;
  2042. return (double)(ScriptTime.TotalMilliseconds / 1000);
  2043. }
  2044. public void llSound(string sound, double volume, int queue, int loop)
  2045. {
  2046. m_host.AddScriptLPS(1);
  2047. // This function has been deprecated
  2048. // see http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSound
  2049. Deprecated("llSound");
  2050. }
  2051. // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
  2052. // 20080530 Updated to remove code duplication
  2053. public void llPlaySound(string sound, double volume)
  2054. {
  2055. m_host.AddScriptLPS(1);
  2056. // send the sound, once, to all clients in range
  2057. if (m_SoundModule != null)
  2058. {
  2059. m_SoundModule.SendSound(m_host.UUID,
  2060. ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0,
  2061. 0, false, false);
  2062. }
  2063. }
  2064. public void llLoopSound(string sound, double volume)
  2065. {
  2066. m_host.AddScriptLPS(1);
  2067. if (m_SoundModule != null)
  2068. {
  2069. m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
  2070. volume, 20, false);
  2071. }
  2072. }
  2073. public void llLoopSoundMaster(string sound, double volume)
  2074. {
  2075. m_host.AddScriptLPS(1);
  2076. if (m_SoundModule != null)
  2077. {
  2078. m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
  2079. volume, 20, true);
  2080. }
  2081. }
  2082. public void llLoopSoundSlave(string sound, double volume)
  2083. {
  2084. m_host.AddScriptLPS(1);
  2085. lock (m_host.ParentGroup.LoopSoundSlavePrims)
  2086. {
  2087. m_host.ParentGroup.LoopSoundSlavePrims.Add(m_host);
  2088. }
  2089. }
  2090. public void llPlaySoundSlave(string sound, double volume)
  2091. {
  2092. m_host.AddScriptLPS(1);
  2093. // send the sound, once, to all clients in range
  2094. if (m_SoundModule != null)
  2095. {
  2096. m_SoundModule.SendSound(m_host.UUID,
  2097. ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0,
  2098. 0, true, false);
  2099. }
  2100. }
  2101. public void llTriggerSound(string sound, double volume)
  2102. {
  2103. m_host.AddScriptLPS(1);
  2104. // send the sound, once, to all clients in rangeTrigger or play an attached sound in this part's inventory.
  2105. if (m_SoundModule != null)
  2106. {
  2107. m_SoundModule.SendSound(m_host.UUID,
  2108. ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, true, 0, 0,
  2109. false, false);
  2110. }
  2111. }
  2112. public void llStopSound()
  2113. {
  2114. m_host.AddScriptLPS(1);
  2115. if (m_SoundModule != null)
  2116. m_SoundModule.StopSound(m_host.UUID);
  2117. }
  2118. public void llPreloadSound(string sound)
  2119. {
  2120. m_host.AddScriptLPS(1);
  2121. if (m_SoundModule != null)
  2122. m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0);
  2123. ScriptSleep(1000);
  2124. }
  2125. /// <summary>
  2126. /// Return a portion of the designated string bounded by
  2127. /// inclusive indices (start and end). As usual, the negative
  2128. /// indices, and the tolerance for out-of-bound values, makes
  2129. /// this more complicated than it might otherwise seem.
  2130. /// </summary>
  2131. public LSL_String llGetSubString(string src, int start, int end)
  2132. {
  2133. m_host.AddScriptLPS(1);
  2134. // Normalize indices (if negative).
  2135. // After normlaization they may still be
  2136. // negative, but that is now relative to
  2137. // the start, rather than the end, of the
  2138. // sequence.
  2139. if (start < 0)
  2140. {
  2141. start = src.Length+start;
  2142. }
  2143. if (end < 0)
  2144. {
  2145. end = src.Length+end;
  2146. }
  2147. // Conventional substring
  2148. if (start <= end)
  2149. {
  2150. // Implies both bounds are out-of-range.
  2151. if (end < 0 || start >= src.Length)
  2152. {
  2153. return String.Empty;
  2154. }
  2155. // If end is positive, then it directly
  2156. // corresponds to the lengt of the substring
  2157. // needed (plus one of course). BUT, it
  2158. // must be within bounds.
  2159. if (end >= src.Length)
  2160. {
  2161. end = src.Length-1;
  2162. }
  2163. if (start < 0)
  2164. {
  2165. return src.Substring(0,end+1);
  2166. }
  2167. // Both indices are positive
  2168. return src.Substring(start, (end+1) - start);
  2169. }
  2170. // Inverted substring (end < start)
  2171. else
  2172. {
  2173. // Implies both indices are below the
  2174. // lower bound. In the inverted case, that
  2175. // means the entire string will be returned
  2176. // unchanged.
  2177. if (start < 0)
  2178. {
  2179. return src;
  2180. }
  2181. // If both indices are greater than the upper
  2182. // bound the result may seem initially counter
  2183. // intuitive.
  2184. if (end >= src.Length)
  2185. {
  2186. return src;
  2187. }
  2188. if (end < 0)
  2189. {
  2190. if (start < src.Length)
  2191. {
  2192. return src.Substring(start);
  2193. }
  2194. else
  2195. {
  2196. return String.Empty;
  2197. }
  2198. }
  2199. else
  2200. {
  2201. if (start < src.Length)
  2202. {
  2203. return src.Substring(0,end+1) + src.Substring(start);
  2204. }
  2205. else
  2206. {
  2207. return src.Substring(0,end+1);
  2208. }
  2209. }
  2210. }
  2211. }
  2212. /// <summary>
  2213. /// Delete substring removes the specified substring bounded
  2214. /// by the inclusive indices start and end. Indices may be
  2215. /// negative (indicating end-relative) and may be inverted,
  2216. /// i.e. end < start.
  2217. /// </summary>
  2218. public LSL_String llDeleteSubString(string src, int start, int end)
  2219. {
  2220. m_host.AddScriptLPS(1);
  2221. // Normalize indices (if negative).
  2222. // After normlaization they may still be
  2223. // negative, but that is now relative to
  2224. // the start, rather than the end, of the
  2225. // sequence.
  2226. if (start < 0)
  2227. {
  2228. start = src.Length+start;
  2229. }
  2230. if (end < 0)
  2231. {
  2232. end = src.Length+end;
  2233. }
  2234. // Conventionally delimited substring
  2235. if (start <= end)
  2236. {
  2237. // If both bounds are outside of the existing
  2238. // string, then return unchanges.
  2239. if (end < 0 || start >= src.Length)
  2240. {
  2241. return src;
  2242. }
  2243. // At least one bound is in-range, so we
  2244. // need to clip the out-of-bound argument.
  2245. if (start < 0)
  2246. {
  2247. start = 0;
  2248. }
  2249. if (end >= src.Length)
  2250. {
  2251. end = src.Length-1;
  2252. }
  2253. return src.Remove(start,end-start+1);
  2254. }
  2255. // Inverted substring
  2256. else
  2257. {
  2258. // In this case, out of bounds means that
  2259. // the existing string is part of the cut.
  2260. if (start < 0 || end >= src.Length)
  2261. {
  2262. return String.Empty;
  2263. }
  2264. if (end > 0)
  2265. {
  2266. if (start < src.Length)
  2267. {
  2268. return src.Remove(start).Remove(0,end+1);
  2269. }
  2270. else
  2271. {
  2272. return src.Remove(0,end+1);
  2273. }
  2274. }
  2275. else
  2276. {
  2277. if (start < src.Length)
  2278. {
  2279. return src.Remove(start);
  2280. }
  2281. else
  2282. {
  2283. return src;
  2284. }
  2285. }
  2286. }
  2287. }
  2288. /// <summary>
  2289. /// Insert string inserts the specified string identified by src
  2290. /// at the index indicated by index. Index may be negative, in
  2291. /// which case it is end-relative. The index may exceed either
  2292. /// string bound, with the result being a concatenation.
  2293. /// </summary>
  2294. public LSL_String llInsertString(string dest, int index, string src)
  2295. {
  2296. m_host.AddScriptLPS(1);
  2297. // Normalize indices (if negative).
  2298. // After normlaization they may still be
  2299. // negative, but that is now relative to
  2300. // the start, rather than the end, of the
  2301. // sequence.
  2302. if (index < 0)
  2303. {
  2304. index = dest.Length+index;
  2305. // Negative now means it is less than the lower
  2306. // bound of the string.
  2307. if (index < 0)
  2308. {
  2309. return src+dest;
  2310. }
  2311. }
  2312. if (index >= dest.Length)
  2313. {
  2314. return dest+src;
  2315. }
  2316. // The index is in bounds.
  2317. // In this case the index refers to the index that will
  2318. // be assigned to the first character of the inserted string.
  2319. // So unlike the other string operations, we do not add one
  2320. // to get the correct string length.
  2321. return dest.Substring(0,index)+src+dest.Substring(index);
  2322. }
  2323. public LSL_String llToUpper(string src)
  2324. {
  2325. m_host.AddScriptLPS(1);
  2326. return src.ToUpper();
  2327. }
  2328. public LSL_String llToLower(string src)
  2329. {
  2330. m_host.AddScriptLPS(1);
  2331. return src.ToLower();
  2332. }
  2333. public void llGiveMoney(string destination, int amount)
  2334. {
  2335. Util.FireAndForget(x =>
  2336. {
  2337. m_host.AddScriptLPS(1);
  2338. if (m_item.PermsGranter == UUID.Zero)
  2339. return;
  2340. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
  2341. {
  2342. LSLError("No permissions to give money");
  2343. return;
  2344. }
  2345. UUID toID = new UUID();
  2346. if (!UUID.TryParse(destination, out toID))
  2347. {
  2348. LSLError("Bad key in llGiveMoney");
  2349. return;
  2350. }
  2351. IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
  2352. if (money == null)
  2353. {
  2354. NotImplemented("llGiveMoney");
  2355. return;
  2356. }
  2357. money.ObjectGiveMoney(
  2358. m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
  2359. });
  2360. }
  2361. public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
  2362. {
  2363. m_host.AddScriptLPS(1);
  2364. Deprecated("llMakeExplosion");
  2365. ScriptSleep(100);
  2366. }
  2367. public void llMakeFountain(int particles, double scale, double vel, double lifetime, double arc, int bounce, string texture, LSL_Vector offset, double bounce_offset)
  2368. {
  2369. m_host.AddScriptLPS(1);
  2370. Deprecated("llMakeFountain");
  2371. ScriptSleep(100);
  2372. }
  2373. public void llMakeSmoke(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
  2374. {
  2375. m_host.AddScriptLPS(1);
  2376. Deprecated("llMakeSmoke");
  2377. ScriptSleep(100);
  2378. }
  2379. public void llMakeFire(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
  2380. {
  2381. m_host.AddScriptLPS(1);
  2382. Deprecated("llMakeFire");
  2383. ScriptSleep(100);
  2384. }
  2385. public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
  2386. {
  2387. m_host.AddScriptLPS(1);
  2388. Util.FireAndForget(x =>
  2389. {
  2390. if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
  2391. return;
  2392. float dist = (float)llVecDist(llGetPos(), pos);
  2393. if (dist > m_ScriptDistanceFactor * 10.0f)
  2394. return;
  2395. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
  2396. if (item == null)
  2397. {
  2398. llSay(0, "Could not find object " + inventory);
  2399. return;
  2400. }
  2401. if (item.InvType != (int)InventoryType.Object)
  2402. {
  2403. llSay(0, "Unable to create requested object. Object is missing from database.");
  2404. return;
  2405. }
  2406. // need the magnitude later
  2407. // float velmag = (float)Util.GetMagnitude(llvel);
  2408. SceneObjectGroup new_group = World.RezObject(m_host, item, pos, rot, vel, param);
  2409. // If either of these are null, then there was an unknown error.
  2410. if (new_group == null)
  2411. return;
  2412. // objects rezzed with this method are die_at_edge by default.
  2413. new_group.RootPart.SetDieAtEdge(true);
  2414. new_group.ResumeScripts();
  2415. m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
  2416. "object_rez", new Object[] {
  2417. new LSL_String(
  2418. new_group.RootPart.UUID.ToString()) },
  2419. new DetectParams[0]));
  2420. float groupmass = new_group.GetMass();
  2421. PhysicsActor pa = new_group.RootPart.PhysActor;
  2422. //Recoil.
  2423. if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero)
  2424. {
  2425. Vector3 recoil = -vel * groupmass * m_recoilScaleFactor;
  2426. if (recoil != Vector3.Zero)
  2427. {
  2428. llApplyImpulse(recoil, 0);
  2429. }
  2430. }
  2431. // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
  2432. });
  2433. //ScriptSleep((int)((groupmass * velmag) / 10));
  2434. ScriptSleep(100);
  2435. }
  2436. public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
  2437. {
  2438. llRezAtRoot(inventory, pos, vel, rot, param);
  2439. }
  2440. public void llLookAt(LSL_Vector target, double strength, double damping)
  2441. {
  2442. m_host.AddScriptLPS(1);
  2443. // Determine where we are looking from
  2444. LSL_Vector from = llGetPos();
  2445. // Work out the normalised vector from the source to the target
  2446. LSL_Vector delta = llVecNorm(target - from);
  2447. LSL_Vector angle = new LSL_Vector(0,0,0);
  2448. // Calculate the yaw
  2449. // subtracting PI_BY_TWO is required to compensate for the odd SL co-ordinate system
  2450. angle.x = llAtan2(delta.z, delta.y) - ScriptBaseClass.PI_BY_TWO;
  2451. // Calculate pitch
  2452. angle.y = llAtan2(delta.x, llSqrt((delta.y * delta.y) + (delta.z * delta.z)));
  2453. // we need to convert from a vector describing
  2454. // the angles of rotation in radians into rotation value
  2455. LSL_Rotation rot = llEuler2Rot(angle);
  2456. // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
  2457. // set the rotation of the object, copy that behavior
  2458. PhysicsActor pa = m_host.PhysActor;
  2459. if (strength == 0 || pa == null || !pa.IsPhysical)
  2460. {
  2461. llSetRot(rot);
  2462. }
  2463. else
  2464. {
  2465. m_host.StartLookAt(rot, (float)strength, (float)damping);
  2466. }
  2467. }
  2468. public void llStopLookAt()
  2469. {
  2470. m_host.AddScriptLPS(1);
  2471. // NotImplemented("llStopLookAt");
  2472. m_host.StopLookAt();
  2473. }
  2474. public void llSetTimerEvent(double sec)
  2475. {
  2476. if (sec != 0.0 && sec < m_MinTimerInterval)
  2477. sec = m_MinTimerInterval;
  2478. m_host.AddScriptLPS(1);
  2479. // Setting timer repeat
  2480. AsyncCommands.TimerPlugin.SetTimerEvent(m_host.LocalId, m_item.ItemID, sec);
  2481. }
  2482. public virtual void llSleep(double sec)
  2483. {
  2484. // m_log.Info("llSleep snoozing " + sec + "s.");
  2485. m_host.AddScriptLPS(1);
  2486. Sleep((int)(sec * 1000));
  2487. }
  2488. public LSL_Float llGetMass()
  2489. {
  2490. m_host.AddScriptLPS(1);
  2491. if (m_host.ParentGroup.IsAttachment)
  2492. {
  2493. ScenePresence attachedAvatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
  2494. if (attachedAvatar != null)
  2495. {
  2496. return attachedAvatar.GetMass();
  2497. }
  2498. else
  2499. {
  2500. return 0;
  2501. }
  2502. }
  2503. else
  2504. {
  2505. if (m_host.IsRoot)
  2506. {
  2507. return m_host.ParentGroup.GetMass();
  2508. }
  2509. else
  2510. {
  2511. return m_host.GetMass();
  2512. }
  2513. }
  2514. }
  2515. public void llCollisionFilter(string name, string id, int accept)
  2516. {
  2517. m_host.AddScriptLPS(1);
  2518. m_host.CollisionFilter.Clear();
  2519. UUID objectID;
  2520. if (!UUID.TryParse(id, out objectID))
  2521. objectID = UUID.Zero;
  2522. if (objectID == UUID.Zero && name == "")
  2523. return;
  2524. m_host.CollisionFilter.Add(accept,objectID.ToString() + name);
  2525. }
  2526. public void llTakeControls(int controls, int accept, int pass_on)
  2527. {
  2528. if (m_item.PermsGranter != UUID.Zero)
  2529. {
  2530. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  2531. if (presence != null)
  2532. {
  2533. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
  2534. {
  2535. presence.RegisterControlEventsToScript(controls, accept, pass_on, m_host.LocalId, m_item.ItemID);
  2536. }
  2537. }
  2538. }
  2539. m_host.AddScriptLPS(1);
  2540. }
  2541. public void llReleaseControls()
  2542. {
  2543. m_host.AddScriptLPS(1);
  2544. if (m_item.PermsGranter != UUID.Zero)
  2545. {
  2546. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  2547. if (presence != null)
  2548. {
  2549. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
  2550. {
  2551. // Unregister controls from Presence
  2552. presence.UnRegisterControlEventsToScript(m_host.LocalId, m_item.ItemID);
  2553. // Remove Take Control permission.
  2554. m_item.PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
  2555. }
  2556. }
  2557. }
  2558. }
  2559. public void llReleaseURL(string url)
  2560. {
  2561. m_host.AddScriptLPS(1);
  2562. if (m_UrlModule != null)
  2563. m_UrlModule.ReleaseURL(url);
  2564. }
  2565. /// <summary>
  2566. /// Attach the object containing this script to the avatar that owns it.
  2567. /// </summary>
  2568. /// <param name='attachmentPoint'>
  2569. /// The attachment point (e.g. <see cref="OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.ATTACH_CHEST">ATTACH_CHEST</see>)
  2570. /// </param>
  2571. /// <returns>true if the attach suceeded, false if it did not</returns>
  2572. public bool AttachToAvatar(int attachmentPoint)
  2573. {
  2574. SceneObjectGroup grp = m_host.ParentGroup;
  2575. ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
  2576. IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
  2577. if (attachmentsModule != null)
  2578. return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, false);
  2579. else
  2580. return false;
  2581. }
  2582. /// <summary>
  2583. /// Detach the object containing this script from the avatar it is attached to.
  2584. /// </summary>
  2585. /// <remarks>
  2586. /// Nothing happens if the object is not attached.
  2587. /// </remarks>
  2588. public void DetachFromAvatar()
  2589. {
  2590. Util.FireAndForget(DetachWrapper, m_host);
  2591. }
  2592. private void DetachWrapper(object o)
  2593. {
  2594. if (World.AttachmentsModule != null)
  2595. {
  2596. SceneObjectPart host = (SceneObjectPart)o;
  2597. ScenePresence presence = World.GetScenePresence(host.OwnerID);
  2598. World.AttachmentsModule.DetachSingleAttachmentToInv(presence, host.ParentGroup);
  2599. }
  2600. }
  2601. public void llAttachToAvatar(int attachmentPoint)
  2602. {
  2603. m_host.AddScriptLPS(1);
  2604. // if (m_host.ParentGroup.RootPart.AttachmentPoint == 0)
  2605. // return;
  2606. if (m_item.PermsGranter != m_host.OwnerID)
  2607. return;
  2608. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
  2609. AttachToAvatar(attachmentPoint);
  2610. }
  2611. public void llDetachFromAvatar()
  2612. {
  2613. m_host.AddScriptLPS(1);
  2614. if (m_host.ParentGroup.AttachmentPoint == 0)
  2615. return;
  2616. if (m_item.PermsGranter != m_host.OwnerID)
  2617. return;
  2618. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
  2619. DetachFromAvatar();
  2620. }
  2621. public void llTakeCamera(string avatar)
  2622. {
  2623. m_host.AddScriptLPS(1);
  2624. Deprecated("llTakeCamera");
  2625. }
  2626. public void llReleaseCamera(string avatar)
  2627. {
  2628. m_host.AddScriptLPS(1);
  2629. Deprecated("llReleaseCamera");
  2630. }
  2631. public LSL_String llGetOwner()
  2632. {
  2633. m_host.AddScriptLPS(1);
  2634. return m_host.OwnerID.ToString();
  2635. }
  2636. public void llInstantMessage(string user, string message)
  2637. {
  2638. m_host.AddScriptLPS(1);
  2639. // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
  2640. // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
  2641. // but I don't think we have a list of scenes available from here.
  2642. // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
  2643. // user is a UUID
  2644. // TODO: figure out values for client, fromSession, and imSessionID
  2645. // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
  2646. UUID friendTransactionID = UUID.Random();
  2647. //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
  2648. GridInstantMessage msg = new GridInstantMessage();
  2649. msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
  2650. msg.toAgentID = new Guid(user); // toAgentID.Guid;
  2651. msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
  2652. // m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
  2653. // m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
  2654. msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp;
  2655. //if (client != null)
  2656. //{
  2657. msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
  2658. //}
  2659. //else
  2660. //{
  2661. // msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it
  2662. //}
  2663. // Cap the message length at 1024.
  2664. if (message != null && message.Length > 1024)
  2665. msg.message = message.Substring(0, 1024);
  2666. else
  2667. msg.message = message;
  2668. msg.dialog = (byte)19; // messgage from script ??? // dialog;
  2669. msg.fromGroup = false;// fromGroup;
  2670. msg.offline = (byte)0; //offline;
  2671. msg.ParentEstateID = 0; //ParentEstateID;
  2672. msg.Position = new Vector3(m_host.AbsolutePosition);
  2673. msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
  2674. msg.binaryBucket
  2675. = Util.StringToBytes256(
  2676. "{0}/{1}/{2}/{3}",
  2677. World.RegionInfo.RegionName,
  2678. (int)Math.Floor(m_host.AbsolutePosition.X),
  2679. (int)Math.Floor(m_host.AbsolutePosition.Y),
  2680. (int)Math.Floor(m_host.AbsolutePosition.Z));
  2681. if (m_TransferModule != null)
  2682. {
  2683. m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
  2684. }
  2685. ScriptSleep(2000);
  2686. }
  2687. public void llEmail(string address, string subject, string message)
  2688. {
  2689. m_host.AddScriptLPS(1);
  2690. IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
  2691. if (emailModule == null)
  2692. {
  2693. ShoutError("llEmail: email module not configured");
  2694. return;
  2695. }
  2696. emailModule.SendEmail(m_host.UUID, address, subject, message);
  2697. llSleep(EMAIL_PAUSE_TIME);
  2698. }
  2699. public void llGetNextEmail(string address, string subject)
  2700. {
  2701. m_host.AddScriptLPS(1);
  2702. IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
  2703. if (emailModule == null)
  2704. {
  2705. ShoutError("llGetNextEmail: email module not configured");
  2706. return;
  2707. }
  2708. Email email;
  2709. email = emailModule.GetNextEmail(m_host.UUID, address, subject);
  2710. if (email == null)
  2711. return;
  2712. m_ScriptEngine.PostObjectEvent(m_host.LocalId,
  2713. new EventParams("email",
  2714. new Object[] {
  2715. new LSL_String(email.time),
  2716. new LSL_String(email.sender),
  2717. new LSL_String(email.subject),
  2718. new LSL_String(email.message),
  2719. new LSL_Integer(email.numLeft)},
  2720. new DetectParams[0]));
  2721. }
  2722. public LSL_String llGetKey()
  2723. {
  2724. m_host.AddScriptLPS(1);
  2725. return m_host.UUID.ToString();
  2726. }
  2727. public LSL_Key llGenerateKey()
  2728. {
  2729. m_host.AddScriptLPS(1);
  2730. return UUID.Random().ToString();
  2731. }
  2732. public void llSetBuoyancy(double buoyancy)
  2733. {
  2734. m_host.AddScriptLPS(1);
  2735. if (!m_host.ParentGroup.IsDeleted)
  2736. {
  2737. m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
  2738. }
  2739. }
  2740. /// <summary>
  2741. /// Attempt to clamp the object on the Z axis at the given height over tau seconds.
  2742. /// </summary>
  2743. /// <param name="height">Height to hover. Height of zero disables hover.</param>
  2744. /// <param name="water">False if height is calculated just from ground, otherwise uses ground or water depending on whichever is higher</param>
  2745. /// <param name="tau">Number of seconds over which to reach target</param>
  2746. public void llSetHoverHeight(double height, int water, double tau)
  2747. {
  2748. m_host.AddScriptLPS(1);
  2749. if (m_host.PhysActor != null)
  2750. {
  2751. PIDHoverType hoverType = PIDHoverType.Ground;
  2752. if (water != 0)
  2753. {
  2754. hoverType = PIDHoverType.GroundAndWater;
  2755. }
  2756. m_host.SetHoverHeight((float)height, hoverType, (float)tau);
  2757. }
  2758. }
  2759. public void llStopHover()
  2760. {
  2761. m_host.AddScriptLPS(1);
  2762. if (m_host.PhysActor != null)
  2763. {
  2764. m_host.SetHoverHeight(0f, PIDHoverType.Ground, 0f);
  2765. }
  2766. }
  2767. public void llMinEventDelay(double delay)
  2768. {
  2769. m_host.AddScriptLPS(1);
  2770. try
  2771. {
  2772. m_ScriptEngine.SetMinEventDelay(m_item.ItemID, delay);
  2773. }
  2774. catch (NotImplementedException)
  2775. {
  2776. // Currently not implemented in DotNetEngine only XEngine
  2777. NotImplemented("llMinEventDelay in DotNetEngine");
  2778. }
  2779. }
  2780. /// <summary>
  2781. /// llSoundPreload is deprecated. In SL this appears to do absolutely nothing
  2782. /// and is documented to have no delay.
  2783. /// </summary>
  2784. public void llSoundPreload(string sound)
  2785. {
  2786. m_host.AddScriptLPS(1);
  2787. }
  2788. public void llRotLookAt(LSL_Rotation target, double strength, double damping)
  2789. {
  2790. m_host.AddScriptLPS(1);
  2791. // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
  2792. // set the rotation of the object, copy that behavior
  2793. PhysicsActor pa = m_host.PhysActor;
  2794. if (strength == 0 || pa == null || !pa.IsPhysical)
  2795. {
  2796. llSetLocalRot(target);
  2797. }
  2798. else
  2799. {
  2800. m_host.RotLookAt(target, (float)strength, (float)damping);
  2801. }
  2802. }
  2803. public LSL_Integer llStringLength(string str)
  2804. {
  2805. m_host.AddScriptLPS(1);
  2806. if (str.Length > 0)
  2807. {
  2808. return str.Length;
  2809. }
  2810. else
  2811. {
  2812. return 0;
  2813. }
  2814. }
  2815. public void llStartAnimation(string anim)
  2816. {
  2817. m_host.AddScriptLPS(1);
  2818. if (m_item.PermsGranter == UUID.Zero)
  2819. return;
  2820. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
  2821. {
  2822. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  2823. if (presence != null)
  2824. {
  2825. // Do NOT try to parse UUID, animations cannot be triggered by ID
  2826. UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation);
  2827. if (animID == UUID.Zero)
  2828. presence.Animator.AddAnimation(anim, m_host.UUID);
  2829. else
  2830. presence.Animator.AddAnimation(animID, m_host.UUID);
  2831. }
  2832. }
  2833. }
  2834. public void llStopAnimation(string anim)
  2835. {
  2836. m_host.AddScriptLPS(1);
  2837. if (m_item.PermsGranter == UUID.Zero)
  2838. return;
  2839. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
  2840. {
  2841. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  2842. if (presence != null)
  2843. {
  2844. UUID animID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, anim);
  2845. if (animID == UUID.Zero)
  2846. presence.Animator.RemoveAnimation(anim);
  2847. else
  2848. presence.Animator.RemoveAnimation(animID, true);
  2849. }
  2850. }
  2851. }
  2852. public void llPointAt(LSL_Vector pos)
  2853. {
  2854. m_host.AddScriptLPS(1);
  2855. }
  2856. public void llStopPointAt()
  2857. {
  2858. m_host.AddScriptLPS(1);
  2859. }
  2860. public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
  2861. {
  2862. m_host.AddScriptLPS(1);
  2863. TargetOmega(m_host, axis, spinrate, gain);
  2864. }
  2865. protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain)
  2866. {
  2867. part.UpdateAngularVelocity(axis * spinrate);
  2868. }
  2869. public LSL_Integer llGetStartParameter()
  2870. {
  2871. m_host.AddScriptLPS(1);
  2872. return m_ScriptEngine.GetStartParameter(m_item.ItemID);
  2873. }
  2874. public void llRequestPermissions(string agent, int perm)
  2875. {
  2876. UUID agentID;
  2877. if (!UUID.TryParse(agent, out agentID))
  2878. return;
  2879. if (agentID == UUID.Zero || perm == 0) // Releasing permissions
  2880. {
  2881. llReleaseControls();
  2882. m_item.PermsGranter = UUID.Zero;
  2883. m_item.PermsMask = 0;
  2884. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
  2885. "run_time_permissions", new Object[] {
  2886. new LSL_Integer(0) },
  2887. new DetectParams[0]));
  2888. return;
  2889. }
  2890. if (m_item.PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
  2891. llReleaseControls();
  2892. m_host.AddScriptLPS(1);
  2893. int implicitPerms = 0;
  2894. if (m_host.ParentGroup.IsAttachment && (UUID)agent == m_host.ParentGroup.AttachedAvatar)
  2895. {
  2896. // When attached, certain permissions are implicit if requested from owner
  2897. implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
  2898. ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
  2899. ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
  2900. ScriptBaseClass.PERMISSION_ATTACH;
  2901. }
  2902. else
  2903. {
  2904. if (m_host.ParentGroup.GetSittingAvatars().Contains(agentID))
  2905. {
  2906. // When agent is sitting, certain permissions are implicit if requested from sitting agent
  2907. implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
  2908. ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
  2909. ScriptBaseClass.PERMISSION_TRACK_CAMERA |
  2910. ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
  2911. }
  2912. else
  2913. {
  2914. if (World.GetExtraSetting("auto_grant_attach_perms") == "true")
  2915. implicitPerms = ScriptBaseClass.PERMISSION_ATTACH;
  2916. }
  2917. }
  2918. if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
  2919. {
  2920. lock (m_host.TaskInventory)
  2921. {
  2922. m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
  2923. m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
  2924. }
  2925. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
  2926. "run_time_permissions", new Object[] {
  2927. new LSL_Integer(perm) },
  2928. new DetectParams[0]));
  2929. return;
  2930. }
  2931. ScenePresence presence = World.GetScenePresence(agentID);
  2932. if (presence != null)
  2933. {
  2934. // If permissions are being requested from an NPC and were not implicitly granted above then
  2935. // auto grant all reuqested permissions if the script is owned by the NPC or the NPCs owner
  2936. INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
  2937. if (npcModule != null && npcModule.IsNPC(agentID, World))
  2938. {
  2939. if (npcModule.CheckPermissions(agentID, m_host.OwnerID))
  2940. {
  2941. lock (m_host.TaskInventory)
  2942. {
  2943. m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
  2944. m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
  2945. }
  2946. m_ScriptEngine.PostScriptEvent(
  2947. m_item.ItemID,
  2948. new EventParams(
  2949. "run_time_permissions", new Object[] { new LSL_Integer(perm) }, new DetectParams[0]));
  2950. }
  2951. // it is an NPC, exit even if the permissions werent granted above, they are not going to answer
  2952. // the question!
  2953. return;
  2954. }
  2955. string ownerName = resolveName(m_host.ParentGroup.RootPart.OwnerID);
  2956. if (ownerName == String.Empty)
  2957. ownerName = "(hippos)";
  2958. if (!m_waitingForScriptAnswer)
  2959. {
  2960. lock (m_host.TaskInventory)
  2961. {
  2962. m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
  2963. m_host.TaskInventory[m_item.ItemID].PermsMask = 0;
  2964. }
  2965. presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
  2966. m_waitingForScriptAnswer=true;
  2967. }
  2968. presence.ControllingClient.SendScriptQuestion(
  2969. m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, m_item.ItemID, perm);
  2970. return;
  2971. }
  2972. // Requested agent is not in range, refuse perms
  2973. m_ScriptEngine.PostScriptEvent(
  2974. m_item.ItemID,
  2975. new EventParams("run_time_permissions", new Object[] { new LSL_Integer(0) }, new DetectParams[0]));
  2976. }
  2977. void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer)
  2978. {
  2979. if (taskID != m_host.UUID)
  2980. return;
  2981. client.OnScriptAnswer -= handleScriptAnswer;
  2982. m_waitingForScriptAnswer = false;
  2983. if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
  2984. llReleaseControls();
  2985. lock (m_host.TaskInventory)
  2986. {
  2987. m_host.TaskInventory[m_item.ItemID].PermsMask = answer;
  2988. }
  2989. m_ScriptEngine.PostScriptEvent(
  2990. m_item.ItemID,
  2991. new EventParams("run_time_permissions", new Object[] { new LSL_Integer(answer) }, new DetectParams[0]));
  2992. }
  2993. public LSL_String llGetPermissionsKey()
  2994. {
  2995. m_host.AddScriptLPS(1);
  2996. return m_item.PermsGranter.ToString();
  2997. }
  2998. public LSL_Integer llGetPermissions()
  2999. {
  3000. m_host.AddScriptLPS(1);
  3001. int perms = m_item.PermsMask;
  3002. if (m_automaticLinkPermission)
  3003. perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
  3004. return perms;
  3005. }
  3006. public LSL_Integer llGetLinkNumber()
  3007. {
  3008. m_host.AddScriptLPS(1);
  3009. if (m_host.ParentGroup.PrimCount > 1)
  3010. {
  3011. return m_host.LinkNum;
  3012. }
  3013. else
  3014. {
  3015. return 0;
  3016. }
  3017. }
  3018. public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
  3019. {
  3020. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  3021. foreach (SceneObjectPart part in parts)
  3022. part.SetFaceColorAlpha(face, color, null);
  3023. }
  3024. public void llCreateLink(string target, int parent)
  3025. {
  3026. m_host.AddScriptLPS(1);
  3027. UUID targetID;
  3028. if (!UUID.TryParse(target, out targetID))
  3029. return;
  3030. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
  3031. && !m_automaticLinkPermission)
  3032. {
  3033. ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
  3034. return;
  3035. }
  3036. IClientAPI client = null;
  3037. ScenePresence sp = World.GetScenePresence(m_item.PermsGranter);
  3038. if (sp != null)
  3039. client = sp.ControllingClient;
  3040. SceneObjectPart targetPart = World.GetSceneObjectPart((UUID)targetID);
  3041. if (targetPart.ParentGroup.AttachmentPoint != 0)
  3042. return; // Fail silently if attached
  3043. if (targetPart.ParentGroup.RootPart.OwnerID != m_host.ParentGroup.RootPart.OwnerID)
  3044. return;
  3045. SceneObjectGroup parentPrim = null, childPrim = null;
  3046. if (targetPart != null)
  3047. {
  3048. if (parent != 0)
  3049. {
  3050. parentPrim = m_host.ParentGroup;
  3051. childPrim = targetPart.ParentGroup;
  3052. }
  3053. else
  3054. {
  3055. parentPrim = targetPart.ParentGroup;
  3056. childPrim = m_host.ParentGroup;
  3057. }
  3058. // Required for linking
  3059. childPrim.RootPart.ClearUpdateSchedule();
  3060. parentPrim.LinkToGroup(childPrim, true);
  3061. }
  3062. parentPrim.TriggerScriptChangedEvent(Changed.LINK);
  3063. parentPrim.RootPart.CreateSelected = true;
  3064. parentPrim.HasGroupChanged = true;
  3065. parentPrim.ScheduleGroupForFullUpdate();
  3066. if (client != null)
  3067. parentPrim.SendPropertiesToClient(client);
  3068. ScriptSleep(1000);
  3069. }
  3070. public void llBreakLink(int linknum)
  3071. {
  3072. m_host.AddScriptLPS(1);
  3073. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
  3074. && !m_automaticLinkPermission)
  3075. {
  3076. ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
  3077. return;
  3078. }
  3079. if (linknum < ScriptBaseClass.LINK_THIS)
  3080. return;
  3081. SceneObjectGroup parentPrim = m_host.ParentGroup;
  3082. if (parentPrim.AttachmentPoint != 0)
  3083. return; // Fail silently if attached
  3084. SceneObjectPart childPrim = null;
  3085. switch (linknum)
  3086. {
  3087. case ScriptBaseClass.LINK_ROOT:
  3088. break;
  3089. case ScriptBaseClass.LINK_SET:
  3090. case ScriptBaseClass.LINK_ALL_OTHERS:
  3091. case ScriptBaseClass.LINK_ALL_CHILDREN:
  3092. case ScriptBaseClass.LINK_THIS:
  3093. foreach (SceneObjectPart part in parentPrim.Parts)
  3094. {
  3095. if (part.UUID != m_host.UUID)
  3096. {
  3097. childPrim = part;
  3098. break;
  3099. }
  3100. }
  3101. break;
  3102. default:
  3103. childPrim = parentPrim.GetLinkNumPart(linknum);
  3104. if (childPrim.UUID == m_host.UUID)
  3105. childPrim = null;
  3106. break;
  3107. }
  3108. if (linknum == ScriptBaseClass.LINK_ROOT)
  3109. {
  3110. // Restructuring Multiple Prims.
  3111. List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
  3112. parts.Remove(parentPrim.RootPart);
  3113. foreach (SceneObjectPart part in parts)
  3114. {
  3115. parentPrim.DelinkFromGroup(part.LocalId, true);
  3116. }
  3117. parentPrim.HasGroupChanged = true;
  3118. parentPrim.ScheduleGroupForFullUpdate();
  3119. parentPrim.TriggerScriptChangedEvent(Changed.LINK);
  3120. if (parts.Count > 0)
  3121. {
  3122. SceneObjectPart newRoot = parts[0];
  3123. parts.Remove(newRoot);
  3124. foreach (SceneObjectPart part in parts)
  3125. {
  3126. // Required for linking
  3127. part.ClearUpdateSchedule();
  3128. newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
  3129. }
  3130. newRoot.ParentGroup.HasGroupChanged = true;
  3131. newRoot.ParentGroup.ScheduleGroupForFullUpdate();
  3132. }
  3133. }
  3134. else
  3135. {
  3136. if (childPrim == null)
  3137. return;
  3138. parentPrim.DelinkFromGroup(childPrim.LocalId, true);
  3139. parentPrim.HasGroupChanged = true;
  3140. parentPrim.ScheduleGroupForFullUpdate();
  3141. parentPrim.TriggerScriptChangedEvent(Changed.LINK);
  3142. }
  3143. }
  3144. public void llBreakAllLinks()
  3145. {
  3146. m_host.AddScriptLPS(1);
  3147. SceneObjectGroup parentPrim = m_host.ParentGroup;
  3148. if (parentPrim.AttachmentPoint != 0)
  3149. return; // Fail silently if attached
  3150. List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
  3151. parts.Remove(parentPrim.RootPart);
  3152. foreach (SceneObjectPart part in parts)
  3153. {
  3154. parentPrim.DelinkFromGroup(part.LocalId, true);
  3155. parentPrim.TriggerScriptChangedEvent(Changed.LINK);
  3156. }
  3157. parentPrim.HasGroupChanged = true;
  3158. parentPrim.ScheduleGroupForFullUpdate();
  3159. }
  3160. public LSL_String llGetLinkKey(int linknum)
  3161. {
  3162. m_host.AddScriptLPS(1);
  3163. if (linknum < 0)
  3164. {
  3165. if (linknum == ScriptBaseClass.LINK_THIS)
  3166. return m_host.UUID.ToString();
  3167. else
  3168. return ScriptBaseClass.NULL_KEY;
  3169. }
  3170. int actualPrimCount = m_host.ParentGroup.PrimCount;
  3171. List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
  3172. int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
  3173. // Special case for a single prim. In this case the linknum is zero. However, this will not match a single
  3174. // prim that has any avatars sat upon it (in which case the root prim is link 1).
  3175. if (linknum == 0)
  3176. {
  3177. if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
  3178. return m_host.UUID.ToString();
  3179. return ScriptBaseClass.NULL_KEY;
  3180. }
  3181. // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
  3182. // here we must match 1 (ScriptBaseClass.LINK_ROOT).
  3183. else if (linknum == 1 && actualPrimCount == 1)
  3184. {
  3185. if (sittingAvatarIds.Count > 0)
  3186. return m_host.ParentGroup.RootPart.UUID.ToString();
  3187. else
  3188. return ScriptBaseClass.NULL_KEY;
  3189. }
  3190. else if (linknum <= adjustedPrimCount)
  3191. {
  3192. if (linknum <= actualPrimCount)
  3193. return m_host.ParentGroup.GetLinkNumPart(linknum).UUID.ToString();
  3194. else
  3195. return sittingAvatarIds[linknum - actualPrimCount - 1].ToString();
  3196. }
  3197. else
  3198. {
  3199. return ScriptBaseClass.NULL_KEY;
  3200. }
  3201. }
  3202. /// <summary>
  3203. /// Returns the name of the child prim or seated avatar matching the
  3204. /// specified link number.
  3205. /// </summary>
  3206. /// <param name="linknum">
  3207. /// The number of a link in the linkset or a link-related constant.
  3208. /// </param>
  3209. /// <returns>
  3210. /// The name determined to match the specified link number.
  3211. /// </returns>
  3212. /// <remarks>
  3213. /// The rules governing the returned name are not simple. The only
  3214. /// time a blank name is returned is if the target prim has a blank
  3215. /// name. If no prim with the given link number can be found then
  3216. /// usually NULL_KEY is returned but there are exceptions.
  3217. ///
  3218. /// In a single unlinked prim, A call with 0 returns the name, all
  3219. /// other values for link number return NULL_KEY
  3220. ///
  3221. /// In link sets it is more complicated.
  3222. ///
  3223. /// If the script is in the root prim:-
  3224. /// A zero link number returns NULL_KEY.
  3225. /// Positive link numbers return the name of the prim, or NULL_KEY
  3226. /// if a prim does not exist at that position.
  3227. /// Negative link numbers return the name of the first child prim.
  3228. ///
  3229. /// If the script is in a child prim:-
  3230. /// Link numbers 0 or 1 return the name of the root prim.
  3231. /// Positive link numbers return the name of the prim or NULL_KEY
  3232. /// if a prim does not exist at that position.
  3233. /// Negative numbers return the name of the root prim.
  3234. ///
  3235. /// References
  3236. /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetLinkName
  3237. /// Mentions NULL_KEY being returned
  3238. /// http://wiki.secondlife.com/wiki/LlGetLinkName
  3239. /// Mentions using the LINK_* constants, some of which are negative
  3240. /// </remarks>
  3241. public LSL_String llGetLinkName(int linknum)
  3242. {
  3243. m_host.AddScriptLPS(1);
  3244. if (linknum < 0)
  3245. {
  3246. if (linknum == ScriptBaseClass.LINK_THIS)
  3247. return m_host.Name;
  3248. else
  3249. return ScriptBaseClass.NULL_KEY;
  3250. }
  3251. int actualPrimCount = m_host.ParentGroup.PrimCount;
  3252. List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
  3253. int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
  3254. // Special case for a single prim. In this case the linknum is zero. However, this will not match a single
  3255. // prim that has any avatars sat upon it (in which case the root prim is link 1).
  3256. if (linknum == 0)
  3257. {
  3258. if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
  3259. return m_host.Name;
  3260. return ScriptBaseClass.NULL_KEY;
  3261. }
  3262. // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
  3263. // here we must match 1 (ScriptBaseClass.LINK_ROOT).
  3264. else if (linknum == 1 && actualPrimCount == 1)
  3265. {
  3266. if (sittingAvatarIds.Count > 0)
  3267. return m_host.ParentGroup.RootPart.Name;
  3268. else
  3269. return ScriptBaseClass.NULL_KEY;
  3270. }
  3271. else if (linknum <= adjustedPrimCount)
  3272. {
  3273. if (linknum <= actualPrimCount)
  3274. {
  3275. return m_host.ParentGroup.GetLinkNumPart(linknum).Name;
  3276. }
  3277. else
  3278. {
  3279. ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]);
  3280. if (sp != null)
  3281. return sp.Name;
  3282. else
  3283. return ScriptBaseClass.NULL_KEY;
  3284. }
  3285. }
  3286. else
  3287. {
  3288. return ScriptBaseClass.NULL_KEY;
  3289. }
  3290. }
  3291. public LSL_Integer llGetInventoryNumber(int type)
  3292. {
  3293. m_host.AddScriptLPS(1);
  3294. int count = 0;
  3295. lock (m_host.TaskInventory)
  3296. {
  3297. foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
  3298. {
  3299. if (inv.Value.Type == type || type == -1)
  3300. {
  3301. count = count + 1;
  3302. }
  3303. }
  3304. }
  3305. return count;
  3306. }
  3307. public LSL_String llGetInventoryName(int type, int number)
  3308. {
  3309. m_host.AddScriptLPS(1);
  3310. ArrayList keys = new ArrayList();
  3311. lock (m_host.TaskInventory)
  3312. {
  3313. foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
  3314. {
  3315. if (inv.Value.Type == type || type == -1)
  3316. {
  3317. keys.Add(inv.Value.Name);
  3318. }
  3319. }
  3320. }
  3321. if (keys.Count == 0)
  3322. {
  3323. return String.Empty;
  3324. }
  3325. keys.Sort();
  3326. if (keys.Count > number)
  3327. {
  3328. return (string)keys[number];
  3329. }
  3330. return String.Empty;
  3331. }
  3332. public LSL_Float llGetEnergy()
  3333. {
  3334. m_host.AddScriptLPS(1);
  3335. // TODO: figure out real energy value
  3336. return 1.0f;
  3337. }
  3338. public void llGiveInventory(string destination, string inventory)
  3339. {
  3340. m_host.AddScriptLPS(1);
  3341. UUID destId = UUID.Zero;
  3342. if (!UUID.TryParse(destination, out destId))
  3343. {
  3344. llSay(0, "Could not parse key " + destination);
  3345. return;
  3346. }
  3347. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
  3348. if (item == null)
  3349. {
  3350. llSay(0, String.Format("Could not find object '{0}'", inventory));
  3351. throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
  3352. }
  3353. UUID objId = item.ItemID;
  3354. // check if destination is an object
  3355. if (World.GetSceneObjectPart(destId) != null)
  3356. {
  3357. // destination is an object
  3358. World.MoveTaskInventoryItem(destId, m_host, objId);
  3359. }
  3360. else
  3361. {
  3362. ScenePresence presence = World.GetScenePresence(destId);
  3363. if (presence == null)
  3364. {
  3365. UserAccount account =
  3366. World.UserAccountService.GetUserAccount(
  3367. World.RegionInfo.ScopeID,
  3368. destId);
  3369. if (account == null)
  3370. {
  3371. llSay(0, "Can't find destination "+destId.ToString());
  3372. return;
  3373. }
  3374. }
  3375. // destination is an avatar
  3376. InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId);
  3377. if (agentItem == null)
  3378. return;
  3379. if (m_TransferModule != null)
  3380. {
  3381. byte[] bucket = new byte[1];
  3382. bucket[0] = (byte)item.Type;
  3383. GridInstantMessage msg = new GridInstantMessage(World,
  3384. m_host.OwnerID, m_host.Name, destId,
  3385. (byte)InstantMessageDialog.TaskInventoryOffered,
  3386. false, item.Name+". "+m_host.Name+" is located at "+
  3387. World.RegionInfo.RegionName+" "+
  3388. m_host.AbsolutePosition.ToString(),
  3389. agentItem.ID, true, m_host.AbsolutePosition,
  3390. bucket, true);
  3391. m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
  3392. }
  3393. ScriptSleep(3000);
  3394. }
  3395. }
  3396. public void llRemoveInventory(string name)
  3397. {
  3398. m_host.AddScriptLPS(1);
  3399. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  3400. if (item == null)
  3401. return;
  3402. if (item.ItemID == m_item.ItemID)
  3403. throw new ScriptDeleteException();
  3404. else
  3405. m_host.Inventory.RemoveInventoryItem(item.ItemID);
  3406. }
  3407. public void llSetText(string text, LSL_Vector color, double alpha)
  3408. {
  3409. m_host.AddScriptLPS(1);
  3410. Vector3 av3 = Util.Clip(color, 0.0f, 1.0f);
  3411. if (text.Length > 254)
  3412. text = text.Remove(254);
  3413. byte[] data;
  3414. do
  3415. {
  3416. data = Util.UTF8.GetBytes(text);
  3417. if (data.Length > 254)
  3418. text = text.Substring(0, text.Length - 1);
  3419. } while (data.Length > 254);
  3420. m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f));
  3421. //m_host.ParentGroup.HasGroupChanged = true;
  3422. //m_host.ParentGroup.ScheduleGroupForFullUpdate();
  3423. }
  3424. public LSL_Float llWater(LSL_Vector offset)
  3425. {
  3426. m_host.AddScriptLPS(1);
  3427. return World.RegionInfo.RegionSettings.WaterHeight;
  3428. }
  3429. public void llPassTouches(int pass)
  3430. {
  3431. m_host.AddScriptLPS(1);
  3432. if (pass != 0)
  3433. m_host.PassTouches = true;
  3434. else
  3435. m_host.PassTouches = false;
  3436. }
  3437. public LSL_String llRequestAgentData(string id, int data)
  3438. {
  3439. m_host.AddScriptLPS(1);
  3440. UUID uuid = (UUID)id;
  3441. PresenceInfo pinfo = null;
  3442. UserAccount account;
  3443. UserInfoCacheEntry ce;
  3444. if (!m_userInfoCache.TryGetValue(uuid, out ce))
  3445. {
  3446. account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid);
  3447. if (account == null)
  3448. {
  3449. m_userInfoCache[uuid] = null; // Cache negative
  3450. return UUID.Zero.ToString();
  3451. }
  3452. PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
  3453. if (pinfos != null && pinfos.Length > 0)
  3454. {
  3455. foreach (PresenceInfo p in pinfos)
  3456. {
  3457. if (p.RegionID != UUID.Zero)
  3458. {
  3459. pinfo = p;
  3460. }
  3461. }
  3462. }
  3463. ce = new UserInfoCacheEntry();
  3464. ce.time = Util.EnvironmentTickCount();
  3465. ce.account = account;
  3466. ce.pinfo = pinfo;
  3467. }
  3468. else
  3469. {
  3470. if (ce == null)
  3471. return UUID.Zero.ToString();
  3472. account = ce.account;
  3473. pinfo = ce.pinfo;
  3474. }
  3475. if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) >= 20000)
  3476. {
  3477. PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
  3478. if (pinfos != null && pinfos.Length > 0)
  3479. {
  3480. foreach (PresenceInfo p in pinfos)
  3481. {
  3482. if (p.RegionID != UUID.Zero)
  3483. {
  3484. pinfo = p;
  3485. }
  3486. }
  3487. }
  3488. else
  3489. pinfo = null;
  3490. ce.time = Util.EnvironmentTickCount();
  3491. ce.pinfo = pinfo;
  3492. }
  3493. string reply = String.Empty;
  3494. switch (data)
  3495. {
  3496. case 1: // DATA_ONLINE (0|1)
  3497. if (pinfo != null && pinfo.RegionID != UUID.Zero)
  3498. reply = "1";
  3499. else
  3500. reply = "0";
  3501. break;
  3502. case 2: // DATA_NAME (First Last)
  3503. reply = account.FirstName + " " + account.LastName;
  3504. break;
  3505. case 3: // DATA_BORN (YYYY-MM-DD)
  3506. DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
  3507. born = born.AddSeconds(account.Created);
  3508. reply = born.ToString("yyyy-MM-dd");
  3509. break;
  3510. case 4: // DATA_RATING (0,0,0,0,0,0)
  3511. reply = "0,0,0,0,0,0";
  3512. break;
  3513. case 7: // DATA_USERLEVEL (integer)
  3514. reply = account.UserLevel.ToString();
  3515. break;
  3516. case 8: // DATA_PAYINFO (0|1|2|3)
  3517. reply = "0";
  3518. break;
  3519. default:
  3520. return UUID.Zero.ToString(); // Raise no event
  3521. }
  3522. UUID rq = UUID.Random();
  3523. UUID tid = AsyncCommands.
  3524. DataserverPlugin.RegisterRequest(m_host.LocalId,
  3525. m_item.ItemID, rq.ToString());
  3526. AsyncCommands.
  3527. DataserverPlugin.DataserverReply(rq.ToString(), reply);
  3528. ScriptSleep(100);
  3529. return tid.ToString();
  3530. }
  3531. public LSL_String llRequestInventoryData(string name)
  3532. {
  3533. m_host.AddScriptLPS(1);
  3534. foreach (TaskInventoryItem item in m_host.Inventory.GetInventoryItems())
  3535. {
  3536. if (item.Type == 3 && item.Name == name)
  3537. {
  3538. UUID tid = AsyncCommands.
  3539. DataserverPlugin.RegisterRequest(m_host.LocalId,
  3540. m_item.ItemID, item.AssetID.ToString());
  3541. Vector3 region = new Vector3(
  3542. World.RegionInfo.RegionLocX * Constants.RegionSize,
  3543. World.RegionInfo.RegionLocY * Constants.RegionSize,
  3544. 0);
  3545. World.AssetService.Get(item.AssetID.ToString(), this,
  3546. delegate(string i, object sender, AssetBase a)
  3547. {
  3548. AssetLandmark lm = new AssetLandmark(a);
  3549. float rx = (uint)(lm.RegionHandle >> 32);
  3550. float ry = (uint)lm.RegionHandle;
  3551. region = lm.Position + new Vector3(rx, ry, 0) - region;
  3552. string reply = region.ToString();
  3553. AsyncCommands.
  3554. DataserverPlugin.DataserverReply(i.ToString(),
  3555. reply);
  3556. });
  3557. ScriptSleep(1000);
  3558. return tid.ToString();
  3559. }
  3560. }
  3561. ScriptSleep(1000);
  3562. return String.Empty;
  3563. }
  3564. public void llSetDamage(double damage)
  3565. {
  3566. m_host.AddScriptLPS(1);
  3567. m_host.ParentGroup.Damage = (float)damage;
  3568. }
  3569. public void llTeleportAgentHome(string agent)
  3570. {
  3571. m_host.AddScriptLPS(1);
  3572. UUID agentId = new UUID();
  3573. if (UUID.TryParse(agent, out agentId))
  3574. {
  3575. ScenePresence presence = World.GetScenePresence(agentId);
  3576. if (presence != null)
  3577. {
  3578. // agent must be over the owners land
  3579. if (m_host.OwnerID == World.LandChannel.GetLandObject(
  3580. presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
  3581. {
  3582. World.TeleportClientHome(agentId, presence.ControllingClient);
  3583. }
  3584. }
  3585. }
  3586. ScriptSleep(5000);
  3587. }
  3588. public void llTeleportAgent(string agent, string destination, LSL_Vector targetPos, LSL_Vector targetLookAt)
  3589. {
  3590. m_host.AddScriptLPS(1);
  3591. UUID agentId = new UUID();
  3592. if (UUID.TryParse(agent, out agentId))
  3593. {
  3594. ScenePresence presence = World.GetScenePresence(agentId);
  3595. if (presence != null && presence.PresenceType != PresenceType.Npc)
  3596. {
  3597. // agent must not be a god
  3598. if (presence.GodLevel >= 200) return;
  3599. if (destination == String.Empty)
  3600. destination = World.RegionInfo.RegionName;
  3601. // agent must be over the owners land
  3602. if (m_host.OwnerID == World.LandChannel.GetLandObject(
  3603. presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
  3604. {
  3605. DoLLTeleport(presence, destination, targetPos, targetLookAt);
  3606. }
  3607. else // or must be wearing the prim
  3608. {
  3609. if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
  3610. {
  3611. DoLLTeleport(presence, destination, targetPos, targetLookAt);
  3612. }
  3613. }
  3614. }
  3615. }
  3616. }
  3617. public void llTeleportAgentGlobalCoords(string agent, LSL_Vector global_coords, LSL_Vector targetPos, LSL_Vector targetLookAt)
  3618. {
  3619. m_host.AddScriptLPS(1);
  3620. UUID agentId = new UUID();
  3621. ulong regionHandle = Utils.UIntsToLong((uint)global_coords.x, (uint)global_coords.y);
  3622. if (UUID.TryParse(agent, out agentId))
  3623. {
  3624. ScenePresence presence = World.GetScenePresence(agentId);
  3625. if (presence != null && presence.PresenceType != PresenceType.Npc)
  3626. {
  3627. // agent must not be a god
  3628. if (presence.GodLevel >= 200) return;
  3629. // agent must be over the owners land
  3630. if (m_host.OwnerID == World.LandChannel.GetLandObject(
  3631. presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
  3632. {
  3633. World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
  3634. }
  3635. else // or must be wearing the prim
  3636. {
  3637. if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
  3638. {
  3639. World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
  3640. }
  3641. }
  3642. }
  3643. }
  3644. }
  3645. private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt)
  3646. {
  3647. UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, destination);
  3648. // The destinaion is not an asset ID and also doesn't name a landmark.
  3649. // Use it as a sim name
  3650. if (assetID == UUID.Zero)
  3651. {
  3652. World.RequestTeleportLocation(sp.ControllingClient, destination, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
  3653. return;
  3654. }
  3655. AssetBase lma = World.AssetService.Get(assetID.ToString());
  3656. if (lma == null)
  3657. return;
  3658. if (lma.Type != (sbyte)AssetType.Landmark)
  3659. return;
  3660. AssetLandmark lm = new AssetLandmark(lma);
  3661. World.RequestTeleportLocation(sp.ControllingClient, lm.RegionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
  3662. }
  3663. public void llTextBox(string agent, string message, int chatChannel)
  3664. {
  3665. IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
  3666. if (dm == null)
  3667. return;
  3668. m_host.AddScriptLPS(1);
  3669. UUID av = new UUID();
  3670. if (!UUID.TryParse(agent,out av))
  3671. {
  3672. LSLError("First parameter to llDialog needs to be a key");
  3673. return;
  3674. }
  3675. if (message == string.Empty)
  3676. {
  3677. ShoutError("Trying to use llTextBox with empty message.");
  3678. }
  3679. else if (message.Length > 512)
  3680. {
  3681. ShoutError("Trying to use llTextBox with message over 512 characters.");
  3682. }
  3683. else
  3684. {
  3685. dm.SendTextBoxToUser(av, message, chatChannel, m_host.Name, m_host.UUID, m_host.OwnerID);
  3686. ScriptSleep(1000);
  3687. }
  3688. }
  3689. public void llModifyLand(int action, int brush)
  3690. {
  3691. m_host.AddScriptLPS(1);
  3692. ITerrainModule tm = m_ScriptEngine.World.RequestModuleInterface<ITerrainModule>();
  3693. if (tm != null)
  3694. {
  3695. tm.ModifyTerrain(m_host.OwnerID, m_host.AbsolutePosition, (byte) brush, (byte) action, m_host.OwnerID);
  3696. }
  3697. }
  3698. public void llCollisionSound(string impact_sound, double impact_volume)
  3699. {
  3700. m_host.AddScriptLPS(1);
  3701. // TODO: Parameter check logic required.
  3702. m_host.CollisionSound = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound);
  3703. m_host.CollisionSoundVolume = (float)impact_volume;
  3704. }
  3705. public LSL_String llGetAnimation(string id)
  3706. {
  3707. // This should only return a value if the avatar is in the same region
  3708. m_host.AddScriptLPS(1);
  3709. UUID avatar = (UUID)id;
  3710. ScenePresence presence = World.GetScenePresence(avatar);
  3711. if (presence == null)
  3712. return "";
  3713. if (m_host.RegionHandle == presence.RegionHandle)
  3714. {
  3715. Dictionary<UUID, string> animationstateNames = DefaultAvatarAnimations.AnimStateNames;
  3716. if (presence != null)
  3717. {
  3718. AnimationSet currentAnims = presence.Animator.Animations;
  3719. string currentAnimationState = String.Empty;
  3720. if (animationstateNames.TryGetValue(currentAnims.ImplicitDefaultAnimation.AnimID, out currentAnimationState))
  3721. return currentAnimationState;
  3722. }
  3723. }
  3724. return String.Empty;
  3725. }
  3726. public void llMessageLinked(int linknumber, int num, string msg, string id)
  3727. {
  3728. m_host.AddScriptLPS(1);
  3729. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  3730. UUID partItemID;
  3731. foreach (SceneObjectPart part in parts)
  3732. {
  3733. foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems())
  3734. {
  3735. if (item.Type == ScriptBaseClass.INVENTORY_SCRIPT)
  3736. {
  3737. partItemID = item.ItemID;
  3738. int linkNumber = m_host.LinkNum;
  3739. if (m_host.ParentGroup.PrimCount == 1)
  3740. linkNumber = 0;
  3741. object[] resobj = new object[]
  3742. {
  3743. new LSL_Integer(linkNumber), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
  3744. };
  3745. m_ScriptEngine.PostScriptEvent(partItemID,
  3746. new EventParams("link_message",
  3747. resobj, new DetectParams[0]));
  3748. }
  3749. }
  3750. }
  3751. }
  3752. public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
  3753. {
  3754. m_host.AddScriptLPS(1);
  3755. bool pushrestricted = World.RegionInfo.RegionSettings.RestrictPushing;
  3756. bool pushAllowed = false;
  3757. bool pusheeIsAvatar = false;
  3758. UUID targetID = UUID.Zero;
  3759. if (!UUID.TryParse(target,out targetID))
  3760. return;
  3761. ScenePresence pusheeav = null;
  3762. Vector3 PusheePos = Vector3.Zero;
  3763. SceneObjectPart pusheeob = null;
  3764. ScenePresence avatar = World.GetScenePresence(targetID);
  3765. if (avatar != null)
  3766. {
  3767. pusheeIsAvatar = true;
  3768. // Pushee doesn't have a physics actor
  3769. if (avatar.PhysicsActor == null)
  3770. return;
  3771. // Pushee is in GodMode this pushing object isn't owned by them
  3772. if (avatar.GodLevel > 0 && m_host.OwnerID != targetID)
  3773. return;
  3774. pusheeav = avatar;
  3775. // Find pushee position
  3776. // Pushee Linked?
  3777. SceneObjectPart sitPart = pusheeav.ParentPart;
  3778. if (sitPart != null)
  3779. PusheePos = sitPart.AbsolutePosition;
  3780. else
  3781. PusheePos = pusheeav.AbsolutePosition;
  3782. }
  3783. if (!pusheeIsAvatar)
  3784. {
  3785. // not an avatar so push is not affected by parcel flags
  3786. pusheeob = World.GetSceneObjectPart((UUID)target);
  3787. // We can't find object
  3788. if (pusheeob == null)
  3789. return;
  3790. // Object not pushable. Not an attachment and has no physics component
  3791. if (!pusheeob.ParentGroup.IsAttachment && pusheeob.PhysActor == null)
  3792. return;
  3793. PusheePos = pusheeob.AbsolutePosition;
  3794. pushAllowed = true;
  3795. }
  3796. else
  3797. {
  3798. if (pushrestricted)
  3799. {
  3800. ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y);
  3801. // We didn't find the parcel but region is push restricted so assume it is NOT ok
  3802. if (targetlandObj == null)
  3803. return;
  3804. // Need provisions for Group Owned here
  3805. if (m_host.OwnerID == targetlandObj.LandData.OwnerID ||
  3806. targetlandObj.LandData.IsGroupOwned || m_host.OwnerID == targetID)
  3807. {
  3808. pushAllowed = true;
  3809. }
  3810. }
  3811. else
  3812. {
  3813. ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y);
  3814. if (targetlandObj == null)
  3815. {
  3816. // We didn't find the parcel but region isn't push restricted so assume it's ok
  3817. pushAllowed = true;
  3818. }
  3819. else
  3820. {
  3821. // Parcel push restriction
  3822. if ((targetlandObj.LandData.Flags & (uint)ParcelFlags.RestrictPushObject) == (uint)ParcelFlags.RestrictPushObject)
  3823. {
  3824. // Need provisions for Group Owned here
  3825. if (m_host.OwnerID == targetlandObj.LandData.OwnerID ||
  3826. targetlandObj.LandData.IsGroupOwned ||
  3827. m_host.OwnerID == targetID)
  3828. {
  3829. pushAllowed = true;
  3830. }
  3831. //ParcelFlags.RestrictPushObject
  3832. //pushAllowed = true;
  3833. }
  3834. else
  3835. {
  3836. // Parcel isn't push restricted
  3837. pushAllowed = true;
  3838. }
  3839. }
  3840. }
  3841. }
  3842. if (pushAllowed)
  3843. {
  3844. float distance = (PusheePos - m_host.AbsolutePosition).Length();
  3845. float distance_term = distance * distance * distance; // Script Energy
  3846. float pusher_mass = m_host.GetMass();
  3847. float PUSH_ATTENUATION_DISTANCE = 17f;
  3848. float PUSH_ATTENUATION_SCALE = 5f;
  3849. float distance_attenuation = 1f;
  3850. if (distance > PUSH_ATTENUATION_DISTANCE)
  3851. {
  3852. float normalized_units = 1f + (distance - PUSH_ATTENUATION_DISTANCE) / PUSH_ATTENUATION_SCALE;
  3853. distance_attenuation = 1f / normalized_units;
  3854. }
  3855. Vector3 applied_linear_impulse = impulse;
  3856. {
  3857. float impulse_length = applied_linear_impulse.Length();
  3858. float desired_energy = impulse_length * pusher_mass;
  3859. if (desired_energy > 0f)
  3860. desired_energy += distance_term;
  3861. float scaling_factor = 1f;
  3862. scaling_factor *= distance_attenuation;
  3863. applied_linear_impulse *= scaling_factor;
  3864. }
  3865. if (pusheeIsAvatar)
  3866. {
  3867. if (pusheeav != null)
  3868. {
  3869. PhysicsActor pa = pusheeav.PhysicsActor;
  3870. if (pa != null)
  3871. {
  3872. if (local != 0)
  3873. {
  3874. applied_linear_impulse *= m_host.GetWorldRotation();
  3875. }
  3876. pa.AddForce(applied_linear_impulse, true);
  3877. }
  3878. }
  3879. }
  3880. else
  3881. {
  3882. if (pusheeob != null)
  3883. {
  3884. if (pusheeob.PhysActor != null)
  3885. {
  3886. pusheeob.ApplyImpulse(applied_linear_impulse, local != 0);
  3887. }
  3888. }
  3889. }
  3890. }
  3891. }
  3892. public void llPassCollisions(int pass)
  3893. {
  3894. m_host.AddScriptLPS(1);
  3895. if (pass == 0)
  3896. {
  3897. m_host.PassCollisions = false;
  3898. }
  3899. else
  3900. {
  3901. m_host.PassCollisions = true;
  3902. }
  3903. }
  3904. public LSL_String llGetScriptName()
  3905. {
  3906. m_host.AddScriptLPS(1);
  3907. return m_item.Name != null ? m_item.Name : String.Empty;
  3908. }
  3909. public LSL_Integer llGetLinkNumberOfSides(int link)
  3910. {
  3911. m_host.AddScriptLPS(1);
  3912. SceneObjectPart linkedPart;
  3913. if (link == ScriptBaseClass.LINK_ROOT)
  3914. linkedPart = m_host.ParentGroup.RootPart;
  3915. else if (link == ScriptBaseClass.LINK_THIS)
  3916. linkedPart = m_host;
  3917. else
  3918. linkedPart = m_host.ParentGroup.GetLinkNumPart(link);
  3919. return GetNumberOfSides(linkedPart);
  3920. }
  3921. public LSL_Integer llGetNumberOfSides()
  3922. {
  3923. m_host.AddScriptLPS(1);
  3924. return GetNumberOfSides(m_host);
  3925. }
  3926. protected int GetNumberOfSides(SceneObjectPart part)
  3927. {
  3928. int sides = part.GetNumberOfSides();
  3929. if (part.GetPrimType() == PrimType.SPHERE && part.Shape.ProfileHollow > 0)
  3930. {
  3931. // Make up for a bug where LSL shows 4 sides rather than 2
  3932. sides += 2;
  3933. }
  3934. return sides;
  3935. }
  3936. /* The new / changed functions were tested with the following LSL script:
  3937. default
  3938. {
  3939. state_entry()
  3940. {
  3941. rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
  3942. llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
  3943. llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
  3944. // convert back and forth between quaternion <-> vector and angle
  3945. rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
  3946. llOwnerSay("Old rotation was: "+(string) rot);
  3947. llOwnerSay("re-converted rotation is: "+(string) newrot);
  3948. llSetRot(rot); // to check the parameters in the prim
  3949. }
  3950. }
  3951. */
  3952. // Xantor 29/apr/2008
  3953. // Returns rotation described by rotating angle radians about axis.
  3954. // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
  3955. public LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle)
  3956. {
  3957. m_host.AddScriptLPS(1);
  3958. double x, y, z, s, t;
  3959. s = Math.Cos(angle * 0.5);
  3960. t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs
  3961. x = axis.x * t;
  3962. y = axis.y * t;
  3963. z = axis.z * t;
  3964. return new LSL_Rotation(x,y,z,s);
  3965. }
  3966. // Xantor 29/apr/2008
  3967. // converts a Quaternion to X,Y,Z axis rotations
  3968. public LSL_Vector llRot2Axis(LSL_Rotation rot)
  3969. {
  3970. m_host.AddScriptLPS(1);
  3971. double x,y,z;
  3972. if (rot.s > 1) // normalization needed
  3973. {
  3974. double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
  3975. rot.z * rot.z + rot.s * rot.s);
  3976. rot.x /= length;
  3977. rot.y /= length;
  3978. rot.z /= length;
  3979. rot.s /= length;
  3980. }
  3981. // double angle = 2 * Math.Acos(rot.s);
  3982. double s = Math.Sqrt(1 - rot.s * rot.s);
  3983. if (s < 0.001)
  3984. {
  3985. x = 1;
  3986. y = z = 0;
  3987. }
  3988. else
  3989. {
  3990. x = rot.x / s; // normalise axis
  3991. y = rot.y / s;
  3992. z = rot.z / s;
  3993. }
  3994. return new LSL_Vector(x,y,z);
  3995. }
  3996. // Returns the angle of a quaternion (see llRot2Axis for the axis)
  3997. public LSL_Float llRot2Angle(LSL_Rotation rot)
  3998. {
  3999. m_host.AddScriptLPS(1);
  4000. if (rot.s > 1) // normalization needed
  4001. {
  4002. double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
  4003. rot.z * rot.z + rot.s * rot.s);
  4004. rot.x /= length;
  4005. rot.y /= length;
  4006. rot.z /= length;
  4007. rot.s /= length;
  4008. }
  4009. double angle = 2 * Math.Acos(rot.s);
  4010. return angle;
  4011. }
  4012. public LSL_Float llAcos(double val)
  4013. {
  4014. m_host.AddScriptLPS(1);
  4015. return (double)Math.Acos(val);
  4016. }
  4017. public LSL_Float llAsin(double val)
  4018. {
  4019. m_host.AddScriptLPS(1);
  4020. return (double)Math.Asin(val);
  4021. }
  4022. // jcochran 5/jan/2012
  4023. public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b)
  4024. {
  4025. m_host.AddScriptLPS(1);
  4026. double aa = (a.x * a.x + a.y * a.y + a.z * a.z + a.s * a.s);
  4027. double bb = (b.x * b.x + b.y * b.y + b.z * b.z + b.s * b.s);
  4028. double aa_bb = aa * bb;
  4029. if (aa_bb == 0) return 0.0;
  4030. double ab = (a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s);
  4031. double quotient = (ab * ab) / aa_bb;
  4032. if (quotient >= 1.0) return 0.0;
  4033. return Math.Acos(2 * quotient - 1);
  4034. }
  4035. public LSL_String llGetInventoryKey(string name)
  4036. {
  4037. m_host.AddScriptLPS(1);
  4038. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  4039. if (item == null)
  4040. return UUID.Zero.ToString();
  4041. if ((item.CurrentPermissions
  4042. & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
  4043. == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
  4044. {
  4045. return item.AssetID.ToString();
  4046. }
  4047. return UUID.Zero.ToString();
  4048. }
  4049. public void llAllowInventoryDrop(int add)
  4050. {
  4051. m_host.AddScriptLPS(1);
  4052. if (add != 0)
  4053. m_host.ParentGroup.RootPart.AllowedDrop = true;
  4054. else
  4055. m_host.ParentGroup.RootPart.AllowedDrop = false;
  4056. // Update the object flags
  4057. m_host.ParentGroup.RootPart.aggregateScriptEvents();
  4058. }
  4059. public LSL_Vector llGetSunDirection()
  4060. {
  4061. m_host.AddScriptLPS(1);
  4062. LSL_Vector SunDoubleVector3;
  4063. Vector3 SunFloatVector3;
  4064. // sunPosition estate setting is set in OpenSim.Region.CoreModules.SunModule
  4065. // have to convert from Vector3 (float) to LSL_Vector (double)
  4066. SunFloatVector3 = World.RegionInfo.RegionSettings.SunVector;
  4067. SunDoubleVector3.x = (double)SunFloatVector3.X;
  4068. SunDoubleVector3.y = (double)SunFloatVector3.Y;
  4069. SunDoubleVector3.z = (double)SunFloatVector3.Z;
  4070. return SunDoubleVector3;
  4071. }
  4072. public LSL_Vector llGetTextureOffset(int face)
  4073. {
  4074. m_host.AddScriptLPS(1);
  4075. return GetTextureOffset(m_host, face);
  4076. }
  4077. protected LSL_Vector GetTextureOffset(SceneObjectPart part, int face)
  4078. {
  4079. Primitive.TextureEntry tex = part.Shape.Textures;
  4080. LSL_Vector offset = new LSL_Vector();
  4081. if (face == ScriptBaseClass.ALL_SIDES)
  4082. {
  4083. face = 0;
  4084. }
  4085. if (face >= 0 && face < GetNumberOfSides(part))
  4086. {
  4087. offset.x = tex.GetFace((uint)face).OffsetU;
  4088. offset.y = tex.GetFace((uint)face).OffsetV;
  4089. offset.z = 0.0;
  4090. return offset;
  4091. }
  4092. else
  4093. {
  4094. return offset;
  4095. }
  4096. }
  4097. public LSL_Vector llGetTextureScale(int side)
  4098. {
  4099. m_host.AddScriptLPS(1);
  4100. Primitive.TextureEntry tex = m_host.Shape.Textures;
  4101. LSL_Vector scale;
  4102. if (side == -1)
  4103. {
  4104. side = 0;
  4105. }
  4106. scale.x = tex.GetFace((uint)side).RepeatU;
  4107. scale.y = tex.GetFace((uint)side).RepeatV;
  4108. scale.z = 0.0;
  4109. return scale;
  4110. }
  4111. public LSL_Float llGetTextureRot(int face)
  4112. {
  4113. m_host.AddScriptLPS(1);
  4114. return GetTextureRot(m_host, face);
  4115. }
  4116. protected LSL_Float GetTextureRot(SceneObjectPart part, int face)
  4117. {
  4118. Primitive.TextureEntry tex = part.Shape.Textures;
  4119. if (face == -1)
  4120. {
  4121. face = 0;
  4122. }
  4123. if (face >= 0 && face < GetNumberOfSides(part))
  4124. {
  4125. return tex.GetFace((uint)face).Rotation;
  4126. }
  4127. else
  4128. {
  4129. return 0.0;
  4130. }
  4131. }
  4132. public LSL_Integer llSubStringIndex(string source, string pattern)
  4133. {
  4134. m_host.AddScriptLPS(1);
  4135. return source.IndexOf(pattern);
  4136. }
  4137. public LSL_String llGetOwnerKey(string id)
  4138. {
  4139. m_host.AddScriptLPS(1);
  4140. UUID key = new UUID();
  4141. if (UUID.TryParse(id, out key))
  4142. {
  4143. try
  4144. {
  4145. SceneObjectPart obj = World.GetSceneObjectPart(key);
  4146. if (obj == null)
  4147. return id; // the key is for an agent so just return the key
  4148. else
  4149. return obj.OwnerID.ToString();
  4150. }
  4151. catch (KeyNotFoundException)
  4152. {
  4153. return id; // The Object/Agent not in the region so just return the key
  4154. }
  4155. }
  4156. else
  4157. {
  4158. return UUID.Zero.ToString();
  4159. }
  4160. }
  4161. public LSL_Vector llGetCenterOfMass()
  4162. {
  4163. m_host.AddScriptLPS(1);
  4164. Vector3 center = m_host.GetCenterOfMass();
  4165. return new LSL_Vector(center.X,center.Y,center.Z);
  4166. }
  4167. public LSL_List llListSort(LSL_List src, int stride, int ascending)
  4168. {
  4169. m_host.AddScriptLPS(1);
  4170. if (stride <= 0)
  4171. {
  4172. stride = 1;
  4173. }
  4174. return src.Sort(stride, ascending);
  4175. }
  4176. public LSL_Integer llGetListLength(LSL_List src)
  4177. {
  4178. m_host.AddScriptLPS(1);
  4179. if (src == null)
  4180. {
  4181. return 0;
  4182. }
  4183. else
  4184. {
  4185. return src.Length;
  4186. }
  4187. }
  4188. public LSL_Integer llList2Integer(LSL_List src, int index)
  4189. {
  4190. m_host.AddScriptLPS(1);
  4191. if (index < 0)
  4192. {
  4193. index = src.Length + index;
  4194. }
  4195. if (index >= src.Length || index < 0)
  4196. {
  4197. return 0;
  4198. }
  4199. // Vectors & Rotations always return zero in SL, but
  4200. // keys don't always return zero, it seems to be a bit complex.
  4201. else if (src.Data[index] is LSL_Vector ||
  4202. src.Data[index] is LSL_Rotation)
  4203. {
  4204. return 0;
  4205. }
  4206. try
  4207. {
  4208. if (src.Data[index] is LSL_Integer)
  4209. return (LSL_Integer)src.Data[index];
  4210. else if (src.Data[index] is LSL_Float)
  4211. return Convert.ToInt32(((LSL_Float)src.Data[index]).value);
  4212. return new LSL_Integer(src.Data[index].ToString());
  4213. }
  4214. catch (FormatException)
  4215. {
  4216. return 0;
  4217. }
  4218. }
  4219. public LSL_Float llList2Float(LSL_List src, int index)
  4220. {
  4221. m_host.AddScriptLPS(1);
  4222. if (index < 0)
  4223. {
  4224. index = src.Length + index;
  4225. }
  4226. if (index >= src.Length || index < 0)
  4227. {
  4228. return 0.0;
  4229. }
  4230. // Vectors & Rotations always return zero in SL
  4231. else if (src.Data[index] is LSL_Vector ||
  4232. src.Data[index] is LSL_Rotation)
  4233. {
  4234. return 0;
  4235. }
  4236. // valid keys seem to get parsed as integers then converted to floats
  4237. else
  4238. {
  4239. UUID uuidt;
  4240. if (src.Data[index] is LSL_Key && UUID.TryParse(src.Data[index].ToString(), out uuidt))
  4241. {
  4242. return Convert.ToDouble(new LSL_Integer(src.Data[index].ToString()).value);
  4243. }
  4244. }
  4245. try
  4246. {
  4247. if (src.Data[index] is LSL_Integer)
  4248. return Convert.ToDouble(((LSL_Integer)src.Data[index]).value);
  4249. else if (src.Data[index] is LSL_Float)
  4250. return Convert.ToDouble(((LSL_Float)src.Data[index]).value);
  4251. else if (src.Data[index] is LSL_String)
  4252. return Convert.ToDouble(((LSL_String)src.Data[index]).m_string);
  4253. return Convert.ToDouble(src.Data[index]);
  4254. }
  4255. catch (FormatException)
  4256. {
  4257. return 0.0;
  4258. }
  4259. }
  4260. public LSL_String llList2String(LSL_List src, int index)
  4261. {
  4262. m_host.AddScriptLPS(1);
  4263. if (index < 0)
  4264. {
  4265. index = src.Length + index;
  4266. }
  4267. if (index >= src.Length || index < 0)
  4268. {
  4269. return String.Empty;
  4270. }
  4271. return src.Data[index].ToString();
  4272. }
  4273. public LSL_Key llList2Key(LSL_List src, int index)
  4274. {
  4275. m_host.AddScriptLPS(1);
  4276. if (index < 0)
  4277. {
  4278. index = src.Length + index;
  4279. }
  4280. if (index >= src.Length || index < 0)
  4281. {
  4282. return "";
  4283. }
  4284. // SL spits out an empty string for types other than key & string
  4285. // At the time of patching, LSL_Key is currently LSL_String,
  4286. // so the OR check may be a little redundant, but it's being done
  4287. // for completion and should LSL_Key ever be implemented
  4288. // as it's own struct
  4289. else if (!(src.Data[index] is LSL_String ||
  4290. src.Data[index] is LSL_Key))
  4291. {
  4292. return "";
  4293. }
  4294. return src.Data[index].ToString();
  4295. }
  4296. public LSL_Vector llList2Vector(LSL_List src, int index)
  4297. {
  4298. m_host.AddScriptLPS(1);
  4299. if (index < 0)
  4300. {
  4301. index = src.Length + index;
  4302. }
  4303. if (index >= src.Length || index < 0)
  4304. {
  4305. return new LSL_Vector(0, 0, 0);
  4306. }
  4307. if (src.Data[index].GetType() == typeof(LSL_Vector))
  4308. {
  4309. return (LSL_Vector)src.Data[index];
  4310. }
  4311. // SL spits always out ZERO_VECTOR for anything other than
  4312. // strings or vectors. Although keys always return ZERO_VECTOR,
  4313. // it is currently difficult to make the distinction between
  4314. // a string, a key as string and a string that by coincidence
  4315. // is a string, so we're going to leave that up to the
  4316. // LSL_Vector constructor.
  4317. else if (!(src.Data[index] is LSL_String ||
  4318. src.Data[index] is LSL_Vector))
  4319. {
  4320. return new LSL_Vector(0, 0, 0);
  4321. }
  4322. else
  4323. {
  4324. return new LSL_Vector(src.Data[index].ToString());
  4325. }
  4326. }
  4327. public LSL_Rotation llList2Rot(LSL_List src, int index)
  4328. {
  4329. m_host.AddScriptLPS(1);
  4330. if (index < 0)
  4331. {
  4332. index = src.Length + index;
  4333. }
  4334. if (index >= src.Length || index < 0)
  4335. {
  4336. return new LSL_Rotation(0, 0, 0, 1);
  4337. }
  4338. // SL spits always out ZERO_ROTATION for anything other than
  4339. // strings or vectors. Although keys always return ZERO_ROTATION,
  4340. // it is currently difficult to make the distinction between
  4341. // a string, a key as string and a string that by coincidence
  4342. // is a string, so we're going to leave that up to the
  4343. // LSL_Rotation constructor.
  4344. else if (!(src.Data[index] is LSL_String ||
  4345. src.Data[index] is LSL_Rotation))
  4346. {
  4347. return new LSL_Rotation(0, 0, 0, 1);
  4348. }
  4349. else if (src.Data[index].GetType() == typeof(LSL_Rotation))
  4350. {
  4351. return (LSL_Rotation)src.Data[index];
  4352. }
  4353. else
  4354. {
  4355. return new LSL_Rotation(src.Data[index].ToString());
  4356. }
  4357. }
  4358. public LSL_List llList2List(LSL_List src, int start, int end)
  4359. {
  4360. m_host.AddScriptLPS(1);
  4361. return src.GetSublist(start, end);
  4362. }
  4363. public LSL_List llDeleteSubList(LSL_List src, int start, int end)
  4364. {
  4365. return src.DeleteSublist(start, end);
  4366. }
  4367. public LSL_Integer llGetListEntryType(LSL_List src, int index)
  4368. {
  4369. m_host.AddScriptLPS(1);
  4370. if (index < 0)
  4371. {
  4372. index = src.Length + index;
  4373. }
  4374. if (index >= src.Length)
  4375. {
  4376. return 0;
  4377. }
  4378. if (src.Data[index] is LSL_Integer || src.Data[index] is Int32)
  4379. return 1;
  4380. if (src.Data[index] is LSL_Float || src.Data[index] is Single || src.Data[index] is Double)
  4381. return 2;
  4382. if (src.Data[index] is LSL_String || src.Data[index] is String)
  4383. {
  4384. UUID tuuid;
  4385. if (UUID.TryParse(src.Data[index].ToString(), out tuuid))
  4386. {
  4387. return 4;
  4388. }
  4389. else
  4390. {
  4391. return 3;
  4392. }
  4393. }
  4394. if (src.Data[index] is LSL_Vector)
  4395. return 5;
  4396. if (src.Data[index] is LSL_Rotation)
  4397. return 6;
  4398. if (src.Data[index] is LSL_List)
  4399. return 7;
  4400. return 0;
  4401. }
  4402. /// <summary>
  4403. /// Process the supplied list and return the
  4404. /// content of the list formatted as a comma
  4405. /// separated list. There is a space after
  4406. /// each comma.
  4407. /// </summary>
  4408. public LSL_String llList2CSV(LSL_List src)
  4409. {
  4410. m_host.AddScriptLPS(1);
  4411. return string.Join(", ",
  4412. (new List<object>(src.Data)).ConvertAll<string>(o =>
  4413. {
  4414. return o.ToString();
  4415. }).ToArray());
  4416. }
  4417. /// <summary>
  4418. /// The supplied string is scanned for commas
  4419. /// and converted into a list. Commas are only
  4420. /// effective if they are encountered outside
  4421. /// of '<' '>' delimiters. Any whitespace
  4422. /// before or after an element is trimmed.
  4423. /// </summary>
  4424. public LSL_List llCSV2List(string src)
  4425. {
  4426. LSL_List result = new LSL_List();
  4427. int parens = 0;
  4428. int start = 0;
  4429. int length = 0;
  4430. m_host.AddScriptLPS(1);
  4431. for (int i = 0; i < src.Length; i++)
  4432. {
  4433. switch (src[i])
  4434. {
  4435. case '<':
  4436. parens++;
  4437. length++;
  4438. break;
  4439. case '>':
  4440. if (parens > 0)
  4441. parens--;
  4442. length++;
  4443. break;
  4444. case ',':
  4445. if (parens == 0)
  4446. {
  4447. result.Add(new LSL_String(src.Substring(start,length).Trim()));
  4448. start += length+1;
  4449. length = 0;
  4450. }
  4451. else
  4452. {
  4453. length++;
  4454. }
  4455. break;
  4456. default:
  4457. length++;
  4458. break;
  4459. }
  4460. }
  4461. result.Add(new LSL_String(src.Substring(start,length).Trim()));
  4462. return result;
  4463. }
  4464. /// <summary>
  4465. /// Randomizes the list, be arbitrarily reordering
  4466. /// sublists of stride elements. As the stride approaches
  4467. /// the size of the list, the options become very
  4468. /// limited.
  4469. /// </summary>
  4470. /// <remarks>
  4471. /// This could take a while for very large list
  4472. /// sizes.
  4473. /// </remarks>
  4474. public LSL_List llListRandomize(LSL_List src, int stride)
  4475. {
  4476. LSL_List result;
  4477. Random rand = new Random();
  4478. int chunkk;
  4479. int[] chunks;
  4480. m_host.AddScriptLPS(1);
  4481. if (stride <= 0)
  4482. {
  4483. stride = 1;
  4484. }
  4485. // Stride MUST be a factor of the list length
  4486. // If not, then return the src list. This also
  4487. // traps those cases where stride > length.
  4488. if (src.Length != stride && src.Length%stride == 0)
  4489. {
  4490. chunkk = src.Length/stride;
  4491. chunks = new int[chunkk];
  4492. for (int i = 0; i < chunkk; i++)
  4493. chunks[i] = i;
  4494. // Knuth shuffle the chunkk index
  4495. for (int i = chunkk - 1; i >= 1; i--)
  4496. {
  4497. // Elect an unrandomized chunk to swap
  4498. int index = rand.Next(i + 1);
  4499. int tmp;
  4500. // and swap position with first unrandomized chunk
  4501. tmp = chunks[i];
  4502. chunks[i] = chunks[index];
  4503. chunks[index] = tmp;
  4504. }
  4505. // Construct the randomized list
  4506. result = new LSL_List();
  4507. for (int i = 0; i < chunkk; i++)
  4508. {
  4509. for (int j = 0; j < stride; j++)
  4510. {
  4511. result.Add(src.Data[chunks[i]*stride+j]);
  4512. }
  4513. }
  4514. }
  4515. else {
  4516. object[] array = new object[src.Length];
  4517. Array.Copy(src.Data, 0, array, 0, src.Length);
  4518. result = new LSL_List(array);
  4519. }
  4520. return result;
  4521. }
  4522. /// <summary>
  4523. /// Elements in the source list starting with 0 and then
  4524. /// every i+stride. If the stride is negative then the scan
  4525. /// is backwards producing an inverted result.
  4526. /// Only those elements that are also in the specified
  4527. /// range are included in the result.
  4528. /// </summary>
  4529. public LSL_List llList2ListStrided(LSL_List src, int start, int end, int stride)
  4530. {
  4531. LSL_List result = new LSL_List();
  4532. int[] si = new int[2];
  4533. int[] ei = new int[2];
  4534. bool twopass = false;
  4535. m_host.AddScriptLPS(1);
  4536. // First step is always to deal with negative indices
  4537. if (start < 0)
  4538. start = src.Length+start;
  4539. if (end < 0)
  4540. end = src.Length+end;
  4541. // Out of bounds indices are OK, just trim them
  4542. // accordingly
  4543. if (start > src.Length)
  4544. start = src.Length;
  4545. if (end > src.Length)
  4546. end = src.Length;
  4547. if (stride == 0)
  4548. stride = 1;
  4549. // There may be one or two ranges to be considered
  4550. if (start != end)
  4551. {
  4552. if (start <= end)
  4553. {
  4554. si[0] = start;
  4555. ei[0] = end;
  4556. }
  4557. else
  4558. {
  4559. si[1] = start;
  4560. ei[1] = src.Length;
  4561. si[0] = 0;
  4562. ei[0] = end;
  4563. twopass = true;
  4564. }
  4565. // The scan always starts from the beginning of the
  4566. // source list, but members are only selected if they
  4567. // fall within the specified sub-range. The specified
  4568. // range values are inclusive.
  4569. // A negative stride reverses the direction of the
  4570. // scan producing an inverted list as a result.
  4571. if (stride > 0)
  4572. {
  4573. for (int i = 0; i < src.Length; i += stride)
  4574. {
  4575. if (i<=ei[0] && i>=si[0])
  4576. result.Add(src.Data[i]);
  4577. if (twopass && i>=si[1] && i<=ei[1])
  4578. result.Add(src.Data[i]);
  4579. }
  4580. }
  4581. else if (stride < 0)
  4582. {
  4583. for (int i = src.Length - 1; i >= 0; i += stride)
  4584. {
  4585. if (i <= ei[0] && i >= si[0])
  4586. result.Add(src.Data[i]);
  4587. if (twopass && i >= si[1] && i <= ei[1])
  4588. result.Add(src.Data[i]);
  4589. }
  4590. }
  4591. }
  4592. else
  4593. {
  4594. if (start%stride == 0)
  4595. {
  4596. result.Add(src.Data[start]);
  4597. }
  4598. }
  4599. return result;
  4600. }
  4601. public LSL_Integer llGetRegionAgentCount()
  4602. {
  4603. m_host.AddScriptLPS(1);
  4604. return new LSL_Integer(World.GetRootAgentCount());
  4605. }
  4606. public LSL_Vector llGetRegionCorner()
  4607. {
  4608. m_host.AddScriptLPS(1);
  4609. return new LSL_Vector(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
  4610. }
  4611. /// <summary>
  4612. /// Insert the list identified by <paramref name="src"/> into the
  4613. /// list designated by <paramref name="dest"/> such that the first
  4614. /// new element has the index specified by <paramref name="index"/>
  4615. /// </summary>
  4616. public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
  4617. {
  4618. LSL_List pref = null;
  4619. LSL_List suff = null;
  4620. m_host.AddScriptLPS(1);
  4621. if (index < 0)
  4622. {
  4623. index = index+dest.Length;
  4624. if (index < 0)
  4625. {
  4626. index = 0;
  4627. }
  4628. }
  4629. if (index != 0)
  4630. {
  4631. pref = dest.GetSublist(0,index-1);
  4632. if (index < dest.Length)
  4633. {
  4634. suff = dest.GetSublist(index,-1);
  4635. return pref + src + suff;
  4636. }
  4637. else
  4638. {
  4639. return pref + src;
  4640. }
  4641. }
  4642. else
  4643. {
  4644. if (index < dest.Length)
  4645. {
  4646. suff = dest.GetSublist(index,-1);
  4647. return src + suff;
  4648. }
  4649. else
  4650. {
  4651. return src;
  4652. }
  4653. }
  4654. }
  4655. /// <summary>
  4656. /// Returns the index of the first occurrence of test
  4657. /// in src.
  4658. /// </summary>
  4659. /// <param name="src">Source list</param>
  4660. /// <param name="test">List to search for</param>
  4661. /// <returns>
  4662. /// The index number of the point in src where test was found if it was found.
  4663. /// Otherwise returns -1
  4664. /// </returns>
  4665. public LSL_Integer llListFindList(LSL_List src, LSL_List test)
  4666. {
  4667. int index = -1;
  4668. int length = src.Length - test.Length + 1;
  4669. m_host.AddScriptLPS(1);
  4670. // If either list is empty, do not match
  4671. if (src.Length != 0 && test.Length != 0)
  4672. {
  4673. for (int i = 0; i < length; i++)
  4674. {
  4675. // Why this piece of insanity? This is because most script constants are C# value types (e.g. int)
  4676. // rather than wrapped LSL types. Such a script constant does not have int.Equal(LSL_Integer) code
  4677. // and so the comparison fails even if the LSL_Integer conceptually has the same value.
  4678. // Therefore, here we test Equals on both the source and destination objects.
  4679. // However, a future better approach may be use LSL struct script constants (e.g. LSL_Integer(1)).
  4680. if (src.Data[i].Equals(test.Data[0]) || test.Data[0].Equals(src.Data[i]))
  4681. {
  4682. int j;
  4683. for (j = 1; j < test.Length; j++)
  4684. if (!(src.Data[i+j].Equals(test.Data[j]) || test.Data[j].Equals(src.Data[i+j])))
  4685. break;
  4686. if (j == test.Length)
  4687. {
  4688. index = i;
  4689. break;
  4690. }
  4691. }
  4692. }
  4693. }
  4694. return index;
  4695. }
  4696. public LSL_String llGetObjectName()
  4697. {
  4698. m_host.AddScriptLPS(1);
  4699. return m_host.Name !=null ? m_host.Name : String.Empty;
  4700. }
  4701. public void llSetObjectName(string name)
  4702. {
  4703. m_host.AddScriptLPS(1);
  4704. m_host.Name = name != null ? name : String.Empty;
  4705. }
  4706. public LSL_String llGetDate()
  4707. {
  4708. m_host.AddScriptLPS(1);
  4709. DateTime date = DateTime.Now.ToUniversalTime();
  4710. string result = date.ToString("yyyy-MM-dd");
  4711. return result;
  4712. }
  4713. public LSL_Integer llEdgeOfWorld(LSL_Vector pos, LSL_Vector dir)
  4714. {
  4715. m_host.AddScriptLPS(1);
  4716. // edge will be used to pass the Region Coordinates offset
  4717. // we want to check for a neighboring sim
  4718. LSL_Vector edge = new LSL_Vector(0, 0, 0);
  4719. if (dir.x == 0)
  4720. {
  4721. if (dir.y == 0)
  4722. {
  4723. // Direction vector is 0,0 so return
  4724. // false since we're staying in the sim
  4725. return 0;
  4726. }
  4727. else
  4728. {
  4729. // Y is the only valid direction
  4730. edge.y = dir.y / Math.Abs(dir.y);
  4731. }
  4732. }
  4733. else
  4734. {
  4735. LSL_Float mag;
  4736. if (dir.x > 0)
  4737. {
  4738. mag = (Constants.RegionSize - pos.x) / dir.x;
  4739. }
  4740. else
  4741. {
  4742. mag = (pos.x/dir.x);
  4743. }
  4744. mag = Math.Abs(mag);
  4745. edge.y = pos.y + (dir.y * mag);
  4746. if (edge.y > Constants.RegionSize || edge.y < 0)
  4747. {
  4748. // Y goes out of bounds first
  4749. edge.y = dir.y / Math.Abs(dir.y);
  4750. }
  4751. else
  4752. {
  4753. // X goes out of bounds first or its a corner exit
  4754. edge.y = 0;
  4755. edge.x = dir.x / Math.Abs(dir.x);
  4756. }
  4757. }
  4758. List<GridRegion> neighbors = World.GridService.GetNeighbours(World.RegionInfo.ScopeID, World.RegionInfo.RegionID);
  4759. uint neighborX = World.RegionInfo.RegionLocX + (uint)dir.x;
  4760. uint neighborY = World.RegionInfo.RegionLocY + (uint)dir.y;
  4761. foreach (GridRegion sri in neighbors)
  4762. {
  4763. if (sri.RegionCoordX == neighborX && sri.RegionCoordY == neighborY)
  4764. return 0;
  4765. }
  4766. return 1;
  4767. }
  4768. /// <summary>
  4769. /// Not fully implemented yet. Still to do:-
  4770. /// AGENT_BUSY
  4771. /// Remove as they are done
  4772. /// </summary>
  4773. public LSL_Integer llGetAgentInfo(string id)
  4774. {
  4775. m_host.AddScriptLPS(1);
  4776. UUID key = new UUID();
  4777. if (!UUID.TryParse(id, out key))
  4778. {
  4779. return 0;
  4780. }
  4781. int flags = 0;
  4782. ScenePresence agent = World.GetScenePresence(key);
  4783. if (agent == null)
  4784. {
  4785. return 0;
  4786. }
  4787. if (agent.IsChildAgent)
  4788. return 0; // Fail if they are not in the same region
  4789. // note: in OpenSim, sitting seems to cancel AGENT_ALWAYS_RUN, unlike SL
  4790. if (agent.SetAlwaysRun)
  4791. {
  4792. flags |= ScriptBaseClass.AGENT_ALWAYS_RUN;
  4793. }
  4794. if (agent.HasAttachments())
  4795. {
  4796. flags |= ScriptBaseClass.AGENT_ATTACHMENTS;
  4797. if (agent.HasScriptedAttachments())
  4798. flags |= ScriptBaseClass.AGENT_SCRIPTED;
  4799. }
  4800. if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0)
  4801. {
  4802. flags |= ScriptBaseClass.AGENT_FLYING;
  4803. flags |= ScriptBaseClass.AGENT_IN_AIR; // flying always implies in-air, even if colliding with e.g. a wall
  4804. }
  4805. if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AWAY) != 0)
  4806. {
  4807. flags |= ScriptBaseClass.AGENT_AWAY;
  4808. }
  4809. // seems to get unset, even if in mouselook, when avatar is sitting on a prim???
  4810. if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
  4811. {
  4812. flags |= ScriptBaseClass.AGENT_MOUSELOOK;
  4813. }
  4814. if ((agent.State & (byte)AgentState.Typing) != (byte)0)
  4815. {
  4816. flags |= ScriptBaseClass.AGENT_TYPING;
  4817. }
  4818. string agentMovementAnimation = agent.Animator.CurrentMovementAnimation;
  4819. if (agentMovementAnimation == "CROUCH")
  4820. {
  4821. flags |= ScriptBaseClass.AGENT_CROUCHING;
  4822. }
  4823. if (agentMovementAnimation == "WALK" || agentMovementAnimation == "CROUCHWALK")
  4824. {
  4825. flags |= ScriptBaseClass.AGENT_WALKING;
  4826. }
  4827. // not colliding implies in air. Note: flying also implies in-air, even if colliding (see above)
  4828. // note: AGENT_IN_AIR and AGENT_WALKING seem to be mutually exclusive states in SL.
  4829. // note: this may need some tweaking when walking downhill. you "fall down" for a brief instant
  4830. // and don't collide when walking downhill, which instantly registers as in-air, briefly. should
  4831. // there be some minimum non-collision threshold time before claiming the avatar is in-air?
  4832. if ((flags & ScriptBaseClass.AGENT_WALKING) == 0 && !agent.IsColliding )
  4833. {
  4834. flags |= ScriptBaseClass.AGENT_IN_AIR;
  4835. }
  4836. if (agent.ParentPart != null)
  4837. {
  4838. flags |= ScriptBaseClass.AGENT_ON_OBJECT;
  4839. flags |= ScriptBaseClass.AGENT_SITTING;
  4840. }
  4841. if (agent.Animator.Animations.ImplicitDefaultAnimation.AnimID
  4842. == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
  4843. {
  4844. flags |= ScriptBaseClass.AGENT_SITTING;
  4845. }
  4846. return flags;
  4847. }
  4848. public LSL_String llGetAgentLanguage(string id)
  4849. {
  4850. // This should only return a value if the avatar is in the same region
  4851. //ckrinke 1-30-09 : This needs to parse the XMLRPC language field supplied
  4852. //by the client at login. Currently returning only en-us until our I18N
  4853. //effort gains momentum
  4854. m_host.AddScriptLPS(1);
  4855. return "en-us";
  4856. }
  4857. /// <summary>
  4858. /// http://wiki.secondlife.com/wiki/LlGetAgentList
  4859. /// The list of options is currently not used in SL
  4860. /// scope is one of:-
  4861. /// AGENT_LIST_REGION - all in the region
  4862. /// AGENT_LIST_PARCEL - all in the same parcel as the scripted object
  4863. /// AGENT_LIST_PARCEL_OWNER - all in any parcel owned by the owner of the
  4864. /// current parcel.
  4865. /// </summary>
  4866. public LSL_List llGetAgentList(LSL_Integer scope, LSL_List options)
  4867. {
  4868. m_host.AddScriptLPS(1);
  4869. // the constants are 1, 2 and 4 so bits are being set, but you
  4870. // get an error "INVALID_SCOPE" if it is anything but 1, 2 and 4
  4871. bool regionWide = scope == ScriptBaseClass.AGENT_LIST_REGION;
  4872. bool parcelOwned = scope == ScriptBaseClass.AGENT_LIST_PARCEL_OWNER;
  4873. bool parcel = scope == ScriptBaseClass.AGENT_LIST_PARCEL;
  4874. LSL_List result = new LSL_List();
  4875. if (!regionWide && !parcelOwned && !parcel)
  4876. {
  4877. result.Add("INVALID_SCOPE");
  4878. return result;
  4879. }
  4880. ILandObject land;
  4881. Vector3 pos;
  4882. UUID id = UUID.Zero;
  4883. if (parcel || parcelOwned)
  4884. {
  4885. pos = m_host.ParentGroup.RootPart.GetWorldPosition();
  4886. land = World.LandChannel.GetLandObject(pos.X, pos.Y);
  4887. if (land == null)
  4888. {
  4889. id = UUID.Zero;
  4890. }
  4891. else
  4892. {
  4893. if (parcelOwned)
  4894. {
  4895. id = land.LandData.OwnerID;
  4896. }
  4897. else
  4898. {
  4899. id = land.LandData.GlobalID;
  4900. }
  4901. }
  4902. }
  4903. World.ForEachRootScenePresence(
  4904. delegate (ScenePresence ssp)
  4905. {
  4906. // Gods are not listed in SL
  4907. if (!ssp.IsDeleted && ssp.GodLevel == 0.0 && !ssp.IsChildAgent)
  4908. {
  4909. if (!regionWide)
  4910. {
  4911. pos = ssp.AbsolutePosition;
  4912. land = World.LandChannel.GetLandObject(pos.X, pos.Y);
  4913. if (land != null)
  4914. {
  4915. if (parcelOwned && land.LandData.OwnerID == id ||
  4916. parcel && land.LandData.GlobalID == id)
  4917. {
  4918. result.Add(new LSL_Key(ssp.UUID.ToString()));
  4919. }
  4920. }
  4921. }
  4922. else
  4923. {
  4924. result.Add(new LSL_Key(ssp.UUID.ToString()));
  4925. }
  4926. }
  4927. // Maximum of 100 results
  4928. if (result.Length > 99)
  4929. {
  4930. return;
  4931. }
  4932. }
  4933. );
  4934. return result;
  4935. }
  4936. public void llAdjustSoundVolume(double volume)
  4937. {
  4938. m_host.AddScriptLPS(1);
  4939. m_host.AdjustSoundGain(volume);
  4940. ScriptSleep(100);
  4941. }
  4942. public void llSetSoundRadius(double radius)
  4943. {
  4944. m_host.AddScriptLPS(1);
  4945. m_host.SoundRadius = radius;
  4946. }
  4947. public LSL_String llKey2Name(string id)
  4948. {
  4949. m_host.AddScriptLPS(1);
  4950. UUID key = new UUID();
  4951. if (UUID.TryParse(id,out key))
  4952. {
  4953. ScenePresence presence = World.GetScenePresence(key);
  4954. if (presence != null)
  4955. {
  4956. return presence.ControllingClient.Name;
  4957. //return presence.Name;
  4958. }
  4959. if (World.GetSceneObjectPart(key) != null)
  4960. {
  4961. return World.GetSceneObjectPart(key).Name;
  4962. }
  4963. }
  4964. return String.Empty;
  4965. }
  4966. public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
  4967. {
  4968. m_host.AddScriptLPS(1);
  4969. SetTextureAnim(m_host, mode, face, sizex, sizey, start, length, rate);
  4970. }
  4971. public void llSetLinkTextureAnim(int linknumber, int mode, int face, int sizex, int sizey, double start, double length, double rate)
  4972. {
  4973. m_host.AddScriptLPS(1);
  4974. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  4975. foreach (SceneObjectPart part in parts)
  4976. {
  4977. SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
  4978. }
  4979. }
  4980. private void SetTextureAnim(SceneObjectPart part, int mode, int face, int sizex, int sizey, double start, double length, double rate)
  4981. {
  4982. Primitive.TextureAnimation pTexAnim = new Primitive.TextureAnimation();
  4983. pTexAnim.Flags = (Primitive.TextureAnimMode)mode;
  4984. //ALL_SIDES
  4985. if (face == ScriptBaseClass.ALL_SIDES)
  4986. face = 255;
  4987. pTexAnim.Face = (uint)face;
  4988. pTexAnim.Length = (float)length;
  4989. pTexAnim.Rate = (float)rate;
  4990. pTexAnim.SizeX = (uint)sizex;
  4991. pTexAnim.SizeY = (uint)sizey;
  4992. pTexAnim.Start = (float)start;
  4993. part.AddTextureAnimation(pTexAnim);
  4994. part.SendFullUpdateToAllClients();
  4995. part.ParentGroup.HasGroupChanged = true;
  4996. }
  4997. public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east,
  4998. LSL_Vector bottom_south_west)
  4999. {
  5000. m_host.AddScriptLPS(1);
  5001. if (m_SoundModule != null)
  5002. {
  5003. m_SoundModule.TriggerSoundLimited(m_host.UUID,
  5004. ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume,
  5005. bottom_south_west, top_north_east);
  5006. }
  5007. }
  5008. public void llEjectFromLand(string pest)
  5009. {
  5010. m_host.AddScriptLPS(1);
  5011. UUID agentID = new UUID();
  5012. if (UUID.TryParse(pest, out agentID))
  5013. {
  5014. ScenePresence presence = World.GetScenePresence(agentID);
  5015. if (presence != null)
  5016. {
  5017. // agent must be over the owners land
  5018. ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
  5019. if (land == null)
  5020. return;
  5021. if (m_host.OwnerID == land.LandData.OwnerID)
  5022. {
  5023. World.TeleportClientHome(agentID, presence.ControllingClient);
  5024. }
  5025. }
  5026. }
  5027. ScriptSleep(5000);
  5028. }
  5029. public LSL_Integer llOverMyLand(string id)
  5030. {
  5031. m_host.AddScriptLPS(1);
  5032. UUID key = new UUID();
  5033. if (UUID.TryParse(id, out key))
  5034. {
  5035. ScenePresence presence = World.GetScenePresence(key);
  5036. if (presence != null) // object is an avatar
  5037. {
  5038. if (m_host.OwnerID
  5039. == World.LandChannel.GetLandObject(
  5040. presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
  5041. return 1;
  5042. }
  5043. else // object is not an avatar
  5044. {
  5045. SceneObjectPart obj = World.GetSceneObjectPart(key);
  5046. if (obj != null)
  5047. if (m_host.OwnerID
  5048. == World.LandChannel.GetLandObject(
  5049. obj.AbsolutePosition.X, obj.AbsolutePosition.Y).LandData.OwnerID)
  5050. return 1;
  5051. }
  5052. }
  5053. return 0;
  5054. }
  5055. public LSL_String llGetLandOwnerAt(LSL_Vector pos)
  5056. {
  5057. m_host.AddScriptLPS(1);
  5058. ILandObject land = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
  5059. if (land == null)
  5060. return UUID.Zero.ToString();
  5061. return land.LandData.OwnerID.ToString();
  5062. }
  5063. /// <summary>
  5064. /// According to http://lslwiki.net/lslwiki/wakka.php?wakka=llGetAgentSize
  5065. /// only the height of avatars vary and that says:
  5066. /// Width (x) and depth (y) are constant. (0.45m and 0.6m respectively).
  5067. /// </summary>
  5068. public LSL_Vector llGetAgentSize(string id)
  5069. {
  5070. m_host.AddScriptLPS(1);
  5071. ScenePresence avatar = World.GetScenePresence((UUID)id);
  5072. LSL_Vector agentSize;
  5073. if (avatar == null || avatar.IsChildAgent) // Fail if not in the same region
  5074. {
  5075. agentSize = ScriptBaseClass.ZERO_VECTOR;
  5076. }
  5077. else
  5078. {
  5079. agentSize = new LSL_Vector(0.45, 0.6, avatar.Appearance.AvatarHeight);
  5080. }
  5081. return agentSize;
  5082. }
  5083. public LSL_Integer llSameGroup(string agent)
  5084. {
  5085. m_host.AddScriptLPS(1);
  5086. UUID agentId = new UUID();
  5087. if (!UUID.TryParse(agent, out agentId))
  5088. return new LSL_Integer(0);
  5089. ScenePresence presence = World.GetScenePresence(agentId);
  5090. if (presence == null || presence.IsChildAgent) // Return flase for child agents
  5091. return new LSL_Integer(0);
  5092. IClientAPI client = presence.ControllingClient;
  5093. if (m_host.GroupID == client.ActiveGroupId)
  5094. return new LSL_Integer(1);
  5095. else
  5096. return new LSL_Integer(0);
  5097. }
  5098. public void llUnSit(string id)
  5099. {
  5100. m_host.AddScriptLPS(1);
  5101. UUID key = new UUID();
  5102. if (UUID.TryParse(id, out key))
  5103. {
  5104. ScenePresence av = World.GetScenePresence(key);
  5105. if (av != null)
  5106. {
  5107. if (llAvatarOnSitTarget() == id)
  5108. {
  5109. // if the avatar is sitting on this object, then
  5110. // we can unsit them. We don't want random scripts unsitting random people
  5111. // Lets avoid the popcorn avatar scenario.
  5112. av.StandUp();
  5113. }
  5114. else
  5115. {
  5116. // If the object owner also owns the parcel
  5117. // or
  5118. // if the land is group owned and the object is group owned by the same group
  5119. // or
  5120. // if the object is owned by a person with estate access.
  5121. ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
  5122. if (parcel != null)
  5123. {
  5124. if (m_host.OwnerID == parcel.LandData.OwnerID ||
  5125. (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.LandData.GroupID
  5126. && parcel.LandData.IsGroupOwned) || World.Permissions.IsGod(m_host.OwnerID))
  5127. {
  5128. av.StandUp();
  5129. }
  5130. }
  5131. }
  5132. }
  5133. }
  5134. }
  5135. public LSL_Vector llGroundSlope(LSL_Vector offset)
  5136. {
  5137. m_host.AddScriptLPS(1);
  5138. //Get the slope normal. This gives us the equation of the plane tangent to the slope.
  5139. LSL_Vector vsn = llGroundNormal(offset);
  5140. //Plug the x,y coordinates of the slope normal into the equation of the plane to get
  5141. //the height of that point on the plane. The resulting vector gives the slope.
  5142. Vector3 vsl = vsn;
  5143. vsl.Z = (float)(((vsn.x * vsn.x) + (vsn.y * vsn.y)) / (-1 * vsn.z));
  5144. vsl.Normalize();
  5145. //Normalization might be overkill here
  5146. return new LSL_Vector(vsl.X, vsl.Y, vsl.Z);
  5147. }
  5148. public LSL_Vector llGroundNormal(LSL_Vector offset)
  5149. {
  5150. m_host.AddScriptLPS(1);
  5151. Vector3 pos = m_host.GetWorldPosition() + (Vector3)offset;
  5152. // Clamp to valid position
  5153. if (pos.X < 0)
  5154. pos.X = 0;
  5155. else if (pos.X >= World.Heightmap.Width)
  5156. pos.X = World.Heightmap.Width - 1;
  5157. if (pos.Y < 0)
  5158. pos.Y = 0;
  5159. else if (pos.Y >= World.Heightmap.Height)
  5160. pos.Y = World.Heightmap.Height - 1;
  5161. //Find two points in addition to the position to define a plane
  5162. Vector3 p0 = new Vector3(pos.X, pos.Y,
  5163. (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
  5164. Vector3 p1 = new Vector3();
  5165. Vector3 p2 = new Vector3();
  5166. if ((pos.X + 1.0f) >= World.Heightmap.Width)
  5167. p1 = new Vector3(pos.X + 1.0f, pos.Y,
  5168. (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
  5169. else
  5170. p1 = new Vector3(pos.X + 1.0f, pos.Y,
  5171. (float)World.Heightmap[(int)(pos.X + 1.0f), (int)pos.Y]);
  5172. if ((pos.Y + 1.0f) >= World.Heightmap.Height)
  5173. p2 = new Vector3(pos.X, pos.Y + 1.0f,
  5174. (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
  5175. else
  5176. p2 = new Vector3(pos.X, pos.Y + 1.0f,
  5177. (float)World.Heightmap[(int)pos.X, (int)(pos.Y + 1.0f)]);
  5178. //Find normalized vectors from p0 to p1 and p0 to p2
  5179. Vector3 v0 = new Vector3(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
  5180. Vector3 v1 = new Vector3(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
  5181. v0.Normalize();
  5182. v1.Normalize();
  5183. //Find the cross product of the vectors (the slope normal).
  5184. Vector3 vsn = new Vector3();
  5185. vsn.X = (v0.Y * v1.Z) - (v0.Z * v1.Y);
  5186. vsn.Y = (v0.Z * v1.X) - (v0.X * v1.Z);
  5187. vsn.Z = (v0.X * v1.Y) - (v0.Y * v1.X);
  5188. vsn.Normalize();
  5189. //I believe the crossproduct of two normalized vectors is a normalized vector so
  5190. //this normalization may be overkill
  5191. return new LSL_Vector(vsn.X, vsn.Y, vsn.Z);
  5192. }
  5193. public LSL_Vector llGroundContour(LSL_Vector offset)
  5194. {
  5195. m_host.AddScriptLPS(1);
  5196. LSL_Vector x = llGroundSlope(offset);
  5197. return new LSL_Vector(-x.y, x.x, 0.0);
  5198. }
  5199. public LSL_Integer llGetAttached()
  5200. {
  5201. m_host.AddScriptLPS(1);
  5202. return m_host.ParentGroup.AttachmentPoint;
  5203. }
  5204. public LSL_Integer llGetFreeMemory()
  5205. {
  5206. m_host.AddScriptLPS(1);
  5207. // Make scripts designed for LSO happy
  5208. return 16384;
  5209. }
  5210. public LSL_Integer llGetFreeURLs()
  5211. {
  5212. m_host.AddScriptLPS(1);
  5213. if (m_UrlModule != null)
  5214. return new LSL_Integer(m_UrlModule.GetFreeUrls());
  5215. return new LSL_Integer(0);
  5216. }
  5217. public LSL_String llGetRegionName()
  5218. {
  5219. m_host.AddScriptLPS(1);
  5220. return World.RegionInfo.RegionName;
  5221. }
  5222. public LSL_Float llGetRegionTimeDilation()
  5223. {
  5224. m_host.AddScriptLPS(1);
  5225. return (double)World.TimeDilation;
  5226. }
  5227. /// <summary>
  5228. /// Returns the value reported in the client Statistics window
  5229. /// </summary>
  5230. public LSL_Float llGetRegionFPS()
  5231. {
  5232. m_host.AddScriptLPS(1);
  5233. return World.StatsReporter.LastReportedSimFPS;
  5234. }
  5235. /* particle system rules should be coming into this routine as doubles, that is
  5236. rule[0] should be an integer from this list and rule[1] should be the arg
  5237. for the same integer. wiki.secondlife.com has most of this mapping, but some
  5238. came from http://www.caligari-designs.com/p4u2
  5239. We iterate through the list for 'Count' elements, incrementing by two for each
  5240. iteration and set the members of Primitive.ParticleSystem, one at a time.
  5241. */
  5242. public enum PrimitiveRule : int
  5243. {
  5244. PSYS_PART_FLAGS = 0,
  5245. PSYS_PART_START_COLOR = 1,
  5246. PSYS_PART_START_ALPHA = 2,
  5247. PSYS_PART_END_COLOR = 3,
  5248. PSYS_PART_END_ALPHA = 4,
  5249. PSYS_PART_START_SCALE = 5,
  5250. PSYS_PART_END_SCALE = 6,
  5251. PSYS_PART_MAX_AGE = 7,
  5252. PSYS_SRC_ACCEL = 8,
  5253. PSYS_SRC_PATTERN = 9,
  5254. PSYS_SRC_INNERANGLE = 10,
  5255. PSYS_SRC_OUTERANGLE = 11,
  5256. PSYS_SRC_TEXTURE = 12,
  5257. PSYS_SRC_BURST_RATE = 13,
  5258. PSYS_SRC_BURST_PART_COUNT = 15,
  5259. PSYS_SRC_BURST_RADIUS = 16,
  5260. PSYS_SRC_BURST_SPEED_MIN = 17,
  5261. PSYS_SRC_BURST_SPEED_MAX = 18,
  5262. PSYS_SRC_MAX_AGE = 19,
  5263. PSYS_SRC_TARGET_KEY = 20,
  5264. PSYS_SRC_OMEGA = 21,
  5265. PSYS_SRC_ANGLE_BEGIN = 22,
  5266. PSYS_SRC_ANGLE_END = 23
  5267. }
  5268. internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
  5269. {
  5270. Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
  5271. return returnval;
  5272. }
  5273. protected Primitive.ParticleSystem getNewParticleSystemWithSLDefaultValues()
  5274. {
  5275. Primitive.ParticleSystem ps = new Primitive.ParticleSystem();
  5276. // TODO find out about the other defaults and add them here
  5277. ps.PartStartColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
  5278. ps.PartEndColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
  5279. ps.PartStartScaleX = 1.0f;
  5280. ps.PartStartScaleY = 1.0f;
  5281. ps.PartEndScaleX = 1.0f;
  5282. ps.PartEndScaleY = 1.0f;
  5283. ps.BurstSpeedMin = 1.0f;
  5284. ps.BurstSpeedMax = 1.0f;
  5285. ps.BurstRate = 0.1f;
  5286. ps.PartMaxAge = 10.0f;
  5287. ps.BurstPartCount = 1;
  5288. return ps;
  5289. }
  5290. public void llLinkParticleSystem(int linknumber, LSL_List rules)
  5291. {
  5292. m_host.AddScriptLPS(1);
  5293. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  5294. foreach (SceneObjectPart part in parts)
  5295. {
  5296. SetParticleSystem(part, rules);
  5297. }
  5298. }
  5299. public void llParticleSystem(LSL_List rules)
  5300. {
  5301. m_host.AddScriptLPS(1);
  5302. SetParticleSystem(m_host, rules);
  5303. }
  5304. private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
  5305. {
  5306. if (rules.Length == 0)
  5307. {
  5308. part.RemoveParticleSystem();
  5309. part.ParentGroup.HasGroupChanged = true;
  5310. }
  5311. else
  5312. {
  5313. Primitive.ParticleSystem prules = getNewParticleSystemWithSLDefaultValues();
  5314. LSL_Vector tempv = new LSL_Vector();
  5315. float tempf = 0;
  5316. for (int i = 0; i < rules.Length; i += 2)
  5317. {
  5318. switch (rules.GetLSLIntegerItem(i))
  5319. {
  5320. case (int)ScriptBaseClass.PSYS_PART_FLAGS:
  5321. prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1);
  5322. break;
  5323. case (int)ScriptBaseClass.PSYS_PART_START_COLOR:
  5324. tempv = rules.GetVector3Item(i + 1);
  5325. prules.PartStartColor.R = (float)tempv.x;
  5326. prules.PartStartColor.G = (float)tempv.y;
  5327. prules.PartStartColor.B = (float)tempv.z;
  5328. break;
  5329. case (int)ScriptBaseClass.PSYS_PART_START_ALPHA:
  5330. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5331. prules.PartStartColor.A = tempf;
  5332. break;
  5333. case (int)ScriptBaseClass.PSYS_PART_END_COLOR:
  5334. tempv = rules.GetVector3Item(i + 1);
  5335. prules.PartEndColor.R = (float)tempv.x;
  5336. prules.PartEndColor.G = (float)tempv.y;
  5337. prules.PartEndColor.B = (float)tempv.z;
  5338. break;
  5339. case (int)ScriptBaseClass.PSYS_PART_END_ALPHA:
  5340. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5341. prules.PartEndColor.A = tempf;
  5342. break;
  5343. case (int)ScriptBaseClass.PSYS_PART_START_SCALE:
  5344. tempv = rules.GetVector3Item(i + 1);
  5345. prules.PartStartScaleX = (float)tempv.x;
  5346. prules.PartStartScaleY = (float)tempv.y;
  5347. break;
  5348. case (int)ScriptBaseClass.PSYS_PART_END_SCALE:
  5349. tempv = rules.GetVector3Item(i + 1);
  5350. prules.PartEndScaleX = (float)tempv.x;
  5351. prules.PartEndScaleY = (float)tempv.y;
  5352. break;
  5353. case (int)ScriptBaseClass.PSYS_PART_MAX_AGE:
  5354. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5355. prules.PartMaxAge = tempf;
  5356. break;
  5357. case (int)ScriptBaseClass.PSYS_SRC_ACCEL:
  5358. tempv = rules.GetVector3Item(i + 1);
  5359. prules.PartAcceleration.X = (float)tempv.x;
  5360. prules.PartAcceleration.Y = (float)tempv.y;
  5361. prules.PartAcceleration.Z = (float)tempv.z;
  5362. break;
  5363. case (int)ScriptBaseClass.PSYS_SRC_PATTERN:
  5364. int tmpi = (int)rules.GetLSLIntegerItem(i + 1);
  5365. prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
  5366. break;
  5367. // PSYS_SRC_INNERANGLE and PSYS_SRC_ANGLE_BEGIN use the same variables. The
  5368. // PSYS_SRC_OUTERANGLE and PSYS_SRC_ANGLE_END also use the same variable. The
  5369. // client tells the difference between the two by looking at the 0x02 bit in
  5370. // the PartFlags variable.
  5371. case (int)ScriptBaseClass.PSYS_SRC_INNERANGLE:
  5372. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5373. prules.InnerAngle = (float)tempf;
  5374. prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off.
  5375. break;
  5376. case (int)ScriptBaseClass.PSYS_SRC_OUTERANGLE:
  5377. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5378. prules.OuterAngle = (float)tempf;
  5379. prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off.
  5380. break;
  5381. case (int)ScriptBaseClass.PSYS_SRC_TEXTURE:
  5382. prules.Texture = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, rules.GetLSLStringItem(i + 1));
  5383. break;
  5384. case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE:
  5385. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5386. prules.BurstRate = (float)tempf;
  5387. break;
  5388. case (int)ScriptBaseClass.PSYS_SRC_BURST_PART_COUNT:
  5389. prules.BurstPartCount = (byte)(int)rules.GetLSLIntegerItem(i + 1);
  5390. break;
  5391. case (int)ScriptBaseClass.PSYS_SRC_BURST_RADIUS:
  5392. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5393. prules.BurstRadius = (float)tempf;
  5394. break;
  5395. case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MIN:
  5396. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5397. prules.BurstSpeedMin = (float)tempf;
  5398. break;
  5399. case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MAX:
  5400. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5401. prules.BurstSpeedMax = (float)tempf;
  5402. break;
  5403. case (int)ScriptBaseClass.PSYS_SRC_MAX_AGE:
  5404. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5405. prules.MaxAge = (float)tempf;
  5406. break;
  5407. case (int)ScriptBaseClass.PSYS_SRC_TARGET_KEY:
  5408. UUID key = UUID.Zero;
  5409. if (UUID.TryParse(rules.Data[i + 1].ToString(), out key))
  5410. {
  5411. prules.Target = key;
  5412. }
  5413. else
  5414. {
  5415. prules.Target = part.UUID;
  5416. }
  5417. break;
  5418. case (int)ScriptBaseClass.PSYS_SRC_OMEGA:
  5419. // AL: This is an assumption, since it is the only thing that would match.
  5420. tempv = rules.GetVector3Item(i + 1);
  5421. prules.AngularVelocity.X = (float)tempv.x;
  5422. prules.AngularVelocity.Y = (float)tempv.y;
  5423. prules.AngularVelocity.Z = (float)tempv.z;
  5424. break;
  5425. case (int)ScriptBaseClass.PSYS_SRC_ANGLE_BEGIN:
  5426. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5427. prules.InnerAngle = (float)tempf;
  5428. prules.PartFlags |= 0x02; // Set new angle format.
  5429. break;
  5430. case (int)ScriptBaseClass.PSYS_SRC_ANGLE_END:
  5431. tempf = (float)rules.GetLSLFloatItem(i + 1);
  5432. prules.OuterAngle = (float)tempf;
  5433. prules.PartFlags |= 0x02; // Set new angle format.
  5434. break;
  5435. }
  5436. }
  5437. prules.CRC = 1;
  5438. part.AddNewParticleSystem(prules);
  5439. part.ParentGroup.HasGroupChanged = true;
  5440. }
  5441. part.SendFullUpdateToAllClients();
  5442. }
  5443. public void llGroundRepel(double height, int water, double tau)
  5444. {
  5445. m_host.AddScriptLPS(1);
  5446. if (m_host.PhysActor != null)
  5447. {
  5448. float ground = (float)llGround(new LSL_Types.Vector3(0, 0, 0));
  5449. float waterLevel = (float)llWater(new LSL_Types.Vector3(0, 0, 0));
  5450. PIDHoverType hoverType = PIDHoverType.Ground;
  5451. if (water != 0)
  5452. {
  5453. hoverType = PIDHoverType.GroundAndWater;
  5454. if (ground < waterLevel)
  5455. height += waterLevel;
  5456. else
  5457. height += ground;
  5458. }
  5459. else
  5460. {
  5461. height += ground;
  5462. }
  5463. m_host.SetHoverHeight((float)height, hoverType, (float)tau);
  5464. }
  5465. }
  5466. public void llGiveInventoryList(string destination, string category, LSL_List inventory)
  5467. {
  5468. m_host.AddScriptLPS(1);
  5469. UUID destID;
  5470. if (!UUID.TryParse(destination, out destID))
  5471. return;
  5472. List<UUID> itemList = new List<UUID>();
  5473. foreach (Object item in inventory.Data)
  5474. {
  5475. string rawItemString = item.ToString();
  5476. UUID itemID;
  5477. if (UUID.TryParse(rawItemString, out itemID))
  5478. {
  5479. itemList.Add(itemID);
  5480. }
  5481. else
  5482. {
  5483. TaskInventoryItem taskItem = m_host.Inventory.GetInventoryItem(rawItemString);
  5484. if (taskItem != null)
  5485. itemList.Add(taskItem.ItemID);
  5486. }
  5487. }
  5488. if (itemList.Count == 0)
  5489. return;
  5490. UUID folderID = m_ScriptEngine.World.MoveTaskInventoryItems(destID, category, m_host, itemList);
  5491. if (folderID == UUID.Zero)
  5492. return;
  5493. if (m_TransferModule != null)
  5494. {
  5495. byte[] bucket = new byte[] { (byte)AssetType.Folder };
  5496. Vector3 pos = m_host.AbsolutePosition;
  5497. GridInstantMessage msg = new GridInstantMessage(World,
  5498. m_host.OwnerID, m_host.Name, destID,
  5499. (byte)InstantMessageDialog.TaskInventoryOffered,
  5500. false, string.Format("'{0}'", category),
  5501. // We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06
  5502. // false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z),
  5503. folderID, false, pos,
  5504. bucket, false);
  5505. m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
  5506. }
  5507. }
  5508. public void llSetVehicleType(int type)
  5509. {
  5510. m_host.AddScriptLPS(1);
  5511. if (!m_host.ParentGroup.IsDeleted)
  5512. {
  5513. m_host.ParentGroup.RootPart.SetVehicleType(type);
  5514. }
  5515. }
  5516. //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
  5517. //CFK 9/28: so these are not complete yet.
  5518. public void llSetVehicleFloatParam(int param, LSL_Float value)
  5519. {
  5520. m_host.AddScriptLPS(1);
  5521. if (!m_host.ParentGroup.IsDeleted)
  5522. {
  5523. m_host.ParentGroup.RootPart.SetVehicleFloatParam(param, (float)value);
  5524. }
  5525. }
  5526. //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
  5527. //CFK 9/28: so these are not complete yet.
  5528. public void llSetVehicleVectorParam(int param, LSL_Vector vec)
  5529. {
  5530. m_host.AddScriptLPS(1);
  5531. if (!m_host.ParentGroup.IsDeleted)
  5532. {
  5533. m_host.ParentGroup.RootPart.SetVehicleVectorParam(param, vec);
  5534. }
  5535. }
  5536. //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
  5537. //CFK 9/28: so these are not complete yet.
  5538. public void llSetVehicleRotationParam(int param, LSL_Rotation rot)
  5539. {
  5540. m_host.AddScriptLPS(1);
  5541. if (!m_host.ParentGroup.IsDeleted)
  5542. {
  5543. m_host.ParentGroup.RootPart.SetVehicleRotationParam(param, rot);
  5544. }
  5545. }
  5546. public void llSetVehicleFlags(int flags)
  5547. {
  5548. m_host.AddScriptLPS(1);
  5549. if (!m_host.ParentGroup.IsDeleted)
  5550. {
  5551. m_host.ParentGroup.RootPart.SetVehicleFlags(flags, false);
  5552. }
  5553. }
  5554. public void llRemoveVehicleFlags(int flags)
  5555. {
  5556. m_host.AddScriptLPS(1);
  5557. if (!m_host.ParentGroup.IsDeleted)
  5558. {
  5559. m_host.ParentGroup.RootPart.SetVehicleFlags(flags, true);
  5560. }
  5561. }
  5562. protected void SitTarget(SceneObjectPart part, LSL_Vector offset, LSL_Rotation rot)
  5563. {
  5564. part.SitTargetPosition = offset;
  5565. part.SitTargetOrientation = rot;
  5566. part.ParentGroup.HasGroupChanged = true;
  5567. }
  5568. public void llSitTarget(LSL_Vector offset, LSL_Rotation rot)
  5569. {
  5570. m_host.AddScriptLPS(1);
  5571. SitTarget(m_host, offset, rot);
  5572. }
  5573. public void llLinkSitTarget(LSL_Integer link, LSL_Vector offset, LSL_Rotation rot)
  5574. {
  5575. m_host.AddScriptLPS(1);
  5576. if (link == ScriptBaseClass.LINK_ROOT)
  5577. SitTarget(m_host.ParentGroup.RootPart, offset, rot);
  5578. else if (link == ScriptBaseClass.LINK_THIS)
  5579. SitTarget(m_host, offset, rot);
  5580. else
  5581. {
  5582. SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
  5583. if (null != part)
  5584. {
  5585. SitTarget(part, offset, rot);
  5586. }
  5587. }
  5588. }
  5589. public LSL_String llAvatarOnSitTarget()
  5590. {
  5591. m_host.AddScriptLPS(1);
  5592. return m_host.SitTargetAvatar.ToString();
  5593. }
  5594. // http://wiki.secondlife.com/wiki/LlAvatarOnLinkSitTarget
  5595. public LSL_String llAvatarOnLinkSitTarget(int linknum)
  5596. {
  5597. m_host.AddScriptLPS(1);
  5598. if(linknum == ScriptBaseClass.LINK_SET ||
  5599. linknum == ScriptBaseClass.LINK_ALL_CHILDREN ||
  5600. linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString();
  5601. List<SceneObjectPart> parts = GetLinkParts(linknum);
  5602. if (parts.Count == 0) return UUID.Zero.ToString();
  5603. return parts[0].SitTargetAvatar.ToString();
  5604. }
  5605. public void llAddToLandPassList(string avatar, double hours)
  5606. {
  5607. m_host.AddScriptLPS(1);
  5608. UUID key;
  5609. ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
  5610. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
  5611. {
  5612. int expires = 0;
  5613. if (hours != 0)
  5614. expires = Util.UnixTimeSinceEpoch() + (int)(3600.0 * hours);
  5615. if (UUID.TryParse(avatar, out key))
  5616. {
  5617. int idx = land.LandData.ParcelAccessList.FindIndex(
  5618. delegate(LandAccessEntry e)
  5619. {
  5620. if (e.AgentID == key && e.Flags == AccessList.Access)
  5621. return true;
  5622. return false;
  5623. });
  5624. if (idx != -1 && (land.LandData.ParcelAccessList[idx].Expires == 0 || (expires != 0 && expires < land.LandData.ParcelAccessList[idx].Expires)))
  5625. return;
  5626. if (idx != -1)
  5627. land.LandData.ParcelAccessList.RemoveAt(idx);
  5628. LandAccessEntry entry = new LandAccessEntry();
  5629. entry.AgentID = key;
  5630. entry.Flags = AccessList.Access;
  5631. entry.Expires = expires;
  5632. land.LandData.ParcelAccessList.Add(entry);
  5633. World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
  5634. }
  5635. }
  5636. ScriptSleep(100);
  5637. }
  5638. public void llSetTouchText(string text)
  5639. {
  5640. m_host.AddScriptLPS(1);
  5641. m_host.TouchName = text;
  5642. }
  5643. public void llSetSitText(string text)
  5644. {
  5645. m_host.AddScriptLPS(1);
  5646. m_host.SitName = text;
  5647. }
  5648. public void llSetCameraEyeOffset(LSL_Vector offset)
  5649. {
  5650. m_host.AddScriptLPS(1);
  5651. m_host.SetCameraEyeOffset(offset);
  5652. }
  5653. public void llSetCameraAtOffset(LSL_Vector offset)
  5654. {
  5655. m_host.AddScriptLPS(1);
  5656. m_host.SetCameraAtOffset(offset);
  5657. }
  5658. public void llSetLinkCamera(LSL_Integer link, LSL_Vector eye, LSL_Vector at)
  5659. {
  5660. m_host.AddScriptLPS(1);
  5661. if (link == ScriptBaseClass.LINK_SET ||
  5662. link == ScriptBaseClass.LINK_ALL_CHILDREN ||
  5663. link == ScriptBaseClass.LINK_ALL_OTHERS) return;
  5664. SceneObjectPart part = null;
  5665. switch (link)
  5666. {
  5667. case ScriptBaseClass.LINK_ROOT:
  5668. part = m_host.ParentGroup.RootPart;
  5669. break;
  5670. case ScriptBaseClass.LINK_THIS:
  5671. part = m_host;
  5672. break;
  5673. default:
  5674. part = m_host.ParentGroup.GetLinkNumPart(link);
  5675. break;
  5676. }
  5677. if (null != part)
  5678. {
  5679. part.SetCameraEyeOffset(eye);
  5680. part.SetCameraAtOffset(at);
  5681. }
  5682. }
  5683. public LSL_String llDumpList2String(LSL_List src, string seperator)
  5684. {
  5685. m_host.AddScriptLPS(1);
  5686. if (src.Length == 0)
  5687. {
  5688. return String.Empty;
  5689. }
  5690. string ret = String.Empty;
  5691. foreach (object o in src.Data)
  5692. {
  5693. ret = ret + o.ToString() + seperator;
  5694. }
  5695. ret = ret.Substring(0, ret.Length - seperator.Length);
  5696. return ret;
  5697. }
  5698. public LSL_Integer llScriptDanger(LSL_Vector pos)
  5699. {
  5700. m_host.AddScriptLPS(1);
  5701. bool result = World.ScriptDanger(m_host.LocalId, pos);
  5702. if (result)
  5703. {
  5704. return 1;
  5705. }
  5706. else
  5707. {
  5708. return 0;
  5709. }
  5710. }
  5711. public void llDialog(string avatar, string message, LSL_List buttons, int chat_channel)
  5712. {
  5713. IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
  5714. if (dm == null)
  5715. return;
  5716. m_host.AddScriptLPS(1);
  5717. UUID av = new UUID();
  5718. if (!UUID.TryParse(avatar,out av))
  5719. {
  5720. LSLError("First parameter to llDialog needs to be a key");
  5721. return;
  5722. }
  5723. if (buttons.Length < 1)
  5724. {
  5725. LSLError("No less than 1 button can be shown");
  5726. return;
  5727. }
  5728. if (buttons.Length > 12)
  5729. {
  5730. LSLError("No more than 12 buttons can be shown");
  5731. return;
  5732. }
  5733. string[] buts = new string[buttons.Length];
  5734. for (int i = 0; i < buttons.Length; i++)
  5735. {
  5736. if (buttons.Data[i].ToString() == String.Empty)
  5737. {
  5738. LSLError("button label cannot be blank");
  5739. return;
  5740. }
  5741. if (buttons.Data[i].ToString().Length > 24)
  5742. {
  5743. LSLError("button label cannot be longer than 24 characters");
  5744. return;
  5745. }
  5746. buts[i] = buttons.Data[i].ToString();
  5747. }
  5748. dm.SendDialogToUser(
  5749. av, m_host.Name, m_host.UUID, m_host.OwnerID,
  5750. message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
  5751. ScriptSleep(1000);
  5752. }
  5753. public void llVolumeDetect(int detect)
  5754. {
  5755. m_host.AddScriptLPS(1);
  5756. if (!m_host.ParentGroup.IsDeleted)
  5757. m_host.ParentGroup.ScriptSetVolumeDetect(detect != 0);
  5758. }
  5759. /// <summary>
  5760. /// This is a depecated function so this just replicates the result of
  5761. /// invoking it in SL
  5762. /// </summary>
  5763. public void llRemoteLoadScript(string target, string name, int running, int start_param)
  5764. {
  5765. m_host.AddScriptLPS(1);
  5766. // Report an error as it does in SL
  5767. ShoutError("Deprecated. Please use llRemoteLoadScriptPin instead.");
  5768. ScriptSleep(3000);
  5769. }
  5770. public void llSetRemoteScriptAccessPin(int pin)
  5771. {
  5772. m_host.AddScriptLPS(1);
  5773. m_host.ScriptAccessPin = pin;
  5774. }
  5775. public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
  5776. {
  5777. m_host.AddScriptLPS(1);
  5778. UUID destId = UUID.Zero;
  5779. if (!UUID.TryParse(target, out destId))
  5780. {
  5781. llSay(0, "Could not parse key " + target);
  5782. return;
  5783. }
  5784. // target must be a different prim than the one containing the script
  5785. if (m_host.UUID == destId)
  5786. {
  5787. return;
  5788. }
  5789. // copy the first script found with this inventory name
  5790. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  5791. // make sure the object is a script
  5792. if (item == null || item.Type != 10)
  5793. {
  5794. llSay(0, "Could not find script " + name);
  5795. return;
  5796. }
  5797. // the rest of the permission checks are done in RezScript, so check the pin there as well
  5798. World.RezScriptFromPrim(item.ItemID, m_host, destId, pin, running, start_param);
  5799. // this will cause the delay even if the script pin or permissions were wrong - seems ok
  5800. ScriptSleep(3000);
  5801. }
  5802. public void llOpenRemoteDataChannel()
  5803. {
  5804. m_host.AddScriptLPS(1);
  5805. IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
  5806. if (xmlrpcMod != null && xmlrpcMod.IsEnabled())
  5807. {
  5808. UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_host.LocalId, m_item.ItemID, UUID.Zero);
  5809. IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
  5810. if (xmlRpcRouter != null)
  5811. {
  5812. string ExternalHostName = m_ScriptEngine.World.RegionInfo.ExternalHostName;
  5813. xmlRpcRouter.RegisterNewReceiver(m_ScriptEngine.ScriptModule, channelID, m_host.UUID,
  5814. m_item.ItemID, String.Format("http://{0}:{1}/", ExternalHostName,
  5815. xmlrpcMod.Port.ToString()));
  5816. }
  5817. object[] resobj = new object[]
  5818. {
  5819. new LSL_Integer(1),
  5820. new LSL_String(channelID.ToString()),
  5821. new LSL_String(UUID.Zero.ToString()),
  5822. new LSL_String(String.Empty),
  5823. new LSL_Integer(0),
  5824. new LSL_String(String.Empty)
  5825. };
  5826. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams("remote_data", resobj,
  5827. new DetectParams[0]));
  5828. }
  5829. ScriptSleep(1000);
  5830. }
  5831. public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata)
  5832. {
  5833. m_host.AddScriptLPS(1);
  5834. IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
  5835. ScriptSleep(3000);
  5836. if (xmlrpcMod == null)
  5837. return "";
  5838. return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString();
  5839. }
  5840. public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
  5841. {
  5842. m_host.AddScriptLPS(1);
  5843. IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
  5844. if (xmlrpcMod != null)
  5845. xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
  5846. ScriptSleep(3000);
  5847. }
  5848. public void llCloseRemoteDataChannel(string channel)
  5849. {
  5850. m_host.AddScriptLPS(1);
  5851. IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
  5852. if (xmlRpcRouter != null)
  5853. {
  5854. xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID);
  5855. }
  5856. IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
  5857. if (xmlrpcMod != null)
  5858. xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
  5859. ScriptSleep(1000);
  5860. }
  5861. public LSL_String llMD5String(string src, int nonce)
  5862. {
  5863. m_host.AddScriptLPS(1);
  5864. return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString()));
  5865. }
  5866. public LSL_String llSHA1String(string src)
  5867. {
  5868. m_host.AddScriptLPS(1);
  5869. return Util.SHA1Hash(src).ToLower();
  5870. }
  5871. protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve)
  5872. {
  5873. float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
  5874. ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
  5875. if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
  5876. holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
  5877. holeshape != (int)ScriptBaseClass.PRIM_HOLE_SQUARE &&
  5878. holeshape != (int)ScriptBaseClass.PRIM_HOLE_TRIANGLE)
  5879. {
  5880. holeshape = (int)ScriptBaseClass.PRIM_HOLE_DEFAULT;
  5881. }
  5882. shapeBlock.PathCurve = pathcurve;
  5883. shapeBlock.ProfileCurve = (byte)holeshape; // Set the hole shape.
  5884. shapeBlock.ProfileCurve += profileshape; // Add in the profile shape.
  5885. if (cut.x < 0f)
  5886. {
  5887. cut.x = 0f;
  5888. }
  5889. if (cut.x > 1f)
  5890. {
  5891. cut.x = 1f;
  5892. }
  5893. if (cut.y < 0f)
  5894. {
  5895. cut.y = 0f;
  5896. }
  5897. if (cut.y > 1f)
  5898. {
  5899. cut.y = 1f;
  5900. }
  5901. if (cut.y - cut.x < 0.05f)
  5902. {
  5903. cut.x = cut.y - 0.05f;
  5904. if (cut.x < 0.0f)
  5905. {
  5906. cut.x = 0.0f;
  5907. cut.y = 0.05f;
  5908. }
  5909. }
  5910. shapeBlock.ProfileBegin = (ushort)(50000 * cut.x);
  5911. shapeBlock.ProfileEnd = (ushort)(50000 * (1 - cut.y));
  5912. if (hollow < 0f)
  5913. {
  5914. hollow = 0f;
  5915. }
  5916. // If the prim is a Cylinder, Prism, Sphere, Torus or Ring (or not a
  5917. // Box or Tube) and the hole shape is a square, hollow is limited to
  5918. // a max of 70%. The viewer performs its own check on this value but
  5919. // we need to do it here also so llGetPrimitiveParams can have access
  5920. // to the correct value.
  5921. if (profileshape != (byte)ProfileCurve.Square &&
  5922. holeshape == (int)ScriptBaseClass.PRIM_HOLE_SQUARE)
  5923. {
  5924. if (hollow > 0.70f)
  5925. {
  5926. hollow = 0.70f;
  5927. }
  5928. }
  5929. // Otherwise, hollow is limited to 95%.
  5930. else
  5931. {
  5932. if (hollow > 0.95f)
  5933. {
  5934. hollow = 0.95f;
  5935. }
  5936. }
  5937. shapeBlock.ProfileHollow = (ushort)(50000 * hollow);
  5938. if (twist.x < -1.0f)
  5939. {
  5940. twist.x = -1.0f;
  5941. }
  5942. if (twist.x > 1.0f)
  5943. {
  5944. twist.x = 1.0f;
  5945. }
  5946. if (twist.y < -1.0f)
  5947. {
  5948. twist.y = -1.0f;
  5949. }
  5950. if (twist.y > 1.0f)
  5951. {
  5952. twist.y = 1.0f;
  5953. }
  5954. // A fairly large precision error occurs for some calculations,
  5955. // if a float or double is directly cast to a byte or sbyte
  5956. // variable, in both .Net and Mono. In .Net, coding
  5957. // "(sbyte)(float)(some expression)" corrects the precision
  5958. // errors. But this does not work for Mono. This longer coding
  5959. // form of creating a tempoary float variable from the
  5960. // expression first, then casting that variable to a byte or
  5961. // sbyte, works for both .Net and Mono. These types of
  5962. // assignments occur in SetPrimtiveBlockShapeParams and
  5963. // SetPrimitiveShapeParams in support of llSetPrimitiveParams.
  5964. tempFloat = (float)(100.0d * twist.x);
  5965. shapeBlock.PathTwistBegin = (sbyte)tempFloat;
  5966. tempFloat = (float)(100.0d * twist.y);
  5967. shapeBlock.PathTwist = (sbyte)tempFloat;
  5968. shapeBlock.ObjectLocalID = part.LocalId;
  5969. part.Shape.SculptEntry = false;
  5970. return shapeBlock;
  5971. }
  5972. // Prim type box, cylinder and prism.
  5973. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve)
  5974. {
  5975. float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
  5976. ObjectShapePacket.ObjectDataBlock shapeBlock;
  5977. shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
  5978. if (taper_b.x < 0f)
  5979. {
  5980. taper_b.x = 0f;
  5981. }
  5982. if (taper_b.x > 2f)
  5983. {
  5984. taper_b.x = 2f;
  5985. }
  5986. if (taper_b.y < 0f)
  5987. {
  5988. taper_b.y = 0f;
  5989. }
  5990. if (taper_b.y > 2f)
  5991. {
  5992. taper_b.y = 2f;
  5993. }
  5994. tempFloat = (float)(100.0d * (2.0d - taper_b.x));
  5995. shapeBlock.PathScaleX = (byte)tempFloat;
  5996. tempFloat = (float)(100.0d * (2.0d - taper_b.y));
  5997. shapeBlock.PathScaleY = (byte)tempFloat;
  5998. if (topshear.x < -0.5f)
  5999. {
  6000. topshear.x = -0.5f;
  6001. }
  6002. if (topshear.x > 0.5f)
  6003. {
  6004. topshear.x = 0.5f;
  6005. }
  6006. if (topshear.y < -0.5f)
  6007. {
  6008. topshear.y = -0.5f;
  6009. }
  6010. if (topshear.y > 0.5f)
  6011. {
  6012. topshear.y = 0.5f;
  6013. }
  6014. tempFloat = (float)(100.0d * topshear.x);
  6015. shapeBlock.PathShearX = (byte)tempFloat;
  6016. tempFloat = (float)(100.0d * topshear.y);
  6017. shapeBlock.PathShearY = (byte)tempFloat;
  6018. part.Shape.SculptEntry = false;
  6019. part.UpdateShape(shapeBlock);
  6020. }
  6021. // Prim type sphere.
  6022. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte profileshape, byte pathcurve)
  6023. {
  6024. ObjectShapePacket.ObjectDataBlock shapeBlock;
  6025. shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
  6026. // profile/path swapped for a sphere
  6027. shapeBlock.PathBegin = shapeBlock.ProfileBegin;
  6028. shapeBlock.PathEnd = shapeBlock.ProfileEnd;
  6029. shapeBlock.PathScaleX = 100;
  6030. shapeBlock.PathScaleY = 100;
  6031. if (dimple.x < 0f)
  6032. {
  6033. dimple.x = 0f;
  6034. }
  6035. if (dimple.x > 1f)
  6036. {
  6037. dimple.x = 1f;
  6038. }
  6039. if (dimple.y < 0f)
  6040. {
  6041. dimple.y = 0f;
  6042. }
  6043. if (dimple.y > 1f)
  6044. {
  6045. dimple.y = 1f;
  6046. }
  6047. if (dimple.y - cut.x < 0.05f)
  6048. {
  6049. dimple.x = cut.y - 0.05f;
  6050. }
  6051. shapeBlock.ProfileBegin = (ushort)(50000 * dimple.x);
  6052. shapeBlock.ProfileEnd = (ushort)(50000 * (1 - dimple.y));
  6053. part.Shape.SculptEntry = false;
  6054. part.UpdateShape(shapeBlock);
  6055. }
  6056. // Prim type torus, tube and ring.
  6057. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte profileshape, byte pathcurve)
  6058. {
  6059. float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
  6060. ObjectShapePacket.ObjectDataBlock shapeBlock;
  6061. shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
  6062. // profile/path swapped for a torrus, tube, ring
  6063. shapeBlock.PathBegin = shapeBlock.ProfileBegin;
  6064. shapeBlock.PathEnd = shapeBlock.ProfileEnd;
  6065. if (holesize.x < 0.05f)
  6066. {
  6067. holesize.x = 0.05f;
  6068. }
  6069. if (holesize.x > 1f)
  6070. {
  6071. holesize.x = 1f;
  6072. }
  6073. if (holesize.y < 0.05f)
  6074. {
  6075. holesize.y = 0.05f;
  6076. }
  6077. if (holesize.y > 0.5f)
  6078. {
  6079. holesize.y = 0.5f;
  6080. }
  6081. tempFloat = (float)(100.0d * (2.0d - holesize.x));
  6082. shapeBlock.PathScaleX = (byte)tempFloat;
  6083. tempFloat = (float)(100.0d * (2.0d - holesize.y));
  6084. shapeBlock.PathScaleY = (byte)tempFloat;
  6085. if (topshear.x < -0.5f)
  6086. {
  6087. topshear.x = -0.5f;
  6088. }
  6089. if (topshear.x > 0.5f)
  6090. {
  6091. topshear.x = 0.5f;
  6092. }
  6093. if (topshear.y < -0.5f)
  6094. {
  6095. topshear.y = -0.5f;
  6096. }
  6097. if (topshear.y > 0.5f)
  6098. {
  6099. topshear.y = 0.5f;
  6100. }
  6101. tempFloat = (float)(100.0d * topshear.x);
  6102. shapeBlock.PathShearX = (byte)tempFloat;
  6103. tempFloat = (float)(100.0d * topshear.y);
  6104. shapeBlock.PathShearY = (byte)tempFloat;
  6105. if (profilecut.x < 0f)
  6106. {
  6107. profilecut.x = 0f;
  6108. }
  6109. if (profilecut.x > 1f)
  6110. {
  6111. profilecut.x = 1f;
  6112. }
  6113. if (profilecut.y < 0f)
  6114. {
  6115. profilecut.y = 0f;
  6116. }
  6117. if (profilecut.y > 1f)
  6118. {
  6119. profilecut.y = 1f;
  6120. }
  6121. if (profilecut.y - profilecut.x < 0.05f)
  6122. {
  6123. profilecut.x = profilecut.y - 0.05f;
  6124. if (profilecut.x < 0.0f)
  6125. {
  6126. profilecut.x = 0.0f;
  6127. profilecut.y = 0.05f;
  6128. }
  6129. }
  6130. shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x);
  6131. shapeBlock.ProfileEnd = (ushort)(50000 * (1 - profilecut.y));
  6132. if (taper_a.x < -1f)
  6133. {
  6134. taper_a.x = -1f;
  6135. }
  6136. if (taper_a.x > 1f)
  6137. {
  6138. taper_a.x = 1f;
  6139. }
  6140. if (taper_a.y < -1f)
  6141. {
  6142. taper_a.y = -1f;
  6143. }
  6144. if (taper_a.y > 1f)
  6145. {
  6146. taper_a.y = 1f;
  6147. }
  6148. tempFloat = (float)(100.0d * taper_a.x);
  6149. shapeBlock.PathTaperX = (sbyte)tempFloat;
  6150. tempFloat = (float)(100.0d * taper_a.y);
  6151. shapeBlock.PathTaperY = (sbyte)tempFloat;
  6152. if (revolutions < 1f)
  6153. {
  6154. revolutions = 1f;
  6155. }
  6156. if (revolutions > 4f)
  6157. {
  6158. revolutions = 4f;
  6159. }
  6160. tempFloat = 66.66667f * (revolutions - 1.0f);
  6161. shapeBlock.PathRevolutions = (byte)tempFloat;
  6162. // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1
  6163. if (radiusoffset < 0f)
  6164. {
  6165. radiusoffset = 0f;
  6166. }
  6167. if (radiusoffset > 1f)
  6168. {
  6169. radiusoffset = 1f;
  6170. }
  6171. tempFloat = 100.0f * radiusoffset;
  6172. shapeBlock.PathRadiusOffset = (sbyte)tempFloat;
  6173. if (skew < -0.95f)
  6174. {
  6175. skew = -0.95f;
  6176. }
  6177. if (skew > 0.95f)
  6178. {
  6179. skew = 0.95f;
  6180. }
  6181. tempFloat = 100.0f * skew;
  6182. shapeBlock.PathSkew = (sbyte)tempFloat;
  6183. part.Shape.SculptEntry = false;
  6184. part.UpdateShape(shapeBlock);
  6185. }
  6186. // Prim type sculpt.
  6187. protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type, byte pathcurve)
  6188. {
  6189. ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
  6190. UUID sculptId;
  6191. if (!UUID.TryParse(map, out sculptId))
  6192. sculptId = ScriptUtils.GetAssetIdFromItemName(m_host, map, (int)AssetType.Texture);
  6193. if (sculptId == UUID.Zero)
  6194. return;
  6195. shapeBlock.PathCurve = pathcurve;
  6196. shapeBlock.ObjectLocalID = part.LocalId;
  6197. shapeBlock.PathScaleX = 100;
  6198. shapeBlock.PathScaleY = 150;
  6199. int flag = type & (ScriptBaseClass.PRIM_SCULPT_FLAG_INVERT | ScriptBaseClass.PRIM_SCULPT_FLAG_MIRROR);
  6200. if (type != (ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER | flag) &&
  6201. type != (ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE | flag) &&
  6202. type != (ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE | flag) &&
  6203. type != (ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS | flag))
  6204. {
  6205. // default
  6206. type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
  6207. }
  6208. part.Shape.SetSculptProperties((byte)type, sculptId);
  6209. part.Shape.SculptEntry = true;
  6210. part.UpdateShape(shapeBlock);
  6211. }
  6212. public void llSetPrimitiveParams(LSL_List rules)
  6213. {
  6214. m_host.AddScriptLPS(1);
  6215. setLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams");
  6216. ScriptSleep(200);
  6217. }
  6218. public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
  6219. {
  6220. m_host.AddScriptLPS(1);
  6221. setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams");
  6222. ScriptSleep(200);
  6223. }
  6224. public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules)
  6225. {
  6226. m_host.AddScriptLPS(1);
  6227. setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast");
  6228. }
  6229. protected void setLinkPrimParams(int linknumber, LSL_List rules, string originFunc)
  6230. {
  6231. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  6232. LSL_List remaining = null;
  6233. uint rulesParsed = 0;
  6234. foreach (SceneObjectPart part in parts)
  6235. remaining = SetPrimParams(part, rules, originFunc, ref rulesParsed);
  6236. while (remaining != null && remaining.Length > 2)
  6237. {
  6238. linknumber = remaining.GetLSLIntegerItem(0);
  6239. rules = remaining.GetSublist(1, -1);
  6240. parts = GetLinkParts(linknumber);
  6241. foreach (SceneObjectPart part in parts)
  6242. remaining = SetPrimParams(part, rules, originFunc, ref rulesParsed);
  6243. }
  6244. }
  6245. protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules, string originFunc, ref uint rulesParsed)
  6246. {
  6247. int idx = 0;
  6248. int idxStart = 0;
  6249. bool positionChanged = false;
  6250. LSL_Vector currentPosition = GetPartLocalPos(part);
  6251. try
  6252. {
  6253. while (idx < rules.Length)
  6254. {
  6255. ++rulesParsed;
  6256. int code = rules.GetLSLIntegerItem(idx++);
  6257. int remain = rules.Length - idx;
  6258. idxStart = idx;
  6259. int face;
  6260. LSL_Vector v;
  6261. switch (code)
  6262. {
  6263. case (int)ScriptBaseClass.PRIM_POSITION:
  6264. case (int)ScriptBaseClass.PRIM_POS_LOCAL:
  6265. if (remain < 1)
  6266. return null;
  6267. v=rules.GetVector3Item(idx++);
  6268. positionChanged = true;
  6269. currentPosition = GetSetPosTarget(part, v, currentPosition);
  6270. break;
  6271. case (int)ScriptBaseClass.PRIM_SIZE:
  6272. if (remain < 1)
  6273. return null;
  6274. v=rules.GetVector3Item(idx++);
  6275. SetScale(part, v);
  6276. break;
  6277. case (int)ScriptBaseClass.PRIM_ROTATION:
  6278. if (remain < 1)
  6279. return null;
  6280. LSL_Rotation q = rules.GetQuaternionItem(idx++);
  6281. // try to let this work as in SL...
  6282. if (part.ParentID == 0)
  6283. {
  6284. // special case: If we are root, rotate complete SOG to new rotation
  6285. SetRot(part, q);
  6286. }
  6287. else
  6288. {
  6289. // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
  6290. SceneObjectPart rootPart = part.ParentGroup.RootPart;
  6291. SetRot(part, rootPart.RotationOffset * (Quaternion)q);
  6292. }
  6293. break;
  6294. case (int)ScriptBaseClass.PRIM_TYPE:
  6295. if (remain < 3)
  6296. return null;
  6297. code = (int)rules.GetLSLIntegerItem(idx++);
  6298. remain = rules.Length - idx;
  6299. float hollow;
  6300. LSL_Vector twist;
  6301. LSL_Vector taper_b;
  6302. LSL_Vector topshear;
  6303. float revolutions;
  6304. float radiusoffset;
  6305. float skew;
  6306. LSL_Vector holesize;
  6307. LSL_Vector profilecut;
  6308. switch (code)
  6309. {
  6310. case (int)ScriptBaseClass.PRIM_TYPE_BOX:
  6311. if (remain < 6)
  6312. return null;
  6313. face = (int)rules.GetLSLIntegerItem(idx++);
  6314. v = rules.GetVector3Item(idx++); // cut
  6315. hollow = (float)rules.GetLSLFloatItem(idx++);
  6316. twist = rules.GetVector3Item(idx++);
  6317. taper_b = rules.GetVector3Item(idx++);
  6318. topshear = rules.GetVector3Item(idx++);
  6319. SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
  6320. (byte)ProfileShape.Square, (byte)Extrusion.Straight);
  6321. break;
  6322. case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER:
  6323. if (remain < 6)
  6324. return null;
  6325. face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
  6326. v = rules.GetVector3Item(idx++); // cut
  6327. hollow = (float)rules.GetLSLFloatItem(idx++);
  6328. twist = rules.GetVector3Item(idx++);
  6329. taper_b = rules.GetVector3Item(idx++);
  6330. topshear = rules.GetVector3Item(idx++);
  6331. SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
  6332. (byte)ProfileShape.Circle, (byte)Extrusion.Straight);
  6333. break;
  6334. case (int)ScriptBaseClass.PRIM_TYPE_PRISM:
  6335. if (remain < 6)
  6336. return null;
  6337. face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
  6338. v = rules.GetVector3Item(idx++); //cut
  6339. hollow = (float)rules.GetLSLFloatItem(idx++);
  6340. twist = rules.GetVector3Item(idx++);
  6341. taper_b = rules.GetVector3Item(idx++);
  6342. topshear = rules.GetVector3Item(idx++);
  6343. SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
  6344. (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Straight);
  6345. break;
  6346. case (int)ScriptBaseClass.PRIM_TYPE_SPHERE:
  6347. if (remain < 5)
  6348. return null;
  6349. face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
  6350. v = rules.GetVector3Item(idx++); // cut
  6351. hollow = (float)rules.GetLSLFloatItem(idx++);
  6352. twist = rules.GetVector3Item(idx++);
  6353. taper_b = rules.GetVector3Item(idx++); // dimple
  6354. SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b,
  6355. (byte)ProfileShape.HalfCircle, (byte)Extrusion.Curve1);
  6356. break;
  6357. case (int)ScriptBaseClass.PRIM_TYPE_TORUS:
  6358. if (remain < 11)
  6359. return null;
  6360. face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
  6361. v = rules.GetVector3Item(idx++); //cut
  6362. hollow = (float)rules.GetLSLFloatItem(idx++);
  6363. twist = rules.GetVector3Item(idx++);
  6364. holesize = rules.GetVector3Item(idx++);
  6365. topshear = rules.GetVector3Item(idx++);
  6366. profilecut = rules.GetVector3Item(idx++);
  6367. taper_b = rules.GetVector3Item(idx++); // taper_a
  6368. revolutions = (float)rules.GetLSLFloatItem(idx++);
  6369. radiusoffset = (float)rules.GetLSLFloatItem(idx++);
  6370. skew = (float)rules.GetLSLFloatItem(idx++);
  6371. SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
  6372. revolutions, radiusoffset, skew, (byte)ProfileShape.Circle, (byte)Extrusion.Curve1);
  6373. break;
  6374. case (int)ScriptBaseClass.PRIM_TYPE_TUBE:
  6375. if (remain < 11)
  6376. return null;
  6377. face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
  6378. v = rules.GetVector3Item(idx++); //cut
  6379. hollow = (float)rules.GetLSLFloatItem(idx++);
  6380. twist = rules.GetVector3Item(idx++);
  6381. holesize = rules.GetVector3Item(idx++);
  6382. topshear = rules.GetVector3Item(idx++);
  6383. profilecut = rules.GetVector3Item(idx++);
  6384. taper_b = rules.GetVector3Item(idx++); // taper_a
  6385. revolutions = (float)rules.GetLSLFloatItem(idx++);
  6386. radiusoffset = (float)rules.GetLSLFloatItem(idx++);
  6387. skew = (float)rules.GetLSLFloatItem(idx++);
  6388. SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
  6389. revolutions, radiusoffset, skew, (byte)ProfileShape.Square, (byte)Extrusion.Curve1);
  6390. break;
  6391. case (int)ScriptBaseClass.PRIM_TYPE_RING:
  6392. if (remain < 11)
  6393. return null;
  6394. face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
  6395. v = rules.GetVector3Item(idx++); //cut
  6396. hollow = (float)rules.GetLSLFloatItem(idx++);
  6397. twist = rules.GetVector3Item(idx++);
  6398. holesize = rules.GetVector3Item(idx++);
  6399. topshear = rules.GetVector3Item(idx++);
  6400. profilecut = rules.GetVector3Item(idx++);
  6401. taper_b = rules.GetVector3Item(idx++); // taper_a
  6402. revolutions = (float)rules.GetLSLFloatItem(idx++);
  6403. radiusoffset = (float)rules.GetLSLFloatItem(idx++);
  6404. skew = (float)rules.GetLSLFloatItem(idx++);
  6405. SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
  6406. revolutions, radiusoffset, skew, (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Curve1);
  6407. break;
  6408. case (int)ScriptBaseClass.PRIM_TYPE_SCULPT:
  6409. if (remain < 2)
  6410. return null;
  6411. string map = rules.Data[idx++].ToString();
  6412. face = (int)rules.GetLSLIntegerItem(idx++); // type
  6413. SetPrimitiveShapeParams(part, map, face, (byte)Extrusion.Curve1);
  6414. break;
  6415. }
  6416. break;
  6417. case (int)ScriptBaseClass.PRIM_TEXTURE:
  6418. if (remain < 5)
  6419. return null;
  6420. face=(int)rules.GetLSLIntegerItem(idx++);
  6421. string tex=rules.Data[idx++].ToString();
  6422. LSL_Vector repeats=rules.GetVector3Item(idx++);
  6423. LSL_Vector offsets=rules.GetVector3Item(idx++);
  6424. double rotation=(double)rules.GetLSLFloatItem(idx++);
  6425. SetTexture(part, tex, face);
  6426. ScaleTexture(part, repeats.x, repeats.y, face);
  6427. OffsetTexture(part, offsets.x, offsets.y, face);
  6428. RotateTexture(part, rotation, face);
  6429. break;
  6430. case (int)ScriptBaseClass.PRIM_COLOR:
  6431. if (remain < 3)
  6432. return null;
  6433. face=(int)rules.GetLSLIntegerItem(idx++);
  6434. LSL_Vector color=rules.GetVector3Item(idx++);
  6435. double alpha=(double)rules.GetLSLFloatItem(idx++);
  6436. part.SetFaceColorAlpha(face, color, alpha);
  6437. break;
  6438. case (int)ScriptBaseClass.PRIM_FLEXIBLE:
  6439. if (remain < 7)
  6440. return null;
  6441. bool flexi = rules.GetLSLIntegerItem(idx++);
  6442. int softness = rules.GetLSLIntegerItem(idx++);
  6443. float gravity = (float)rules.GetLSLFloatItem(idx++);
  6444. float friction = (float)rules.GetLSLFloatItem(idx++);
  6445. float wind = (float)rules.GetLSLFloatItem(idx++);
  6446. float tension = (float)rules.GetLSLFloatItem(idx++);
  6447. LSL_Vector force = rules.GetVector3Item(idx++);
  6448. SetFlexi(part, flexi, softness, gravity, friction, wind, tension, force);
  6449. break;
  6450. case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
  6451. if (remain < 5)
  6452. return null;
  6453. bool light = rules.GetLSLIntegerItem(idx++);
  6454. LSL_Vector lightcolor = rules.GetVector3Item(idx++);
  6455. float intensity = (float)rules.GetLSLFloatItem(idx++);
  6456. float radius = (float)rules.GetLSLFloatItem(idx++);
  6457. float falloff = (float)rules.GetLSLFloatItem(idx++);
  6458. SetPointLight(part, light, lightcolor, intensity, radius, falloff);
  6459. break;
  6460. case (int)ScriptBaseClass.PRIM_GLOW:
  6461. if (remain < 2)
  6462. return null;
  6463. face = rules.GetLSLIntegerItem(idx++);
  6464. float glow = (float)rules.GetLSLFloatItem(idx++);
  6465. SetGlow(part, face, glow);
  6466. break;
  6467. case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
  6468. if (remain < 3)
  6469. return null;
  6470. face = (int)rules.GetLSLIntegerItem(idx++);
  6471. int shiny = (int)rules.GetLSLIntegerItem(idx++);
  6472. Bumpiness bump = (Bumpiness)(int)rules.GetLSLIntegerItem(idx++);
  6473. SetShiny(part, face, shiny, bump);
  6474. break;
  6475. case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
  6476. if (remain < 2)
  6477. return null;
  6478. face = rules.GetLSLIntegerItem(idx++);
  6479. bool st = rules.GetLSLIntegerItem(idx++);
  6480. SetFullBright(part, face , st);
  6481. break;
  6482. case (int)ScriptBaseClass.PRIM_MATERIAL:
  6483. if (remain < 1)
  6484. return null;
  6485. int mat = rules.GetLSLIntegerItem(idx++);
  6486. if (mat < 0 || mat > 7)
  6487. return null;
  6488. part.Material = Convert.ToByte(mat);
  6489. break;
  6490. case (int)ScriptBaseClass.PRIM_PHANTOM:
  6491. if (remain < 1)
  6492. return null;
  6493. string ph = rules.Data[idx++].ToString();
  6494. m_host.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1"));
  6495. break;
  6496. case (int)ScriptBaseClass.PRIM_PHYSICS:
  6497. if (remain < 1)
  6498. return null;
  6499. string phy = rules.Data[idx++].ToString();
  6500. bool physics;
  6501. if (phy.Equals("1"))
  6502. physics = true;
  6503. else
  6504. physics = false;
  6505. part.ScriptSetPhysicsStatus(physics);
  6506. break;
  6507. case (int)ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE:
  6508. if (remain < 1)
  6509. return null;
  6510. int shape_type = rules.GetLSLIntegerItem(idx++);
  6511. ExtraPhysicsData physdata = new ExtraPhysicsData();
  6512. physdata.Density = part.Density;
  6513. physdata.Bounce = part.Restitution;
  6514. physdata.GravitationModifier = part.GravityModifier;
  6515. physdata.PhysShapeType = (PhysShapeType)shape_type;
  6516. part.UpdateExtraPhysics(physdata);
  6517. break;
  6518. case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
  6519. if (remain < 1)
  6520. return null;
  6521. string temp = rules.Data[idx++].ToString();
  6522. m_host.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1"));
  6523. break;
  6524. case (int)ScriptBaseClass.PRIM_TEXGEN:
  6525. if (remain < 2)
  6526. return null;
  6527. //face,type
  6528. face = rules.GetLSLIntegerItem(idx++);
  6529. int style = rules.GetLSLIntegerItem(idx++);
  6530. SetTexGen(part, face, style);
  6531. break;
  6532. case (int)ScriptBaseClass.PRIM_TEXT:
  6533. if (remain < 3)
  6534. return null;
  6535. string primText = rules.GetLSLStringItem(idx++);
  6536. LSL_Vector primTextColor = rules.GetVector3Item(idx++);
  6537. LSL_Float primTextAlpha = rules.GetLSLFloatItem(idx++);
  6538. Vector3 av3 = Util.Clip(primTextColor, 0.0f, 1.0f);
  6539. part.SetText(primText, av3, Util.Clip((float)primTextAlpha, 0.0f, 1.0f));
  6540. break;
  6541. case (int)ScriptBaseClass.PRIM_NAME:
  6542. if (remain < 1)
  6543. return null;
  6544. string primName = rules.GetLSLStringItem(idx++);
  6545. part.Name = primName;
  6546. break;
  6547. case (int)ScriptBaseClass.PRIM_DESC:
  6548. if (remain < 1)
  6549. return null;
  6550. string primDesc = rules.GetLSLStringItem(idx++);
  6551. part.Description = primDesc;
  6552. break;
  6553. case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
  6554. if (remain < 1)
  6555. return null;
  6556. SetRot(part, rules.GetQuaternionItem(idx++));
  6557. break;
  6558. case (int)ScriptBaseClass.PRIM_OMEGA:
  6559. if (remain < 3)
  6560. return null;
  6561. LSL_Vector axis = rules.GetVector3Item(idx++);
  6562. LSL_Float spinrate = rules.GetLSLFloatItem(idx++);
  6563. LSL_Float gain = rules.GetLSLFloatItem(idx++);
  6564. TargetOmega(part, axis, (double)spinrate, (double)gain);
  6565. break;
  6566. case (int)ScriptBaseClass.PRIM_SLICE:
  6567. if (remain < 1)
  6568. return null;
  6569. LSL_Vector slice = rules.GetVector3Item(idx++);
  6570. part.UpdateSlice((float)slice.x, (float)slice.y);
  6571. break;
  6572. case (int)ScriptBaseClass.PRIM_LINK_TARGET:
  6573. if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
  6574. return null;
  6575. return rules.GetSublist(idx, -1);
  6576. }
  6577. }
  6578. }
  6579. catch (InvalidCastException e)
  6580. {
  6581. ShoutError(string.Format(
  6582. "{0} error running rule #{1}: arg #{2} ",
  6583. originFunc, rulesParsed, idx - idxStart) + e.Message);
  6584. }
  6585. finally
  6586. {
  6587. if (positionChanged)
  6588. {
  6589. if (part.ParentGroup.RootPart == part)
  6590. {
  6591. SceneObjectGroup parent = part.ParentGroup;
  6592. parent.UpdateGroupPosition(currentPosition);
  6593. }
  6594. else
  6595. {
  6596. part.OffsetPosition = currentPosition;
  6597. SceneObjectGroup parent = part.ParentGroup;
  6598. parent.HasGroupChanged = true;
  6599. parent.ScheduleGroupForTerseUpdate();
  6600. }
  6601. }
  6602. }
  6603. return null;
  6604. }
  6605. public LSL_String llStringToBase64(string str)
  6606. {
  6607. m_host.AddScriptLPS(1);
  6608. try
  6609. {
  6610. byte[] encData_byte = new byte[str.Length];
  6611. encData_byte = Util.UTF8.GetBytes(str);
  6612. string encodedData = Convert.ToBase64String(encData_byte);
  6613. return encodedData;
  6614. }
  6615. catch (Exception e)
  6616. {
  6617. throw new Exception("Error in base64Encode" + e.Message);
  6618. }
  6619. }
  6620. public LSL_String llBase64ToString(string str)
  6621. {
  6622. m_host.AddScriptLPS(1);
  6623. try
  6624. {
  6625. return Util.Base64ToString(str);
  6626. }
  6627. catch (Exception e)
  6628. {
  6629. throw new Exception("Error in base64Decode" + e.Message);
  6630. }
  6631. }
  6632. public LSL_String llXorBase64Strings(string str1, string str2)
  6633. {
  6634. m_host.AddScriptLPS(1);
  6635. Deprecated("llXorBase64Strings");
  6636. ScriptSleep(300);
  6637. return String.Empty;
  6638. }
  6639. public void llRemoteDataSetRegion()
  6640. {
  6641. m_host.AddScriptLPS(1);
  6642. Deprecated("llRemoteDataSetRegion");
  6643. }
  6644. public LSL_Float llLog10(double val)
  6645. {
  6646. m_host.AddScriptLPS(1);
  6647. return (double)Math.Log10(val);
  6648. }
  6649. public LSL_Float llLog(double val)
  6650. {
  6651. m_host.AddScriptLPS(1);
  6652. return (double)Math.Log(val);
  6653. }
  6654. public LSL_List llGetAnimationList(string id)
  6655. {
  6656. m_host.AddScriptLPS(1);
  6657. LSL_List l = new LSL_List();
  6658. ScenePresence av = World.GetScenePresence((UUID)id);
  6659. if (av == null || av.IsChildAgent) // only if in the region
  6660. return l;
  6661. UUID[] anims;
  6662. anims = av.Animator.GetAnimationArray();
  6663. foreach (UUID foo in anims)
  6664. l.Add(new LSL_Key(foo.ToString()));
  6665. return l;
  6666. }
  6667. public void llSetParcelMusicURL(string url)
  6668. {
  6669. m_host.AddScriptLPS(1);
  6670. ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
  6671. if (land.LandData.OwnerID != m_host.OwnerID)
  6672. return;
  6673. land.SetMusicUrl(url);
  6674. ScriptSleep(2000);
  6675. }
  6676. public LSL_String llGetParcelMusicURL()
  6677. {
  6678. m_host.AddScriptLPS(1);
  6679. ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
  6680. if (land.LandData.OwnerID != m_host.OwnerID)
  6681. return String.Empty;
  6682. return land.GetMusicUrl();
  6683. }
  6684. public LSL_Vector llGetRootPosition()
  6685. {
  6686. m_host.AddScriptLPS(1);
  6687. return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y,
  6688. m_host.ParentGroup.AbsolutePosition.Z);
  6689. }
  6690. /// <summary>
  6691. /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetRot
  6692. /// http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
  6693. /// Also tested in sl in regards to the behaviour in attachments/mouselook
  6694. /// In the root prim:-
  6695. /// Returns the object rotation if not attached
  6696. /// Returns the avatars rotation if attached
  6697. /// Returns the camera rotation if attached and the avatar is in mouselook
  6698. /// </summary>
  6699. public LSL_Rotation llGetRootRotation()
  6700. {
  6701. m_host.AddScriptLPS(1);
  6702. Quaternion q;
  6703. if (m_host.ParentGroup.AttachmentPoint != 0)
  6704. {
  6705. ScenePresence avatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
  6706. if (avatar != null)
  6707. if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
  6708. q = avatar.CameraRotation; // Mouselook
  6709. else
  6710. q = avatar.Rotation; // Currently infrequently updated so may be inaccurate
  6711. else
  6712. q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
  6713. }
  6714. else
  6715. q = m_host.ParentGroup.GroupRotation; // just the group rotation
  6716. return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
  6717. }
  6718. public LSL_String llGetObjectDesc()
  6719. {
  6720. return m_host.Description!=null?m_host.Description:String.Empty;
  6721. }
  6722. public void llSetObjectDesc(string desc)
  6723. {
  6724. m_host.AddScriptLPS(1);
  6725. m_host.Description = desc!=null?desc:String.Empty;
  6726. }
  6727. public LSL_String llGetCreator()
  6728. {
  6729. m_host.AddScriptLPS(1);
  6730. return m_host.CreatorID.ToString();
  6731. }
  6732. public LSL_String llGetTimestamp()
  6733. {
  6734. m_host.AddScriptLPS(1);
  6735. return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
  6736. }
  6737. public LSL_Integer llGetNumberOfPrims()
  6738. {
  6739. m_host.AddScriptLPS(1);
  6740. return m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount();
  6741. }
  6742. /// <summary>
  6743. /// A partial implementation.
  6744. /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox
  6745. /// So far only valid for standing/flying/ground sitting avatars and single prim objects.
  6746. /// If the object has multiple prims and/or a sitting avatar then the bounding
  6747. /// box is for the root prim only.
  6748. /// </summary>
  6749. public LSL_List llGetBoundingBox(string obj)
  6750. {
  6751. m_host.AddScriptLPS(1);
  6752. UUID objID = UUID.Zero;
  6753. LSL_List result = new LSL_List();
  6754. if (!UUID.TryParse(obj, out objID))
  6755. {
  6756. result.Add(new LSL_Vector());
  6757. result.Add(new LSL_Vector());
  6758. return result;
  6759. }
  6760. ScenePresence presence = World.GetScenePresence(objID);
  6761. if (presence != null)
  6762. {
  6763. if (presence.ParentID == 0) // not sat on an object
  6764. {
  6765. LSL_Vector lower;
  6766. LSL_Vector upper;
  6767. if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID
  6768. == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
  6769. {
  6770. // This is for ground sitting avatars
  6771. float height = presence.Appearance.AvatarHeight / 2.66666667f;
  6772. lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
  6773. upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
  6774. }
  6775. else
  6776. {
  6777. // This is for standing/flying avatars
  6778. float height = presence.Appearance.AvatarHeight / 2.0f;
  6779. lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
  6780. upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
  6781. }
  6782. result.Add(lower);
  6783. result.Add(upper);
  6784. return result;
  6785. }
  6786. else
  6787. {
  6788. // sitting on an object so we need the bounding box of that
  6789. // which should include the avatar so set the UUID to the
  6790. // UUID of the object the avatar is sat on and allow it to fall through
  6791. // to processing an object
  6792. SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID);
  6793. objID = p.UUID;
  6794. }
  6795. }
  6796. SceneObjectPart part = World.GetSceneObjectPart(objID);
  6797. // Currently only works for single prims without a sitting avatar
  6798. if (part != null)
  6799. {
  6800. Vector3 halfSize = part.Scale / 2.0f;
  6801. LSL_Vector lower = (new LSL_Vector(halfSize)) * -1.0f;
  6802. LSL_Vector upper = new LSL_Vector(halfSize);
  6803. result.Add(lower);
  6804. result.Add(upper);
  6805. return result;
  6806. }
  6807. // Not found so return empty values
  6808. result.Add(new LSL_Vector());
  6809. result.Add(new LSL_Vector());
  6810. return result;
  6811. }
  6812. public LSL_Vector llGetGeometricCenter()
  6813. {
  6814. return new LSL_Vector(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z);
  6815. }
  6816. public LSL_List llGetPrimitiveParams(LSL_List rules)
  6817. {
  6818. m_host.AddScriptLPS(1);
  6819. LSL_List result = new LSL_List();
  6820. LSL_List remaining = GetPrimParams(m_host, rules, ref result);
  6821. while (remaining != null && remaining.Length > 2)
  6822. {
  6823. int linknumber = remaining.GetLSLIntegerItem(0);
  6824. rules = remaining.GetSublist(1, -1);
  6825. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  6826. foreach (SceneObjectPart part in parts)
  6827. remaining = GetPrimParams(part, rules, ref result);
  6828. }
  6829. return result;
  6830. }
  6831. public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules)
  6832. {
  6833. m_host.AddScriptLPS(1);
  6834. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  6835. LSL_List res = new LSL_List();
  6836. LSL_List remaining = null;
  6837. foreach (SceneObjectPart part in parts)
  6838. {
  6839. remaining = GetPrimParams(part, rules, ref res);
  6840. }
  6841. while (remaining != null && remaining.Length > 2)
  6842. {
  6843. linknumber = remaining.GetLSLIntegerItem(0);
  6844. rules = remaining.GetSublist(1, -1);
  6845. parts = GetLinkParts(linknumber);
  6846. foreach (SceneObjectPart part in parts)
  6847. remaining = GetPrimParams(part, rules, ref res);
  6848. }
  6849. return res;
  6850. }
  6851. public LSL_List GetPrimParams(SceneObjectPart part, LSL_List rules, ref LSL_List res)
  6852. {
  6853. int idx=0;
  6854. while (idx < rules.Length)
  6855. {
  6856. int code=(int)rules.GetLSLIntegerItem(idx++);
  6857. int remain=rules.Length-idx;
  6858. switch (code)
  6859. {
  6860. case (int)ScriptBaseClass.PRIM_MATERIAL:
  6861. res.Add(new LSL_Integer(part.Material));
  6862. break;
  6863. case (int)ScriptBaseClass.PRIM_PHYSICS:
  6864. if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) != 0)
  6865. res.Add(new LSL_Integer(1));
  6866. else
  6867. res.Add(new LSL_Integer(0));
  6868. break;
  6869. case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
  6870. if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) != 0)
  6871. res.Add(new LSL_Integer(1));
  6872. else
  6873. res.Add(new LSL_Integer(0));
  6874. break;
  6875. case (int)ScriptBaseClass.PRIM_PHANTOM:
  6876. if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
  6877. res.Add(new LSL_Integer(1));
  6878. else
  6879. res.Add(new LSL_Integer(0));
  6880. break;
  6881. case (int)ScriptBaseClass.PRIM_POSITION:
  6882. LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X,
  6883. part.AbsolutePosition.Y,
  6884. part.AbsolutePosition.Z);
  6885. // For some reason, the part.AbsolutePosition.* values do not change if the
  6886. // linkset is rotated; they always reflect the child prim's world position
  6887. // as though the linkset is unrotated. This is incompatible behavior with SL's
  6888. // implementation, so will break scripts imported from there (not to mention it
  6889. // makes it more difficult to determine a child prim's actual inworld position).
  6890. if (part.ParentID != 0)
  6891. v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition();
  6892. res.Add(v);
  6893. break;
  6894. case (int)ScriptBaseClass.PRIM_SIZE:
  6895. res.Add(new LSL_Vector(part.Scale.X,
  6896. part.Scale.Y,
  6897. part.Scale.Z));
  6898. break;
  6899. case (int)ScriptBaseClass.PRIM_ROTATION:
  6900. res.Add(GetPartRot(part));
  6901. break;
  6902. case (int)ScriptBaseClass.PRIM_TYPE:
  6903. // implementing box
  6904. PrimitiveBaseShape Shape = part.Shape;
  6905. int primType = (int)part.GetPrimType();
  6906. res.Add(new LSL_Integer(primType));
  6907. double topshearx = (double)(sbyte)Shape.PathShearX / 100.0; // Fix negative values for PathShearX
  6908. double topsheary = (double)(sbyte)Shape.PathShearY / 100.0; // and PathShearY.
  6909. switch (primType)
  6910. {
  6911. case ScriptBaseClass.PRIM_TYPE_BOX:
  6912. case ScriptBaseClass.PRIM_TYPE_CYLINDER:
  6913. case ScriptBaseClass.PRIM_TYPE_PRISM:
  6914. res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
  6915. res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
  6916. res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
  6917. res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
  6918. res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
  6919. res.Add(new LSL_Vector(topshearx, topsheary, 0));
  6920. break;
  6921. case ScriptBaseClass.PRIM_TYPE_SPHERE:
  6922. res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
  6923. res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
  6924. res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
  6925. res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
  6926. res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
  6927. break;
  6928. case ScriptBaseClass.PRIM_TYPE_SCULPT:
  6929. res.Add(Shape.SculptTexture.ToString());
  6930. res.Add(new LSL_Integer(Shape.SculptType));
  6931. break;
  6932. case ScriptBaseClass.PRIM_TYPE_RING:
  6933. case ScriptBaseClass.PRIM_TYPE_TUBE:
  6934. case ScriptBaseClass.PRIM_TYPE_TORUS:
  6935. // holeshape
  6936. res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
  6937. // cut
  6938. res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
  6939. // hollow
  6940. res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
  6941. // twist
  6942. res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
  6943. // vector holesize
  6944. res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
  6945. // vector topshear
  6946. res.Add(new LSL_Vector(topshearx, topsheary, 0));
  6947. // vector profilecut
  6948. res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
  6949. // vector tapera
  6950. res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
  6951. // float revolutions
  6952. res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d);
  6953. // Slightly inaccurate, because an unsigned byte is being used to represent
  6954. // the entire range of floating-point values from 1.0 through 4.0 (which is how
  6955. // SL does it).
  6956. //
  6957. // Using these formulas to store and retrieve PathRevolutions, it is not
  6958. // possible to use all values between 1.00 and 4.00. For instance, you can't
  6959. // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you
  6960. // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them
  6961. // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar
  6962. // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11.
  6963. // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value
  6964. // such as 1.10. So, SL must store and retreive the actual user input rather
  6965. // than only storing the encoded value.
  6966. // float radiusoffset
  6967. res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0));
  6968. // float skew
  6969. res.Add(new LSL_Float(Shape.PathSkew / 100.0));
  6970. break;
  6971. }
  6972. break;
  6973. case (int)ScriptBaseClass.PRIM_TEXTURE:
  6974. if (remain < 1)
  6975. return null;
  6976. int face = (int)rules.GetLSLIntegerItem(idx++);
  6977. Primitive.TextureEntry tex = part.Shape.Textures;
  6978. if (face == ScriptBaseClass.ALL_SIDES)
  6979. {
  6980. for (face = 0 ; face < GetNumberOfSides(part); face++)
  6981. {
  6982. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  6983. res.Add(new LSL_String(texface.TextureID.ToString()));
  6984. res.Add(new LSL_Vector(texface.RepeatU,
  6985. texface.RepeatV,
  6986. 0));
  6987. res.Add(new LSL_Vector(texface.OffsetU,
  6988. texface.OffsetV,
  6989. 0));
  6990. res.Add(new LSL_Float(texface.Rotation));
  6991. }
  6992. }
  6993. else
  6994. {
  6995. if (face >= 0 && face < GetNumberOfSides(part))
  6996. {
  6997. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  6998. res.Add(new LSL_String(texface.TextureID.ToString()));
  6999. res.Add(new LSL_Vector(texface.RepeatU,
  7000. texface.RepeatV,
  7001. 0));
  7002. res.Add(new LSL_Vector(texface.OffsetU,
  7003. texface.OffsetV,
  7004. 0));
  7005. res.Add(new LSL_Float(texface.Rotation));
  7006. }
  7007. }
  7008. break;
  7009. case (int)ScriptBaseClass.PRIM_COLOR:
  7010. if (remain < 1)
  7011. return null;
  7012. face=(int)rules.GetLSLIntegerItem(idx++);
  7013. tex = part.Shape.Textures;
  7014. Color4 texcolor;
  7015. if (face == ScriptBaseClass.ALL_SIDES)
  7016. {
  7017. for (face = 0 ; face < GetNumberOfSides(part); face++)
  7018. {
  7019. texcolor = tex.GetFace((uint)face).RGBA;
  7020. res.Add(new LSL_Vector(texcolor.R,
  7021. texcolor.G,
  7022. texcolor.B));
  7023. res.Add(new LSL_Float(texcolor.A));
  7024. }
  7025. }
  7026. else
  7027. {
  7028. texcolor = tex.GetFace((uint)face).RGBA;
  7029. res.Add(new LSL_Vector(texcolor.R,
  7030. texcolor.G,
  7031. texcolor.B));
  7032. res.Add(new LSL_Float(texcolor.A));
  7033. }
  7034. break;
  7035. case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
  7036. if (remain < 1)
  7037. return null;
  7038. face=(int)rules.GetLSLIntegerItem(idx++);
  7039. tex = part.Shape.Textures;
  7040. if (face == ScriptBaseClass.ALL_SIDES)
  7041. {
  7042. for (face = 0; face < GetNumberOfSides(part); face++)
  7043. {
  7044. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  7045. // Convert Shininess to PRIM_SHINY_*
  7046. res.Add(new LSL_Integer((uint)texface.Shiny >> 6));
  7047. // PRIM_BUMP_*
  7048. res.Add(new LSL_Integer((int)texface.Bump));
  7049. }
  7050. }
  7051. else
  7052. {
  7053. if (face >= 0 && face < GetNumberOfSides(part))
  7054. {
  7055. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  7056. // Convert Shininess to PRIM_SHINY_*
  7057. res.Add(new LSL_Integer((uint)texface.Shiny >> 6));
  7058. // PRIM_BUMP_*
  7059. res.Add(new LSL_Integer((int)texface.Bump));
  7060. }
  7061. }
  7062. break;
  7063. case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
  7064. if (remain < 1)
  7065. return null;
  7066. face=(int)rules.GetLSLIntegerItem(idx++);
  7067. tex = part.Shape.Textures;
  7068. if (face == ScriptBaseClass.ALL_SIDES)
  7069. {
  7070. for (face = 0; face < GetNumberOfSides(part); face++)
  7071. {
  7072. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  7073. res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0));
  7074. }
  7075. }
  7076. else
  7077. {
  7078. if (face >= 0 && face < GetNumberOfSides(part))
  7079. {
  7080. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  7081. res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0));
  7082. }
  7083. }
  7084. break;
  7085. case (int)ScriptBaseClass.PRIM_FLEXIBLE:
  7086. PrimitiveBaseShape shape = part.Shape;
  7087. if (shape.FlexiEntry)
  7088. res.Add(new LSL_Integer(1)); // active
  7089. else
  7090. res.Add(new LSL_Integer(0));
  7091. res.Add(new LSL_Integer(shape.FlexiSoftness));// softness
  7092. res.Add(new LSL_Float(shape.FlexiGravity)); // gravity
  7093. res.Add(new LSL_Float(shape.FlexiDrag)); // friction
  7094. res.Add(new LSL_Float(shape.FlexiWind)); // wind
  7095. res.Add(new LSL_Float(shape.FlexiTension)); // tension
  7096. res.Add(new LSL_Vector(shape.FlexiForceX, // force
  7097. shape.FlexiForceY,
  7098. shape.FlexiForceZ));
  7099. break;
  7100. case (int)ScriptBaseClass.PRIM_TEXGEN:
  7101. if (remain < 1)
  7102. return null;
  7103. face=(int)rules.GetLSLIntegerItem(idx++);
  7104. tex = part.Shape.Textures;
  7105. if (face == ScriptBaseClass.ALL_SIDES)
  7106. {
  7107. for (face = 0; face < GetNumberOfSides(part); face++)
  7108. {
  7109. MappingType texgen = tex.GetFace((uint)face).TexMapType;
  7110. // Convert MappingType to PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR etc.
  7111. res.Add(new LSL_Integer((uint)texgen >> 1));
  7112. }
  7113. }
  7114. else
  7115. {
  7116. if (face >= 0 && face < GetNumberOfSides(part))
  7117. {
  7118. MappingType texgen = tex.GetFace((uint)face).TexMapType;
  7119. res.Add(new LSL_Integer((uint)texgen >> 1));
  7120. }
  7121. }
  7122. break;
  7123. case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
  7124. shape = part.Shape;
  7125. if (shape.LightEntry)
  7126. res.Add(new LSL_Integer(1)); // active
  7127. else
  7128. res.Add(new LSL_Integer(0));
  7129. res.Add(new LSL_Vector(shape.LightColorR, // color
  7130. shape.LightColorG,
  7131. shape.LightColorB));
  7132. res.Add(new LSL_Float(shape.LightIntensity)); // intensity
  7133. res.Add(new LSL_Float(shape.LightRadius)); // radius
  7134. res.Add(new LSL_Float(shape.LightFalloff)); // falloff
  7135. break;
  7136. case (int)ScriptBaseClass.PRIM_GLOW:
  7137. if (remain < 1)
  7138. return null;
  7139. face=(int)rules.GetLSLIntegerItem(idx++);
  7140. tex = part.Shape.Textures;
  7141. if (face == ScriptBaseClass.ALL_SIDES)
  7142. {
  7143. for (face = 0; face < GetNumberOfSides(part); face++)
  7144. {
  7145. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  7146. res.Add(new LSL_Float(texface.Glow));
  7147. }
  7148. }
  7149. else
  7150. {
  7151. if (face >= 0 && face < GetNumberOfSides(part))
  7152. {
  7153. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  7154. res.Add(new LSL_Float(texface.Glow));
  7155. }
  7156. }
  7157. break;
  7158. case (int)ScriptBaseClass.PRIM_TEXT:
  7159. Color4 textColor = part.GetTextColor();
  7160. res.Add(new LSL_String(part.Text));
  7161. res.Add(new LSL_Vector(textColor.R,
  7162. textColor.G,
  7163. textColor.B));
  7164. res.Add(new LSL_Float(textColor.A));
  7165. break;
  7166. case (int)ScriptBaseClass.PRIM_NAME:
  7167. res.Add(new LSL_String(part.Name));
  7168. break;
  7169. case (int)ScriptBaseClass.PRIM_DESC:
  7170. res.Add(new LSL_String(part.Description));
  7171. break;
  7172. case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
  7173. res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W));
  7174. break;
  7175. case (int)ScriptBaseClass.PRIM_POS_LOCAL:
  7176. res.Add(new LSL_Vector(GetPartLocalPos(part)));
  7177. break;
  7178. case (int)ScriptBaseClass.PRIM_SLICE:
  7179. PrimType prim_type = part.GetPrimType();
  7180. bool useProfileBeginEnd = (prim_type == PrimType.SPHERE || prim_type == PrimType.TORUS || prim_type == PrimType.TUBE || prim_type == PrimType.RING);
  7181. res.Add(new LSL_Vector(
  7182. (useProfileBeginEnd ? part.Shape.ProfileBegin : part.Shape.PathBegin) / 50000.0,
  7183. 1 - (useProfileBeginEnd ? part.Shape.ProfileEnd : part.Shape.PathEnd) / 50000.0,
  7184. 0
  7185. ));
  7186. break;
  7187. case (int)ScriptBaseClass.PRIM_LINK_TARGET:
  7188. if(remain < 3)
  7189. return null;
  7190. return rules.GetSublist(idx, -1);
  7191. }
  7192. }
  7193. return null;
  7194. }
  7195. public LSL_List llGetPrimMediaParams(int face, LSL_List rules)
  7196. {
  7197. m_host.AddScriptLPS(1);
  7198. ScriptSleep(1000);
  7199. return GetPrimMediaParams(m_host, face, rules);
  7200. }
  7201. public LSL_List llGetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules)
  7202. {
  7203. m_host.AddScriptLPS(1);
  7204. ScriptSleep(1000);
  7205. if (link == ScriptBaseClass.LINK_ROOT)
  7206. return GetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules);
  7207. else if (link == ScriptBaseClass.LINK_THIS)
  7208. return GetPrimMediaParams(m_host, face, rules);
  7209. else
  7210. {
  7211. SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
  7212. if (null != part)
  7213. return GetPrimMediaParams(part, face, rules);
  7214. }
  7215. return new LSL_List();
  7216. }
  7217. private LSL_List GetPrimMediaParams(SceneObjectPart part, int face, LSL_List rules)
  7218. {
  7219. // LSL Spec http://wiki.secondlife.com/wiki/LlGetPrimMediaParams says to fail silently if face is invalid
  7220. // TODO: Need to correctly handle case where a face has no media (which gives back an empty list).
  7221. // Assuming silently fail means give back an empty list. Ideally, need to check this.
  7222. if (face < 0 || face > part.GetNumberOfSides() - 1)
  7223. return new LSL_List();
  7224. IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
  7225. if (null == module)
  7226. return new LSL_List();
  7227. MediaEntry me = module.GetMediaEntry(part, face);
  7228. // As per http://wiki.secondlife.com/wiki/LlGetPrimMediaParams
  7229. if (null == me)
  7230. return new LSL_List();
  7231. LSL_List res = new LSL_List();
  7232. for (int i = 0; i < rules.Length; i++)
  7233. {
  7234. int code = (int)rules.GetLSLIntegerItem(i);
  7235. switch (code)
  7236. {
  7237. case ScriptBaseClass.PRIM_MEDIA_ALT_IMAGE_ENABLE:
  7238. // Not implemented
  7239. res.Add(new LSL_Integer(0));
  7240. break;
  7241. case ScriptBaseClass.PRIM_MEDIA_CONTROLS:
  7242. if (me.Controls == MediaControls.Standard)
  7243. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MEDIA_CONTROLS_STANDARD));
  7244. else
  7245. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MEDIA_CONTROLS_MINI));
  7246. break;
  7247. case ScriptBaseClass.PRIM_MEDIA_CURRENT_URL:
  7248. res.Add(new LSL_String(me.CurrentURL));
  7249. break;
  7250. case ScriptBaseClass.PRIM_MEDIA_HOME_URL:
  7251. res.Add(new LSL_String(me.HomeURL));
  7252. break;
  7253. case ScriptBaseClass.PRIM_MEDIA_AUTO_LOOP:
  7254. res.Add(me.AutoLoop ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  7255. break;
  7256. case ScriptBaseClass.PRIM_MEDIA_AUTO_PLAY:
  7257. res.Add(me.AutoPlay ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  7258. break;
  7259. case ScriptBaseClass.PRIM_MEDIA_AUTO_SCALE:
  7260. res.Add(me.AutoScale ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  7261. break;
  7262. case ScriptBaseClass.PRIM_MEDIA_AUTO_ZOOM:
  7263. res.Add(me.AutoZoom ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  7264. break;
  7265. case ScriptBaseClass.PRIM_MEDIA_FIRST_CLICK_INTERACT:
  7266. res.Add(me.InteractOnFirstClick ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  7267. break;
  7268. case ScriptBaseClass.PRIM_MEDIA_WIDTH_PIXELS:
  7269. res.Add(new LSL_Integer(me.Width));
  7270. break;
  7271. case ScriptBaseClass.PRIM_MEDIA_HEIGHT_PIXELS:
  7272. res.Add(new LSL_Integer(me.Height));
  7273. break;
  7274. case ScriptBaseClass.PRIM_MEDIA_WHITELIST_ENABLE:
  7275. res.Add(me.EnableWhiteList ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  7276. break;
  7277. case ScriptBaseClass.PRIM_MEDIA_WHITELIST:
  7278. string[] urls = (string[])me.WhiteList.Clone();
  7279. for (int j = 0; j < urls.Length; j++)
  7280. urls[j] = Uri.EscapeDataString(urls[j]);
  7281. res.Add(new LSL_String(string.Join(", ", urls)));
  7282. break;
  7283. case ScriptBaseClass.PRIM_MEDIA_PERMS_INTERACT:
  7284. res.Add(new LSL_Integer((int)me.InteractPermissions));
  7285. break;
  7286. case ScriptBaseClass.PRIM_MEDIA_PERMS_CONTROL:
  7287. res.Add(new LSL_Integer((int)me.ControlPermissions));
  7288. break;
  7289. default: return ScriptBaseClass.LSL_STATUS_MALFORMED_PARAMS;
  7290. }
  7291. }
  7292. return res;
  7293. }
  7294. public LSL_Integer llSetPrimMediaParams(LSL_Integer face, LSL_List rules)
  7295. {
  7296. m_host.AddScriptLPS(1);
  7297. ScriptSleep(1000);
  7298. return SetPrimMediaParams(m_host, face, rules);
  7299. }
  7300. public LSL_Integer llSetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules)
  7301. {
  7302. m_host.AddScriptLPS(1);
  7303. ScriptSleep(1000);
  7304. if (link == ScriptBaseClass.LINK_ROOT)
  7305. return SetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules);
  7306. else if (link == ScriptBaseClass.LINK_THIS)
  7307. return SetPrimMediaParams(m_host, face, rules);
  7308. else
  7309. {
  7310. SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
  7311. if (null != part)
  7312. return SetPrimMediaParams(part, face, rules);
  7313. }
  7314. return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
  7315. }
  7316. private LSL_Integer SetPrimMediaParams(SceneObjectPart part, LSL_Integer face, LSL_List rules)
  7317. {
  7318. // LSL Spec http://wiki.secondlife.com/wiki/LlSetPrimMediaParams says to fail silently if face is invalid
  7319. // Assuming silently fail means sending back LSL_STATUS_OK. Ideally, need to check this.
  7320. // Don't perform the media check directly
  7321. if (face < 0 || face > part.GetNumberOfSides() - 1)
  7322. return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
  7323. IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
  7324. if (null == module)
  7325. return ScriptBaseClass.LSL_STATUS_NOT_SUPPORTED;
  7326. MediaEntry me = module.GetMediaEntry(part, face);
  7327. if (null == me)
  7328. me = new MediaEntry();
  7329. int i = 0;
  7330. while (i < rules.Length - 1)
  7331. {
  7332. int code = rules.GetLSLIntegerItem(i++);
  7333. switch (code)
  7334. {
  7335. case ScriptBaseClass.PRIM_MEDIA_ALT_IMAGE_ENABLE:
  7336. me.EnableAlterntiveImage = (rules.GetLSLIntegerItem(i++) != 0 ? true : false);
  7337. break;
  7338. case ScriptBaseClass.PRIM_MEDIA_CONTROLS:
  7339. int v = rules.GetLSLIntegerItem(i++);
  7340. if (ScriptBaseClass.PRIM_MEDIA_CONTROLS_STANDARD == v)
  7341. me.Controls = MediaControls.Standard;
  7342. else
  7343. me.Controls = MediaControls.Mini;
  7344. break;
  7345. case ScriptBaseClass.PRIM_MEDIA_CURRENT_URL:
  7346. me.CurrentURL = rules.GetLSLStringItem(i++);
  7347. break;
  7348. case ScriptBaseClass.PRIM_MEDIA_HOME_URL:
  7349. me.HomeURL = rules.GetLSLStringItem(i++);
  7350. break;
  7351. case ScriptBaseClass.PRIM_MEDIA_AUTO_LOOP:
  7352. me.AutoLoop = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
  7353. break;
  7354. case ScriptBaseClass.PRIM_MEDIA_AUTO_PLAY:
  7355. me.AutoPlay = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
  7356. break;
  7357. case ScriptBaseClass.PRIM_MEDIA_AUTO_SCALE:
  7358. me.AutoScale = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
  7359. break;
  7360. case ScriptBaseClass.PRIM_MEDIA_AUTO_ZOOM:
  7361. me.AutoZoom = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
  7362. break;
  7363. case ScriptBaseClass.PRIM_MEDIA_FIRST_CLICK_INTERACT:
  7364. me.InteractOnFirstClick = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
  7365. break;
  7366. case ScriptBaseClass.PRIM_MEDIA_WIDTH_PIXELS:
  7367. me.Width = (int)rules.GetLSLIntegerItem(i++);
  7368. break;
  7369. case ScriptBaseClass.PRIM_MEDIA_HEIGHT_PIXELS:
  7370. me.Height = (int)rules.GetLSLIntegerItem(i++);
  7371. break;
  7372. case ScriptBaseClass.PRIM_MEDIA_WHITELIST_ENABLE:
  7373. me.EnableWhiteList = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
  7374. break;
  7375. case ScriptBaseClass.PRIM_MEDIA_WHITELIST:
  7376. string[] rawWhiteListUrls = rules.GetLSLStringItem(i++).ToString().Split(new char[] { ',' });
  7377. List<string> whiteListUrls = new List<string>();
  7378. Array.ForEach(
  7379. rawWhiteListUrls, delegate(string rawUrl) { whiteListUrls.Add(rawUrl.Trim()); });
  7380. me.WhiteList = whiteListUrls.ToArray();
  7381. break;
  7382. case ScriptBaseClass.PRIM_MEDIA_PERMS_INTERACT:
  7383. me.InteractPermissions = (MediaPermission)(byte)(int)rules.GetLSLIntegerItem(i++);
  7384. break;
  7385. case ScriptBaseClass.PRIM_MEDIA_PERMS_CONTROL:
  7386. me.ControlPermissions = (MediaPermission)(byte)(int)rules.GetLSLIntegerItem(i++);
  7387. break;
  7388. default: return ScriptBaseClass.LSL_STATUS_MALFORMED_PARAMS;
  7389. }
  7390. }
  7391. module.SetMediaEntry(part, face, me);
  7392. return ScriptBaseClass.LSL_STATUS_OK;
  7393. }
  7394. public LSL_Integer llClearPrimMedia(LSL_Integer face)
  7395. {
  7396. m_host.AddScriptLPS(1);
  7397. ScriptSleep(1000);
  7398. return ClearPrimMedia(m_host, face);
  7399. }
  7400. public LSL_Integer llClearLinkMedia(LSL_Integer link, LSL_Integer face)
  7401. {
  7402. m_host.AddScriptLPS(1);
  7403. ScriptSleep(1000);
  7404. if (link == ScriptBaseClass.LINK_ROOT)
  7405. return ClearPrimMedia(m_host.ParentGroup.RootPart, face);
  7406. else if (link == ScriptBaseClass.LINK_THIS)
  7407. return ClearPrimMedia(m_host, face);
  7408. else
  7409. {
  7410. SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
  7411. if (null != part)
  7412. return ClearPrimMedia(part, face);
  7413. }
  7414. return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
  7415. }
  7416. private LSL_Integer ClearPrimMedia(SceneObjectPart part, LSL_Integer face)
  7417. {
  7418. // LSL Spec http://wiki.secondlife.com/wiki/LlClearPrimMedia says to fail silently if face is invalid
  7419. // Assuming silently fail means sending back LSL_STATUS_OK. Ideally, need to check this.
  7420. // FIXME: Don't perform the media check directly
  7421. if (face < 0 || face > part.GetNumberOfSides() - 1)
  7422. return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
  7423. IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
  7424. if (null == module)
  7425. return ScriptBaseClass.LSL_STATUS_NOT_SUPPORTED;
  7426. module.ClearMediaEntry(part, face);
  7427. return ScriptBaseClass.LSL_STATUS_OK;
  7428. }
  7429. // <remarks>
  7430. // <para>
  7431. // The .NET definition of base 64 is:
  7432. // <list>
  7433. // <item>
  7434. // Significant: A-Z a-z 0-9 + -
  7435. // </item>
  7436. // <item>
  7437. // Whitespace: \t \n \r ' '
  7438. // </item>
  7439. // <item>
  7440. // Valueless: =
  7441. // </item>
  7442. // <item>
  7443. // End-of-string: \0 or '=='
  7444. // </item>
  7445. // </list>
  7446. // </para>
  7447. // <para>
  7448. // Each point in a base-64 string represents
  7449. // a 6 bit value. A 32-bit integer can be
  7450. // represented using 6 characters (with some
  7451. // redundancy).
  7452. // </para>
  7453. // <para>
  7454. // LSL requires a base64 string to be 8
  7455. // characters in length. LSL also uses '/'
  7456. // rather than '-' (MIME compliant).
  7457. // </para>
  7458. // <para>
  7459. // RFC 1341 used as a reference (as specified
  7460. // by the SecondLife Wiki).
  7461. // </para>
  7462. // <para>
  7463. // SL do not record any kind of exception for
  7464. // these functions, so the string to integer
  7465. // conversion returns '0' if an invalid
  7466. // character is encountered during conversion.
  7467. // </para>
  7468. // <para>
  7469. // References
  7470. // <list>
  7471. // <item>
  7472. // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
  7473. // </item>
  7474. // <item>
  7475. // </item>
  7476. // </list>
  7477. // </para>
  7478. // </remarks>
  7479. // <summary>
  7480. // Table for converting 6-bit integers into
  7481. // base-64 characters
  7482. // </summary>
  7483. protected static readonly char[] i2ctable =
  7484. {
  7485. 'A','B','C','D','E','F','G','H',
  7486. 'I','J','K','L','M','N','O','P',
  7487. 'Q','R','S','T','U','V','W','X',
  7488. 'Y','Z',
  7489. 'a','b','c','d','e','f','g','h',
  7490. 'i','j','k','l','m','n','o','p',
  7491. 'q','r','s','t','u','v','w','x',
  7492. 'y','z',
  7493. '0','1','2','3','4','5','6','7',
  7494. '8','9',
  7495. '+','/'
  7496. };
  7497. // <summary>
  7498. // Table for converting base-64 characters
  7499. // into 6-bit integers.
  7500. // </summary>
  7501. protected static readonly int[] c2itable =
  7502. {
  7503. -1,-1,-1,-1,-1,-1,-1,-1, // 0x
  7504. -1,-1,-1,-1,-1,-1,-1,-1,
  7505. -1,-1,-1,-1,-1,-1,-1,-1, // 1x
  7506. -1,-1,-1,-1,-1,-1,-1,-1,
  7507. -1,-1,-1,-1,-1,-1,-1,-1, // 2x
  7508. -1,-1,-1,63,-1,-1,-1,64,
  7509. 53,54,55,56,57,58,59,60, // 3x
  7510. 61,62,-1,-1,-1,0,-1,-1,
  7511. -1,1,2,3,4,5,6,7, // 4x
  7512. 8,9,10,11,12,13,14,15,
  7513. 16,17,18,19,20,21,22,23, // 5x
  7514. 24,25,26,-1,-1,-1,-1,-1,
  7515. -1,27,28,29,30,31,32,33, // 6x
  7516. 34,35,36,37,38,39,40,41,
  7517. 42,43,44,45,46,47,48,49, // 7x
  7518. 50,51,52,-1,-1,-1,-1,-1,
  7519. -1,-1,-1,-1,-1,-1,-1,-1, // 8x
  7520. -1,-1,-1,-1,-1,-1,-1,-1,
  7521. -1,-1,-1,-1,-1,-1,-1,-1, // 9x
  7522. -1,-1,-1,-1,-1,-1,-1,-1,
  7523. -1,-1,-1,-1,-1,-1,-1,-1, // Ax
  7524. -1,-1,-1,-1,-1,-1,-1,-1,
  7525. -1,-1,-1,-1,-1,-1,-1,-1, // Bx
  7526. -1,-1,-1,-1,-1,-1,-1,-1,
  7527. -1,-1,-1,-1,-1,-1,-1,-1, // Cx
  7528. -1,-1,-1,-1,-1,-1,-1,-1,
  7529. -1,-1,-1,-1,-1,-1,-1,-1, // Dx
  7530. -1,-1,-1,-1,-1,-1,-1,-1,
  7531. -1,-1,-1,-1,-1,-1,-1,-1, // Ex
  7532. -1,-1,-1,-1,-1,-1,-1,-1,
  7533. -1,-1,-1,-1,-1,-1,-1,-1, // Fx
  7534. -1,-1,-1,-1,-1,-1,-1,-1
  7535. };
  7536. // <summary>
  7537. // Converts a 32-bit integer into a Base64
  7538. // character string. Base64 character strings
  7539. // are always 8 characters long. All iinteger
  7540. // values are acceptable.
  7541. // </summary>
  7542. // <param name="number">
  7543. // 32-bit integer to be converted.
  7544. // </param>
  7545. // <returns>
  7546. // 8 character string. The 1st six characters
  7547. // contain the encoded number, the last two
  7548. // characters are padded with "=".
  7549. // </returns>
  7550. public LSL_String llIntegerToBase64(int number)
  7551. {
  7552. // uninitialized string
  7553. char[] imdt = new char[8];
  7554. m_host.AddScriptLPS(1);
  7555. // Manually unroll the loop
  7556. imdt[7] = '=';
  7557. imdt[6] = '=';
  7558. imdt[5] = i2ctable[number<<4 & 0x3F];
  7559. imdt[4] = i2ctable[number>>2 & 0x3F];
  7560. imdt[3] = i2ctable[number>>8 & 0x3F];
  7561. imdt[2] = i2ctable[number>>14 & 0x3F];
  7562. imdt[1] = i2ctable[number>>20 & 0x3F];
  7563. imdt[0] = i2ctable[number>>26 & 0x3F];
  7564. return new string(imdt);
  7565. }
  7566. // <summary>
  7567. // Converts an eight character base-64 string
  7568. // into a 32-bit integer.
  7569. // </summary>
  7570. // <param name="str">
  7571. // 8 characters string to be converted. Other
  7572. // length strings return zero.
  7573. // </param>
  7574. // <returns>
  7575. // Returns an integer representing the
  7576. // encoded value providedint he 1st 6
  7577. // characters of the string.
  7578. // </returns>
  7579. // <remarks>
  7580. // This is coded to behave like LSL's
  7581. // implementation (I think), based upon the
  7582. // information available at the Wiki.
  7583. // If more than 8 characters are supplied,
  7584. // zero is returned.
  7585. // If a NULL string is supplied, zero will
  7586. // be returned.
  7587. // If fewer than 6 characters are supplied, then
  7588. // the answer will reflect a partial
  7589. // accumulation.
  7590. // <para>
  7591. // The 6-bit segments are
  7592. // extracted left-to-right in big-endian mode,
  7593. // which means that segment 6 only contains the
  7594. // two low-order bits of the 32 bit integer as
  7595. // its high order 2 bits. A short string therefore
  7596. // means loss of low-order information. E.g.
  7597. //
  7598. // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
  7599. // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
  7600. // |3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1| | | | | | | | | | |P|P|P|P|
  7601. // |1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|P|P|P|P|
  7602. // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
  7603. //
  7604. // </para>
  7605. // </remarks>
  7606. public LSL_Integer llBase64ToInteger(string str)
  7607. {
  7608. int number = 0;
  7609. int digit;
  7610. m_host.AddScriptLPS(1);
  7611. // Require a well-fromed base64 string
  7612. if (str.Length > 8)
  7613. return 0;
  7614. // The loop is unrolled in the interests
  7615. // of performance and simple necessity.
  7616. //
  7617. // MUST find 6 digits to be well formed
  7618. // -1 == invalid
  7619. // 0 == padding
  7620. if ((digit = c2itable[str[0]]) <= 0)
  7621. {
  7622. return digit < 0 ? (int)0 : number;
  7623. }
  7624. number += --digit<<26;
  7625. if ((digit = c2itable[str[1]]) <= 0)
  7626. {
  7627. return digit < 0 ? (int)0 : number;
  7628. }
  7629. number += --digit<<20;
  7630. if ((digit = c2itable[str[2]]) <= 0)
  7631. {
  7632. return digit < 0 ? (int)0 : number;
  7633. }
  7634. number += --digit<<14;
  7635. if ((digit = c2itable[str[3]]) <= 0)
  7636. {
  7637. return digit < 0 ? (int)0 : number;
  7638. }
  7639. number += --digit<<8;
  7640. if ((digit = c2itable[str[4]]) <= 0)
  7641. {
  7642. return digit < 0 ? (int)0 : number;
  7643. }
  7644. number += --digit<<2;
  7645. if ((digit = c2itable[str[5]]) <= 0)
  7646. {
  7647. return digit < 0 ? (int)0 : number;
  7648. }
  7649. number += --digit>>4;
  7650. // ignore trailing padding
  7651. return number;
  7652. }
  7653. public LSL_Float llGetGMTclock()
  7654. {
  7655. m_host.AddScriptLPS(1);
  7656. return DateTime.UtcNow.TimeOfDay.TotalSeconds;
  7657. }
  7658. public LSL_String llGetHTTPHeader(LSL_Key request_id, string header)
  7659. {
  7660. m_host.AddScriptLPS(1);
  7661. if (m_UrlModule != null)
  7662. return m_UrlModule.GetHttpHeader(new UUID(request_id), header);
  7663. return String.Empty;
  7664. }
  7665. public LSL_String llGetSimulatorHostname()
  7666. {
  7667. m_host.AddScriptLPS(1);
  7668. IUrlModule UrlModule = World.RequestModuleInterface<IUrlModule>();
  7669. return UrlModule.ExternalHostNameForLSL;
  7670. }
  7671. // <summary>
  7672. // Scan the string supplied in 'src' and
  7673. // tokenize it based upon two sets of
  7674. // tokenizers provided in two lists,
  7675. // separators and spacers.
  7676. // </summary>
  7677. //
  7678. // <remarks>
  7679. // Separators demarcate tokens and are
  7680. // elided as they are encountered. Spacers
  7681. // also demarcate tokens, but are themselves
  7682. // retained as tokens.
  7683. //
  7684. // Both separators and spacers may be arbitrarily
  7685. // long strings. i.e. ":::".
  7686. //
  7687. // The function returns an ordered list
  7688. // representing the tokens found in the supplied
  7689. // sources string. If two successive tokenizers
  7690. // are encountered, then a NULL entry is added
  7691. // to the list.
  7692. //
  7693. // It is a precondition that the source and
  7694. // toekizer lisst are non-null. If they are null,
  7695. // then a null pointer exception will be thrown
  7696. // while their lengths are being determined.
  7697. //
  7698. // A small amount of working memoryis required
  7699. // of approximately 8*#tokenizers.
  7700. //
  7701. // There are many ways in which this function
  7702. // can be implemented, this implementation is
  7703. // fairly naive and assumes that when the
  7704. // function is invooked with a short source
  7705. // string and/or short lists of tokenizers, then
  7706. // performance will not be an issue.
  7707. //
  7708. // In order to minimize the perofrmance
  7709. // effects of long strings, or large numbers
  7710. // of tokeizers, the function skips as far as
  7711. // possible whenever a toekenizer is found,
  7712. // and eliminates redundant tokenizers as soon
  7713. // as is possible.
  7714. //
  7715. // The implementation tries to avoid any copying
  7716. // of arrays or other objects.
  7717. // </remarks>
  7718. private LSL_List ParseString(string src, LSL_List separators, LSL_List spacers, bool keepNulls)
  7719. {
  7720. int beginning = 0;
  7721. int srclen = src.Length;
  7722. int seplen = separators.Length;
  7723. object[] separray = separators.Data;
  7724. int spclen = spacers.Length;
  7725. object[] spcarray = spacers.Data;
  7726. int mlen = seplen+spclen;
  7727. int[] offset = new int[mlen+1];
  7728. bool[] active = new bool[mlen];
  7729. int best;
  7730. int j;
  7731. // Initial capacity reduces resize cost
  7732. LSL_List tokens = new LSL_List();
  7733. // All entries are initially valid
  7734. for (int i = 0; i < mlen; i++)
  7735. active[i] = true;
  7736. offset[mlen] = srclen;
  7737. while (beginning < srclen)
  7738. {
  7739. best = mlen; // as bad as it gets
  7740. // Scan for separators
  7741. for (j = 0; j < seplen; j++)
  7742. {
  7743. if (separray[j].ToString() == String.Empty)
  7744. active[j] = false;
  7745. if (active[j])
  7746. {
  7747. // scan all of the markers
  7748. if ((offset[j] = src.IndexOf(separray[j].ToString(), beginning)) == -1)
  7749. {
  7750. // not present at all
  7751. active[j] = false;
  7752. }
  7753. else
  7754. {
  7755. // present and correct
  7756. if (offset[j] < offset[best])
  7757. {
  7758. // closest so far
  7759. best = j;
  7760. if (offset[best] == beginning)
  7761. break;
  7762. }
  7763. }
  7764. }
  7765. }
  7766. // Scan for spacers
  7767. if (offset[best] != beginning)
  7768. {
  7769. for (j = seplen; (j < mlen) && (offset[best] > beginning); j++)
  7770. {
  7771. if (spcarray[j-seplen].ToString() == String.Empty)
  7772. active[j] = false;
  7773. if (active[j])
  7774. {
  7775. // scan all of the markers
  7776. if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
  7777. {
  7778. // not present at all
  7779. active[j] = false;
  7780. }
  7781. else
  7782. {
  7783. // present and correct
  7784. if (offset[j] < offset[best])
  7785. {
  7786. // closest so far
  7787. best = j;
  7788. }
  7789. }
  7790. }
  7791. }
  7792. }
  7793. // This is the normal exit from the scanning loop
  7794. if (best == mlen)
  7795. {
  7796. // no markers were found on this pass
  7797. // so we're pretty much done
  7798. if ((keepNulls) || ((!keepNulls) && (srclen - beginning) > 0))
  7799. tokens.Add(new LSL_String(src.Substring(beginning, srclen - beginning)));
  7800. break;
  7801. }
  7802. // Otherwise we just add the newly delimited token
  7803. // and recalculate where the search should continue.
  7804. if ((keepNulls) || ((!keepNulls) && (offset[best] - beginning) > 0))
  7805. tokens.Add(new LSL_String(src.Substring(beginning,offset[best]-beginning)));
  7806. if (best < seplen)
  7807. {
  7808. beginning = offset[best] + (separray[best].ToString()).Length;
  7809. }
  7810. else
  7811. {
  7812. beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
  7813. string str = spcarray[best - seplen].ToString();
  7814. if ((keepNulls) || ((!keepNulls) && (str.Length > 0)))
  7815. tokens.Add(new LSL_String(str));
  7816. }
  7817. }
  7818. // This an awkward an not very intuitive boundary case. If the
  7819. // last substring is a tokenizer, then there is an implied trailing
  7820. // null list entry. Hopefully the single comparison will not be too
  7821. // arduous. Alternatively the 'break' could be replced with a return
  7822. // but that's shabby programming.
  7823. if ((beginning == srclen) && (keepNulls))
  7824. {
  7825. if (srclen != 0)
  7826. tokens.Add(new LSL_String(""));
  7827. }
  7828. return tokens;
  7829. }
  7830. public LSL_List llParseString2List(string src, LSL_List separators, LSL_List spacers)
  7831. {
  7832. m_host.AddScriptLPS(1);
  7833. return this.ParseString(src, separators, spacers, false);
  7834. }
  7835. public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
  7836. {
  7837. m_host.AddScriptLPS(1);
  7838. return this.ParseString(src, separators, spacers, true);
  7839. }
  7840. public LSL_Integer llGetObjectPermMask(int mask)
  7841. {
  7842. m_host.AddScriptLPS(1);
  7843. int permmask = 0;
  7844. if (mask == ScriptBaseClass.MASK_BASE)//0
  7845. {
  7846. permmask = (int)m_host.BaseMask;
  7847. }
  7848. else if (mask == ScriptBaseClass.MASK_OWNER)//1
  7849. {
  7850. permmask = (int)m_host.OwnerMask;
  7851. }
  7852. else if (mask == ScriptBaseClass.MASK_GROUP)//2
  7853. {
  7854. permmask = (int)m_host.GroupMask;
  7855. }
  7856. else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
  7857. {
  7858. permmask = (int)m_host.EveryoneMask;
  7859. }
  7860. else if (mask == ScriptBaseClass.MASK_NEXT)//4
  7861. {
  7862. permmask = (int)m_host.NextOwnerMask;
  7863. }
  7864. return permmask;
  7865. }
  7866. public void llSetObjectPermMask(int mask, int value)
  7867. {
  7868. m_host.AddScriptLPS(1);
  7869. if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false))
  7870. {
  7871. if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID))
  7872. {
  7873. if (mask == ScriptBaseClass.MASK_BASE)//0
  7874. {
  7875. m_host.BaseMask = (uint)value;
  7876. }
  7877. else if (mask == ScriptBaseClass.MASK_OWNER)//1
  7878. {
  7879. m_host.OwnerMask = (uint)value;
  7880. }
  7881. else if (mask == ScriptBaseClass.MASK_GROUP)//2
  7882. {
  7883. m_host.GroupMask = (uint)value;
  7884. }
  7885. else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
  7886. {
  7887. m_host.EveryoneMask = (uint)value;
  7888. }
  7889. else if (mask == ScriptBaseClass.MASK_NEXT)//4
  7890. {
  7891. m_host.NextOwnerMask = (uint)value;
  7892. }
  7893. }
  7894. }
  7895. }
  7896. public LSL_Integer llGetInventoryPermMask(string itemName, int mask)
  7897. {
  7898. m_host.AddScriptLPS(1);
  7899. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
  7900. if (item == null)
  7901. return -1;
  7902. switch (mask)
  7903. {
  7904. case 0:
  7905. return (int)item.BasePermissions;
  7906. case 1:
  7907. return (int)item.CurrentPermissions;
  7908. case 2:
  7909. return (int)item.GroupPermissions;
  7910. case 3:
  7911. return (int)item.EveryonePermissions;
  7912. case 4:
  7913. return (int)item.NextPermissions;
  7914. }
  7915. return -1;
  7916. }
  7917. public void llSetInventoryPermMask(string itemName, int mask, int value)
  7918. {
  7919. m_host.AddScriptLPS(1);
  7920. if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false))
  7921. {
  7922. if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID))
  7923. {
  7924. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
  7925. if (item != null)
  7926. {
  7927. switch (mask)
  7928. {
  7929. case 0:
  7930. item.BasePermissions = (uint)value;
  7931. break;
  7932. case 1:
  7933. item.CurrentPermissions = (uint)value;
  7934. break;
  7935. case 2:
  7936. item.GroupPermissions = (uint)value;
  7937. break;
  7938. case 3:
  7939. item.EveryonePermissions = (uint)value;
  7940. break;
  7941. case 4:
  7942. item.NextPermissions = (uint)value;
  7943. break;
  7944. }
  7945. }
  7946. }
  7947. }
  7948. }
  7949. public LSL_String llGetInventoryCreator(string itemName)
  7950. {
  7951. m_host.AddScriptLPS(1);
  7952. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
  7953. if (item == null)
  7954. {
  7955. llSay(0, "No item name '" + item + "'");
  7956. return String.Empty;
  7957. }
  7958. return item.CreatorID.ToString();
  7959. }
  7960. public void llOwnerSay(string msg)
  7961. {
  7962. m_host.AddScriptLPS(1);
  7963. World.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0,
  7964. m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
  7965. // IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  7966. // wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
  7967. }
  7968. public LSL_String llRequestSecureURL()
  7969. {
  7970. m_host.AddScriptLPS(1);
  7971. if (m_UrlModule != null)
  7972. return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString();
  7973. return UUID.Zero.ToString();
  7974. }
  7975. public LSL_String llRequestSimulatorData(string simulator, int data)
  7976. {
  7977. IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "OSSL");
  7978. try
  7979. {
  7980. m_host.AddScriptLPS(1);
  7981. string reply = String.Empty;
  7982. GridRegion info;
  7983. if (World.RegionInfo.RegionName == simulator)
  7984. info = new GridRegion(World.RegionInfo);
  7985. else
  7986. info = World.GridService.GetRegionByName(m_ScriptEngine.World.RegionInfo.ScopeID, simulator);
  7987. switch (data)
  7988. {
  7989. case ScriptBaseClass.DATA_SIM_POS:
  7990. if (info == null)
  7991. {
  7992. ScriptSleep(1000);
  7993. return UUID.Zero.ToString();
  7994. }
  7995. bool isHypergridRegion = false;
  7996. if (World.RegionInfo.RegionName != simulator && info.RegionSecret != "")
  7997. {
  7998. // Hypergrid is currently placing real destination region co-ords into RegionSecret.
  7999. // But other code can also use this field for a genuine RegionSecret! Therefore, if
  8000. // anything is present we need to disambiguate.
  8001. //
  8002. // FIXME: Hypergrid should be storing this data in a different field.
  8003. RegionFlags regionFlags
  8004. = (RegionFlags)m_ScriptEngine.World.GridService.GetRegionFlags(
  8005. info.ScopeID, info.RegionID);
  8006. isHypergridRegion = (regionFlags & RegionFlags.Hyperlink) != 0;
  8007. }
  8008. if (isHypergridRegion)
  8009. {
  8010. uint rx = 0, ry = 0;
  8011. Utils.LongToUInts(Convert.ToUInt64(info.RegionSecret), out rx, out ry);
  8012. reply = new LSL_Vector(
  8013. rx,
  8014. ry,
  8015. 0).ToString();
  8016. }
  8017. else
  8018. {
  8019. // Local grid co-oridnates
  8020. reply = new LSL_Vector(
  8021. info.RegionLocX,
  8022. info.RegionLocY,
  8023. 0).ToString();
  8024. }
  8025. break;
  8026. case ScriptBaseClass.DATA_SIM_STATUS:
  8027. if (info != null)
  8028. reply = "up"; // Duh!
  8029. else
  8030. reply = "unknown";
  8031. break;
  8032. case ScriptBaseClass.DATA_SIM_RATING:
  8033. if (info == null)
  8034. {
  8035. ScriptSleep(1000);
  8036. return UUID.Zero.ToString();
  8037. }
  8038. int access = info.Maturity;
  8039. if (access == 0)
  8040. reply = "PG";
  8041. else if (access == 1)
  8042. reply = "MATURE";
  8043. else if (access == 2)
  8044. reply = "ADULT";
  8045. else
  8046. reply = "UNKNOWN";
  8047. break;
  8048. case ScriptBaseClass.DATA_SIM_RELEASE:
  8049. if (ossl != null)
  8050. ossl.CheckThreatLevel(ThreatLevel.High, "llRequestSimulatorData");
  8051. reply = "OpenSim";
  8052. break;
  8053. default:
  8054. ScriptSleep(1000);
  8055. return UUID.Zero.ToString(); // Raise no event
  8056. }
  8057. UUID rq = UUID.Random();
  8058. UUID tid = AsyncCommands.
  8059. DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
  8060. AsyncCommands.
  8061. DataserverPlugin.DataserverReply(rq.ToString(), reply);
  8062. ScriptSleep(1000);
  8063. return tid.ToString();
  8064. }
  8065. catch(Exception)
  8066. {
  8067. //m_log.Error("[LSL_API]: llRequestSimulatorData" + e.ToString());
  8068. return UUID.Zero.ToString();
  8069. }
  8070. }
  8071. public LSL_String llRequestURL()
  8072. {
  8073. m_host.AddScriptLPS(1);
  8074. if (m_UrlModule != null)
  8075. return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString();
  8076. return UUID.Zero.ToString();
  8077. }
  8078. public void llForceMouselook(int mouselook)
  8079. {
  8080. m_host.AddScriptLPS(1);
  8081. m_host.SetForceMouselook(mouselook != 0);
  8082. }
  8083. public LSL_Float llGetObjectMass(string id)
  8084. {
  8085. m_host.AddScriptLPS(1);
  8086. UUID key = new UUID();
  8087. if (UUID.TryParse(id, out key))
  8088. {
  8089. try
  8090. {
  8091. SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
  8092. if (obj != null)
  8093. return (double)obj.GetMass();
  8094. // the object is null so the key is for an avatar
  8095. ScenePresence avatar = World.GetScenePresence(key);
  8096. if (avatar != null)
  8097. if (avatar.IsChildAgent)
  8098. // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass
  8099. // child agents have a mass of 1.0
  8100. return 1;
  8101. else
  8102. return (double)avatar.GetMass();
  8103. }
  8104. catch (KeyNotFoundException)
  8105. {
  8106. return 0; // The Object/Agent not in the region so just return zero
  8107. }
  8108. }
  8109. return 0;
  8110. }
  8111. /// <summary>
  8112. /// illListReplaceList removes the sub-list defined by the inclusive indices
  8113. /// start and end and inserts the src list in its place. The inclusive
  8114. /// nature of the indices means that at least one element must be deleted
  8115. /// if the indices are within the bounds of the existing list. I.e. 2,2
  8116. /// will remove the element at index 2 and replace it with the source
  8117. /// list. Both indices may be negative, with the usual interpretation. An
  8118. /// interesting case is where end is lower than start. As these indices
  8119. /// bound the list to be removed, then 0->end, and start->lim are removed
  8120. /// and the source list is added as a suffix.
  8121. /// </summary>
  8122. public LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end)
  8123. {
  8124. LSL_List pref = null;
  8125. m_host.AddScriptLPS(1);
  8126. // Note that although we have normalized, both
  8127. // indices could still be negative.
  8128. if (start < 0)
  8129. {
  8130. start = start+dest.Length;
  8131. }
  8132. if (end < 0)
  8133. {
  8134. end = end+dest.Length;
  8135. }
  8136. // The comventional case, remove a sequence starting with
  8137. // start and ending with end. And then insert the source
  8138. // list.
  8139. if (start <= end)
  8140. {
  8141. // If greater than zero, then there is going to be a
  8142. // surviving prefix. Otherwise the inclusive nature
  8143. // of the indices mean that we're going to add the
  8144. // source list as a prefix.
  8145. if (start > 0)
  8146. {
  8147. pref = dest.GetSublist(0,start-1);
  8148. // Only add a suffix if there is something
  8149. // beyond the end index (it's inclusive too).
  8150. if (end + 1 < dest.Length)
  8151. {
  8152. return pref + src + dest.GetSublist(end + 1, -1);
  8153. }
  8154. else
  8155. {
  8156. return pref + src;
  8157. }
  8158. }
  8159. // If start is less than or equal to zero, then
  8160. // the new list is simply a prefix. We still need to
  8161. // figure out any necessary surgery to the destination
  8162. // based upon end. Note that if end exceeds the upper
  8163. // bound in this case, the entire destination list
  8164. // is removed.
  8165. else
  8166. {
  8167. if (end + 1 < dest.Length)
  8168. {
  8169. return src + dest.GetSublist(end + 1, -1);
  8170. }
  8171. else
  8172. {
  8173. return src;
  8174. }
  8175. }
  8176. }
  8177. // Finally, if start > end, we strip away a prefix and
  8178. // a suffix, to leave the list that sits <between> ens
  8179. // and start, and then tag on the src list. AT least
  8180. // that's my interpretation. We can get sublist to do
  8181. // this for us. Note that one, or both of the indices
  8182. // might have been negative.
  8183. else
  8184. {
  8185. return dest.GetSublist(end + 1, start - 1) + src;
  8186. }
  8187. }
  8188. public void llLoadURL(string avatar_id, string message, string url)
  8189. {
  8190. m_host.AddScriptLPS(1);
  8191. IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
  8192. if (null != dm)
  8193. dm.SendUrlToUser(
  8194. new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url);
  8195. ScriptSleep(10000);
  8196. }
  8197. public void llParcelMediaCommandList(LSL_List commandList)
  8198. {
  8199. // TODO: Not implemented yet (missing in libomv?):
  8200. // PARCEL_MEDIA_COMMAND_LOOP_SET float loop Use this to get or set the parcel's media loop duration. (1.19.1 RC0 or later)
  8201. m_host.AddScriptLPS(1);
  8202. // according to the docs, this command only works if script owner and land owner are the same
  8203. // lets add estate owners and gods, too, and use the generic permission check.
  8204. ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
  8205. if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return;
  8206. bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)?
  8207. byte loop = 0;
  8208. LandData landData = landObject.LandData;
  8209. string url = landData.MediaURL;
  8210. string texture = landData.MediaID.ToString();
  8211. bool autoAlign = landData.MediaAutoScale != 0;
  8212. string mediaType = ""; // TODO these have to be added as soon as LandData supports it
  8213. string description = "";
  8214. int width = 0;
  8215. int height = 0;
  8216. ParcelMediaCommandEnum? commandToSend = null;
  8217. float time = 0.0f; // default is from start
  8218. ScenePresence presence = null;
  8219. for (int i = 0; i < commandList.Data.Length; i++)
  8220. {
  8221. ParcelMediaCommandEnum command = (ParcelMediaCommandEnum)commandList.Data[i];
  8222. switch (command)
  8223. {
  8224. case ParcelMediaCommandEnum.Agent:
  8225. // we send only to one agent
  8226. if ((i + 1) < commandList.Length)
  8227. {
  8228. if (commandList.Data[i + 1] is LSL_String)
  8229. {
  8230. UUID agentID;
  8231. if (UUID.TryParse((LSL_String)commandList.Data[i + 1], out agentID))
  8232. {
  8233. presence = World.GetScenePresence(agentID);
  8234. }
  8235. }
  8236. else ShoutError("The argument of PARCEL_MEDIA_COMMAND_AGENT must be a key");
  8237. ++i;
  8238. }
  8239. break;
  8240. case ParcelMediaCommandEnum.Loop:
  8241. loop = 1;
  8242. commandToSend = command;
  8243. update = true; //need to send the media update packet to set looping
  8244. break;
  8245. case ParcelMediaCommandEnum.Play:
  8246. loop = 0;
  8247. commandToSend = command;
  8248. update = true; //need to send the media update packet to make sure it doesn't loop
  8249. break;
  8250. case ParcelMediaCommandEnum.Pause:
  8251. case ParcelMediaCommandEnum.Stop:
  8252. case ParcelMediaCommandEnum.Unload:
  8253. commandToSend = command;
  8254. break;
  8255. case ParcelMediaCommandEnum.Url:
  8256. if ((i + 1) < commandList.Length)
  8257. {
  8258. if (commandList.Data[i + 1] is LSL_String)
  8259. {
  8260. url = (LSL_String)commandList.Data[i + 1];
  8261. update = true;
  8262. }
  8263. else ShoutError("The argument of PARCEL_MEDIA_COMMAND_URL must be a string.");
  8264. ++i;
  8265. }
  8266. break;
  8267. case ParcelMediaCommandEnum.Texture:
  8268. if ((i + 1) < commandList.Length)
  8269. {
  8270. if (commandList.Data[i + 1] is LSL_String)
  8271. {
  8272. texture = (LSL_String)commandList.Data[i + 1];
  8273. update = true;
  8274. }
  8275. else ShoutError("The argument of PARCEL_MEDIA_COMMAND_TEXTURE must be a string or key.");
  8276. ++i;
  8277. }
  8278. break;
  8279. case ParcelMediaCommandEnum.Time:
  8280. if ((i + 1) < commandList.Length)
  8281. {
  8282. if (commandList.Data[i + 1] is LSL_Float)
  8283. {
  8284. time = (float)(LSL_Float)commandList.Data[i + 1];
  8285. }
  8286. else ShoutError("The argument of PARCEL_MEDIA_COMMAND_TIME must be a float.");
  8287. ++i;
  8288. }
  8289. break;
  8290. case ParcelMediaCommandEnum.AutoAlign:
  8291. if ((i + 1) < commandList.Length)
  8292. {
  8293. if (commandList.Data[i + 1] is LSL_Integer)
  8294. {
  8295. autoAlign = (LSL_Integer)commandList.Data[i + 1];
  8296. update = true;
  8297. }
  8298. else ShoutError("The argument of PARCEL_MEDIA_COMMAND_AUTO_ALIGN must be an integer.");
  8299. ++i;
  8300. }
  8301. break;
  8302. case ParcelMediaCommandEnum.Type:
  8303. if ((i + 1) < commandList.Length)
  8304. {
  8305. if (commandList.Data[i + 1] is LSL_String)
  8306. {
  8307. mediaType = (LSL_String)commandList.Data[i + 1];
  8308. update = true;
  8309. }
  8310. else ShoutError("The argument of PARCEL_MEDIA_COMMAND_TYPE must be a string.");
  8311. ++i;
  8312. }
  8313. break;
  8314. case ParcelMediaCommandEnum.Desc:
  8315. if ((i + 1) < commandList.Length)
  8316. {
  8317. if (commandList.Data[i + 1] is LSL_String)
  8318. {
  8319. description = (LSL_String)commandList.Data[i + 1];
  8320. update = true;
  8321. }
  8322. else ShoutError("The argument of PARCEL_MEDIA_COMMAND_DESC must be a string.");
  8323. ++i;
  8324. }
  8325. break;
  8326. case ParcelMediaCommandEnum.Size:
  8327. if ((i + 2) < commandList.Length)
  8328. {
  8329. if (commandList.Data[i + 1] is LSL_Integer)
  8330. {
  8331. if (commandList.Data[i + 2] is LSL_Integer)
  8332. {
  8333. width = (LSL_Integer)commandList.Data[i + 1];
  8334. height = (LSL_Integer)commandList.Data[i + 2];
  8335. update = true;
  8336. }
  8337. else ShoutError("The second argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer.");
  8338. }
  8339. else ShoutError("The first argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer.");
  8340. i += 2;
  8341. }
  8342. break;
  8343. default:
  8344. NotImplemented("llParcelMediaCommandList parameter not supported yet: " + Enum.Parse(typeof(ParcelMediaCommandEnum), commandList.Data[i].ToString()).ToString());
  8345. break;
  8346. }//end switch
  8347. }//end for
  8348. // if we didn't get a presence, we send to all and change the url
  8349. // if we did get a presence, we only send to the agent specified, and *don't change the land settings*!
  8350. // did something important change or do we only start/stop/pause?
  8351. if (update)
  8352. {
  8353. if (presence == null)
  8354. {
  8355. // we send to all
  8356. landData.MediaID = new UUID(texture);
  8357. landData.MediaAutoScale = autoAlign ? (byte)1 : (byte)0;
  8358. landData.MediaWidth = width;
  8359. landData.MediaHeight = height;
  8360. landData.MediaType = mediaType;
  8361. // do that one last, it will cause a ParcelPropertiesUpdate
  8362. landObject.SetMediaUrl(url);
  8363. // now send to all (non-child) agents in the parcel
  8364. World.ForEachRootScenePresence(delegate(ScenePresence sp)
  8365. {
  8366. if (sp.currentParcelUUID == landData.GlobalID)
  8367. {
  8368. sp.ControllingClient.SendParcelMediaUpdate(landData.MediaURL,
  8369. landData.MediaID,
  8370. landData.MediaAutoScale,
  8371. mediaType,
  8372. description,
  8373. width, height,
  8374. loop);
  8375. }
  8376. });
  8377. }
  8378. else if (!presence.IsChildAgent)
  8379. {
  8380. // we only send to one (root) agent
  8381. presence.ControllingClient.SendParcelMediaUpdate(url,
  8382. new UUID(texture),
  8383. autoAlign ? (byte)1 : (byte)0,
  8384. mediaType,
  8385. description,
  8386. width, height,
  8387. loop);
  8388. }
  8389. }
  8390. if (commandToSend != null)
  8391. {
  8392. // the commandList contained a start/stop/... command, too
  8393. if (presence == null)
  8394. {
  8395. // send to all (non-child) agents in the parcel
  8396. World.ForEachRootScenePresence(delegate(ScenePresence sp)
  8397. {
  8398. if (sp.currentParcelUUID == landData.GlobalID)
  8399. {
  8400. sp.ControllingClient.SendParcelMediaCommand(0x4, // TODO what is this?
  8401. (ParcelMediaCommandEnum)commandToSend,
  8402. time);
  8403. }
  8404. });
  8405. }
  8406. else if (!presence.IsChildAgent)
  8407. {
  8408. presence.ControllingClient.SendParcelMediaCommand(0x4, // TODO what is this?
  8409. (ParcelMediaCommandEnum)commandToSend,
  8410. time);
  8411. }
  8412. }
  8413. ScriptSleep(2000);
  8414. }
  8415. public LSL_List llParcelMediaQuery(LSL_List aList)
  8416. {
  8417. m_host.AddScriptLPS(1);
  8418. LSL_List list = new LSL_List();
  8419. //TO DO: make the implementation for the missing commands
  8420. //PARCEL_MEDIA_COMMAND_LOOP_SET float loop Use this to get or set the parcel's media loop duration. (1.19.1 RC0 or later)
  8421. for (int i = 0; i < aList.Data.Length; i++)
  8422. {
  8423. if (aList.Data[i] != null)
  8424. {
  8425. switch ((ParcelMediaCommandEnum) aList.Data[i])
  8426. {
  8427. case ParcelMediaCommandEnum.Url:
  8428. list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaURL));
  8429. break;
  8430. case ParcelMediaCommandEnum.Desc:
  8431. list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).Description));
  8432. break;
  8433. case ParcelMediaCommandEnum.Texture:
  8434. list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaID.ToString()));
  8435. break;
  8436. case ParcelMediaCommandEnum.Type:
  8437. list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaType));
  8438. break;
  8439. case ParcelMediaCommandEnum.Size:
  8440. list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaWidth));
  8441. list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaHeight));
  8442. break;
  8443. default:
  8444. ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
  8445. NotImplemented("llParcelMediaQuery parameter do not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString());
  8446. break;
  8447. }
  8448. }
  8449. }
  8450. ScriptSleep(2000);
  8451. return list;
  8452. }
  8453. public LSL_Integer llModPow(int a, int b, int c)
  8454. {
  8455. m_host.AddScriptLPS(1);
  8456. Int64 tmp = 0;
  8457. Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp);
  8458. ScriptSleep(1000);
  8459. return Convert.ToInt32(tmp);
  8460. }
  8461. public LSL_Integer llGetInventoryType(string name)
  8462. {
  8463. m_host.AddScriptLPS(1);
  8464. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  8465. if (item == null)
  8466. return -1;
  8467. return item.Type;
  8468. }
  8469. public void llSetPayPrice(int price, LSL_List quick_pay_buttons)
  8470. {
  8471. m_host.AddScriptLPS(1);
  8472. if (quick_pay_buttons.Data.Length < 4)
  8473. {
  8474. LSLError("List must have at least 4 elements");
  8475. return;
  8476. }
  8477. m_host.ParentGroup.RootPart.PayPrice[0]=price;
  8478. m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0];
  8479. m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1];
  8480. m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2];
  8481. m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3];
  8482. m_host.ParentGroup.HasGroupChanged = true;
  8483. }
  8484. public LSL_Vector llGetCameraPos()
  8485. {
  8486. m_host.AddScriptLPS(1);
  8487. if (m_item.PermsGranter == UUID.Zero)
  8488. return new LSL_Vector();
  8489. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
  8490. {
  8491. ShoutError("No permissions to track the camera");
  8492. return new LSL_Vector();
  8493. }
  8494. ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
  8495. if (presence != null)
  8496. {
  8497. LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z);
  8498. return pos;
  8499. }
  8500. return new LSL_Vector();
  8501. }
  8502. public LSL_Rotation llGetCameraRot()
  8503. {
  8504. m_host.AddScriptLPS(1);
  8505. if (m_item.PermsGranter == UUID.Zero)
  8506. return new LSL_Rotation();
  8507. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
  8508. {
  8509. ShoutError("No permissions to track the camera");
  8510. return new LSL_Rotation();
  8511. }
  8512. ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
  8513. if (presence != null)
  8514. {
  8515. return new LSL_Rotation(presence.CameraRotation.X, presence.CameraRotation.Y, presence.CameraRotation.Z, presence.CameraRotation.W);
  8516. }
  8517. return new LSL_Rotation();
  8518. }
  8519. /// <summary>
  8520. /// The SL implementation does nothing, it is deprecated
  8521. /// This duplicates SL
  8522. /// </summary>
  8523. public void llSetPrimURL(string url)
  8524. {
  8525. m_host.AddScriptLPS(1);
  8526. ScriptSleep(2000);
  8527. }
  8528. /// <summary>
  8529. /// The SL implementation shouts an error, it is deprecated
  8530. /// This duplicates SL
  8531. /// </summary>
  8532. public void llRefreshPrimURL()
  8533. {
  8534. m_host.AddScriptLPS(1);
  8535. ShoutError("llRefreshPrimURL - not yet supported");
  8536. ScriptSleep(20000);
  8537. }
  8538. public LSL_String llEscapeURL(string url)
  8539. {
  8540. m_host.AddScriptLPS(1);
  8541. try
  8542. {
  8543. return Uri.EscapeDataString(url);
  8544. }
  8545. catch (Exception ex)
  8546. {
  8547. return "llEscapeURL: " + ex.ToString();
  8548. }
  8549. }
  8550. public LSL_String llUnescapeURL(string url)
  8551. {
  8552. m_host.AddScriptLPS(1);
  8553. try
  8554. {
  8555. return Uri.UnescapeDataString(url);
  8556. }
  8557. catch (Exception ex)
  8558. {
  8559. return "llUnescapeURL: " + ex.ToString();
  8560. }
  8561. }
  8562. public void llMapDestination(string simname, LSL_Vector pos, LSL_Vector lookAt)
  8563. {
  8564. m_host.AddScriptLPS(1);
  8565. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, 0);
  8566. if (detectedParams == null) return; // only works on the first detected avatar
  8567. ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
  8568. if (avatar != null)
  8569. {
  8570. avatar.ControllingClient.SendScriptTeleportRequest(m_host.Name,
  8571. simname, pos, lookAt);
  8572. }
  8573. ScriptSleep(1000);
  8574. }
  8575. public void llAddToLandBanList(string avatar, double hours)
  8576. {
  8577. m_host.AddScriptLPS(1);
  8578. UUID key;
  8579. ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
  8580. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
  8581. {
  8582. int expires = 0;
  8583. if (hours != 0)
  8584. expires = Util.UnixTimeSinceEpoch() + (int)(3600.0 * hours);
  8585. if (UUID.TryParse(avatar, out key))
  8586. {
  8587. int idx = land.LandData.ParcelAccessList.FindIndex(
  8588. delegate(LandAccessEntry e)
  8589. {
  8590. if (e.AgentID == key && e.Flags == AccessList.Ban)
  8591. return true;
  8592. return false;
  8593. });
  8594. if (idx != -1 && (land.LandData.ParcelAccessList[idx].Expires == 0 || (expires != 0 && expires < land.LandData.ParcelAccessList[idx].Expires)))
  8595. return;
  8596. if (idx != -1)
  8597. land.LandData.ParcelAccessList.RemoveAt(idx);
  8598. LandAccessEntry entry = new LandAccessEntry();
  8599. entry.AgentID = key;
  8600. entry.Flags = AccessList.Ban;
  8601. entry.Expires = expires;
  8602. land.LandData.ParcelAccessList.Add(entry);
  8603. World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
  8604. }
  8605. }
  8606. ScriptSleep(100);
  8607. }
  8608. public void llRemoveFromLandPassList(string avatar)
  8609. {
  8610. m_host.AddScriptLPS(1);
  8611. UUID key;
  8612. ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
  8613. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed))
  8614. {
  8615. if (UUID.TryParse(avatar, out key))
  8616. {
  8617. int idx = land.LandData.ParcelAccessList.FindIndex(
  8618. delegate(LandAccessEntry e)
  8619. {
  8620. if (e.AgentID == key && e.Flags == AccessList.Access)
  8621. return true;
  8622. return false;
  8623. });
  8624. if (idx != -1)
  8625. {
  8626. land.LandData.ParcelAccessList.RemoveAt(idx);
  8627. World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
  8628. }
  8629. }
  8630. }
  8631. ScriptSleep(100);
  8632. }
  8633. public void llRemoveFromLandBanList(string avatar)
  8634. {
  8635. m_host.AddScriptLPS(1);
  8636. UUID key;
  8637. ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
  8638. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
  8639. {
  8640. if (UUID.TryParse(avatar, out key))
  8641. {
  8642. int idx = land.LandData.ParcelAccessList.FindIndex(
  8643. delegate(LandAccessEntry e)
  8644. {
  8645. if (e.AgentID == key && e.Flags == AccessList.Ban)
  8646. return true;
  8647. return false;
  8648. });
  8649. if (idx != -1)
  8650. {
  8651. land.LandData.ParcelAccessList.RemoveAt(idx);
  8652. World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
  8653. }
  8654. }
  8655. }
  8656. ScriptSleep(100);
  8657. }
  8658. public void llSetCameraParams(LSL_List rules)
  8659. {
  8660. m_host.AddScriptLPS(1);
  8661. // the object we are in
  8662. UUID objectID = m_host.ParentUUID;
  8663. if (objectID == UUID.Zero)
  8664. return;
  8665. // we need the permission first, to know which avatar we want to set the camera for
  8666. UUID agentID = m_item.PermsGranter;
  8667. if (agentID == UUID.Zero)
  8668. return;
  8669. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
  8670. return;
  8671. ScenePresence presence = World.GetScenePresence(agentID);
  8672. // we are not interested in child-agents
  8673. if (presence.IsChildAgent) return;
  8674. SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
  8675. object[] data = rules.Data;
  8676. for (int i = 0; i < data.Length; ++i) {
  8677. int type = Convert.ToInt32(data[i++].ToString());
  8678. if (i >= data.Length) break; // odd number of entries => ignore the last
  8679. // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
  8680. switch (type) {
  8681. case ScriptBaseClass.CAMERA_FOCUS:
  8682. case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
  8683. case ScriptBaseClass.CAMERA_POSITION:
  8684. LSL_Vector v = (LSL_Vector)data[i];
  8685. parameters.Add(type + 1, (float)v.x);
  8686. parameters.Add(type + 2, (float)v.y);
  8687. parameters.Add(type + 3, (float)v.z);
  8688. break;
  8689. default:
  8690. // TODO: clean that up as soon as the implicit casts are in
  8691. if (data[i] is LSL_Float)
  8692. parameters.Add(type, (float)((LSL_Float)data[i]).value);
  8693. else if (data[i] is LSL_Integer)
  8694. parameters.Add(type, (float)((LSL_Integer)data[i]).value);
  8695. else parameters.Add(type, Convert.ToSingle(data[i]));
  8696. break;
  8697. }
  8698. }
  8699. if (parameters.Count > 0) presence.ControllingClient.SendSetFollowCamProperties(objectID, parameters);
  8700. }
  8701. public void llClearCameraParams()
  8702. {
  8703. m_host.AddScriptLPS(1);
  8704. // the object we are in
  8705. UUID objectID = m_host.ParentUUID;
  8706. if (objectID == UUID.Zero)
  8707. return;
  8708. // we need the permission first, to know which avatar we want to clear the camera for
  8709. UUID agentID = m_item.PermsGranter;
  8710. if (agentID == UUID.Zero)
  8711. return;
  8712. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
  8713. return;
  8714. ScenePresence presence = World.GetScenePresence(agentID);
  8715. // we are not interested in child-agents
  8716. if (presence.IsChildAgent)
  8717. return;
  8718. presence.ControllingClient.SendClearFollowCamProperties(objectID);
  8719. }
  8720. public LSL_Float llListStatistics(int operation, LSL_List src)
  8721. {
  8722. m_host.AddScriptLPS(1);
  8723. switch (operation)
  8724. {
  8725. case ScriptBaseClass.LIST_STAT_RANGE:
  8726. return src.Range();
  8727. case ScriptBaseClass.LIST_STAT_MIN:
  8728. return src.Min();
  8729. case ScriptBaseClass.LIST_STAT_MAX:
  8730. return src.Max();
  8731. case ScriptBaseClass.LIST_STAT_MEAN:
  8732. return src.Mean();
  8733. case ScriptBaseClass.LIST_STAT_MEDIAN:
  8734. return LSL_List.ToDoubleList(src).Median();
  8735. case ScriptBaseClass.LIST_STAT_NUM_COUNT:
  8736. return src.NumericLength();
  8737. case ScriptBaseClass.LIST_STAT_STD_DEV:
  8738. return src.StdDev();
  8739. case ScriptBaseClass.LIST_STAT_SUM:
  8740. return src.Sum();
  8741. case ScriptBaseClass.LIST_STAT_SUM_SQUARES:
  8742. return src.SumSqrs();
  8743. case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN:
  8744. return src.GeometricMean();
  8745. case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN:
  8746. return src.HarmonicMean();
  8747. default:
  8748. return 0.0;
  8749. }
  8750. }
  8751. public LSL_Integer llGetUnixTime()
  8752. {
  8753. m_host.AddScriptLPS(1);
  8754. return Util.UnixTimeSinceEpoch();
  8755. }
  8756. public LSL_Integer llGetParcelFlags(LSL_Vector pos)
  8757. {
  8758. m_host.AddScriptLPS(1);
  8759. return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).LandData.Flags;
  8760. }
  8761. public LSL_Integer llGetRegionFlags()
  8762. {
  8763. m_host.AddScriptLPS(1);
  8764. IEstateModule estate = World.RequestModuleInterface<IEstateModule>();
  8765. if (estate == null)
  8766. return 67108864;
  8767. return (int)estate.GetRegionFlags();
  8768. }
  8769. public LSL_String llXorBase64StringsCorrect(string str1, string str2)
  8770. {
  8771. m_host.AddScriptLPS(1);
  8772. string ret = String.Empty;
  8773. string src1 = llBase64ToString(str1);
  8774. string src2 = llBase64ToString(str2);
  8775. int c = 0;
  8776. for (int i = 0; i < src1.Length; i++)
  8777. {
  8778. ret += (char) (src1[i] ^ src2[c]);
  8779. c++;
  8780. if (c >= src2.Length)
  8781. c = 0;
  8782. }
  8783. return llStringToBase64(ret);
  8784. }
  8785. public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
  8786. {
  8787. // Partial implementation: support for parameter flags needed
  8788. // see http://wiki.secondlife.com/wiki/LlHTTPRequest
  8789. // parameter flags support are implemented in ScriptsHttpRequests.cs
  8790. // in StartHttpRequest
  8791. m_host.AddScriptLPS(1);
  8792. IHttpRequestModule httpScriptMod =
  8793. m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
  8794. List<string> param = new List<string>();
  8795. foreach (object o in parameters.Data)
  8796. {
  8797. param.Add(o.ToString());
  8798. }
  8799. Vector3 position = m_host.AbsolutePosition;
  8800. Vector3 velocity = m_host.Velocity;
  8801. Quaternion rotation = m_host.RotationOffset;
  8802. string ownerName = String.Empty;
  8803. ScenePresence scenePresence = World.GetScenePresence(m_host.OwnerID);
  8804. if (scenePresence == null)
  8805. ownerName = resolveName(m_host.OwnerID);
  8806. else
  8807. ownerName = scenePresence.Name;
  8808. RegionInfo regionInfo = World.RegionInfo;
  8809. Dictionary<string, string> httpHeaders = new Dictionary<string, string>();
  8810. string shard = "OpenSim";
  8811. IConfigSource config = m_ScriptEngine.ConfigSource;
  8812. if (config.Configs["Network"] != null)
  8813. {
  8814. shard = config.Configs["Network"].GetString("shard", shard);
  8815. }
  8816. httpHeaders["X-SecondLife-Shard"] = shard;
  8817. httpHeaders["X-SecondLife-Object-Name"] = m_host.Name;
  8818. httpHeaders["X-SecondLife-Object-Key"] = m_host.UUID.ToString();
  8819. httpHeaders["X-SecondLife-Region"] = string.Format("{0} ({1}, {2})", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY);
  8820. httpHeaders["X-SecondLife-Local-Position"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", position.X, position.Y, position.Z);
  8821. httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z);
  8822. httpHeaders["X-SecondLife-Local-Rotation"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000})", rotation.X, rotation.Y, rotation.Z, rotation.W);
  8823. httpHeaders["X-SecondLife-Owner-Name"] = ownerName;
  8824. httpHeaders["X-SecondLife-Owner-Key"] = m_host.OwnerID.ToString();
  8825. string userAgent = config.Configs["Network"].GetString("user_agent", null);
  8826. if (userAgent != null)
  8827. httpHeaders["User-Agent"] = userAgent;
  8828. string authregex = @"^(https?:\/\/)(\w+):(\w+)@(.*)$";
  8829. Regex r = new Regex(authregex);
  8830. int[] gnums = r.GetGroupNumbers();
  8831. Match m = r.Match(url);
  8832. if (m.Success) {
  8833. for (int i = 1; i < gnums.Length; i++) {
  8834. //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]];
  8835. //CaptureCollection cc = g.Captures;
  8836. }
  8837. if (m.Groups.Count == 5) {
  8838. httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString())));
  8839. url = m.Groups[1].ToString() + m.Groups[4].ToString();
  8840. }
  8841. }
  8842. UUID reqID
  8843. = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body);
  8844. if (reqID != UUID.Zero)
  8845. return reqID.ToString();
  8846. else
  8847. return null;
  8848. }
  8849. public void llHTTPResponse(LSL_Key id, int status, string body)
  8850. {
  8851. // Partial implementation: support for parameter flags needed
  8852. // see http://wiki.secondlife.com/wiki/llHTTPResponse
  8853. m_host.AddScriptLPS(1);
  8854. if (m_UrlModule != null)
  8855. m_UrlModule.HttpResponse(new UUID(id), status,body);
  8856. }
  8857. public void llResetLandBanList()
  8858. {
  8859. m_host.AddScriptLPS(1);
  8860. LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData;
  8861. if (land.OwnerID == m_host.OwnerID)
  8862. {
  8863. foreach (LandAccessEntry entry in land.ParcelAccessList)
  8864. {
  8865. if (entry.Flags == AccessList.Ban)
  8866. {
  8867. land.ParcelAccessList.Remove(entry);
  8868. }
  8869. }
  8870. }
  8871. ScriptSleep(100);
  8872. }
  8873. public void llResetLandPassList()
  8874. {
  8875. m_host.AddScriptLPS(1);
  8876. LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData;
  8877. if (land.OwnerID == m_host.OwnerID)
  8878. {
  8879. foreach (LandAccessEntry entry in land.ParcelAccessList)
  8880. {
  8881. if (entry.Flags == AccessList.Access)
  8882. {
  8883. land.ParcelAccessList.Remove(entry);
  8884. }
  8885. }
  8886. }
  8887. ScriptSleep(100);
  8888. }
  8889. public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
  8890. {
  8891. m_host.AddScriptLPS(1);
  8892. ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
  8893. if (lo == null)
  8894. return 0;
  8895. IPrimCounts pc = lo.PrimCounts;
  8896. if (sim_wide != ScriptBaseClass.FALSE)
  8897. {
  8898. if (category == ScriptBaseClass.PARCEL_COUNT_TOTAL)
  8899. {
  8900. return pc.Simulator;
  8901. }
  8902. else
  8903. {
  8904. // counts not implemented yet
  8905. return 0;
  8906. }
  8907. }
  8908. else
  8909. {
  8910. if (category == ScriptBaseClass.PARCEL_COUNT_TOTAL)
  8911. return pc.Total;
  8912. else if (category == ScriptBaseClass.PARCEL_COUNT_OWNER)
  8913. return pc.Owner;
  8914. else if (category == ScriptBaseClass.PARCEL_COUNT_GROUP)
  8915. return pc.Group;
  8916. else if (category == ScriptBaseClass.PARCEL_COUNT_OTHER)
  8917. return pc.Others;
  8918. else if (category == ScriptBaseClass.PARCEL_COUNT_SELECTED)
  8919. return pc.Selected;
  8920. else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP)
  8921. return 0; // counts not implemented yet
  8922. }
  8923. return 0;
  8924. }
  8925. public LSL_List llGetParcelPrimOwners(LSL_Vector pos)
  8926. {
  8927. m_host.AddScriptLPS(1);
  8928. LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
  8929. LSL_List ret = new LSL_List();
  8930. if (land != null)
  8931. {
  8932. foreach (KeyValuePair<UUID, int> detectedParams in land.GetLandObjectOwners())
  8933. {
  8934. ret.Add(new LSL_String(detectedParams.Key.ToString()));
  8935. ret.Add(new LSL_Integer(detectedParams.Value));
  8936. }
  8937. }
  8938. ScriptSleep(2000);
  8939. return ret;
  8940. }
  8941. public LSL_Integer llGetObjectPrimCount(string object_id)
  8942. {
  8943. m_host.AddScriptLPS(1);
  8944. SceneObjectPart part = World.GetSceneObjectPart(new UUID(object_id));
  8945. if (part == null)
  8946. {
  8947. return 0;
  8948. }
  8949. else
  8950. {
  8951. return part.ParentGroup.PrimCount;
  8952. }
  8953. }
  8954. public LSL_Integer llGetParcelMaxPrims(LSL_Vector pos, int sim_wide)
  8955. {
  8956. m_host.AddScriptLPS(1);
  8957. ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
  8958. if (lo == null)
  8959. return 0;
  8960. if (sim_wide != 0)
  8961. return lo.GetSimulatorMaxPrimCount();
  8962. else
  8963. return lo.GetParcelMaxPrimCount();
  8964. }
  8965. public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param)
  8966. {
  8967. m_host.AddScriptLPS(1);
  8968. LandData land = World.GetLandData(pos);
  8969. if (land == null)
  8970. {
  8971. return new LSL_List(0);
  8972. }
  8973. LSL_List ret = new LSL_List();
  8974. foreach (object o in param.Data)
  8975. {
  8976. switch (o.ToString())
  8977. {
  8978. case "0":
  8979. ret.Add(new LSL_String(land.Name));
  8980. break;
  8981. case "1":
  8982. ret.Add(new LSL_String(land.Description));
  8983. break;
  8984. case "2":
  8985. ret.Add(new LSL_Key(land.OwnerID.ToString()));
  8986. break;
  8987. case "3":
  8988. ret.Add(new LSL_Key(land.GroupID.ToString()));
  8989. break;
  8990. case "4":
  8991. ret.Add(new LSL_Integer(land.Area));
  8992. break;
  8993. case "5":
  8994. ret.Add(new LSL_Key(land.GlobalID.ToString()));
  8995. break;
  8996. default:
  8997. ret.Add(new LSL_Integer(0));
  8998. break;
  8999. }
  9000. }
  9001. return ret;
  9002. }
  9003. public LSL_String llStringTrim(string src, int type)
  9004. {
  9005. m_host.AddScriptLPS(1);
  9006. if (type == (int)ScriptBaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); }
  9007. if (type == (int)ScriptBaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); }
  9008. if (type == (int)ScriptBaseClass.STRING_TRIM) { return src.Trim(); }
  9009. return src;
  9010. }
  9011. public LSL_List llGetObjectDetails(string id, LSL_List args)
  9012. {
  9013. m_host.AddScriptLPS(1);
  9014. LSL_List ret = new LSL_List();
  9015. UUID key = new UUID();
  9016. if (UUID.TryParse(id, out key))
  9017. {
  9018. ScenePresence av = World.GetScenePresence(key);
  9019. if (av != null)
  9020. {
  9021. foreach (object o in args.Data)
  9022. {
  9023. switch (int.Parse(o.ToString()))
  9024. {
  9025. case ScriptBaseClass.OBJECT_NAME:
  9026. ret.Add(new LSL_String(av.Firstname + " " + av.Lastname));
  9027. break;
  9028. case ScriptBaseClass.OBJECT_DESC:
  9029. ret.Add(new LSL_String(""));
  9030. break;
  9031. case ScriptBaseClass.OBJECT_POS:
  9032. ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
  9033. break;
  9034. case ScriptBaseClass.OBJECT_ROT:
  9035. ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W));
  9036. break;
  9037. case ScriptBaseClass.OBJECT_VELOCITY:
  9038. ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
  9039. break;
  9040. case ScriptBaseClass.OBJECT_OWNER:
  9041. ret.Add(new LSL_String(id));
  9042. break;
  9043. case ScriptBaseClass.OBJECT_GROUP:
  9044. ret.Add(new LSL_String(UUID.Zero.ToString()));
  9045. break;
  9046. case ScriptBaseClass.OBJECT_CREATOR:
  9047. ret.Add(new LSL_String(UUID.Zero.ToString()));
  9048. break;
  9049. // For the following 8 see the Object version below
  9050. case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT:
  9051. ret.Add(new LSL_Integer(av.RunningScriptCount()));
  9052. break;
  9053. case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT:
  9054. ret.Add(new LSL_Integer(av.ScriptCount()));
  9055. break;
  9056. case ScriptBaseClass.OBJECT_SCRIPT_MEMORY:
  9057. ret.Add(new LSL_Integer(av.RunningScriptCount() * 16384));
  9058. break;
  9059. case ScriptBaseClass.OBJECT_SCRIPT_TIME:
  9060. ret.Add(new LSL_Float(av.ScriptExecutionTime() / 1000.0f));
  9061. break;
  9062. case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE:
  9063. ret.Add(new LSL_Integer(1));
  9064. break;
  9065. case ScriptBaseClass.OBJECT_SERVER_COST:
  9066. ret.Add(new LSL_Float(0));
  9067. break;
  9068. case ScriptBaseClass.OBJECT_STREAMING_COST:
  9069. ret.Add(new LSL_Float(0));
  9070. break;
  9071. case ScriptBaseClass.OBJECT_PHYSICS_COST:
  9072. ret.Add(new LSL_Float(0));
  9073. break;
  9074. case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
  9075. ret.Add(new LSL_Float(0));
  9076. break;
  9077. case ScriptBaseClass.OBJECT_ROOT:
  9078. SceneObjectPart p = av.ParentPart;
  9079. if (p != null)
  9080. {
  9081. ret.Add(new LSL_String(p.ParentGroup.RootPart.UUID.ToString()));
  9082. }
  9083. else
  9084. {
  9085. ret.Add(new LSL_String(id));
  9086. }
  9087. break;
  9088. case ScriptBaseClass.OBJECT_ATTACHED_POINT:
  9089. ret.Add(new LSL_Integer(0));
  9090. break;
  9091. case ScriptBaseClass.OBJECT_PATHFINDING_TYPE: // Pathfinding
  9092. ret.Add(new LSL_Integer(ScriptBaseClass.OPT_AVATAR));
  9093. break;
  9094. case ScriptBaseClass.OBJECT_PHYSICS:
  9095. ret.Add(new LSL_Integer(0));
  9096. break;
  9097. case ScriptBaseClass.OBJECT_PHANTOM:
  9098. ret.Add(new LSL_Integer(0));
  9099. break;
  9100. case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
  9101. ret.Add(new LSL_Integer(0));
  9102. break;
  9103. default:
  9104. // Invalid or unhandled constant.
  9105. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
  9106. break;
  9107. }
  9108. }
  9109. return ret;
  9110. }
  9111. SceneObjectPart obj = World.GetSceneObjectPart(key);
  9112. if (obj != null)
  9113. {
  9114. foreach (object o in args.Data)
  9115. {
  9116. switch (int.Parse(o.ToString()))
  9117. {
  9118. case ScriptBaseClass.OBJECT_NAME:
  9119. ret.Add(new LSL_String(obj.Name));
  9120. break;
  9121. case ScriptBaseClass.OBJECT_DESC:
  9122. ret.Add(new LSL_String(obj.Description));
  9123. break;
  9124. case ScriptBaseClass.OBJECT_POS:
  9125. ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z));
  9126. break;
  9127. case ScriptBaseClass.OBJECT_ROT:
  9128. {
  9129. Quaternion rot = Quaternion.Identity;
  9130. if (obj.ParentGroup.RootPart == obj)
  9131. rot = obj.ParentGroup.GroupRotation;
  9132. else
  9133. rot = obj.GetWorldRotation();
  9134. LSL_Rotation objrot = new LSL_Rotation(rot);
  9135. ret.Add(objrot);
  9136. }
  9137. break;
  9138. case ScriptBaseClass.OBJECT_VELOCITY:
  9139. ret.Add(new LSL_Vector(obj.Velocity));
  9140. break;
  9141. case ScriptBaseClass.OBJECT_OWNER:
  9142. ret.Add(new LSL_String(obj.OwnerID.ToString()));
  9143. break;
  9144. case ScriptBaseClass.OBJECT_GROUP:
  9145. ret.Add(new LSL_String(obj.GroupID.ToString()));
  9146. break;
  9147. case ScriptBaseClass.OBJECT_CREATOR:
  9148. ret.Add(new LSL_String(obj.CreatorID.ToString()));
  9149. break;
  9150. case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT:
  9151. ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount()));
  9152. break;
  9153. case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT:
  9154. ret.Add(new LSL_Integer(obj.ParentGroup.ScriptCount()));
  9155. break;
  9156. case ScriptBaseClass.OBJECT_SCRIPT_MEMORY:
  9157. // The value returned in SL for mono scripts is 65536 * number of active scripts
  9158. // and 16384 * number of active scripts for LSO. since llGetFreememory
  9159. // is coded to give the LSO value use it here
  9160. ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount() * 16384));
  9161. break;
  9162. case ScriptBaseClass.OBJECT_SCRIPT_TIME:
  9163. // Average cpu time in seconds per simulator frame expended on all scripts in the object
  9164. ret.Add(new LSL_Float(obj.ParentGroup.ScriptExecutionTime() / 1000.0f));
  9165. break;
  9166. case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE:
  9167. // according to the SL wiki A prim or linkset will have prim
  9168. // equivalent of the number of prims in a linkset if it does not
  9169. // contain a mesh anywhere in the link set or is not a normal prim
  9170. // The value returned in SL for normal prims is prim count
  9171. ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount));
  9172. break;
  9173. // The following 3 costs I have intentionaly coded to return zero. They are part of
  9174. // "Land Impact" calculations. These calculations are probably not applicable
  9175. // to OpenSim and are not yet complete in SL
  9176. case ScriptBaseClass.OBJECT_SERVER_COST:
  9177. // The linden calculation is here
  9178. // http://wiki.secondlife.com/wiki/Mesh/Mesh_Server_Weight
  9179. // The value returned in SL for normal prims looks like the prim count
  9180. ret.Add(new LSL_Float(0));
  9181. break;
  9182. case ScriptBaseClass.OBJECT_STREAMING_COST:
  9183. // The linden calculation is here
  9184. // http://wiki.secondlife.com/wiki/Mesh/Mesh_Streaming_Cost
  9185. // The value returned in SL for normal prims looks like the prim count * 0.06
  9186. ret.Add(new LSL_Float(0));
  9187. break;
  9188. case ScriptBaseClass.OBJECT_PHYSICS_COST:
  9189. // The linden calculation is here
  9190. // http://wiki.secondlife.com/wiki/Mesh/Mesh_physics
  9191. // The value returned in SL for normal prims looks like the prim count
  9192. ret.Add(new LSL_Float(0));
  9193. break;
  9194. case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
  9195. ret.Add(new LSL_Float(0));
  9196. break;
  9197. case ScriptBaseClass.OBJECT_ROOT:
  9198. ret.Add(new LSL_String(obj.ParentGroup.RootPart.UUID.ToString()));
  9199. break;
  9200. case ScriptBaseClass.OBJECT_ATTACHED_POINT:
  9201. ret.Add(new LSL_Integer(obj.ParentGroup.AttachmentPoint));
  9202. break;
  9203. case ScriptBaseClass.OBJECT_PATHFINDING_TYPE:
  9204. byte pcode = obj.Shape.PCode;
  9205. if (obj.ParentGroup.AttachmentPoint != 0
  9206. || pcode == (byte)PCode.Grass
  9207. || pcode == (byte)PCode.Tree
  9208. || pcode == (byte)PCode.NewTree)
  9209. {
  9210. ret.Add(new LSL_Integer(ScriptBaseClass.OPT_OTHER));
  9211. }
  9212. else
  9213. {
  9214. ret.Add(new LSL_Integer(ScriptBaseClass.OPT_LEGACY_LINKSET));
  9215. }
  9216. break;
  9217. case ScriptBaseClass.OBJECT_PHYSICS:
  9218. if (obj.ParentGroup.AttachmentPoint != 0)
  9219. {
  9220. ret.Add(new LSL_Integer(0)); // Always false if attached
  9221. }
  9222. else
  9223. {
  9224. ret.Add(new LSL_Integer(obj.ParentGroup.UsesPhysics ? 1 : 0));
  9225. }
  9226. break;
  9227. case ScriptBaseClass.OBJECT_PHANTOM:
  9228. if (obj.ParentGroup.AttachmentPoint != 0)
  9229. {
  9230. ret.Add(new LSL_Integer(0)); // Always false if attached
  9231. }
  9232. else
  9233. {
  9234. ret.Add(new LSL_Integer(obj.ParentGroup.IsPhantom ? 1 : 0));
  9235. }
  9236. break;
  9237. case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
  9238. ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0));
  9239. break;
  9240. default:
  9241. // Invalid or unhandled constant.
  9242. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
  9243. break;
  9244. }
  9245. }
  9246. return ret;
  9247. }
  9248. }
  9249. return new LSL_List();
  9250. }
  9251. internal UUID GetScriptByName(string name)
  9252. {
  9253. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  9254. if (item == null || item.Type != 10)
  9255. return UUID.Zero;
  9256. return item.ItemID;
  9257. }
  9258. internal void ShoutError(string msg)
  9259. {
  9260. llShout(ScriptBaseClass.DEBUG_CHANNEL, msg);
  9261. }
  9262. internal void NotImplemented(string command)
  9263. {
  9264. if (throwErrorOnNotImplemented)
  9265. throw new NotImplementedException("Command not implemented: " + command);
  9266. }
  9267. internal void Deprecated(string command)
  9268. {
  9269. throw new ScriptException("Command deprecated: " + command);
  9270. }
  9271. internal void LSLError(string msg)
  9272. {
  9273. throw new ScriptException("LSL Runtime Error: " + msg);
  9274. }
  9275. public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
  9276. protected void WithNotecard(UUID assetID, AssetRequestCallback cb)
  9277. {
  9278. World.AssetService.Get(assetID.ToString(), this,
  9279. delegate(string i, object sender, AssetBase a)
  9280. {
  9281. UUID uuid = UUID.Zero;
  9282. UUID.TryParse(i, out uuid);
  9283. cb(uuid, a);
  9284. });
  9285. }
  9286. public LSL_String llGetNumberOfNotecardLines(string name)
  9287. {
  9288. m_host.AddScriptLPS(1);
  9289. UUID assetID = UUID.Zero;
  9290. if (!UUID.TryParse(name, out assetID))
  9291. {
  9292. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  9293. if (item != null && item.Type == 7)
  9294. assetID = item.AssetID;
  9295. }
  9296. if (assetID == UUID.Zero)
  9297. {
  9298. // => complain loudly, as specified by the LSL docs
  9299. ShoutError("Notecard '" + name + "' could not be found.");
  9300. return UUID.Zero.ToString();
  9301. }
  9302. // was: UUID tid = tid = AsyncCommands.
  9303. UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString());
  9304. if (NotecardCache.IsCached(assetID))
  9305. {
  9306. AsyncCommands.
  9307. DataserverPlugin.DataserverReply(assetID.ToString(),
  9308. NotecardCache.GetLines(assetID).ToString());
  9309. ScriptSleep(100);
  9310. return tid.ToString();
  9311. }
  9312. WithNotecard(assetID, delegate (UUID id, AssetBase a)
  9313. {
  9314. if (a == null || a.Type != 7)
  9315. {
  9316. ShoutError("Notecard '" + name + "' could not be found.");
  9317. return;
  9318. }
  9319. string data = Encoding.UTF8.GetString(a.Data);
  9320. //m_log.Debug(data);
  9321. NotecardCache.Cache(id, data);
  9322. AsyncCommands.
  9323. DataserverPlugin.DataserverReply(id.ToString(),
  9324. NotecardCache.GetLines(id).ToString());
  9325. });
  9326. ScriptSleep(100);
  9327. return tid.ToString();
  9328. }
  9329. public LSL_String llGetNotecardLine(string name, int line)
  9330. {
  9331. m_host.AddScriptLPS(1);
  9332. UUID assetID = UUID.Zero;
  9333. if (!UUID.TryParse(name, out assetID))
  9334. {
  9335. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  9336. if (item != null && item.Type == 7)
  9337. assetID = item.AssetID;
  9338. }
  9339. if (assetID == UUID.Zero)
  9340. {
  9341. // => complain loudly, as specified by the LSL docs
  9342. ShoutError("Notecard '" + name + "' could not be found.");
  9343. return UUID.Zero.ToString();
  9344. }
  9345. // was: UUID tid = tid = AsyncCommands.
  9346. UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString());
  9347. if (NotecardCache.IsCached(assetID))
  9348. {
  9349. AsyncCommands.DataserverPlugin.DataserverReply(assetID.ToString(),
  9350. NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
  9351. ScriptSleep(100);
  9352. return tid.ToString();
  9353. }
  9354. WithNotecard(assetID, delegate (UUID id, AssetBase a)
  9355. {
  9356. if (a == null || a.Type != 7)
  9357. {
  9358. ShoutError("Notecard '" + name + "' could not be found.");
  9359. return;
  9360. }
  9361. string data = Encoding.UTF8.GetString(a.Data);
  9362. //m_log.Debug(data);
  9363. NotecardCache.Cache(id, data);
  9364. AsyncCommands.DataserverPlugin.DataserverReply(id.ToString(),
  9365. NotecardCache.GetLine(id, line, m_notecardLineReadCharsMax));
  9366. });
  9367. ScriptSleep(100);
  9368. return tid.ToString();
  9369. }
  9370. public void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc)
  9371. {
  9372. SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim));
  9373. if (obj == null)
  9374. return;
  9375. if (obj.OwnerID != m_host.OwnerID)
  9376. return;
  9377. uint rulesParsed = 0;
  9378. LSL_List remaining = SetPrimParams(obj, rules, originFunc, ref rulesParsed);
  9379. while ((object)remaining != null && remaining.Length > 2)
  9380. {
  9381. LSL_Integer newLink = remaining.GetLSLIntegerItem(0);
  9382. LSL_List newrules = remaining.GetSublist(1, -1);
  9383. foreach(SceneObjectPart part in GetLinkParts(obj, newLink)){
  9384. remaining = SetPrimParams(part, newrules, originFunc, ref rulesParsed);
  9385. }
  9386. }
  9387. }
  9388. public LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules)
  9389. {
  9390. SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim));
  9391. LSL_List result = new LSL_List();
  9392. if (obj != null && obj.OwnerID != m_host.OwnerID)
  9393. {
  9394. LSL_List remaining = GetPrimParams(obj, rules, ref result);
  9395. while (remaining != null && remaining.Length > 2)
  9396. {
  9397. int linknumber = remaining.GetLSLIntegerItem(0);
  9398. rules = remaining.GetSublist(1, -1);
  9399. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  9400. foreach (SceneObjectPart part in parts)
  9401. remaining = GetPrimParams(part, rules, ref result);
  9402. }
  9403. }
  9404. return result;
  9405. }
  9406. public void print(string str)
  9407. {
  9408. // yes, this is a real LSL function. See: http://wiki.secondlife.com/wiki/Print
  9409. IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "OSSL");
  9410. if (ossl != null)
  9411. {
  9412. ossl.CheckThreatLevel(ThreatLevel.High, "print");
  9413. m_log.Info("LSL print():" + str);
  9414. }
  9415. }
  9416. private string Name2Username(string name)
  9417. {
  9418. string[] parts = name.Split(new char[] {' '});
  9419. if (parts.Length < 2)
  9420. return name.ToLower();
  9421. if (parts[1] == "Resident")
  9422. return parts[0].ToLower();
  9423. return name.Replace(" ", ".").ToLower();
  9424. }
  9425. public LSL_String llGetUsername(string id)
  9426. {
  9427. return Name2Username(llKey2Name(id));
  9428. }
  9429. public LSL_String llRequestUsername(string id)
  9430. {
  9431. UUID rq = UUID.Random();
  9432. AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
  9433. AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), Name2Username(llKey2Name(id)));
  9434. return rq.ToString();
  9435. }
  9436. public LSL_String llGetDisplayName(string id)
  9437. {
  9438. return llKey2Name(id);
  9439. }
  9440. public LSL_String llRequestDisplayName(string id)
  9441. {
  9442. UUID rq = UUID.Random();
  9443. AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
  9444. AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), llKey2Name(id));
  9445. return rq.ToString();
  9446. }
  9447. private struct Tri
  9448. {
  9449. public Vector3 p1;
  9450. public Vector3 p2;
  9451. public Vector3 p3;
  9452. }
  9453. private bool InBoundingBox(ScenePresence avatar, Vector3 point)
  9454. {
  9455. float height = avatar.Appearance.AvatarHeight;
  9456. Vector3 b1 = avatar.AbsolutePosition + new Vector3(-0.22f, -0.22f, -height/2);
  9457. Vector3 b2 = avatar.AbsolutePosition + new Vector3(0.22f, 0.22f, height/2);
  9458. if (point.X > b1.X && point.X < b2.X &&
  9459. point.Y > b1.Y && point.Y < b2.Y &&
  9460. point.Z > b1.Z && point.Z < b2.Z)
  9461. return true;
  9462. return false;
  9463. }
  9464. private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd)
  9465. {
  9466. List<ContactResult> contacts = new List<ContactResult>();
  9467. Vector3 ab = rayEnd - rayStart;
  9468. World.ForEachScenePresence(delegate(ScenePresence sp)
  9469. {
  9470. Vector3 ac = sp.AbsolutePosition - rayStart;
  9471. Vector3 bc = sp.AbsolutePosition - rayEnd;
  9472. double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
  9473. if (d > 1.5)
  9474. return;
  9475. double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
  9476. if (d2 > 0)
  9477. return;
  9478. double dp = Math.Sqrt(Vector3.Mag(ac) * Vector3.Mag(ac) - d * d);
  9479. Vector3 p = rayStart + Vector3.Divide(Vector3.Multiply(ab, (float)dp), (float)Vector3.Mag(ab));
  9480. if (!InBoundingBox(sp, p))
  9481. return;
  9482. ContactResult result = new ContactResult ();
  9483. result.ConsumerID = sp.LocalId;
  9484. result.Depth = Vector3.Distance(rayStart, p);
  9485. result.Normal = Vector3.Zero;
  9486. result.Pos = p;
  9487. contacts.Add(result);
  9488. });
  9489. return contacts.ToArray();
  9490. }
  9491. private ContactResult[] ObjectIntersection(Vector3 rayStart, Vector3 rayEnd, bool includePhysical, bool includeNonPhysical, bool includePhantom)
  9492. {
  9493. Ray ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
  9494. List<ContactResult> contacts = new List<ContactResult>();
  9495. Vector3 ab = rayEnd - rayStart;
  9496. World.ForEachSOG(delegate(SceneObjectGroup group)
  9497. {
  9498. if (m_host.ParentGroup == group)
  9499. return;
  9500. if (group.IsAttachment)
  9501. return;
  9502. if (group.RootPart.PhysActor == null)
  9503. {
  9504. if (!includePhantom)
  9505. return;
  9506. }
  9507. else
  9508. {
  9509. if (group.RootPart.PhysActor.IsPhysical)
  9510. {
  9511. if (!includePhysical)
  9512. return;
  9513. }
  9514. else
  9515. {
  9516. if (!includeNonPhysical)
  9517. return;
  9518. }
  9519. }
  9520. // Find the radius ouside of which we don't even need to hit test
  9521. float minX;
  9522. float maxX;
  9523. float minY;
  9524. float maxY;
  9525. float minZ;
  9526. float maxZ;
  9527. float radius = 0.0f;
  9528. group.GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
  9529. if (Math.Abs(minX) > radius)
  9530. radius = Math.Abs(minX);
  9531. if (Math.Abs(minY) > radius)
  9532. radius = Math.Abs(minY);
  9533. if (Math.Abs(minZ) > radius)
  9534. radius = Math.Abs(minZ);
  9535. if (Math.Abs(maxX) > radius)
  9536. radius = Math.Abs(maxX);
  9537. if (Math.Abs(maxY) > radius)
  9538. radius = Math.Abs(maxY);
  9539. if (Math.Abs(maxZ) > radius)
  9540. radius = Math.Abs(maxZ);
  9541. radius = radius*1.413f;
  9542. Vector3 ac = group.AbsolutePosition - rayStart;
  9543. Vector3 bc = group.AbsolutePosition - rayEnd;
  9544. double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
  9545. // Too far off ray, don't bother
  9546. if (d > radius)
  9547. return;
  9548. // Behind ray, drop
  9549. double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
  9550. if (d2 > 0)
  9551. return;
  9552. ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
  9553. EntityIntersection intersection = group.TestIntersection(ray, true, false);
  9554. // Miss.
  9555. if (!intersection.HitTF)
  9556. return;
  9557. Vector3 b1 = group.AbsolutePosition + new Vector3(minX, minY, minZ);
  9558. Vector3 b2 = group.AbsolutePosition + new Vector3(maxX, maxY, maxZ);
  9559. //m_log.DebugFormat("[LLCASTRAY]: min<{0},{1},{2}>, max<{3},{4},{5}> = hitp<{6},{7},{8}>", b1.X,b1.Y,b1.Z,b2.X,b2.Y,b2.Z,intersection.ipoint.X,intersection.ipoint.Y,intersection.ipoint.Z);
  9560. if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X &&
  9561. intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y &&
  9562. intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z))
  9563. return;
  9564. ContactResult result = new ContactResult ();
  9565. result.ConsumerID = group.LocalId;
  9566. result.Depth = intersection.distance;
  9567. result.Normal = intersection.normal;
  9568. result.Pos = intersection.ipoint;
  9569. contacts.Add(result);
  9570. });
  9571. return contacts.ToArray();
  9572. }
  9573. private ContactResult? GroundIntersection(Vector3 rayStart, Vector3 rayEnd)
  9574. {
  9575. double[,] heightfield = World.Heightmap.GetDoubles();
  9576. List<ContactResult> contacts = new List<ContactResult>();
  9577. double min = 2048.0;
  9578. double max = 0.0;
  9579. // Find the min and max of the heightfield
  9580. for (int x = 0 ; x < World.Heightmap.Width ; x++)
  9581. {
  9582. for (int y = 0 ; y < World.Heightmap.Height ; y++)
  9583. {
  9584. if (heightfield[x, y] > max)
  9585. max = heightfield[x, y];
  9586. if (heightfield[x, y] < min)
  9587. min = heightfield[x, y];
  9588. }
  9589. }
  9590. // A ray extends past rayEnd, but doesn't go back before
  9591. // rayStart. If the start is above the highest point of the ground
  9592. // and the ray goes up, we can't hit the ground. Ever.
  9593. if (rayStart.Z > max && rayEnd.Z >= rayStart.Z)
  9594. return null;
  9595. // Same for going down
  9596. if (rayStart.Z < min && rayEnd.Z <= rayStart.Z)
  9597. return null;
  9598. List<Tri> trilist = new List<Tri>();
  9599. // Create our triangle list
  9600. for (int x = 1 ; x < World.Heightmap.Width ; x++)
  9601. {
  9602. for (int y = 1 ; y < World.Heightmap.Height ; y++)
  9603. {
  9604. Tri t1 = new Tri();
  9605. Tri t2 = new Tri();
  9606. Vector3 p1 = new Vector3(x-1, y-1, (float)heightfield[x-1, y-1]);
  9607. Vector3 p2 = new Vector3(x, y-1, (float)heightfield[x, y-1]);
  9608. Vector3 p3 = new Vector3(x, y, (float)heightfield[x, y]);
  9609. Vector3 p4 = new Vector3(x-1, y, (float)heightfield[x-1, y]);
  9610. t1.p1 = p1;
  9611. t1.p2 = p2;
  9612. t1.p3 = p3;
  9613. t2.p1 = p3;
  9614. t2.p2 = p4;
  9615. t2.p3 = p1;
  9616. trilist.Add(t1);
  9617. trilist.Add(t2);
  9618. }
  9619. }
  9620. // Ray direction
  9621. Vector3 rayDirection = rayEnd - rayStart;
  9622. foreach (Tri t in trilist)
  9623. {
  9624. // Compute triangle plane normal and edges
  9625. Vector3 u = t.p2 - t.p1;
  9626. Vector3 v = t.p3 - t.p1;
  9627. Vector3 n = Vector3.Cross(u, v);
  9628. if (n == Vector3.Zero)
  9629. continue;
  9630. Vector3 w0 = rayStart - t.p1;
  9631. double a = -Vector3.Dot(n, w0);
  9632. double b = Vector3.Dot(n, rayDirection);
  9633. // Not intersecting the plane, or in plane (same thing)
  9634. // Ignoring this MAY cause the ground to not be detected
  9635. // sometimes
  9636. if (Math.Abs(b) < 0.000001)
  9637. continue;
  9638. double r = a / b;
  9639. // ray points away from plane
  9640. if (r < 0.0)
  9641. continue;
  9642. Vector3 ip = rayStart + Vector3.Multiply(rayDirection, (float)r);
  9643. float uu = Vector3.Dot(u, u);
  9644. float uv = Vector3.Dot(u, v);
  9645. float vv = Vector3.Dot(v, v);
  9646. Vector3 w = ip - t.p1;
  9647. float wu = Vector3.Dot(w, u);
  9648. float wv = Vector3.Dot(w, v);
  9649. float d = uv * uv - uu * vv;
  9650. float cs = (uv * wv - vv * wu) / d;
  9651. if (cs < 0 || cs > 1.0)
  9652. continue;
  9653. float ct = (uv * wu - uu * wv) / d;
  9654. if (ct < 0 || (cs + ct) > 1.0)
  9655. continue;
  9656. // Add contact point
  9657. ContactResult result = new ContactResult ();
  9658. result.ConsumerID = 0;
  9659. result.Depth = Vector3.Distance(rayStart, ip);
  9660. result.Normal = n;
  9661. result.Pos = ip;
  9662. contacts.Add(result);
  9663. }
  9664. if (contacts.Count == 0)
  9665. return null;
  9666. contacts.Sort(delegate(ContactResult a, ContactResult b)
  9667. {
  9668. return (int)(a.Depth - b.Depth);
  9669. });
  9670. return contacts[0];
  9671. }
  9672. public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
  9673. {
  9674. LSL_List list = new LSL_List();
  9675. m_host.AddScriptLPS(1);
  9676. Vector3 rayStart = start;
  9677. Vector3 rayEnd = end;
  9678. Vector3 dir = rayEnd - rayStart;
  9679. float dist = Vector3.Mag(dir);
  9680. int count = 1;
  9681. bool detectPhantom = false;
  9682. int dataFlags = 0;
  9683. int rejectTypes = 0;
  9684. for (int i = 0; i < options.Length; i += 2)
  9685. {
  9686. if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
  9687. count = options.GetLSLIntegerItem(i + 1);
  9688. else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
  9689. detectPhantom = (options.GetLSLIntegerItem(i + 1) > 0);
  9690. else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
  9691. dataFlags = options.GetLSLIntegerItem(i + 1);
  9692. else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
  9693. rejectTypes = options.GetLSLIntegerItem(i + 1);
  9694. }
  9695. if (count > 16)
  9696. count = 16;
  9697. List<ContactResult> results = new List<ContactResult>();
  9698. bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND);
  9699. bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS);
  9700. bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL);
  9701. bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL);
  9702. if (World.SupportsRayCastFiltered())
  9703. {
  9704. if (dist == 0)
  9705. return list;
  9706. RayFilterFlags rayfilter = RayFilterFlags.ClosestAndBackCull;
  9707. if (checkTerrain)
  9708. rayfilter |= RayFilterFlags.land;
  9709. // if (checkAgents)
  9710. // rayfilter |= RayFilterFlags.agent;
  9711. if (checkPhysical)
  9712. rayfilter |= RayFilterFlags.physical;
  9713. if (checkNonPhysical)
  9714. rayfilter |= RayFilterFlags.nonphysical;
  9715. if (detectPhantom)
  9716. rayfilter |= RayFilterFlags.LSLPhantom;
  9717. Vector3 direction = dir * ( 1/dist);
  9718. if(rayfilter == 0)
  9719. {
  9720. list.Add(new LSL_Integer(0));
  9721. return list;
  9722. }
  9723. // get some more contacts to sort ???
  9724. int physcount = 4 * count;
  9725. if (physcount > 20)
  9726. physcount = 20;
  9727. object physresults;
  9728. physresults = World.RayCastFiltered(rayStart, direction, dist, physcount, rayfilter);
  9729. if (physresults == null)
  9730. {
  9731. list.Add(new LSL_Integer(-3)); // timeout error
  9732. return list;
  9733. }
  9734. results = (List<ContactResult>)physresults;
  9735. // for now physics doesn't detect sitted avatars so do it outside physics
  9736. if (checkAgents)
  9737. {
  9738. ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
  9739. foreach (ContactResult r in agentHits)
  9740. results.Add(r);
  9741. }
  9742. // TODO: Replace this with a better solution. ObjectIntersection can only
  9743. // detect nonphysical phantoms. They are detected by virtue of being
  9744. // nonphysical (e.g. no PhysActor) so will not conflict with detecting
  9745. // physicsl phantoms as done by the physics scene
  9746. // We don't want anything else but phantoms here.
  9747. if (detectPhantom)
  9748. {
  9749. ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, false, false, true);
  9750. foreach (ContactResult r in objectHits)
  9751. results.Add(r);
  9752. }
  9753. }
  9754. else
  9755. {
  9756. if (checkAgents)
  9757. {
  9758. ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
  9759. foreach (ContactResult r in agentHits)
  9760. results.Add(r);
  9761. }
  9762. if (checkPhysical || checkNonPhysical || detectPhantom)
  9763. {
  9764. ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
  9765. for (int iter = 0; iter < objectHits.Length; iter++)
  9766. {
  9767. // Redistance the Depth because the Scene RayCaster returns distance from center to make the rezzing code simpler.
  9768. objectHits[iter].Depth = Vector3.Distance(objectHits[iter].Pos, rayStart);
  9769. results.Add(objectHits[iter]);
  9770. }
  9771. }
  9772. }
  9773. if (checkTerrain)
  9774. {
  9775. ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
  9776. if (groundContact != null)
  9777. results.Add((ContactResult)groundContact);
  9778. }
  9779. results.Sort(delegate(ContactResult a, ContactResult b)
  9780. {
  9781. return a.Depth.CompareTo(b.Depth);
  9782. });
  9783. int values = 0;
  9784. SceneObjectGroup thisgrp = m_host.ParentGroup;
  9785. foreach (ContactResult result in results)
  9786. {
  9787. if (result.Depth > dist)
  9788. continue;
  9789. // physics ray can return colisions with host prim
  9790. if (m_host.LocalId == result.ConsumerID)
  9791. continue;
  9792. UUID itemID = UUID.Zero;
  9793. int linkNum = 0;
  9794. SceneObjectPart part = World.GetSceneObjectPart(result.ConsumerID);
  9795. // It's a prim!
  9796. if (part != null)
  9797. {
  9798. // dont detect members of same object ???
  9799. if (part.ParentGroup == thisgrp)
  9800. continue;
  9801. if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY)
  9802. itemID = part.ParentGroup.UUID;
  9803. else
  9804. itemID = part.UUID;
  9805. linkNum = part.LinkNum;
  9806. }
  9807. else
  9808. {
  9809. ScenePresence sp = World.GetScenePresence(result.ConsumerID);
  9810. /// It it a boy? a girl?
  9811. if (sp != null)
  9812. itemID = sp.UUID;
  9813. }
  9814. list.Add(new LSL_String(itemID.ToString()));
  9815. list.Add(new LSL_String(result.Pos.ToString()));
  9816. if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM)
  9817. list.Add(new LSL_Integer(linkNum));
  9818. if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
  9819. list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z));
  9820. values++;
  9821. if (values >= count)
  9822. break;
  9823. }
  9824. list.Add(new LSL_Integer(values));
  9825. return list;
  9826. }
  9827. public LSL_Integer llManageEstateAccess(int action, string avatar)
  9828. {
  9829. m_host.AddScriptLPS(1);
  9830. EstateSettings estate = World.RegionInfo.EstateSettings;
  9831. bool isAccount = false;
  9832. bool isGroup = false;
  9833. if (!estate.IsEstateOwner(m_host.OwnerID) || !estate.IsEstateManagerOrOwner(m_host.OwnerID))
  9834. return 0;
  9835. UUID id = new UUID();
  9836. if (!UUID.TryParse(avatar, out id))
  9837. return 0;
  9838. UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, id);
  9839. isAccount = account != null ? true : false;
  9840. if (!isAccount)
  9841. {
  9842. IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
  9843. if (groups != null)
  9844. {
  9845. GroupRecord group = groups.GetGroupRecord(id);
  9846. isGroup = group != null ? true : false;
  9847. if (!isGroup)
  9848. return 0;
  9849. }
  9850. else
  9851. return 0;
  9852. }
  9853. switch (action)
  9854. {
  9855. case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_ADD:
  9856. if (!isAccount) return 0;
  9857. if (estate.HasAccess(id)) return 1;
  9858. if (estate.IsBanned(id))
  9859. estate.RemoveBan(id);
  9860. estate.AddEstateUser(id);
  9861. break;
  9862. case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_REMOVE:
  9863. if (!isAccount || !estate.HasAccess(id)) return 0;
  9864. estate.RemoveEstateUser(id);
  9865. break;
  9866. case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_GROUP_ADD:
  9867. if (!isGroup) return 0;
  9868. if (estate.GroupAccess(id)) return 1;
  9869. estate.AddEstateGroup(id);
  9870. break;
  9871. case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_GROUP_REMOVE:
  9872. if (!isGroup || !estate.GroupAccess(id)) return 0;
  9873. estate.RemoveEstateGroup(id);
  9874. break;
  9875. case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_ADD:
  9876. if (!isAccount) return 0;
  9877. if (estate.IsBanned(id)) return 1;
  9878. EstateBan ban = new EstateBan();
  9879. ban.EstateID = estate.EstateID;
  9880. ban.BannedUserID = id;
  9881. estate.AddBan(ban);
  9882. break;
  9883. case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_REMOVE:
  9884. if (!isAccount || !estate.IsBanned(id)) return 0;
  9885. estate.RemoveBan(id);
  9886. break;
  9887. default: return 0;
  9888. }
  9889. return 1;
  9890. }
  9891. public LSL_Integer llGetMemoryLimit()
  9892. {
  9893. m_host.AddScriptLPS(1);
  9894. // The value returned for LSO scripts in SL
  9895. return 16384;
  9896. }
  9897. public LSL_Integer llSetMemoryLimit(LSL_Integer limit)
  9898. {
  9899. m_host.AddScriptLPS(1);
  9900. // Treat as an LSO script
  9901. return ScriptBaseClass.FALSE;
  9902. }
  9903. public LSL_Integer llGetSPMaxMemory()
  9904. {
  9905. m_host.AddScriptLPS(1);
  9906. // The value returned for LSO scripts in SL
  9907. return 16384;
  9908. }
  9909. public LSL_Integer llGetUsedMemory()
  9910. {
  9911. m_host.AddScriptLPS(1);
  9912. // The value returned for LSO scripts in SL
  9913. return 16384;
  9914. }
  9915. public void llScriptProfiler(LSL_Integer flags)
  9916. {
  9917. m_host.AddScriptLPS(1);
  9918. // This does nothing for LSO scripts in SL
  9919. }
  9920. #region Not Implemented
  9921. //
  9922. // Listing the unimplemented lsl functions here, please move
  9923. // them from this region as they are completed
  9924. //
  9925. public void llGetEnv(LSL_String name)
  9926. {
  9927. m_host.AddScriptLPS(1);
  9928. NotImplemented("llGetEnv");
  9929. }
  9930. public void llSetSoundQueueing(int queue)
  9931. {
  9932. m_host.AddScriptLPS(1);
  9933. NotImplemented("llSetSoundQueueing");
  9934. }
  9935. public void llCollisionSprite(string impact_sprite)
  9936. {
  9937. m_host.AddScriptLPS(1);
  9938. NotImplemented("llCollisionSprite");
  9939. }
  9940. public void llGodLikeRezObject(string inventory, LSL_Vector pos)
  9941. {
  9942. m_host.AddScriptLPS(1);
  9943. NotImplemented("llGodLikeRezObject");
  9944. }
  9945. public LSL_String llTransferLindenDollars(string destination, int amount)
  9946. {
  9947. UUID txn = UUID.Random();
  9948. Util.FireAndForget(delegate(object x)
  9949. {
  9950. int replycode = 0;
  9951. string replydata = destination + "," + amount.ToString();
  9952. try
  9953. {
  9954. TaskInventoryItem item = m_item;
  9955. if (item == null)
  9956. {
  9957. replydata = "SERVICE_ERROR";
  9958. return;
  9959. }
  9960. m_host.AddScriptLPS(1);
  9961. if (item.PermsGranter == UUID.Zero)
  9962. {
  9963. replydata = "MISSING_PERMISSION_DEBIT";
  9964. return;
  9965. }
  9966. if ((item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
  9967. {
  9968. replydata = "MISSING_PERMISSION_DEBIT";
  9969. return;
  9970. }
  9971. UUID toID = new UUID();
  9972. if (!UUID.TryParse(destination, out toID))
  9973. {
  9974. replydata = "INVALID_AGENT";
  9975. return;
  9976. }
  9977. IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
  9978. if (money == null)
  9979. {
  9980. replydata = "TRANSFERS_DISABLED";
  9981. return;
  9982. }
  9983. bool result = money.ObjectGiveMoney(
  9984. m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
  9985. if (result)
  9986. {
  9987. replycode = 1;
  9988. return;
  9989. }
  9990. replydata = "LINDENDOLLAR_INSUFFICIENTFUNDS";
  9991. }
  9992. finally
  9993. {
  9994. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
  9995. "transaction_result", new Object[] {
  9996. new LSL_String(txn.ToString()),
  9997. new LSL_Integer(replycode),
  9998. new LSL_String(replydata) },
  9999. new DetectParams[0]));
  10000. }
  10001. });
  10002. return txn.ToString();
  10003. }
  10004. #endregion
  10005. }
  10006. public class NotecardCache
  10007. {
  10008. protected class Notecard
  10009. {
  10010. public string[] text;
  10011. public DateTime lastRef;
  10012. }
  10013. protected static Dictionary<UUID, Notecard> m_Notecards =
  10014. new Dictionary<UUID, Notecard>();
  10015. public static void Cache(UUID assetID, string text)
  10016. {
  10017. CacheCheck();
  10018. lock (m_Notecards)
  10019. {
  10020. if (m_Notecards.ContainsKey(assetID))
  10021. return;
  10022. Notecard nc = new Notecard();
  10023. nc.lastRef = DateTime.Now;
  10024. nc.text = SLUtil.ParseNotecardToList(text).ToArray();
  10025. m_Notecards[assetID] = nc;
  10026. }
  10027. }
  10028. public static bool IsCached(UUID assetID)
  10029. {
  10030. lock (m_Notecards)
  10031. {
  10032. return m_Notecards.ContainsKey(assetID);
  10033. }
  10034. }
  10035. public static int GetLines(UUID assetID)
  10036. {
  10037. if (!IsCached(assetID))
  10038. return -1;
  10039. lock (m_Notecards)
  10040. {
  10041. m_Notecards[assetID].lastRef = DateTime.Now;
  10042. return m_Notecards[assetID].text.Length;
  10043. }
  10044. }
  10045. /// <summary>
  10046. /// Get a notecard line.
  10047. /// </summary>
  10048. /// <param name="assetID"></param>
  10049. /// <param name="lineNumber">Lines start at index 0</param>
  10050. /// <returns></returns>
  10051. public static string GetLine(UUID assetID, int lineNumber)
  10052. {
  10053. if (lineNumber < 0)
  10054. return "";
  10055. string data;
  10056. if (!IsCached(assetID))
  10057. return "";
  10058. lock (m_Notecards)
  10059. {
  10060. m_Notecards[assetID].lastRef = DateTime.Now;
  10061. if (lineNumber >= m_Notecards[assetID].text.Length)
  10062. return "\n\n\n";
  10063. data = m_Notecards[assetID].text[lineNumber];
  10064. return data;
  10065. }
  10066. }
  10067. /// <summary>
  10068. /// Get a notecard line.
  10069. /// </summary>
  10070. /// <param name="assetID"></param>
  10071. /// <param name="lineNumber">Lines start at index 0</param>
  10072. /// <param name="maxLength">
  10073. /// Maximum length of the returned line.
  10074. /// </param>
  10075. /// <returns>
  10076. /// If the line length is longer than <paramref name="maxLength"/>,
  10077. /// the return string will be truncated.
  10078. /// </returns>
  10079. public static string GetLine(UUID assetID, int lineNumber, int maxLength)
  10080. {
  10081. string line = GetLine(assetID, lineNumber);
  10082. if (line.Length > maxLength)
  10083. line = line.Substring(0, maxLength);
  10084. return line;
  10085. }
  10086. public static void CacheCheck()
  10087. {
  10088. foreach (UUID key in new List<UUID>(m_Notecards.Keys))
  10089. {
  10090. Notecard nc = m_Notecards[key];
  10091. if (nc.lastRef.AddSeconds(30) < DateTime.Now)
  10092. m_Notecards.Remove(key);
  10093. }
  10094. }
  10095. }
  10096. }