/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
C# | 11784 lines | 8932 code | 1681 blank | 1171 comment | 1937 complexity | cd8c1e05459df14cd225b18da69481df MD5 | raw file
Possible License(s): Unlicense, MIT, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Runtime.Remoting.Lifetime;
- using System.Text;
- using System.Threading;
- using System.Text.RegularExpressions;
- using Nini.Config;
- using log4net;
- using OpenMetaverse;
- using OpenMetaverse.Packets;
- using OpenSim;
- using OpenSim.Framework;
- using OpenSim.Region.CoreModules;
- using OpenSim.Region.CoreModules.World.Land;
- using OpenSim.Region.CoreModules.World.Terrain;
- using OpenSim.Region.Framework.Interfaces;
- using OpenSim.Region.Framework.Scenes;
- using OpenSim.Region.Framework.Scenes.Animation;
- using OpenSim.Region.Framework.Scenes.Scripting;
- using OpenSim.Region.Physics.Manager;
- using OpenSim.Region.ScriptEngine.Shared;
- using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
- using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
- using OpenSim.Region.ScriptEngine.Interfaces;
- using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
- using OpenSim.Services.Interfaces;
- using GridRegion = OpenSim.Services.Interfaces.GridRegion;
- using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
- using PrimType = OpenSim.Region.Framework.Scenes.PrimType;
- using AssetLandmark = OpenSim.Framework.AssetLandmark;
- using RegionFlags = OpenSim.Framework.RegionFlags;
- using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
- using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
- using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
- using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
- using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
- using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
- using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
- using System.Reflection;
- namespace OpenSim.Region.ScriptEngine.Shared.Api
- {
- // MUST be a ref type
- public class UserInfoCacheEntry
- {
- public int time;
- public UserAccount account;
- public PresenceInfo pinfo;
- }
- /// <summary>
- /// Contains all LSL ll-functions. This class will be in Default AppDomain.
- /// </summary>
- public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
- {
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- protected IScriptEngine m_ScriptEngine;
- protected SceneObjectPart m_host;
- /// <summary>
- /// Used for script sleeps when we are using co-operative script termination.
- /// </summary>
- /// <remarks>null if co-operative script termination is not active</remarks>
- WaitHandle m_coopSleepHandle;
- /// <summary>
- /// The item that hosts this script
- /// </summary>
- protected TaskInventoryItem m_item;
- protected bool throwErrorOnNotImplemented = true;
- protected AsyncCommandManager AsyncCommands = null;
- protected float m_ScriptDelayFactor = 1.0f;
- protected float m_ScriptDistanceFactor = 1.0f;
- protected float m_MinTimerInterval = 0.5f;
- protected float m_recoilScaleFactor = 0.0f;
- protected DateTime m_timer = DateTime.Now;
- protected bool m_waitingForScriptAnswer = false;
- protected bool m_automaticLinkPermission = false;
- protected IMessageTransferModule m_TransferModule = null;
- protected int m_notecardLineReadCharsMax = 255;
- protected int m_scriptConsoleChannel = 0;
- protected bool m_scriptConsoleChannelEnabled = false;
- protected IUrlModule m_UrlModule = null;
- protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache = new Dictionary<UUID, UserInfoCacheEntry>();
- protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp.
- protected ISoundModule m_SoundModule = null;
- public void Initialize(
- IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle)
- {
- m_ScriptEngine = scriptEngine;
- m_host = host;
- m_item = item;
- m_coopSleepHandle = coopSleepHandle;
- LoadConfig();
- m_TransferModule =
- m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>();
- m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>();
- m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>();
- AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
- }
- /// <summary>
- /// Load configuration items that affect script, object and run-time behavior. */
- /// </summary>
- private void LoadConfig()
- {
- m_ScriptDelayFactor =
- m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f);
- m_ScriptDistanceFactor =
- m_ScriptEngine.Config.GetFloat("ScriptDistanceLimitFactor", 1.0f);
- m_MinTimerInterval =
- m_ScriptEngine.Config.GetFloat("MinTimerInterval", 0.5f);
- m_automaticLinkPermission =
- m_ScriptEngine.Config.GetBoolean("AutomaticLinkPermission", false);
- m_notecardLineReadCharsMax =
- m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255);
- if (m_notecardLineReadCharsMax > 65535)
- m_notecardLineReadCharsMax = 65535;
- // load limits for particular subsystems.
- IConfig SMTPConfig;
- if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) {
- // there's an smtp config, so load in the snooze time.
- EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME);
- }
- // Rezzing an object with a velocity can create recoil. This feature seems to have been
- // removed from recent versions of SL. The code computes recoil (vel*mass) and scales
- // it by this factor. May be zero to turn off recoil all together.
- m_recoilScaleFactor = m_ScriptEngine.Config.GetFloat("RecoilScaleFactor", m_recoilScaleFactor);
- }
- public override Object InitializeLifetimeService()
- {
- ILease lease = (ILease)base.InitializeLifetimeService();
- if (lease.CurrentState == LeaseState.Initial)
- {
- lease.InitialLeaseTime = TimeSpan.FromMinutes(0);
- // lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
- // lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
- }
- return lease;
- }
- protected virtual void ScriptSleep(int delay)
- {
- delay = (int)((float)delay * m_ScriptDelayFactor);
- if (delay == 0)
- return;
- Sleep(delay);
- }
- protected virtual void Sleep(int delay)
- {
- if (m_coopSleepHandle == null)
- System.Threading.Thread.Sleep(delay);
- else
- CheckForCoopTermination(delay);
- }
- /// <summary>
- /// Check for co-operative termination.
- /// </summary>
- /// <param name='delay'>If called with 0, then just the check is performed with no wait.</param>
- protected virtual void CheckForCoopTermination(int delay)
- {
- if (m_coopSleepHandle.WaitOne(delay))
- throw new ScriptCoopStopException();
- }
- public Scene World
- {
- get { return m_ScriptEngine.World; }
- }
- public void state(string newState)
- {
- m_ScriptEngine.SetState(m_item.ItemID, newState);
- }
- /// <summary>
- /// Reset the named script. The script must be present
- /// in the same prim.
- /// </summary>
- public void llResetScript()
- {
- m_host.AddScriptLPS(1);
- // We need to tell the URL module, if we hav one, to release
- // the allocated URLs
- if (m_UrlModule != null)
- m_UrlModule.ScriptRemoved(m_item.ItemID);
- m_ScriptEngine.ApiResetScript(m_item.ItemID);
- }
- public void llResetOtherScript(string name)
- {
- UUID item;
- m_host.AddScriptLPS(1);
- if ((item = GetScriptByName(name)) != UUID.Zero)
- m_ScriptEngine.ResetScript(item);
- else
- ShoutError("llResetOtherScript: script "+name+" not found");
- }
- public LSL_Integer llGetScriptState(string name)
- {
- UUID item;
- m_host.AddScriptLPS(1);
- if ((item = GetScriptByName(name)) != UUID.Zero)
- {
- return m_ScriptEngine.GetScriptState(item) ?1:0;
- }
- ShoutError("llGetScriptState: script "+name+" not found");
- // If we didn't find it, then it's safe to
- // assume it is not running.
- return 0;
- }
- public void llSetScriptState(string name, int run)
- {
- UUID item;
- m_host.AddScriptLPS(1);
- // These functions are supposed to be robust,
- // so get the state one step at a time.
- if ((item = GetScriptByName(name)) != UUID.Zero)
- {
- m_ScriptEngine.SetScriptState(item, run == 0 ? false : true);
- }
- else
- {
- ShoutError("llSetScriptState: script "+name+" not found");
- }
- }
- public List<SceneObjectPart> GetLinkParts(int linkType)
- {
- return GetLinkParts(m_host, linkType);
- }
- public static List<SceneObjectPart> GetLinkParts(SceneObjectPart part, int linkType)
- {
- List<SceneObjectPart> ret = new List<SceneObjectPart>();
- ret.Add(part);
- switch (linkType)
- {
- case ScriptBaseClass.LINK_SET:
- return new List<SceneObjectPart>(part.ParentGroup.Parts);
- case ScriptBaseClass.LINK_ROOT:
- ret = new List<SceneObjectPart>();
- ret.Add(part.ParentGroup.RootPart);
- return ret;
- case ScriptBaseClass.LINK_ALL_OTHERS:
- ret = new List<SceneObjectPart>(part.ParentGroup.Parts);
- if (ret.Contains(part))
- ret.Remove(part);
- return ret;
- case ScriptBaseClass.LINK_ALL_CHILDREN:
- ret = new List<SceneObjectPart>(part.ParentGroup.Parts);
- if (ret.Contains(part.ParentGroup.RootPart))
- ret.Remove(part.ParentGroup.RootPart);
- return ret;
- case ScriptBaseClass.LINK_THIS:
- return ret;
- default:
- if (linkType < 0)
- return new List<SceneObjectPart>();
- SceneObjectPart target = part.ParentGroup.GetLinkNumPart(linkType);
- if (target == null)
- return new List<SceneObjectPart>();
- ret = new List<SceneObjectPart>();
- ret.Add(target);
- return ret;
- }
- }
- //These are the implementations of the various ll-functions used by the LSL scripts.
- public LSL_Float llSin(double f)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Sin(f);
- }
- public LSL_Float llCos(double f)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Cos(f);
- }
- public LSL_Float llTan(double f)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Tan(f);
- }
- public LSL_Float llAtan2(double x, double y)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Atan2(x, y);
- }
- public LSL_Float llSqrt(double f)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Sqrt(f);
- }
- public LSL_Float llPow(double fbase, double fexponent)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Pow(fbase, fexponent);
- }
- public LSL_Integer llAbs(int i)
- {
- // changed to replicate LSL behaviour whereby minimum int value is returned untouched.
- m_host.AddScriptLPS(1);
- if (i == Int32.MinValue)
- return i;
- else
- return (int)Math.Abs(i);
- }
- public LSL_Float llFabs(double f)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Abs(f);
- }
- public LSL_Float llFrand(double mag)
- {
- m_host.AddScriptLPS(1);
- lock (Util.RandomClass)
- {
- return Util.RandomClass.NextDouble() * mag;
- }
- }
- public LSL_Integer llFloor(double f)
- {
- m_host.AddScriptLPS(1);
- return (int)Math.Floor(f);
- }
- public LSL_Integer llCeil(double f)
- {
- m_host.AddScriptLPS(1);
- return (int)Math.Ceiling(f);
- }
- // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
- public LSL_Integer llRound(double f)
- {
- m_host.AddScriptLPS(1);
- return (int)Math.Round(f, MidpointRounding.AwayFromZero);
- }
- //This next group are vector operations involving squaring and square root. ckrinke
- public LSL_Float llVecMag(LSL_Vector v)
- {
- m_host.AddScriptLPS(1);
- return LSL_Vector.Mag(v);
- }
- public LSL_Vector llVecNorm(LSL_Vector v)
- {
- m_host.AddScriptLPS(1);
- return LSL_Vector.Norm(v);
- }
- private double VecDist(LSL_Vector a, LSL_Vector b)
- {
- double dx = a.x - b.x;
- double dy = a.y - b.y;
- double dz = a.z - b.z;
- return Math.Sqrt(dx * dx + dy * dy + dz * dz);
- }
- public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b)
- {
- m_host.AddScriptLPS(1);
- return VecDist(a, b);
- }
- //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
- /// <summary>
- /// Convert an LSL rotation to a Euler vector.
- /// </summary>
- /// <remarks>
- /// Using algorithm based off http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/quat_2_euler_paper_ver2-1.pdf
- /// to avoid issues with singularity and rounding with Y rotation of +/- PI/2
- /// </remarks>
- /// <param name="r"></param>
- /// <returns></returns>
- public LSL_Vector llRot2Euler(LSL_Rotation r)
- {
- m_host.AddScriptLPS(1);
- LSL_Vector v = new LSL_Vector(0.0, 0.0, 1.0) * r; // Z axis unit vector unaffected by Z rotation component of r.
- double m = LSL_Vector.Mag(v); // Just in case v isn't normalized, need magnitude for Asin() operation later.
- if (m == 0.0) return new LSL_Vector();
- double x = Math.Atan2(-v.y, v.z);
- double sin = v.x / m;
- if (sin < -0.999999 || sin > 0.999999) x = 0.0; // Force X rotation to 0 at the singularities.
- double y = Math.Asin(sin);
- // Rotate X axis unit vector by r and unwind the X and Y rotations leaving only the Z rotation
- 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)));
- double z = Math.Atan2(v.y, v.x);
- return new LSL_Vector(x, y, z);
- }
- /* From wiki:
- The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes
- in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation,
- a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting
- vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis.
- */
- /* How we arrived at this llEuler2Rot
- *
- * Experiment in SL to determine conventions:
- * llEuler2Rot(<PI,0,0>)=<1,0,0,0>
- * llEuler2Rot(<0,PI,0>)=<0,1,0,0>
- * llEuler2Rot(<0,0,PI>)=<0,0,1,0>
- *
- * Important facts about Quaternions
- * - multiplication is non-commutative (a*b != b*a)
- * - http://en.wikipedia.org/wiki/Quaternion#Basis_multiplication
- *
- * Above SL experiment gives (c1,c2,c3,s1,s2,s3 as defined in our llEuler2Rot):
- * Qx = c1+i*s1
- * Qy = c2+j*s2;
- * Qz = c3+k*s3;
- *
- * Rotations applied in order (from above) Z, Y, X
- * Q = (Qz * Qy) * Qx
- * ((c1+i*s1)*(c2+j*s2))*(c3+k*s3)
- * (c1*c2+i*s1*c2+j*c1*s2+ij*s1*s2)*(c3+k*s3)
- * (c1*c2+i*s1*c2+j*c1*s2+k*s1*s2)*(c3+k*s3)
- * 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
- * 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
- * regroup: x=i*(s1*c2*c3+c1*s2*s3)
- * y=j*(c1*s2*c3-s1*c2*s3)
- * z=k*(s1*s2*c3+c1*c2*s3)
- * s= c1*c2*c3-s1*s2*s3
- *
- * This implementation agrees with the functions found here:
- * http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions
- * And with the results in SL.
- *
- * It's also possible to calculate llEuler2Rot by direct multiplication of
- * the Qz, Qy, and Qx vectors (as above - and done in the "accurate" function
- * from the wiki).
- * Apparently in some cases this is better from a numerical precision perspective?
- */
- public LSL_Rotation llEuler2Rot(LSL_Vector v)
- {
- m_host.AddScriptLPS(1);
- double x,y,z,s;
- double c1 = Math.Cos(v.x * 0.5);
- double c2 = Math.Cos(v.y * 0.5);
- double c3 = Math.Cos(v.z * 0.5);
- double s1 = Math.Sin(v.x * 0.5);
- double s2 = Math.Sin(v.y * 0.5);
- double s3 = Math.Sin(v.z * 0.5);
- x = s1 * c2 * c3 + c1 * s2 * s3;
- y = c1 * s2 * c3 - s1 * c2 * s3;
- z = s1 * s2 * c3 + c1 * c2 * s3;
- s = c1 * c2 * c3 - s1 * s2 * s3;
- return new LSL_Rotation(x, y, z, s);
- }
- public LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up)
- {
- m_host.AddScriptLPS(1);
- double s;
- double tr = fwd.x + left.y + up.z + 1.0;
- if (tr >= 1.0)
- {
- s = 0.5 / Math.Sqrt(tr);
- return new LSL_Rotation(
- (left.z - up.y) * s,
- (up.x - fwd.z) * s,
- (fwd.y - left.x) * s,
- 0.25 / s);
- }
- else
- {
- double max = (left.y > up.z) ? left.y : up.z;
- if (max < fwd.x)
- {
- s = Math.Sqrt(fwd.x - (left.y + up.z) + 1.0);
- double x = s * 0.5;
- s = 0.5 / s;
- return new LSL_Rotation(
- x,
- (fwd.y + left.x) * s,
- (up.x + fwd.z) * s,
- (left.z - up.y) * s);
- }
- else if (max == left.y)
- {
- s = Math.Sqrt(left.y - (up.z + fwd.x) + 1.0);
- double y = s * 0.5;
- s = 0.5 / s;
- return new LSL_Rotation(
- (fwd.y + left.x) * s,
- y,
- (left.z + up.y) * s,
- (up.x - fwd.z) * s);
- }
- else
- {
- s = Math.Sqrt(up.z - (fwd.x + left.y) + 1.0);
- double z = s * 0.5;
- s = 0.5 / s;
- return new LSL_Rotation(
- (up.x + fwd.z) * s,
- (left.z + up.y) * s,
- z,
- (fwd.y - left.x) * s);
- }
- }
- }
- public LSL_Vector llRot2Fwd(LSL_Rotation r)
- {
- m_host.AddScriptLPS(1);
- double x, y, z, m;
- m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
- // m is always greater than zero
- // if m is not equal to 1 then Rotation needs to be normalized
- if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
- {
- m = 1.0 / Math.Sqrt(m);
- r.x *= m;
- r.y *= m;
- r.z *= m;
- r.s *= m;
- }
- // Fast Algebric Calculations instead of Vectors & Quaternions Product
- x = r.x * r.x - r.y * r.y - r.z * r.z + r.s * r.s;
- y = 2 * (r.x * r.y + r.z * r.s);
- z = 2 * (r.x * r.z - r.y * r.s);
- return (new LSL_Vector(x, y, z));
- }
- public LSL_Vector llRot2Left(LSL_Rotation r)
- {
- m_host.AddScriptLPS(1);
- double x, y, z, m;
- m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
- // m is always greater than zero
- // if m is not equal to 1 then Rotation needs to be normalized
- if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
- {
- m = 1.0 / Math.Sqrt(m);
- r.x *= m;
- r.y *= m;
- r.z *= m;
- r.s *= m;
- }
- // Fast Algebric Calculations instead of Vectors & Quaternions Product
- x = 2 * (r.x * r.y - r.z * r.s);
- y = -r.x * r.x + r.y * r.y - r.z * r.z + r.s * r.s;
- z = 2 * (r.x * r.s + r.y * r.z);
- return (new LSL_Vector(x, y, z));
- }
- public LSL_Vector llRot2Up(LSL_Rotation r)
- {
- m_host.AddScriptLPS(1);
- double x, y, z, m;
- m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
- // m is always greater than zero
- // if m is not equal to 1 then Rotation needs to be normalized
- if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
- {
- m = 1.0 / Math.Sqrt(m);
- r.x *= m;
- r.y *= m;
- r.z *= m;
- r.s *= m;
- }
- // Fast Algebric Calculations instead of Vectors & Quaternions Product
- x = 2 * (r.x * r.z + r.y * r.s);
- y = 2 * (-r.x * r.s + r.y * r.z);
- z = -r.x * r.x - r.y * r.y + r.z * r.z + r.s * r.s;
- return (new LSL_Vector(x, y, z));
- }
- public LSL_Rotation llRotBetween(LSL_Vector a, LSL_Vector b)
- {
- //A and B should both be normalized
- m_host.AddScriptLPS(1);
- LSL_Rotation rotBetween;
- // Check for zero vectors. If either is zero, return zero rotation. Otherwise,
- // continue calculation.
- if (a == new LSL_Vector(0.0f, 0.0f, 0.0f) || b == new LSL_Vector(0.0f, 0.0f, 0.0f))
- {
- rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
- }
- else
- {
- a = LSL_Vector.Norm(a);
- b = LSL_Vector.Norm(b);
- double dotProduct = LSL_Vector.Dot(a, b);
- // There are two degenerate cases possible. These are for vectors 180 or
- // 0 degrees apart. These have to be detected and handled individually.
- //
- // Check for vectors 180 degrees apart.
- // A dot product of -1 would mean the angle between vectors is 180 degrees.
- if (dotProduct < -0.9999999f)
- {
- // First assume X axis is orthogonal to the vectors.
- LSL_Vector orthoVector = new LSL_Vector(1.0f, 0.0f, 0.0f);
- orthoVector = orthoVector - a * (a.x / LSL_Vector.Dot(a, a));
- // Check for near zero vector. A very small non-zero number here will create
- // a rotation in an undesired direction.
- if (LSL_Vector.Mag(orthoVector) > 0.0001)
- {
- rotBetween = new LSL_Rotation(orthoVector.x, orthoVector.y, orthoVector.z, 0.0f);
- }
- // If the magnitude of the vector was near zero, then assume the X axis is not
- // orthogonal and use the Z axis instead.
- else
- {
- // Set 180 z rotation.
- rotBetween = new LSL_Rotation(0.0f, 0.0f, 1.0f, 0.0f);
- }
- }
- // Check for parallel vectors.
- // A dot product of 1 would mean the angle between vectors is 0 degrees.
- else if (dotProduct > 0.9999999f)
- {
- // Set zero rotation.
- rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
- }
- else
- {
- // All special checks have been performed so get the axis of rotation.
- LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
- // Quarternion s value is the length of the unit vector + dot product.
- double qs = 1.0 + dotProduct;
- rotBetween = new LSL_Rotation(crossProduct.x, crossProduct.y, crossProduct.z, qs);
- // Normalize the rotation.
- double mag = LSL_Rotation.Mag(rotBetween);
- // We shouldn't have to worry about a divide by zero here. The qs value will be
- // non-zero because we already know if we're here, then the dotProduct is not -1 so
- // qs will not be zero. Also, we've already handled the input vectors being zero so the
- // crossProduct vector should also not be zero.
- rotBetween.x = rotBetween.x / mag;
- rotBetween.y = rotBetween.y / mag;
- rotBetween.z = rotBetween.z / mag;
- rotBetween.s = rotBetween.s / mag;
- // Check for undefined values and set zero rotation if any found. This code might not actually be required
- // any longer since zero vectors are checked for at the top.
- if (Double.IsNaN(rotBetween.x) || Double.IsNaN(rotBetween.y) || Double.IsNaN(rotBetween.z) || Double.IsNaN(rotBetween.s))
- {
- rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
- }
- }
- }
- return rotBetween;
- }
- public void llWhisper(int channelID, string text)
- {
- m_host.AddScriptLPS(1);
- if (text.Length > 1023)
- text = text.Substring(0, 1023);
- World.SimChat(Utils.StringToBytes(text),
- ChatTypeEnum.Whisper, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- if (wComm != null)
- wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text);
- }
- public void llSay(int channelID, string text)
- {
- m_host.AddScriptLPS(1);
- if (m_scriptConsoleChannelEnabled && (channelID == m_scriptConsoleChannel))
- {
- Console.WriteLine(text);
- }
- else
- {
- if (text.Length > 1023)
- text = text.Substring(0, 1023);
- World.SimChat(Utils.StringToBytes(text),
- ChatTypeEnum.Say, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- if (wComm != null)
- wComm.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, text);
- }
- }
- public void llShout(int channelID, string text)
- {
- m_host.AddScriptLPS(1);
- if (text.Length > 1023)
- text = text.Substring(0, 1023);
- World.SimChat(Utils.StringToBytes(text),
- ChatTypeEnum.Shout, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true);
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- if (wComm != null)
- wComm.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, text);
- }
- public void llRegionSay(int channelID, string text)
- {
- if (channelID == 0)
- {
- LSLError("Cannot use llRegionSay() on channel 0");
- return;
- }
- if (text.Length > 1023)
- text = text.Substring(0, 1023);
- m_host.AddScriptLPS(1);
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- if (wComm != null)
- wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
- }
- public void llRegionSayTo(string target, int channel, string msg)
- {
- if (msg.Length > 1023)
- msg = msg.Substring(0, 1023);
- m_host.AddScriptLPS(1);
- if (channel == ScriptBaseClass.DEBUG_CHANNEL)
- {
- return;
- }
- UUID TargetID;
- UUID.TryParse(target, out TargetID);
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- if (wComm != null)
- wComm.DeliverMessageTo(TargetID, channel, m_host.AbsolutePosition, m_host.Name, m_host.UUID, msg);
- }
- public LSL_Integer llListen(int channelID, string name, string ID, string msg)
- {
- m_host.AddScriptLPS(1);
- UUID keyID;
- UUID.TryParse(ID, out keyID);
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- if (wComm != null)
- return wComm.Listen(m_host.LocalId, m_item.ItemID, m_host.UUID, channelID, name, keyID, msg);
- else
- return -1;
- }
- public void llListenControl(int number, int active)
- {
- m_host.AddScriptLPS(1);
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- if (wComm != null)
- wComm.ListenControl(m_item.ItemID, number, active);
- }
- public void llListenRemove(int number)
- {
- m_host.AddScriptLPS(1);
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- if (wComm != null)
- wComm.ListenRemove(m_item.ItemID, number);
- }
- public void llSensor(string name, string id, int type, double range, double arc)
- {
- m_host.AddScriptLPS(1);
- UUID keyID = UUID.Zero;
- UUID.TryParse(id, out keyID);
- AsyncCommands.SensorRepeatPlugin.SenseOnce(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, m_host);
- }
- public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
- {
- m_host.AddScriptLPS(1);
- UUID keyID = UUID.Zero;
- UUID.TryParse(id, out keyID);
- AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, rate, m_host);
- }
- public void llSensorRemove()
- {
- m_host.AddScriptLPS(1);
- AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_host.LocalId, m_item.ItemID);
- }
- public string resolveName(UUID objecUUID)
- {
- // try avatar username surname
- UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, objecUUID);
- if (account != null)
- {
- string avatarname = account.Name;
- return avatarname;
- }
- // try an scene object
- SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
- if (SOP != null)
- {
- string objectname = SOP.Name;
- return objectname;
- }
- EntityBase SensedObject;
- World.Entities.TryGetValue(objecUUID, out SensedObject);
- if (SensedObject == null)
- {
- IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
- if (groups != null)
- {
- GroupRecord gr = groups.GetGroupRecord(objecUUID);
- if (gr != null)
- return gr.GroupName;
- }
- return String.Empty;
- }
- return SensedObject.Name;
- }
- public LSL_String llDetectedName(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (detectedParams == null)
- return String.Empty;
- return detectedParams.Name;
- }
- public LSL_String llDetectedKey(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (detectedParams == null)
- return String.Empty;
- return detectedParams.Key.ToString();
- }
- public LSL_String llDetectedOwner(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (detectedParams == null)
- return String.Empty;
- return detectedParams.Owner.ToString();
- }
- public LSL_Integer llDetectedType(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (detectedParams == null)
- return 0;
- return new LSL_Integer(detectedParams.Type);
- }
- public LSL_Vector llDetectedPos(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (detectedParams == null)
- return new LSL_Vector();
- return detectedParams.Position;
- }
- public LSL_Vector llDetectedVel(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (detectedParams == null)
- return new LSL_Vector();
- return detectedParams.Velocity;
- }
- public LSL_Vector llDetectedGrab(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (parms == null)
- return new LSL_Vector(0, 0, 0);
- return parms.OffsetPos;
- }
- public LSL_Rotation llDetectedRot(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (detectedParams == null)
- return new LSL_Rotation();
- return detectedParams.Rotation;
- }
- public LSL_Integer llDetectedGroup(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (detectedParams == null)
- return new LSL_Integer(0);
- if (m_host.GroupID == detectedParams.Group)
- return new LSL_Integer(1);
- return new LSL_Integer(0);
- }
- public LSL_Integer llDetectedLinkNumber(int number)
- {
- m_host.AddScriptLPS(1);
- DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
- if (parms == null)
- return new LSL_Integer(0);
- return new LSL_Integer(parms.LinkNum);
- }
- /// <summary>
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchBinormal for details
- /// </summary>
- public LSL_Vector llDetectedTouchBinormal(int index)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
- if (detectedParams == null)
- return new LSL_Vector();
- return detectedParams.TouchBinormal;
- }
- /// <summary>
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchFace for details
- /// </summary>
- public LSL_Integer llDetectedTouchFace(int index)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
- if (detectedParams == null)
- return new LSL_Integer(-1);
- return new LSL_Integer(detectedParams.TouchFace);
- }
- /// <summary>
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchNormal for details
- /// </summary>
- public LSL_Vector llDetectedTouchNormal(int index)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
- if (detectedParams == null)
- return new LSL_Vector();
- return detectedParams.TouchNormal;
- }
- /// <summary>
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchPos for details
- /// </summary>
- public LSL_Vector llDetectedTouchPos(int index)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
- if (detectedParams == null)
- return new LSL_Vector();
- return detectedParams.TouchPos;
- }
- /// <summary>
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchST for details
- /// </summary>
- public LSL_Vector llDetectedTouchST(int index)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
- if (detectedParams == null)
- return new LSL_Vector(-1.0, -1.0, 0.0);
- return detectedParams.TouchST;
- }
- /// <summary>
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchUV for details
- /// </summary>
- public LSL_Vector llDetectedTouchUV(int index)
- {
- m_host.AddScriptLPS(1);
- DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
- if (detectedParams == null)
- return new LSL_Vector(-1.0, -1.0, 0.0);
- return detectedParams.TouchUV;
- }
- public virtual void llDie()
- {
- m_host.AddScriptLPS(1);
- throw new SelfDeleteException();
- }
- public LSL_Float llGround(LSL_Vector offset)
- {
- m_host.AddScriptLPS(1);
- Vector3 pos = m_host.GetWorldPosition() + (Vector3)offset;
- //Get the slope normal. This gives us the equation of the plane tangent to the slope.
- LSL_Vector vsn = llGroundNormal(offset);
- // Clamp to valid position
- if (pos.X < 0)
- pos.X = 0;
- else if (pos.X >= World.Heightmap.Width)
- pos.X = World.Heightmap.Width - 1;
- if (pos.Y < 0)
- pos.Y = 0;
- else if (pos.Y >= World.Heightmap.Height)
- pos.Y = World.Heightmap.Height - 1;
- //Get the height for the integer coordinates from the Heightmap
- float baseheight = (float)World.Heightmap[(int)pos.X, (int)pos.Y];
- //Calculate the difference between the actual coordinates and the integer coordinates
- float xdiff = pos.X - (float)((int)pos.X);
- float ydiff = pos.Y - (float)((int)pos.Y);
- //Use the equation of the tangent plane to adjust the height to account for slope
- return (((vsn.x * xdiff) + (vsn.y * ydiff)) / (-1 * vsn.z)) + baseheight;
- }
- public LSL_Float llCloud(LSL_Vector offset)
- {
- m_host.AddScriptLPS(1);
- float cloudCover = 0f;
- ICloudModule module = World.RequestModuleInterface<ICloudModule>();
- if (module != null)
- {
- Vector3 pos = m_host.GetWorldPosition();
- int x = (int)(pos.X + offset.x);
- int y = (int)(pos.Y + offset.y);
- cloudCover = module.CloudCover(x, y, 0);
- }
- return cloudCover;
- }
- public LSL_Vector llWind(LSL_Vector offset)
- {
- m_host.AddScriptLPS(1);
- LSL_Vector wind = new LSL_Vector(0, 0, 0);
- IWindModule module = World.RequestModuleInterface<IWindModule>();
- if (module != null)
- {
- Vector3 pos = m_host.GetWorldPosition();
- int x = (int)(pos.X + offset.x);
- int y = (int)(pos.Y + offset.y);
- Vector3 windSpeed = module.WindSpeed(x, y, 0);
- wind.x = windSpeed.X;
- wind.y = windSpeed.Y;
- }
- return wind;
- }
- public void llSetStatus(int status, int value)
- {
- m_host.AddScriptLPS(1);
- int statusrotationaxis = 0;
- if ((status & ScriptBaseClass.STATUS_PHYSICS) == ScriptBaseClass.STATUS_PHYSICS)
- {
- if (value != 0)
- {
- SceneObjectGroup group = m_host.ParentGroup;
- bool allow = true;
- foreach (SceneObjectPart part in group.Parts)
- {
- if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys)
- {
- allow = false;
- break;
- }
- }
- if (!allow)
- return;
- m_host.ScriptSetPhysicsStatus(true);
- }
- else
- {
- m_host.ScriptSetPhysicsStatus(false);
- }
- }
- if ((status & ScriptBaseClass.STATUS_PHANTOM) == ScriptBaseClass.STATUS_PHANTOM)
- {
- m_host.ParentGroup.ScriptSetPhantomStatus(value != 0);
- }
- if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) == ScriptBaseClass.STATUS_CAST_SHADOWS)
- {
- m_host.AddFlag(PrimFlags.CastShadows);
- }
- if ((status & ScriptBaseClass.STATUS_ROTATE_X) == ScriptBaseClass.STATUS_ROTATE_X)
- {
- statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_X;
- }
- if ((status & ScriptBaseClass.STATUS_ROTATE_Y) == ScriptBaseClass.STATUS_ROTATE_Y)
- {
- statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Y;
- }
- if ((status & ScriptBaseClass.STATUS_ROTATE_Z) == ScriptBaseClass.STATUS_ROTATE_Z)
- {
- statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Z;
- }
- if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB) == ScriptBaseClass.STATUS_BLOCK_GRAB)
- {
- if (value != 0)
- m_host.SetBlockGrab(true);
- else
- m_host.SetBlockGrab(false);
- }
- if ((status & ScriptBaseClass.STATUS_DIE_AT_EDGE) == ScriptBaseClass.STATUS_DIE_AT_EDGE)
- {
- if (value != 0)
- m_host.SetDieAtEdge(true);
- else
- m_host.SetDieAtEdge(false);
- }
- if ((status & ScriptBaseClass.STATUS_RETURN_AT_EDGE) == ScriptBaseClass.STATUS_RETURN_AT_EDGE)
- {
- if (value != 0)
- m_host.SetReturnAtEdge(true);
- else
- m_host.SetReturnAtEdge(false);
- }
- if ((status & ScriptBaseClass.STATUS_SANDBOX) == ScriptBaseClass.STATUS_SANDBOX)
- {
- if (value != 0)
- m_host.SetStatusSandbox(true);
- else
- m_host.SetStatusSandbox(false);
- }
- if (statusrotationaxis != 0)
- {
- m_host.SetAxisRotation(statusrotationaxis, value);
- }
- }
- private bool IsPhysical()
- {
- return ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) == (uint)PrimFlags.Physics);
- }
- public LSL_Integer llGetStatus(int status)
- {
- m_host.AddScriptLPS(1);
- // m_log.Debug(m_host.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
- switch (status)
- {
- case ScriptBaseClass.STATUS_PHYSICS:
- return IsPhysical() ? 1 : 0;
- case ScriptBaseClass.STATUS_PHANTOM:
- if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == (uint)PrimFlags.Phantom)
- {
- return 1;
- }
- return 0;
- case ScriptBaseClass.STATUS_CAST_SHADOWS:
- if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.CastShadows) == (uint)PrimFlags.CastShadows)
- {
- return 1;
- }
- return 0;
- case ScriptBaseClass.STATUS_BLOCK_GRAB:
- if (m_host.GetBlockGrab())
- return 1;
- else
- return 0;
- case ScriptBaseClass.STATUS_DIE_AT_EDGE:
- if (m_host.GetDieAtEdge())
- return 1;
- else
- return 0;
- case ScriptBaseClass.STATUS_RETURN_AT_EDGE:
- if (m_host.GetReturnAtEdge())
- return 1;
- else
- return 0;
- case ScriptBaseClass.STATUS_ROTATE_X:
- // if (m_host.GetAxisRotation(2) != 0)
- if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
- return 1;
- else
- return 0;
- case ScriptBaseClass.STATUS_ROTATE_Y:
- if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
- return 1;
- else
- return 0;
- case ScriptBaseClass.STATUS_ROTATE_Z:
- if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
- return 1;
- else
- return 0;
- …
Large files files are truncated, but you can click here to view the full file